diff options
Diffstat (limited to 'contrib/bsnmp/gensnmptree')
-rw-r--r-- | contrib/bsnmp/gensnmptree/gensnmptree.1 | 190 | ||||
-rw-r--r-- | contrib/bsnmp/gensnmptree/gensnmptree.c | 770 |
2 files changed, 960 insertions, 0 deletions
diff --git a/contrib/bsnmp/gensnmptree/gensnmptree.1 b/contrib/bsnmp/gensnmptree/gensnmptree.1 new file mode 100644 index 000000000000..2970355df2bf --- /dev/null +++ b/contrib/bsnmp/gensnmptree/gensnmptree.1 @@ -0,0 +1,190 @@ +.\" +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Redistribution of this software and documentation and use in source and +.\" binary forms, with or without modification, are permitted provided that +.\" the following conditions are met: +.\" +.\" 1. Redistributions of source code or documentation must retain the above +.\" copyright notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the Institute nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS +.\" AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +.\" FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +.\" FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +.\" OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/gensnmptree/gensnmptree.1,v 1.1 2002/08/15 13:27:44 hbb Exp $ +.\" +.\" Author: Harti Brandt <harti@freebsd.org> +.\" +.Dd October 7, 2003 +.Dt gensnmptree 1 +.Os +.Sh NAME +.Nm gensnmptree +.Nd "generate C and header files from a MIB description file" +.Sh SYNOPSIS +.Nm +.Op Fl hel +.Op Fl p Ar prefix +.Op Ar name Ar ... +.Sh DESCRIPTION +The +.Nm +utility is used to either generate C language tables and header files from +a MIB description or to numeric OIDs from MIB descriptions. The first form +is used only for maintaining the +.Xr snmpd 1 +daemon or for module writers. +The second form may be used by SNMP client program writers. +.Pp +If the +.Fl e +option is not used +.Nm +reads a MIB description from its standard input and creates two files: a +C-file +.Ar prefix Ns tree.c +containing a table used by +.Xr snmpd 1 +during PDU processing +and a header file +.Ar prefix Ns tree.h +containing appropriate declarations of the callback functions used in this table +and the table itself. +.Pp +If the +.Fl e +option is specified +.Nm +expects MIB variable names (only the last component) on its command line. +It reads a MIB specification from standard input and for each MIB variable +name emits two C preprocessor defines on its standard output. One define +.Va OID_ Ns Ar name +can be used as an array initialized to initialize a +.Va struct asn_oid . +The other define +.Va OIDLEN_ Ns Ar name +contains the length of the OID. +.Pp +The options are as follows: +.Bl -tag -width ".Fl d Ar argument" +.It Fl h +Print a short help page. +.It Fl e +Enter extract mode. +.It Fl l +Generate local preprocessor includes. This is used for bootstrapping +.Xr snmpd 1 . +.It Fl p Ar prefix +Prefix the file names and the table name with +.Ar prefix . +.El +.Sh MIBS +The syntax of the MIB description file can formally be specified as follows: +.Bd -unfilled -offset indent +tree := head elements ')' + +entry := head ':' index STRING elements ')' + +leaf := head TYPE STRING ACCESS ')' + +column := head TYPE ACCESS ')' + +head := '(' INT STRING + +elements := EMPTY | elements element + +element := tree | leaf + +index := TYPE | index TYPE +.Ed +.Pp +.Ar TYPE +specifies a SNMP data type and may be one of +.Bl -bullet -offset indent -compact +.It +NULL +.It +INTEGER +.It +INTEGER32 (same as INTEGER) +.It +UNSIGNED32 (same as GAUGE) +.It +OCTETSTRING +.It +IPADDRESS +.It +OID +.It +TIMETICKS +.It +COUNTER +.It +GAUGE +.It +COUNTER64 +.El +.Pp +.Ar ACCESS +specifies the accessibility of the MIB variable (which operation can be +performed) and is one of +.Bl -bullet -offset indent -compact +.It +GET +.It +SET +.El +.Pp +.Ar INT +is a decimal integer and +.Ar STRING +is any string starting with a letter or underscore and consisting of +letters, digits and underscores, that is not one of the keywords. +.Sh EXAMPLES +The following MIB description describes the system group: +.Bd -literal -offset indent +(1 internet + (2 mgmt + (1 mibII + (1 system + (1 sysDescr OCTETSTRING op_system_group GET) + (2 sysObjectId OID op_system_group GET) + (3 sysUpTime TIMETICKS op_system_group GET) + (4 sysContact OCTETSTRING op_system_group GET SET) + (5 sysName OCTETSTRING op_system_group GET SET) + (6 sysLocation OCTETSTRING op_system_group GET SET) + (7 sysServices INTEGER op_system_group GET) + (8 sysORLastChange TIMETICKS op_system_group GET) + (9 sysORTable + (1 sysOREntry : INTEGER op_or_table + (1 sysORIndex INTEGER) + (2 sysORID OID GET) + (3 sysORDescr OCTETSTRING GET) + (4 sysORUpTime TIMETICKS GET) + )) + ) + ) + ) +) +.Ed +.Sh SEE ALSO +.Xr snmpd 1 +.Sh AUTHORS +.An Hartmut Brandt Aq harti@freebsd.org diff --git a/contrib/bsnmp/gensnmptree/gensnmptree.c b/contrib/bsnmp/gensnmptree/gensnmptree.c new file mode 100644 index 000000000000..5c400e3d7a74 --- /dev/null +++ b/contrib/bsnmp/gensnmptree/gensnmptree.c @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * Redistribution of this software and documentation and use in source and + * binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * 1. Redistributions of source code or documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.34 2003/01/28 13:44:34 hbb Exp $ + * + * Generate OID table from table description. + * + * Syntax is: + * --------- + * tree := head elements ')' + * + * entry := head ':' index STRING elements ')' + * + * leaf := head TYPE STRING ACCESS ')' + * + * column := head TYPE ACCESS ')' + * + * head := '(' INT STRING + * + * elements := EMPTY | elements element + * + * element := tree | leaf + * + * index := TYPE | index TYPE + * + */ +#include <sys/types.h> +#include <sys/param.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <err.h> +#include <sys/queue.h> +#include "asn1.h" +#include "snmp.h" +#include "snmpagent.h" + +/* + * Constant prefix for all OIDs + */ +static const asn_subid_t prefix[] = { 1, 3, 6 }; +#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) + +u_int tree_size; +static const char *file_prefix = ""; +static FILE *fp; + +/* if true generate local include paths */ +static int localincs = 0; + +static const char usgtxt[] = "\ +Generate SNMP tables. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ +Open Communication Systems (FhG Fokus). All rights reserved.\n\ +usage: gensnmptree [-hel] [-p prefix] [name]...\n\ +options:\n\ + -h print this info\n\ + -e extrace the named oids\n\ + -l generate local include directives\n\ + -p prefix prepend prefix to file and variable names\n\ +"; + +/* + * A node in the OID tree + */ +enum ntype { + NODE_LEAF = 1, + NODE_TREE, + NODE_ENTRY, + NODE_COLUMN +}; + +enum { + FL_GET = 0x01, + FL_SET = 0x02, +}; + +struct node; +TAILQ_HEAD(node_list, node); + +struct node { + enum ntype type; + asn_subid_t id; /* last element of OID */ + char *name; /* name of node */ + TAILQ_ENTRY(node) link; + u_int lno; /* starting line number */ + u_int flags; /* allowed operations */ + + union { + struct tree { + struct node_list subs; + } tree; + + struct entry { + u_int32_t index; /* index for table entry */ + char *func; /* function for tables */ + struct node_list subs; + } entry; + + struct leaf { + enum snmp_syntax syntax; /* syntax for this leaf */ + char *func; /* function name */ + } leaf; + + struct column { + enum snmp_syntax syntax; /* syntax for this column */ + } column; + } u; +}; + +struct func { + const char *name; + LIST_ENTRY(func) link; +}; + +static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); + +/************************************************************ + * + * Allocate memory and panic just in the case... + */ +static void * +xalloc(size_t size) +{ + void *ptr; + + if ((ptr = malloc(size)) == NULL) + err(1, "allocing %u bytes", size); + + return (ptr); +} + +/************************************************************ + * + * Parsing input + */ +enum tok { + TOK_EOF = 0200, /* end-of-file seen */ + TOK_NUM, /* number */ + TOK_STR, /* string */ + TOK_ACCESS, /* access operator */ + TOK_TYPE, /* type operator */ +}; + +static const struct { + const char *str; + enum tok tok; + u_int val; +} keywords[] = { + { "GET", TOK_ACCESS, FL_GET }, + { "SET", TOK_ACCESS, FL_SET }, + { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, + { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, + { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, + { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, + { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, + { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, + { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, + { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, + { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, + { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, + { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, + { NULL, 0, 0 } +}; + +/* arbitrary upper limit on node names and function names */ +#define MAXSTR 1000 +char str[MAXSTR]; +u_long val; /* integer values */ +u_int lno = 1; /* current line number */ + +static void report(const char *, ...) __dead2 __printflike(1, 2); +static void report_node(const struct node *, const char *, ...) + __dead2 __printflike(2, 3); + +/* + * Report an error and exit. + */ +static void +report(const char *fmt, ...) +{ + va_list ap; + int c; + + va_start(ap, fmt); + fprintf(stderr, "line %u: ", lno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + fprintf(stderr, "context: \""); + while ((c = getchar()) != EOF && c != '\n') + fprintf(stderr, "%c", c); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} +static void +report_node(const struct node *np, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "line %u, node %s: ", np->lno, np->name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +/* + * Return a fresh copy of the string constituting the current token. + */ +static char * +savetok(void) +{ + return (strcpy(xalloc(strlen(str)+1), str)); +} + +/* + * Get the next token from input. + */ +static int +gettoken(void) +{ + int c; + + again: + /* + * Skip any whitespace before the next token + */ + while ((c = getchar()) != EOF) { + if (c == '\n') + lno++; + if (!isspace(c)) + break; + } + if (c == EOF) + return (TOK_EOF); + if (!isascii(c)) + report("unexpected character %#2x", (u_int)c); + + /* + * Skip comments + */ + if (c == '#') { + while ((c = getchar()) != EOF) { + if (c == '\n') { + lno++; + goto again; + } + } + report("unexpected EOF in comment"); + } + + /* + * Single character tokens + */ + if (c == ')' || c == '(' || c == ':') + return (c); + + /* + * Sort out numbers + */ + if (isdigit(c)) { + ungetc(c, stdin); + scanf("%lu", &val); + return (TOK_NUM); + } + + /* + * So that has to be a string. + */ + if (isalpha(c) || c == '_') { + size_t n = 0; + str[n++] = c; + while ((c = getchar()) != EOF) { + if (!isalnum(c) && c != '_') { + ungetc(c, stdin); + break; + } + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("string too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + + /* + * Keywords + */ + for (c = 0; keywords[c].str != NULL; c++) + if (strcmp(keywords[c].str, str) == 0) { + val = keywords[c].val; + return (keywords[c].tok); + } + + return (TOK_STR); + } + if (isprint(c)) + errx(1, "%u: unexpected character '%c'", lno, c); + else + errx(1, "%u: unexpected character 0x%02x", lno, (u_int)c); +} + +/* + * Parse the next node (complete with all subnodes) + */ +static struct node * +parse(enum tok tok) +{ + struct node *node; + struct node *sub; + u_int index_count; + + node = xalloc(sizeof(struct node)); + node->lno = lno; + + if (tok != '(') + report("'(' expected at begin of node"); + if (gettoken() != TOK_NUM) + report("node id expected after opening '('"); + if (val > ASN_MAXID) + report("subid too large '%lu'", val); + node->id = (asn_subid_t)val; + if (gettoken() != TOK_STR) + report("node name expected after '(' ID"); + node->name = savetok(); + + if ((tok = gettoken()) == TOK_TYPE) { + /* LEAF or COLUM */ + u_int syntax = val; + + if ((tok = gettoken()) == TOK_STR) { + /* LEAF */ + node->type = NODE_LEAF; + node->u.leaf.func = savetok(); + node->u.leaf.syntax = syntax; + tok = gettoken(); + } else { + /* COLUMN */ + node->type = NODE_COLUMN; + node->u.column.syntax = syntax; + } + + while (tok != ')') { + if (tok != TOK_ACCESS) + report("access keyword or ')' expected"); + node->flags |= (u_int)val; + tok = gettoken(); + } + + } else if (tok == ':') { + /* ENTRY */ + node->type = NODE_ENTRY; + TAILQ_INIT(&node->u.entry.subs); + + index_count = 0; + node->u.entry.index = 0; + while ((tok = gettoken()) == TOK_TYPE) { + if (index_count++ == SNMP_INDEXES_MAX) + report("too many table indexes"); + node->u.entry.index |= + val << (SNMP_INDEX_SHIFT * index_count); + } + node->u.entry.index |= index_count; + if (index_count == 0) + report("need at least one index"); + + if (tok != TOK_STR) + report("function name expected"); + + node->u.entry.func = savetok(); + + tok = gettoken(); + + while (tok != ')') { + sub = parse(tok); + TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); + tok = gettoken(); + } + + } else { + /* subtree */ + node->type = NODE_TREE; + TAILQ_INIT(&node->u.tree.subs); + + while (tok != ')') { + sub = parse(tok); + TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); + tok = gettoken(); + } + } + return (node); +} + +/* + * Generate the C-code table part for one node. + */ +static void +gen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func) +{ + u_int n; + struct node *sub; + u_int syntax; + + if (oid->len == ASN_MAXOIDLEN) + report_node(np, "OID too long"); + oid->subs[oid->len++] = np->id; + + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + gen_node(sub, oid, 0, NULL); + oid->len--; + return; + } + if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + gen_node(sub, oid, np->u.entry.index, np->u.entry.func); + oid->len--; + return; + } + + /* leaf or column */ + if ((np->flags & (FL_GET|FL_SET)) == 0) { + oid->len--; + return; + } + + fprintf(fp, " {{ %u, {", oid->len); + for (n = 0; n < oid->len; n++) + fprintf(fp, " %u,", oid->subs[n]); + fprintf(fp, " }}, \"%s\", ", np->name); + + if (np->type == NODE_COLUMN) { + syntax = np->u.column.syntax; + fprintf(fp, "SNMP_NODE_COLUMN, "); + } else { + syntax = np->u.leaf.syntax; + fprintf(fp, "SNMP_NODE_LEAF, "); + } + + switch (syntax) { + + case SNMP_SYNTAX_NULL: + fprintf(fp, "SNMP_SYNTAX_NULL, "); + break; + + case SNMP_SYNTAX_INTEGER: + fprintf(fp, "SNMP_SYNTAX_INTEGER, "); + break; + + case SNMP_SYNTAX_OCTETSTRING: + fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); + break; + + case SNMP_SYNTAX_IPADDRESS: + fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); + break; + + case SNMP_SYNTAX_OID: + fprintf(fp, "SNMP_SYNTAX_OID, "); + break; + + case SNMP_SYNTAX_TIMETICKS: + fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); + break; + + case SNMP_SYNTAX_COUNTER: + fprintf(fp, "SNMP_SYNTAX_COUNTER, "); + break; + + case SNMP_SYNTAX_GAUGE: + fprintf(fp, "SNMP_SYNTAX_GAUGE, "); + break; + + case SNMP_SYNTAX_COUNTER64: + fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + + if (np->type == NODE_COLUMN) + fprintf(fp, "%s, ", func); + else + fprintf(fp, "%s, ", np->u.leaf.func); + + fprintf(fp, "0"); + if (np->flags & FL_SET) + fprintf(fp, "|SNMP_NODE_CANSET"); + fprintf(fp, ", %#x, NULL },\n", idx); + oid->len--; + return; +} + +/* + * Generate the header file with the function declarations. + */ +static void +gen_header(struct node *np, u_int oidlen, const char *func) +{ + char f[MAXSTR + 4]; + struct node *sub; + struct func *ptr; + + oidlen++; + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + gen_header(sub, oidlen, NULL); + return; + } + if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + gen_header(sub, oidlen, np->u.entry.func); + return; + } + + if((np->flags & (FL_GET|FL_SET)) == 0) + return; + + if (np->type == NODE_COLUMN) + sprintf(f, "%s", func); + else + sprintf(f, "%s", np->u.leaf.func); + + LIST_FOREACH(ptr, &funcs, link) + if (strcmp(ptr->name, f) == 0) + break; + + if (ptr == NULL) { + ptr = xalloc(sizeof(*ptr)); + ptr->name = strcpy(xalloc(strlen(f)+1), f); + LIST_INSERT_HEAD(&funcs, ptr, link); + + fprintf(fp, "int %s(struct snmp_context *, " + "struct snmp_value *, u_int, u_int, " + "enum snmp_op);\n", f); + } + + fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); +} + +/* + * Generate the OID table. + */ +static void +gen_table(struct node *node) +{ + struct asn_oid oid; + + fprintf(fp, "#include <sys/types.h>\n"); + fprintf(fp, "#include <stdio.h>\n"); + if (localincs) { + fprintf(fp, "#include \"asn1.h\"\n"); + fprintf(fp, "#include \"snmp.h\"\n"); + fprintf(fp, "#include \"snmpagent.h\"\n"); + } else { + fprintf(fp, "#include <bsnmp/asn1.h>\n"); + fprintf(fp, "#include <bsnmp/snmp.h>\n"); + fprintf(fp, "#include <bsnmp/snmpagent.h>\n"); + } + fprintf(fp, "#include \"%stree.h\"\n", file_prefix); + fprintf(fp, "\n"); + + fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); + + oid.len = PREFIX_LEN; + memcpy(oid.subs, prefix, sizeof(prefix)); + gen_node(node, &oid, 0, NULL); + + fprintf(fp, "};\n\n"); +} + +static int +extract(const struct node *np, struct asn_oid *oid, const char *obj) +{ + struct node *sub; + u_long n; + + if (oid->len == ASN_MAXOIDLEN) + report_node(np, "OID too long"); + oid->subs[oid->len++] = np->id; + + if (strcmp(obj, np->name) == 0) { + fprintf(fp, "#define OID_%s\t%u\n", np->name, np->id); + fprintf(fp, "#define OIDLEN_%s\t%u\n", np->name, oid->len); + fprintf(fp, "#define OIDX_%s\t{ %u, {", np->name, oid->len); + for (n = 0; n < oid->len; n++) + fprintf(fp, " %u,", oid->subs[n]); + fprintf(fp, " } }\n"); + return (0); + } + + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + if (!extract(sub, oid, obj)) + return (0); + } else if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + if (!extract(sub, oid, obj)) + return (0); + } + oid->len--; + return (1); +} + +static int +gen_extract(const struct node *root, const char *object) +{ + struct asn_oid oid; + + oid.len = PREFIX_LEN; + memcpy(oid.subs, prefix, sizeof(prefix)); + return (extract(root, &oid, object)); +} + + +static void +check_sub_order(const struct node *np, const struct node_list *subs) +{ + int first; + const struct node *sub; + asn_subid_t maxid = 0; + + /* ensure, that subids are ordered */ + first = 1; + TAILQ_FOREACH(sub, subs, link) { + if (!first && sub->id <= maxid) + report_node(np, "subids not ordered at %s", sub->name); + maxid = sub->id; + first = 0; + } +} + +/* + * Do some sanity checks on the tree definition and do some computations. + */ +static void +check_tree(struct node *np) +{ + struct node *sub; + + if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { + if ((np->flags & (FL_GET|FL_SET)) != 0) + tree_size++; + return; + } + + if (np->type == NODE_ENTRY) { + check_sub_order(np, &np->u.entry.subs); + + /* ensure all subnodes are columns */ + TAILQ_FOREACH(sub, &np->u.entry.subs, link) { + if (sub->type != NODE_COLUMN) + report_node(np, "entry subnode '%s' is not " + "a column", sub->name); + check_tree(sub); + } + } else { + check_sub_order(np, &np->u.tree.subs); + + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + check_tree(sub); + } +} + +int +main(int argc, char *argv[]) +{ + int do_extract = 0; + int opt; + struct node *root; + char fname[MAXPATHLEN + 1]; + + while ((opt = getopt(argc, argv, "help:")) != EOF) + switch (opt) { + + case 'h': + fprintf(stderr, "%s", usgtxt); + exit(0); + + case 'e': + do_extract = 1; + break; + + case 'l': + localincs = 1; + break; + + case 'p': + file_prefix = optarg; + if (strlen(file_prefix) + strlen("tree.c") > + MAXPATHLEN) + errx(1, "prefix too long"); + break; + } + + if (!do_extract && argc != optind) + errx(1, "no arguments allowed"); + if (do_extract && argc == optind) + errx(1, "no objects specified"); + + root = parse(gettoken()); + if (gettoken() != TOK_EOF) + report("junk after closing ')'"); + + check_tree(root); + + if (do_extract) { + fp = stdout; + while (optind < argc) { + if (gen_extract(root, argv[optind])) + errx(1, "object not found: %s", argv[optind]); + optind++; + } + + return (0); + } + sprintf(fname, "%stree.h", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_header(root, PREFIX_LEN, NULL); + + fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); + fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); + + fclose(fp); + + sprintf(fname, "%stree.c", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_table(root); + fclose(fp); + + return (0); +} |