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