1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6159063Sharti * Copyright (c) 2004-2006 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 * 33159063Sharti * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $ 34122394Sharti * 35122394Sharti * Generate OID table from table description. 36122394Sharti * 37122394Sharti * Syntax is: 38122394Sharti * --------- 39159063Sharti * file := top | top file 40133211Sharti * 41159063Sharti * top := tree | typedef | include 42159063Sharti * 43122394Sharti * tree := head elements ')' 44122394Sharti * 45122394Sharti * entry := head ':' index STRING elements ')' 46122394Sharti * 47159063Sharti * leaf := head type STRING ACCESS ')' 48122394Sharti * 49159063Sharti * column := head type ACCESS ')' 50122394Sharti * 51159063Sharti * type := BASETYPE | BASETYPE '|' subtype | enum | bits 52159063Sharti * 53159063Sharti * subtype := STRING 54159063Sharti * 55159063Sharti * enum := ENUM '(' value ')' 56159063Sharti * 57159063Sharti * bits := BITS '(' value ')' 58159063Sharti * 59159063Sharti * value := optminus INT STRING | optminus INT STRING value 60159063Sharti * 61159063Sharti * optminus := '-' | EMPTY 62159063Sharti * 63122394Sharti * head := '(' INT STRING 64122394Sharti * 65122394Sharti * elements := EMPTY | elements element 66122394Sharti * 67142810Sharti * element := tree | leaf | column 68122394Sharti * 69159063Sharti * index := type | index type 70122394Sharti * 71159063Sharti * typedef := 'typedef' STRING type 72159063Sharti * 73159063Sharti * include := 'include' filespec 74159063Sharti * 75159063Sharti * filespec := '"' STRING '"' | '<' STRING '>' 76122394Sharti */ 77122394Sharti#include <sys/types.h> 78122394Sharti#include <sys/param.h> 79122394Sharti#include <stdio.h> 80122394Sharti#include <stdlib.h> 81122394Sharti#include <stdarg.h> 82122394Sharti#include <unistd.h> 83122394Sharti#include <string.h> 84122394Sharti#include <ctype.h> 85133429Sharti#include <inttypes.h> 86133211Sharti#include <errno.h> 87133211Sharti#ifdef HAVE_ERR_H 88122394Sharti#include <err.h> 89133211Sharti#endif 90122394Sharti#include <sys/queue.h> 91133211Sharti#include "support.h" 92122394Sharti#include "asn1.h" 93122394Sharti#include "snmp.h" 94122394Sharti#include "snmpagent.h" 95122394Sharti 96122394Sharti/* 97122394Sharti * Constant prefix for all OIDs 98122394Sharti */ 99122394Shartistatic const asn_subid_t prefix[] = { 1, 3, 6 }; 100122394Sharti#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) 101122394Sharti 102122394Shartiu_int tree_size; 103122394Shartistatic const char *file_prefix = ""; 104122394Sharti 105122394Sharti/* if true generate local include paths */ 106122394Shartistatic int localincs = 0; 107122394Sharti 108159063Sharti/* if true print tokens */ 109159063Shartistatic int debug; 110159063Sharti 111122394Shartistatic const char usgtxt[] = "\ 112159063ShartiGenerate SNMP tables.\n\ 113159063Shartiusage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\n\ 114159063Sharti [name]...\n\ 115122394Shartioptions:\n\ 116159063Sharti -d debug mode\n\ 117159063Sharti -E extract the named enums and bits only\n\ 118159063Sharti -e extract the named oids or enums\n\ 119122394Sharti -h print this info\n\ 120159063Sharti -I directory add directory to include path\n\ 121159063Sharti -i ifile read from the named file instead of stdin\n\ 122122394Sharti -l generate local include directives\n\ 123122394Sharti -p prefix prepend prefix to file and variable names\n\ 124159063Sharti -t generated a .def file\n\ 125122394Sharti"; 126122394Sharti 127122394Sharti/* 128122394Sharti * A node in the OID tree 129122394Sharti */ 130122394Shartienum ntype { 131122394Sharti NODE_LEAF = 1, 132122394Sharti NODE_TREE, 133122394Sharti NODE_ENTRY, 134122394Sharti NODE_COLUMN 135122394Sharti}; 136122394Sharti 137122394Shartienum { 138122394Sharti FL_GET = 0x01, 139122394Sharti FL_SET = 0x02, 140122394Sharti}; 141122394Sharti 142122394Shartistruct node; 143122394ShartiTAILQ_HEAD(node_list, node); 144122394Sharti 145122394Shartistruct node { 146122394Sharti enum ntype type; 147122394Sharti asn_subid_t id; /* last element of OID */ 148122394Sharti char *name; /* name of node */ 149122394Sharti TAILQ_ENTRY(node) link; 150122394Sharti u_int lno; /* starting line number */ 151122394Sharti u_int flags; /* allowed operations */ 152122394Sharti 153122394Sharti union { 154122394Sharti struct tree { 155122394Sharti struct node_list subs; 156122394Sharti } tree; 157122394Sharti 158122394Sharti struct entry { 159133211Sharti uint32_t index; /* index for table entry */ 160122394Sharti char *func; /* function for tables */ 161122394Sharti struct node_list subs; 162122394Sharti } entry; 163122394Sharti 164122394Sharti struct leaf { 165122394Sharti enum snmp_syntax syntax; /* syntax for this leaf */ 166122394Sharti char *func; /* function name */ 167122394Sharti } leaf; 168122394Sharti 169122394Sharti struct column { 170122394Sharti enum snmp_syntax syntax; /* syntax for this column */ 171122394Sharti } column; 172122394Sharti } u; 173122394Sharti}; 174122394Sharti 175122394Shartistruct func { 176122394Sharti const char *name; 177122394Sharti LIST_ENTRY(func) link; 178122394Sharti}; 179122394Sharti 180122394Shartistatic LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); 181122394Sharti 182159063Shartistruct enums { 183159063Sharti const char *name; 184159063Sharti long value; 185159063Sharti TAILQ_ENTRY(enums) link; 186159063Sharti}; 187159063Sharti 188159063Shartistruct type { 189159063Sharti const char *name; 190159063Sharti const char *from_fname; 191159063Sharti u_int from_lno; 192159063Sharti u_int syntax; 193159063Sharti int is_enum; 194159063Sharti int is_bits; 195159063Sharti TAILQ_HEAD(, enums) enums; 196159063Sharti LIST_ENTRY(type) link; 197159063Sharti}; 198159063Sharti 199159063Shartistatic LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types); 200159063Sharti 201159063Shartistatic void report(const char *, ...) __dead2 __printflike(1, 2); 202159063Shartistatic void report_node(const struct node *, const char *, ...) 203159063Sharti __dead2 __printflike(2, 3); 204159063Sharti 205122394Sharti/************************************************************ 206122394Sharti * 207122394Sharti * Allocate memory and panic just in the case... 208122394Sharti */ 209122394Shartistatic void * 210122394Shartixalloc(size_t size) 211122394Sharti{ 212122394Sharti void *ptr; 213122394Sharti 214122394Sharti if ((ptr = malloc(size)) == NULL) 215145557Sharti err(1, "allocing %zu bytes", size); 216122394Sharti 217122394Sharti return (ptr); 218122394Sharti} 219122394Sharti 220159063Shartistatic char * 221159063Shartisavestr(const char *s) 222159063Sharti{ 223159063Sharti 224159063Sharti if (s == NULL) 225159063Sharti return (NULL); 226159063Sharti return (strcpy(xalloc(strlen(s) + 1), s)); 227159063Sharti} 228159063Sharti 229122394Sharti/************************************************************ 230122394Sharti * 231159063Sharti * Input stack 232159063Sharti */ 233159063Shartistruct input { 234159063Sharti FILE *fp; 235159063Sharti u_int lno; 236159063Sharti char *fname; 237159063Sharti char *path; 238159063Sharti LIST_ENTRY(input) link; 239159063Sharti}; 240159063Shartistatic LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); 241159063Shartistatic struct input *input = NULL; 242159063Sharti 243159063Sharti#define MAX_PATHS 100 244159063Shartistatic u_int npaths = 2; 245159063Shartistatic u_int stdpaths = 2; 246159063Shartistatic const char *paths[MAX_PATHS + 1] = { 247159063Sharti "/usr/share/snmp/defs", 248159063Sharti "/usr/local/share/snmp/defs", 249159063Sharti NULL 250159063Sharti}; 251159063Sharti 252159063Shartistatic int pbchar = -1; 253159063Sharti 254159063Shartistatic void 255159063Shartipath_new(const char *path) 256159063Sharti{ 257159063Sharti if (npaths >= MAX_PATHS) 258159063Sharti report("too many -I directives"); 259159063Sharti memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths], 260159063Sharti sizeof(path[0]) * stdpaths); 261159063Sharti paths[npaths - stdpaths] = savestr(path); 262159063Sharti npaths++; 263159063Sharti} 264159063Sharti 265159063Shartistatic void 266159063Shartiinput_new(FILE *fp, const char *path, const char *fname) 267159063Sharti{ 268159063Sharti struct input *ip; 269159063Sharti 270159063Sharti ip = xalloc(sizeof(*ip)); 271159063Sharti ip->fp = fp; 272159063Sharti ip->lno = 1; 273159063Sharti ip->fname = savestr(fname); 274159063Sharti ip->path = savestr(path); 275159063Sharti LIST_INSERT_HEAD(&inputs, ip, link); 276159063Sharti 277159063Sharti input = ip; 278159063Sharti} 279159063Sharti 280159063Shartistatic void 281159063Shartiinput_close(void) 282159063Sharti{ 283159063Sharti 284159063Sharti if (input == NULL) 285159063Sharti return; 286159063Sharti fclose(input->fp); 287159063Sharti free(input->fname); 288159063Sharti free(input->path); 289159063Sharti LIST_REMOVE(input, link); 290159063Sharti free(input); 291159063Sharti 292159063Sharti input = LIST_FIRST(&inputs); 293159063Sharti} 294159063Sharti 295159063Shartistatic FILE * 296159063Shartitryopen(const char *path, const char *fname) 297159063Sharti{ 298159063Sharti char *fn; 299159063Sharti FILE *fp; 300159063Sharti 301159063Sharti if (path == NULL) 302159063Sharti fn = savestr(fname); 303159063Sharti else { 304159063Sharti fn = xalloc(strlen(path) + strlen(fname) + 2); 305159063Sharti sprintf(fn, "%s/%s", path, fname); 306159063Sharti } 307159063Sharti fp = fopen(fn, "r"); 308159063Sharti free(fn); 309159063Sharti return (fp); 310159063Sharti} 311159063Sharti 312159063Shartistatic void 313159063Shartiinput_fopen(const char *fname, int loc) 314159063Sharti{ 315159063Sharti FILE *fp; 316159063Sharti char *path; 317159063Sharti u_int p; 318159063Sharti 319159063Sharti if (fname[0] == '/') { 320159063Sharti if ((fp = tryopen(NULL, fname)) != NULL) { 321159063Sharti input_new(fp, NULL, fname); 322159063Sharti return; 323159063Sharti } 324159063Sharti 325159063Sharti } else { 326159063Sharti if (loc) { 327159063Sharti if (input == NULL) 328159063Sharti path = NULL; 329159063Sharti else 330159063Sharti path = input->path; 331159063Sharti 332159063Sharti if ((fp = tryopen(path, fname)) != NULL) { 333159063Sharti input_new(fp, NULL, fname); 334159063Sharti return; 335159063Sharti } 336159063Sharti } 337159063Sharti 338159063Sharti for (p = 0; paths[p] != NULL; p++) 339159063Sharti if ((fp = tryopen(paths[p], fname)) != NULL) { 340159063Sharti input_new(fp, paths[p], fname); 341159063Sharti return; 342159063Sharti } 343159063Sharti } 344159063Sharti report("cannot open '%s'", fname); 345159063Sharti} 346159063Sharti 347159063Shartistatic int 348159063Shartitgetc(void) 349159063Sharti{ 350159063Sharti int c; 351159063Sharti 352159063Sharti if (pbchar != -1) { 353159063Sharti c = pbchar; 354159063Sharti pbchar = -1; 355159063Sharti return (c); 356159063Sharti } 357159063Sharti 358159063Sharti for (;;) { 359159063Sharti if (input == NULL) 360159063Sharti return (EOF); 361159063Sharti 362159063Sharti if ((c = getc(input->fp)) != EOF) 363159063Sharti return (c); 364159063Sharti 365159063Sharti input_close(); 366159063Sharti } 367159063Sharti} 368159063Sharti 369159063Shartistatic void 370159063Shartitungetc(int c) 371159063Sharti{ 372159063Sharti 373159063Sharti if (pbchar != -1) 374159063Sharti abort(); 375159063Sharti pbchar = c; 376159063Sharti} 377159063Sharti 378159063Sharti/************************************************************ 379159063Sharti * 380122394Sharti * Parsing input 381122394Sharti */ 382122394Shartienum tok { 383122394Sharti TOK_EOF = 0200, /* end-of-file seen */ 384122394Sharti TOK_NUM, /* number */ 385122394Sharti TOK_STR, /* string */ 386122394Sharti TOK_ACCESS, /* access operator */ 387122394Sharti TOK_TYPE, /* type operator */ 388159063Sharti TOK_ENUM, /* enum token (kind of a type) */ 389159063Sharti TOK_TYPEDEF, /* typedef directive */ 390159063Sharti TOK_DEFTYPE, /* defined type */ 391159063Sharti TOK_INCLUDE, /* include directive */ 392159063Sharti TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */ 393159063Sharti TOK_BITS, /* bits token (kind of a type) */ 394122394Sharti}; 395122394Sharti 396122394Shartistatic const struct { 397122394Sharti const char *str; 398122394Sharti enum tok tok; 399122394Sharti u_int val; 400122394Sharti} keywords[] = { 401122394Sharti { "GET", TOK_ACCESS, FL_GET }, 402122394Sharti { "SET", TOK_ACCESS, FL_SET }, 403122394Sharti { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, 404122394Sharti { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 405122394Sharti { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, 406122394Sharti { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 407122394Sharti { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, 408122394Sharti { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, 409122394Sharti { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, 410122394Sharti { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, 411122394Sharti { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, 412122394Sharti { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, 413122394Sharti { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, 414159063Sharti { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, 415159063Sharti { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, 416159063Sharti { "typedef", TOK_TYPEDEF, 0 }, 417159063Sharti { "include", TOK_INCLUDE, 0 }, 418122394Sharti { NULL, 0, 0 } 419122394Sharti}; 420122394Sharti 421122394Sharti/* arbitrary upper limit on node names and function names */ 422122394Sharti#define MAXSTR 1000 423122394Shartichar str[MAXSTR]; 424122394Shartiu_long val; /* integer values */ 425133211Shartiint all_cond; /* all conditions are true */ 426159063Shartiint saved_token = -1; 427122394Sharti 428122394Sharti/* 429122394Sharti * Report an error and exit. 430122394Sharti */ 431122394Shartistatic void 432122394Shartireport(const char *fmt, ...) 433122394Sharti{ 434122394Sharti va_list ap; 435122394Sharti int c; 436122394Sharti 437122394Sharti va_start(ap, fmt); 438159063Sharti fprintf(stderr, "line %u: ", input->lno); 439122394Sharti vfprintf(stderr, fmt, ap); 440122394Sharti fprintf(stderr, "\n"); 441122394Sharti fprintf(stderr, "context: \""); 442159063Sharti while ((c = tgetc()) != EOF && c != '\n') 443122394Sharti fprintf(stderr, "%c", c); 444122394Sharti fprintf(stderr, "\n"); 445122394Sharti va_end(ap); 446122394Sharti exit(1); 447122394Sharti} 448122394Shartistatic void 449122394Shartireport_node(const struct node *np, const char *fmt, ...) 450122394Sharti{ 451122394Sharti va_list ap; 452122394Sharti 453122394Sharti va_start(ap, fmt); 454122394Sharti fprintf(stderr, "line %u, node %s: ", np->lno, np->name); 455122394Sharti vfprintf(stderr, fmt, ap); 456122394Sharti fprintf(stderr, "\n"); 457122394Sharti va_end(ap); 458122394Sharti exit(1); 459122394Sharti} 460122394Sharti 461122394Sharti/* 462122394Sharti * Return a fresh copy of the string constituting the current token. 463122394Sharti */ 464122394Shartistatic char * 465122394Shartisavetok(void) 466122394Sharti{ 467159063Sharti return (savestr(str)); 468122394Sharti} 469122394Sharti 470122394Sharti/* 471122394Sharti * Get the next token from input. 472122394Sharti */ 473122394Shartistatic int 474159063Shartigettoken_internal(void) 475122394Sharti{ 476122394Sharti int c; 477159063Sharti struct type *t; 478122394Sharti 479159063Sharti if (saved_token != -1) { 480159063Sharti c = saved_token; 481159063Sharti saved_token = -1; 482159063Sharti return (c); 483159063Sharti } 484159063Sharti 485122394Sharti again: 486122394Sharti /* 487122394Sharti * Skip any whitespace before the next token 488122394Sharti */ 489159063Sharti while ((c = tgetc()) != EOF) { 490122394Sharti if (c == '\n') 491159063Sharti input->lno++; 492122394Sharti if (!isspace(c)) 493122394Sharti break; 494122394Sharti } 495122394Sharti if (c == EOF) 496122394Sharti return (TOK_EOF); 497122394Sharti if (!isascii(c)) 498122394Sharti report("unexpected character %#2x", (u_int)c); 499122394Sharti 500122394Sharti /* 501122394Sharti * Skip comments 502122394Sharti */ 503122394Sharti if (c == '#') { 504159063Sharti while ((c = tgetc()) != EOF) { 505122394Sharti if (c == '\n') { 506159063Sharti input->lno++; 507122394Sharti goto again; 508122394Sharti } 509122394Sharti } 510122394Sharti report("unexpected EOF in comment"); 511122394Sharti } 512122394Sharti 513122394Sharti /* 514122394Sharti * Single character tokens 515122394Sharti */ 516159063Sharti if (strchr("():|-", c) != NULL) 517122394Sharti return (c); 518122394Sharti 519159063Sharti if (c == '"' || c == '<') { 520159063Sharti int end = c; 521159063Sharti size_t n = 0; 522159063Sharti 523159063Sharti val = 1; 524159063Sharti if (c == '<') { 525159063Sharti val = 0; 526159063Sharti end = '>'; 527159063Sharti } 528159063Sharti 529159063Sharti while ((c = tgetc()) != EOF) { 530159063Sharti if (c == end) 531159063Sharti break; 532159063Sharti if (n == sizeof(str) - 1) { 533159063Sharti str[n++] = '\0'; 534159063Sharti report("filename too long '%s...'", str); 535159063Sharti } 536159063Sharti str[n++] = c; 537159063Sharti } 538159063Sharti str[n++] = '\0'; 539159063Sharti return (TOK_FILENAME); 540159063Sharti } 541159063Sharti 542122394Sharti /* 543122394Sharti * Sort out numbers 544122394Sharti */ 545122394Sharti if (isdigit(c)) { 546159063Sharti size_t n = 0; 547159063Sharti str[n++] = c; 548159063Sharti while ((c = tgetc()) != EOF) { 549159063Sharti if (!isdigit(c)) { 550159063Sharti tungetc(c); 551159063Sharti break; 552159063Sharti } 553159063Sharti if (n == sizeof(str) - 1) { 554159063Sharti str[n++] = '\0'; 555159063Sharti report("number too long '%s...'", str); 556159063Sharti } 557159063Sharti str[n++] = c; 558159063Sharti } 559159063Sharti str[n++] = '\0'; 560159063Sharti sscanf(str, "%lu", &val); 561122394Sharti return (TOK_NUM); 562122394Sharti } 563122394Sharti 564122394Sharti /* 565122394Sharti * So that has to be a string. 566122394Sharti */ 567122394Sharti if (isalpha(c) || c == '_') { 568122394Sharti size_t n = 0; 569122394Sharti str[n++] = c; 570159063Sharti while ((c = tgetc()) != EOF) { 571159063Sharti if (!isalnum(c) && c != '_' && c != '-') { 572159063Sharti tungetc(c); 573122394Sharti break; 574122394Sharti } 575122394Sharti if (n == sizeof(str) - 1) { 576122394Sharti str[n++] = '\0'; 577122394Sharti report("string too long '%s...'", str); 578122394Sharti } 579122394Sharti str[n++] = c; 580122394Sharti } 581122394Sharti str[n++] = '\0'; 582122394Sharti 583122394Sharti /* 584122394Sharti * Keywords 585122394Sharti */ 586122394Sharti for (c = 0; keywords[c].str != NULL; c++) 587122394Sharti if (strcmp(keywords[c].str, str) == 0) { 588122394Sharti val = keywords[c].val; 589122394Sharti return (keywords[c].tok); 590122394Sharti } 591122394Sharti 592159063Sharti LIST_FOREACH(t, &types, link) { 593159063Sharti if (strcmp(t->name, str) == 0) { 594159063Sharti val = t->syntax; 595159063Sharti return (TOK_DEFTYPE); 596159063Sharti } 597159063Sharti } 598122394Sharti return (TOK_STR); 599122394Sharti } 600122394Sharti if (isprint(c)) 601159063Sharti errx(1, "%u: unexpected character '%c'", input->lno, c); 602122394Sharti else 603159063Sharti errx(1, "%u: unexpected character 0x%02x", input->lno, 604159063Sharti (u_int)c); 605122394Sharti} 606159063Shartistatic int 607159063Shartigettoken(void) 608159063Sharti{ 609159063Sharti int tok = gettoken_internal(); 610122394Sharti 611159063Sharti if (debug) { 612159063Sharti switch (tok) { 613159063Sharti 614159063Sharti case TOK_EOF: 615159063Sharti fprintf(stderr, "EOF "); 616159063Sharti break; 617159063Sharti 618159063Sharti case TOK_NUM: 619159063Sharti fprintf(stderr, "NUM(%lu) ", val); 620159063Sharti break; 621159063Sharti 622159063Sharti case TOK_STR: 623159063Sharti fprintf(stderr, "STR(%s) ", str); 624159063Sharti break; 625159063Sharti 626159063Sharti case TOK_ACCESS: 627159063Sharti fprintf(stderr, "ACCESS(%lu) ", val); 628159063Sharti break; 629159063Sharti 630159063Sharti case TOK_TYPE: 631159063Sharti fprintf(stderr, "TYPE(%lu) ", val); 632159063Sharti break; 633159063Sharti 634159063Sharti case TOK_ENUM: 635159063Sharti fprintf(stderr, "ENUM "); 636159063Sharti break; 637159063Sharti 638159063Sharti case TOK_BITS: 639159063Sharti fprintf(stderr, "BITS "); 640159063Sharti break; 641159063Sharti 642159063Sharti case TOK_TYPEDEF: 643159063Sharti fprintf(stderr, "TYPEDEF "); 644159063Sharti break; 645159063Sharti 646159063Sharti case TOK_DEFTYPE: 647159063Sharti fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val); 648159063Sharti break; 649159063Sharti 650159063Sharti case TOK_INCLUDE: 651159063Sharti fprintf(stderr, "INCLUDE "); 652159063Sharti break; 653159063Sharti 654159063Sharti case TOK_FILENAME: 655159063Sharti fprintf(stderr, "FILENAME "); 656159063Sharti break; 657159063Sharti 658159063Sharti default: 659159063Sharti if (tok < TOK_EOF) { 660159063Sharti if (isprint(tok)) 661159063Sharti fprintf(stderr, "'%c' ", tok); 662159063Sharti else if (tok == '\n') 663159063Sharti fprintf(stderr, "\n"); 664159063Sharti else 665159063Sharti fprintf(stderr, "%02x ", tok); 666159063Sharti } else 667159063Sharti abort(); 668159063Sharti break; 669159063Sharti } 670159063Sharti } 671159063Sharti return (tok); 672159063Sharti} 673159063Sharti 674159063Sharti/** 675159063Sharti * Pushback a token 676159063Sharti */ 677159063Shartistatic void 678159063Shartipushback(enum tok tok) 679159063Sharti{ 680159063Sharti 681159063Sharti if (saved_token != -1) 682159063Sharti abort(); 683159063Sharti saved_token = tok; 684159063Sharti} 685159063Sharti 686122394Sharti/* 687159063Sharti * Create a new type 688159063Sharti */ 689159063Shartistatic struct type * 690159063Shartimake_type(const char *s) 691159063Sharti{ 692159063Sharti struct type *t; 693159063Sharti 694159063Sharti t = xalloc(sizeof(*t)); 695159063Sharti t->name = savestr(s); 696159063Sharti t->is_enum = 0; 697159063Sharti t->syntax = SNMP_SYNTAX_NULL; 698159063Sharti t->from_fname = savestr(input->fname); 699159063Sharti t->from_lno = input->lno; 700159063Sharti TAILQ_INIT(&t->enums); 701159063Sharti LIST_INSERT_HEAD(&types, t, link); 702159063Sharti 703159063Sharti return (t); 704159063Sharti} 705159063Sharti 706159063Sharti/* 707159063Sharti * Parse a type. We've seen the ENUM or type keyword already. Leave next 708159063Sharti * token. 709159063Sharti */ 710159063Shartistatic u_int 711159063Shartiparse_type(enum tok *tok, struct type *t, const char *vname) 712159063Sharti{ 713159063Sharti u_int syntax; 714159063Sharti struct enums *e; 715159063Sharti 716159063Sharti syntax = val; 717159063Sharti 718159063Sharti if (*tok == TOK_ENUM || *tok == TOK_BITS) { 719159063Sharti if (t == NULL && vname != NULL) { 720159063Sharti t = make_type(vname); 721159063Sharti t->is_enum = (*tok == TOK_ENUM); 722159063Sharti t->is_bits = (*tok == TOK_BITS); 723159063Sharti t->syntax = syntax; 724159063Sharti } 725159063Sharti if (gettoken() != '(') 726159063Sharti report("'(' expected after ENUM"); 727159063Sharti 728159063Sharti if ((*tok = gettoken()) == TOK_EOF) 729159063Sharti report("unexpected EOF in ENUM"); 730159063Sharti do { 731159063Sharti e = NULL; 732159063Sharti if (t != NULL) { 733159063Sharti e = xalloc(sizeof(*e)); 734159063Sharti } 735159063Sharti if (*tok == '-') { 736159063Sharti if ((*tok = gettoken()) == TOK_EOF) 737159063Sharti report("unexpected EOF in ENUM"); 738159063Sharti e->value = -(long)val; 739159063Sharti } else 740159063Sharti e->value = val; 741159063Sharti 742159063Sharti if (*tok != TOK_NUM) 743159063Sharti report("need value for ENUM/BITS"); 744159063Sharti if (gettoken() != TOK_STR) 745159063Sharti report("need string in ENUM/BITS"); 746159063Sharti if (e != NULL) { 747159063Sharti e->name = savetok(); 748159063Sharti TAILQ_INSERT_TAIL(&t->enums, e, link); 749159063Sharti } 750159063Sharti if ((*tok = gettoken()) == TOK_EOF) 751159063Sharti report("unexpected EOF in ENUM/BITS"); 752159063Sharti } while (*tok != ')'); 753159063Sharti *tok = gettoken(); 754159063Sharti 755159063Sharti } else if (*tok == TOK_DEFTYPE) { 756159063Sharti *tok = gettoken(); 757159063Sharti 758159063Sharti } else { 759159063Sharti if ((*tok = gettoken()) == '|') { 760159063Sharti if (gettoken() != TOK_STR) 761159063Sharti report("subtype expected after '|'"); 762159063Sharti *tok = gettoken(); 763159063Sharti } 764159063Sharti } 765159063Sharti 766159063Sharti return (syntax); 767159063Sharti} 768159063Sharti 769159063Sharti/* 770122394Sharti * Parse the next node (complete with all subnodes) 771122394Sharti */ 772122394Shartistatic struct node * 773122394Shartiparse(enum tok tok) 774122394Sharti{ 775122394Sharti struct node *node; 776122394Sharti struct node *sub; 777122394Sharti u_int index_count; 778122394Sharti 779122394Sharti node = xalloc(sizeof(struct node)); 780159063Sharti node->lno = input->lno; 781154182Sharti node->flags = 0; 782122394Sharti 783122394Sharti if (tok != '(') 784122394Sharti report("'(' expected at begin of node"); 785122394Sharti if (gettoken() != TOK_NUM) 786122394Sharti report("node id expected after opening '('"); 787122394Sharti if (val > ASN_MAXID) 788122394Sharti report("subid too large '%lu'", val); 789122394Sharti node->id = (asn_subid_t)val; 790122394Sharti if (gettoken() != TOK_STR) 791122394Sharti report("node name expected after '(' ID"); 792122394Sharti node->name = savetok(); 793122394Sharti 794159063Sharti if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || 795159063Sharti tok == TOK_ENUM || tok == TOK_BITS) { 796122394Sharti /* LEAF or COLUM */ 797159063Sharti u_int syntax = parse_type(&tok, NULL, node->name); 798122394Sharti 799159063Sharti if (tok == TOK_STR) { 800122394Sharti /* LEAF */ 801122394Sharti node->type = NODE_LEAF; 802122394Sharti node->u.leaf.func = savetok(); 803122394Sharti node->u.leaf.syntax = syntax; 804122394Sharti tok = gettoken(); 805122394Sharti } else { 806122394Sharti /* COLUMN */ 807122394Sharti node->type = NODE_COLUMN; 808122394Sharti node->u.column.syntax = syntax; 809122394Sharti } 810122394Sharti 811122394Sharti while (tok != ')') { 812122394Sharti if (tok != TOK_ACCESS) 813122394Sharti report("access keyword or ')' expected"); 814122394Sharti node->flags |= (u_int)val; 815122394Sharti tok = gettoken(); 816122394Sharti } 817122394Sharti 818122394Sharti } else if (tok == ':') { 819122394Sharti /* ENTRY */ 820122394Sharti node->type = NODE_ENTRY; 821122394Sharti TAILQ_INIT(&node->u.entry.subs); 822122394Sharti 823122394Sharti index_count = 0; 824122394Sharti node->u.entry.index = 0; 825159063Sharti tok = gettoken(); 826159063Sharti while (tok == TOK_TYPE || tok == TOK_DEFTYPE || 827159063Sharti tok == TOK_ENUM || tok == TOK_BITS) { 828159063Sharti u_int syntax = parse_type(&tok, NULL, node->name); 829122394Sharti if (index_count++ == SNMP_INDEXES_MAX) 830122394Sharti report("too many table indexes"); 831122394Sharti node->u.entry.index |= 832159063Sharti syntax << (SNMP_INDEX_SHIFT * index_count); 833122394Sharti } 834122394Sharti node->u.entry.index |= index_count; 835122394Sharti if (index_count == 0) 836122394Sharti report("need at least one index"); 837122394Sharti if (tok != TOK_STR) 838122394Sharti report("function name expected"); 839122394Sharti 840122394Sharti node->u.entry.func = savetok(); 841122394Sharti 842122394Sharti tok = gettoken(); 843122394Sharti 844122394Sharti while (tok != ')') { 845122394Sharti sub = parse(tok); 846122394Sharti TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); 847122394Sharti tok = gettoken(); 848122394Sharti } 849122394Sharti 850122394Sharti } else { 851122394Sharti /* subtree */ 852122394Sharti node->type = NODE_TREE; 853122394Sharti TAILQ_INIT(&node->u.tree.subs); 854122394Sharti 855122394Sharti while (tok != ')') { 856122394Sharti sub = parse(tok); 857122394Sharti TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); 858122394Sharti tok = gettoken(); 859122394Sharti } 860122394Sharti } 861122394Sharti return (node); 862122394Sharti} 863122394Sharti 864122394Sharti/* 865159063Sharti * Parse a top level element. Return the tree if it was a tree, NULL 866159063Sharti * otherwise. 867159063Sharti */ 868159063Shartistatic struct node * 869159063Shartiparse_top(enum tok tok) 870159063Sharti{ 871159063Sharti struct type *t; 872159063Sharti 873159063Sharti if (tok == '(') 874159063Sharti return (parse(tok)); 875159063Sharti 876159063Sharti if (tok == TOK_TYPEDEF) { 877159063Sharti if (gettoken() != TOK_STR) 878159063Sharti report("type name expected after typedef"); 879159063Sharti 880159063Sharti t = make_type(str); 881159063Sharti 882159063Sharti tok = gettoken(); 883159063Sharti t->is_enum = (tok == TOK_ENUM); 884159063Sharti t->is_bits = (tok == TOK_BITS); 885159063Sharti t->syntax = parse_type(&tok, t, NULL); 886159063Sharti pushback(tok); 887159063Sharti 888159063Sharti return (NULL); 889159063Sharti } 890159063Sharti 891159063Sharti if (tok == TOK_INCLUDE) { 892159063Sharti if (gettoken() != TOK_FILENAME) 893159063Sharti report("filename expected in include directive"); 894159063Sharti 895159063Sharti input_fopen(str, val); 896159063Sharti return (NULL); 897159063Sharti } 898159063Sharti 899159063Sharti report("'(' or 'typedef' expected"); 900159063Sharti} 901159063Sharti 902159063Sharti/* 903122394Sharti * Generate the C-code table part for one node. 904122394Sharti */ 905122394Shartistatic void 906159063Shartigen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, 907159063Sharti const char *func) 908122394Sharti{ 909122394Sharti u_int n; 910122394Sharti struct node *sub; 911122394Sharti u_int syntax; 912122394Sharti 913122394Sharti if (oid->len == ASN_MAXOIDLEN) 914122394Sharti report_node(np, "OID too long"); 915122394Sharti oid->subs[oid->len++] = np->id; 916122394Sharti 917122394Sharti if (np->type == NODE_TREE) { 918122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 919159063Sharti gen_node(fp, sub, oid, 0, NULL); 920122394Sharti oid->len--; 921122394Sharti return; 922122394Sharti } 923122394Sharti if (np->type == NODE_ENTRY) { 924122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 925159063Sharti gen_node(fp, sub, oid, np->u.entry.index, 926159063Sharti np->u.entry.func); 927122394Sharti oid->len--; 928122394Sharti return; 929122394Sharti } 930122394Sharti 931122394Sharti /* leaf or column */ 932122394Sharti if ((np->flags & (FL_GET|FL_SET)) == 0) { 933122394Sharti oid->len--; 934122394Sharti return; 935122394Sharti } 936122394Sharti 937122394Sharti fprintf(fp, " {{ %u, {", oid->len); 938122394Sharti for (n = 0; n < oid->len; n++) 939122394Sharti fprintf(fp, " %u,", oid->subs[n]); 940122394Sharti fprintf(fp, " }}, \"%s\", ", np->name); 941122394Sharti 942122394Sharti if (np->type == NODE_COLUMN) { 943122394Sharti syntax = np->u.column.syntax; 944122394Sharti fprintf(fp, "SNMP_NODE_COLUMN, "); 945122394Sharti } else { 946122394Sharti syntax = np->u.leaf.syntax; 947122394Sharti fprintf(fp, "SNMP_NODE_LEAF, "); 948122394Sharti } 949122394Sharti 950122394Sharti switch (syntax) { 951122394Sharti 952122394Sharti case SNMP_SYNTAX_NULL: 953122394Sharti fprintf(fp, "SNMP_SYNTAX_NULL, "); 954122394Sharti break; 955122394Sharti 956122394Sharti case SNMP_SYNTAX_INTEGER: 957122394Sharti fprintf(fp, "SNMP_SYNTAX_INTEGER, "); 958122394Sharti break; 959122394Sharti 960122394Sharti case SNMP_SYNTAX_OCTETSTRING: 961122394Sharti fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); 962122394Sharti break; 963122394Sharti 964122394Sharti case SNMP_SYNTAX_IPADDRESS: 965122394Sharti fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); 966122394Sharti break; 967122394Sharti 968122394Sharti case SNMP_SYNTAX_OID: 969122394Sharti fprintf(fp, "SNMP_SYNTAX_OID, "); 970122394Sharti break; 971122394Sharti 972122394Sharti case SNMP_SYNTAX_TIMETICKS: 973122394Sharti fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); 974122394Sharti break; 975122394Sharti 976122394Sharti case SNMP_SYNTAX_COUNTER: 977122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER, "); 978122394Sharti break; 979122394Sharti 980122394Sharti case SNMP_SYNTAX_GAUGE: 981122394Sharti fprintf(fp, "SNMP_SYNTAX_GAUGE, "); 982122394Sharti break; 983122394Sharti 984122394Sharti case SNMP_SYNTAX_COUNTER64: 985122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); 986122394Sharti break; 987122394Sharti 988122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 989122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 990122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 991122394Sharti abort(); 992122394Sharti } 993122394Sharti 994122394Sharti if (np->type == NODE_COLUMN) 995122394Sharti fprintf(fp, "%s, ", func); 996122394Sharti else 997122394Sharti fprintf(fp, "%s, ", np->u.leaf.func); 998122394Sharti 999122394Sharti fprintf(fp, "0"); 1000122394Sharti if (np->flags & FL_SET) 1001122394Sharti fprintf(fp, "|SNMP_NODE_CANSET"); 1002128237Sharti fprintf(fp, ", %#x, NULL, NULL },\n", idx); 1003122394Sharti oid->len--; 1004122394Sharti return; 1005122394Sharti} 1006122394Sharti 1007122394Sharti/* 1008122394Sharti * Generate the header file with the function declarations. 1009122394Sharti */ 1010122394Shartistatic void 1011159063Shartigen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) 1012122394Sharti{ 1013122394Sharti char f[MAXSTR + 4]; 1014122394Sharti struct node *sub; 1015122394Sharti struct func *ptr; 1016122394Sharti 1017122394Sharti oidlen++; 1018122394Sharti if (np->type == NODE_TREE) { 1019122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1020159063Sharti gen_header(fp, sub, oidlen, NULL); 1021122394Sharti return; 1022122394Sharti } 1023122394Sharti if (np->type == NODE_ENTRY) { 1024122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1025159063Sharti gen_header(fp, sub, oidlen, np->u.entry.func); 1026122394Sharti return; 1027122394Sharti } 1028122394Sharti 1029122394Sharti if((np->flags & (FL_GET|FL_SET)) == 0) 1030122394Sharti return; 1031122394Sharti 1032142810Sharti if (np->type == NODE_COLUMN) { 1033142810Sharti if (func == NULL) 1034142810Sharti errx(1, "column without function (%s) - probably " 1035142810Sharti "outside of a table", np->name); 1036122394Sharti sprintf(f, "%s", func); 1037142810Sharti } else 1038122394Sharti sprintf(f, "%s", np->u.leaf.func); 1039122394Sharti 1040122394Sharti LIST_FOREACH(ptr, &funcs, link) 1041122394Sharti if (strcmp(ptr->name, f) == 0) 1042122394Sharti break; 1043122394Sharti 1044122394Sharti if (ptr == NULL) { 1045122394Sharti ptr = xalloc(sizeof(*ptr)); 1046159063Sharti ptr->name = savestr(f); 1047122394Sharti LIST_INSERT_HEAD(&funcs, ptr, link); 1048122394Sharti 1049122394Sharti fprintf(fp, "int %s(struct snmp_context *, " 1050122394Sharti "struct snmp_value *, u_int, u_int, " 1051122394Sharti "enum snmp_op);\n", f); 1052122394Sharti } 1053122394Sharti 1054122394Sharti fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); 1055122394Sharti} 1056122394Sharti 1057122394Sharti/* 1058122394Sharti * Generate the OID table. 1059122394Sharti */ 1060122394Shartistatic void 1061159063Shartigen_table(FILE *fp, struct node *node) 1062122394Sharti{ 1063122394Sharti struct asn_oid oid; 1064122394Sharti 1065122394Sharti fprintf(fp, "#include <sys/types.h>\n"); 1066122394Sharti fprintf(fp, "#include <stdio.h>\n"); 1067150920Sharti#ifdef HAVE_STDINT_H 1068133211Sharti fprintf(fp, "#include <stdint.h>\n"); 1069150920Sharti#endif 1070122394Sharti if (localincs) { 1071122394Sharti fprintf(fp, "#include \"asn1.h\"\n"); 1072122394Sharti fprintf(fp, "#include \"snmp.h\"\n"); 1073122394Sharti fprintf(fp, "#include \"snmpagent.h\"\n"); 1074122394Sharti } else { 1075122394Sharti fprintf(fp, "#include <bsnmp/asn1.h>\n"); 1076122394Sharti fprintf(fp, "#include <bsnmp/snmp.h>\n"); 1077122394Sharti fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); 1078122394Sharti } 1079122394Sharti fprintf(fp, "#include \"%stree.h\"\n", file_prefix); 1080122394Sharti fprintf(fp, "\n"); 1081122394Sharti 1082122394Sharti fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); 1083122394Sharti 1084122394Sharti oid.len = PREFIX_LEN; 1085122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 1086159063Sharti gen_node(fp, node, &oid, 0, NULL); 1087122394Sharti 1088122394Sharti fprintf(fp, "};\n\n"); 1089122394Sharti} 1090122394Sharti 1091133211Shartistatic void 1092133211Shartiprint_syntax(u_int syntax) 1093133211Sharti{ 1094133211Sharti u_int i; 1095133211Sharti 1096133211Sharti for (i = 0; keywords[i].str != NULL; i++) 1097133211Sharti if (keywords[i].tok == TOK_TYPE && 1098133211Sharti keywords[i].val == syntax) { 1099133211Sharti printf(" %s", keywords[i].str); 1100133211Sharti return; 1101133211Sharti } 1102133211Sharti abort(); 1103133211Sharti} 1104133211Sharti 1105133211Sharti/* 1106133211Sharti * Generate a tree definition file 1107133211Sharti */ 1108133211Shartistatic void 1109133211Shartigen_tree(const struct node *np, int level) 1110133211Sharti{ 1111133211Sharti const struct node *sp; 1112133211Sharti u_int i; 1113133211Sharti 1114133211Sharti printf("%*s(%u %s", 2 * level, "", np->id, np->name); 1115133211Sharti 1116133211Sharti switch (np->type) { 1117133211Sharti 1118133211Sharti case NODE_LEAF: 1119133211Sharti print_syntax(np->u.leaf.syntax); 1120133211Sharti printf(" %s%s%s)\n", np->u.leaf.func, 1121133211Sharti (np->flags & FL_GET) ? " GET" : "", 1122133211Sharti (np->flags & FL_SET) ? " SET" : ""); 1123133211Sharti break; 1124133211Sharti 1125133211Sharti case NODE_TREE: 1126133211Sharti if (TAILQ_EMPTY(&np->u.tree.subs)) { 1127133211Sharti printf(")\n"); 1128133211Sharti } else { 1129133211Sharti printf("\n"); 1130133211Sharti TAILQ_FOREACH(sp, &np->u.tree.subs, link) 1131133211Sharti gen_tree(sp, level + 1); 1132133211Sharti printf("%*s)\n", 2 * level, ""); 1133133211Sharti } 1134133211Sharti break; 1135133211Sharti 1136133211Sharti case NODE_ENTRY: 1137133211Sharti printf(" :"); 1138133211Sharti 1139133211Sharti for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) 1140133211Sharti print_syntax(SNMP_INDEX(np->u.entry.index, i)); 1141133211Sharti printf(" %s\n", np->u.entry.func); 1142133211Sharti TAILQ_FOREACH(sp, &np->u.entry.subs, link) 1143133211Sharti gen_tree(sp, level + 1); 1144133211Sharti printf("%*s)\n", 2 * level, ""); 1145133211Sharti break; 1146133211Sharti 1147133211Sharti case NODE_COLUMN: 1148133211Sharti print_syntax(np->u.column.syntax); 1149133211Sharti printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", 1150133211Sharti (np->flags & FL_SET) ? " SET" : ""); 1151133211Sharti break; 1152133211Sharti } 1153133211Sharti} 1154133211Sharti 1155122394Shartistatic int 1156159063Shartiextract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj, 1157133211Sharti const struct asn_oid *idx, const char *iname) 1158122394Sharti{ 1159122394Sharti struct node *sub; 1160122394Sharti u_long n; 1161122394Sharti 1162122394Sharti if (oid->len == ASN_MAXOIDLEN) 1163122394Sharti report_node(np, "OID too long"); 1164122394Sharti oid->subs[oid->len++] = np->id; 1165122394Sharti 1166122394Sharti if (strcmp(obj, np->name) == 0) { 1167133211Sharti if (oid->len + idx->len >= ASN_MAXOIDLEN) 1168133211Sharti report_node(np, "OID too long"); 1169133211Sharti fprintf(fp, "#define OID_%s%s\t%u\n", np->name, 1170133211Sharti iname ? iname : "", np->id); 1171133211Sharti fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, 1172133211Sharti iname ? iname : "", oid->len + idx->len); 1173133211Sharti fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, 1174133211Sharti iname ? iname : "", oid->len + idx->len); 1175122394Sharti for (n = 0; n < oid->len; n++) 1176122394Sharti fprintf(fp, " %u,", oid->subs[n]); 1177133211Sharti for (n = 0; n < idx->len; n++) 1178133211Sharti fprintf(fp, " %u,", idx->subs[n]); 1179122394Sharti fprintf(fp, " } }\n"); 1180122394Sharti return (0); 1181122394Sharti } 1182122394Sharti 1183122394Sharti if (np->type == NODE_TREE) { 1184122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1185159063Sharti if (!extract(fp, sub, oid, obj, idx, iname)) 1186122394Sharti return (0); 1187122394Sharti } else if (np->type == NODE_ENTRY) { 1188122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1189159063Sharti if (!extract(fp, sub, oid, obj, idx, iname)) 1190122394Sharti return (0); 1191122394Sharti } 1192122394Sharti oid->len--; 1193122394Sharti return (1); 1194122394Sharti} 1195122394Sharti 1196122394Shartistatic int 1197159063Shartigen_extract(FILE *fp, const struct node *root, char *object) 1198122394Sharti{ 1199122394Sharti struct asn_oid oid; 1200133211Sharti struct asn_oid idx; 1201133211Sharti char *s, *e, *end, *iname; 1202133211Sharti u_long ul; 1203133211Sharti int ret; 1204122394Sharti 1205133211Sharti /* look whether the object to extract has an index part */ 1206133211Sharti idx.len = 0; 1207133211Sharti iname = NULL; 1208133211Sharti s = strchr(object, '.'); 1209133211Sharti if (s != NULL) { 1210133211Sharti iname = malloc(strlen(s) + 1); 1211133211Sharti if (iname == NULL) 1212133211Sharti err(1, "cannot allocated index"); 1213133211Sharti 1214133211Sharti strcpy(iname, s); 1215133211Sharti for (e = iname; *e != '\0'; e++) 1216133211Sharti if (*e == '.') 1217133211Sharti *e = '_'; 1218133211Sharti 1219133211Sharti *s++ = '\0'; 1220133211Sharti while (s != NULL) { 1221133211Sharti if (*s == '\0') 1222133211Sharti errx(1, "bad index syntax"); 1223133211Sharti if ((e = strchr(s, '.')) != NULL) 1224133211Sharti *e++ = '\0'; 1225133211Sharti 1226133211Sharti errno = 0; 1227133211Sharti ul = strtoul(s, &end, 0); 1228133211Sharti if (*end != '\0') 1229133211Sharti errx(1, "bad index syntax '%s'", end); 1230133211Sharti if (errno != 0) 1231133211Sharti err(1, "bad index syntax"); 1232133211Sharti 1233133211Sharti if (idx.len == ASN_MAXOIDLEN) 1234133211Sharti errx(1, "index oid too large"); 1235133211Sharti idx.subs[idx.len++] = ul; 1236133211Sharti 1237133211Sharti s = e; 1238133211Sharti } 1239133211Sharti } 1240133211Sharti 1241122394Sharti oid.len = PREFIX_LEN; 1242122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 1243159063Sharti ret = extract(fp, root, &oid, object, &idx, iname); 1244133211Sharti if (iname != NULL) 1245133211Sharti free(iname); 1246133211Sharti 1247133211Sharti return (ret); 1248122394Sharti} 1249122394Sharti 1250122394Sharti 1251122394Shartistatic void 1252122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs) 1253122394Sharti{ 1254122394Sharti int first; 1255122394Sharti const struct node *sub; 1256122394Sharti asn_subid_t maxid = 0; 1257122394Sharti 1258122394Sharti /* ensure, that subids are ordered */ 1259122394Sharti first = 1; 1260122394Sharti TAILQ_FOREACH(sub, subs, link) { 1261122394Sharti if (!first && sub->id <= maxid) 1262122394Sharti report_node(np, "subids not ordered at %s", sub->name); 1263122394Sharti maxid = sub->id; 1264122394Sharti first = 0; 1265122394Sharti } 1266122394Sharti} 1267122394Sharti 1268122394Sharti/* 1269122394Sharti * Do some sanity checks on the tree definition and do some computations. 1270122394Sharti */ 1271122394Shartistatic void 1272122394Sharticheck_tree(struct node *np) 1273122394Sharti{ 1274122394Sharti struct node *sub; 1275122394Sharti 1276122394Sharti if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { 1277122394Sharti if ((np->flags & (FL_GET|FL_SET)) != 0) 1278122394Sharti tree_size++; 1279122394Sharti return; 1280122394Sharti } 1281122394Sharti 1282122394Sharti if (np->type == NODE_ENTRY) { 1283122394Sharti check_sub_order(np, &np->u.entry.subs); 1284122394Sharti 1285122394Sharti /* ensure all subnodes are columns */ 1286122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) { 1287122394Sharti if (sub->type != NODE_COLUMN) 1288122394Sharti report_node(np, "entry subnode '%s' is not " 1289122394Sharti "a column", sub->name); 1290122394Sharti check_tree(sub); 1291122394Sharti } 1292122394Sharti } else { 1293122394Sharti check_sub_order(np, &np->u.tree.subs); 1294122394Sharti 1295122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1296122394Sharti check_tree(sub); 1297122394Sharti } 1298122394Sharti} 1299122394Sharti 1300133211Shartistatic void 1301133211Shartimerge_subs(struct node_list *s1, struct node_list *s2) 1302133211Sharti{ 1303133211Sharti struct node *n1, *n2; 1304133211Sharti 1305133211Sharti while (!TAILQ_EMPTY(s2)) { 1306133211Sharti n2 = TAILQ_FIRST(s2); 1307133211Sharti TAILQ_REMOVE(s2, n2, link); 1308133211Sharti 1309133211Sharti TAILQ_FOREACH(n1, s1, link) 1310133211Sharti if (n1->id >= n2->id) 1311133211Sharti break; 1312133211Sharti if (n1 == NULL) 1313133211Sharti TAILQ_INSERT_TAIL(s1, n2, link); 1314133211Sharti else if (n1->id > n2->id) 1315133211Sharti TAILQ_INSERT_BEFORE(n1, n2, link); 1316133211Sharti else { 1317133211Sharti if (n1->type == NODE_TREE && n2->type == NODE_TREE) { 1318133211Sharti if (strcmp(n1->name, n2->name) != 0) 1319133211Sharti errx(1, "trees to merge must have " 1320133211Sharti "same name '%s' '%s'", n1->name, 1321133211Sharti n2->name); 1322133211Sharti merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); 1323133211Sharti free(n2); 1324133211Sharti } else if (n1->type == NODE_ENTRY && 1325133211Sharti n2->type == NODE_ENTRY) { 1326133211Sharti if (strcmp(n1->name, n2->name) != 0) 1327133211Sharti errx(1, "entries to merge must have " 1328133211Sharti "same name '%s' '%s'", n1->name, 1329133211Sharti n2->name); 1330133211Sharti if (n1->u.entry.index != n2->u.entry.index) 1331133211Sharti errx(1, "entries to merge must have " 1332133211Sharti "same index '%s'", n1->name); 1333133211Sharti if (strcmp(n1->u.entry.func, 1334133211Sharti n2->u.entry.func) != 0) 1335133211Sharti errx(1, "entries to merge must have " 1336133211Sharti "same op '%s'", n1->name); 1337133211Sharti merge_subs(&n1->u.entry.subs, 1338133211Sharti &n2->u.entry.subs); 1339133211Sharti free(n2); 1340133211Sharti } else 1341133211Sharti errx(1, "entities to merge must be both " 1342133211Sharti "trees or both entries: %s, %s", 1343133211Sharti n1->name, n2->name); 1344133211Sharti } 1345133211Sharti } 1346133211Sharti} 1347133211Sharti 1348133211Shartistatic void 1349159063Shartimerge(struct node **root, struct node *t) 1350133211Sharti{ 1351133211Sharti 1352159063Sharti if (*root == NULL) { 1353159063Sharti *root = t; 1354159063Sharti return; 1355159063Sharti } 1356159063Sharti if (t == NULL) 1357159063Sharti return; 1358159063Sharti 1359133211Sharti /* both must be trees */ 1360159063Sharti if ((*root)->type != NODE_TREE) 1361133211Sharti errx(1, "root is not a tree"); 1362133211Sharti if (t->type != NODE_TREE) 1363133211Sharti errx(1, "can merge only with tree"); 1364159063Sharti if ((*root)->id != t->id) 1365133211Sharti errx(1, "trees to merge must have same id"); 1366133211Sharti 1367159063Sharti merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs); 1368133211Sharti} 1369133211Sharti 1370159063Shartistatic void 1371159063Shartiunminus(FILE *fp, const char *s) 1372159063Sharti{ 1373159063Sharti 1374159063Sharti while (*s != '\0') { 1375159063Sharti if (*s == '-') 1376159063Sharti fprintf(fp, "_"); 1377159063Sharti else 1378159063Sharti fprintf(fp, "%c", *s); 1379159063Sharti s++; 1380159063Sharti } 1381159063Sharti} 1382159063Sharti 1383159063Shartistatic void 1384159063Shartigen_enum(FILE *fp, const struct type *t) 1385159063Sharti{ 1386159063Sharti const struct enums *e; 1387159063Sharti long min = LONG_MAX; 1388159063Sharti 1389159063Sharti fprintf(fp, "\n"); 1390159063Sharti fprintf(fp, "#ifndef %s_defined__\n", t->name); 1391159063Sharti fprintf(fp, "#define %s_defined__\n", t->name); 1392159063Sharti fprintf(fp, "/*\n"); 1393159063Sharti fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); 1394159063Sharti fprintf(fp, " */\n"); 1395159063Sharti fprintf(fp, "enum %s {\n", t->name); 1396159063Sharti TAILQ_FOREACH(e, &t->enums, link) { 1397159063Sharti fprintf(fp, "\t%s_", t->name); 1398159063Sharti unminus(fp, e->name); 1399159063Sharti fprintf(fp, " = %ld,\n", e->value); 1400159063Sharti if (e->value < min) 1401159063Sharti min = e->value; 1402159063Sharti } 1403159063Sharti fprintf(fp, "};\n"); 1404159063Sharti fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); 1405159063Sharti fprintf(fp, "#define STRING_%s \\\n", t->name); 1406159063Sharti TAILQ_FOREACH(e, &t->enums, link) { 1407159063Sharti fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name); 1408159063Sharti unminus(fp, e->name); 1409159063Sharti fprintf(fp, "\",\\\n"); 1410159063Sharti } 1411159063Sharti fprintf(fp, "\n"); 1412159063Sharti fprintf(fp, "#endif /* %s_defined__ */\n", t->name); 1413159063Sharti} 1414159063Sharti 1415159063Shartistatic void 1416159063Shartigen_enums(FILE *fp) 1417159063Sharti{ 1418159063Sharti const struct type *t; 1419159063Sharti 1420159063Sharti LIST_FOREACH(t, &types, link) 1421159063Sharti if (t->is_enum || t->is_bits) 1422159063Sharti gen_enum(fp, t); 1423159063Sharti} 1424159063Sharti 1425159063Shartistatic int 1426159063Shartiextract_enum(FILE *fp, const char *name) 1427159063Sharti{ 1428159063Sharti const struct type *t; 1429159063Sharti 1430159063Sharti LIST_FOREACH(t, &types, link) 1431159063Sharti if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { 1432159063Sharti gen_enum(fp, t); 1433159063Sharti return (0); 1434159063Sharti } 1435159063Sharti return (-1); 1436159063Sharti} 1437159063Sharti 1438122394Shartiint 1439122394Shartimain(int argc, char *argv[]) 1440122394Sharti{ 1441122394Sharti int do_extract = 0; 1442133211Sharti int do_tree = 0; 1443159063Sharti int do_enums = 0; 1444122394Sharti int opt; 1445122394Sharti struct node *root; 1446122394Sharti char fname[MAXPATHLEN + 1]; 1447133211Sharti int tok; 1448159063Sharti FILE *fp; 1449159063Sharti char *infile = NULL; 1450122394Sharti 1451159063Sharti while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF) 1452122394Sharti switch (opt) { 1453122394Sharti 1454159063Sharti case 'd': 1455159063Sharti debug = 1; 1456159063Sharti break; 1457159063Sharti 1458122394Sharti case 'h': 1459122394Sharti fprintf(stderr, "%s", usgtxt); 1460122394Sharti exit(0); 1461122394Sharti 1462159063Sharti case 'E': 1463159063Sharti do_enums = 1; 1464159063Sharti break; 1465159063Sharti 1466122394Sharti case 'e': 1467122394Sharti do_extract = 1; 1468122394Sharti break; 1469122394Sharti 1470159063Sharti case 'I': 1471159063Sharti path_new(optarg); 1472159063Sharti break; 1473159063Sharti 1474159063Sharti case 'i': 1475159063Sharti infile = optarg; 1476159063Sharti break; 1477159063Sharti 1478122394Sharti case 'l': 1479122394Sharti localincs = 1; 1480122394Sharti break; 1481122394Sharti 1482122394Sharti case 'p': 1483122394Sharti file_prefix = optarg; 1484122394Sharti if (strlen(file_prefix) + strlen("tree.c") > 1485122394Sharti MAXPATHLEN) 1486122394Sharti errx(1, "prefix too long"); 1487122394Sharti break; 1488133211Sharti 1489133211Sharti case 't': 1490133211Sharti do_tree = 1; 1491133211Sharti break; 1492122394Sharti } 1493122394Sharti 1494159063Sharti if (do_extract + do_tree + do_enums > 1) 1495159063Sharti errx(1, "conflicting options -e/-t/-E"); 1496159063Sharti if (!do_extract && !do_enums && argc != optind) 1497122394Sharti errx(1, "no arguments allowed"); 1498159063Sharti if ((do_extract || do_enums) && argc == optind) 1499122394Sharti errx(1, "no objects specified"); 1500122394Sharti 1501159063Sharti if (infile == NULL) { 1502159063Sharti input_new(stdin, NULL, "<stdin>"); 1503159063Sharti } else { 1504159063Sharti if ((fp = fopen(infile, "r")) == NULL) 1505159063Sharti err(1, "%s", infile); 1506159063Sharti input_new(fp, NULL, infile); 1507159063Sharti } 1508159063Sharti 1509159063Sharti root = parse_top(gettoken()); 1510133211Sharti while ((tok = gettoken()) != TOK_EOF) 1511159063Sharti merge(&root, parse_top(tok)); 1512122394Sharti 1513122394Sharti check_tree(root); 1514122394Sharti 1515122394Sharti if (do_extract) { 1516122394Sharti while (optind < argc) { 1517159063Sharti if (gen_extract(stdout, root, argv[optind])) 1518122394Sharti errx(1, "object not found: %s", argv[optind]); 1519122394Sharti optind++; 1520122394Sharti } 1521122394Sharti return (0); 1522122394Sharti } 1523159063Sharti if (do_enums) { 1524159063Sharti while (optind < argc) { 1525159063Sharti if (extract_enum(stdout, argv[optind])) 1526159063Sharti errx(1, "enum not found: %s", argv[optind]); 1527159063Sharti optind++; 1528159063Sharti } 1529159063Sharti return (0); 1530159063Sharti } 1531133211Sharti if (do_tree) { 1532133211Sharti gen_tree(root, 0); 1533133211Sharti return (0); 1534133211Sharti } 1535122394Sharti sprintf(fname, "%stree.h", file_prefix); 1536122394Sharti if ((fp = fopen(fname, "w")) == NULL) 1537122394Sharti err(1, "%s: ", fname); 1538159063Sharti gen_header(fp, root, PREFIX_LEN, NULL); 1539122394Sharti 1540159063Sharti fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); 1541159063Sharti gen_enums(fp); 1542159063Sharti fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); 1543159063Sharti 1544122394Sharti fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); 1545122394Sharti fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); 1546122394Sharti 1547122394Sharti fclose(fp); 1548122394Sharti 1549122394Sharti sprintf(fname, "%stree.c", file_prefix); 1550122394Sharti if ((fp = fopen(fname, "w")) == NULL) 1551122394Sharti err(1, "%s: ", fname); 1552159063Sharti gen_table(fp, root); 1553122394Sharti fclose(fp); 1554122394Sharti 1555122394Sharti return (0); 1556122394Sharti} 1557