gensnmptree.c revision 154182
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 *
33150920Sharti * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.43 2005/10/04 11:21:29 brandt_h 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 *
53142810Sharti * element := tree | leaf | column
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>
66133429Sharti#include <inttypes.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)
166145557Sharti		err(1, "allocing %zu 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;
356154182Sharti	node->flags = 0;
357122394Sharti
358122394Sharti	if (tok != '(')
359122394Sharti		report("'(' expected at begin of node");
360122394Sharti	if (gettoken() != TOK_NUM)
361122394Sharti		report("node id expected after opening '('");
362122394Sharti	if (val > ASN_MAXID)
363122394Sharti		report("subid too large '%lu'", val);
364122394Sharti	node->id = (asn_subid_t)val;
365122394Sharti	if (gettoken() != TOK_STR)
366122394Sharti		report("node name expected after '(' ID");
367122394Sharti	node->name = savetok();
368122394Sharti
369122394Sharti	if ((tok = gettoken()) == TOK_TYPE) {
370122394Sharti		/* LEAF or COLUM */
371122394Sharti		u_int syntax = val;
372122394Sharti
373122394Sharti		if ((tok = gettoken()) == TOK_STR) {
374122394Sharti			/* LEAF */
375122394Sharti			node->type = NODE_LEAF;
376122394Sharti			node->u.leaf.func = savetok();
377122394Sharti			node->u.leaf.syntax = syntax;
378122394Sharti			tok = gettoken();
379122394Sharti		} else {
380122394Sharti			/* COLUMN */
381122394Sharti			node->type = NODE_COLUMN;
382122394Sharti			node->u.column.syntax = syntax;
383122394Sharti		}
384122394Sharti
385122394Sharti		while (tok != ')') {
386122394Sharti			if (tok != TOK_ACCESS)
387122394Sharti				report("access keyword or ')' expected");
388122394Sharti			node->flags |= (u_int)val;
389122394Sharti			tok = gettoken();
390122394Sharti		}
391122394Sharti
392122394Sharti	} else if (tok == ':') {
393122394Sharti		/* ENTRY */
394122394Sharti		node->type = NODE_ENTRY;
395122394Sharti		TAILQ_INIT(&node->u.entry.subs);
396122394Sharti
397122394Sharti		index_count = 0;
398122394Sharti		node->u.entry.index = 0;
399122394Sharti		while ((tok = gettoken()) == TOK_TYPE) {
400122394Sharti			if (index_count++ == SNMP_INDEXES_MAX)
401122394Sharti				report("too many table indexes");
402122394Sharti			node->u.entry.index |=
403122394Sharti			    val << (SNMP_INDEX_SHIFT * index_count);
404122394Sharti		}
405122394Sharti		node->u.entry.index |= index_count;
406122394Sharti		if (index_count == 0)
407122394Sharti			report("need at least one index");
408122394Sharti
409122394Sharti		if (tok != TOK_STR)
410122394Sharti			report("function name expected");
411122394Sharti
412122394Sharti		node->u.entry.func = savetok();
413122394Sharti
414122394Sharti		tok = gettoken();
415122394Sharti
416122394Sharti		while (tok != ')') {
417122394Sharti			sub = parse(tok);
418122394Sharti			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
419122394Sharti			tok = gettoken();
420122394Sharti		}
421122394Sharti
422122394Sharti	} else {
423122394Sharti		/* subtree */
424122394Sharti		node->type = NODE_TREE;
425122394Sharti		TAILQ_INIT(&node->u.tree.subs);
426122394Sharti
427122394Sharti		while (tok != ')') {
428122394Sharti			sub = parse(tok);
429122394Sharti			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
430122394Sharti			tok = gettoken();
431122394Sharti		}
432122394Sharti	}
433122394Sharti	return (node);
434122394Sharti}
435122394Sharti
436122394Sharti/*
437122394Sharti * Generate the C-code table part for one node.
438122394Sharti */
439122394Shartistatic void
440122394Shartigen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func)
441122394Sharti{
442122394Sharti	u_int n;
443122394Sharti	struct node *sub;
444122394Sharti	u_int syntax;
445122394Sharti
446122394Sharti	if (oid->len == ASN_MAXOIDLEN)
447122394Sharti		report_node(np, "OID too long");
448122394Sharti	oid->subs[oid->len++] = np->id;
449122394Sharti
450122394Sharti	if (np->type == NODE_TREE) {
451122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
452122394Sharti			gen_node(sub, oid, 0, NULL);
453122394Sharti		oid->len--;
454122394Sharti		return;
455122394Sharti	}
456122394Sharti	if (np->type == NODE_ENTRY) {
457122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
458122394Sharti			gen_node(sub, oid, np->u.entry.index, np->u.entry.func);
459122394Sharti		oid->len--;
460122394Sharti		return;
461122394Sharti	}
462122394Sharti
463122394Sharti	/* leaf or column */
464122394Sharti	if ((np->flags & (FL_GET|FL_SET)) == 0) {
465122394Sharti		oid->len--;
466122394Sharti		return;
467122394Sharti	}
468122394Sharti
469122394Sharti	fprintf(fp, "    {{ %u, {", oid->len);
470122394Sharti	for (n = 0; n < oid->len; n++)
471122394Sharti		fprintf(fp, " %u,", oid->subs[n]);
472122394Sharti	fprintf(fp, " }}, \"%s\", ", np->name);
473122394Sharti
474122394Sharti	if (np->type == NODE_COLUMN) {
475122394Sharti		syntax = np->u.column.syntax;
476122394Sharti		fprintf(fp, "SNMP_NODE_COLUMN, ");
477122394Sharti	} else {
478122394Sharti		syntax = np->u.leaf.syntax;
479122394Sharti		fprintf(fp, "SNMP_NODE_LEAF, ");
480122394Sharti	}
481122394Sharti
482122394Sharti	switch (syntax) {
483122394Sharti
484122394Sharti	  case SNMP_SYNTAX_NULL:
485122394Sharti		fprintf(fp, "SNMP_SYNTAX_NULL, ");
486122394Sharti		break;
487122394Sharti
488122394Sharti	  case SNMP_SYNTAX_INTEGER:
489122394Sharti		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
490122394Sharti		break;
491122394Sharti
492122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
493122394Sharti		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
494122394Sharti		break;
495122394Sharti
496122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
497122394Sharti		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
498122394Sharti		break;
499122394Sharti
500122394Sharti	  case SNMP_SYNTAX_OID:
501122394Sharti		fprintf(fp, "SNMP_SYNTAX_OID, ");
502122394Sharti		break;
503122394Sharti
504122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
505122394Sharti		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
506122394Sharti		break;
507122394Sharti
508122394Sharti	  case SNMP_SYNTAX_COUNTER:
509122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
510122394Sharti		break;
511122394Sharti
512122394Sharti	  case SNMP_SYNTAX_GAUGE:
513122394Sharti		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
514122394Sharti		break;
515122394Sharti
516122394Sharti	  case SNMP_SYNTAX_COUNTER64:
517122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
518122394Sharti		break;
519122394Sharti
520122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
521122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
522122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
523122394Sharti		abort();
524122394Sharti	}
525122394Sharti
526122394Sharti	if (np->type == NODE_COLUMN)
527122394Sharti		fprintf(fp, "%s, ", func);
528122394Sharti	else
529122394Sharti		fprintf(fp, "%s, ", np->u.leaf.func);
530122394Sharti
531122394Sharti	fprintf(fp, "0");
532122394Sharti	if (np->flags & FL_SET)
533122394Sharti		fprintf(fp, "|SNMP_NODE_CANSET");
534128237Sharti	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
535122394Sharti	oid->len--;
536122394Sharti	return;
537122394Sharti}
538122394Sharti
539122394Sharti/*
540122394Sharti * Generate the header file with the function declarations.
541122394Sharti */
542122394Shartistatic void
543122394Shartigen_header(struct node *np, u_int oidlen, const char *func)
544122394Sharti{
545122394Sharti	char f[MAXSTR + 4];
546122394Sharti	struct node *sub;
547122394Sharti	struct func *ptr;
548122394Sharti
549122394Sharti	oidlen++;
550122394Sharti	if (np->type == NODE_TREE) {
551122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
552122394Sharti			gen_header(sub, oidlen, NULL);
553122394Sharti		return;
554122394Sharti	}
555122394Sharti	if (np->type == NODE_ENTRY) {
556122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
557122394Sharti			gen_header(sub, oidlen, np->u.entry.func);
558122394Sharti		return;
559122394Sharti	}
560122394Sharti
561122394Sharti 	if((np->flags & (FL_GET|FL_SET)) == 0)
562122394Sharti		return;
563122394Sharti
564142810Sharti	if (np->type == NODE_COLUMN) {
565142810Sharti		if (func == NULL)
566142810Sharti			errx(1, "column without function (%s) - probably "
567142810Sharti			    "outside of a table", np->name);
568122394Sharti		sprintf(f, "%s", func);
569142810Sharti	} else
570122394Sharti		sprintf(f, "%s", np->u.leaf.func);
571122394Sharti
572122394Sharti	LIST_FOREACH(ptr, &funcs, link)
573122394Sharti		if (strcmp(ptr->name, f) == 0)
574122394Sharti			break;
575122394Sharti
576122394Sharti	if (ptr == NULL) {
577122394Sharti		ptr = xalloc(sizeof(*ptr));
578122394Sharti		ptr->name = strcpy(xalloc(strlen(f)+1), f);
579122394Sharti		LIST_INSERT_HEAD(&funcs, ptr, link);
580122394Sharti
581122394Sharti		fprintf(fp, "int	%s(struct snmp_context *, "
582122394Sharti		    "struct snmp_value *, u_int, u_int, "
583122394Sharti		    "enum snmp_op);\n", f);
584122394Sharti	}
585122394Sharti
586122394Sharti	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
587122394Sharti}
588122394Sharti
589122394Sharti/*
590122394Sharti * Generate the OID table.
591122394Sharti */
592122394Shartistatic void
593122394Shartigen_table(struct node *node)
594122394Sharti{
595122394Sharti	struct asn_oid oid;
596122394Sharti
597122394Sharti	fprintf(fp, "#include <sys/types.h>\n");
598122394Sharti	fprintf(fp, "#include <stdio.h>\n");
599150920Sharti#ifdef HAVE_STDINT_H
600133211Sharti	fprintf(fp, "#include <stdint.h>\n");
601150920Sharti#endif
602122394Sharti	if (localincs) {
603122394Sharti		fprintf(fp, "#include \"asn1.h\"\n");
604122394Sharti		fprintf(fp, "#include \"snmp.h\"\n");
605122394Sharti		fprintf(fp, "#include \"snmpagent.h\"\n");
606122394Sharti	} else {
607122394Sharti		fprintf(fp, "#include <bsnmp/asn1.h>\n");
608122394Sharti		fprintf(fp, "#include <bsnmp/snmp.h>\n");
609122394Sharti		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
610122394Sharti	}
611122394Sharti	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
612122394Sharti	fprintf(fp, "\n");
613122394Sharti
614122394Sharti	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
615122394Sharti
616122394Sharti	oid.len = PREFIX_LEN;
617122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
618122394Sharti	gen_node(node, &oid, 0, NULL);
619122394Sharti
620122394Sharti	fprintf(fp, "};\n\n");
621122394Sharti}
622122394Sharti
623133211Shartistatic void
624133211Shartiprint_syntax(u_int syntax)
625133211Sharti{
626133211Sharti	u_int i;
627133211Sharti
628133211Sharti	for (i = 0; keywords[i].str != NULL; i++)
629133211Sharti		if (keywords[i].tok == TOK_TYPE &&
630133211Sharti		    keywords[i].val == syntax) {
631133211Sharti			printf(" %s", keywords[i].str);
632133211Sharti			return;
633133211Sharti	}
634133211Sharti	abort();
635133211Sharti}
636133211Sharti
637133211Sharti/*
638133211Sharti * Generate a tree definition file
639133211Sharti */
640133211Shartistatic void
641133211Shartigen_tree(const struct node *np, int level)
642133211Sharti{
643133211Sharti	const struct node *sp;
644133211Sharti	u_int i;
645133211Sharti
646133211Sharti	printf("%*s(%u %s", 2 * level, "", np->id, np->name);
647133211Sharti
648133211Sharti	switch (np->type) {
649133211Sharti
650133211Sharti	  case NODE_LEAF:
651133211Sharti		print_syntax(np->u.leaf.syntax);
652133211Sharti		printf(" %s%s%s)\n", np->u.leaf.func,
653133211Sharti		    (np->flags & FL_GET) ? " GET" : "",
654133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
655133211Sharti		break;
656133211Sharti
657133211Sharti	  case NODE_TREE:
658133211Sharti		if (TAILQ_EMPTY(&np->u.tree.subs)) {
659133211Sharti			printf(")\n");
660133211Sharti		} else {
661133211Sharti			printf("\n");
662133211Sharti			TAILQ_FOREACH(sp, &np->u.tree.subs, link)
663133211Sharti				gen_tree(sp, level + 1);
664133211Sharti			printf("%*s)\n", 2 * level, "");
665133211Sharti		}
666133211Sharti		break;
667133211Sharti
668133211Sharti	  case NODE_ENTRY:
669133211Sharti		printf(" :");
670133211Sharti
671133211Sharti		for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++)
672133211Sharti			print_syntax(SNMP_INDEX(np->u.entry.index, i));
673133211Sharti		printf(" %s\n", np->u.entry.func);
674133211Sharti		TAILQ_FOREACH(sp, &np->u.entry.subs, link)
675133211Sharti			gen_tree(sp, level + 1);
676133211Sharti		printf("%*s)\n", 2 * level, "");
677133211Sharti		break;
678133211Sharti
679133211Sharti	  case NODE_COLUMN:
680133211Sharti		print_syntax(np->u.column.syntax);
681133211Sharti		printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
682133211Sharti		    (np->flags & FL_SET) ? " SET" : "");
683133211Sharti		break;
684133211Sharti
685133211Sharti	}
686133211Sharti}
687133211Sharti
688122394Shartistatic int
689133211Shartiextract(const struct node *np, struct asn_oid *oid, const char *obj,
690133211Sharti    const struct asn_oid *idx, const char *iname)
691122394Sharti{
692122394Sharti	struct node *sub;
693122394Sharti	u_long n;
694122394Sharti
695122394Sharti	if (oid->len == ASN_MAXOIDLEN)
696122394Sharti		report_node(np, "OID too long");
697122394Sharti	oid->subs[oid->len++] = np->id;
698122394Sharti
699122394Sharti	if (strcmp(obj, np->name) == 0) {
700133211Sharti		if (oid->len + idx->len >= ASN_MAXOIDLEN)
701133211Sharti			report_node(np, "OID too long");
702133211Sharti		fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
703133211Sharti		    iname ? iname : "", np->id);
704133211Sharti		fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
705133211Sharti		    iname ? iname : "", oid->len + idx->len);
706133211Sharti		fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
707133211Sharti		    iname ? iname : "", oid->len + idx->len);
708122394Sharti		for (n = 0; n < oid->len; n++)
709122394Sharti			fprintf(fp, " %u,", oid->subs[n]);
710133211Sharti		for (n = 0; n < idx->len; n++)
711133211Sharti			fprintf(fp, " %u,", idx->subs[n]);
712122394Sharti		fprintf(fp, " } }\n");
713122394Sharti		return (0);
714122394Sharti	}
715122394Sharti
716122394Sharti	if (np->type == NODE_TREE) {
717122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
718133211Sharti			if (!extract(sub, oid, obj, idx, iname))
719122394Sharti				return (0);
720122394Sharti	} else if (np->type == NODE_ENTRY) {
721122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
722133211Sharti			if (!extract(sub, oid, obj, idx, iname))
723122394Sharti				return (0);
724122394Sharti	}
725122394Sharti	oid->len--;
726122394Sharti	return (1);
727122394Sharti}
728122394Sharti
729122394Shartistatic int
730133211Shartigen_extract(const struct node *root, char *object)
731122394Sharti{
732122394Sharti	struct asn_oid oid;
733133211Sharti	struct asn_oid idx;
734133211Sharti	char *s, *e, *end, *iname;
735133211Sharti	u_long ul;
736133211Sharti	int ret;
737122394Sharti
738133211Sharti	/* look whether the object to extract has an index part */
739133211Sharti	idx.len = 0;
740133211Sharti	iname = NULL;
741133211Sharti	s = strchr(object, '.');
742133211Sharti	if (s != NULL) {
743133211Sharti		iname = malloc(strlen(s) + 1);
744133211Sharti		if (iname == NULL)
745133211Sharti			err(1, "cannot allocated index");
746133211Sharti
747133211Sharti		strcpy(iname, s);
748133211Sharti		for (e = iname; *e != '\0'; e++)
749133211Sharti			if (*e == '.')
750133211Sharti				*e = '_';
751133211Sharti
752133211Sharti		*s++ = '\0';
753133211Sharti		while (s != NULL) {
754133211Sharti			if (*s == '\0')
755133211Sharti				errx(1, "bad index syntax");
756133211Sharti			if ((e = strchr(s, '.')) != NULL)
757133211Sharti				*e++ = '\0';
758133211Sharti
759133211Sharti			errno = 0;
760133211Sharti			ul = strtoul(s, &end, 0);
761133211Sharti			if (*end != '\0')
762133211Sharti				errx(1, "bad index syntax '%s'", end);
763133211Sharti			if (errno != 0)
764133211Sharti				err(1, "bad index syntax");
765133211Sharti
766133211Sharti			if (idx.len == ASN_MAXOIDLEN)
767133211Sharti				errx(1, "index oid too large");
768133211Sharti			idx.subs[idx.len++] = ul;
769133211Sharti
770133211Sharti			s = e;
771133211Sharti		}
772133211Sharti	}
773133211Sharti
774122394Sharti	oid.len = PREFIX_LEN;
775122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
776133211Sharti	ret = extract(root, &oid, object, &idx, iname);
777133211Sharti	if (iname != NULL)
778133211Sharti		free(iname);
779133211Sharti
780133211Sharti	return (ret);
781122394Sharti}
782122394Sharti
783122394Sharti
784122394Shartistatic void
785122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs)
786122394Sharti{
787122394Sharti	int first;
788122394Sharti	const struct node *sub;
789122394Sharti	asn_subid_t maxid = 0;
790122394Sharti
791122394Sharti	/* ensure, that subids are ordered */
792122394Sharti	first = 1;
793122394Sharti	TAILQ_FOREACH(sub, subs, link) {
794122394Sharti		if (!first && sub->id <= maxid)
795122394Sharti			report_node(np, "subids not ordered at %s", sub->name);
796122394Sharti		maxid = sub->id;
797122394Sharti		first = 0;
798122394Sharti	}
799122394Sharti}
800122394Sharti
801122394Sharti/*
802122394Sharti * Do some sanity checks on the tree definition and do some computations.
803122394Sharti */
804122394Shartistatic void
805122394Sharticheck_tree(struct node *np)
806122394Sharti{
807122394Sharti	struct node *sub;
808122394Sharti
809122394Sharti	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
810122394Sharti		if ((np->flags & (FL_GET|FL_SET)) != 0)
811122394Sharti			tree_size++;
812122394Sharti		return;
813122394Sharti	}
814122394Sharti
815122394Sharti	if (np->type == NODE_ENTRY) {
816122394Sharti		check_sub_order(np, &np->u.entry.subs);
817122394Sharti
818122394Sharti		/* ensure all subnodes are columns */
819122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
820122394Sharti			if (sub->type != NODE_COLUMN)
821122394Sharti				report_node(np, "entry subnode '%s' is not "
822122394Sharti				    "a column", sub->name);
823122394Sharti			check_tree(sub);
824122394Sharti		}
825122394Sharti	} else {
826122394Sharti		check_sub_order(np, &np->u.tree.subs);
827122394Sharti
828122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
829122394Sharti			check_tree(sub);
830122394Sharti	}
831122394Sharti}
832122394Sharti
833133211Shartistatic void
834133211Shartimerge_subs(struct node_list *s1, struct node_list *s2)
835133211Sharti{
836133211Sharti	struct node *n1, *n2;
837133211Sharti
838133211Sharti	while (!TAILQ_EMPTY(s2)) {
839133211Sharti		n2 = TAILQ_FIRST(s2);
840133211Sharti		TAILQ_REMOVE(s2, n2, link);
841133211Sharti
842133211Sharti		TAILQ_FOREACH(n1, s1, link)
843133211Sharti			if (n1->id >= n2->id)
844133211Sharti				break;
845133211Sharti		if (n1 == NULL)
846133211Sharti			TAILQ_INSERT_TAIL(s1, n2, link);
847133211Sharti		else if (n1->id > n2->id)
848133211Sharti			TAILQ_INSERT_BEFORE(n1, n2, link);
849133211Sharti		else {
850133211Sharti			if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
851133211Sharti				if (strcmp(n1->name, n2->name) != 0)
852133211Sharti					errx(1, "trees to merge must have "
853133211Sharti					    "same name '%s' '%s'", n1->name,
854133211Sharti					    n2->name);
855133211Sharti				merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
856133211Sharti				free(n2);
857133211Sharti			} else if (n1->type == NODE_ENTRY &&
858133211Sharti			    n2->type == NODE_ENTRY) {
859133211Sharti				if (strcmp(n1->name, n2->name) != 0)
860133211Sharti					errx(1, "entries to merge must have "
861133211Sharti					    "same name '%s' '%s'", n1->name,
862133211Sharti					    n2->name);
863133211Sharti				if (n1->u.entry.index != n2->u.entry.index)
864133211Sharti					errx(1, "entries to merge must have "
865133211Sharti					    "same index '%s'", n1->name);
866133211Sharti				if (strcmp(n1->u.entry.func,
867133211Sharti				    n2->u.entry.func) != 0)
868133211Sharti					errx(1, "entries to merge must have "
869133211Sharti					    "same op '%s'", n1->name);
870133211Sharti				merge_subs(&n1->u.entry.subs,
871133211Sharti				    &n2->u.entry.subs);
872133211Sharti				free(n2);
873133211Sharti			} else
874133211Sharti				errx(1, "entities to merge must be both "
875133211Sharti				    "trees or both entries: %s, %s",
876133211Sharti				    n1->name, n2->name);
877133211Sharti		}
878133211Sharti	}
879133211Sharti}
880133211Sharti
881133211Shartistatic void
882133211Shartimerge(struct node *root, struct node *t)
883133211Sharti{
884133211Sharti
885133211Sharti	/* both must be trees */
886133211Sharti	if (root->type != NODE_TREE)
887133211Sharti		errx(1, "root is not a tree");
888133211Sharti	if (t->type != NODE_TREE)
889133211Sharti		errx(1, "can merge only with tree");
890133211Sharti	if (root->id != t->id)
891133211Sharti		errx(1, "trees to merge must have same id");
892133211Sharti
893133211Sharti	merge_subs(&root->u.tree.subs, &t->u.tree.subs);
894133211Sharti}
895133211Sharti
896122394Shartiint
897122394Shartimain(int argc, char *argv[])
898122394Sharti{
899122394Sharti	int do_extract = 0;
900133211Sharti	int do_tree = 0;
901122394Sharti	int opt;
902122394Sharti	struct node *root;
903122394Sharti	char fname[MAXPATHLEN + 1];
904133211Sharti	int tok;
905122394Sharti
906133211Sharti	while ((opt = getopt(argc, argv, "help:t")) != EOF)
907122394Sharti		switch (opt) {
908122394Sharti
909122394Sharti		  case 'h':
910122394Sharti			fprintf(stderr, "%s", usgtxt);
911122394Sharti			exit(0);
912122394Sharti
913122394Sharti		  case 'e':
914122394Sharti			do_extract = 1;
915122394Sharti			break;
916122394Sharti
917122394Sharti		  case 'l':
918122394Sharti			localincs = 1;
919122394Sharti			break;
920122394Sharti
921122394Sharti		  case 'p':
922122394Sharti			file_prefix = optarg;
923122394Sharti			if (strlen(file_prefix) + strlen("tree.c") >
924122394Sharti			    MAXPATHLEN)
925122394Sharti				errx(1, "prefix too long");
926122394Sharti			break;
927133211Sharti
928133211Sharti		  case 't':
929133211Sharti			do_tree = 1;
930133211Sharti			break;
931122394Sharti		}
932122394Sharti
933133211Sharti	if (do_extract && do_tree)
934133211Sharti		errx(1, "conflicting options -e and -t");
935122394Sharti	if (!do_extract && argc != optind)
936122394Sharti		errx(1, "no arguments allowed");
937122394Sharti	if (do_extract && argc == optind)
938122394Sharti		errx(1, "no objects specified");
939122394Sharti
940122394Sharti	root = parse(gettoken());
941133211Sharti	while ((tok = gettoken()) != TOK_EOF)
942133211Sharti		merge(root, parse(tok));
943122394Sharti
944122394Sharti	check_tree(root);
945122394Sharti
946122394Sharti	if (do_extract) {
947122394Sharti		fp = stdout;
948122394Sharti		while (optind < argc) {
949122394Sharti			if (gen_extract(root, argv[optind]))
950122394Sharti				errx(1, "object not found: %s", argv[optind]);
951122394Sharti			optind++;
952122394Sharti		}
953122394Sharti
954122394Sharti		return (0);
955122394Sharti	}
956133211Sharti	if (do_tree) {
957133211Sharti		gen_tree(root, 0);
958133211Sharti		return (0);
959133211Sharti	}
960122394Sharti	sprintf(fname, "%stree.h", file_prefix);
961122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
962122394Sharti		err(1, "%s: ", fname);
963122394Sharti	gen_header(root, PREFIX_LEN, NULL);
964122394Sharti
965122394Sharti	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
966122394Sharti	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
967122394Sharti
968122394Sharti	fclose(fp);
969122394Sharti
970122394Sharti	sprintf(fname, "%stree.c", file_prefix);
971122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
972122394Sharti		err(1, "%s: ", fname);
973122394Sharti	gen_table(root);
974122394Sharti	fclose(fp);
975122394Sharti
976122394Sharti	return (0);
977122394Sharti}
978