gensnmptree.c revision 145557
1129468Sru/* 2129468Sru * Copyright (c) 2001-2003 3147647Shmp * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4246751Sglebius * All rights reserved. 5137872Srwatson * 6129468Sru * Copyright (c) 2004 7137872Srwatson * Hartmut Brandt. 8129468Sru * All rights reserved. 9129468Sru * 10129468Sru * Author: Harti Brandt <harti@freebsd.org> 11129468Sru * 12129468Sru * Redistribution and use in source and binary forms, with or without 13129468Sru * modification, are permitted provided that the following conditions 14129468Sru * are met: 15129468Sru * 1. Redistributions of source code must retain the above copyright 16129468Sru * notice, this list of conditions and the following disclaimer. 17129468Sru * 2. Redistributions in binary form must reproduce the above copyright 18129468Sru * notice, this list of conditions and the following disclaimer in the 19129468Sru * documentation and/or other materials provided with the distribution. 20129468Sru * 21129468Sru * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22129468Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23175253Smaxim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24129468Sru * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 25129468Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26129468Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27129468Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28129468Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29129468Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30129468Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31129468Sru * SUCH DAMAGE. 32231564Sed * 33129468Sru * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.42 2005/04/26 16:26:19 brandt_h Exp $ 34129468Sru * 35129468Sru * Generate OID table from table description. 36129468Sru * 37129468Sru * Syntax is: 38129468Sru * --------- 39129468Sru * file := tree | tree file 40129468Sru * 41129468Sru * tree := head elements ')' 42129468Sru * 43129468Sru * entry := head ':' index STRING elements ')' 44129468Sru * 45129468Sru * leaf := head TYPE STRING ACCESS ')' 46129468Sru * 47129468Sru * column := head TYPE ACCESS ')' 48129468Sru * 49129468Sru * head := '(' INT STRING 50129468Sru * 51129468Sru * elements := EMPTY | elements element 52129468Sru * 53129468Sru * element := tree | leaf | column 54231564Sed * 55129468Sru * index := TYPE | index TYPE 56129468Sru * 57129468Sru */ 58129468Sru#include <sys/types.h> 59129468Sru#include <sys/param.h> 60129468Sru#include <stdio.h> 61129468Sru#include <stdlib.h> 62137872Srwatson#include <stdarg.h> 63137872Srwatson#include <unistd.h> 64137872Srwatson#include <string.h> 65137872Srwatson#include <ctype.h> 66137872Srwatson#include <inttypes.h> 67137872Srwatson#include <errno.h> 68137872Srwatson#ifdef HAVE_ERR_H 69137953Srwatson#include <err.h> 70137872Srwatson#endif 71137872Srwatson#include <sys/queue.h> 72175247Smaxim#include "support.h" 73175247Smaxim#include "asn1.h" 74137872Srwatson#include "snmp.h" 75137872Srwatson#include "snmpagent.h" 76137872Srwatson 77137872Srwatson/* 78137872Srwatson * Constant prefix for all OIDs 79137872Srwatson */ 80137872Srwatsonstatic const asn_subid_t prefix[] = { 1, 3, 6 }; 81137953Srwatson#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) 82137953Srwatson 83137953Srwatsonu_int tree_size; 84137953Srwatsonstatic const char *file_prefix = ""; 85137872Srwatsonstatic FILE *fp; 86137872Srwatson 87137872Srwatson/* if true generate local include paths */ 88137872Srwatsonstatic int localincs = 0; 89129468Sru 90129468Srustatic const char usgtxt[] = "\ 91129468SruGenerate SNMP tables. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 92129468SruOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 93129468Sruusage: gensnmptree [-hel] [-p prefix] [name]...\n\ 94129468Sruoptions:\n\ 95129468Sru -h print this info\n\ 96129468Sru -e extrace the named oids\n\ 97129468Sru -l generate local include directives\n\ 98129468Sru -p prefix prepend prefix to file and variable names\n\ 99129468Sru"; 100129468Sru 101129468Sru/* 102129468Sru * A node in the OID tree 103231564Sed */ 104231564Sedenum ntype { 105231564Sed NODE_LEAF = 1, 106129468Sru NODE_TREE, 107129468Sru NODE_ENTRY, 108129468Sru NODE_COLUMN 109129468Sru}; 110129468Sru 111129468Sruenum { 112129468Sru FL_GET = 0x01, 113129468Sru FL_SET = 0x02, 114129468Sru}; 115129468Sru 116129468Srustruct node; 117129468SruTAILQ_HEAD(node_list, node); 118129468Sru 119129468Srustruct node { 120129468Sru enum ntype type; 121129468Sru asn_subid_t id; /* last element of OID */ 122129468Sru char *name; /* name of node */ 123136347Sglebius TAILQ_ENTRY(node) link; 124140140Sru u_int lno; /* starting line number */ 125129468Sru u_int flags; /* allowed operations */ 126129468Sru 127129468Sru union { 128129468Sru struct tree { 129129468Sru struct node_list subs; 130129468Sru } tree; 131129468Sru 132129468Sru struct entry { 133129468Sru uint32_t index; /* index for table entry */ 134129468Sru char *func; /* function for tables */ 135129468Sru struct node_list subs; 136129468Sru } entry; 137129468Sru 138129468Sru struct leaf { 139129468Sru enum snmp_syntax syntax; /* syntax for this leaf */ 140129468Sru char *func; /* function name */ 141129468Sru } leaf; 142129468Sru 143129468Sru struct column { 144129468Sru enum snmp_syntax syntax; /* syntax for this column */ 145129468Sru } column; 146129468Sru } u; 147129468Sru}; 148129468Sru 149129468Srustruct func { 150129468Sru const char *name; 151129468Sru LIST_ENTRY(func) link; 152129468Sru}; 153129468Sru 154129468Srustatic LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); 155129468Sru 156129468Sru/************************************************************ 157129468Sru * 158129468Sru * Allocate memory and panic just in the case... 159129468Sru */ 160129468Srustatic void * 161129468Sruxalloc(size_t size) 162129468Sru{ 163129468Sru void *ptr; 164129468Sru 165129468Sru if ((ptr = malloc(size)) == NULL) 166129468Sru err(1, "allocing %zu bytes", size); 167129468Sru 168129468Sru return (ptr); 169129468Sru} 170129468Sru 171129468Sru/************************************************************ 172129468Sru * 173129468Sru * Parsing input 174129468Sru */ 175129468Sruenum tok { 176129468Sru TOK_EOF = 0200, /* end-of-file seen */ 177129468Sru TOK_NUM, /* number */ 178129468Sru TOK_STR, /* string */ 179129468Sru TOK_ACCESS, /* access operator */ 180129468Sru TOK_TYPE, /* type operator */ 181129468Sru}; 182129468Sru 183129468Srustatic const struct { 184129468Sru const char *str; 185129468Sru enum tok tok; 186129468Sru u_int val; 187129468Sru} keywords[] = { 188129468Sru { "GET", TOK_ACCESS, FL_GET }, 189129468Sru { "SET", TOK_ACCESS, FL_SET }, 190129468Sru { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 191129468Sru { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 192129468Sru { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 193129468Sru { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 194129468Sru { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 195129468Sru { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 196129468Sru { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 197129468Sru { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 198129468Sru { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 199129468Sru { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 200129468Sru { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 201129468Sru { NULL, 0, 0 } 202129468Sru}; 203129468Sru 204129468Sru/* arbitrary upper limit on node names and function names */ 205129468Sru#define MAXSTR 1000 206129468Sruchar str[MAXSTR]; 207129468Sruu_long val; /* integer values */ 208129468Sruu_int lno = 1; /* current line number */ 209129468Sruint all_cond; /* all conditions are true */ 210129468Sru 211129468Srustatic void report(const char *, ...) __dead2 __printflike(1, 2); 212129468Srustatic void report_node(const struct node *, const char *, ...) 213129468Sru __dead2 __printflike(2, 3); 214129468Sru 215129468Sru/* 216129468Sru * Report an error and exit. 217129468Sru */ 218129468Srustatic void 219129468Srureport(const char *fmt, ...) 220129468Sru{ 221129468Sru va_list ap; 222129468Sru int c; 223129468Sru 224129468Sru va_start(ap, fmt); 225129468Sru fprintf(stderr, "line %u: ", lno); 226136347Sglebius vfprintf(stderr, fmt, ap); 227136347Sglebius fprintf(stderr, "\n"); 228136347Sglebius fprintf(stderr, "context: \""); 229140140Sru while ((c = getchar()) != EOF && c != '\n') 230140140Sru fprintf(stderr, "%c", c); 231140140Sru fprintf(stderr, "\n"); 232136347Sglebius va_end(ap); 233129468Sru exit(1); 234129468Sru} 235129468Srustatic void 236129468Srureport_node(const struct node *np, const char *fmt, ...) 237129468Sru{ 238129468Sru va_list ap; 239129468Sru 240129468Sru va_start(ap, fmt); 241129468Sru fprintf(stderr, "line %u, node %s: ", np->lno, np->name); 242129468Sru vfprintf(stderr, fmt, ap); 243129468Sru fprintf(stderr, "\n"); 244129468Sru va_end(ap); 245129468Sru exit(1); 246129468Sru} 247129468Sru 248129468Sru/* 249129468Sru * Return a fresh copy of the string constituting the current token. 250129468Sru */ 251129468Srustatic char * 252129468Srusavetok(void) 253129468Sru{ 254129468Sru return (strcpy(xalloc(strlen(str)+1), str)); 255129468Sru} 256129468Sru 257129468Sru/* 258129468Sru * Get the next token from input. 259129468Sru */ 260129468Srustatic int 261129468Srugettoken(void) 262129468Sru{ 263129468Sru int c; 264129468Sru 265129468Sru again: 266129468Sru /* 267129468Sru * Skip any whitespace before the next token 268129468Sru */ 269129468Sru while ((c = getchar()) != EOF) { 270129468Sru if (c == '\n') 271129468Sru lno++; 272129468Sru if (!isspace(c)) 273129468Sru break; 274129468Sru } 275129468Sru if (c == EOF) 276129468Sru return (TOK_EOF); 277129468Sru if (!isascii(c)) 278129468Sru report("unexpected character %#2x", (u_int)c); 279129468Sru 280129468Sru /* 281129468Sru * Skip comments 282129468Sru */ 283129468Sru if (c == '#') { 284129468Sru while ((c = getchar()) != EOF) { 285129468Sru if (c == '\n') { 286129468Sru lno++; 287 goto again; 288 } 289 } 290 report("unexpected EOF in comment"); 291 } 292 293 /* 294 * Single character tokens 295 */ 296 if (c == ')' || c == '(' || c == ':') 297 return (c); 298 299 /* 300 * Sort out numbers 301 */ 302 if (isdigit(c)) { 303 ungetc(c, stdin); 304 scanf("%lu", &val); 305 return (TOK_NUM); 306 } 307 308 /* 309 * So that has to be a string. 310 */ 311 if (isalpha(c) || c == '_') { 312 size_t n = 0; 313 str[n++] = c; 314 while ((c = getchar()) != EOF) { 315 if (!isalnum(c) && c != '_') { 316 ungetc(c, stdin); 317 break; 318 } 319 if (n == sizeof(str) - 1) { 320 str[n++] = '\0'; 321 report("string too long '%s...'", str); 322 } 323 str[n++] = c; 324 } 325 str[n++] = '\0'; 326 327 /* 328 * Keywords 329 */ 330 for (c = 0; keywords[c].str != NULL; c++) 331 if (strcmp(keywords[c].str, str) == 0) { 332 val = keywords[c].val; 333 return (keywords[c].tok); 334 } 335 336 return (TOK_STR); 337 } 338 if (isprint(c)) 339 errx(1, "%u: unexpected character '%c'", lno, c); 340 else 341 errx(1, "%u: unexpected character 0x%02x", lno, (u_int)c); 342} 343 344/* 345 * Parse the next node (complete with all subnodes) 346 */ 347static struct node * 348parse(enum tok tok) 349{ 350 struct node *node; 351 struct node *sub; 352 u_int index_count; 353 354 node = xalloc(sizeof(struct node)); 355 node->lno = lno; 356 357 if (tok != '(') 358 report("'(' expected at begin of node"); 359 if (gettoken() != TOK_NUM) 360 report("node id expected after opening '('"); 361 if (val > ASN_MAXID) 362 report("subid too large '%lu'", val); 363 node->id = (asn_subid_t)val; 364 if (gettoken() != TOK_STR) 365 report("node name expected after '(' ID"); 366 node->name = savetok(); 367 368 if ((tok = gettoken()) == TOK_TYPE) { 369 /* LEAF or COLUM */ 370 u_int syntax = val; 371 372 if ((tok = gettoken()) == TOK_STR) { 373 /* LEAF */ 374 node->type = NODE_LEAF; 375 node->u.leaf.func = savetok(); 376 node->u.leaf.syntax = syntax; 377 tok = gettoken(); 378 } else { 379 /* COLUMN */ 380 node->type = NODE_COLUMN; 381 node->u.column.syntax = syntax; 382 } 383 384 while (tok != ')') { 385 if (tok != TOK_ACCESS) 386 report("access keyword or ')' expected"); 387 node->flags |= (u_int)val; 388 tok = gettoken(); 389 } 390 391 } else if (tok == ':') { 392 /* ENTRY */ 393 node->type = NODE_ENTRY; 394 TAILQ_INIT(&node->u.entry.subs); 395 396 index_count = 0; 397 node->u.entry.index = 0; 398 while ((tok = gettoken()) == TOK_TYPE) { 399 if (index_count++ == SNMP_INDEXES_MAX) 400 report("too many table indexes"); 401 node->u.entry.index |= 402 val << (SNMP_INDEX_SHIFT * index_count); 403 } 404 node->u.entry.index |= index_count; 405 if (index_count == 0) 406 report("need at least one index"); 407 408 if (tok != TOK_STR) 409 report("function name expected"); 410 411 node->u.entry.func = savetok(); 412 413 tok = gettoken(); 414 415 while (tok != ')') { 416 sub = parse(tok); 417 TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); 418 tok = gettoken(); 419 } 420 421 } else { 422 /* subtree */ 423 node->type = NODE_TREE; 424 TAILQ_INIT(&node->u.tree.subs); 425 426 while (tok != ')') { 427 sub = parse(tok); 428 TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); 429 tok = gettoken(); 430 } 431 } 432 return (node); 433} 434 435/* 436 * Generate the C-code table part for one node. 437 */ 438static void 439gen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) 440{ 441 u_int n; 442 struct node *sub; 443 u_int syntax; 444 445 if (oid->len == ASN_MAXOIDLEN) 446 report_node(np, "OID too long"); 447 oid->subs[oid->len++] = np->id; 448 449 if (np->type == NODE_TREE) { 450 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 451 gen_node(sub, oid, 0, NULL); 452 oid->len--; 453 return; 454 } 455 if (np->type == NODE_ENTRY) { 456 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 457 gen_node(sub, oid, np->u.entry.index, np->u.entry.func); 458 oid->len--; 459 return; 460 } 461 462 /* leaf or column */ 463 if ((np->flags & (FL_GET|FL_SET)) == 0) { 464 oid->len--; 465 return; 466 } 467 468 fprintf(fp, " {{ %u, {", oid->len); 469 for (n = 0; n < oid->len; n++) 470 fprintf(fp, " %u,", oid->subs[n]); 471 fprintf(fp, " }}, \"%s\", ", np->name); 472 473 if (np->type == NODE_COLUMN) { 474 syntax = np->u.column.syntax; 475 fprintf(fp, "SNMP_NODE_COLUMN, "); 476 } else { 477 syntax = np->u.leaf.syntax; 478 fprintf(fp, "SNMP_NODE_LEAF, "); 479 } 480 481 switch (syntax) { 482 483 case SNMP_SYNTAX_NULL: 484 fprintf(fp, "SNMP_SYNTAX_NULL, "); 485 break; 486 487 case SNMP_SYNTAX_INTEGER: 488 fprintf(fp, "SNMP_SYNTAX_INTEGER, "); 489 break; 490 491 case SNMP_SYNTAX_OCTETSTRING: 492 fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); 493 break; 494 495 case SNMP_SYNTAX_IPADDRESS: 496 fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); 497 break; 498 499 case SNMP_SYNTAX_OID: 500 fprintf(fp, "SNMP_SYNTAX_OID, "); 501 break; 502 503 case SNMP_SYNTAX_TIMETICKS: 504 fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); 505 break; 506 507 case SNMP_SYNTAX_COUNTER: 508 fprintf(fp, "SNMP_SYNTAX_COUNTER, "); 509 break; 510 511 case SNMP_SYNTAX_GAUGE: 512 fprintf(fp, "SNMP_SYNTAX_GAUGE, "); 513 break; 514 515 case SNMP_SYNTAX_COUNTER64: 516 fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); 517 break; 518 519 case SNMP_SYNTAX_NOSUCHOBJECT: 520 case SNMP_SYNTAX_NOSUCHINSTANCE: 521 case SNMP_SYNTAX_ENDOFMIBVIEW: 522 abort(); 523 } 524 525 if (np->type == NODE_COLUMN) 526 fprintf(fp, "%s, ", func); 527 else 528 fprintf(fp, "%s, ", np->u.leaf.func); 529 530 fprintf(fp, "0"); 531 if (np->flags & FL_SET) 532 fprintf(fp, "|SNMP_NODE_CANSET"); 533 fprintf(fp, ", %#x, NULL, NULL },\n", idx); 534 oid->len--; 535 return; 536} 537 538/* 539 * Generate the header file with the function declarations. 540 */ 541static void 542gen_header(struct node *np, u_int oidlen, const char *func) 543{ 544 char f[MAXSTR + 4]; 545 struct node *sub; 546 struct func *ptr; 547 548 oidlen++; 549 if (np->type == NODE_TREE) { 550 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 551 gen_header(sub, oidlen, NULL); 552 return; 553 } 554 if (np->type == NODE_ENTRY) { 555 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 556 gen_header(sub, oidlen, np->u.entry.func); 557 return; 558 } 559 560 if((np->flags & (FL_GET|FL_SET)) == 0) 561 return; 562 563 if (np->type == NODE_COLUMN) { 564 if (func == NULL) 565 errx(1, "column without function (%s) - probably " 566 "outside of a table", np->name); 567 sprintf(f, "%s", func); 568 } else 569 sprintf(f, "%s", np->u.leaf.func); 570 571 LIST_FOREACH(ptr, &funcs, link) 572 if (strcmp(ptr->name, f) == 0) 573 break; 574 575 if (ptr == NULL) { 576 ptr = xalloc(sizeof(*ptr)); 577 ptr->name = strcpy(xalloc(strlen(f)+1), f); 578 LIST_INSERT_HEAD(&funcs, ptr, link); 579 580 fprintf(fp, "int %s(struct snmp_context *, " 581 "struct snmp_value *, u_int, u_int, " 582 "enum snmp_op);\n", f); 583 } 584 585 fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); 586} 587 588/* 589 * Generate the OID table. 590 */ 591static void 592gen_table(struct node *node) 593{ 594 struct asn_oid oid; 595 596 fprintf(fp, "#include <sys/types.h>\n"); 597 fprintf(fp, "#include <stdio.h>\n"); 598 fprintf(fp, "#include <stdint.h>\n"); 599 if (localincs) { 600 fprintf(fp, "#include \"asn1.h\"\n"); 601 fprintf(fp, "#include \"snmp.h\"\n"); 602 fprintf(fp, "#include \"snmpagent.h\"\n"); 603 } else { 604 fprintf(fp, "#include <bsnmp/asn1.h>\n"); 605 fprintf(fp, "#include <bsnmp/snmp.h>\n"); 606 fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); 607 } 608 fprintf(fp, "#include \"%stree.h\"\n", file_prefix); 609 fprintf(fp, "\n"); 610 611 fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); 612 613 oid.len = PREFIX_LEN; 614 memcpy(oid.subs, prefix, sizeof(prefix)); 615 gen_node(node, &oid, 0, NULL); 616 617 fprintf(fp, "};\n\n"); 618} 619 620static void 621print_syntax(u_int syntax) 622{ 623 u_int i; 624 625 for (i = 0; keywords[i].str != NULL; i++) 626 if (keywords[i].tok == TOK_TYPE && 627 keywords[i].val == syntax) { 628 printf(" %s", keywords[i].str); 629 return; 630 } 631 abort(); 632} 633 634/* 635 * Generate a tree definition file 636 */ 637static void 638gen_tree(const struct node *np, int level) 639{ 640 const struct node *sp; 641 u_int i; 642 643 printf("%*s(%u %s", 2 * level, "", np->id, np->name); 644 645 switch (np->type) { 646 647 case NODE_LEAF: 648 print_syntax(np->u.leaf.syntax); 649 printf(" %s%s%s)\n", np->u.leaf.func, 650 (np->flags & FL_GET) ? " GET" : "", 651 (np->flags & FL_SET) ? " SET" : ""); 652 break; 653 654 case NODE_TREE: 655 if (TAILQ_EMPTY(&np->u.tree.subs)) { 656 printf(")\n"); 657 } else { 658 printf("\n"); 659 TAILQ_FOREACH(sp, &np->u.tree.subs, link) 660 gen_tree(sp, level + 1); 661 printf("%*s)\n", 2 * level, ""); 662 } 663 break; 664 665 case NODE_ENTRY: 666 printf(" :"); 667 668 for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) 669 print_syntax(SNMP_INDEX(np->u.entry.index, i)); 670 printf(" %s\n", np->u.entry.func); 671 TAILQ_FOREACH(sp, &np->u.entry.subs, link) 672 gen_tree(sp, level + 1); 673 printf("%*s)\n", 2 * level, ""); 674 break; 675 676 case NODE_COLUMN: 677 print_syntax(np->u.column.syntax); 678 printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", 679 (np->flags & FL_SET) ? " SET" : ""); 680 break; 681 682 } 683} 684 685static int 686extract(const struct node *np, struct asn_oid *oid, const char *obj, 687 const struct asn_oid *idx, const char *iname) 688{ 689 struct node *sub; 690 u_long n; 691 692 if (oid->len == ASN_MAXOIDLEN) 693 report_node(np, "OID too long"); 694 oid->subs[oid->len++] = np->id; 695 696 if (strcmp(obj, np->name) == 0) { 697 if (oid->len + idx->len >= ASN_MAXOIDLEN) 698 report_node(np, "OID too long"); 699 fprintf(fp, "#define OID_%s%s\t%u\n", np->name, 700 iname ? iname : "", np->id); 701 fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, 702 iname ? iname : "", oid->len + idx->len); 703 fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, 704 iname ? iname : "", oid->len + idx->len); 705 for (n = 0; n < oid->len; n++) 706 fprintf(fp, " %u,", oid->subs[n]); 707 for (n = 0; n < idx->len; n++) 708 fprintf(fp, " %u,", idx->subs[n]); 709 fprintf(fp, " } }\n"); 710 return (0); 711 } 712 713 if (np->type == NODE_TREE) { 714 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 715 if (!extract(sub, oid, obj, idx, iname)) 716 return (0); 717 } else if (np->type == NODE_ENTRY) { 718 TAILQ_FOREACH(sub, &np->u.entry.subs, link) 719 if (!extract(sub, oid, obj, idx, iname)) 720 return (0); 721 } 722 oid->len--; 723 return (1); 724} 725 726static int 727gen_extract(const struct node *root, char *object) 728{ 729 struct asn_oid oid; 730 struct asn_oid idx; 731 char *s, *e, *end, *iname; 732 u_long ul; 733 int ret; 734 735 /* look whether the object to extract has an index part */ 736 idx.len = 0; 737 iname = NULL; 738 s = strchr(object, '.'); 739 if (s != NULL) { 740 iname = malloc(strlen(s) + 1); 741 if (iname == NULL) 742 err(1, "cannot allocated index"); 743 744 strcpy(iname, s); 745 for (e = iname; *e != '\0'; e++) 746 if (*e == '.') 747 *e = '_'; 748 749 *s++ = '\0'; 750 while (s != NULL) { 751 if (*s == '\0') 752 errx(1, "bad index syntax"); 753 if ((e = strchr(s, '.')) != NULL) 754 *e++ = '\0'; 755 756 errno = 0; 757 ul = strtoul(s, &end, 0); 758 if (*end != '\0') 759 errx(1, "bad index syntax '%s'", end); 760 if (errno != 0) 761 err(1, "bad index syntax"); 762 763 if (idx.len == ASN_MAXOIDLEN) 764 errx(1, "index oid too large"); 765 idx.subs[idx.len++] = ul; 766 767 s = e; 768 } 769 } 770 771 oid.len = PREFIX_LEN; 772 memcpy(oid.subs, prefix, sizeof(prefix)); 773 ret = extract(root, &oid, object, &idx, iname); 774 if (iname != NULL) 775 free(iname); 776 777 return (ret); 778} 779 780 781static void 782check_sub_order(const struct node *np, const struct node_list *subs) 783{ 784 int first; 785 const struct node *sub; 786 asn_subid_t maxid = 0; 787 788 /* ensure, that subids are ordered */ 789 first = 1; 790 TAILQ_FOREACH(sub, subs, link) { 791 if (!first && sub->id <= maxid) 792 report_node(np, "subids not ordered at %s", sub->name); 793 maxid = sub->id; 794 first = 0; 795 } 796} 797 798/* 799 * Do some sanity checks on the tree definition and do some computations. 800 */ 801static void 802check_tree(struct node *np) 803{ 804 struct node *sub; 805 806 if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { 807 if ((np->flags & (FL_GET|FL_SET)) != 0) 808 tree_size++; 809 return; 810 } 811 812 if (np->type == NODE_ENTRY) { 813 check_sub_order(np, &np->u.entry.subs); 814 815 /* ensure all subnodes are columns */ 816 TAILQ_FOREACH(sub, &np->u.entry.subs, link) { 817 if (sub->type != NODE_COLUMN) 818 report_node(np, "entry subnode '%s' is not " 819 "a column", sub->name); 820 check_tree(sub); 821 } 822 } else { 823 check_sub_order(np, &np->u.tree.subs); 824 825 TAILQ_FOREACH(sub, &np->u.tree.subs, link) 826 check_tree(sub); 827 } 828} 829 830static void 831merge_subs(struct node_list *s1, struct node_list *s2) 832{ 833 struct node *n1, *n2; 834 835 while (!TAILQ_EMPTY(s2)) { 836 n2 = TAILQ_FIRST(s2); 837 TAILQ_REMOVE(s2, n2, link); 838 839 TAILQ_FOREACH(n1, s1, link) 840 if (n1->id >= n2->id) 841 break; 842 if (n1 == NULL) 843 TAILQ_INSERT_TAIL(s1, n2, link); 844 else if (n1->id > n2->id) 845 TAILQ_INSERT_BEFORE(n1, n2, link); 846 else { 847 if (n1->type == NODE_TREE && n2->type == NODE_TREE) { 848 if (strcmp(n1->name, n2->name) != 0) 849 errx(1, "trees to merge must have " 850 "same name '%s' '%s'", n1->name, 851 n2->name); 852 merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); 853 free(n2); 854 } else if (n1->type == NODE_ENTRY && 855 n2->type == NODE_ENTRY) { 856 if (strcmp(n1->name, n2->name) != 0) 857 errx(1, "entries to merge must have " 858 "same name '%s' '%s'", n1->name, 859 n2->name); 860 if (n1->u.entry.index != n2->u.entry.index) 861 errx(1, "entries to merge must have " 862 "same index '%s'", n1->name); 863 if (strcmp(n1->u.entry.func, 864 n2->u.entry.func) != 0) 865 errx(1, "entries to merge must have " 866 "same op '%s'", n1->name); 867 merge_subs(&n1->u.entry.subs, 868 &n2->u.entry.subs); 869 free(n2); 870 } else 871 errx(1, "entities to merge must be both " 872 "trees or both entries: %s, %s", 873 n1->name, n2->name); 874 } 875 } 876} 877 878static void 879merge(struct node *root, struct node *t) 880{ 881 882 /* both must be trees */ 883 if (root->type != NODE_TREE) 884 errx(1, "root is not a tree"); 885 if (t->type != NODE_TREE) 886 errx(1, "can merge only with tree"); 887 if (root->id != t->id) 888 errx(1, "trees to merge must have same id"); 889 890 merge_subs(&root->u.tree.subs, &t->u.tree.subs); 891} 892 893int 894main(int argc, char *argv[]) 895{ 896 int do_extract = 0; 897 int do_tree = 0; 898 int opt; 899 struct node *root; 900 char fname[MAXPATHLEN + 1]; 901 int tok; 902 903 while ((opt = getopt(argc, argv, "help:t")) != EOF) 904 switch (opt) { 905 906 case 'h': 907 fprintf(stderr, "%s", usgtxt); 908 exit(0); 909 910 case 'e': 911 do_extract = 1; 912 break; 913 914 case 'l': 915 localincs = 1; 916 break; 917 918 case 'p': 919 file_prefix = optarg; 920 if (strlen(file_prefix) + strlen("tree.c") > 921 MAXPATHLEN) 922 errx(1, "prefix too long"); 923 break; 924 925 case 't': 926 do_tree = 1; 927 break; 928 } 929 930 if (do_extract && do_tree) 931 errx(1, "conflicting options -e and -t"); 932 if (!do_extract && argc != optind) 933 errx(1, "no arguments allowed"); 934 if (do_extract && argc == optind) 935 errx(1, "no objects specified"); 936 937 root = parse(gettoken()); 938 while ((tok = gettoken()) != TOK_EOF) 939 merge(root, parse(tok)); 940 941 check_tree(root); 942 943 if (do_extract) { 944 fp = stdout; 945 while (optind < argc) { 946 if (gen_extract(root, argv[optind])) 947 errx(1, "object not found: %s", argv[optind]); 948 optind++; 949 } 950 951 return (0); 952 } 953 if (do_tree) { 954 gen_tree(root, 0); 955 return (0); 956 } 957 sprintf(fname, "%stree.h", file_prefix); 958 if ((fp = fopen(fname, "w")) == NULL) 959 err(1, "%s: ", fname); 960 gen_header(root, PREFIX_LEN, NULL); 961 962 fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); 963 fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); 964 965 fclose(fp); 966 967 sprintf(fname, "%stree.c", file_prefix); 968 if ((fp = fopen(fname, "w")) == NULL) 969 err(1, "%s: ", fname); 970 gen_table(root); 971 fclose(fp); 972 973 return (0); 974} 975