1 /* $OpenBSD: src/usr.sbin/ntpd/parse.y,v 1.24 2004/11/25 06:27:41 henning Exp $ */
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>
38 static struct ntpd_conf *conf;
39 static FILE *fin = NULL;
40 static int lineno = 1;
41 static int errors = 0;
44 int yyerror(const char *, ...);
46 int kw_cmp(const void *, const void *);
57 struct ntp_addr_wrap *addr;
67 %token <v.string> STRING
68 %type <v.addr> address
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);
89 for (; h != NULL; h = next) {
91 if (h->ss.ss_family == AF_UNSPEC) {
96 la = calloc(1, sizeof(struct listen_addr));
98 fatal("listen on calloc");
100 memcpy(&la->sa, &h->ss,
101 sizeof(struct sockaddr_storage));
102 TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
111 struct ntp_addr *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");
133 p->addr_head.pool = 1;
134 p->addr_head.name = strdup($2->name);
135 if (p->addr_head.name == NULL)
137 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
147 struct ntp_addr *h, *next;
150 for (h = $2->a; h != NULL; 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");
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)
171 TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
178 if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
181 if (host($1, &$$->a) == -1) {
182 yyerror("could not parse address spec \"%s\"",
200 yyerror(const char *fmt, ...)
207 if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
208 fatalx("yyerror asprintf");
209 vlog(LOG_CRIT, nfmt, ap);
216 kw_cmp(const void *k, const void *e)
218 return (strcmp(k, ((const struct keywords *)e)->k_name));
224 /* this has to be sorted always */
225 static const struct keywords keywords[] = {
229 { "servers", SERVERS}
231 const struct keywords *p;
233 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
234 sizeof(keywords[0]), kw_cmp);
242 #define MAXPUSHBACK 128
246 char pushback_buffer[MAXPUSHBACK];
247 int pushback_index = 0;
255 /* Read character from the parsebuffer instead of input. */
256 if (parseindex >= 0) {
257 c = parsebuf[parseindex++];
266 return (pushback_buffer[--pushback_index]);
268 while ((c = getc(f)) == '\\') {
272 yyerror("whitespace after \\");
276 yylval.lineno = lineno;
279 if (c == '\t' || c == ' ') {
280 /* Compress blanks to a single space. */
283 } while (c == '\t' || c == ' ');
301 if (pushback_index < MAXPUSHBACK-1)
302 return (pushback_buffer[pushback_index++] = c);
315 /* skip to either EOF or the first real EOL */
337 while ((c = lgetc(fin)) == ' ')
340 yylval.lineno = lineno;
342 while ((c = lgetc(fin)) != '\n' && c != EOF)
350 if ((c = lgetc(fin)) == EOF)
360 if (p + 1 >= buf + sizeof(buf) - 1) {
361 yyerror("string too long");
366 yylval.v.string = strdup(buf);
367 if (yylval.v.string == NULL)
368 fatal("yylex: strdup");
372 #define allowed_in_string(x) \
373 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
374 x != '{' && x != '}' && x != '<' && x != '>' && \
375 x != '!' && x != '=' && x != '/' && x != '#' && \
378 if (isalnum(c) || c == ':' || c == '_' || c == '*') {
381 if ((unsigned)(p-buf) >= sizeof(buf)) {
382 yyerror("string too long");
385 } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
388 if ((token = lookup(buf)) == STRING)
389 if ((yylval.v.string = strdup(buf)) == NULL)
390 fatal("yylex: strdup");
394 yylval.lineno = lineno;
403 parse_config(const char *filename, struct ntpd_conf *xconf)
408 TAILQ_INIT(&conf->listen_addrs);
409 TAILQ_INIT(&conf->ntp_peers);
411 if ((fin = fopen(filename, "r")) == NULL) {
412 log_warn("%s", filename);
421 return (errors ? -1 : 0);