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