|
|
- /* $OpenBSD: parse.y,v 1.29 2006/06/01 06:06:59 otto Exp $ */
-
- /*
- * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 2001 Markus Friedl. All rights reserved.
- * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
- * Copyright (c) 2001 Theo de Raadt. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
- %{
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
-
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <syslog.h>
-
- #include "ntpd.h"
-
- static struct ntpd_conf *conf;
- static FILE *fin = NULL;
- static int lineno = 1;
- static int errors = 0;
- const char *infile;
-
- int yyerror(const char *, ...);
- int yyparse(void);
- int kw_cmp(const void *, const void *);
- int lookup(char *);
- int lgetc(FILE *);
- int lungetc(int);
- int findeol(void);
- int yylex(void);
-
- typedef struct {
- union {
- u_int32_t number;
- char *string;
- struct ntp_addr_wrap *addr;
- } v;
- int lineno;
- } YYSTYPE;
-
- %}
-
- %token LISTEN ON
- %token SERVER SERVERS SENSOR WEIGHT
- %token ERROR
- %token <v.string> STRING
- %type <v.addr> address
- %type <v.number> number weight
- %%
-
- grammar : /* empty */
- | grammar '\n'
- | grammar conf_main '\n'
- | grammar error '\n' { errors++; }
- ;
-
- conf_main : LISTEN ON address {
- struct listen_addr *la;
- struct ntp_addr *h, *next;
-
- if ((h = $3->a) == NULL &&
- (host_dns($3->name, &h) == -1 || !h)) {
- yyerror("could not resolve \"%s\"", $3->name);
- free($3->name);
- free($3);
- YYERROR;
- }
-
- for (; h != NULL; h = next) {
- next = h->next;
- if (h->ss.ss_family == AF_UNSPEC) {
- conf->listen_all = 1;
- free(h);
- continue;
- }
- la = calloc(1, sizeof(struct listen_addr));
- if (la == NULL)
- fatal("listen on calloc");
- la->fd = -1;
- memcpy(&la->sa, &h->ss,
- sizeof(struct sockaddr_storage));
- TAILQ_INSERT_TAIL(&conf->listen_addrs, la,
- entry);
- free(h);
- }
- free($3->name);
- free($3);
- }
- | SERVERS address weight {
- struct ntp_peer *p;
- struct ntp_addr *h, *next;
-
- h = $2->a;
- do {
- if (h != NULL) {
- next = h->next;
- if (h->ss.ss_family != AF_INET &&
- h->ss.ss_family != AF_INET6) {
- yyerror("IPv4 or IPv6 address "
- "or hostname expected");
- free(h);
- free($2->name);
- free($2);
- YYERROR;
- }
- h->next = NULL;
- } else
- next = NULL;
-
- p = new_peer();
- p->weight = $3;
- p->addr = h;
- p->addr_head.a = h;
- p->addr_head.pool = 1;
- p->addr_head.name = strdup($2->name);
- if (p->addr_head.name == NULL)
- fatal(NULL);
- if (p->addr != NULL)
- p->state = STATE_DNS_DONE;
- TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
-
- h = next;
- } while (h != NULL);
-
- free($2->name);
- free($2);
- }
- | SERVER address weight {
- struct ntp_peer *p;
- struct ntp_addr *h, *next;
-
- p = new_peer();
- for (h = $2->a; h != NULL; h = next) {
- next = h->next;
- if (h->ss.ss_family != AF_INET &&
- h->ss.ss_family != AF_INET6) {
- yyerror("IPv4 or IPv6 address "
- "or hostname expected");
- free(h);
- free(p);
- free($2->name);
- free($2);
- YYERROR;
- }
- h->next = p->addr;
- p->addr = h;
- }
-
- p->weight = $3;
- p->addr_head.a = p->addr;
- p->addr_head.pool = 0;
- p->addr_head.name = strdup($2->name);
- if (p->addr_head.name == NULL)
- fatal(NULL);
- if (p->addr != NULL)
- p->state = STATE_DNS_DONE;
- TAILQ_INSERT_TAIL(&conf->ntp_peers, p, entry);
- free($2->name);
- free($2);
- }
- | SENSOR STRING weight {
- struct ntp_conf_sensor *s;
-
- s = new_sensor($2);
- s->weight = $3;
- free($2);
- TAILQ_INSERT_TAIL(&conf->ntp_conf_sensors, s, entry);
- }
- ;
-
- address : STRING {
- if (($$ = calloc(1, sizeof(struct ntp_addr_wrap))) ==
- NULL)
- fatal(NULL);
- if (host($1, &$$->a) == -1) {
- yyerror("could not parse address spec \"%s\"",
- $1);
- free($1);
- free($$);
- YYERROR;
- }
- $$->name = $1;
- }
- ;
-
- number : STRING {
- u_long ulval;
- const char *errstr;
-
- ulval = strtonum($1, 0, LONG_MAX, &errstr);
- if (errstr) {
- yyerror("\"%s\" invalid: %s", $1, errstr);
- free($1);
- YYERROR;
- } else
- $$ = ulval;
- free($1);
- }
- ;
-
- weight : /* empty */ { $$ = 1; }
- | WEIGHT number {
- if ($2 < 1 || $2 > 10) {
- yyerror("weight must be between 1 and 10");
- YYERROR;
- }
- $$ = $2;
- }
- ;
-
- %%
-
- struct keywords {
- const char *k_name;
- int k_val;
- };
-
- int
- yyerror(const char *fmt, ...)
- {
- va_list ap;
- char *nfmt;
-
- errors = 1;
- va_start(ap, fmt);
- if (asprintf(&nfmt, "%s:%d: %s", infile, yylval.lineno, fmt) == -1)
- fatalx("yyerror asprintf");
- vlog(LOG_CRIT, nfmt, ap);
- va_end(ap);
- free(nfmt);
- return (0);
- }
-
- int
- kw_cmp(const void *k, const void *e)
- {
- return (strcmp(k, ((const struct keywords *)e)->k_name));
- }
-
- int
- lookup(char *s)
- {
- /* this has to be sorted always */
- static const struct keywords keywords[] = {
- { "listen", LISTEN},
- { "on", ON},
- { "sensor", SENSOR},
- { "server", SERVER},
- { "servers", SERVERS},
- { "weight", WEIGHT}
- };
- const struct keywords *p;
-
- p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
- sizeof(keywords[0]), kw_cmp);
-
- if (p)
- return (p->k_val);
- else
- return (STRING);
- }
-
- #define MAXPUSHBACK 128
-
- char *parsebuf;
- int parseindex;
- char pushback_buffer[MAXPUSHBACK];
- int pushback_index = 0;
-
- int
- lgetc(FILE *f)
- {
- int c, next;
-
- if (parsebuf) {
- /* Read character from the parsebuffer instead of input. */
- if (parseindex >= 0) {
- c = parsebuf[parseindex++];
- if (c != '\0')
- return (c);
- parsebuf = NULL;
- } else
- parseindex++;
- }
-
- if (pushback_index)
- return (pushback_buffer[--pushback_index]);
-
- while ((c = getc(f)) == '\\') {
- next = getc(f);
- if (next != '\n') {
- c = next;
- break;
- }
- yylval.lineno = lineno;
- lineno++;
- }
- if (c == '\t' || c == ' ') {
- /* Compress blanks to a single space. */
- do {
- c = getc(f);
- } while (c == '\t' || c == ' ');
- ungetc(c, f);
- c = ' ';
- }
-
- return (c);
- }
-
- int
- lungetc(int c)
- {
- if (c == EOF)
- return (EOF);
- if (parsebuf) {
- parseindex--;
- if (parseindex >= 0)
- return (c);
- }
- if (pushback_index < MAXPUSHBACK-1)
- return (pushback_buffer[pushback_index++] = c);
- else
- return (EOF);
- }
-
- int
- findeol(void)
- {
- int c;
-
- parsebuf = NULL;
- pushback_index = 0;
-
- /* skip to either EOF or the first real EOL */
- while (1) {
- c = lgetc(fin);
- if (c == '\n') {
- lineno++;
- break;
- }
- if (c == EOF)
- break;
- }
- return (ERROR);
- }
-
- int
- yylex(void)
- {
- char buf[8096];
- char *p;
- int endc, c;
- int token;
-
- p = buf;
- while ((c = lgetc(fin)) == ' ')
- ; /* nothing */
-
- yylval.lineno = lineno;
- if (c == '#')
- while ((c = lgetc(fin)) != '\n' && c != EOF)
- ; /* nothing */
-
- switch (c) {
- case '\'':
- case '"':
- endc = c;
- while (1) {
- if ((c = lgetc(fin)) == EOF)
- return (0);
- if (c == endc) {
- *p = '\0';
- break;
- }
- if (c == '\n') {
- lineno++;
- continue;
- }
- if (p + 1 >= buf + sizeof(buf) - 1) {
- yyerror("string too long");
- return (findeol());
- }
- *p++ = (char)c;
- }
- yylval.v.string = strdup(buf);
- if (yylval.v.string == NULL)
- fatal("yylex: strdup");
- return (STRING);
- }
-
- #define allowed_in_string(x) \
- (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
- x != '{' && x != '}' && x != '<' && x != '>' && \
- x != '!' && x != '=' && x != '/' && x != '#' && \
- x != ','))
-
- if (isalnum(c) || c == ':' || c == '_' || c == '*') {
- do {
- *p++ = c;
- if ((unsigned)(p-buf) >= sizeof(buf)) {
- yyerror("string too long");
- return (findeol());
- }
- } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
- lungetc(c);
- *p = '\0';
- if ((token = lookup(buf)) == STRING)
- if ((yylval.v.string = strdup(buf)) == NULL)
- fatal("yylex: strdup");
- return (token);
- }
- if (c == '\n') {
- yylval.lineno = lineno;
- lineno++;
- }
- if (c == EOF)
- return (0);
- return (c);
- }
-
- int
- parse_config(const char *filename, struct ntpd_conf *xconf)
- {
- conf = xconf;
- lineno = 1;
- errors = 0;
- TAILQ_INIT(&conf->listen_addrs);
- TAILQ_INIT(&conf->ntp_peers);
- TAILQ_INIT(&conf->ntp_conf_sensors);
-
- if ((fin = fopen(filename, "r")) == NULL) {
- log_warn("%s", filename);
- return (-1);
- }
- infile = filename;
-
- yyparse();
-
- fclose(fin);
-
- return (errors ? -1 : 0);
- }
|