/contrib/bsnmp/gensnmptree/gensnmptree.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1556 lines · 1379 code · 61 blank · 116 comment · 58 complexity · cae68a9a5ad50ce71c9b3b669f8641ee MD5 · raw file

  1. /*
  2. * Copyright (c) 2001-2003
  3. * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4. * All rights reserved.
  5. *
  6. * Copyright (c) 2004-2006
  7. * Hartmut Brandt.
  8. * All rights reserved.
  9. *
  10. * Author: Harti Brandt <harti@freebsd.org>
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * 1. Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
  34. *
  35. * Generate OID table from table description.
  36. *
  37. * Syntax is:
  38. * ---------
  39. * file := top | top file
  40. *
  41. * top := tree | typedef | include
  42. *
  43. * tree := head elements ')'
  44. *
  45. * entry := head ':' index STRING elements ')'
  46. *
  47. * leaf := head type STRING ACCESS ')'
  48. *
  49. * column := head type ACCESS ')'
  50. *
  51. * type := BASETYPE | BASETYPE '|' subtype | enum | bits
  52. *
  53. * subtype := STRING
  54. *
  55. * enum := ENUM '(' value ')'
  56. *
  57. * bits := BITS '(' value ')'
  58. *
  59. * value := optminus INT STRING | optminus INT STRING value
  60. *
  61. * optminus := '-' | EMPTY
  62. *
  63. * head := '(' INT STRING
  64. *
  65. * elements := EMPTY | elements element
  66. *
  67. * element := tree | leaf | column
  68. *
  69. * index := type | index type
  70. *
  71. * typedef := 'typedef' STRING type
  72. *
  73. * include := 'include' filespec
  74. *
  75. * filespec := '"' STRING '"' | '<' STRING '>'
  76. */
  77. #include <sys/types.h>
  78. #include <sys/param.h>
  79. #include <stdio.h>
  80. #include <stdlib.h>
  81. #include <stdarg.h>
  82. #include <unistd.h>
  83. #include <string.h>
  84. #include <ctype.h>
  85. #include <inttypes.h>
  86. #include <errno.h>
  87. #ifdef HAVE_ERR_H
  88. #include <err.h>
  89. #endif
  90. #include <sys/queue.h>
  91. #include "support.h"
  92. #include "asn1.h"
  93. #include "snmp.h"
  94. #include "snmpagent.h"
  95. /*
  96. * Constant prefix for all OIDs
  97. */
  98. static const asn_subid_t prefix[] = { 1, 3, 6 };
  99. #define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0]))
  100. u_int tree_size;
  101. static const char *file_prefix = "";
  102. /* if true generate local include paths */
  103. static int localincs = 0;
  104. /* if true print tokens */
  105. static int debug;
  106. static const char usgtxt[] = "\
  107. Generate SNMP tables.\n\
  108. usage: gensnmptree [-dEehlt] [-I directory] [-i infile] [-p prefix]\n\
  109. [name]...\n\
  110. options:\n\
  111. -d debug mode\n\
  112. -E extract the named enums and bits only\n\
  113. -e extract the named oids or enums\n\
  114. -h print this info\n\
  115. -I directory add directory to include path\n\
  116. -i ifile read from the named file instead of stdin\n\
  117. -l generate local include directives\n\
  118. -p prefix prepend prefix to file and variable names\n\
  119. -t generated a .def file\n\
  120. ";
  121. /*
  122. * A node in the OID tree
  123. */
  124. enum ntype {
  125. NODE_LEAF = 1,
  126. NODE_TREE,
  127. NODE_ENTRY,
  128. NODE_COLUMN
  129. };
  130. enum {
  131. FL_GET = 0x01,
  132. FL_SET = 0x02,
  133. };
  134. struct node;
  135. TAILQ_HEAD(node_list, node);
  136. struct node {
  137. enum ntype type;
  138. asn_subid_t id; /* last element of OID */
  139. char *name; /* name of node */
  140. TAILQ_ENTRY(node) link;
  141. u_int lno; /* starting line number */
  142. u_int flags; /* allowed operations */
  143. union {
  144. struct tree {
  145. struct node_list subs;
  146. } tree;
  147. struct entry {
  148. uint32_t index; /* index for table entry */
  149. char *func; /* function for tables */
  150. struct node_list subs;
  151. } entry;
  152. struct leaf {
  153. enum snmp_syntax syntax; /* syntax for this leaf */
  154. char *func; /* function name */
  155. } leaf;
  156. struct column {
  157. enum snmp_syntax syntax; /* syntax for this column */
  158. } column;
  159. } u;
  160. };
  161. struct func {
  162. const char *name;
  163. LIST_ENTRY(func) link;
  164. };
  165. static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
  166. struct enums {
  167. const char *name;
  168. long value;
  169. TAILQ_ENTRY(enums) link;
  170. };
  171. struct type {
  172. const char *name;
  173. const char *from_fname;
  174. u_int from_lno;
  175. u_int syntax;
  176. int is_enum;
  177. int is_bits;
  178. TAILQ_HEAD(, enums) enums;
  179. LIST_ENTRY(type) link;
  180. };
  181. static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
  182. static void report(const char *, ...) __dead2 __printflike(1, 2);
  183. static void report_node(const struct node *, const char *, ...)
  184. __dead2 __printflike(2, 3);
  185. /************************************************************
  186. *
  187. * Allocate memory and panic just in the case...
  188. */
  189. static void *
  190. xalloc(size_t size)
  191. {
  192. void *ptr;
  193. if ((ptr = malloc(size)) == NULL)
  194. err(1, "allocing %zu bytes", size);
  195. return (ptr);
  196. }
  197. static char *
  198. savestr(const char *s)
  199. {
  200. if (s == NULL)
  201. return (NULL);
  202. return (strcpy(xalloc(strlen(s) + 1), s));
  203. }
  204. /************************************************************
  205. *
  206. * Input stack
  207. */
  208. struct input {
  209. FILE *fp;
  210. u_int lno;
  211. char *fname;
  212. char *path;
  213. LIST_ENTRY(input) link;
  214. };
  215. static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
  216. static struct input *input = NULL;
  217. #define MAX_PATHS 100
  218. static u_int npaths = 2;
  219. static u_int stdpaths = 2;
  220. static const char *paths[MAX_PATHS + 1] = {
  221. "/usr/share/snmp/defs",
  222. "/usr/local/share/snmp/defs",
  223. NULL
  224. };
  225. static int pbchar = -1;
  226. static void
  227. path_new(const char *path)
  228. {
  229. if (npaths >= MAX_PATHS)
  230. report("too many -I directives");
  231. memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths],
  232. sizeof(path[0]) * stdpaths);
  233. paths[npaths - stdpaths] = savestr(path);
  234. npaths++;
  235. }
  236. static void
  237. input_new(FILE *fp, const char *path, const char *fname)
  238. {
  239. struct input *ip;
  240. ip = xalloc(sizeof(*ip));
  241. ip->fp = fp;
  242. ip->lno = 1;
  243. ip->fname = savestr(fname);
  244. ip->path = savestr(path);
  245. LIST_INSERT_HEAD(&inputs, ip, link);
  246. input = ip;
  247. }
  248. static void
  249. input_close(void)
  250. {
  251. if (input == NULL)
  252. return;
  253. fclose(input->fp);
  254. free(input->fname);
  255. free(input->path);
  256. LIST_REMOVE(input, link);
  257. free(input);
  258. input = LIST_FIRST(&inputs);
  259. }
  260. static FILE *
  261. tryopen(const char *path, const char *fname)
  262. {
  263. char *fn;
  264. FILE *fp;
  265. if (path == NULL)
  266. fn = savestr(fname);
  267. else {
  268. fn = xalloc(strlen(path) + strlen(fname) + 2);
  269. sprintf(fn, "%s/%s", path, fname);
  270. }
  271. fp = fopen(fn, "r");
  272. free(fn);
  273. return (fp);
  274. }
  275. static void
  276. input_fopen(const char *fname, int loc)
  277. {
  278. FILE *fp;
  279. char *path;
  280. u_int p;
  281. if (fname[0] == '/') {
  282. if ((fp = tryopen(NULL, fname)) != NULL) {
  283. input_new(fp, NULL, fname);
  284. return;
  285. }
  286. } else {
  287. if (loc) {
  288. if (input == NULL)
  289. path = NULL;
  290. else
  291. path = input->path;
  292. if ((fp = tryopen(path, fname)) != NULL) {
  293. input_new(fp, NULL, fname);
  294. return;
  295. }
  296. }
  297. for (p = 0; paths[p] != NULL; p++)
  298. if ((fp = tryopen(paths[p], fname)) != NULL) {
  299. input_new(fp, paths[p], fname);
  300. return;
  301. }
  302. }
  303. report("cannot open '%s'", fname);
  304. }
  305. static int
  306. tgetc(void)
  307. {
  308. int c;
  309. if (pbchar != -1) {
  310. c = pbchar;
  311. pbchar = -1;
  312. return (c);
  313. }
  314. for (;;) {
  315. if (input == NULL)
  316. return (EOF);
  317. if ((c = getc(input->fp)) != EOF)
  318. return (c);
  319. input_close();
  320. }
  321. }
  322. static void
  323. tungetc(int c)
  324. {
  325. if (pbchar != -1)
  326. abort();
  327. pbchar = c;
  328. }
  329. /************************************************************
  330. *
  331. * Parsing input
  332. */
  333. enum tok {
  334. TOK_EOF = 0200, /* end-of-file seen */
  335. TOK_NUM, /* number */
  336. TOK_STR, /* string */
  337. TOK_ACCESS, /* access operator */
  338. TOK_TYPE, /* type operator */
  339. TOK_ENUM, /* enum token (kind of a type) */
  340. TOK_TYPEDEF, /* typedef directive */
  341. TOK_DEFTYPE, /* defined type */
  342. TOK_INCLUDE, /* include directive */
  343. TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */
  344. TOK_BITS, /* bits token (kind of a type) */
  345. };
  346. static const struct {
  347. const char *str;
  348. enum tok tok;
  349. u_int val;
  350. } keywords[] = {
  351. { "GET", TOK_ACCESS, FL_GET },
  352. { "SET", TOK_ACCESS, FL_SET },
  353. { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
  354. { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
  355. { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
  356. { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
  357. { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
  358. { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
  359. { "OID", TOK_TYPE, SNMP_SYNTAX_OID },
  360. { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
  361. { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
  362. { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
  363. { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
  364. { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
  365. { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
  366. { "typedef", TOK_TYPEDEF, 0 },
  367. { "include", TOK_INCLUDE, 0 },
  368. { NULL, 0, 0 }
  369. };
  370. /* arbitrary upper limit on node names and function names */
  371. #define MAXSTR 1000
  372. char str[MAXSTR];
  373. u_long val; /* integer values */
  374. int all_cond; /* all conditions are true */
  375. int saved_token = -1;
  376. /*
  377. * Report an error and exit.
  378. */
  379. static void
  380. report(const char *fmt, ...)
  381. {
  382. va_list ap;
  383. int c;
  384. va_start(ap, fmt);
  385. fprintf(stderr, "line %u: ", input->lno);
  386. vfprintf(stderr, fmt, ap);
  387. fprintf(stderr, "\n");
  388. fprintf(stderr, "context: \"");
  389. while ((c = tgetc()) != EOF && c != '\n')
  390. fprintf(stderr, "%c", c);
  391. fprintf(stderr, "\n");
  392. va_end(ap);
  393. exit(1);
  394. }
  395. static void
  396. report_node(const struct node *np, const char *fmt, ...)
  397. {
  398. va_list ap;
  399. va_start(ap, fmt);
  400. fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
  401. vfprintf(stderr, fmt, ap);
  402. fprintf(stderr, "\n");
  403. va_end(ap);
  404. exit(1);
  405. }
  406. /*
  407. * Return a fresh copy of the string constituting the current token.
  408. */
  409. static char *
  410. savetok(void)
  411. {
  412. return (savestr(str));
  413. }
  414. /*
  415. * Get the next token from input.
  416. */
  417. static int
  418. gettoken_internal(void)
  419. {
  420. int c;
  421. struct type *t;
  422. if (saved_token != -1) {
  423. c = saved_token;
  424. saved_token = -1;
  425. return (c);
  426. }
  427. again:
  428. /*
  429. * Skip any whitespace before the next token
  430. */
  431. while ((c = tgetc()) != EOF) {
  432. if (c == '\n')
  433. input->lno++;
  434. if (!isspace(c))
  435. break;
  436. }
  437. if (c == EOF)
  438. return (TOK_EOF);
  439. if (!isascii(c))
  440. report("unexpected character %#2x", (u_int)c);
  441. /*
  442. * Skip comments
  443. */
  444. if (c == '#') {
  445. while ((c = tgetc()) != EOF) {
  446. if (c == '\n') {
  447. input->lno++;
  448. goto again;
  449. }
  450. }
  451. report("unexpected EOF in comment");
  452. }
  453. /*
  454. * Single character tokens
  455. */
  456. if (strchr("():|-", c) != NULL)
  457. return (c);
  458. if (c == '"' || c == '<') {
  459. int end = c;
  460. size_t n = 0;
  461. val = 1;
  462. if (c == '<') {
  463. val = 0;
  464. end = '>';
  465. }
  466. while ((c = tgetc()) != EOF) {
  467. if (c == end)
  468. break;
  469. if (n == sizeof(str) - 1) {
  470. str[n++] = '\0';
  471. report("filename too long '%s...'", str);
  472. }
  473. str[n++] = c;
  474. }
  475. str[n++] = '\0';
  476. return (TOK_FILENAME);
  477. }
  478. /*
  479. * Sort out numbers
  480. */
  481. if (isdigit(c)) {
  482. size_t n = 0;
  483. str[n++] = c;
  484. while ((c = tgetc()) != EOF) {
  485. if (!isdigit(c)) {
  486. tungetc(c);
  487. break;
  488. }
  489. if (n == sizeof(str) - 1) {
  490. str[n++] = '\0';
  491. report("number too long '%s...'", str);
  492. }
  493. str[n++] = c;
  494. }
  495. str[n++] = '\0';
  496. sscanf(str, "%lu", &val);
  497. return (TOK_NUM);
  498. }
  499. /*
  500. * So that has to be a string.
  501. */
  502. if (isalpha(c) || c == '_') {
  503. size_t n = 0;
  504. str[n++] = c;
  505. while ((c = tgetc()) != EOF) {
  506. if (!isalnum(c) && c != '_' && c != '-') {
  507. tungetc(c);
  508. break;
  509. }
  510. if (n == sizeof(str) - 1) {
  511. str[n++] = '\0';
  512. report("string too long '%s...'", str);
  513. }
  514. str[n++] = c;
  515. }
  516. str[n++] = '\0';
  517. /*
  518. * Keywords
  519. */
  520. for (c = 0; keywords[c].str != NULL; c++)
  521. if (strcmp(keywords[c].str, str) == 0) {
  522. val = keywords[c].val;
  523. return (keywords[c].tok);
  524. }
  525. LIST_FOREACH(t, &types, link) {
  526. if (strcmp(t->name, str) == 0) {
  527. val = t->syntax;
  528. return (TOK_DEFTYPE);
  529. }
  530. }
  531. return (TOK_STR);
  532. }
  533. if (isprint(c))
  534. errx(1, "%u: unexpected character '%c'", input->lno, c);
  535. else
  536. errx(1, "%u: unexpected character 0x%02x", input->lno,
  537. (u_int)c);
  538. }
  539. static int
  540. gettoken(void)
  541. {
  542. int tok = gettoken_internal();
  543. if (debug) {
  544. switch (tok) {
  545. case TOK_EOF:
  546. fprintf(stderr, "EOF ");
  547. break;
  548. case TOK_NUM:
  549. fprintf(stderr, "NUM(%lu) ", val);
  550. break;
  551. case TOK_STR:
  552. fprintf(stderr, "STR(%s) ", str);
  553. break;
  554. case TOK_ACCESS:
  555. fprintf(stderr, "ACCESS(%lu) ", val);
  556. break;
  557. case TOK_TYPE:
  558. fprintf(stderr, "TYPE(%lu) ", val);
  559. break;
  560. case TOK_ENUM:
  561. fprintf(stderr, "ENUM ");
  562. break;
  563. case TOK_BITS:
  564. fprintf(stderr, "BITS ");
  565. break;
  566. case TOK_TYPEDEF:
  567. fprintf(stderr, "TYPEDEF ");
  568. break;
  569. case TOK_DEFTYPE:
  570. fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
  571. break;
  572. case TOK_INCLUDE:
  573. fprintf(stderr, "INCLUDE ");
  574. break;
  575. case TOK_FILENAME:
  576. fprintf(stderr, "FILENAME ");
  577. break;
  578. default:
  579. if (tok < TOK_EOF) {
  580. if (isprint(tok))
  581. fprintf(stderr, "'%c' ", tok);
  582. else if (tok == '\n')
  583. fprintf(stderr, "\n");
  584. else
  585. fprintf(stderr, "%02x ", tok);
  586. } else
  587. abort();
  588. break;
  589. }
  590. }
  591. return (tok);
  592. }
  593. /**
  594. * Pushback a token
  595. */
  596. static void
  597. pushback(enum tok tok)
  598. {
  599. if (saved_token != -1)
  600. abort();
  601. saved_token = tok;
  602. }
  603. /*
  604. * Create a new type
  605. */
  606. static struct type *
  607. make_type(const char *s)
  608. {
  609. struct type *t;
  610. t = xalloc(sizeof(*t));
  611. t->name = savestr(s);
  612. t->is_enum = 0;
  613. t->syntax = SNMP_SYNTAX_NULL;
  614. t->from_fname = savestr(input->fname);
  615. t->from_lno = input->lno;
  616. TAILQ_INIT(&t->enums);
  617. LIST_INSERT_HEAD(&types, t, link);
  618. return (t);
  619. }
  620. /*
  621. * Parse a type. We've seen the ENUM or type keyword already. Leave next
  622. * token.
  623. */
  624. static u_int
  625. parse_type(enum tok *tok, struct type *t, const char *vname)
  626. {
  627. u_int syntax;
  628. struct enums *e;
  629. syntax = val;
  630. if (*tok == TOK_ENUM || *tok == TOK_BITS) {
  631. if (t == NULL && vname != NULL) {
  632. t = make_type(vname);
  633. t->is_enum = (*tok == TOK_ENUM);
  634. t->is_bits = (*tok == TOK_BITS);
  635. t->syntax = syntax;
  636. }
  637. if (gettoken() != '(')
  638. report("'(' expected after ENUM");
  639. if ((*tok = gettoken()) == TOK_EOF)
  640. report("unexpected EOF in ENUM");
  641. do {
  642. e = NULL;
  643. if (t != NULL) {
  644. e = xalloc(sizeof(*e));
  645. }
  646. if (*tok == '-') {
  647. if ((*tok = gettoken()) == TOK_EOF)
  648. report("unexpected EOF in ENUM");
  649. e->value = -(long)val;
  650. } else
  651. e->value = val;
  652. if (*tok != TOK_NUM)
  653. report("need value for ENUM/BITS");
  654. if (gettoken() != TOK_STR)
  655. report("need string in ENUM/BITS");
  656. if (e != NULL) {
  657. e->name = savetok();
  658. TAILQ_INSERT_TAIL(&t->enums, e, link);
  659. }
  660. if ((*tok = gettoken()) == TOK_EOF)
  661. report("unexpected EOF in ENUM/BITS");
  662. } while (*tok != ')');
  663. *tok = gettoken();
  664. } else if (*tok == TOK_DEFTYPE) {
  665. *tok = gettoken();
  666. } else {
  667. if ((*tok = gettoken()) == '|') {
  668. if (gettoken() != TOK_STR)
  669. report("subtype expected after '|'");
  670. *tok = gettoken();
  671. }
  672. }
  673. return (syntax);
  674. }
  675. /*
  676. * Parse the next node (complete with all subnodes)
  677. */
  678. static struct node *
  679. parse(enum tok tok)
  680. {
  681. struct node *node;
  682. struct node *sub;
  683. u_int index_count;
  684. node = xalloc(sizeof(struct node));
  685. node->lno = input->lno;
  686. node->flags = 0;
  687. if (tok != '(')
  688. report("'(' expected at begin of node");
  689. if (gettoken() != TOK_NUM)
  690. report("node id expected after opening '('");
  691. if (val > ASN_MAXID)
  692. report("subid too large '%lu'", val);
  693. node->id = (asn_subid_t)val;
  694. if (gettoken() != TOK_STR)
  695. report("node name expected after '(' ID");
  696. node->name = savetok();
  697. if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
  698. tok == TOK_ENUM || tok == TOK_BITS) {
  699. /* LEAF or COLUM */
  700. u_int syntax = parse_type(&tok, NULL, node->name);
  701. if (tok == TOK_STR) {
  702. /* LEAF */
  703. node->type = NODE_LEAF;
  704. node->u.leaf.func = savetok();
  705. node->u.leaf.syntax = syntax;
  706. tok = gettoken();
  707. } else {
  708. /* COLUMN */
  709. node->type = NODE_COLUMN;
  710. node->u.column.syntax = syntax;
  711. }
  712. while (tok != ')') {
  713. if (tok != TOK_ACCESS)
  714. report("access keyword or ')' expected");
  715. node->flags |= (u_int)val;
  716. tok = gettoken();
  717. }
  718. } else if (tok == ':') {
  719. /* ENTRY */
  720. node->type = NODE_ENTRY;
  721. TAILQ_INIT(&node->u.entry.subs);
  722. index_count = 0;
  723. node->u.entry.index = 0;
  724. tok = gettoken();
  725. while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
  726. tok == TOK_ENUM || tok == TOK_BITS) {
  727. u_int syntax = parse_type(&tok, NULL, node->name);
  728. if (index_count++ == SNMP_INDEXES_MAX)
  729. report("too many table indexes");
  730. node->u.entry.index |=
  731. syntax << (SNMP_INDEX_SHIFT * index_count);
  732. }
  733. node->u.entry.index |= index_count;
  734. if (index_count == 0)
  735. report("need at least one index");
  736. if (tok != TOK_STR)
  737. report("function name expected");
  738. node->u.entry.func = savetok();
  739. tok = gettoken();
  740. while (tok != ')') {
  741. sub = parse(tok);
  742. TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
  743. tok = gettoken();
  744. }
  745. } else {
  746. /* subtree */
  747. node->type = NODE_TREE;
  748. TAILQ_INIT(&node->u.tree.subs);
  749. while (tok != ')') {
  750. sub = parse(tok);
  751. TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
  752. tok = gettoken();
  753. }
  754. }
  755. return (node);
  756. }
  757. /*
  758. * Parse a top level element. Return the tree if it was a tree, NULL
  759. * otherwise.
  760. */
  761. static struct node *
  762. parse_top(enum tok tok)
  763. {
  764. struct type *t;
  765. if (tok == '(')
  766. return (parse(tok));
  767. if (tok == TOK_TYPEDEF) {
  768. if (gettoken() != TOK_STR)
  769. report("type name expected after typedef");
  770. t = make_type(str);
  771. tok = gettoken();
  772. t->is_enum = (tok == TOK_ENUM);
  773. t->is_bits = (tok == TOK_BITS);
  774. t->syntax = parse_type(&tok, t, NULL);
  775. pushback(tok);
  776. return (NULL);
  777. }
  778. if (tok == TOK_INCLUDE) {
  779. if (gettoken() != TOK_FILENAME)
  780. report("filename expected in include directive");
  781. input_fopen(str, val);
  782. return (NULL);
  783. }
  784. report("'(' or 'typedef' expected");
  785. }
  786. /*
  787. * Generate the C-code table part for one node.
  788. */
  789. static void
  790. gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
  791. const char *func)
  792. {
  793. u_int n;
  794. struct node *sub;
  795. u_int syntax;
  796. if (oid->len == ASN_MAXOIDLEN)
  797. report_node(np, "OID too long");
  798. oid->subs[oid->len++] = np->id;
  799. if (np->type == NODE_TREE) {
  800. TAILQ_FOREACH(sub, &np->u.tree.subs, link)
  801. gen_node(fp, sub, oid, 0, NULL);
  802. oid->len--;
  803. return;
  804. }
  805. if (np->type == NODE_ENTRY) {
  806. TAILQ_FOREACH(sub, &np->u.entry.subs, link)
  807. gen_node(fp, sub, oid, np->u.entry.index,
  808. np->u.entry.func);
  809. oid->len--;
  810. return;
  811. }
  812. /* leaf or column */
  813. if ((np->flags & (FL_GET|FL_SET)) == 0) {
  814. oid->len--;
  815. return;
  816. }
  817. fprintf(fp, " {{ %u, {", oid->len);
  818. for (n = 0; n < oid->len; n++)
  819. fprintf(fp, " %u,", oid->subs[n]);
  820. fprintf(fp, " }}, \"%s\", ", np->name);
  821. if (np->type == NODE_COLUMN) {
  822. syntax = np->u.column.syntax;
  823. fprintf(fp, "SNMP_NODE_COLUMN, ");
  824. } else {
  825. syntax = np->u.leaf.syntax;
  826. fprintf(fp, "SNMP_NODE_LEAF, ");
  827. }
  828. switch (syntax) {
  829. case SNMP_SYNTAX_NULL:
  830. fprintf(fp, "SNMP_SYNTAX_NULL, ");
  831. break;
  832. case SNMP_SYNTAX_INTEGER:
  833. fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
  834. break;
  835. case SNMP_SYNTAX_OCTETSTRING:
  836. fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
  837. break;
  838. case SNMP_SYNTAX_IPADDRESS:
  839. fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
  840. break;
  841. case SNMP_SYNTAX_OID:
  842. fprintf(fp, "SNMP_SYNTAX_OID, ");
  843. break;
  844. case SNMP_SYNTAX_TIMETICKS:
  845. fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
  846. break;
  847. case SNMP_SYNTAX_COUNTER:
  848. fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
  849. break;
  850. case SNMP_SYNTAX_GAUGE:
  851. fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
  852. break;
  853. case SNMP_SYNTAX_COUNTER64:
  854. fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
  855. break;
  856. case SNMP_SYNTAX_NOSUCHOBJECT:
  857. case SNMP_SYNTAX_NOSUCHINSTANCE:
  858. case SNMP_SYNTAX_ENDOFMIBVIEW:
  859. abort();
  860. }
  861. if (np->type == NODE_COLUMN)
  862. fprintf(fp, "%s, ", func);
  863. else
  864. fprintf(fp, "%s, ", np->u.leaf.func);
  865. fprintf(fp, "0");
  866. if (np->flags & FL_SET)
  867. fprintf(fp, "|SNMP_NODE_CANSET");
  868. fprintf(fp, ", %#x, NULL, NULL },\n", idx);
  869. oid->len--;
  870. return;
  871. }
  872. /*
  873. * Generate the header file with the function declarations.
  874. */
  875. static void
  876. gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
  877. {
  878. char f[MAXSTR + 4];
  879. struct node *sub;
  880. struct func *ptr;
  881. oidlen++;
  882. if (np->type == NODE_TREE) {
  883. TAILQ_FOREACH(sub, &np->u.tree.subs, link)
  884. gen_header(fp, sub, oidlen, NULL);
  885. return;
  886. }
  887. if (np->type == NODE_ENTRY) {
  888. TAILQ_FOREACH(sub, &np->u.entry.subs, link)
  889. gen_header(fp, sub, oidlen, np->u.entry.func);
  890. return;
  891. }
  892. if((np->flags & (FL_GET|FL_SET)) == 0)
  893. return;
  894. if (np->type == NODE_COLUMN) {
  895. if (func == NULL)
  896. errx(1, "column without function (%s) - probably "
  897. "outside of a table", np->name);
  898. sprintf(f, "%s", func);
  899. } else
  900. sprintf(f, "%s", np->u.leaf.func);
  901. LIST_FOREACH(ptr, &funcs, link)
  902. if (strcmp(ptr->name, f) == 0)
  903. break;
  904. if (ptr == NULL) {
  905. ptr = xalloc(sizeof(*ptr));
  906. ptr->name = savestr(f);
  907. LIST_INSERT_HEAD(&funcs, ptr, link);
  908. fprintf(fp, "int %s(struct snmp_context *, "
  909. "struct snmp_value *, u_int, u_int, "
  910. "enum snmp_op);\n", f);
  911. }
  912. fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
  913. }
  914. /*
  915. * Generate the OID table.
  916. */
  917. static void
  918. gen_table(FILE *fp, struct node *node)
  919. {
  920. struct asn_oid oid;
  921. fprintf(fp, "#include <sys/types.h>\n");
  922. fprintf(fp, "#include <stdio.h>\n");
  923. #ifdef HAVE_STDINT_H
  924. fprintf(fp, "#include <stdint.h>\n");
  925. #endif
  926. if (localincs) {
  927. fprintf(fp, "#include \"asn1.h\"\n");
  928. fprintf(fp, "#include \"snmp.h\"\n");
  929. fprintf(fp, "#include \"snmpagent.h\"\n");
  930. } else {
  931. fprintf(fp, "#include <bsnmp/asn1.h>\n");
  932. fprintf(fp, "#include <bsnmp/snmp.h>\n");
  933. fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
  934. }
  935. fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
  936. fprintf(fp, "\n");
  937. fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
  938. oid.len = PREFIX_LEN;
  939. memcpy(oid.subs, prefix, sizeof(prefix));
  940. gen_node(fp, node, &oid, 0, NULL);
  941. fprintf(fp, "};\n\n");
  942. }
  943. static void
  944. print_syntax(u_int syntax)
  945. {
  946. u_int i;
  947. for (i = 0; keywords[i].str != NULL; i++)
  948. if (keywords[i].tok == TOK_TYPE &&
  949. keywords[i].val == syntax) {
  950. printf(" %s", keywords[i].str);
  951. return;
  952. }
  953. abort();
  954. }
  955. /*
  956. * Generate a tree definition file
  957. */
  958. static void
  959. gen_tree(const struct node *np, int level)
  960. {
  961. const struct node *sp;
  962. u_int i;
  963. printf("%*s(%u %s", 2 * level, "", np->id, np->name);
  964. switch (np->type) {
  965. case NODE_LEAF:
  966. print_syntax(np->u.leaf.syntax);
  967. printf(" %s%s%s)\n", np->u.leaf.func,
  968. (np->flags & FL_GET) ? " GET" : "",
  969. (np->flags & FL_SET) ? " SET" : "");
  970. break;
  971. case NODE_TREE:
  972. if (TAILQ_EMPTY(&np->u.tree.subs)) {
  973. printf(")\n");
  974. } else {
  975. printf("\n");
  976. TAILQ_FOREACH(sp, &np->u.tree.subs, link)
  977. gen_tree(sp, level + 1);
  978. printf("%*s)\n", 2 * level, "");
  979. }
  980. break;
  981. case NODE_ENTRY:
  982. printf(" :");
  983. for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
  984. print_syntax(SNMP_INDEX(np->u.entry.index, i));
  985. printf(" %s\n", np->u.entry.func);
  986. TAILQ_FOREACH(sp, &np->u.entry.subs, link)
  987. gen_tree(sp, level + 1);
  988. printf("%*s)\n", 2 * level, "");
  989. break;
  990. case NODE_COLUMN:
  991. print_syntax(np->u.column.syntax);
  992. printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
  993. (np->flags & FL_SET) ? " SET" : "");
  994. break;
  995. }
  996. }
  997. static int
  998. extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
  999. const struct asn_oid *idx, const char *iname)
  1000. {
  1001. struct node *sub;
  1002. u_long n;
  1003. if (oid->len == ASN_MAXOIDLEN)
  1004. report_node(np, "OID too long");
  1005. oid->subs[oid->len++] = np->id;
  1006. if (strcmp(obj, np->name) == 0) {
  1007. if (oid->len + idx->len >= ASN_MAXOIDLEN)
  1008. report_node(np, "OID too long");
  1009. fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
  1010. iname ? iname : "", np->id);
  1011. fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
  1012. iname ? iname : "", oid->len + idx->len);
  1013. fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
  1014. iname ? iname : "", oid->len + idx->len);
  1015. for (n = 0; n < oid->len; n++)
  1016. fprintf(fp, " %u,", oid->subs[n]);
  1017. for (n = 0; n < idx->len; n++)
  1018. fprintf(fp, " %u,", idx->subs[n]);
  1019. fprintf(fp, " } }\n");
  1020. return (0);
  1021. }
  1022. if (np->type == NODE_TREE) {
  1023. TAILQ_FOREACH(sub, &np->u.tree.subs, link)
  1024. if (!extract(fp, sub, oid, obj, idx, iname))
  1025. return (0);
  1026. } else if (np->type == NODE_ENTRY) {
  1027. TAILQ_FOREACH(sub, &np->u.entry.subs, link)
  1028. if (!extract(fp, sub, oid, obj, idx, iname))
  1029. return (0);
  1030. }
  1031. oid->len--;
  1032. return (1);
  1033. }
  1034. static int
  1035. gen_extract(FILE *fp, const struct node *root, char *object)
  1036. {
  1037. struct asn_oid oid;
  1038. struct asn_oid idx;
  1039. char *s, *e, *end, *iname;
  1040. u_long ul;
  1041. int ret;
  1042. /* look whether the object to extract has an index part */
  1043. idx.len = 0;
  1044. iname = NULL;
  1045. s = strchr(object, '.');
  1046. if (s != NULL) {
  1047. iname = malloc(strlen(s) + 1);
  1048. if (iname == NULL)
  1049. err(1, "cannot allocated index");
  1050. strcpy(iname, s);
  1051. for (e = iname; *e != '\0'; e++)
  1052. if (*e == '.')
  1053. *e = '_';
  1054. *s++ = '\0';
  1055. while (s != NULL) {
  1056. if (*s == '\0')
  1057. errx(1, "bad index syntax");
  1058. if ((e = strchr(s, '.')) != NULL)
  1059. *e++ = '\0';
  1060. errno = 0;
  1061. ul = strtoul(s, &end, 0);
  1062. if (*end != '\0')
  1063. errx(1, "bad index syntax '%s'", end);
  1064. if (errno != 0)
  1065. err(1, "bad index syntax");
  1066. if (idx.len == ASN_MAXOIDLEN)
  1067. errx(1, "index oid too large");
  1068. idx.subs[idx.len++] = ul;
  1069. s = e;
  1070. }
  1071. }
  1072. oid.len = PREFIX_LEN;
  1073. memcpy(oid.subs, prefix, sizeof(prefix));
  1074. ret = extract(fp, root, &oid, object, &idx, iname);
  1075. if (iname != NULL)
  1076. free(iname);
  1077. return (ret);
  1078. }
  1079. static void
  1080. check_sub_order(const struct node *np, const struct node_list *subs)
  1081. {
  1082. int first;
  1083. const struct node *sub;
  1084. asn_subid_t maxid = 0;
  1085. /* ensure, that subids are ordered */
  1086. first = 1;
  1087. TAILQ_FOREACH(sub, subs, link) {
  1088. if (!first && sub->id <= maxid)
  1089. report_node(np, "subids not ordered at %s", sub->name);
  1090. maxid = sub->id;
  1091. first = 0;
  1092. }
  1093. }
  1094. /*
  1095. * Do some sanity checks on the tree definition and do some computations.
  1096. */
  1097. static void
  1098. check_tree(struct node *np)
  1099. {
  1100. struct node *sub;
  1101. if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
  1102. if ((np->flags & (FL_GET|FL_SET)) != 0)
  1103. tree_size++;
  1104. return;
  1105. }
  1106. if (np->type == NODE_ENTRY) {
  1107. check_sub_order(np, &np->u.entry.subs);
  1108. /* ensure all subnodes are columns */
  1109. TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
  1110. if (sub->type != NODE_COLUMN)
  1111. report_node(np, "entry subnode '%s' is not "
  1112. "a column", sub->name);
  1113. check_tree(sub);
  1114. }
  1115. } else {
  1116. check_sub_order(np, &np->u.tree.subs);
  1117. TAILQ_FOREACH(sub, &np->u.tree.subs, link)
  1118. check_tree(sub);
  1119. }
  1120. }
  1121. static void
  1122. merge_subs(struct node_list *s1, struct node_list *s2)
  1123. {
  1124. struct node *n1, *n2;
  1125. while (!TAILQ_EMPTY(s2)) {
  1126. n2 = TAILQ_FIRST(s2);
  1127. TAILQ_REMOVE(s2, n2, link);
  1128. TAILQ_FOREACH(n1, s1, link)
  1129. if (n1->id >= n2->id)
  1130. break;
  1131. if (n1 == NULL)
  1132. TAILQ_INSERT_TAIL(s1, n2, link);
  1133. else if (n1->id > n2->id)
  1134. TAILQ_INSERT_BEFORE(n1, n2, link);
  1135. else {
  1136. if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
  1137. if (strcmp(n1->name, n2->name) != 0)
  1138. errx(1, "trees to merge must have "
  1139. "same name '%s' '%s'", n1->name,
  1140. n2->name);
  1141. merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
  1142. free(n2);
  1143. } else if (n1->type == NODE_ENTRY &&
  1144. n2->type == NODE_ENTRY) {
  1145. if (strcmp(n1->name, n2->name) != 0)
  1146. errx(1, "entries to merge must have "
  1147. "same name '%s' '%s'", n1->name,
  1148. n2->name);
  1149. if (n1->u.entry.index != n2->u.entry.index)
  1150. errx(1, "entries to merge must have "
  1151. "same index '%s'", n1->name);
  1152. if (strcmp(n1->u.entry.func,
  1153. n2->u.entry.func) != 0)
  1154. errx(1, "entries to merge must have "
  1155. "same op '%s'", n1->name);
  1156. merge_subs(&n1->u.entry.subs,
  1157. &n2->u.entry.subs);
  1158. free(n2);
  1159. } else
  1160. errx(1, "entities to merge must be both "
  1161. "trees or both entries: %s, %s",
  1162. n1->name, n2->name);
  1163. }
  1164. }
  1165. }
  1166. static void
  1167. merge(struct node **root, struct node *t)
  1168. {
  1169. if (*root == NULL) {
  1170. *root = t;
  1171. return;
  1172. }
  1173. if (t == NULL)
  1174. return;
  1175. /* both must be trees */
  1176. if ((*root)->type != NODE_TREE)
  1177. errx(1, "root is not a tree");
  1178. if (t->type != NODE_TREE)
  1179. errx(1, "can merge only with tree");
  1180. if ((*root)->id != t->id)
  1181. errx(1, "trees to merge must have same id");
  1182. merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
  1183. }
  1184. static void
  1185. unminus(FILE *fp, const char *s)
  1186. {
  1187. while (*s != '\0') {
  1188. if (*s == '-')
  1189. fprintf(fp, "_");
  1190. else
  1191. fprintf(fp, "%c", *s);
  1192. s++;
  1193. }
  1194. }
  1195. static void
  1196. gen_enum(FILE *fp, const struct type *t)
  1197. {
  1198. const struct enums *e;
  1199. long min = LONG_MAX;
  1200. fprintf(fp, "\n");
  1201. fprintf(fp, "#ifndef %s_defined__\n", t->name);
  1202. fprintf(fp, "#define %s_defined__\n", t->name);
  1203. fprintf(fp, "/*\n");
  1204. fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
  1205. fprintf(fp, " */\n");
  1206. fprintf(fp, "enum %s {\n", t->name);
  1207. TAILQ_FOREACH(e, &t->enums, link) {
  1208. fprintf(fp, "\t%s_", t->name);
  1209. unminus(fp, e->name);
  1210. fprintf(fp, " = %ld,\n", e->value);
  1211. if (e->value < min)
  1212. min = e->value;
  1213. }
  1214. fprintf(fp, "};\n");
  1215. fprintf(fp, "#define STROFF_%s %ld\n", t->name, min);
  1216. fprintf(fp, "#define STRING_%s \\\n", t->name);
  1217. TAILQ_FOREACH(e, &t->enums, link) {
  1218. fprintf(fp, "\t[%ld] \"%s_", e->value - min, t->name);
  1219. unminus(fp, e->name);
  1220. fprintf(fp, "\",\\\n");
  1221. }
  1222. fprintf(fp, "\n");
  1223. fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
  1224. }
  1225. static void
  1226. gen_enums(FILE *fp)
  1227. {
  1228. const struct type *t;
  1229. LIST_FOREACH(t, &types, link)
  1230. if (t->is_enum || t->is_bits)
  1231. gen_enum(fp, t);
  1232. }
  1233. static int
  1234. extract_enum(FILE *fp, const char *name)
  1235. {
  1236. const struct type *t;
  1237. LIST_FOREACH(t, &types, link)
  1238. if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
  1239. gen_enum(fp, t);
  1240. return (0);
  1241. }
  1242. return (-1);
  1243. }
  1244. int
  1245. main(int argc, char *argv[])
  1246. {
  1247. int do_extract = 0;
  1248. int do_tree = 0;
  1249. int do_enums = 0;
  1250. int opt;
  1251. struct node *root;
  1252. char fname[MAXPATHLEN + 1];
  1253. int tok;
  1254. FILE *fp;
  1255. char *infile = NULL;
  1256. while ((opt = getopt(argc, argv, "dEehI:i:lp:t")) != EOF)
  1257. switch (opt) {
  1258. case 'd':
  1259. debug = 1;
  1260. break;
  1261. case 'h':
  1262. fprintf(stderr, "%s", usgtxt);
  1263. exit(0);
  1264. case 'E':
  1265. do_enums = 1;
  1266. break;
  1267. case 'e':
  1268. do_extract = 1;
  1269. break;
  1270. case 'I':
  1271. path_new(optarg);
  1272. break;
  1273. case 'i':
  1274. infile = optarg;
  1275. break;
  1276. case 'l':
  1277. localincs = 1;
  1278. break;
  1279. case 'p':
  1280. file_prefix = optarg;
  1281. if (strlen(file_prefix) + strlen("tree.c") >
  1282. MAXPATHLEN)
  1283. errx(1, "prefix too long");
  1284. break;
  1285. case 't':
  1286. do_tree = 1;
  1287. break;
  1288. }
  1289. if (do_extract + do_tree + do_enums > 1)
  1290. errx(1, "conflicting options -e/-t/-E");
  1291. if (!do_extract && !do_enums && argc != optind)
  1292. errx(1, "no arguments allowed");
  1293. if ((do_extract || do_enums) && argc == optind)
  1294. errx(1, "no objects specified");
  1295. if (infile == NULL) {
  1296. input_new(stdin, NULL, "<stdin>");
  1297. } else {
  1298. if ((fp = fopen(infile, "r")) == NULL)
  1299. err(1, "%s", infile);
  1300. input_new(fp, NULL, infile);
  1301. }
  1302. root = parse_top(gettoken());
  1303. while ((tok = gettoken()) != TOK_EOF)
  1304. merge(&root, parse_top(tok));
  1305. check_tree(root);
  1306. if (do_extract) {
  1307. while (optind < argc) {
  1308. if (gen_extract(stdout, root, argv[optind]))
  1309. errx(1, "object not found: %s", argv[optind]);
  1310. optind++;
  1311. }
  1312. return (0);
  1313. }
  1314. if (do_enums) {
  1315. while (optind < argc) {
  1316. if (extract_enum(stdout, argv[optind]))
  1317. errx(1, "enum not found: %s", argv[optind]);
  1318. optind++;
  1319. }
  1320. return (0);
  1321. }
  1322. if (do_tree) {
  1323. gen_tree(root, 0);
  1324. return (0);
  1325. }
  1326. sprintf(fname, "%stree.h", file_prefix);
  1327. if ((fp = fopen(fname, "w")) == NULL)
  1328. err(1, "%s: ", fname);
  1329. gen_header(fp, root, PREFIX_LEN, NULL);
  1330. fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
  1331. gen_enums(fp);
  1332. fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
  1333. fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
  1334. fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
  1335. fclose(fp);
  1336. sprintf(fname, "%stree.c", file_prefix);
  1337. if ((fp = fopen(fname, "w")) == NULL)
  1338. err(1, "%s: ", fname);
  1339. gen_table(fp, root);
  1340. fclose(fp);
  1341. return (0);
  1342. }