gensnmptree.c revision 154182
1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6133211Sharti * Copyright (c) 2004 7133211Sharti * Hartmut Brandt. 8133211Sharti * All rights reserved. 9133211Sharti * 10122394Sharti * Author: Harti Brandt <harti@freebsd.org> 11133211Sharti * 12133211Sharti * Redistribution and use in source and binary forms, with or without 13133211Sharti * modification, are permitted provided that the following conditions 14133211Sharti * are met: 15133211Sharti * 1. Redistributions of source code must retain the above copyright 16133211Sharti * notice, this list of conditions and the following disclaimer. 17122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 18122394Sharti * notice, this list of conditions and the following disclaimer in the 19122394Sharti * documentation and/or other materials provided with the distribution. 20133211Sharti * 21133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 25133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31133211Sharti * SUCH DAMAGE. 32122394Sharti * 33150920Sharti * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.43 2005/10/04 11:21:29 brandt_h Exp $ 34122394Sharti * 35122394Sharti * Generate OID table from table description. 36122394Sharti * 37122394Sharti * Syntax is: 38122394Sharti * --------- 39133211Sharti * file := tree | tree file 40133211Sharti * 41122394Sharti * tree := head elements ')' 42122394Sharti * 43122394Sharti * entry := head ':' index STRING elements ')' 44122394Sharti * 45122394Sharti * leaf := head TYPE STRING ACCESS ')' 46122394Sharti * 47122394Sharti * column := head TYPE ACCESS ')' 48122394Sharti * 49122394Sharti * head := '(' INT STRING 50122394Sharti * 51122394Sharti * elements := EMPTY | elements element 52122394Sharti * 53142810Sharti * element := tree | leaf | column 54122394Sharti * 55122394Sharti * index := TYPE | index TYPE 56122394Sharti * 57122394Sharti */ 58122394Sharti#include <sys/types.h> 59122394Sharti#include <sys/param.h> 60122394Sharti#include <stdio.h> 61122394Sharti#include <stdlib.h> 62122394Sharti#include <stdarg.h> 63122394Sharti#include <unistd.h> 64122394Sharti#include <string.h> 65122394Sharti#include <ctype.h> 66133429Sharti#include <inttypes.h> 67133211Sharti#include <errno.h> 68133211Sharti#ifdef HAVE_ERR_H 69122394Sharti#include <err.h> 70133211Sharti#endif 71122394Sharti#include <sys/queue.h> 72133211Sharti#include "support.h" 73122394Sharti#include "asn1.h" 74122394Sharti#include "snmp.h" 75122394Sharti#include "snmpagent.h" 76122394Sharti 77122394Sharti/* 78122394Sharti * Constant prefix for all OIDs 79122394Sharti */ 80122394Shartistatic const asn_subid_t prefix[] = { 1, 3, 6 }; 81122394Sharti#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) 82122394Sharti 83122394Shartiu_int tree_size; 84122394Shartistatic const char *file_prefix = ""; 85122394Shartistatic FILE *fp; 86122394Sharti 87122394Sharti/* if true generate local include paths */ 88122394Shartistatic int localincs = 0; 89122394Sharti 90122394Shartistatic const char usgtxt[] = "\ 91122394ShartiGenerate SNMP tables. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 92122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 93122394Shartiusage: gensnmptree [-hel] [-p prefix] [name]...\n\ 94122394Shartioptions:\n\ 95122394Sharti -h print this info\n\ 96122394Sharti -e extrace the named oids\n\ 97122394Sharti -l generate local include directives\n\ 98122394Sharti -p prefix prepend prefix to file and variable names\n\ 99122394Sharti"; 100122394Sharti 101122394Sharti/* 102122394Sharti * A node in the OID tree 103122394Sharti */ 104122394Shartienum ntype { 105122394Sharti NODE_LEAF = 1, 106122394Sharti NODE_TREE, 107122394Sharti NODE_ENTRY, 108122394Sharti NODE_COLUMN 109122394Sharti}; 110122394Sharti 111122394Shartienum { 112122394Sharti FL_GET = 0x01, 113122394Sharti FL_SET = 0x02, 114122394Sharti}; 115122394Sharti 116122394Shartistruct node; 117122394ShartiTAILQ_HEAD(node_list, node); 118122394Sharti 119122394Shartistruct node { 120122394Sharti enum ntype type; 121122394Sharti asn_subid_t id; /* last element of OID */ 122122394Sharti char *name; /* name of node */ 123122394Sharti TAILQ_ENTRY(node) link; 124122394Sharti u_int lno; /* starting line number */ 125122394Sharti u_int flags; /* allowed operations */ 126122394Sharti 127122394Sharti union { 128122394Sharti struct tree { 129122394Sharti struct node_list subs; 130122394Sharti } tree; 131122394Sharti 132122394Sharti struct entry { 133133211Sharti uint32_t index; /* index for table entry */ 134122394Sharti char *func; /* function for tables */ 135122394Sharti struct node_list subs; 136122394Sharti } entry; 137122394Sharti 138122394Sharti struct leaf { 139122394Sharti enum snmp_syntax syntax; /* syntax for this leaf */ 140122394Sharti char *func; /* function name */ 141122394Sharti } leaf; 142122394Sharti 143122394Sharti struct column { 144122394Sharti enum snmp_syntax syntax; /* syntax for this column */ 145122394Sharti } column; 146122394Sharti } u; 147122394Sharti}; 148122394Sharti 149122394Shartistruct func { 150122394Sharti const char *name; 151122394Sharti LIST_ENTRY(func) link; 152122394Sharti}; 153122394Sharti 154122394Shartistatic LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); 155122394Sharti 156122394Sharti/************************************************************ 157122394Sharti * 158122394Sharti * Allocate memory and panic just in the case... 159122394Sharti */ 160122394Shartistatic void * 161122394Shartixalloc(size_t size) 162122394Sharti{ 163122394Sharti void *ptr; 164122394Sharti 165122394Sharti if ((ptr = malloc(size)) == NULL) 166145557Sharti err(1, "allocing %zu bytes", size); 167122394Sharti 168122394Sharti return (ptr); 169122394Sharti} 170122394Sharti 171122394Sharti/************************************************************ 172122394Sharti * 173122394Sharti * Parsing input 174122394Sharti */ 175122394Shartienum tok { 176122394Sharti TOK_EOF = 0200, /* end-of-file seen */ 177122394Sharti TOK_NUM, /* number */ 178122394Sharti TOK_STR, /* string */ 179122394Sharti TOK_ACCESS, /* access operator */ 180122394Sharti TOK_TYPE, /* type operator */ 181122394Sharti}; 182122394Sharti 183122394Shartistatic const struct { 184122394Sharti const char *str; 185122394Sharti enum tok tok; 186122394Sharti u_int val; 187122394Sharti} keywords[] = { 188122394Sharti { "GET", TOK_ACCESS, FL_GET }, 189122394Sharti { "SET", TOK_ACCESS, FL_SET }, 190122394Sharti { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 191122394Sharti { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 192122394Sharti { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 193122394Sharti { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 194122394Sharti { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 195122394Sharti { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 196122394Sharti { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 197122394Sharti { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 198122394Sharti { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 199122394Sharti { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 200122394Sharti { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 201122394Sharti { NULL, 0, 0 } 202122394Sharti}; 203122394Sharti 204122394Sharti/* arbitrary upper limit on node names and function names */ 205122394Sharti#define MAXSTR 1000 206122394Shartichar str[MAXSTR]; 207122394Shartiu_long val; /* integer values */ 208122394Shartiu_int lno = 1; /* current line number */ 209133211Shartiint all_cond; /* all conditions are true */ 210122394Sharti 211122394Shartistatic void report(const char *, ...) __dead2 __printflike(1, 2); 212122394Shartistatic void report_node(const struct node *, const char *, ...) 213122394Sharti __dead2 __printflike(2, 3); 214122394Sharti 215122394Sharti/* 216122394Sharti * Report an error and exit. 217122394Sharti */ 218122394Shartistatic void 219122394Shartireport(const char *fmt, ...) 220122394Sharti{ 221122394Sharti va_list ap; 222122394Sharti int c; 223122394Sharti 224122394Sharti va_start(ap, fmt); 225122394Sharti fprintf(stderr, "line %u: ", lno); 226122394Sharti vfprintf(stderr, fmt, ap); 227122394Sharti fprintf(stderr, "\n"); 228122394Sharti fprintf(stderr, "context: \""); 229122394Sharti while ((c = getchar()) != EOF && c != '\n') 230122394Sharti fprintf(stderr, "%c", c); 231122394Sharti fprintf(stderr, "\n"); 232122394Sharti va_end(ap); 233122394Sharti exit(1); 234122394Sharti} 235122394Shartistatic void 236122394Shartireport_node(const struct node *np, const char *fmt, ...) 237122394Sharti{ 238122394Sharti va_list ap; 239122394Sharti 240122394Sharti va_start(ap, fmt); 241122394Sharti fprintf(stderr, "line %u, node %s: ", np->lno, np->name); 242122394Sharti vfprintf(stderr, fmt, ap); 243122394Sharti fprintf(stderr, "\n"); 244122394Sharti va_end(ap); 245122394Sharti exit(1); 246122394Sharti} 247122394Sharti 248122394Sharti/* 249122394Sharti * Return a fresh copy of the string constituting the current token. 250122394Sharti */ 251122394Shartistatic char * 252122394Shartisavetok(void) 253122394Sharti{ 254122394Sharti return (strcpy(xalloc(strlen(str)+1), str)); 255122394Sharti} 256122394Sharti 257122394Sharti/* 258122394Sharti * Get the next token from input. 259122394Sharti */ 260122394Shartistatic int 261122394Shartigettoken(void) 262122394Sharti{ 263122394Sharti int c; 264122394Sharti 265122394Sharti again: 266122394Sharti /* 267122394Sharti * Skip any whitespace before the next token 268122394Sharti */ 269122394Sharti while ((c = getchar()) != EOF) { 270122394Sharti if (c == '\n') 271122394Sharti lno++; 272122394Sharti if (!isspace(c)) 273122394Sharti break; 274122394Sharti } 275122394Sharti if (c == EOF) 276122394Sharti return (TOK_EOF); 277122394Sharti if (!isascii(c)) 278122394Sharti report("unexpected character %#2x", (u_int)c); 279122394Sharti 280122394Sharti /* 281122394Sharti * Skip comments 282122394Sharti */ 283122394Sharti if (c == '#') { 284122394Sharti while ((c = getchar()) != EOF) { 285122394Sharti if (c == '\n') { 286122394Sharti lno++; 287122394Sharti goto again; 288122394Sharti } 289122394Sharti } 290122394Sharti report("unexpected EOF in comment"); 291122394Sharti } 292122394Sharti 293122394Sharti /* 294122394Sharti * Single character tokens 295122394Sharti */ 296122394Sharti if (c == ')' || c == '(' || c == ':') 297122394Sharti return (c); 298122394Sharti 299122394Sharti /* 300122394Sharti * Sort out numbers 301122394Sharti */ 302122394Sharti if (isdigit(c)) { 303122394Sharti ungetc(c, stdin); 304122394Sharti scanf("%lu", &val); 305122394Sharti return (TOK_NUM); 306122394Sharti } 307122394Sharti 308122394Sharti /* 309122394Sharti * So that has to be a string. 310122394Sharti */ 311122394Sharti if (isalpha(c) || c == '_') { 312122394Sharti size_t n = 0; 313122394Sharti str[n++] = c; 314122394Sharti while ((c = getchar()) != EOF) { 315122394Sharti if (!isalnum(c) && c != '_') { 316122394Sharti ungetc(c, stdin); 317122394Sharti break; 318122394Sharti } 319122394Sharti if (n == sizeof(str) - 1) { 320122394Sharti str[n++] = '\0'; 321122394Sharti report("string too long '%s...'", str); 322122394Sharti } 323122394Sharti str[n++] = c; 324122394Sharti } 325122394Sharti str[n++] = '\0'; 326122394Sharti 327122394Sharti /* 328122394Sharti * Keywords 329122394Sharti */ 330122394Sharti for (c = 0; keywords[c].str != NULL; c++) 331122394Sharti if (strcmp(keywords[c].str, str) == 0) { 332122394Sharti val = keywords[c].val; 333122394Sharti return (keywords[c].tok); 334122394Sharti } 335122394Sharti 336122394Sharti return (TOK_STR); 337122394Sharti } 338122394Sharti if (isprint(c)) 339122394Sharti errx(1, "%u: unexpected character '%c'", lno, c); 340122394Sharti else 341122394Sharti errx(1, "%u: unexpected character 0x%02x", lno, (u_int)c); 342122394Sharti} 343122394Sharti 344122394Sharti/* 345122394Sharti * Parse the next node (complete with all subnodes) 346122394Sharti */ 347122394Shartistatic struct node * 348122394Shartiparse(enum tok tok) 349122394Sharti{ 350122394Sharti struct node *node; 351122394Sharti struct node *sub; 352122394Sharti u_int index_count; 353122394Sharti 354122394Sharti node = xalloc(sizeof(struct node)); 355122394Sharti node->lno = lno; 356154182Sharti node->flags = 0; 357122394Sharti 358122394Sharti if (tok != '(') 359122394Sharti report("'(' expected at begin of node"); 360122394Sharti if (gettoken() != TOK_NUM) 361122394Sharti report("node id expected after opening '('"); 362122394Sharti if (val > ASN_MAXID) 363122394Sharti report("subid too large '%lu'", val); 364122394Sharti node->id = (asn_subid_t)val; 365122394Sharti if (gettoken() != TOK_STR) 366122394Sharti report("node name expected after '(' ID"); 367122394Sharti node->name = savetok(); 368122394Sharti 369122394Sharti if ((tok = gettoken()) == TOK_TYPE) { 370122394Sharti /* LEAF or COLUM */ 371122394Sharti u_int syntax = val; 372122394Sharti 373122394Sharti if ((tok = gettoken()) == TOK_STR) { 374122394Sharti /* LEAF */ 375122394Sharti node->type = NODE_LEAF; 376122394Sharti node->u.leaf.func = savetok(); 377122394Sharti node->u.leaf.syntax = syntax; 378122394Sharti tok = gettoken(); 379122394Sharti } else { 380122394Sharti /* COLUMN */ 381122394Sharti node->type = NODE_COLUMN; 382122394Sharti node->u.column.syntax = syntax; 383122394Sharti } 384122394Sharti 385122394Sharti while (tok != ')') { 386122394Sharti if (tok != TOK_ACCESS) 387122394Sharti report("access keyword or ')' expected"); 388122394Sharti node->flags |= (u_int)val; 389122394Sharti tok = gettoken(); 390122394Sharti } 391122394Sharti 392122394Sharti } else if (tok == ':') { 393122394Sharti /* ENTRY */ 394122394Sharti node->type = NODE_ENTRY; 395122394Sharti TAILQ_INIT(&node->u.entry.subs); 396122394Sharti 397122394Sharti index_count = 0; 398122394Sharti node->u.entry.index = 0; 399122394Sharti while ((tok = gettoken()) == TOK_TYPE) { 400122394Sharti if (index_count++ == SNMP_INDEXES_MAX) 401122394Sharti report("too many table indexes"); 402122394Sharti node->u.entry.index |= 403122394Sharti val << (SNMP_INDEX_SHIFT * index_count); 404122394Sharti } 405122394Sharti node->u.entry.index |= index_count; 406122394Sharti if (index_count == 0) 407122394Sharti report("need at least one index"); 408122394Sharti 409122394Sharti if (tok != TOK_STR) 410122394Sharti report("function name expected"); 411122394Sharti 412122394Sharti node->u.entry.func = savetok(); 413122394Sharti 414122394Sharti tok = gettoken(); 415122394Sharti 416122394Sharti while (tok != ')') { 417122394Sharti sub = parse(tok); 418122394Sharti TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); 419122394Sharti tok = gettoken(); 420122394Sharti } 421122394Sharti 422122394Sharti } else { 423122394Sharti /* subtree */ 424122394Sharti node->type = NODE_TREE; 425122394Sharti TAILQ_INIT(&node->u.tree.subs); 426122394Sharti 427122394Sharti while (tok != ')') { 428122394Sharti sub = parse(tok); 429122394Sharti TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); 430122394Sharti tok = gettoken(); 431122394Sharti } 432122394Sharti } 433122394Sharti return (node); 434122394Sharti} 435122394Sharti 436122394Sharti/* 437122394Sharti * Generate the C-code table part for one node. 438122394Sharti */ 439122394Shartistatic void 440122394Shartigen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) 441122394Sharti{ 442122394Sharti u_int n; 443122394Sharti struct node *sub; 444122394Sharti u_int syntax; 445122394Sharti 446122394Sharti if (oid->len == ASN_MAXOIDLEN) 447122394Sharti report_node(np, "OID too long"); 448122394Sharti oid->subs[oid->len++] = np->id; 449122394Sharti 450122394Sharti if (np->type == NODE_TREE) { 451122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 452122394Sharti gen_node(sub, oid, 0, NULL); 453122394Sharti oid->len--; 454122394Sharti return; 455122394Sharti } 456122394Sharti if (np->type == NODE_ENTRY) { 457122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 458122394Sharti gen_node(sub, oid, np->u.entry.index, np->u.entry.func); 459122394Sharti oid->len--; 460122394Sharti return; 461122394Sharti } 462122394Sharti 463122394Sharti /* leaf or column */ 464122394Sharti if ((np->flags & (FL_GET|FL_SET)) == 0) { 465122394Sharti oid->len--; 466122394Sharti return; 467122394Sharti } 468122394Sharti 469122394Sharti fprintf(fp, " {{ %u, {", oid->len); 470122394Sharti for (n = 0; n < oid->len; n++) 471122394Sharti fprintf(fp, " %u,", oid->subs[n]); 472122394Sharti fprintf(fp, " }}, \"%s\", ", np->name); 473122394Sharti 474122394Sharti if (np->type == NODE_COLUMN) { 475122394Sharti syntax = np->u.column.syntax; 476122394Sharti fprintf(fp, "SNMP_NODE_COLUMN, "); 477122394Sharti } else { 478122394Sharti syntax = np->u.leaf.syntax; 479122394Sharti fprintf(fp, "SNMP_NODE_LEAF, "); 480122394Sharti } 481122394Sharti 482122394Sharti switch (syntax) { 483122394Sharti 484122394Sharti case SNMP_SYNTAX_NULL: 485122394Sharti fprintf(fp, "SNMP_SYNTAX_NULL, "); 486122394Sharti break; 487122394Sharti 488122394Sharti case SNMP_SYNTAX_INTEGER: 489122394Sharti fprintf(fp, "SNMP_SYNTAX_INTEGER, "); 490122394Sharti break; 491122394Sharti 492122394Sharti case SNMP_SYNTAX_OCTETSTRING: 493122394Sharti fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); 494122394Sharti break; 495122394Sharti 496122394Sharti case SNMP_SYNTAX_IPADDRESS: 497122394Sharti fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); 498122394Sharti break; 499122394Sharti 500122394Sharti case SNMP_SYNTAX_OID: 501122394Sharti fprintf(fp, "SNMP_SYNTAX_OID, "); 502122394Sharti break; 503122394Sharti 504122394Sharti case SNMP_SYNTAX_TIMETICKS: 505122394Sharti fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); 506122394Sharti break; 507122394Sharti 508122394Sharti case SNMP_SYNTAX_COUNTER: 509122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER, "); 510122394Sharti break; 511122394Sharti 512122394Sharti case SNMP_SYNTAX_GAUGE: 513122394Sharti fprintf(fp, "SNMP_SYNTAX_GAUGE, "); 514122394Sharti break; 515122394Sharti 516122394Sharti case SNMP_SYNTAX_COUNTER64: 517122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); 518122394Sharti break; 519122394Sharti 520122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 521122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 522122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 523122394Sharti abort(); 524122394Sharti } 525122394Sharti 526122394Sharti if (np->type == NODE_COLUMN) 527122394Sharti fprintf(fp, "%s, ", func); 528122394Sharti else 529122394Sharti fprintf(fp, "%s, ", np->u.leaf.func); 530122394Sharti 531122394Sharti fprintf(fp, "0"); 532122394Sharti if (np->flags & FL_SET) 533122394Sharti fprintf(fp, "|SNMP_NODE_CANSET"); 534128237Sharti fprintf(fp, ", %#x, NULL, NULL },\n", idx); 535122394Sharti oid->len--; 536122394Sharti return; 537122394Sharti} 538122394Sharti 539122394Sharti/* 540122394Sharti * Generate the header file with the function declarations. 541122394Sharti */ 542122394Shartistatic void 543122394Shartigen_header(struct node *np, u_int oidlen, const char *func) 544122394Sharti{ 545122394Sharti char f[MAXSTR + 4]; 546122394Sharti struct node *sub; 547122394Sharti struct func *ptr; 548122394Sharti 549122394Sharti oidlen++; 550122394Sharti if (np->type == NODE_TREE) { 551122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 552122394Sharti gen_header(sub, oidlen, NULL); 553122394Sharti return; 554122394Sharti } 555122394Sharti if (np->type == NODE_ENTRY) { 556122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 557122394Sharti gen_header(sub, oidlen, np->u.entry.func); 558122394Sharti return; 559122394Sharti } 560122394Sharti 561122394Sharti if((np->flags & (FL_GET|FL_SET)) == 0) 562122394Sharti return; 563122394Sharti 564142810Sharti if (np->type == NODE_COLUMN) { 565142810Sharti if (func == NULL) 566142810Sharti errx(1, "column without function (%s) - probably " 567142810Sharti "outside of a table", np->name); 568122394Sharti sprintf(f, "%s", func); 569142810Sharti } else 570122394Sharti sprintf(f, "%s", np->u.leaf.func); 571122394Sharti 572122394Sharti LIST_FOREACH(ptr, &funcs, link) 573122394Sharti if (strcmp(ptr->name, f) == 0) 574122394Sharti break; 575122394Sharti 576122394Sharti if (ptr == NULL) { 577122394Sharti ptr = xalloc(sizeof(*ptr)); 578122394Sharti ptr->name = strcpy(xalloc(strlen(f)+1), f); 579122394Sharti LIST_INSERT_HEAD(&funcs, ptr, link); 580122394Sharti 581122394Sharti fprintf(fp, "int %s(struct snmp_context *, " 582122394Sharti "struct snmp_value *, u_int, u_int, " 583122394Sharti "enum snmp_op);\n", f); 584122394Sharti } 585122394Sharti 586122394Sharti fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); 587122394Sharti} 588122394Sharti 589122394Sharti/* 590122394Sharti * Generate the OID table. 591122394Sharti */ 592122394Shartistatic void 593122394Shartigen_table(struct node *node) 594122394Sharti{ 595122394Sharti struct asn_oid oid; 596122394Sharti 597122394Sharti fprintf(fp, "#include <sys/types.h>\n"); 598122394Sharti fprintf(fp, "#include <stdio.h>\n"); 599150920Sharti#ifdef HAVE_STDINT_H 600133211Sharti fprintf(fp, "#include <stdint.h>\n"); 601150920Sharti#endif 602122394Sharti if (localincs) { 603122394Sharti fprintf(fp, "#include \"asn1.h\"\n"); 604122394Sharti fprintf(fp, "#include \"snmp.h\"\n"); 605122394Sharti fprintf(fp, "#include \"snmpagent.h\"\n"); 606122394Sharti } else { 607122394Sharti fprintf(fp, "#include <bsnmp/asn1.h>\n"); 608122394Sharti fprintf(fp, "#include <bsnmp/snmp.h>\n"); 609122394Sharti fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); 610122394Sharti } 611122394Sharti fprintf(fp, "#include \"%stree.h\"\n", file_prefix); 612122394Sharti fprintf(fp, "\n"); 613122394Sharti 614122394Sharti fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); 615122394Sharti 616122394Sharti oid.len = PREFIX_LEN; 617122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 618122394Sharti gen_node(node, &oid, 0, NULL); 619122394Sharti 620122394Sharti fprintf(fp, "};\n\n"); 621122394Sharti} 622122394Sharti 623133211Shartistatic void 624133211Shartiprint_syntax(u_int syntax) 625133211Sharti{ 626133211Sharti u_int i; 627133211Sharti 628133211Sharti for (i = 0; keywords[i].str != NULL; i++) 629133211Sharti if (keywords[i].tok == TOK_TYPE && 630133211Sharti keywords[i].val == syntax) { 631133211Sharti printf(" %s", keywords[i].str); 632133211Sharti return; 633133211Sharti } 634133211Sharti abort(); 635133211Sharti} 636133211Sharti 637133211Sharti/* 638133211Sharti * Generate a tree definition file 639133211Sharti */ 640133211Shartistatic void 641133211Shartigen_tree(const struct node *np, int level) 642133211Sharti{ 643133211Sharti const struct node *sp; 644133211Sharti u_int i; 645133211Sharti 646133211Sharti printf("%*s(%u %s", 2 * level, "", np->id, np->name); 647133211Sharti 648133211Sharti switch (np->type) { 649133211Sharti 650133211Sharti case NODE_LEAF: 651133211Sharti print_syntax(np->u.leaf.syntax); 652133211Sharti printf(" %s%s%s)\n", np->u.leaf.func, 653133211Sharti (np->flags & FL_GET) ? " GET" : "", 654133211Sharti (np->flags & FL_SET) ? " SET" : ""); 655133211Sharti break; 656133211Sharti 657133211Sharti case NODE_TREE: 658133211Sharti if (TAILQ_EMPTY(&np->u.tree.subs)) { 659133211Sharti printf(")\n"); 660133211Sharti } else { 661133211Sharti printf("\n"); 662133211Sharti TAILQ_FOREACH(sp, &np->u.tree.subs, link) 663133211Sharti gen_tree(sp, level + 1); 664133211Sharti printf("%*s)\n", 2 * level, ""); 665133211Sharti } 666133211Sharti break; 667133211Sharti 668133211Sharti case NODE_ENTRY: 669133211Sharti printf(" :"); 670133211Sharti 671133211Sharti for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) 672133211Sharti print_syntax(SNMP_INDEX(np->u.entry.index, i)); 673133211Sharti printf(" %s\n", np->u.entry.func); 674133211Sharti TAILQ_FOREACH(sp, &np->u.entry.subs, link) 675133211Sharti gen_tree(sp, level + 1); 676133211Sharti printf("%*s)\n", 2 * level, ""); 677133211Sharti break; 678133211Sharti 679133211Sharti case NODE_COLUMN: 680133211Sharti print_syntax(np->u.column.syntax); 681133211Sharti printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", 682133211Sharti (np->flags & FL_SET) ? " SET" : ""); 683133211Sharti break; 684133211Sharti 685133211Sharti } 686133211Sharti} 687133211Sharti 688122394Shartistatic int 689133211Shartiextract(const struct node *np, struct asn_oid *oid, const char *obj, 690133211Sharti const struct asn_oid *idx, const char *iname) 691122394Sharti{ 692122394Sharti struct node *sub; 693122394Sharti u_long n; 694122394Sharti 695122394Sharti if (oid->len == ASN_MAXOIDLEN) 696122394Sharti report_node(np, "OID too long"); 697122394Sharti oid->subs[oid->len++] = np->id; 698122394Sharti 699122394Sharti if (strcmp(obj, np->name) == 0) { 700133211Sharti if (oid->len + idx->len >= ASN_MAXOIDLEN) 701133211Sharti report_node(np, "OID too long"); 702133211Sharti fprintf(fp, "#define OID_%s%s\t%u\n", np->name, 703133211Sharti iname ? iname : "", np->id); 704133211Sharti fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, 705133211Sharti iname ? iname : "", oid->len + idx->len); 706133211Sharti fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, 707133211Sharti iname ? iname : "", oid->len + idx->len); 708122394Sharti for (n = 0; n < oid->len; n++) 709122394Sharti fprintf(fp, " %u,", oid->subs[n]); 710133211Sharti for (n = 0; n < idx->len; n++) 711133211Sharti fprintf(fp, " %u,", idx->subs[n]); 712122394Sharti fprintf(fp, " } }\n"); 713122394Sharti return (0); 714122394Sharti } 715122394Sharti 716122394Sharti if (np->type == NODE_TREE) { 717122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 718133211Sharti if (!extract(sub, oid, obj, idx, iname)) 719122394Sharti return (0); 720122394Sharti } else if (np->type == NODE_ENTRY) { 721122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 722133211Sharti if (!extract(sub, oid, obj, idx, iname)) 723122394Sharti return (0); 724122394Sharti } 725122394Sharti oid->len--; 726122394Sharti return (1); 727122394Sharti} 728122394Sharti 729122394Shartistatic int 730133211Shartigen_extract(const struct node *root, char *object) 731122394Sharti{ 732122394Sharti struct asn_oid oid; 733133211Sharti struct asn_oid idx; 734133211Sharti char *s, *e, *end, *iname; 735133211Sharti u_long ul; 736133211Sharti int ret; 737122394Sharti 738133211Sharti /* look whether the object to extract has an index part */ 739133211Sharti idx.len = 0; 740133211Sharti iname = NULL; 741133211Sharti s = strchr(object, '.'); 742133211Sharti if (s != NULL) { 743133211Sharti iname = malloc(strlen(s) + 1); 744133211Sharti if (iname == NULL) 745133211Sharti err(1, "cannot allocated index"); 746133211Sharti 747133211Sharti strcpy(iname, s); 748133211Sharti for (e = iname; *e != '\0'; e++) 749133211Sharti if (*e == '.') 750133211Sharti *e = '_'; 751133211Sharti 752133211Sharti *s++ = '\0'; 753133211Sharti while (s != NULL) { 754133211Sharti if (*s == '\0') 755133211Sharti errx(1, "bad index syntax"); 756133211Sharti if ((e = strchr(s, '.')) != NULL) 757133211Sharti *e++ = '\0'; 758133211Sharti 759133211Sharti errno = 0; 760133211Sharti ul = strtoul(s, &end, 0); 761133211Sharti if (*end != '\0') 762133211Sharti errx(1, "bad index syntax '%s'", end); 763133211Sharti if (errno != 0) 764133211Sharti err(1, "bad index syntax"); 765133211Sharti 766133211Sharti if (idx.len == ASN_MAXOIDLEN) 767133211Sharti errx(1, "index oid too large"); 768133211Sharti idx.subs[idx.len++] = ul; 769133211Sharti 770133211Sharti s = e; 771133211Sharti } 772133211Sharti } 773133211Sharti 774122394Sharti oid.len = PREFIX_LEN; 775122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 776133211Sharti ret = extract(root, &oid, object, &idx, iname); 777133211Sharti if (iname != NULL) 778133211Sharti free(iname); 779133211Sharti 780133211Sharti return (ret); 781122394Sharti} 782122394Sharti 783122394Sharti 784122394Shartistatic void 785122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs) 786122394Sharti{ 787122394Sharti int first; 788122394Sharti const struct node *sub; 789122394Sharti asn_subid_t maxid = 0; 790122394Sharti 791122394Sharti /* ensure, that subids are ordered */ 792122394Sharti first = 1; 793122394Sharti TAILQ_FOREACH(sub, subs, link) { 794122394Sharti if (!first && sub->id <= maxid) 795122394Sharti report_node(np, "subids not ordered at %s", sub->name); 796122394Sharti maxid = sub->id; 797122394Sharti first = 0; 798122394Sharti } 799122394Sharti} 800122394Sharti 801122394Sharti/* 802122394Sharti * Do some sanity checks on the tree definition and do some computations. 803122394Sharti */ 804122394Shartistatic void 805122394Sharticheck_tree(struct node *np) 806122394Sharti{ 807122394Sharti struct node *sub; 808122394Sharti 809122394Sharti if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { 810122394Sharti if ((np->flags & (FL_GET|FL_SET)) != 0) 811122394Sharti tree_size++; 812122394Sharti return; 813122394Sharti } 814122394Sharti 815122394Sharti if (np->type == NODE_ENTRY) { 816122394Sharti check_sub_order(np, &np->u.entry.subs); 817122394Sharti 818122394Sharti /* ensure all subnodes are columns */ 819122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) { 820122394Sharti if (sub->type != NODE_COLUMN) 821122394Sharti report_node(np, "entry subnode '%s' is not " 822122394Sharti "a column", sub->name); 823122394Sharti check_tree(sub); 824122394Sharti } 825122394Sharti } else { 826122394Sharti check_sub_order(np, &np->u.tree.subs); 827122394Sharti 828122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 829122394Sharti check_tree(sub); 830122394Sharti } 831122394Sharti} 832122394Sharti 833133211Shartistatic void 834133211Shartimerge_subs(struct node_list *s1, struct node_list *s2) 835133211Sharti{ 836133211Sharti struct node *n1, *n2; 837133211Sharti 838133211Sharti while (!TAILQ_EMPTY(s2)) { 839133211Sharti n2 = TAILQ_FIRST(s2); 840133211Sharti TAILQ_REMOVE(s2, n2, link); 841133211Sharti 842133211Sharti TAILQ_FOREACH(n1, s1, link) 843133211Sharti if (n1->id >= n2->id) 844133211Sharti break; 845133211Sharti if (n1 == NULL) 846133211Sharti TAILQ_INSERT_TAIL(s1, n2, link); 847133211Sharti else if (n1->id > n2->id) 848133211Sharti TAILQ_INSERT_BEFORE(n1, n2, link); 849133211Sharti else { 850133211Sharti if (n1->type == NODE_TREE && n2->type == NODE_TREE) { 851133211Sharti if (strcmp(n1->name, n2->name) != 0) 852133211Sharti errx(1, "trees to merge must have " 853133211Sharti "same name '%s' '%s'", n1->name, 854133211Sharti n2->name); 855133211Sharti merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); 856133211Sharti free(n2); 857133211Sharti } else if (n1->type == NODE_ENTRY && 858133211Sharti n2->type == NODE_ENTRY) { 859133211Sharti if (strcmp(n1->name, n2->name) != 0) 860133211Sharti errx(1, "entries to merge must have " 861133211Sharti "same name '%s' '%s'", n1->name, 862133211Sharti n2->name); 863133211Sharti if (n1->u.entry.index != n2->u.entry.index) 864133211Sharti errx(1, "entries to merge must have " 865133211Sharti "same index '%s'", n1->name); 866133211Sharti if (strcmp(n1->u.entry.func, 867133211Sharti n2->u.entry.func) != 0) 868133211Sharti errx(1, "entries to merge must have " 869133211Sharti "same op '%s'", n1->name); 870133211Sharti merge_subs(&n1->u.entry.subs, 871133211Sharti &n2->u.entry.subs); 872133211Sharti free(n2); 873133211Sharti } else 874133211Sharti errx(1, "entities to merge must be both " 875133211Sharti "trees or both entries: %s, %s", 876133211Sharti n1->name, n2->name); 877133211Sharti } 878133211Sharti } 879133211Sharti} 880133211Sharti 881133211Shartistatic void 882133211Shartimerge(struct node *root, struct node *t) 883133211Sharti{ 884133211Sharti 885133211Sharti /* both must be trees */ 886133211Sharti if (root->type != NODE_TREE) 887133211Sharti errx(1, "root is not a tree"); 888133211Sharti if (t->type != NODE_TREE) 889133211Sharti errx(1, "can merge only with tree"); 890133211Sharti if (root->id != t->id) 891133211Sharti errx(1, "trees to merge must have same id"); 892133211Sharti 893133211Sharti merge_subs(&root->u.tree.subs, &t->u.tree.subs); 894133211Sharti} 895133211Sharti 896122394Shartiint 897122394Shartimain(int argc, char *argv[]) 898122394Sharti{ 899122394Sharti int do_extract = 0; 900133211Sharti int do_tree = 0; 901122394Sharti int opt; 902122394Sharti struct node *root; 903122394Sharti char fname[MAXPATHLEN + 1]; 904133211Sharti int tok; 905122394Sharti 906133211Sharti while ((opt = getopt(argc, argv, "help:t")) != EOF) 907122394Sharti switch (opt) { 908122394Sharti 909122394Sharti case 'h': 910122394Sharti fprintf(stderr, "%s", usgtxt); 911122394Sharti exit(0); 912122394Sharti 913122394Sharti case 'e': 914122394Sharti do_extract = 1; 915122394Sharti break; 916122394Sharti 917122394Sharti case 'l': 918122394Sharti localincs = 1; 919122394Sharti break; 920122394Sharti 921122394Sharti case 'p': 922122394Sharti file_prefix = optarg; 923122394Sharti if (strlen(file_prefix) + strlen("tree.c") > 924122394Sharti MAXPATHLEN) 925122394Sharti errx(1, "prefix too long"); 926122394Sharti break; 927133211Sharti 928133211Sharti case 't': 929133211Sharti do_tree = 1; 930133211Sharti break; 931122394Sharti } 932122394Sharti 933133211Sharti if (do_extract && do_tree) 934133211Sharti errx(1, "conflicting options -e and -t"); 935122394Sharti if (!do_extract && argc != optind) 936122394Sharti errx(1, "no arguments allowed"); 937122394Sharti if (do_extract && argc == optind) 938122394Sharti errx(1, "no objects specified"); 939122394Sharti 940122394Sharti root = parse(gettoken()); 941133211Sharti while ((tok = gettoken()) != TOK_EOF) 942133211Sharti merge(root, parse(tok)); 943122394Sharti 944122394Sharti check_tree(root); 945122394Sharti 946122394Sharti if (do_extract) { 947122394Sharti fp = stdout; 948122394Sharti while (optind < argc) { 949122394Sharti if (gen_extract(root, argv[optind])) 950122394Sharti errx(1, "object not found: %s", argv[optind]); 951122394Sharti optind++; 952122394Sharti } 953122394Sharti 954122394Sharti return (0); 955122394Sharti } 956133211Sharti if (do_tree) { 957133211Sharti gen_tree(root, 0); 958133211Sharti return (0); 959133211Sharti } 960122394Sharti sprintf(fname, "%stree.h", file_prefix); 961122394Sharti if ((fp = fopen(fname, "w")) == NULL) 962122394Sharti err(1, "%s: ", fname); 963122394Sharti gen_header(root, PREFIX_LEN, NULL); 964122394Sharti 965122394Sharti fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); 966122394Sharti fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); 967122394Sharti 968122394Sharti fclose(fp); 969122394Sharti 970122394Sharti sprintf(fname, "%stree.c", file_prefix); 971122394Sharti if ((fp = fopen(fname, "w")) == NULL) 972122394Sharti err(1, "%s: ", fname); 973122394Sharti gen_table(root); 974122394Sharti fclose(fp); 975122394Sharti 976122394Sharti return (0); 977122394Sharti} 978