1 /*- 2 * Copyright (c) 2006 The FreeBSD Project 3 * All rights reserved. 4 * 5 * Author: Shteryana Shopova <syrinx@FreeBSD.org> 6 * 7 * Redistribution of this software and documentation and use in source and 8 * binary forms, with or without modification, are permitted provided that 9 * the following conditions are met: 10 * 11 * 1. Redistributions of source code or documentation must retain the above 12 * copyright notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Read file containing table description - reuse magic from gensnmptree.c. 32 * Hopefully one day most of the code here will be part of libbsnmp and 33 * this duplication won't be necessary. 34 * 35 * Syntax is: 36 * --------- 37 * file := top | top file 38 * 39 * top := tree | typedef | include 40 * 41 * tree := head elements ')' 42 * 43 * entry := head ':' index STRING elements ')' 44 * 45 * leaf := head type STRING ACCESS ')' 46 * 47 * column := head type ACCESS ')' 48 * 49 * type := BASETYPE | BASETYPE '|' subtype | enum | bits 50 * 51 * subtype := STRING 52 * 53 * enum := ENUM '(' value ')' 54 * 55 * bits := BITS '(' value ')' 56 * 57 * value := INT STRING | INT STRING value 58 * 59 * head := '(' INT STRING 60 * 61 * elements := EMPTY | elements element 62 * 63 * element := tree | leaf | column 64 * 65 * index := type | index type 66 * 67 * typedef := 'typedef' STRING type 68 * 69 * include := 'include' filespec 70 * 71 * filespec := '"' STRING '"' | '<' STRING '>' 72 */ 73 74 #include <sys/param.h> 75 #include <sys/queue.h> 76 #include <sys/uio.h> 77 78 #include <ctype.h> 79 #include <err.h> 80 #include <errno.h> 81 #include <fcntl.h> 82 #include <paths.h> 83 #include <stdio.h> 84 #include <stdlib.h> 85 #include <string.h> 86 #include <syslog.h> 87 #include <unistd.h> 88 89 #include <bsnmp/asn1.h> 90 #include <bsnmp/snmp.h> 91 #include <bsnmp/snmpagent.h> /* SNMP_INDEXES_MAX */ 92 #include "bsnmptc.h" 93 #include "bsnmptools.h" 94 95 enum snmp_tbl_entry { 96 ENTRY_NONE = 0, 97 ENTRY_INDEX, 98 ENTRY_DATA 99 }; 100 101 enum { 102 FL_GET = 0x01, 103 FL_SET = 0x02, 104 }; 105 106 /************************************************************ 107 * 108 * Allocate memory and panic just in the case... 109 */ 110 static void * 111 xalloc(size_t size) 112 { 113 void *ptr; 114 115 if ((ptr = malloc(size)) == NULL) 116 err(1, "allocing %zu bytes", size); 117 118 return (ptr); 119 } 120 121 static char * 122 savestr(const char *s) 123 { 124 if (s == NULL) 125 return (NULL); 126 127 return (strcpy(xalloc(strlen(s) + 1), s)); 128 } 129 130 /************************************************************ 131 * 132 * Input stack 133 */ 134 struct input { 135 FILE *fp; 136 uint32_t lno; 137 char *fname; 138 char *path; 139 LIST_ENTRY(input) link; 140 }; 141 142 static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); 143 static struct input *input = NULL; 144 static int32_t pbchar = -1; 145 146 #define MAX_PATHS 100 147 148 static const char *paths[MAX_PATHS + 1] = { 149 "/usr/share/snmp/defs", 150 _PATH_LOCALBASE "/share/snmp/defs", 151 NULL 152 }; 153 154 static void 155 input_new(FILE *fp, const char *path, const char *fname) 156 { 157 struct input *ip; 158 159 ip = xalloc(sizeof(*ip)); 160 ip->fp = fp; 161 ip->lno = 1; 162 ip->fname = savestr(fname); 163 ip->path = savestr(path); 164 LIST_INSERT_HEAD(&inputs, ip, link); 165 166 input = ip; 167 } 168 169 static void 170 input_close(void) 171 { 172 if (input == NULL) 173 return; 174 175 fclose(input->fp); 176 free(input->fname); 177 free(input->path); 178 LIST_REMOVE(input, link); 179 free(input); 180 181 input = LIST_FIRST(&inputs); 182 } 183 184 static FILE * 185 tryopen(const char *path, const char *fname) 186 { 187 char *fn; 188 FILE *fp; 189 190 if (path == NULL) 191 fn = savestr(fname); 192 else { 193 fn = xalloc(strlen(path) + strlen(fname) + 2); 194 sprintf(fn, "%s/%s", path, fname); 195 } 196 fp = fopen(fn, "r"); 197 free(fn); 198 return (fp); 199 } 200 201 static int32_t 202 input_fopen(const char *fname) 203 { 204 FILE *fp; 205 u_int p; 206 207 if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') { 208 if ((fp = tryopen(NULL, fname)) != NULL) { 209 input_new(fp, NULL, fname); 210 return (0); 211 } 212 213 } else { 214 215 for (p = 0; paths[p] != NULL; p++) 216 if ((fp = tryopen(paths[p], fname)) != NULL) { 217 input_new(fp, paths[p], fname); 218 return (0); 219 } 220 } 221 222 warnx("cannot open '%s'", fname); 223 return (-1); 224 } 225 226 static int32_t 227 tgetc(void) 228 { 229 int c; 230 231 if (pbchar != -1) { 232 c = pbchar; 233 pbchar = -1; 234 return (c); 235 } 236 237 for (;;) { 238 if (input == NULL) 239 return (EOF); 240 241 if ((c = getc(input->fp)) != EOF) 242 return (c); 243 244 input_close(); 245 } 246 } 247 248 static int32_t 249 tungetc(int c) 250 { 251 252 if (pbchar != -1) 253 return (-1); 254 255 pbchar = c; 256 return (1); 257 } 258 259 /************************************************************ 260 * 261 * Parsing input 262 */ 263 enum tok { 264 TOK_EOF = 0200, /* end-of-file seen */ 265 TOK_NUM, /* number */ 266 TOK_STR, /* string */ 267 TOK_ACCESS, /* access operator */ 268 TOK_TYPE, /* type operator */ 269 TOK_ENUM, /* enum token (kind of a type) */ 270 TOK_TYPEDEF, /* typedef directive */ 271 TOK_DEFTYPE, /* defined type */ 272 TOK_INCLUDE, /* include directive */ 273 TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */ 274 TOK_BITS, /* bits token (kind of a type) */ 275 TOK_ERR /* unexpected char - exit */ 276 }; 277 278 static const struct { 279 const char *str; 280 enum tok tok; 281 uint32_t val; 282 } keywords[] = { 283 { "GET", TOK_ACCESS, FL_GET }, 284 { "SET", TOK_ACCESS, FL_SET }, 285 { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 286 { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 287 { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 288 { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 289 { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 290 { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 291 { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 292 { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 293 { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 294 { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 295 { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 296 { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, 297 { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, 298 { "typedef", TOK_TYPEDEF, 0 }, 299 { "include", TOK_INCLUDE, 0 }, 300 { NULL, 0, 0 } 301 }; 302 303 static struct { 304 /* Current OID type, regarding table membership. */ 305 enum snmp_tbl_entry tbl_type; 306 /* A pointer to a structure in table list to add to its members. */ 307 struct snmp_index_entry *table_idx; 308 } table_data; 309 310 static struct asn_oid current_oid; 311 static char nexttok[MAXSTR]; 312 static u_long val; /* integer values */ 313 static int32_t all_cond; /* all conditions are true */ 314 static int32_t saved_token = -1; 315 316 /* Prepare the global data before parsing a new file. */ 317 static void 318 snmp_import_init(struct asn_oid *append) 319 { 320 memset(&table_data, 0, sizeof(table_data)); 321 memset(¤t_oid, 0, sizeof(struct asn_oid)); 322 memset(nexttok, 0, MAXSTR); 323 324 if (append != NULL) 325 asn_append_oid(¤t_oid, append); 326 327 all_cond = 0; 328 val = 0; 329 saved_token = -1; 330 } 331 332 static int32_t 333 gettoken(struct snmp_toolinfo *snmptoolctx) 334 { 335 int c; 336 struct enum_type *t; 337 338 if (saved_token != -1) { 339 c = saved_token; 340 saved_token = -1; 341 return (c); 342 } 343 344 again: 345 /* 346 * Skip any whitespace before the next token. 347 */ 348 while ((c = tgetc()) != EOF) { 349 if (c == '\n') 350 input->lno++; 351 if (!isspace(c)) 352 break; 353 } 354 if (c == EOF) 355 return (TOK_EOF); 356 357 if (!isascii(c)) { 358 warnx("unexpected character %#2x", (u_int) c); 359 return (TOK_ERR); 360 } 361 362 /* 363 * Skip comments. 364 */ 365 if (c == '#') { 366 while ((c = tgetc()) != EOF) { 367 if (c == '\n') { 368 input->lno++; 369 goto again; 370 } 371 } 372 warnx("unexpected EOF in comment"); 373 return (TOK_ERR); 374 } 375 376 /* 377 * Single character tokens. 378 */ 379 if (strchr("():|", c) != NULL) 380 return (c); 381 382 if (c == '"' || c == '<') { 383 int32_t end = c; 384 size_t n = 0; 385 386 val = 1; 387 if (c == '<') { 388 val = 0; 389 end = '>'; 390 } 391 392 while ((c = tgetc()) != EOF) { 393 if (c == end) 394 break; 395 if (n == sizeof(nexttok) - 1) { 396 nexttok[n++] = '\0'; 397 warnx("filename too long '%s...'", nexttok); 398 return (TOK_ERR); 399 } 400 nexttok[n++] = c; 401 } 402 nexttok[n++] = '\0'; 403 return (TOK_FILENAME); 404 } 405 406 /* 407 * Sort out numbers. 408 */ 409 if (isdigit(c)) { 410 size_t n = 0; 411 nexttok[n++] = c; 412 while ((c = tgetc()) != EOF) { 413 if (!isdigit(c)) { 414 if (tungetc(c) < 0) 415 return (TOK_ERR); 416 break; 417 } 418 if (n == sizeof(nexttok) - 1) { 419 nexttok[n++] = '\0'; 420 warnx("number too long '%s...'", nexttok); 421 return (TOK_ERR); 422 } 423 nexttok[n++] = c; 424 } 425 nexttok[n++] = '\0'; 426 sscanf(nexttok, "%lu", &val); 427 return (TOK_NUM); 428 } 429 430 /* 431 * So that has to be a string. 432 */ 433 if (isalpha(c) || c == '_' || c == '-') { 434 size_t n = 0; 435 nexttok[n++] = c; 436 while ((c = tgetc()) != EOF) { 437 if (!isalnum(c) && c != '_' && c != '-') { 438 if (tungetc (c) < 0) 439 return (TOK_ERR); 440 break; 441 } 442 if (n == sizeof(nexttok) - 1) { 443 nexttok[n++] = '\0'; 444 warnx("string too long '%s...'", nexttok); 445 return (TOK_ERR); 446 } 447 nexttok[n++] = c; 448 } 449 nexttok[n++] = '\0'; 450 451 /* 452 * Keywords. 453 */ 454 for (c = 0; keywords[c].str != NULL; c++) 455 if (strcmp(keywords[c].str, nexttok) == 0) { 456 val = keywords[c].val; 457 return (keywords[c].tok); 458 } 459 460 if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) { 461 val = t->syntax; 462 return (TOK_DEFTYPE); 463 } 464 465 return (TOK_STR); 466 } 467 468 if (isprint(c)) 469 warnx("%u: unexpected character '%c'", input->lno, c); 470 else 471 warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c); 472 473 return (TOK_ERR); 474 } 475 476 /* 477 * Update table information. 478 */ 479 static struct snmp_index_entry * 480 snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl) 481 { 482 switch (te) { 483 case ENTRY_NONE: 484 if (table_data.tbl_type == ENTRY_NONE) 485 return (NULL); 486 if (table_data.tbl_type == ENTRY_INDEX) 487 table_data.table_idx = NULL; 488 table_data.tbl_type--; 489 return (NULL); 490 491 case ENTRY_INDEX: 492 if (tbl == NULL) 493 warnx("No table_index to add!!!"); 494 table_data.table_idx = tbl; 495 table_data.tbl_type = ENTRY_INDEX; 496 return (tbl); 497 498 case ENTRY_DATA: 499 if (table_data.tbl_type == ENTRY_INDEX) { 500 table_data.tbl_type = ENTRY_DATA; 501 return (table_data.table_idx); 502 } 503 return (NULL); 504 505 default: 506 /* NOTREACHED */ 507 warnx("Unknown table entry type!!!"); 508 break; 509 } 510 511 return (NULL); 512 } 513 514 static int32_t 515 parse_enum(struct snmp_toolinfo *snmptoolctx, int32_t *tok, 516 struct enum_pairs *enums) 517 { 518 while ((*tok = gettoken(snmptoolctx)) == TOK_STR) { 519 if (enum_pair_insert(enums, val, nexttok) < 0) 520 return (-1); 521 if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) 522 break; 523 } 524 525 if (*tok != ')') { 526 warnx("')' at end of enums"); 527 return (-1); 528 } 529 530 return (1); 531 } 532 533 static int32_t 534 parse_subtype(struct snmp_toolinfo *snmptoolctx, int32_t *tok, 535 enum snmp_tc *tc) 536 { 537 if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { 538 warnx("subtype expected after '|'"); 539 return (-1); 540 } 541 542 *tc = snmp_get_tc(nexttok); 543 *tok = gettoken(snmptoolctx); 544 545 return (1); 546 } 547 548 static int32_t 549 parse_type(struct snmp_toolinfo *snmptoolctx, int32_t *tok, 550 enum snmp_tc *tc, struct enum_pairs **snmp_enum) 551 { 552 int32_t syntax, mem; 553 554 syntax = val; 555 *tc = 0; 556 557 if (*tok == TOK_ENUM || *tok == TOK_BITS) { 558 if (*snmp_enum == NULL) { 559 if ((*snmp_enum = enum_pairs_init()) == NULL) 560 return (-1); 561 mem = 1; 562 *tc = SNMP_TC_OWN; 563 } else 564 mem = 0; 565 566 if (gettoken(snmptoolctx) != '(') { 567 warnx("'(' expected after ENUM/BITS"); 568 return (-1); 569 } 570 571 if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) { 572 warnx("need value for ENUM//BITS"); 573 if (mem == 1) { 574 free(*snmp_enum); 575 *snmp_enum = NULL; 576 } 577 return (-1); 578 } 579 580 if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) { 581 enum_pairs_free(*snmp_enum); 582 *snmp_enum = NULL; 583 return (-1); 584 } 585 586 *tok = gettoken(snmptoolctx); 587 588 } else if (*tok == TOK_DEFTYPE) { 589 struct enum_type *t; 590 591 *tc = 0; 592 t = snmp_enumtc_lookup(snmptoolctx, nexttok); 593 if (t != NULL) 594 *snmp_enum = t->snmp_enum; 595 596 *tok = gettoken(snmptoolctx); 597 598 } else { 599 if ((*tok = gettoken(snmptoolctx)) == '|') { 600 if (parse_subtype(snmptoolctx, tok, tc) < 0) 601 return (-1); 602 } 603 } 604 605 return (syntax); 606 } 607 608 static int32_t 609 snmp_import_head(struct snmp_toolinfo *snmptoolctx) 610 { 611 enum tok tok; 612 613 if ((tok = gettoken(snmptoolctx)) == '(') 614 tok = gettoken(snmptoolctx); 615 616 if (tok != TOK_NUM || val > ASN_MAXID ) { 617 warnx("Suboid expected - line %d", input->lno); 618 return (-1); 619 } 620 621 if (gettoken(snmptoolctx) != TOK_STR) { 622 warnx("Node name expected at line %d", input->lno); 623 return (-1); 624 } 625 626 return (1); 627 } 628 629 static int32_t 630 snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj) 631 { 632 int32_t i, tok; 633 enum snmp_tc tc; 634 struct snmp_index_entry *entry; 635 636 if ((entry = calloc(1, sizeof(struct snmp_index_entry))) == NULL) { 637 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 638 return (-1); 639 } 640 641 STAILQ_INIT(&(entry->index_list)); 642 643 for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) { 644 int32_t syntax; 645 struct enum_pairs *enums = NULL; 646 647 if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM && 648 tok != TOK_BITS) 649 break; 650 651 if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) { 652 enum_pairs_free(enums); 653 snmp_index_listfree(&(entry->index_list)); 654 free(entry); 655 return (-1); 656 } 657 658 if (snmp_syntax_insert(&(entry->index_list), enums, syntax, 659 tc) < 0) { 660 snmp_index_listfree(&(entry->index_list)); 661 enum_pairs_free(enums); 662 free(entry); 663 return (-1); 664 } 665 } 666 667 if (i == 0 || i > SNMP_INDEXES_MAX) { 668 warnx("Bad number of indexes at line %d", input->lno); 669 snmp_index_listfree(&(entry->index_list)); 670 free(entry); 671 return (-1); 672 } 673 674 if (tok != TOK_STR) { 675 warnx("String expected after indexes at line %d", input->lno); 676 snmp_index_listfree(&(entry->index_list)); 677 free(entry); 678 return (-1); 679 } 680 681 entry->string = obj->string; 682 entry->strlen = obj->strlen; 683 asn_append_oid(&(entry->var), &(obj->var)); 684 685 if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) { 686 snmp_index_listfree(&(entry->index_list)); 687 free(entry); 688 return (-1); 689 } else if (i == 0) { 690 /* Same entry already present in lists. */ 691 free(entry->string); 692 free(entry); 693 return (0); 694 } 695 696 (void) snmp_import_update_table(ENTRY_INDEX, entry); 697 698 return (1); 699 } 700 701 /* 702 * Read everything after the syntax type that is certainly a leaf OID info. 703 */ 704 static int32_t 705 snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, int32_t *tok, 706 struct snmp_oid2str *oid2str) 707 { 708 int32_t i, syntax; 709 710 if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum))) 711 < 0) 712 return(-1); 713 714 oid2str->syntax = syntax; 715 /* 716 * That is the name of the function, corresponding to the entry. 717 * It is used by bsnmpd, but is not interesting for us. 718 */ 719 if (*tok == TOK_STR) 720 *tok = gettoken(snmptoolctx); 721 722 for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) { 723 oid2str->access |= (uint32_t) val; 724 *tok = gettoken(snmptoolctx); 725 } 726 727 if (*tok != ')') { 728 warnx("')' expected at end of line %d", input->lno); 729 return (-1); 730 } 731 732 oid2str->table_idx = snmp_import_update_table(ENTRY_DATA, NULL); 733 734 if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) { 735 warnx("Error adding leaf %s to list", oid2str->string); 736 return (-1); 737 } 738 739 /* 740 * Same entry is already present in the mapping lists and 741 * the new one was not inserted. 742 */ 743 if (i == 0) { 744 free(oid2str->string); 745 free(oid2str); 746 } 747 748 (void) snmp_import_update_table(ENTRY_NONE, NULL); 749 750 return (1); 751 } 752 753 static int32_t 754 snmp_import_object(struct snmp_toolinfo *snmptoolctx) 755 { 756 char *string; 757 int i; 758 int32_t tok; 759 struct snmp_oid2str *oid2str; 760 761 if (snmp_import_head(snmptoolctx) < 0) 762 return (-1); 763 764 if ((oid2str = calloc(1, sizeof(struct snmp_oid2str))) == NULL) { 765 syslog(LOG_ERR, "calloc() failed: %s", strerror(errno)); 766 return (-1); 767 } 768 769 if ((string = strdup(nexttok)) == NULL) { 770 syslog(LOG_ERR, "strdup() failed: %s", strerror(errno)); 771 free(oid2str); 772 return (-1); 773 } 774 775 oid2str->string = string; 776 oid2str->strlen = strlen(nexttok); 777 778 asn_append_oid(&(oid2str->var), &(current_oid)); 779 if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0) 780 goto error; 781 782 /* 783 * Prepared the entry - now figure out where to insert it. 784 * After the object we have following options: 785 * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist; 786 * 2) new line , ( - nonleaf oid -> snmp_nodelist; 787 * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more) 788 * may follow and second string must end line -> snmp_tablelist; 789 * 3) OID , string ) - this is a trap entry or a leaf -> snmp_oidlist; 790 * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last 791 * and )- this is definitely a leaf. 792 */ 793 794 switch (tok = gettoken(snmptoolctx)) { 795 case ')': 796 if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0) 797 goto error; 798 if (i == 0) { 799 free(oid2str->string); 800 free(oid2str); 801 } 802 return (1); 803 804 case '(': 805 if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) 806 goto error; 807 808 /* 809 * Ignore the error for nodes since the .def files currently 810 * contain different strings for 1.3.6.1.2.1 - mibII. Only make 811 * sure the memory is freed and don't complain. 812 */ 813 if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) { 814 free(string); 815 free(oid2str); 816 } 817 return (snmp_import_object(snmptoolctx)); 818 819 case ':': 820 if (snmp_suboid_append(¤t_oid, (asn_subid_t) val) < 0) 821 goto error; 822 if (snmp_import_table(snmptoolctx, oid2str) < 0) 823 goto error; 824 /* 825 * A different table entry type was malloced and the data is 826 * contained there. 827 */ 828 free(oid2str); 829 return (1); 830 831 case TOK_TYPE: 832 /* FALLTHROUGH */ 833 case TOK_DEFTYPE: 834 /* FALLTHROUGH */ 835 case TOK_ENUM: 836 /* FALLTHROUGH */ 837 case TOK_BITS: 838 if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0) 839 goto error; 840 return (1); 841 842 default: 843 warnx("Unexpected token at line %d - %s", input->lno, 844 input->fname); 845 break; 846 } 847 848 error: 849 snmp_mapping_entryfree(oid2str); 850 851 return (-1); 852 } 853 854 static int32_t 855 snmp_import_tree(struct snmp_toolinfo *snmptoolctx, int32_t *tok) 856 { 857 while (*tok != TOK_EOF) { 858 switch (*tok) { 859 case TOK_ERR: 860 return (-1); 861 case '(': 862 if (snmp_import_object(snmptoolctx) < 0) 863 return (-1); 864 break; 865 case ')': 866 if (snmp_suboid_pop(¤t_oid) < 0) 867 return (-1); 868 (void) snmp_import_update_table(ENTRY_NONE, NULL); 869 break; 870 default: 871 /* Anything else here would be illegal. */ 872 return (-1); 873 } 874 *tok = gettoken(snmptoolctx); 875 } 876 877 return (0); 878 } 879 880 static int32_t 881 snmp_import_top(struct snmp_toolinfo *snmptoolctx, int32_t *tok) 882 { 883 enum snmp_tc tc; 884 struct enum_type *t; 885 886 if (*tok == '(') 887 return (snmp_import_tree(snmptoolctx, tok)); 888 889 if (*tok == TOK_TYPEDEF) { 890 if ((*tok = gettoken(snmptoolctx)) != TOK_STR) { 891 warnx("type name expected after typedef - %s", 892 input->fname); 893 return (-1); 894 } 895 896 t = snmp_enumtc_init(nexttok); 897 898 *tok = gettoken(snmptoolctx); 899 t->is_enum = (*tok == TOK_ENUM); 900 t->is_bits = (*tok == TOK_BITS); 901 t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum)); 902 snmp_enumtc_insert(snmptoolctx, t); 903 904 return (1); 905 } 906 907 if (*tok == TOK_INCLUDE) { 908 int i; 909 910 *tok = gettoken(snmptoolctx); 911 if (*tok != TOK_FILENAME) { 912 warnx("filename expected in include directive - %s", 913 nexttok); 914 return (-1); 915 } 916 917 if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) { 918 *tok = gettoken(snmptoolctx); 919 return (1); 920 } 921 922 if (i == -1) 923 return (-1); 924 925 input_fopen(nexttok); 926 *tok = gettoken(snmptoolctx); 927 return (1); 928 } 929 930 warnx("'(' or 'typedef' expected - %s", nexttok); 931 return (-1); 932 } 933 934 static int32_t 935 snmp_import(struct snmp_toolinfo *snmptoolctx) 936 { 937 int i; 938 int32_t tok; 939 940 tok = gettoken(snmptoolctx); 941 942 do 943 i = snmp_import_top(snmptoolctx, &tok); 944 while (i > 0); 945 946 return (i); 947 } 948 949 /* 950 * Read a .def file and import oid<->string mapping. 951 * Mappings are inserted into a global structure containing list for each OID 952 * syntax type. 953 */ 954 int32_t 955 snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file) 956 { 957 int idx; 958 959 snmp_import_init(&(file->cut)); 960 input_fopen(file->name); 961 if ((idx = snmp_import(snmptoolctx)) < 0) 962 warnx("Failed to read mappings from file %s", file->name); 963 964 input_close(); 965 966 return (idx); 967 } 968