1 /* $OpenBSD: parse.y,v 1.40 2021/10/15 15:01:27 naddy Exp $ */
2
3 /*
4 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
5 * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 2001 Markus Friedl. All rights reserved.
8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
9 * Copyright (c) 2001 Theo de Raadt. All rights reserved.
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 %{
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <sys/stat.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <net/if.h>
32 #include <ctype.h>
33 #include <err.h>
34 #include <limits.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <syslog.h>
41
42 #include "igmp.h"
43 #include "dvmrp.h"
44 #include "dvmrpd.h"
45 #include "dvmrpe.h"
46 #include "log.h"
47
48 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
49 static struct file {
50 TAILQ_ENTRY(file) entry;
51 FILE *stream;
52 char *name;
53 int lineno;
54 int errors;
55 } *file, *topfile;
56 struct file *pushfile(const char *, int);
57 int popfile(void);
58 int check_file_secrecy(int, const char *);
59 int yyparse(void);
60 int yylex(void);
61 int yyerror(const char *, ...)
62 __attribute__((__format__ (printf, 1, 2)))
63 __attribute__((__nonnull__ (1)));
64 int kw_cmp(const void *, const void *);
65 int lookup(char *);
66 int lgetc(int);
67 int lungetc(int);
68 int findeol(void);
69
70 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
71 struct sym {
72 TAILQ_ENTRY(sym) entry;
73 int used;
74 int persist;
75 char *nam;
76 char *val;
77 };
78 int symset(const char *, const char *, int);
79 char *symget(const char *);
80
81 static struct dvmrpd_conf *conf;
82 char *start_state;
83 struct iface *iface = NULL;
84
85 static struct {
86 u_int32_t probe_interval;
87 u_int32_t query_interval;
88 u_int32_t query_resp_interval;
89 u_int32_t startup_query_interval;
90 u_int32_t startup_query_cnt;
91 u_int32_t last_member_query_interval;
92 u_int32_t last_member_query_cnt;
93 u_int32_t dead_interval;
94 u_int16_t metric;
95 u_int8_t robustness;
96 u_int8_t igmp_version;
97 } *defs, *grdefs, globaldefs, groupdefs, ifacedefs;
98
99 void clear_config(struct dvmrpd_conf *xconf);
100 struct iface *conf_get_if(struct kif *);
101 struct iface *new_group(void);
102
103 typedef struct {
104 union {
105 int64_t number;
106 char *string;
107 } v;
108 int lineno;
109 } YYSTYPE;
110
111 %}
112
113 %token INTERFACE FIBUPDATE
114 %token GROUP
115 %token METRIC PASSIVE
116 %token ROBUSTNESS QUERYINTERVAL QUERYRESPINTERVAL
117 %token STARTUPQUERYINTERVAL STARTUPQUERYCNT
118 %token LASTMEMBERQUERYINTERVAL LASTMEMBERQUERYCNT
119 %token IGMPVERSION
120 %token ERROR
121 %token <v.string> STRING
122 %token <v.number> NUMBER
123 %type <v.number> yesno
124 %type <v.string> string
125
126 %%
127
128 grammar : /* empty */
129 | grammar '\n'
130 | grammar conf_main '\n'
131 | grammar varset '\n'
132 | grammar interface '\n'
133 | grammar group '\n'
134 | grammar error '\n' { file->errors++; }
135 ;
136
137 string : string STRING {
138 if (asprintf(&$$, "%s %s", $1, $2) == -1) {
139 free($1);
140 free($2);
141 yyerror("string: asprintf");
142 YYERROR;
143 }
144 free($1);
145 free($2);
146 }
147 | STRING
148 ;
149
150 yesno : STRING {
151 if (!strcmp($1, "yes"))
152 $$ = 1;
153 else if (!strcmp($1, "no"))
154 $$ = 0;
155 else {
156 yyerror("syntax error, "
157 "either yes or no expected");
158 free($1);
159 YYERROR;
160 }
161 free($1);
162 }
163 ;
164
165 varset : STRING '=' string {
166 char *s = $1;
167 if (conf->opts & DVMRPD_OPT_VERBOSE)
168 printf("%s = \"%s\"\n", $1, $3);
169 while (*s++) {
170 if (isspace((unsigned char)*s)) {
171 yyerror("macro name cannot contain "
172 "whitespace");
173 free($1);
174 free($3);
175 YYERROR;
176 }
177 }
178 if (symset($1, $3, 0) == -1)
179 fatal("cannot store variable");
180 free($1);
181 free($3);
182 }
183 ;
184
185 conf_main : FIBUPDATE yesno {
186 if ($2 == 0)
187 conf->flags |= DVMRPD_FLAG_NO_FIB_UPDATE;
188 else
189 conf->flags &= ~DVMRPD_FLAG_NO_FIB_UPDATE;
190 }
191 | defaults
192 ;
193
194 defaults : LASTMEMBERQUERYCNT NUMBER {
195 if ($2 < MIN_LAST_MEMBER_QUERY_CNT ||
196 $2 > MAX_LAST_MEMBER_QUERY_CNT) {
197 yyerror("last-member-query-count out of "
198 "range (%d-%d)",
199 MIN_LAST_MEMBER_QUERY_CNT,
200 MAX_LAST_MEMBER_QUERY_CNT);
201 YYERROR;
202 }
203 defs->last_member_query_cnt = $2;
204 }
205 | LASTMEMBERQUERYINTERVAL NUMBER {
206 if ($2 < MIN_LAST_MEMBER_QUERY_INTERVAL ||
207 $2 > MAX_LAST_MEMBER_QUERY_INTERVAL) {
208 yyerror("last-member-query-interval out of "
209 "range (%d-%d)",
210 MIN_LAST_MEMBER_QUERY_INTERVAL,
211 MAX_LAST_MEMBER_QUERY_INTERVAL);
212 YYERROR;
213 }
214 defs->last_member_query_interval = $2;
215 }
216 | METRIC NUMBER {
217 if ($2 < MIN_METRIC || $2 > MAX_METRIC) {
218 yyerror("metric out of range (%d-%d)",
219 MIN_METRIC, MAX_METRIC);
220 YYERROR;
221 }
222 defs->metric = $2;
223 }
224 | QUERYINTERVAL NUMBER {
225 if ($2 < MIN_QUERY_INTERVAL ||
226 $2 > MAX_QUERY_INTERVAL) {
227 yyerror("query-interval out of range (%d-%d)",
228 MIN_QUERY_INTERVAL, MAX_QUERY_INTERVAL);
229 YYERROR;
230 }
231 defs->query_interval = $2;
232 }
233 | QUERYRESPINTERVAL NUMBER {
234 if ($2 < MIN_QUERY_RESP_INTERVAL ||
235 $2 > MAX_QUERY_RESP_INTERVAL) {
236 yyerror("query-response-interval out of "
237 "range (%d-%d)",
238 MIN_QUERY_RESP_INTERVAL,
239 MAX_QUERY_RESP_INTERVAL);
240 YYERROR;
241 }
242 defs->query_resp_interval = $2;
243 }
244 | ROBUSTNESS NUMBER {
245 if ($2 < MIN_ROBUSTNESS || $2 > MAX_ROBUSTNESS) {
246 yyerror("robustness out of range (%d-%d)",
247 MIN_ROBUSTNESS, MAX_ROBUSTNESS);
248 YYERROR;
249 }
250 defs->robustness = $2;
251 }
252 | STARTUPQUERYCNT NUMBER {
253 if ($2 < MIN_STARTUP_QUERY_CNT ||
254 $2 > MAX_STARTUP_QUERY_CNT) {
255 yyerror("startup-query-count out of "
256 "range (%d-%d)",
257 MIN_STARTUP_QUERY_CNT,
258 MAX_STARTUP_QUERY_CNT);
259 YYERROR;
260 }
261 defs->startup_query_cnt = $2;
262 }
263 | STARTUPQUERYINTERVAL NUMBER {
264 if ($2 < MIN_STARTUP_QUERY_INTERVAL ||
265 $2 > MAX_STARTUP_QUERY_INTERVAL) {
266 yyerror("startup-query-interval out of "
267 "range (%d-%d)",
268 MIN_STARTUP_QUERY_INTERVAL,
269 MAX_STARTUP_QUERY_INTERVAL);
270 YYERROR;
271 }
272 defs->startup_query_interval = $2;
273 }
274 | IGMPVERSION NUMBER {
275 if ($2 < MIN_IGMP_VERSION ||
276 $2 > MAX_IGMP_VERSION) {
277 yyerror("igmp-version out of range (%d-%d)",
278 MIN_IGMP_VERSION, MAX_IGMP_VERSION);
279 YYERROR;
280 }
281 defs->igmp_version = $2;
282 }
283 ;
284
285 optnl : '\n' optnl
286 |
287 ;
288
289 nl : '\n' optnl /* one newline or more */
290 ;
291
292 interface : INTERFACE STRING {
293 struct kif *kif;
294
295 if ((kif = kif_findname($2)) == NULL) {
296 yyerror("unknown interface %s", $2);
297 free($2);
298 YYERROR;
299 }
300 free($2);
301 iface = conf_get_if(kif);
302 if (iface == NULL)
303 YYERROR;
304 LIST_INSERT_HEAD(&conf->iface_list, iface, entry);
305
306 memcpy(&ifacedefs, defs, sizeof(ifacedefs));
307 defs = &ifacedefs;
308 } interface_block {
309 iface->probe_interval = defs->probe_interval;
310 iface->query_interval = defs->query_interval;
311 iface->query_resp_interval = defs->query_resp_interval;
312 iface->startup_query_interval =
313 defs->startup_query_interval;
314 iface->startup_query_cnt = defs->startup_query_cnt;
315 iface->last_member_query_interval =
316 defs->last_member_query_interval;
317 iface->last_member_query_cnt =
318 defs->last_member_query_cnt;
319 iface->dead_interval = defs->dead_interval;
320 iface->metric = defs->metric;
321 iface->robustness = defs->robustness;
322 iface->igmp_version = defs->igmp_version;
323 if (grdefs)
324 defs = grdefs;
325 else
326 defs = &globaldefs;
327 iface = NULL;
328 }
329 ;
330
331 interface_block : '{' optnl interfaceopts_l '}'
332 | '{' optnl '}'
333 |
334 ;
335
336 interfaceopts_l : interfaceopts_l interfaceoptsl
337 | interfaceoptsl
338 ;
339
340 interfaceoptsl : PASSIVE nl { iface->passive = 1; }
341 | defaults nl
342 ;
343
344 group : GROUP optnl '{' optnl {
345 memcpy(&groupdefs, defs, sizeof(groupdefs));
346 grdefs = defs = &groupdefs;
347 }
348 groupopts_l '}' {
349 grdefs = NULL;
350 defs = &globaldefs;
351 }
352 ;
353
354 groupopts_l : groupopts_l groupoptsl
355 | groupoptsl
356 ;
357
358 groupoptsl : interface nl
359 | defaults nl
360 | error nl
361 ;
362
363 %%
364
365 struct keywords {
366 const char *k_name;
367 int k_val;
368 };
369
370 int
yyerror(const char * fmt,...)371 yyerror(const char *fmt, ...)
372 {
373 va_list ap;
374 char *msg;
375
376 file->errors++;
377 va_start(ap, fmt);
378 if (vasprintf(&msg, fmt, ap) == -1)
379 fatalx("yyerror vasprintf");
380 va_end(ap);
381 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
382 free(msg);
383 return (0);
384 }
385
386 int
kw_cmp(const void * k,const void * e)387 kw_cmp(const void *k, const void *e)
388 {
389 return (strcmp(k, ((const struct keywords *)e)->k_name));
390 }
391
392 int
lookup(char * s)393 lookup(char *s)
394 {
395 /* this has to be sorted always */
396 static const struct keywords keywords[] = {
397 {"fib-update", FIBUPDATE},
398 {"group", GROUP},
399 {"igmp-version", IGMPVERSION},
400 {"interface", INTERFACE},
401 {"last-member-query-count", LASTMEMBERQUERYCNT},
402 {"last-member-query-interval", LASTMEMBERQUERYINTERVAL},
403 {"metric", METRIC},
404 {"passive", PASSIVE},
405 {"query-interval", QUERYINTERVAL},
406 {"query-response-interval", QUERYRESPINTERVAL},
407 {"robustness", ROBUSTNESS},
408 {"startup-query-count", STARTUPQUERYCNT},
409 {"startup-query-interval", STARTUPQUERYINTERVAL}
410 };
411 const struct keywords *p;
412
413 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
414 sizeof(keywords[0]), kw_cmp);
415
416 if (p)
417 return (p->k_val);
418 else
419 return (STRING);
420 }
421
422 #define MAXPUSHBACK 128
423
424 char *parsebuf;
425 int parseindex;
426 char pushback_buffer[MAXPUSHBACK];
427 int pushback_index = 0;
428
429 int
lgetc(int quotec)430 lgetc(int quotec)
431 {
432 int c, next;
433
434 if (parsebuf) {
435 /* Read character from the parsebuffer instead of input. */
436 if (parseindex >= 0) {
437 c = (unsigned char)parsebuf[parseindex++];
438 if (c != '\0')
439 return (c);
440 parsebuf = NULL;
441 } else
442 parseindex++;
443 }
444
445 if (pushback_index)
446 return ((unsigned char)pushback_buffer[--pushback_index]);
447
448 if (quotec) {
449 if ((c = getc(file->stream)) == EOF) {
450 yyerror("reached end of file while parsing "
451 "quoted string");
452 if (file == topfile || popfile() == EOF)
453 return (EOF);
454 return (quotec);
455 }
456 return (c);
457 }
458
459 while ((c = getc(file->stream)) == '\\') {
460 next = getc(file->stream);
461 if (next != '\n') {
462 c = next;
463 break;
464 }
465 yylval.lineno = file->lineno;
466 file->lineno++;
467 }
468
469 while (c == EOF) {
470 if (file == topfile || popfile() == EOF)
471 return (EOF);
472 c = getc(file->stream);
473 }
474 return (c);
475 }
476
477 int
lungetc(int c)478 lungetc(int c)
479 {
480 if (c == EOF)
481 return (EOF);
482 if (parsebuf) {
483 parseindex--;
484 if (parseindex >= 0)
485 return (c);
486 }
487 if (pushback_index + 1 >= MAXPUSHBACK)
488 return (EOF);
489 pushback_buffer[pushback_index++] = c;
490 return (c);
491 }
492
493 int
findeol(void)494 findeol(void)
495 {
496 int c;
497
498 parsebuf = NULL;
499
500 /* skip to either EOF or the first real EOL */
501 while (1) {
502 if (pushback_index)
503 c = (unsigned char)pushback_buffer[--pushback_index];
504 else
505 c = lgetc(0);
506 if (c == '\n') {
507 file->lineno++;
508 break;
509 }
510 if (c == EOF)
511 break;
512 }
513 return (ERROR);
514 }
515
516 int
yylex(void)517 yylex(void)
518 {
519 char buf[8096];
520 char *p, *val;
521 int quotec, next, c;
522 int token;
523
524 top:
525 p = buf;
526 while ((c = lgetc(0)) == ' ' || c == '\t')
527 ; /* nothing */
528
529 yylval.lineno = file->lineno;
530 if (c == '#')
531 while ((c = lgetc(0)) != '\n' && c != EOF)
532 ; /* nothing */
533 if (c == '$' && parsebuf == NULL) {
534 while (1) {
535 if ((c = lgetc(0)) == EOF)
536 return (0);
537
538 if (p + 1 >= buf + sizeof(buf) - 1) {
539 yyerror("string too long");
540 return (findeol());
541 }
542 if (isalnum(c) || c == '_') {
543 *p++ = c;
544 continue;
545 }
546 *p = '\0';
547 lungetc(c);
548 break;
549 }
550 val = symget(buf);
551 if (val == NULL) {
552 yyerror("macro '%s' not defined", buf);
553 return (findeol());
554 }
555 parsebuf = val;
556 parseindex = 0;
557 goto top;
558 }
559
560 switch (c) {
561 case '\'':
562 case '"':
563 quotec = c;
564 while (1) {
565 if ((c = lgetc(quotec)) == EOF)
566 return (0);
567 if (c == '\n') {
568 file->lineno++;
569 continue;
570 } else if (c == '\\') {
571 if ((next = lgetc(quotec)) == EOF)
572 return (0);
573 if (next == quotec || next == ' ' ||
574 next == '\t')
575 c = next;
576 else if (next == '\n') {
577 file->lineno++;
578 continue;
579 } else
580 lungetc(next);
581 } else if (c == quotec) {
582 *p = '\0';
583 break;
584 } else if (c == '\0') {
585 yyerror("syntax error");
586 return (findeol());
587 }
588 if (p + 1 >= buf + sizeof(buf) - 1) {
589 yyerror("string too long");
590 return (findeol());
591 }
592 *p++ = c;
593 }
594 yylval.v.string = strdup(buf);
595 if (yylval.v.string == NULL)
596 err(1, "%s", __func__);
597 return (STRING);
598 }
599
600 #define allowed_to_end_number(x) \
601 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
602
603 if (c == '-' || isdigit(c)) {
604 do {
605 *p++ = c;
606 if ((size_t)(p-buf) >= sizeof(buf)) {
607 yyerror("string too long");
608 return (findeol());
609 }
610 } while ((c = lgetc(0)) != EOF && isdigit(c));
611 lungetc(c);
612 if (p == buf + 1 && buf[0] == '-')
613 goto nodigits;
614 if (c == EOF || allowed_to_end_number(c)) {
615 const char *errstr = NULL;
616
617 *p = '\0';
618 yylval.v.number = strtonum(buf, LLONG_MIN,
619 LLONG_MAX, &errstr);
620 if (errstr) {
621 yyerror("\"%s\" invalid number: %s",
622 buf, errstr);
623 return (findeol());
624 }
625 return (NUMBER);
626 } else {
627 nodigits:
628 while (p > buf + 1)
629 lungetc((unsigned char)*--p);
630 c = (unsigned char)*--p;
631 if (c == '-')
632 return (c);
633 }
634 }
635
636 #define allowed_in_string(x) \
637 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
638 x != '{' && x != '}' && \
639 x != '!' && x != '=' && x != '#' && \
640 x != ','))
641
642 if (isalnum(c) || c == ':' || c == '_') {
643 do {
644 *p++ = c;
645 if ((size_t)(p-buf) >= sizeof(buf)) {
646 yyerror("string too long");
647 return (findeol());
648 }
649 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
650 lungetc(c);
651 *p = '\0';
652 if ((token = lookup(buf)) == STRING)
653 if ((yylval.v.string = strdup(buf)) == NULL)
654 err(1, "%s", __func__);
655 return (token);
656 }
657 if (c == '\n') {
658 yylval.lineno = file->lineno;
659 file->lineno++;
660 }
661 if (c == EOF)
662 return (0);
663 return (c);
664 }
665
666 int
check_file_secrecy(int fd,const char * fname)667 check_file_secrecy(int fd, const char *fname)
668 {
669 struct stat st;
670
671 if (fstat(fd, &st)) {
672 log_warn("cannot stat %s", fname);
673 return (-1);
674 }
675 if (st.st_uid != 0 && st.st_uid != getuid()) {
676 log_warnx("%s: owner not root or current user", fname);
677 return (-1);
678 }
679 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
680 log_warnx("%s: group writable or world read/writable", fname);
681 return (-1);
682 }
683 return (0);
684 }
685
686 struct file *
pushfile(const char * name,int secret)687 pushfile(const char *name, int secret)
688 {
689 struct file *nfile;
690
691 if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
692 log_warn("%s", __func__);
693 return (NULL);
694 }
695 if ((nfile->name = strdup(name)) == NULL) {
696 log_warn("%s", __func__);
697 free(nfile);
698 return (NULL);
699 }
700 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
701 log_warn("%s: %s", __func__, nfile->name);
702 free(nfile->name);
703 free(nfile);
704 return (NULL);
705 } else if (secret &&
706 check_file_secrecy(fileno(nfile->stream), nfile->name)) {
707 fclose(nfile->stream);
708 free(nfile->name);
709 free(nfile);
710 return (NULL);
711 }
712 nfile->lineno = 1;
713 TAILQ_INSERT_TAIL(&files, nfile, entry);
714 return (nfile);
715 }
716
717 int
popfile(void)718 popfile(void)
719 {
720 struct file *prev;
721
722 if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
723 prev->errors += file->errors;
724
725 TAILQ_REMOVE(&files, file, entry);
726 fclose(file->stream);
727 free(file->name);
728 free(file);
729 file = prev;
730 return (file ? 0 : EOF);
731 }
732
733 struct dvmrpd_conf *
parse_config(char * filename,int opts)734 parse_config(char *filename, int opts)
735 {
736 int errors = 0;
737 struct sym *sym, *next;
738 struct timeval now;
739
740 if ((conf = calloc(1, sizeof(struct dvmrpd_conf))) == NULL) {
741 errx(1, "parse_config calloc");
742 return (NULL);
743 }
744
745 defs = &globaldefs;
746 defs->probe_interval = DEFAULT_PROBE_INTERVAL;
747 defs->last_member_query_cnt = DEFAULT_LAST_MEMBER_QUERY_CNT;
748 defs->last_member_query_interval = DEFAULT_LAST_MEMBER_QUERY_INTERVAL;
749 defs->metric = DEFAULT_METRIC;
750 defs->query_interval = DEFAULT_QUERY_INTERVAL;
751 defs->query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL;
752 defs->robustness = DEFAULT_ROBUSTNESS;
753 defs->startup_query_cnt = DEFAULT_STARTUP_QUERY_CNT;
754 defs->startup_query_interval = DEFAULT_STARTUP_QUERY_INTERVAL;
755 defs->igmp_version = DEFAULT_IGMP_VERSION;
756 defs->dead_interval = NBR_TMOUT;
757
758 if ((file = pushfile(filename, 1)) == NULL) {
759 free(conf);
760 return (NULL);
761 }
762 topfile = file;
763
764 gettimeofday(&now, NULL);
765 conf->gen_id = (u_int32_t)now.tv_sec; /* for a while after 2038 */
766 conf->opts = opts;
767
768 yyparse();
769 errors = file->errors;
770 popfile();
771
772 /* Free macros and check which have not been used. */
773 TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
774 if ((conf->opts & DVMRPD_OPT_VERBOSE2) && !sym->used)
775 fprintf(stderr, "warning: macro '%s' not "
776 "used\n", sym->nam);
777 if (!sym->persist) {
778 free(sym->nam);
779 free(sym->val);
780 TAILQ_REMOVE(&symhead, sym, entry);
781 free(sym);
782 }
783 }
784
785 if (errors) {
786 clear_config(conf);
787 return (NULL);
788 }
789
790 return (conf);
791 }
792
793 int
symset(const char * nam,const char * val,int persist)794 symset(const char *nam, const char *val, int persist)
795 {
796 struct sym *sym;
797
798 TAILQ_FOREACH(sym, &symhead, entry) {
799 if (strcmp(nam, sym->nam) == 0)
800 break;
801 }
802
803 if (sym != NULL) {
804 if (sym->persist == 1)
805 return (0);
806 else {
807 free(sym->nam);
808 free(sym->val);
809 TAILQ_REMOVE(&symhead, sym, entry);
810 free(sym);
811 }
812 }
813 if ((sym = calloc(1, sizeof(*sym))) == NULL)
814 return (-1);
815
816 sym->nam = strdup(nam);
817 if (sym->nam == NULL) {
818 free(sym);
819 return (-1);
820 }
821 sym->val = strdup(val);
822 if (sym->val == NULL) {
823 free(sym->nam);
824 free(sym);
825 return (-1);
826 }
827 sym->used = 0;
828 sym->persist = persist;
829 TAILQ_INSERT_TAIL(&symhead, sym, entry);
830 return (0);
831 }
832
833 int
cmdline_symset(char * s)834 cmdline_symset(char *s)
835 {
836 char *sym, *val;
837 int ret;
838
839 if ((val = strrchr(s, '=')) == NULL)
840 return (-1);
841 sym = strndup(s, val - s);
842 if (sym == NULL)
843 errx(1, "%s: strndup", __func__);
844 ret = symset(sym, val + 1, 1);
845 free(sym);
846
847 return (ret);
848 }
849
850 char *
symget(const char * nam)851 symget(const char *nam)
852 {
853 struct sym *sym;
854
855 TAILQ_FOREACH(sym, &symhead, entry) {
856 if (strcmp(nam, sym->nam) == 0) {
857 sym->used = 1;
858 return (sym->val);
859 }
860 }
861 return (NULL);
862 }
863
864 struct iface *
conf_get_if(struct kif * kif)865 conf_get_if(struct kif *kif)
866 {
867 struct iface *i;
868
869 if (kif->ifindex >= MAXVIFS) {
870 yyerror("interface %s index too large", kif->ifname);
871 return (NULL);
872 }
873
874 LIST_FOREACH(i, &conf->iface_list, entry)
875 if (i->ifindex == kif->ifindex) {
876 yyerror("interface %s already configured",
877 kif->ifname);
878 return (NULL);
879 }
880
881 i = if_new(kif);
882 i->passive = 0;
883 i->recv_query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL;
884
885 return (i);
886 }
887
888 void
clear_config(struct dvmrpd_conf * xconf)889 clear_config(struct dvmrpd_conf *xconf)
890 {
891 /* XXX clear conf */
892 /* ... */
893 }
894