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> 11310901Sngie * 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. 20310901Sngie * 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; 741310901Sngie 742159063Sharti if (*tok != TOK_NUM) 743159063Sharti report("need value for ENUM/BITS"); 744159063Sharti if (gettoken() != TOK_STR) 745159063Sharti report("need string in ENUM/BITS"); 746298450Sngie e->name = savetok(); 747298450Sngie TAILQ_INSERT_TAIL(&t->enums, e, link); 748159063Sharti if ((*tok = gettoken()) == TOK_EOF) 749159063Sharti report("unexpected EOF in ENUM/BITS"); 750159063Sharti } while (*tok != ')'); 751159063Sharti *tok = gettoken(); 752159063Sharti 753159063Sharti } else if (*tok == TOK_DEFTYPE) { 754159063Sharti *tok = gettoken(); 755159063Sharti 756159063Sharti } else { 757159063Sharti if ((*tok = gettoken()) == '|') { 758159063Sharti if (gettoken() != TOK_STR) 759159063Sharti report("subtype expected after '|'"); 760159063Sharti *tok = gettoken(); 761159063Sharti } 762159063Sharti } 763159063Sharti 764159063Sharti return (syntax); 765159063Sharti} 766159063Sharti 767159063Sharti/* 768122394Sharti * Parse the next node (complete with all subnodes) 769122394Sharti */ 770122394Shartistatic struct node * 771122394Shartiparse(enum tok tok) 772122394Sharti{ 773122394Sharti struct node *node; 774122394Sharti struct node *sub; 775122394Sharti u_int index_count; 776122394Sharti 777122394Sharti node = xalloc(sizeof(struct node)); 778159063Sharti node->lno = input->lno; 779154182Sharti node->flags = 0; 780122394Sharti 781122394Sharti if (tok != '(') 782122394Sharti report("'(' expected at begin of node"); 783122394Sharti if (gettoken() != TOK_NUM) 784122394Sharti report("node id expected after opening '('"); 785122394Sharti if (val > ASN_MAXID) 786122394Sharti report("subid too large '%lu'", val); 787122394Sharti node->id = (asn_subid_t)val; 788122394Sharti if (gettoken() != TOK_STR) 789122394Sharti report("node name expected after '(' ID"); 790122394Sharti node->name = savetok(); 791122394Sharti 792159063Sharti if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || 793159063Sharti tok == TOK_ENUM || tok == TOK_BITS) { 794122394Sharti /* LEAF or COLUM */ 795159063Sharti u_int syntax = parse_type(&tok, NULL, node->name); 796122394Sharti 797159063Sharti if (tok == TOK_STR) { 798122394Sharti /* LEAF */ 799122394Sharti node->type = NODE_LEAF; 800122394Sharti node->u.leaf.func = savetok(); 801122394Sharti node->u.leaf.syntax = syntax; 802122394Sharti tok = gettoken(); 803122394Sharti } else { 804122394Sharti /* COLUMN */ 805122394Sharti node->type = NODE_COLUMN; 806122394Sharti node->u.column.syntax = syntax; 807122394Sharti } 808122394Sharti 809122394Sharti while (tok != ')') { 810122394Sharti if (tok != TOK_ACCESS) 811122394Sharti report("access keyword or ')' expected"); 812122394Sharti node->flags |= (u_int)val; 813122394Sharti tok = gettoken(); 814122394Sharti } 815122394Sharti 816122394Sharti } else if (tok == ':') { 817122394Sharti /* ENTRY */ 818122394Sharti node->type = NODE_ENTRY; 819122394Sharti TAILQ_INIT(&node->u.entry.subs); 820122394Sharti 821122394Sharti index_count = 0; 822122394Sharti node->u.entry.index = 0; 823159063Sharti tok = gettoken(); 824159063Sharti while (tok == TOK_TYPE || tok == TOK_DEFTYPE || 825159063Sharti tok == TOK_ENUM || tok == TOK_BITS) { 826159063Sharti u_int syntax = parse_type(&tok, NULL, node->name); 827122394Sharti if (index_count++ == SNMP_INDEXES_MAX) 828122394Sharti report("too many table indexes"); 829122394Sharti node->u.entry.index |= 830159063Sharti syntax << (SNMP_INDEX_SHIFT * index_count); 831122394Sharti } 832122394Sharti node->u.entry.index |= index_count; 833122394Sharti if (index_count == 0) 834122394Sharti report("need at least one index"); 835122394Sharti if (tok != TOK_STR) 836122394Sharti report("function name expected"); 837122394Sharti 838122394Sharti node->u.entry.func = savetok(); 839122394Sharti 840122394Sharti tok = gettoken(); 841122394Sharti 842122394Sharti while (tok != ')') { 843122394Sharti sub = parse(tok); 844122394Sharti TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); 845122394Sharti tok = gettoken(); 846122394Sharti } 847122394Sharti 848122394Sharti } else { 849122394Sharti /* subtree */ 850122394Sharti node->type = NODE_TREE; 851122394Sharti TAILQ_INIT(&node->u.tree.subs); 852122394Sharti 853122394Sharti while (tok != ')') { 854122394Sharti sub = parse(tok); 855122394Sharti TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); 856122394Sharti tok = gettoken(); 857122394Sharti } 858122394Sharti } 859122394Sharti return (node); 860122394Sharti} 861122394Sharti 862122394Sharti/* 863159063Sharti * Parse a top level element. Return the tree if it was a tree, NULL 864159063Sharti * otherwise. 865159063Sharti */ 866159063Shartistatic struct node * 867159063Shartiparse_top(enum tok tok) 868159063Sharti{ 869159063Sharti struct type *t; 870159063Sharti 871159063Sharti if (tok == '(') 872159063Sharti return (parse(tok)); 873159063Sharti 874159063Sharti if (tok == TOK_TYPEDEF) { 875159063Sharti if (gettoken() != TOK_STR) 876159063Sharti report("type name expected after typedef"); 877159063Sharti 878159063Sharti t = make_type(str); 879159063Sharti 880159063Sharti tok = gettoken(); 881159063Sharti t->is_enum = (tok == TOK_ENUM); 882159063Sharti t->is_bits = (tok == TOK_BITS); 883159063Sharti t->syntax = parse_type(&tok, t, NULL); 884159063Sharti pushback(tok); 885159063Sharti 886159063Sharti return (NULL); 887159063Sharti } 888159063Sharti 889159063Sharti if (tok == TOK_INCLUDE) { 890159063Sharti if (gettoken() != TOK_FILENAME) 891159063Sharti report("filename expected in include directive"); 892159063Sharti 893159063Sharti input_fopen(str, val); 894159063Sharti return (NULL); 895159063Sharti } 896159063Sharti 897159063Sharti report("'(' or 'typedef' expected"); 898159063Sharti} 899159063Sharti 900159063Sharti/* 901122394Sharti * Generate the C-code table part for one node. 902122394Sharti */ 903122394Shartistatic void 904159063Shartigen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, 905159063Sharti const char *func) 906122394Sharti{ 907122394Sharti u_int n; 908122394Sharti struct node *sub; 909122394Sharti u_int syntax; 910122394Sharti 911122394Sharti if (oid->len == ASN_MAXOIDLEN) 912122394Sharti report_node(np, "OID too long"); 913122394Sharti oid->subs[oid->len++] = np->id; 914122394Sharti 915122394Sharti if (np->type == NODE_TREE) { 916122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 917159063Sharti gen_node(fp, sub, oid, 0, NULL); 918122394Sharti oid->len--; 919122394Sharti return; 920122394Sharti } 921122394Sharti if (np->type == NODE_ENTRY) { 922122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 923159063Sharti gen_node(fp, sub, oid, np->u.entry.index, 924159063Sharti np->u.entry.func); 925122394Sharti oid->len--; 926122394Sharti return; 927122394Sharti } 928122394Sharti 929122394Sharti /* leaf or column */ 930122394Sharti if ((np->flags & (FL_GET|FL_SET)) == 0) { 931122394Sharti oid->len--; 932122394Sharti return; 933122394Sharti } 934122394Sharti 935122394Sharti fprintf(fp, " {{ %u, {", oid->len); 936122394Sharti for (n = 0; n < oid->len; n++) 937122394Sharti fprintf(fp, " %u,", oid->subs[n]); 938122394Sharti fprintf(fp, " }}, \"%s\", ", np->name); 939122394Sharti 940122394Sharti if (np->type == NODE_COLUMN) { 941122394Sharti syntax = np->u.column.syntax; 942122394Sharti fprintf(fp, "SNMP_NODE_COLUMN, "); 943122394Sharti } else { 944122394Sharti syntax = np->u.leaf.syntax; 945122394Sharti fprintf(fp, "SNMP_NODE_LEAF, "); 946122394Sharti } 947122394Sharti 948122394Sharti switch (syntax) { 949122394Sharti 950122394Sharti case SNMP_SYNTAX_NULL: 951122394Sharti fprintf(fp, "SNMP_SYNTAX_NULL, "); 952122394Sharti break; 953122394Sharti 954122394Sharti case SNMP_SYNTAX_INTEGER: 955122394Sharti fprintf(fp, "SNMP_SYNTAX_INTEGER, "); 956122394Sharti break; 957122394Sharti 958122394Sharti case SNMP_SYNTAX_OCTETSTRING: 959122394Sharti fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); 960122394Sharti break; 961122394Sharti 962122394Sharti case SNMP_SYNTAX_IPADDRESS: 963122394Sharti fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); 964122394Sharti break; 965122394Sharti 966122394Sharti case SNMP_SYNTAX_OID: 967122394Sharti fprintf(fp, "SNMP_SYNTAX_OID, "); 968122394Sharti break; 969122394Sharti 970122394Sharti case SNMP_SYNTAX_TIMETICKS: 971122394Sharti fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); 972122394Sharti break; 973122394Sharti 974122394Sharti case SNMP_SYNTAX_COUNTER: 975122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER, "); 976122394Sharti break; 977122394Sharti 978122394Sharti case SNMP_SYNTAX_GAUGE: 979122394Sharti fprintf(fp, "SNMP_SYNTAX_GAUGE, "); 980122394Sharti break; 981122394Sharti 982122394Sharti case SNMP_SYNTAX_COUNTER64: 983122394Sharti fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); 984122394Sharti break; 985122394Sharti 986122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 987122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 988122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 989122394Sharti abort(); 990122394Sharti } 991122394Sharti 992122394Sharti if (np->type == NODE_COLUMN) 993122394Sharti fprintf(fp, "%s, ", func); 994122394Sharti else 995122394Sharti fprintf(fp, "%s, ", np->u.leaf.func); 996122394Sharti 997122394Sharti fprintf(fp, "0"); 998122394Sharti if (np->flags & FL_SET) 999122394Sharti fprintf(fp, "|SNMP_NODE_CANSET"); 1000128237Sharti fprintf(fp, ", %#x, NULL, NULL },\n", idx); 1001122394Sharti oid->len--; 1002122394Sharti return; 1003122394Sharti} 1004122394Sharti 1005122394Sharti/* 1006122394Sharti * Generate the header file with the function declarations. 1007122394Sharti */ 1008122394Shartistatic void 1009159063Shartigen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) 1010122394Sharti{ 1011122394Sharti char f[MAXSTR + 4]; 1012122394Sharti struct node *sub; 1013122394Sharti struct func *ptr; 1014122394Sharti 1015122394Sharti oidlen++; 1016122394Sharti if (np->type == NODE_TREE) { 1017122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1018159063Sharti gen_header(fp, sub, oidlen, NULL); 1019122394Sharti return; 1020122394Sharti } 1021122394Sharti if (np->type == NODE_ENTRY) { 1022122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1023159063Sharti gen_header(fp, sub, oidlen, np->u.entry.func); 1024122394Sharti return; 1025122394Sharti } 1026122394Sharti 1027122394Sharti if((np->flags & (FL_GET|FL_SET)) == 0) 1028122394Sharti return; 1029122394Sharti 1030142810Sharti if (np->type == NODE_COLUMN) { 1031142810Sharti if (func == NULL) 1032142810Sharti errx(1, "column without function (%s) - probably " 1033142810Sharti "outside of a table", np->name); 1034122394Sharti sprintf(f, "%s", func); 1035142810Sharti } else 1036122394Sharti sprintf(f, "%s", np->u.leaf.func); 1037122394Sharti 1038122394Sharti LIST_FOREACH(ptr, &funcs, link) 1039122394Sharti if (strcmp(ptr->name, f) == 0) 1040122394Sharti break; 1041122394Sharti 1042122394Sharti if (ptr == NULL) { 1043122394Sharti ptr = xalloc(sizeof(*ptr)); 1044159063Sharti ptr->name = savestr(f); 1045122394Sharti LIST_INSERT_HEAD(&funcs, ptr, link); 1046122394Sharti 1047122394Sharti fprintf(fp, "int %s(struct snmp_context *, " 1048122394Sharti "struct snmp_value *, u_int, u_int, " 1049122394Sharti "enum snmp_op);\n", f); 1050122394Sharti } 1051122394Sharti 1052122394Sharti fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); 1053122394Sharti} 1054122394Sharti 1055122394Sharti/* 1056122394Sharti * Generate the OID table. 1057122394Sharti */ 1058122394Shartistatic void 1059159063Shartigen_table(FILE *fp, struct node *node) 1060122394Sharti{ 1061122394Sharti struct asn_oid oid; 1062122394Sharti 1063122394Sharti fprintf(fp, "#include <sys/types.h>\n"); 1064122394Sharti fprintf(fp, "#include <stdio.h>\n"); 1065150920Sharti#ifdef HAVE_STDINT_H 1066133211Sharti fprintf(fp, "#include <stdint.h>\n"); 1067150920Sharti#endif 1068122394Sharti if (localincs) { 1069122394Sharti fprintf(fp, "#include \"asn1.h\"\n"); 1070122394Sharti fprintf(fp, "#include \"snmp.h\"\n"); 1071122394Sharti fprintf(fp, "#include \"snmpagent.h\"\n"); 1072122394Sharti } else { 1073122394Sharti fprintf(fp, "#include <bsnmp/asn1.h>\n"); 1074122394Sharti fprintf(fp, "#include <bsnmp/snmp.h>\n"); 1075122394Sharti fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); 1076122394Sharti } 1077122394Sharti fprintf(fp, "#include \"%stree.h\"\n", file_prefix); 1078122394Sharti fprintf(fp, "\n"); 1079122394Sharti 1080122394Sharti fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); 1081122394Sharti 1082122394Sharti oid.len = PREFIX_LEN; 1083122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 1084159063Sharti gen_node(fp, node, &oid, 0, NULL); 1085122394Sharti 1086122394Sharti fprintf(fp, "};\n\n"); 1087122394Sharti} 1088122394Sharti 1089133211Shartistatic void 1090133211Shartiprint_syntax(u_int syntax) 1091133211Sharti{ 1092133211Sharti u_int i; 1093133211Sharti 1094133211Sharti for (i = 0; keywords[i].str != NULL; i++) 1095133211Sharti if (keywords[i].tok == TOK_TYPE && 1096133211Sharti keywords[i].val == syntax) { 1097133211Sharti printf(" %s", keywords[i].str); 1098133211Sharti return; 1099133211Sharti } 1100133211Sharti abort(); 1101133211Sharti} 1102133211Sharti 1103133211Sharti/* 1104133211Sharti * Generate a tree definition file 1105133211Sharti */ 1106133211Shartistatic void 1107133211Shartigen_tree(const struct node *np, int level) 1108133211Sharti{ 1109133211Sharti const struct node *sp; 1110133211Sharti u_int i; 1111133211Sharti 1112133211Sharti printf("%*s(%u %s", 2 * level, "", np->id, np->name); 1113133211Sharti 1114133211Sharti switch (np->type) { 1115133211Sharti 1116133211Sharti case NODE_LEAF: 1117133211Sharti print_syntax(np->u.leaf.syntax); 1118133211Sharti printf(" %s%s%s)\n", np->u.leaf.func, 1119133211Sharti (np->flags & FL_GET) ? " GET" : "", 1120133211Sharti (np->flags & FL_SET) ? " SET" : ""); 1121133211Sharti break; 1122133211Sharti 1123133211Sharti case NODE_TREE: 1124133211Sharti if (TAILQ_EMPTY(&np->u.tree.subs)) { 1125133211Sharti printf(")\n"); 1126133211Sharti } else { 1127133211Sharti printf("\n"); 1128133211Sharti TAILQ_FOREACH(sp, &np->u.tree.subs, link) 1129133211Sharti gen_tree(sp, level + 1); 1130133211Sharti printf("%*s)\n", 2 * level, ""); 1131133211Sharti } 1132133211Sharti break; 1133133211Sharti 1134133211Sharti case NODE_ENTRY: 1135133211Sharti printf(" :"); 1136133211Sharti 1137133211Sharti for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) 1138133211Sharti print_syntax(SNMP_INDEX(np->u.entry.index, i)); 1139133211Sharti printf(" %s\n", np->u.entry.func); 1140133211Sharti TAILQ_FOREACH(sp, &np->u.entry.subs, link) 1141133211Sharti gen_tree(sp, level + 1); 1142133211Sharti printf("%*s)\n", 2 * level, ""); 1143133211Sharti break; 1144133211Sharti 1145133211Sharti case NODE_COLUMN: 1146133211Sharti print_syntax(np->u.column.syntax); 1147133211Sharti printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", 1148133211Sharti (np->flags & FL_SET) ? " SET" : ""); 1149133211Sharti break; 1150133211Sharti } 1151133211Sharti} 1152133211Sharti 1153122394Shartistatic int 1154159063Shartiextract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj, 1155133211Sharti const struct asn_oid *idx, const char *iname) 1156122394Sharti{ 1157122394Sharti struct node *sub; 1158122394Sharti u_long n; 1159122394Sharti 1160122394Sharti if (oid->len == ASN_MAXOIDLEN) 1161122394Sharti report_node(np, "OID too long"); 1162122394Sharti oid->subs[oid->len++] = np->id; 1163122394Sharti 1164122394Sharti if (strcmp(obj, np->name) == 0) { 1165133211Sharti if (oid->len + idx->len >= ASN_MAXOIDLEN) 1166133211Sharti report_node(np, "OID too long"); 1167133211Sharti fprintf(fp, "#define OID_%s%s\t%u\n", np->name, 1168133211Sharti iname ? iname : "", np->id); 1169133211Sharti fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, 1170133211Sharti iname ? iname : "", oid->len + idx->len); 1171133211Sharti fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, 1172133211Sharti iname ? iname : "", oid->len + idx->len); 1173122394Sharti for (n = 0; n < oid->len; n++) 1174122394Sharti fprintf(fp, " %u,", oid->subs[n]); 1175133211Sharti for (n = 0; n < idx->len; n++) 1176133211Sharti fprintf(fp, " %u,", idx->subs[n]); 1177122394Sharti fprintf(fp, " } }\n"); 1178122394Sharti return (0); 1179122394Sharti } 1180122394Sharti 1181122394Sharti if (np->type == NODE_TREE) { 1182122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1183159063Sharti if (!extract(fp, sub, oid, obj, idx, iname)) 1184122394Sharti return (0); 1185122394Sharti } else if (np->type == NODE_ENTRY) { 1186122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) 1187159063Sharti if (!extract(fp, sub, oid, obj, idx, iname)) 1188122394Sharti return (0); 1189122394Sharti } 1190122394Sharti oid->len--; 1191122394Sharti return (1); 1192122394Sharti} 1193122394Sharti 1194122394Shartistatic int 1195159063Shartigen_extract(FILE *fp, const struct node *root, char *object) 1196122394Sharti{ 1197122394Sharti struct asn_oid oid; 1198133211Sharti struct asn_oid idx; 1199133211Sharti char *s, *e, *end, *iname; 1200133211Sharti u_long ul; 1201133211Sharti int ret; 1202122394Sharti 1203133211Sharti /* look whether the object to extract has an index part */ 1204133211Sharti idx.len = 0; 1205133211Sharti iname = NULL; 1206133211Sharti s = strchr(object, '.'); 1207133211Sharti if (s != NULL) { 1208133211Sharti iname = malloc(strlen(s) + 1); 1209133211Sharti if (iname == NULL) 1210133211Sharti err(1, "cannot allocated index"); 1211133211Sharti 1212133211Sharti strcpy(iname, s); 1213133211Sharti for (e = iname; *e != '\0'; e++) 1214133211Sharti if (*e == '.') 1215133211Sharti *e = '_'; 1216133211Sharti 1217133211Sharti *s++ = '\0'; 1218133211Sharti while (s != NULL) { 1219133211Sharti if (*s == '\0') 1220133211Sharti errx(1, "bad index syntax"); 1221133211Sharti if ((e = strchr(s, '.')) != NULL) 1222133211Sharti *e++ = '\0'; 1223133211Sharti 1224133211Sharti errno = 0; 1225133211Sharti ul = strtoul(s, &end, 0); 1226133211Sharti if (*end != '\0') 1227133211Sharti errx(1, "bad index syntax '%s'", end); 1228133211Sharti if (errno != 0) 1229133211Sharti err(1, "bad index syntax"); 1230133211Sharti 1231133211Sharti if (idx.len == ASN_MAXOIDLEN) 1232133211Sharti errx(1, "index oid too large"); 1233133211Sharti idx.subs[idx.len++] = ul; 1234133211Sharti 1235133211Sharti s = e; 1236133211Sharti } 1237133211Sharti } 1238133211Sharti 1239122394Sharti oid.len = PREFIX_LEN; 1240122394Sharti memcpy(oid.subs, prefix, sizeof(prefix)); 1241159063Sharti ret = extract(fp, root, &oid, object, &idx, iname); 1242133211Sharti if (iname != NULL) 1243133211Sharti free(iname); 1244133211Sharti 1245133211Sharti return (ret); 1246122394Sharti} 1247122394Sharti 1248122394Sharti 1249122394Shartistatic void 1250122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs) 1251122394Sharti{ 1252122394Sharti int first; 1253122394Sharti const struct node *sub; 1254122394Sharti asn_subid_t maxid = 0; 1255122394Sharti 1256122394Sharti /* ensure, that subids are ordered */ 1257122394Sharti first = 1; 1258122394Sharti TAILQ_FOREACH(sub, subs, link) { 1259122394Sharti if (!first && sub->id <= maxid) 1260122394Sharti report_node(np, "subids not ordered at %s", sub->name); 1261122394Sharti maxid = sub->id; 1262122394Sharti first = 0; 1263122394Sharti } 1264122394Sharti} 1265122394Sharti 1266122394Sharti/* 1267122394Sharti * Do some sanity checks on the tree definition and do some computations. 1268122394Sharti */ 1269122394Shartistatic void 1270122394Sharticheck_tree(struct node *np) 1271122394Sharti{ 1272122394Sharti struct node *sub; 1273122394Sharti 1274122394Sharti if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { 1275122394Sharti if ((np->flags & (FL_GET|FL_SET)) != 0) 1276122394Sharti tree_size++; 1277122394Sharti return; 1278122394Sharti } 1279122394Sharti 1280122394Sharti if (np->type == NODE_ENTRY) { 1281122394Sharti check_sub_order(np, &np->u.entry.subs); 1282122394Sharti 1283122394Sharti /* ensure all subnodes are columns */ 1284122394Sharti TAILQ_FOREACH(sub, &np->u.entry.subs, link) { 1285122394Sharti if (sub->type != NODE_COLUMN) 1286122394Sharti report_node(np, "entry subnode '%s' is not " 1287122394Sharti "a column", sub->name); 1288122394Sharti check_tree(sub); 1289122394Sharti } 1290122394Sharti } else { 1291122394Sharti check_sub_order(np, &np->u.tree.subs); 1292122394Sharti 1293122394Sharti TAILQ_FOREACH(sub, &np->u.tree.subs, link) 1294122394Sharti check_tree(sub); 1295122394Sharti } 1296122394Sharti} 1297122394Sharti 1298133211Shartistatic void 1299133211Shartimerge_subs(struct node_list *s1, struct node_list *s2) 1300133211Sharti{ 1301133211Sharti struct node *n1, *n2; 1302133211Sharti 1303133211Sharti while (!TAILQ_EMPTY(s2)) { 1304133211Sharti n2 = TAILQ_FIRST(s2); 1305133211Sharti TAILQ_REMOVE(s2, n2, link); 1306133211Sharti 1307133211Sharti TAILQ_FOREACH(n1, s1, link) 1308133211Sharti if (n1->id >= n2->id) 1309133211Sharti break; 1310133211Sharti if (n1 == NULL) 1311133211Sharti TAILQ_INSERT_TAIL(s1, n2, link); 1312133211Sharti else if (n1->id > n2->id) 1313133211Sharti TAILQ_INSERT_BEFORE(n1, n2, link); 1314133211Sharti else { 1315133211Sharti if (n1->type == NODE_TREE && n2->type == NODE_TREE) { 1316133211Sharti if (strcmp(n1->name, n2->name) != 0) 1317133211Sharti errx(1, "trees to merge must have " 1318133211Sharti "same name '%s' '%s'", n1->name, 1319133211Sharti n2->name); 1320133211Sharti merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); 1321133211Sharti free(n2); 1322133211Sharti } else if (n1->type == NODE_ENTRY && 1323133211Sharti n2->type == NODE_ENTRY) { 1324133211Sharti if (strcmp(n1->name, n2->name) != 0) 1325133211Sharti errx(1, "entries to merge must have " 1326133211Sharti "same name '%s' '%s'", n1->name, 1327133211Sharti n2->name); 1328133211Sharti if (n1->u.entry.index != n2->u.entry.index) 1329133211Sharti errx(1, "entries to merge must have " 1330133211Sharti "same index '%s'", n1->name); 1331133211Sharti if (strcmp(n1->u.entry.func, 1332133211Sharti n2->u.entry.func) != 0) 1333133211Sharti errx(1, "entries to merge must have " 1334133211Sharti "same op '%s'", n1->name); 1335133211Sharti merge_subs(&n1->u.entry.subs, 1336133211Sharti &n2->u.entry.subs); 1337133211Sharti free(n2); 1338133211Sharti } else 1339133211Sharti errx(1, "entities to merge must be both " 1340133211Sharti "trees or both entries: %s, %s", 1341133211Sharti n1->name, n2->name); 1342133211Sharti } 1343133211Sharti } 1344133211Sharti} 1345133211Sharti 1346133211Shartistatic void 1347159063Shartimerge(struct node **root, struct node *t) 1348133211Sharti{ 1349133211Sharti 1350159063Sharti if (*root == NULL) { 1351159063Sharti *root = t; 1352159063Sharti return; 1353159063Sharti } 1354159063Sharti if (t == NULL) 1355159063Sharti return; 1356159063Sharti 1357133211Sharti /* both must be trees */ 1358159063Sharti if ((*root)->type != NODE_TREE) 1359133211Sharti errx(1, "root is not a tree"); 1360133211Sharti if (t->type != NODE_TREE) 1361133211Sharti errx(1, "can merge only with tree"); 1362159063Sharti if ((*root)->id != t->id) 1363133211Sharti errx(1, "trees to merge must have same id"); 1364133211Sharti 1365159063Sharti merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs); 1366133211Sharti} 1367133211Sharti 1368159063Shartistatic void 1369159063Shartiunminus(FILE *fp, const char *s) 1370159063Sharti{ 1371159063Sharti 1372159063Sharti while (*s != '\0') { 1373159063Sharti if (*s == '-') 1374159063Sharti fprintf(fp, "_"); 1375159063Sharti else 1376159063Sharti fprintf(fp, "%c", *s); 1377159063Sharti s++; 1378159063Sharti } 1379159063Sharti} 1380159063Sharti 1381159063Shartistatic void 1382159063Shartigen_enum(FILE *fp, const struct type *t) 1383159063Sharti{ 1384159063Sharti const struct enums *e; 1385159063Sharti long min = LONG_MAX; 1386159063Sharti 1387159063Sharti fprintf(fp, "\n"); 1388159063Sharti fprintf(fp, "#ifndef %s_defined__\n", t->name); 1389159063Sharti fprintf(fp, "#define %s_defined__\n", t->name); 1390159063Sharti fprintf(fp, "/*\n"); 1391159063Sharti fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); 1392159063Sharti fprintf(fp, " */\n"); 1393159063Sharti fprintf(fp, "enum %s {\n", t->name); 1394159063Sharti TAILQ_FOREACH(e, &t->enums, link) { 1395159063Sharti fprintf(fp, "\t%s_", t->name); 1396159063Sharti unminus(fp, e->name); 1397159063Sharti fprintf(fp, " = %ld,\n", e->value); 1398159063Sharti if (e->value < min) 1399159063Sharti min = e->value; 1400159063Sharti } 1401159063Sharti fprintf(fp, "};\n"); 1402159063Sharti fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); 1403159063Sharti fprintf(fp, "#define STRING_%s \\\n", t->name); 1404159063Sharti TAILQ_FOREACH(e, &t->enums, link) { 1405159063Sharti fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name); 1406159063Sharti unminus(fp, e->name); 1407159063Sharti fprintf(fp, "\",\\\n"); 1408159063Sharti } 1409159063Sharti fprintf(fp, "\n"); 1410159063Sharti fprintf(fp, "#endif /* %s_defined__ */\n", t->name); 1411159063Sharti} 1412159063Sharti 1413159063Shartistatic void 1414159063Shartigen_enums(FILE *fp) 1415159063Sharti{ 1416159063Sharti const struct type *t; 1417159063Sharti 1418159063Sharti LIST_FOREACH(t, &types, link) 1419159063Sharti if (t->is_enum || t->is_bits) 1420159063Sharti gen_enum(fp, t); 1421159063Sharti} 1422159063Sharti 1423159063Shartistatic int 1424159063Shartiextract_enum(FILE *fp, const char *name) 1425159063Sharti{ 1426159063Sharti const struct type *t; 1427159063Sharti 1428159063Sharti LIST_FOREACH(t, &types, link) 1429159063Sharti if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { 1430159063Sharti gen_enum(fp, t); 1431159063Sharti return (0); 1432159063Sharti } 1433159063Sharti return (-1); 1434159063Sharti} 1435159063Sharti 1436122394Shartiint 1437122394Shartimain(int argc, char *argv[]) 1438122394Sharti{ 1439122394Sharti int do_extract = 0; 1440133211Sharti int do_tree = 0; 1441159063Sharti int do_enums = 0; 1442122394Sharti int opt; 1443122394Sharti struct node *root; 1444122394Sharti char fname[MAXPATHLEN + 1]; 1445133211Sharti int tok; 1446159063Sharti FILE *fp; 1447159063Sharti char *infile = NULL; 1448122394Sharti 1449159063Sharti while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF) 1450122394Sharti switch (opt) { 1451122394Sharti 1452159063Sharti case 'd': 1453159063Sharti debug = 1; 1454159063Sharti break; 1455159063Sharti 1456122394Sharti case 'h': 1457122394Sharti fprintf(stderr, "%s", usgtxt); 1458122394Sharti exit(0); 1459122394Sharti 1460159063Sharti case 'E': 1461159063Sharti do_enums = 1; 1462159063Sharti break; 1463159063Sharti 1464122394Sharti case 'e': 1465122394Sharti do_extract = 1; 1466122394Sharti break; 1467122394Sharti 1468159063Sharti case 'I': 1469159063Sharti path_new(optarg); 1470159063Sharti break; 1471159063Sharti 1472159063Sharti case 'i': 1473159063Sharti infile = optarg; 1474159063Sharti break; 1475159063Sharti 1476122394Sharti case 'l': 1477122394Sharti localincs = 1; 1478122394Sharti break; 1479122394Sharti 1480122394Sharti case 'p': 1481122394Sharti file_prefix = optarg; 1482122394Sharti if (strlen(file_prefix) + strlen("tree.c") > 1483122394Sharti MAXPATHLEN) 1484122394Sharti errx(1, "prefix too long"); 1485122394Sharti break; 1486133211Sharti 1487133211Sharti case 't': 1488133211Sharti do_tree = 1; 1489133211Sharti break; 1490122394Sharti } 1491122394Sharti 1492159063Sharti if (do_extract + do_tree + do_enums > 1) 1493159063Sharti errx(1, "conflicting options -e/-t/-E"); 1494159063Sharti if (!do_extract && !do_enums && argc != optind) 1495122394Sharti errx(1, "no arguments allowed"); 1496159063Sharti if ((do_extract || do_enums) && argc == optind) 1497122394Sharti errx(1, "no objects specified"); 1498122394Sharti 1499159063Sharti if (infile == NULL) { 1500159063Sharti input_new(stdin, NULL, "<stdin>"); 1501159063Sharti } else { 1502159063Sharti if ((fp = fopen(infile, "r")) == NULL) 1503159063Sharti err(1, "%s", infile); 1504159063Sharti input_new(fp, NULL, infile); 1505159063Sharti } 1506159063Sharti 1507159063Sharti root = parse_top(gettoken()); 1508133211Sharti while ((tok = gettoken()) != TOK_EOF) 1509159063Sharti merge(&root, parse_top(tok)); 1510122394Sharti 1511122394Sharti check_tree(root); 1512122394Sharti 1513122394Sharti if (do_extract) { 1514122394Sharti while (optind < argc) { 1515159063Sharti if (gen_extract(stdout, root, argv[optind])) 1516122394Sharti errx(1, "object not found: %s", argv[optind]); 1517122394Sharti optind++; 1518122394Sharti } 1519122394Sharti return (0); 1520122394Sharti } 1521159063Sharti if (do_enums) { 1522159063Sharti while (optind < argc) { 1523159063Sharti if (extract_enum(stdout, argv[optind])) 1524159063Sharti errx(1, "enum not found: %s", argv[optind]); 1525159063Sharti optind++; 1526159063Sharti } 1527159063Sharti return (0); 1528159063Sharti } 1529133211Sharti if (do_tree) { 1530133211Sharti gen_tree(root, 0); 1531133211Sharti return (0); 1532133211Sharti } 1533122394Sharti sprintf(fname, "%stree.h", file_prefix); 1534122394Sharti if ((fp = fopen(fname, "w")) == NULL) 1535122394Sharti err(1, "%s: ", fname); 1536159063Sharti gen_header(fp, root, PREFIX_LEN, NULL); 1537122394Sharti 1538159063Sharti fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); 1539159063Sharti gen_enums(fp); 1540159063Sharti fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); 1541159063Sharti 1542122394Sharti fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); 1543122394Sharti fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); 1544122394Sharti 1545122394Sharti fclose(fp); 1546122394Sharti 1547122394Sharti sprintf(fname, "%stree.c", file_prefix); 1548122394Sharti if ((fp = fopen(fname, "w")) == NULL) 1549122394Sharti err(1, "%s: ", fname); 1550159063Sharti gen_table(fp, root); 1551122394Sharti fclose(fp); 1552122394Sharti 1553122394Sharti return (0); 1554122394Sharti} 1555