Add READMEs.
[dragonfly.git] / contrib / ntpd / parse.y
blob09e23103cb66a9909fb83b13851501b5d4234a27
1 /* $OpenBSD: src/usr.sbin/ntpd/parse.y,v 1.24 2004/11/25 06:27:41 henning Exp $ */
3 /*
4 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2001 Markus Friedl. All rights reserved.
6 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
7 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <syslog.h>
36 #include "ntpd.h"
38 static struct ntpd_conf *conf;
39 static FILE *fin = NULL;
40 static int lineno = 1;
41 static int errors = 0;
42 const char *infile;
44 int yyerror(const char *, ...);
45 int yyparse(void);
46 int kw_cmp(const void *, const void *);
47 int lookup(char *);
48 int lgetc(FILE *);
49 int lungetc(int);
50 int findeol(void);
51 int yylex(void);
53 typedef struct {
54 union {
55 u_int32_t number;
56 char *string;
57 struct ntp_addr_wrap *addr;
58 } v;
59 int lineno;
60 } YYSTYPE;
64 %token LISTEN ON
65 %token SERVER SERVERS
66 %token ERROR
67 %token <v.string> STRING
68 %type <v.addr> address
71 grammar : /* empty */
72 | grammar '\n'
73 | grammar conf_main '\n'
74 | grammar error '\n' { errors++; }
77 conf_main : LISTEN ON address {
78 struct listen_addr *la;
79 struct ntp_addr *h, *next;
81 if ((h = $3->a) == NULL &&
82 (host_dns($3->name, &h) == -1 || !h)) {
83 yyerror("could not resolve \"%s\"", $3->name);
84 free($3->name);
85 free($3);
86 YYERROR;
89 for (; h != NULL; h = next) {
90 next = h->next;
91 if (h->ss.ss_family == AF_UNSPEC) {
92 conf->listen_all = 1;
93 free(h);
94 continue;
96 la = calloc(1, sizeof(struct listen_addr));
97 if (la == NULL)
98 fatal("listen on calloc");
99 la->fd = -1;
100 memcpy(&la->sa, &h->ss,
101 sizeof(struct sockaddr_storage));
102 TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
103 entry);
104 free(h);
106 free($3->name);
107 free($3);
109 | SERVERS address {
110 struct ntp_peer *p;
111 struct ntp_addr *h, *next;
113 h = $2->a;
114 do {
115 if (h != NULL) {
116 next = h->next;
117 if (h->ss.ss_family != AF_INET &&
118 h->ss.ss_family != AF_INET6) {
119 yyerror("IPv4 or IPv6 address "
120 "or hostname expected");
121 free(h);
122 free($2->name);
123 free($2);
124 YYERROR;
126 h->next = NULL;
127 } else
128 next = NULL;
130 p = new_peer();
131 p->addr = h;
132 p->addr_head.a = h;
133 p->addr_head.pool = 1;
134 p->addr_head.name = strdup($2->name);
135 if (p->addr_head.name == NULL)
136 fatal(NULL);
137 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
139 h = next;
140 } while (h != NULL);
142 free($2->name);
143 free($2);
145 | SERVER address {
146 struct ntp_peer *p;
147 struct ntp_addr *h, *next;
149 p = new_peer();
150 for (h = $2->a; h != NULL; h = next) {
151 next = h->next;
152 if (h->ss.ss_family != AF_INET &&
153 h->ss.ss_family != AF_INET6) {
154 yyerror("IPv4 or IPv6 address "
155 "or hostname expected");
156 free(h);
157 free(p);
158 free($2->name);
159 free($2);
160 YYERROR;
162 h->next = p->addr;
163 p->addr = h;
166 p->addr_head.a = p->addr;
167 p->addr_head.pool = 0;
168 p->addr_head.name = strdup($2->name);
169 if (p->addr_head.name == NULL)
170 fatal(NULL);
171 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
172 free($2->name);
173 free($2);
177 address : STRING {
178 if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
179 NULL)
180 fatal(NULL);
181 if (host($1, &$$->a) == -1) {
182 yyerror("could not parse address spec \"%s\"",
183 $1);
184 free($1);
185 free($$);
186 YYERROR;
188 $$->name = $1;
194 struct keywords {
195 const char *k_name;
196 int k_val;
200 yyerror(const char *fmt, ...)
202 va_list ap;
203 char *nfmt;
205 errors = 1;
206 va_start(ap, fmt);
207 if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
208 fatalx("yyerror asprintf");
209 vlog(LOG_CRIT, nfmt, ap);
210 va_end(ap);
211 free(nfmt);
212 return (0);
216 kw_cmp(const void *k, const void *e)
218 return (strcmp(k, ((const struct keywords *)e)->k_name));
222 lookup(char *s)
224 /* this has to be sorted always */
225 static const struct keywords keywords[] = {
226 { "listen", LISTEN},
227 { "on", ON},
228 { "server", SERVER},
229 { "servers", SERVERS}
231 const struct keywords *p;
233 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
234 sizeof(keywords[0]), kw_cmp);
236 if (p)
237 return (p->k_val);
238 else
239 return (STRING);
242 #define MAXPUSHBACK 128
244 char *parsebuf;
245 int parseindex;
246 char pushback_buffer[MAXPUSHBACK];
247 int pushback_index = 0;
250 lgetc(FILE *f)
252 int c, next;
254 if (parsebuf) {
255 /* Read character from the parsebuffer instead of input. */
256 if (parseindex >= 0) {
257 c = parsebuf[parseindex++];
258 if (c != '\0')
259 return (c);
260 parsebuf = NULL;
261 } else
262 parseindex++;
265 if (pushback_index)
266 return (pushback_buffer[--pushback_index]);
268 while ((c = getc(f)) == '\\') {
269 next = getc(f);
270 if (next != '\n') {
271 if (isspace(next))
272 yyerror("whitespace after \\");
273 ungetc(next, f);
274 break;
276 yylval.lineno = lineno;
277 lineno++;
279 if (c == '\t' || c == ' ') {
280 /* Compress blanks to a single space. */
281 do {
282 c = getc(f);
283 } while (c == '\t' || c == ' ');
284 ungetc(c, f);
285 c = ' ';
288 return (c);
292 lungetc(int c)
294 if (c == EOF)
295 return (EOF);
296 if (parsebuf) {
297 parseindex--;
298 if (parseindex >= 0)
299 return (c);
301 if (pushback_index < MAXPUSHBACK-1)
302 return (pushback_buffer[pushback_index++] = c);
303 else
304 return (EOF);
308 findeol(void)
310 int c;
312 parsebuf = NULL;
313 pushback_index = 0;
315 /* skip to either EOF or the first real EOL */
316 while (1) {
317 c = lgetc(fin);
318 if (c == '\n') {
319 lineno++;
320 break;
322 if (c == EOF)
323 break;
325 return (ERROR);
329 yylex(void)
331 char buf[8096];
332 char *p;
333 int endc, c;
334 int token;
336 p = buf;
337 while ((c = lgetc(fin)) == ' ')
338 ; /* nothing */
340 yylval.lineno = lineno;
341 if (c == '#')
342 while ((c = lgetc(fin)) != '\n' && c != EOF)
343 ; /* nothing */
345 switch (c) {
346 case '\'':
347 case '"':
348 endc = c;
349 while (1) {
350 if ((c = lgetc(fin)) == EOF)
351 return (0);
352 if (c == endc) {
353 *p = '\0';
354 break;
356 if (c == '\n') {
357 lineno++;
358 continue;
360 if (p + 1 >= buf + sizeof(buf) - 1) {
361 yyerror("string too long");
362 return (findeol());
364 *p++ = (char)c;
366 yylval.v.string = strdup(buf);
367 if (yylval.v.string == NULL)
368 fatal("yylex: strdup");
369 return (STRING);
372 #define allowed_in_string(x) \
373 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
374 x != '{' && x != '}' && x != '<' && x != '>' && \
375 x != '!' && x != '=' && x != '/' && x != '#' && \
376 x != ','))
378 if (isalnum(c) || c == ':' || c == '_' || c == '*') {
379 do {
380 *p++ = c;
381 if ((unsigned)(p-buf) >= sizeof(buf)) {
382 yyerror("string too long");
383 return (findeol());
385 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
386 lungetc(c);
387 *p = '\0';
388 if ((token = lookup(buf)) == STRING)
389 if ((yylval.v.string = strdup(buf)) == NULL)
390 fatal("yylex: strdup");
391 return (token);
393 if (c == '\n') {
394 yylval.lineno = lineno;
395 lineno++;
397 if (c == EOF)
398 return (0);
399 return (c);
403 parse_config(const char *filename, struct ntpd_conf *xconf)
405 conf = xconf;
406 lineno = 1;
407 errors = 0;
408 TAILQ_INIT(&conf->listen_addrs);
409 TAILQ_INIT(&conf->ntp_peers);
411 if ((fin = fopen(filename, "r")) == NULL) {
412 log_warn("%s", filename);
413 return (-1);
415 infile = filename;
417 yyparse();
419 fclose(fin);
421 return (errors ? -1 : 0);