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