1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Copyright (c) 2004-2006,2018 7 * Hartmut Brandt. 8 * All rights reserved. 9 * 10 * Author: Harti Brandt <harti@freebsd.org> 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $ 34 * 35 * Generate OID table from table description. 36 * 37 * Syntax is: 38 * --------- 39 * file := top | top file 40 * 41 * top := tree | typedef | include 42 * 43 * tree := head elements ')' 44 * 45 * entry := head ':' index STRING elements ')' 46 * 47 * leaf := head type STRING ACCESS ')' 48 * 49 * column := head type ACCESS ')' 50 * 51 * type := BASETYPE | BASETYPE '|' subtype | enum | bits 52 * 53 * subtype := STRING 54 * 55 * enum := ENUM '(' value ')' 56 * 57 * bits := BITS '(' value ')' 58 * 59 * value := optminus INT STRING | optminus INT STRING value 60 * 61 * optminus := '-' | EMPTY 62 * 63 * head := '(' INT STRING 64 * 65 * elements := EMPTY | elements element 66 * 67 * element := tree | leaf | column 68 * 69 * index := type | index type 70 * 71 * typedef := 'typedef' STRING type 72 * 73 * include := 'include' filespec 74 * 75 * filespec := '"' STRING '"' | '<' STRING '>' 76 */ 77 #include <sys/types.h> 78 #include <sys/param.h> 79 #include <stdio.h> 80 #include <stdlib.h> 81 #include <stdarg.h> 82 #include <unistd.h> 83 #include <string.h> 84 #include <ctype.h> 85 #include <inttypes.h> 86 #include <errno.h> 87 #ifdef HAVE_ERR_H 88 #include <err.h> 89 #endif 90 #include <sys/queue.h> 91 #include "support.h" 92 #include "asn1.h" 93 #include "snmp.h" 94 #include "snmpagent.h" 95 96 /* 97 * Constant prefix for all OIDs 98 */ 99 static const asn_subid_t prefix[] = { 1, 3, 6 }; 100 #define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) 101 102 u_int tree_size; 103 static const char *file_prefix = ""; 104 105 /* if true generate local include paths */ 106 static int localincs = 0; 107 108 /* if true print tokens */ 109 static int debug; 110 111 static const char usgtxt[] = "\ 112 Generate SNMP tables.\n\ 113 $Id$\n\ 114 usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ 115 [name]...\n\ 116 options:\n\ 117 -d debug mode\n\ 118 -E extract the named or all enums and bits only\n\ 119 -e extract the named oids or enums\n\ 120 -F generate functions for -E into a .c file\n\ 121 -f generate functions for -E into the header\n\ 122 -h print this info\n\ 123 -I directory add directory to include path\n\ 124 -i ifile read from the named file instead of stdin\n\ 125 -l generate local include directives\n\ 126 -p prefix prepend prefix to file and variable names\n\ 127 -t generate a .def file\n\ 128 "; 129 130 /* 131 * A node in the OID tree 132 */ 133 enum ntype { 134 NODE_LEAF = 1, 135 NODE_TREE, 136 NODE_ENTRY, 137 NODE_COLUMN 138 }; 139 140 enum { 141 FL_GET = 0x01, 142 FL_SET = 0x02, 143 }; 144 145 struct node; 146 TAILQ_HEAD(node_list, node); 147 148 struct node { 149 enum ntype type; 150 asn_subid_t id; /* last element of OID */ 151 char *name; /* name of node */ 152 TAILQ_ENTRY(node) link; 153 u_int lno; /* starting line number */ 154 u_int flags; /* allowed operations */ 155 156 union { 157 struct tree { 158 struct node_list subs; 159 } tree; 160 161 struct entry { 162 uint32_t index; /* index for table entry */ 163 char *func; /* function for tables */ 164 struct node_list subs; 165 } entry; 166 167 struct leaf { 168 enum snmp_syntax syntax; /* syntax for this leaf */ 169 char *func; /* function name */ 170 } leaf; 171 172 struct column { 173 enum snmp_syntax syntax; /* syntax for this column */ 174 } column; 175 } u; 176 }; 177 178 struct func { 179 const char *name; 180 LIST_ENTRY(func) link; 181 }; 182 183 static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); 184 185 struct enums { 186 const char *name; 187 long value; 188 TAILQ_ENTRY(enums) link; 189 }; 190 191 struct type { 192 const char *name; 193 const char *from_fname; 194 u_int from_lno; 195 u_int syntax; 196 int is_enum; 197 int is_bits; 198 TAILQ_HEAD(, enums) enums; 199 LIST_ENTRY(type) link; 200 }; 201 202 static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types); 203 204 static void report(const char *, ...) __dead2 __printflike(1, 2); 205 static void report_node(const struct node *, const char *, ...) 206 __dead2 __printflike(2, 3); 207 208 /************************************************************ 209 * 210 * Allocate memory and panic just in the case... 211 */ 212 static void * 213 xalloc(size_t size) 214 { 215 void *ptr; 216 217 if ((ptr = malloc(size)) == NULL) 218 err(1, "allocing %zu bytes", size); 219 220 return (ptr); 221 } 222 223 static char * 224 savestr(const char *s) 225 { 226 227 if (s == NULL) 228 return (NULL); 229 return (strcpy(xalloc(strlen(s) + 1), s)); 230 } 231 232 /************************************************************ 233 * 234 * Input stack 235 */ 236 struct input { 237 FILE *fp; 238 u_int lno; 239 char *fname; 240 char *path; 241 LIST_ENTRY(input) link; 242 }; 243 static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); 244 static struct input *input = NULL; 245 246 #define MAX_PATHS 100 247 static u_int npaths = 2; 248 static u_int stdpaths = 2; 249 static const char *paths[MAX_PATHS + 1] = { 250 "/usr/share/snmp/defs", 251 "/usr/local/share/snmp/defs", 252 NULL 253 }; 254 255 static int pbchar = -1; 256 257 static void 258 path_new(const char *path) 259 { 260 if (npaths >= MAX_PATHS) 261 report("too many -I directives"); 262 memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths], 263 sizeof(path[0]) * stdpaths); 264 paths[npaths - stdpaths] = savestr(path); 265 npaths++; 266 } 267 268 static void 269 input_new(FILE *fp, const char *path, const char *fname) 270 { 271 struct input *ip; 272 273 ip = xalloc(sizeof(*ip)); 274 ip->fp = fp; 275 ip->lno = 1; 276 ip->fname = savestr(fname); 277 ip->path = savestr(path); 278 LIST_INSERT_HEAD(&inputs, ip, link); 279 280 input = ip; 281 } 282 283 static void 284 input_close(void) 285 { 286 287 if (input == NULL) 288 return; 289 fclose(input->fp); 290 free(input->fname); 291 free(input->path); 292 LIST_REMOVE(input, link); 293 free(input); 294 295 input = LIST_FIRST(&inputs); 296 } 297 298 static FILE * 299 tryopen(const char *path, const char *fname) 300 { 301 char *fn; 302 FILE *fp; 303 304 if (path == NULL) 305 fn = savestr(fname); 306 else { 307 fn = xalloc(strlen(path) + strlen(fname) + 2); 308 sprintf(fn, "%s/%s", path, fname); 309 } 310 fp = fopen(fn, "r"); 311 free(fn); 312 return (fp); 313 } 314 315 static void 316 input_fopen(const char *fname, int loc) 317 { 318 FILE *fp; 319 char *path; 320 u_int p; 321 322 if (fname[0] == '/') { 323 if ((fp = tryopen(NULL, fname)) != NULL) { 324 input_new(fp, NULL, fname); 325 return; 326 } 327 328 } else { 329 if (loc) { 330 if (input == NULL) 331 path = NULL; 332 else 333 path = input->path; 334 335 if ((fp = tryopen(path, fname)) != NULL) { 336 input_new(fp, NULL, fname); 337 return; 338 } 339 } 340 341 for (p = 0; paths[p] != NULL; p++) 342 if ((fp = tryopen(paths[p], fname)) != NULL) { 343 input_new(fp, paths[p], fname); 344 return; 345 } 346 } 347 report("cannot open '%s'", fname); 348 } 349 350 static int 351 tgetc(void) 352 { 353 int c; 354 355 if (pbchar != -1) { 356 c = pbchar; 357 pbchar = -1; 358 return (c); 359 } 360 361 for (;;) { 362 if (input == NULL) 363 return (EOF); 364 365 if ((c = getc(input->fp)) != EOF) 366 return (c); 367 368 input_close(); 369 } 370 } 371 372 static void 373 tungetc(int c) 374 { 375 376 if (pbchar != -1) 377 abort(); 378 pbchar = c; 379 } 380 381 /************************************************************ 382 * 383 * Parsing input 384 */ 385 enum tok { 386 TOK_EOF = 0200, /* end-of-file seen */ 387 TOK_NUM, /* number */ 388 TOK_STR, /* string */ 389 TOK_ACCESS, /* access operator */ 390 TOK_TYPE, /* type operator */ 391 TOK_ENUM, /* enum token (kind of a type) */ 392 TOK_TYPEDEF, /* typedef directive */ 393 TOK_DEFTYPE, /* defined type */ 394 TOK_INCLUDE, /* include directive */ 395 TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */ 396 TOK_BITS, /* bits token (kind of a type) */ 397 }; 398 399 static const struct { 400 const char *str; 401 enum tok tok; 402 u_int val; 403 } keywords[] = { 404 { "GET", TOK_ACCESS, FL_GET }, 405 { "SET", TOK_ACCESS, FL_SET }, 406 { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 407 { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 408 { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 409 { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 410 { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 411 { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 412 { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 413 { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 414 { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 415 { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 416 { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 417 { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, 418 { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, 419 { "typedef", TOK_TYPEDEF, 0 }, 420 { "include", TOK_INCLUDE, 0 }, 421 { NULL, 0, 0 } 422 }; 423 424 /* arbitrary upper limit on node names and function names */ 425 #define MAXSTR 1000 426 static char str[MAXSTR]; 427 static u_long val; /* integer values */ 428 static int saved_token = -1; 429 430 /* 431 * Report an error and exit. 432 */ 433 static void 434 report(const char *fmt, ...) 435 { 436 va_list ap; 437 int c; 438 439 va_start(ap, fmt); 440 fprintf(stderr, "line %u: ", input->lno); 441 vfprintf(stderr, fmt, ap); 442 fprintf(stderr, "\n"); 443 fprintf(stderr, "context: \""); 444 while ((c = tgetc()) != EOF && c != '\n') 445 fprintf(stderr, "%c", c); 446 fprintf(stderr, "\n"); 447 va_end(ap); 448 exit(1); 449 } 450 static void 451 report_node(const struct node *np, const char *fmt, ...) 452 { 453 va_list ap; 454 455 va_start(ap, fmt); 456 fprintf(stderr, "line %u, node %s: ", np->lno, np->name); 457 vfprintf(stderr, fmt, ap); 458 fprintf(stderr, "\n"); 459 va_end(ap); 460 exit(1); 461 } 462 463 /* 464 * Return a fresh copy of the string constituting the current token. 465 */ 466 static char * 467 savetok(void) 468 { 469 return (savestr(str)); 470 } 471 472 /* 473 * Get the next token from input. 474 */ 475 static int 476 gettoken_internal(void) 477 { 478 int c; 479 struct type *t; 480 481 if (saved_token != -1) { 482 c = saved_token; 483 saved_token = -1; 484 return (c); 485 } 486 487 again: 488 /* 489 * Skip any whitespace before the next token 490 */ 491 while ((c = tgetc()) != EOF) { 492 if (c == '\n') 493 input->lno++; 494 if (!isspace(c)) 495 break; 496 } 497 if (c == EOF) 498 return (TOK_EOF); 499 if (!isascii(c)) 500 report("unexpected character %#2x", (u_int)c); 501 502 /* 503 * Skip comments 504 */ 505 if (c == '#') { 506 while ((c = tgetc()) != EOF) { 507 if (c == '\n') { 508 input->lno++; 509 goto again; 510 } 511 } 512 report("unexpected EOF in comment"); 513 } 514 515 /* 516 * Single character tokens 517 */ 518 if (strchr("():|-", c) != NULL) 519 return (c); 520 521 if (c == '"' || c == '<') { 522 int end = c; 523 size_t n = 0; 524 525 val = 1; 526 if (c == '<') { 527 val = 0; 528 end = '>'; 529 } 530 531 while ((c = tgetc()) != EOF) { 532 if (c == end) 533 break; 534 if (n == sizeof(str) - 1) { 535 str[n++] = '\0'; 536 report("filename too long '%s...'", str); 537 } 538 str[n++] = c; 539 } 540 str[n++] = '\0'; 541 return (TOK_FILENAME); 542 } 543 544 /* 545 * Sort out numbers 546 */ 547 if (isdigit(c)) { 548 size_t n = 0; 549 str[n++] = c; 550 while ((c = tgetc()) != EOF) { 551 if (!isdigit(c)) { 552 tungetc(c); 553 break; 554 } 555 if (n == sizeof(str) - 1) { 556 str[n++] = '\0'; 557 report("number too long '%s...'", str); 558 } 559 str[n++] = c; 560 } 561 str[n++] = '\0'; 562 sscanf(str, "%lu", &val); 563 return (TOK_NUM); 564 } 565 566 /* 567 * So that has to be a string. 568 */ 569 if (isalpha(c) || c == '_') { 570 size_t n = 0; 571 str[n++] = c; 572 while ((c = tgetc()) != EOF) { 573 if (!isalnum(c) && c != '_' && c != '-') { 574 tungetc(c); 575 break; 576 } 577 if (n == sizeof(str) - 1) { 578 str[n++] = '\0'; 579 report("string too long '%s...'", str); 580 } 581 str[n++] = c; 582 } 583 str[n++] = '\0'; 584 585 /* 586 * Keywords 587 */ 588 for (c = 0; keywords[c].str != NULL; c++) 589 if (strcmp(keywords[c].str, str) == 0) { 590 val = keywords[c].val; 591 return (keywords[c].tok); 592 } 593 594 LIST_FOREACH(t, &types, link) { 595 if (strcmp(t->name, str) == 0) { 596 val = t->syntax; 597 return (TOK_DEFTYPE); 598 } 599 } 600 return (TOK_STR); 601 } 602 if (isprint(c)) 603 errx(1, "%u: unexpected character '%c'", input->lno, c); 604 else 605 errx(1, "%u: unexpected character 0x%02x", input->lno, 606 (u_int)c); 607 } 608 static int 609 gettoken(void) 610 { 611 int tok = gettoken_internal(); 612 613 if (debug) { 614 switch (tok) { 615 616 case TOK_EOF: 617 fprintf(stderr, "EOF "); 618 break; 619 620 case TOK_NUM: 621 fprintf(stderr, "NUM(%lu) ", val); 622 break; 623 624 case TOK_STR: 625 fprintf(stderr, "STR(%s) ", str); 626 break; 627 628 case TOK_ACCESS: 629 fprintf(stderr, "ACCESS(%lu) ", val); 630 break; 631 632 case TOK_TYPE: 633 fprintf(stderr, "TYPE(%lu) ", val); 634 break; 635 636 case TOK_ENUM: 637 fprintf(stderr, "ENUM "); 638 break; 639 640 case TOK_BITS: 641 fprintf(stderr, "BITS "); 642 break; 643 644 case TOK_TYPEDEF: 645 fprintf(stderr, "TYPEDEF "); 646 break; 647 648 case TOK_DEFTYPE: 649 fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val); 650 break; 651 652 case TOK_INCLUDE: 653 fprintf(stderr, "INCLUDE "); 654 break; 655 656 case TOK_FILENAME: 657 fprintf(stderr, "FILENAME "); 658 break; 659 660 default: 661 if (tok < TOK_EOF) { 662 if (isprint(tok)) 663 fprintf(stderr, "'%c' ", tok); 664 else if (tok == '\n') 665 fprintf(stderr, "\n"); 666 else 667 fprintf(stderr, "%02x ", tok); 668 } else 669 abort(); 670 break; 671 } 672 } 673 return (tok); 674 } 675 676 /** 677 * Pushback a token 678 */ 679 static void 680 pushback(enum tok tok) 681 { 682 683 if (saved_token != -1) 684 abort(); 685 saved_token = tok; 686 } 687 688 /* 689 * Create a new type 690 */ 691 static struct type * 692 make_type(const char *s) 693 { 694 struct type *t; 695 696 t = xalloc(sizeof(*t)); 697 t->name = savestr(s); 698 t->is_enum = 0; 699 t->syntax = SNMP_SYNTAX_NULL; 700 t->from_fname = savestr(input->fname); 701 t->from_lno = input->lno; 702 TAILQ_INIT(&t->enums); 703 LIST_INSERT_HEAD(&types, t, link); 704 705 return (t); 706 } 707 708 /* 709 * Parse a type. We've seen the ENUM or type keyword already. Leave next 710 * token. 711 */ 712 static u_int 713 parse_type(enum tok *tok, struct type *t, const char *vname) 714 { 715 u_int syntax; 716 struct enums *e; 717 718 syntax = val; 719 720 if (*tok == TOK_ENUM || *tok == TOK_BITS) { 721 if (t == NULL && vname != NULL) { 722 t = make_type(vname); 723 t->is_enum = (*tok == TOK_ENUM); 724 t->is_bits = (*tok == TOK_BITS); 725 t->syntax = syntax; 726 } 727 if (gettoken() != '(') 728 report("'(' expected after ENUM"); 729 730 if ((*tok = gettoken()) == TOK_EOF) 731 report("unexpected EOF in ENUM"); 732 do { 733 e = NULL; 734 if (t != NULL) { 735 e = xalloc(sizeof(*e)); 736 } 737 if (*tok == '-') { 738 if ((*tok = gettoken()) == TOK_EOF) 739 report("unexpected EOF in ENUM"); 740 e->value = -(long)val; 741 } else 742 e->value = val; 743 744 if (*tok != TOK_NUM) 745 report("need value for ENUM/BITS"); 746 if (gettoken() != TOK_STR) 747 report("need string in ENUM/BITS"); 748 e->name = savetok(); 749 TAILQ_INSERT_TAIL(&t->enums, e, link); 750 if ((*tok = gettoken()) == TOK_EOF) 751 report("unexpected EOF in ENUM/BITS"); 752 } while (*tok != ')'); 753 *tok = gettoken(); 754 755 } else if (*tok == TOK_DEFTYPE) { 756 *tok = gettoken(); 757 758 } else { 759 if ((*tok = gettoken()) == '|') { 760 if (gettoken() != TOK_STR) 761 report("subtype expected after '|'"); 762 *tok = gettoken(); 763 } 764 } 765 766 return (syntax); 767 } 768 769 /* 770 * Parse the next node (complete with all subnodes) 771 */ 772 static struct node * 773 parse(enum tok tok) 774 { 775 struct node *node; 776 struct node *sub; 777 u_int index_count; 778 779 node = xalloc(sizeof(struct node)); 780 node->lno = input->lno; 781 node->flags = 0; 782 783 if (tok != '(') 784 report("'(' expected at begin of node"); 785 if (gettoken() != TOK_NUM) 786 report("node id expected after opening '('"); 787 if (val > ASN_MAXID) 788 report("subid too large '%lu'", val); 789 node->id = (asn_subid_t)val; 790 if (gettoken() != TOK_STR) 791 report("node name expected after '(' ID"); 792 node->name = savetok(); 793 794 if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || 795 tok == TOK_ENUM || tok == TOK_BITS) { 796 /* LEAF or COLUM */ 797 u_int syntax = parse_type(&tok, NULL, node->name); 798 799 if (tok == TOK_STR) { 800 /* LEAF */ 801 node->type = NODE_LEAF; 802 node->u.leaf.func = savetok(); 803 node->u.leaf.syntax = syntax; 804 tok = gettoken(); 805 } else { 806 /* COLUMN */ 807 node->type = NODE_COLUMN; 808 node->u.column.syntax = syntax; 809 } 810 811 while (tok != ')') { 812 if (tok != TOK_ACCESS) 813 report("access keyword or ')' expected"); 814 node->flags |= (u_int)val; 815 tok = gettoken(); 816 } 817 818 } else if (tok == ':') { 819 /* ENTRY */ 820 node->type = NODE_ENTRY; 821 TAILQ_INIT(&node->u.entry.subs); 822 823 index_count = 0; 824 node->u.entry.index = 0; 825 tok = gettoken(); 826 while (tok == TOK_TYPE || tok == TOK_DEFTYPE || 827 tok == TOK_ENUM || tok == TOK_BITS) { 828 u_int syntax = parse_type(&tok, NULL, node->name); 829 if (index_count++ == SNMP_INDEXES_MAX) 830 report("too many table indexes"); 831 node->u.entry.index |= 832 syntax << (SNMP_INDEX_SHIFT * index_count); 833 } 834 node->u.entry.index |= index_count; 835 if (index_count == 0) 836 report("need at least one index"); 837 if (tok != TOK_STR) 838 report("function name expected"); 839 840 node->u.entry.func = savetok(); 841 842 tok = gettoken(); 843 844 while (tok != ')') { 845 sub = parse(tok); 846 TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); 847 tok = gettoken(); 848 } 849 850 } else { 851 /* subtree */ 852 node->type = NODE_TREE; 853 TAILQ_INIT(&node->u.tree.subs); 854 855 while (tok != ')') { 856 sub = parse(tok); 857 TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); 858 tok = gettoken(); 859 } 860 } 861 return (node); 862 } 863 864 /* 865 * Parse a top level element. Return the tree if it was a tree, NULL 866 * otherwise. 867 */ 868 static struct node * 869 parse_top(enum tok tok) 870 { 871 struct type *t; 872 873 if (tok == '(') 874 return (parse(tok)); 875 876 if (tok == TOK_TYPEDEF) { 877 if (gettoken() != TOK_STR) 878 report("type name expected after typedef"); 879 880 t = make_type(str); 881 882 tok = gettoken(); 883 t->is_enum = (tok == TOK_ENUM); 884 t->is_bits = (tok == TOK_BITS); 885 t->syntax = parse_type(&tok, t, NULL); 886 pushback(tok); 887 888 return (NULL); 889 } 890 891 if (tok == TOK_INCLUDE) { 892 if (gettoken() != TOK_FILENAME) 893 report("filename expected in include directive"); 894 895 input_fopen(str, val); 896 return (NULL); 897 } 898 899 report("'(' or 'typedef' expected"); 900 } 901 902 /* 903 * Generate the C-code table part for one node. 904 */ 905 static void 906 gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, 907 const char *func) 908 { 909 u_int n; 910 struct node *sub; 911 u_int syntax; 912 913 if (oid->len == ASN_MAXOIDLEN) 914 report_node(np, "OID too long"); 915 oid->subs[oid->len++] = np->id; 916 917 if (np->type == NODE_TREE) { 918 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 919 gen_node(fp, sub, oid, 0, NULL); 920 oid->len--; 921 return; 922 } 923 if (np->type == NODE_ENTRY) { 924 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 925 gen_node(fp, sub, oid, np->u.entry.index, 926 np->u.entry.func); 927 oid->len--; 928 return; 929 } 930 931 /* leaf or column */ 932 if ((np->flags & (FL_GET|FL_SET)) == 0) { 933 oid->len--; 934 return; 935 } 936 937 fprintf(fp, " {{ %u, {", oid->len); 938 for (n = 0; n < oid->len; n++) 939 fprintf(fp, " %u,", oid->subs[n]); 940 fprintf(fp, " }}, \"%s\", ", np->name); 941 942 if (np->type == NODE_COLUMN) { 943 syntax = np->u.column.syntax; 944 fprintf(fp, "SNMP_NODE_COLUMN, "); 945 } else { 946 syntax = np->u.leaf.syntax; 947 fprintf(fp, "SNMP_NODE_LEAF, "); 948 } 949 950 switch (syntax) { 951 952 case SNMP_SYNTAX_NULL: 953 fprintf(fp, "SNMP_SYNTAX_NULL, "); 954 break; 955 956 case SNMP_SYNTAX_INTEGER: 957 fprintf(fp, "SNMP_SYNTAX_INTEGER, "); 958 break; 959 960 case SNMP_SYNTAX_OCTETSTRING: 961 fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); 962 break; 963 964 case SNMP_SYNTAX_IPADDRESS: 965 fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); 966 break; 967 968 case SNMP_SYNTAX_OID: 969 fprintf(fp, "SNMP_SYNTAX_OID, "); 970 break; 971 972 case SNMP_SYNTAX_TIMETICKS: 973 fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); 974 break; 975 976 case SNMP_SYNTAX_COUNTER: 977 fprintf(fp, "SNMP_SYNTAX_COUNTER, "); 978 break; 979 980 case SNMP_SYNTAX_GAUGE: 981 fprintf(fp, "SNMP_SYNTAX_GAUGE, "); 982 break; 983 984 case SNMP_SYNTAX_COUNTER64: 985 fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); 986 break; 987 988 case SNMP_SYNTAX_NOSUCHOBJECT: 989 case SNMP_SYNTAX_NOSUCHINSTANCE: 990 case SNMP_SYNTAX_ENDOFMIBVIEW: 991 abort(); 992 } 993 994 if (np->type == NODE_COLUMN) 995 fprintf(fp, "%s, ", func); 996 else 997 fprintf(fp, "%s, ", np->u.leaf.func); 998 999 fprintf(fp, "0"); 1000 if (np->flags & FL_SET) 1001 fprintf(fp, "|SNMP_NODE_CANSET"); 1002 fprintf(fp, ", %#x, NULL, NULL },\n", idx); 1003 oid->len--; 1004 return; 1005 } 1006 1007 /* 1008 * Generate the header file with the function declarations. 1009 */ 1010 static void 1011 gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) 1012 { 1013 char f[MAXSTR + 4]; 1014 struct node *sub; 1015 struct func *ptr; 1016 1017 oidlen++; 1018 if (np->type == NODE_TREE) { 1019 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1020 gen_header(fp, sub, oidlen, NULL); 1021 return; 1022 } 1023 if (np->type == NODE_ENTRY) { 1024 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1025 gen_header(fp, sub, oidlen, np->u.entry.func); 1026 return; 1027 } 1028 1029 if((np->flags & (FL_GET|FL_SET)) == 0) 1030 return; 1031 1032 if (np->type == NODE_COLUMN) { 1033 if (func == NULL) 1034 errx(1, "column without function (%s) - probably " 1035 "outside of a table", np->name); 1036 sprintf(f, "%s", func); 1037 } else 1038 sprintf(f, "%s", np->u.leaf.func); 1039 1040 LIST_FOREACH(ptr, &funcs, link) 1041 if (strcmp(ptr->name, f) == 0) 1042 break; 1043 1044 if (ptr == NULL) { 1045 ptr = xalloc(sizeof(*ptr)); 1046 ptr->name = savestr(f); 1047 LIST_INSERT_HEAD(&funcs, ptr, link); 1048 1049 fprintf(fp, "int %s(struct snmp_context *, " 1050 "struct snmp_value *, u_int, u_int, " 1051 "enum snmp_op);\n", f); 1052 } 1053 1054 fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); 1055 } 1056 1057 /* 1058 * Generate the OID table. 1059 */ 1060 static void 1061 gen_table(FILE *fp, struct node *node) 1062 { 1063 struct asn_oid oid; 1064 1065 fprintf(fp, "#include <sys/types.h>\n"); 1066 fprintf(fp, "#include <stdio.h>\n"); 1067 #ifdef HAVE_STDINT_H 1068 fprintf(fp, "#include <stdint.h>\n"); 1069 #endif 1070 fprintf(fp, "#include <string.h>\n"); 1071 if (localincs) { 1072 fprintf(fp, "#include \"asn1.h\"\n"); 1073 fprintf(fp, "#include \"snmp.h\"\n"); 1074 fprintf(fp, "#include \"snmpagent.h\"\n"); 1075 } else { 1076 fprintf(fp, "#include <bsnmp/asn1.h>\n"); 1077 fprintf(fp, "#include <bsnmp/snmp.h>\n"); 1078 fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); 1079 } 1080 fprintf(fp, "#include \"%stree.h\"\n", file_prefix); 1081 fprintf(fp, "\n"); 1082 1083 fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); 1084 1085 oid.len = PREFIX_LEN; 1086 memcpy(oid.subs, prefix, sizeof(prefix)); 1087 gen_node(fp, node, &oid, 0, NULL); 1088 1089 fprintf(fp, "};\n\n"); 1090 } 1091 1092 static void 1093 print_syntax(u_int syntax) 1094 { 1095 u_int i; 1096 1097 for (i = 0; keywords[i].str != NULL; i++) 1098 if (keywords[i].tok == TOK_TYPE && 1099 keywords[i].val == syntax) { 1100 printf(" %s", keywords[i].str); 1101 return; 1102 } 1103 abort(); 1104 } 1105 1106 /* 1107 * Generate a tree definition file 1108 */ 1109 static void 1110 gen_tree(const struct node *np, int level) 1111 { 1112 const struct node *sp; 1113 u_int i; 1114 1115 printf("%*s(%u %s", 2 * level, "", np->id, np->name); 1116 1117 switch (np->type) { 1118 1119 case NODE_LEAF: 1120 print_syntax(np->u.leaf.syntax); 1121 printf(" %s%s%s)\n", np->u.leaf.func, 1122 (np->flags & FL_GET) ? " GET" : "", 1123 (np->flags & FL_SET) ? " SET" : ""); 1124 break; 1125 1126 case NODE_TREE: 1127 if (TAILQ_EMPTY(&np->u.tree.subs)) { 1128 printf(")\n"); 1129 } else { 1130 printf("\n"); 1131 TAILQ_FOREACH(sp, &np->u.tree.subs, link) 1132 gen_tree(sp, level + 1); 1133 printf("%*s)\n", 2 * level, ""); 1134 } 1135 break; 1136 1137 case NODE_ENTRY: 1138 printf(" :"); 1139 1140 for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) 1141 print_syntax(SNMP_INDEX(np->u.entry.index, i)); 1142 printf(" %s\n", np->u.entry.func); 1143 TAILQ_FOREACH(sp, &np->u.entry.subs, link) 1144 gen_tree(sp, level + 1); 1145 printf("%*s)\n", 2 * level, ""); 1146 break; 1147 1148 case NODE_COLUMN: 1149 print_syntax(np->u.column.syntax); 1150 printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", 1151 (np->flags & FL_SET) ? " SET" : ""); 1152 break; 1153 } 1154 } 1155 1156 static int 1157 extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj, 1158 const struct asn_oid *idx, const char *iname) 1159 { 1160 struct node *sub; 1161 u_long n; 1162 1163 if (oid->len == ASN_MAXOIDLEN) 1164 report_node(np, "OID too long"); 1165 oid->subs[oid->len++] = np->id; 1166 1167 if (strcmp(obj, np->name) == 0) { 1168 if (oid->len + idx->len >= ASN_MAXOIDLEN) 1169 report_node(np, "OID too long"); 1170 fprintf(fp, "#define OID_%s%s\t%u\n", np->name, 1171 iname ? iname : "", np->id); 1172 fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, 1173 iname ? iname : "", oid->len + idx->len); 1174 fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, 1175 iname ? iname : "", oid->len + idx->len); 1176 for (n = 0; n < oid->len; n++) 1177 fprintf(fp, " %u,", oid->subs[n]); 1178 for (n = 0; n < idx->len; n++) 1179 fprintf(fp, " %u,", idx->subs[n]); 1180 fprintf(fp, " } }\n"); 1181 return (0); 1182 } 1183 1184 if (np->type == NODE_TREE) { 1185 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1186 if (!extract(fp, sub, oid, obj, idx, iname)) 1187 return (0); 1188 } else if (np->type == NODE_ENTRY) { 1189 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1190 if (!extract(fp, sub, oid, obj, idx, iname)) 1191 return (0); 1192 } 1193 oid->len--; 1194 return (1); 1195 } 1196 1197 /** 1198 * Extract the named OID. 1199 * 1200 * \param fp file to extract to 1201 * \param root root of the tree 1202 * \param object name of the object to extract 1203 * 1204 * \return 0 on success, -1 if the object was not found 1205 */ 1206 static int 1207 gen_extract(FILE *fp, const struct node *root, char *object) 1208 { 1209 struct asn_oid oid; 1210 struct asn_oid idx; 1211 char *s, *e, *end, *iname; 1212 u_long ul; 1213 int ret; 1214 1215 /* look whether the object to extract has an index part */ 1216 idx.len = 0; 1217 iname = NULL; 1218 s = strchr(object, '.'); 1219 if (s != NULL) { 1220 iname = malloc(strlen(s) + 1); 1221 if (iname == NULL) 1222 err(1, "cannot allocated index"); 1223 1224 strcpy(iname, s); 1225 for (e = iname; *e != '\0'; e++) 1226 if (*e == '.') 1227 *e = '_'; 1228 1229 *s++ = '\0'; 1230 while (s != NULL) { 1231 if (*s == '\0') 1232 errx(1, "bad index syntax"); 1233 if ((e = strchr(s, '.')) != NULL) 1234 *e++ = '\0'; 1235 1236 errno = 0; 1237 ul = strtoul(s, &end, 0); 1238 if (*end != '\0') 1239 errx(1, "bad index syntax '%s'", end); 1240 if (errno != 0) 1241 err(1, "bad index syntax"); 1242 1243 if (idx.len == ASN_MAXOIDLEN) 1244 errx(1, "index oid too large"); 1245 idx.subs[idx.len++] = ul; 1246 1247 s = e; 1248 } 1249 } 1250 1251 oid.len = PREFIX_LEN; 1252 memcpy(oid.subs, prefix, sizeof(prefix)); 1253 ret = extract(fp, root, &oid, object, &idx, iname); 1254 if (iname != NULL) 1255 free(iname); 1256 1257 return (ret); 1258 } 1259 1260 1261 static void 1262 check_sub_order(const struct node *np, const struct node_list *subs) 1263 { 1264 int first; 1265 const struct node *sub; 1266 asn_subid_t maxid = 0; 1267 1268 /* ensure, that subids are ordered */ 1269 first = 1; 1270 TAILQ_FOREACH(sub, subs, link) { 1271 if (!first && sub->id <= maxid) 1272 report_node(np, "subids not ordered at %s", sub->name); 1273 maxid = sub->id; 1274 first = 0; 1275 } 1276 } 1277 1278 /* 1279 * Do some sanity checks on the tree definition and do some computations. 1280 */ 1281 static void 1282 check_tree(struct node *np) 1283 { 1284 struct node *sub; 1285 1286 if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { 1287 if ((np->flags & (FL_GET|FL_SET)) != 0) 1288 tree_size++; 1289 return; 1290 } 1291 1292 if (np->type == NODE_ENTRY) { 1293 check_sub_order(np, &np->u.entry.subs); 1294 1295 /* ensure all subnodes are columns */ 1296 TAILQ_FOREACH(sub, &np->u.entry.subs, link) { 1297 if (sub->type != NODE_COLUMN) 1298 report_node(np, "entry subnode '%s' is not " 1299 "a column", sub->name); 1300 check_tree(sub); 1301 } 1302 } else { 1303 check_sub_order(np, &np->u.tree.subs); 1304 1305 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1306 check_tree(sub); 1307 } 1308 } 1309 1310 static void 1311 merge_subs(struct node_list *s1, struct node_list *s2) 1312 { 1313 struct node *n1, *n2; 1314 1315 while (!TAILQ_EMPTY(s2)) { 1316 n2 = TAILQ_FIRST(s2); 1317 TAILQ_REMOVE(s2, n2, link); 1318 1319 TAILQ_FOREACH(n1, s1, link) 1320 if (n1->id >= n2->id) 1321 break; 1322 if (n1 == NULL) 1323 TAILQ_INSERT_TAIL(s1, n2, link); 1324 else if (n1->id > n2->id) 1325 TAILQ_INSERT_BEFORE(n1, n2, link); 1326 else { 1327 if (n1->type == NODE_TREE && n2->type == NODE_TREE) { 1328 if (strcmp(n1->name, n2->name) != 0) 1329 errx(1, "trees to merge must have " 1330 "same name '%s' '%s'", n1->name, 1331 n2->name); 1332 merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); 1333 free(n2); 1334 } else if (n1->type == NODE_ENTRY && 1335 n2->type == NODE_ENTRY) { 1336 if (strcmp(n1->name, n2->name) != 0) 1337 errx(1, "entries to merge must have " 1338 "same name '%s' '%s'", n1->name, 1339 n2->name); 1340 if (n1->u.entry.index != n2->u.entry.index) 1341 errx(1, "entries to merge must have " 1342 "same index '%s'", n1->name); 1343 if (strcmp(n1->u.entry.func, 1344 n2->u.entry.func) != 0) 1345 errx(1, "entries to merge must have " 1346 "same op '%s'", n1->name); 1347 merge_subs(&n1->u.entry.subs, 1348 &n2->u.entry.subs); 1349 free(n2); 1350 } else 1351 errx(1, "entities to merge must be both " 1352 "trees or both entries: %s, %s", 1353 n1->name, n2->name); 1354 } 1355 } 1356 } 1357 1358 static void 1359 merge(struct node **root, struct node *t) 1360 { 1361 1362 if (*root == NULL) { 1363 *root = t; 1364 return; 1365 } 1366 if (t == NULL) 1367 return; 1368 1369 /* both must be trees */ 1370 if ((*root)->type != NODE_TREE) 1371 errx(1, "root is not a tree"); 1372 if (t->type != NODE_TREE) 1373 errx(1, "can merge only with tree"); 1374 if ((*root)->id != t->id) 1375 errx(1, "trees to merge must have same id"); 1376 1377 merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs); 1378 } 1379 1380 static void 1381 unminus(FILE *fp, const char *s) 1382 { 1383 1384 while (*s != '\0') { 1385 if (*s == '-') 1386 fprintf(fp, "_"); 1387 else 1388 fprintf(fp, "%c", *s); 1389 s++; 1390 } 1391 } 1392 1393 /** 1394 * Generate a definition for the enum packed into a guard against multiple 1395 * definitions. 1396 * 1397 * \param fp file to write definition to 1398 * \param t type 1399 */ 1400 static void 1401 gen_enum(FILE *fp, const struct type *t) 1402 { 1403 const struct enums *e; 1404 long min = LONG_MAX; 1405 1406 fprintf(fp, "\n"); 1407 fprintf(fp, "#ifndef %s_defined__\n", t->name); 1408 fprintf(fp, "#define %s_defined__\n", t->name); 1409 fprintf(fp, "/*\n"); 1410 fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); 1411 fprintf(fp, " */\n"); 1412 fprintf(fp, "enum %s {\n", t->name); 1413 TAILQ_FOREACH(e, &t->enums, link) { 1414 fprintf(fp, "\t%s_", t->name); 1415 unminus(fp, e->name); 1416 fprintf(fp, " = %ld,\n", e->value); 1417 if (e->value < min) 1418 min = e->value; 1419 } 1420 fprintf(fp, "};\n"); 1421 fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); 1422 fprintf(fp, "#define STRING_%s \\\n", t->name); 1423 TAILQ_FOREACH(e, &t->enums, link) { 1424 fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name); 1425 unminus(fp, e->name); 1426 fprintf(fp, "\",\\\n"); 1427 } 1428 fprintf(fp, "\n"); 1429 fprintf(fp, "#endif /* %s_defined__ */\n", t->name); 1430 } 1431 1432 /** 1433 * Generate helper functions for an enum. 1434 * 1435 * We always generate a switch statement for the isok function. The compiler 1436 * optimizes this into range checks if possible. 1437 * 1438 * \param fp file to write to 1439 * \param t type 1440 * \param ccode generate externally visible non-inline functions 1441 */ 1442 static void 1443 gen_enum_funcs(FILE *fp, const struct type *t, int ccode) 1444 { 1445 fprintf(fp, "\n"); 1446 1447 if (!ccode) 1448 fprintf(fp, "static inline "); 1449 fprintf(fp, "int\n"); 1450 fprintf(fp, "isok_%s(enum %s s)\n", t->name, t->name); 1451 fprintf(fp, "{\n"); 1452 fprintf(fp, " switch (s) {\n"); 1453 1454 const struct enums *e; 1455 TAILQ_FOREACH(e, &t->enums, link) { 1456 fprintf(fp, "\t case %s_", t->name); 1457 unminus(fp, e->name); 1458 fprintf(fp, ":\n"); 1459 } 1460 1461 fprintf(fp, " return (1);\n"); 1462 fprintf(fp, " }\n"); 1463 fprintf(fp, " return (0);\n"); 1464 fprintf(fp, "}\n\n"); 1465 1466 if (!ccode) 1467 fprintf(fp, "static inline "); 1468 fprintf(fp, "const char *\n"); 1469 fprintf(fp, "tostr_%s(enum %s s)\n", t->name, t->name); 1470 fprintf(fp, "{\n"); 1471 fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name); 1472 fprintf(fp, "\n"); 1473 fprintf(fp, " if (isok_%s(s))\n", t->name); 1474 fprintf(fp, " return (vals[(int)s - STROFF_%s]);\n", t->name); 1475 fprintf(fp, " return (\"%s???\");\n", t->name); 1476 fprintf(fp, "}\n\n"); 1477 1478 if (!ccode) 1479 fprintf(fp, "static inline "); 1480 fprintf(fp, "int\n"); 1481 fprintf(fp, "fromstr_%s(const char *str, enum %s *s)\n", 1482 t->name, t->name); 1483 fprintf(fp, "{\n"); 1484 fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name); 1485 fprintf(fp, "\n"); 1486 fprintf(fp, " for (size_t i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {\n"); 1487 fprintf(fp, " if (vals[i] != NULL && strcmp(vals[i], str) == 0) {\n"); 1488 fprintf(fp, " *s = i + STROFF_%s;\n", t->name); 1489 fprintf(fp, " return (1);\n"); 1490 fprintf(fp, " }\n"); 1491 fprintf(fp, " }\n"); 1492 fprintf(fp, " return (0);\n"); 1493 fprintf(fp, "}\n"); 1494 } 1495 1496 /** 1497 * Generate helper functions for an enum. This generates code for a c file. 1498 * 1499 * \param fp file to write to 1500 * \param name enum name 1501 */ 1502 static int 1503 gen_enum_funcs_str(FILE *fp, const char *name) 1504 { 1505 const struct type *t; 1506 1507 LIST_FOREACH(t, &types, link) 1508 if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { 1509 gen_enum_funcs(fp, t, 1); 1510 return (0); 1511 } 1512 1513 return (-1); 1514 } 1515 1516 /** 1517 * Generate helper functions for all enums. 1518 * 1519 * \param fp file to write to 1520 * \param ccode generate externally visible non-inline functions 1521 */ 1522 static void 1523 gen_all_enum_funcs(FILE *fp, int ccode) 1524 { 1525 const struct type *t; 1526 1527 LIST_FOREACH(t, &types, link) 1528 if (t->is_enum || t->is_bits) 1529 gen_enum_funcs(fp, t, ccode); 1530 } 1531 1532 /** 1533 * Extract a given enum to the specified file and optionally generate static 1534 * inline helper functions for them. 1535 * 1536 * \param fp file to print on 1537 * \param name name of the enum 1538 * \param gen_funcs generate the functions too 1539 * 1540 * \return 0 if found, -1 otherwise 1541 */ 1542 static int 1543 extract_enum(FILE *fp, const char *name, int gen_funcs) 1544 { 1545 const struct type *t; 1546 1547 LIST_FOREACH(t, &types, link) 1548 if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { 1549 gen_enum(fp, t); 1550 if (gen_funcs) 1551 gen_enum_funcs(fp, t, 0); 1552 return (0); 1553 } 1554 return (-1); 1555 } 1556 1557 /** 1558 * Extract all enums to the given file and optionally generate static inline 1559 * helper functions for them. 1560 * 1561 * \param fp file to print on 1562 * \param gen_funcs generate the functions too 1563 */ 1564 static void 1565 extract_all_enums(FILE *fp, int gen_funcs) 1566 { 1567 const struct type *t; 1568 1569 LIST_FOREACH(t, &types, link) 1570 if (t->is_enum || t->is_bits) { 1571 gen_enum(fp, t); 1572 if (gen_funcs) 1573 gen_enum_funcs(fp, t, 0); 1574 } 1575 } 1576 1577 /** 1578 * Extract enums and optionally generate some helper functions for them. 1579 * 1580 * \param argc number of arguments 1581 * \param argv arguments (enum names) 1582 * \param gen_funcs_h generate functions into the header file 1583 * \param gen_funcs_c generate a .c file with functions 1584 */ 1585 static void 1586 make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c) 1587 { 1588 if (gen_funcs_c) { 1589 if (argc == 0) 1590 gen_all_enum_funcs(stdout, 1); 1591 else { 1592 for (int i = 0; i < argc; i++) 1593 if (gen_enum_funcs_str(stdout, argv[i])) 1594 errx(1, "enum not found: %s", argv[i]); 1595 } 1596 } else { 1597 if (argc == 0) 1598 extract_all_enums(stdout, gen_funcs_h); 1599 else { 1600 for (int i = 0; i < argc; i++) 1601 if (extract_enum(stdout, argv[i], gen_funcs_h)) 1602 errx(1, "enum not found: %s", argv[i]); 1603 } 1604 } 1605 } 1606 1607 int 1608 main(int argc, char *argv[]) 1609 { 1610 int do_extract = 0; 1611 int do_tree = 0; 1612 int do_enums = 0; 1613 int gen_funcs_h = 0; 1614 int gen_funcs_c = 0; 1615 int opt; 1616 struct node *root; 1617 char fname[MAXPATHLEN + 1]; 1618 int tok; 1619 FILE *fp; 1620 char *infile = NULL; 1621 1622 while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) 1623 switch (opt) { 1624 1625 case 'd': 1626 debug = 1; 1627 break; 1628 1629 case 'E': 1630 do_enums = 1; 1631 break; 1632 1633 case 'e': 1634 do_extract = 1; 1635 break; 1636 1637 case 'F': 1638 gen_funcs_c = 1; 1639 break; 1640 1641 case 'f': 1642 gen_funcs_h = 1; 1643 break; 1644 1645 case 'h': 1646 fprintf(stderr, "%s", usgtxt); 1647 exit(0); 1648 1649 case 'I': 1650 path_new(optarg); 1651 break; 1652 1653 case 'i': 1654 infile = optarg; 1655 break; 1656 1657 case 'l': 1658 localincs = 1; 1659 break; 1660 1661 case 'p': 1662 file_prefix = optarg; 1663 if (strlen(file_prefix) + strlen("tree.c") > 1664 MAXPATHLEN) 1665 errx(1, "prefix too long"); 1666 break; 1667 1668 case 't': 1669 do_tree = 1; 1670 break; 1671 } 1672 1673 if (do_extract + do_tree + do_enums > 1) 1674 errx(1, "conflicting options -e/-t/-E"); 1675 if (!do_extract && !do_enums && argc != optind) 1676 errx(1, "no arguments allowed"); 1677 if (do_extract && argc == optind) 1678 errx(1, "no objects specified"); 1679 1680 if ((gen_funcs_h || gen_funcs_c) && (do_extract || do_tree)) 1681 errx(1, "-f and -F not allowed with -e or -t"); 1682 if (gen_funcs_c && !do_enums) 1683 errx(1, "-F requires -E"); 1684 if (gen_funcs_h && gen_funcs_c) 1685 errx(1, "-f and -F are mutually exclusive"); 1686 1687 if (infile == NULL) { 1688 input_new(stdin, NULL, "<stdin>"); 1689 } else { 1690 if ((fp = fopen(infile, "r")) == NULL) 1691 err(1, "%s", infile); 1692 input_new(fp, NULL, infile); 1693 } 1694 1695 root = parse_top(gettoken()); 1696 while ((tok = gettoken()) != TOK_EOF) 1697 merge(&root, parse_top(tok)); 1698 1699 if (root) 1700 check_tree(root); 1701 1702 if (do_extract) { 1703 while (optind < argc) { 1704 if (gen_extract(stdout, root, argv[optind])) 1705 errx(1, "object not found: %s", argv[optind]); 1706 optind++; 1707 } 1708 return (0); 1709 } 1710 if (do_enums) { 1711 make_enums(argc - optind, argv + optind, 1712 gen_funcs_h, gen_funcs_c); 1713 return (0); 1714 } 1715 if (do_tree) { 1716 gen_tree(root, 0); 1717 return (0); 1718 } 1719 sprintf(fname, "%stree.h", file_prefix); 1720 if ((fp = fopen(fname, "w")) == NULL) 1721 err(1, "%s: ", fname); 1722 gen_header(fp, root, PREFIX_LEN, NULL); 1723 1724 fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); 1725 extract_all_enums(fp, gen_funcs_h); 1726 fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); 1727 1728 fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); 1729 fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); 1730 1731 fclose(fp); 1732 1733 sprintf(fname, "%stree.c", file_prefix); 1734 if ((fp = fopen(fname, "w")) == NULL) 1735 err(1, "%s: ", fname); 1736 gen_table(fp, root); 1737 fclose(fp); 1738 1739 return (0); 1740 } 1741