1 /* $OpenBSD: parse.y,v 1.30 2016/06/21 21:35:24 benno 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 YYERROR; 174 } 175 } 176 if (symset($1, $3, 0) == -1) 177 fatal("cannot store variable"); 178 free($1); 179 free($3); 180 } 181 ; 182 183 conf_main : FIBUPDATE yesno { 184 if ($2 == 0) 185 conf->flags |= DVMRPD_FLAG_NO_FIB_UPDATE; 186 else 187 conf->flags &= ~DVMRPD_FLAG_NO_FIB_UPDATE; 188 } 189 | defaults 190 ; 191 192 defaults : LASTMEMBERQUERYCNT NUMBER { 193 if ($2 < MIN_LAST_MEMBER_QUERY_CNT || 194 $2 > MAX_LAST_MEMBER_QUERY_CNT) { 195 yyerror("last-member-query-count out of " 196 "range (%d-%d)", 197 MIN_LAST_MEMBER_QUERY_CNT, 198 MAX_LAST_MEMBER_QUERY_CNT); 199 YYERROR; 200 } 201 defs->last_member_query_cnt = $2; 202 } 203 | LASTMEMBERQUERYINTERVAL NUMBER { 204 if ($2 < MIN_LAST_MEMBER_QUERY_INTERVAL || 205 $2 > MAX_LAST_MEMBER_QUERY_INTERVAL) { 206 yyerror("last-member-query-interval out of " 207 "range (%d-%d)", 208 MIN_LAST_MEMBER_QUERY_INTERVAL, 209 MAX_LAST_MEMBER_QUERY_INTERVAL); 210 YYERROR; 211 } 212 defs->last_member_query_interval = $2; 213 } 214 | METRIC NUMBER { 215 if ($2 < MIN_METRIC || $2 > MAX_METRIC) { 216 yyerror("metric out of range (%d-%d)", 217 MIN_METRIC, MAX_METRIC); 218 YYERROR; 219 } 220 defs->metric = $2; 221 } 222 | QUERYINTERVAL NUMBER { 223 if ($2 < MIN_QUERY_INTERVAL || 224 $2 > MAX_QUERY_INTERVAL) { 225 yyerror("query-interval out of range (%d-%d)", 226 MIN_QUERY_INTERVAL, MAX_QUERY_INTERVAL); 227 YYERROR; 228 } 229 defs->query_interval = $2; 230 } 231 | QUERYRESPINTERVAL NUMBER { 232 if ($2 < MIN_QUERY_RESP_INTERVAL || 233 $2 > MAX_QUERY_RESP_INTERVAL) { 234 yyerror("query-response-interval out of " 235 "range (%d-%d)", 236 MIN_QUERY_RESP_INTERVAL, 237 MAX_QUERY_RESP_INTERVAL); 238 YYERROR; 239 } 240 defs->query_resp_interval = $2; 241 } 242 | ROBUSTNESS NUMBER { 243 if ($2 < MIN_ROBUSTNESS || $2 > MAX_ROBUSTNESS) { 244 yyerror("robustness out of range (%d-%d)", 245 MIN_ROBUSTNESS, MAX_ROBUSTNESS); 246 YYERROR; 247 } 248 defs->robustness = $2; 249 } 250 | STARTUPQUERYCNT NUMBER { 251 if ($2 < MIN_STARTUP_QUERY_CNT || 252 $2 > MAX_STARTUP_QUERY_CNT) { 253 yyerror("startup-query-count out of " 254 "range (%d-%d)", 255 MIN_STARTUP_QUERY_CNT, 256 MAX_STARTUP_QUERY_CNT); 257 YYERROR; 258 } 259 defs->startup_query_cnt = $2; 260 } 261 | STARTUPQUERYINTERVAL NUMBER { 262 if ($2 < MIN_STARTUP_QUERY_INTERVAL || 263 $2 > MAX_STARTUP_QUERY_INTERVAL) { 264 yyerror("startup-query-interval out of " 265 "range (%d-%d)", 266 MIN_STARTUP_QUERY_INTERVAL, 267 MAX_STARTUP_QUERY_INTERVAL); 268 YYERROR; 269 } 270 defs->startup_query_interval = $2; 271 } 272 | IGMPVERSION NUMBER { 273 if ($2 < MIN_IGMP_VERSION || 274 $2 > MAX_IGMP_VERSION) { 275 yyerror("igmp-version out of range (%d-%d)", 276 MIN_IGMP_VERSION, MAX_IGMP_VERSION); 277 YYERROR; 278 } 279 defs->igmp_version = $2; 280 } 281 ; 282 283 optnl : '\n' optnl 284 | 285 ; 286 287 nl : '\n' optnl /* one newline or more */ 288 ; 289 290 interface : INTERFACE STRING { 291 struct kif *kif; 292 293 if ((kif = kif_findname($2)) == NULL) { 294 yyerror("unknown interface %s", $2); 295 free($2); 296 YYERROR; 297 } 298 free($2); 299 iface = conf_get_if(kif); 300 if (iface == NULL) 301 YYERROR; 302 LIST_INSERT_HEAD(&conf->iface_list, iface, entry); 303 304 memcpy(&ifacedefs, defs, sizeof(ifacedefs)); 305 defs = &ifacedefs; 306 } interface_block { 307 iface->probe_interval = defs->probe_interval; 308 iface->query_interval = defs->query_interval; 309 iface->query_resp_interval = defs->query_resp_interval; 310 iface->startup_query_interval = 311 defs->startup_query_interval; 312 iface->startup_query_cnt = defs->startup_query_cnt; 313 iface->last_member_query_interval = 314 defs->last_member_query_interval; 315 iface->last_member_query_cnt = 316 defs->last_member_query_cnt; 317 iface->dead_interval = defs->dead_interval; 318 iface->metric = defs->metric; 319 iface->robustness = defs->robustness; 320 iface->igmp_version = defs->igmp_version; 321 if (grdefs) 322 defs = grdefs; 323 else 324 defs = &globaldefs; 325 iface = NULL; 326 } 327 ; 328 329 interface_block : '{' optnl interfaceopts_l '}' 330 | '{' optnl '}' 331 | 332 ; 333 334 interfaceopts_l : interfaceopts_l interfaceoptsl 335 | interfaceoptsl 336 ; 337 338 interfaceoptsl : PASSIVE nl { iface->passive = 1; } 339 | defaults nl 340 ; 341 342 group : GROUP optnl '{' optnl { 343 memcpy(&groupdefs, defs, sizeof(groupdefs)); 344 grdefs = defs = &groupdefs; 345 } 346 groupopts_l '}' { 347 grdefs = NULL; 348 defs = &globaldefs; 349 } 350 ; 351 352 groupopts_l : groupopts_l groupoptsl 353 | groupoptsl 354 ; 355 356 groupoptsl : interface nl 357 | defaults nl 358 | error nl 359 ; 360 361 %% 362 363 struct keywords { 364 const char *k_name; 365 int k_val; 366 }; 367 368 int 369 yyerror(const char *fmt, ...) 370 { 371 va_list ap; 372 char *msg; 373 374 file->errors++; 375 va_start(ap, fmt); 376 if (vasprintf(&msg, fmt, ap) == -1) 377 fatalx("yyerror vasprintf"); 378 va_end(ap); 379 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 380 free(msg); 381 return (0); 382 } 383 384 int 385 kw_cmp(const void *k, const void *e) 386 { 387 return (strcmp(k, ((const struct keywords *)e)->k_name)); 388 } 389 390 int 391 lookup(char *s) 392 { 393 /* this has to be sorted always */ 394 static const struct keywords keywords[] = { 395 {"fib-update", FIBUPDATE}, 396 {"group", GROUP}, 397 {"igmp-version", IGMPVERSION}, 398 {"interface", INTERFACE}, 399 {"last-member-query-count", LASTMEMBERQUERYCNT}, 400 {"last-member-query-interval", LASTMEMBERQUERYINTERVAL}, 401 {"metric", METRIC}, 402 {"passive", PASSIVE}, 403 {"query-interval", QUERYINTERVAL}, 404 {"query-response-interval", QUERYRESPINTERVAL}, 405 {"robustness", ROBUSTNESS}, 406 {"startup-query-count", STARTUPQUERYCNT}, 407 {"startup-query-interval", STARTUPQUERYINTERVAL} 408 }; 409 const struct keywords *p; 410 411 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 412 sizeof(keywords[0]), kw_cmp); 413 414 if (p) 415 return (p->k_val); 416 else 417 return (STRING); 418 } 419 420 #define MAXPUSHBACK 128 421 422 u_char *parsebuf; 423 int parseindex; 424 u_char pushback_buffer[MAXPUSHBACK]; 425 int pushback_index = 0; 426 427 int 428 lgetc(int quotec) 429 { 430 int c, next; 431 432 if (parsebuf) { 433 /* Read character from the parsebuffer instead of input. */ 434 if (parseindex >= 0) { 435 c = parsebuf[parseindex++]; 436 if (c != '\0') 437 return (c); 438 parsebuf = NULL; 439 } else 440 parseindex++; 441 } 442 443 if (pushback_index) 444 return (pushback_buffer[--pushback_index]); 445 446 if (quotec) { 447 if ((c = getc(file->stream)) == EOF) { 448 yyerror("reached end of file while parsing " 449 "quoted string"); 450 if (file == topfile || popfile() == EOF) 451 return (EOF); 452 return (quotec); 453 } 454 return (c); 455 } 456 457 while ((c = getc(file->stream)) == '\\') { 458 next = getc(file->stream); 459 if (next != '\n') { 460 c = next; 461 break; 462 } 463 yylval.lineno = file->lineno; 464 file->lineno++; 465 } 466 467 while (c == EOF) { 468 if (file == topfile || popfile() == EOF) 469 return (EOF); 470 c = getc(file->stream); 471 } 472 return (c); 473 } 474 475 int 476 lungetc(int c) 477 { 478 if (c == EOF) 479 return (EOF); 480 if (parsebuf) { 481 parseindex--; 482 if (parseindex >= 0) 483 return (c); 484 } 485 if (pushback_index < MAXPUSHBACK-1) 486 return (pushback_buffer[pushback_index++] = c); 487 else 488 return (EOF); 489 } 490 491 int 492 findeol(void) 493 { 494 int c; 495 496 parsebuf = NULL; 497 498 /* skip to either EOF or the first real EOL */ 499 while (1) { 500 if (pushback_index) 501 c = pushback_buffer[--pushback_index]; 502 else 503 c = lgetc(0); 504 if (c == '\n') { 505 file->lineno++; 506 break; 507 } 508 if (c == EOF) 509 break; 510 } 511 return (ERROR); 512 } 513 514 int 515 yylex(void) 516 { 517 u_char buf[8096]; 518 u_char *p, *val; 519 int quotec, next, c; 520 int token; 521 522 top: 523 p = buf; 524 while ((c = lgetc(0)) == ' ' || c == '\t') 525 ; /* nothing */ 526 527 yylval.lineno = file->lineno; 528 if (c == '#') 529 while ((c = lgetc(0)) != '\n' && c != EOF) 530 ; /* nothing */ 531 if (c == '$' && parsebuf == NULL) { 532 while (1) { 533 if ((c = lgetc(0)) == EOF) 534 return (0); 535 536 if (p + 1 >= buf + sizeof(buf) - 1) { 537 yyerror("string too long"); 538 return (findeol()); 539 } 540 if (isalnum(c) || c == '_') { 541 *p++ = c; 542 continue; 543 } 544 *p = '\0'; 545 lungetc(c); 546 break; 547 } 548 val = symget(buf); 549 if (val == NULL) { 550 yyerror("macro '%s' not defined", buf); 551 return (findeol()); 552 } 553 parsebuf = val; 554 parseindex = 0; 555 goto top; 556 } 557 558 switch (c) { 559 case '\'': 560 case '"': 561 quotec = c; 562 while (1) { 563 if ((c = lgetc(quotec)) == EOF) 564 return (0); 565 if (c == '\n') { 566 file->lineno++; 567 continue; 568 } else if (c == '\\') { 569 if ((next = lgetc(quotec)) == EOF) 570 return (0); 571 if (next == quotec || c == ' ' || c == '\t') 572 c = next; 573 else if (next == '\n') { 574 file->lineno++; 575 continue; 576 } else 577 lungetc(next); 578 } else if (c == quotec) { 579 *p = '\0'; 580 break; 581 } else if (c == '\0') { 582 yyerror("syntax error"); 583 return (findeol()); 584 } 585 if (p + 1 >= buf + sizeof(buf) - 1) { 586 yyerror("string too long"); 587 return (findeol()); 588 } 589 *p++ = c; 590 } 591 yylval.v.string = strdup(buf); 592 if (yylval.v.string == NULL) 593 err(1, "yylex: strdup"); 594 return (STRING); 595 } 596 597 #define allowed_to_end_number(x) \ 598 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 599 600 if (c == '-' || isdigit(c)) { 601 do { 602 *p++ = c; 603 if ((unsigned)(p-buf) >= sizeof(buf)) { 604 yyerror("string too long"); 605 return (findeol()); 606 } 607 } while ((c = lgetc(0)) != EOF && isdigit(c)); 608 lungetc(c); 609 if (p == buf + 1 && buf[0] == '-') 610 goto nodigits; 611 if (c == EOF || allowed_to_end_number(c)) { 612 const char *errstr = NULL; 613 614 *p = '\0'; 615 yylval.v.number = strtonum(buf, LLONG_MIN, 616 LLONG_MAX, &errstr); 617 if (errstr) { 618 yyerror("\"%s\" invalid number: %s", 619 buf, errstr); 620 return (findeol()); 621 } 622 return (NUMBER); 623 } else { 624 nodigits: 625 while (p > buf + 1) 626 lungetc(*--p); 627 c = *--p; 628 if (c == '-') 629 return (c); 630 } 631 } 632 633 #define allowed_in_string(x) \ 634 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 635 x != '{' && x != '}' && \ 636 x != '!' && x != '=' && x != '#' && \ 637 x != ',')) 638 639 if (isalnum(c) || c == ':' || c == '_') { 640 do { 641 *p++ = c; 642 if ((unsigned)(p-buf) >= sizeof(buf)) { 643 yyerror("string too long"); 644 return (findeol()); 645 } 646 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 647 lungetc(c); 648 *p = '\0'; 649 if ((token = lookup(buf)) == STRING) 650 if ((yylval.v.string = strdup(buf)) == NULL) 651 err(1, "yylex: strdup"); 652 return (token); 653 } 654 if (c == '\n') { 655 yylval.lineno = file->lineno; 656 file->lineno++; 657 } 658 if (c == EOF) 659 return (0); 660 return (c); 661 } 662 663 int 664 check_file_secrecy(int fd, const char *fname) 665 { 666 struct stat st; 667 668 if (fstat(fd, &st)) { 669 log_warn("cannot stat %s", fname); 670 return (-1); 671 } 672 if (st.st_uid != 0 && st.st_uid != getuid()) { 673 log_warnx("%s: owner not root or current user", fname); 674 return (-1); 675 } 676 if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { 677 log_warnx("%s: group writable or world read/writable", fname); 678 return (-1); 679 } 680 return (0); 681 } 682 683 struct file * 684 pushfile(const char *name, int secret) 685 { 686 struct file *nfile; 687 688 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 689 log_warn("malloc"); 690 return (NULL); 691 } 692 if ((nfile->name = strdup(name)) == NULL) { 693 log_warn("malloc"); 694 free(nfile); 695 return (NULL); 696 } 697 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 698 log_warn("%s", nfile->name); 699 free(nfile->name); 700 free(nfile); 701 return (NULL); 702 } else if (secret && 703 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 704 fclose(nfile->stream); 705 free(nfile->name); 706 free(nfile); 707 return (NULL); 708 } 709 nfile->lineno = 1; 710 TAILQ_INSERT_TAIL(&files, nfile, entry); 711 return (nfile); 712 } 713 714 int 715 popfile(void) 716 { 717 struct file *prev; 718 719 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 720 prev->errors += file->errors; 721 722 TAILQ_REMOVE(&files, file, entry); 723 fclose(file->stream); 724 free(file->name); 725 free(file); 726 file = prev; 727 return (file ? 0 : EOF); 728 } 729 730 struct dvmrpd_conf * 731 parse_config(char *filename, int opts) 732 { 733 int errors = 0; 734 struct sym *sym, *next; 735 struct timeval now; 736 737 if ((conf = calloc(1, sizeof(struct dvmrpd_conf))) == NULL) { 738 errx(1, "parse_config calloc"); 739 return (NULL); 740 } 741 742 defs = &globaldefs; 743 defs->probe_interval = DEFAULT_PROBE_INTERVAL; 744 defs->last_member_query_cnt = DEFAULT_LAST_MEMBER_QUERY_CNT; 745 defs->last_member_query_interval = DEFAULT_LAST_MEMBER_QUERY_INTERVAL; 746 defs->metric = DEFAULT_METRIC; 747 defs->query_interval = DEFAULT_QUERY_INTERVAL; 748 defs->query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL; 749 defs->robustness = DEFAULT_ROBUSTNESS; 750 defs->startup_query_cnt = DEFAULT_STARTUP_QUERY_CNT; 751 defs->startup_query_interval = DEFAULT_STARTUP_QUERY_INTERVAL; 752 defs->igmp_version = DEFAULT_IGMP_VERSION; 753 defs->dead_interval = NBR_TMOUT; 754 755 if ((file = pushfile(filename, 1)) == NULL) { 756 free(conf); 757 return (NULL); 758 } 759 topfile = file; 760 761 gettimeofday(&now, NULL); 762 conf->gen_id = (u_int32_t)now.tv_sec; /* for a while after 2038 */ 763 conf->opts = opts; 764 765 yyparse(); 766 errors = file->errors; 767 popfile(); 768 769 /* Free macros and check which have not been used. */ 770 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 771 next = TAILQ_NEXT(sym, entry); 772 if ((conf->opts & DVMRPD_OPT_VERBOSE2) && !sym->used) 773 fprintf(stderr, "warning: macro '%s' not " 774 "used\n", sym->nam); 775 if (!sym->persist) { 776 free(sym->nam); 777 free(sym->val); 778 TAILQ_REMOVE(&symhead, sym, entry); 779 free(sym); 780 } 781 } 782 783 if (errors) { 784 clear_config(conf); 785 return (NULL); 786 } 787 788 return (conf); 789 } 790 791 int 792 symset(const char *nam, const char *val, int persist) 793 { 794 struct sym *sym; 795 796 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 797 sym = TAILQ_NEXT(sym, entry)) 798 ; /* nothing */ 799 800 if (sym != NULL) { 801 if (sym->persist == 1) 802 return (0); 803 else { 804 free(sym->nam); 805 free(sym->val); 806 TAILQ_REMOVE(&symhead, sym, entry); 807 free(sym); 808 } 809 } 810 if ((sym = calloc(1, sizeof(*sym))) == NULL) 811 return (-1); 812 813 sym->nam = strdup(nam); 814 if (sym->nam == NULL) { 815 free(sym); 816 return (-1); 817 } 818 sym->val = strdup(val); 819 if (sym->val == NULL) { 820 free(sym->nam); 821 free(sym); 822 return (-1); 823 } 824 sym->used = 0; 825 sym->persist = persist; 826 TAILQ_INSERT_TAIL(&symhead, sym, entry); 827 return (0); 828 } 829 830 int 831 cmdline_symset(char *s) 832 { 833 char *sym, *val; 834 int ret; 835 size_t len; 836 837 if ((val = strrchr(s, '=')) == NULL) 838 return (-1); 839 840 len = strlen(s) - strlen(val) + 1; 841 if ((sym = malloc(len)) == NULL) 842 errx(1, "cmdline_symset: malloc"); 843 844 strlcpy(sym, s, len); 845 846 ret = symset(sym, val + 1, 1); 847 free(sym); 848 849 return (ret); 850 } 851 852 char * 853 symget(const char *nam) 854 { 855 struct sym *sym; 856 857 TAILQ_FOREACH(sym, &symhead, entry) 858 if (strcmp(nam, sym->nam) == 0) { 859 sym->used = 1; 860 return (sym->val); 861 } 862 return (NULL); 863 } 864 865 struct iface * 866 conf_get_if(struct kif *kif) 867 { 868 struct iface *i; 869 870 if (kif->ifindex >= MAXVIFS) { 871 yyerror("interface %s index too large", kif->ifname); 872 return (NULL); 873 } 874 875 LIST_FOREACH(i, &conf->iface_list, entry) 876 if (i->ifindex == kif->ifindex) { 877 yyerror("interface %s already configured", 878 kif->ifname); 879 return (NULL); 880 } 881 882 i = if_new(kif); 883 i->passive = 0; 884 i->recv_query_resp_interval = DEFAULT_QUERY_RESP_INTERVAL; 885 886 return (i); 887 } 888 889 void 890 clear_config(struct dvmrpd_conf *xconf) 891 { 892 /* XXX clear conf */ 893 /* ... */ 894 } 895