gensnmptree.c revision 128237
1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7122394Sharti *
8122394Sharti * Redistribution of this software and documentation and use in source and
9122394Sharti * binary forms, with or without modification, are permitted provided that
10122394Sharti * the following conditions are met:
11122394Sharti *
12122394Sharti * 1. Redistributions of source code or documentation must retain the above
13122394Sharti *    copyright notice, this list of conditions and the following disclaimer.
14122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
15122394Sharti *    notice, this list of conditions and the following disclaimer in the
16122394Sharti *    documentation and/or other materials provided with the distribution.
17122394Sharti * 3. Neither the name of the Institute nor the names of its contributors
18122394Sharti *    may be used to endorse or promote products derived from this software
19122394Sharti *    without specific prior written permission.
20122394Sharti *
21122394Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22122394Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23122394Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24122394Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25122394Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26122394Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27122394Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28122394Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29122394Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30122394Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31122394Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32122394Sharti *
33128237Sharti * $Begemot: bsnmp/gensnmptree/gensnmptree.c,v 1.37 2004/04/13 15:18:15 novo Exp $
34122394Sharti *
35122394Sharti * Generate OID table from table description.
36122394Sharti *
37122394Sharti * Syntax is:
38122394Sharti * ---------
39122394Sharti * tree := head elements ')'
40122394Sharti *
41122394Sharti * entry := head ':' index STRING elements ')'
42122394Sharti *
43122394Sharti * leaf := head TYPE STRING ACCESS ')'
44122394Sharti *
45122394Sharti * column := head TYPE ACCESS ')'
46122394Sharti *
47122394Sharti * head := '(' INT STRING
48122394Sharti *
49122394Sharti * elements := EMPTY | elements element
50122394Sharti *
51122394Sharti * element := tree | leaf
52122394Sharti *
53122394Sharti * index := TYPE | index TYPE
54122394Sharti *
55122394Sharti */
56122394Sharti#include <sys/types.h>
57122394Sharti#include <sys/param.h>
58122394Sharti#include <stdio.h>
59122394Sharti#include <stdlib.h>
60122394Sharti#include <stdarg.h>
61122394Sharti#include <unistd.h>
62122394Sharti#include <string.h>
63122394Sharti#include <ctype.h>
64122394Sharti#include <err.h>
65122394Sharti#include <sys/queue.h>
66122394Sharti#include "asn1.h"
67122394Sharti#include "snmp.h"
68122394Sharti#include "snmpagent.h"
69122394Sharti
70122394Sharti/*
71122394Sharti * Constant prefix for all OIDs
72122394Sharti */
73122394Shartistatic const asn_subid_t prefix[] = { 1, 3, 6 };
74122394Sharti#define	PREFIX_LEN	(sizeof(prefix) / sizeof(prefix[0]))
75122394Sharti
76122394Shartiu_int tree_size;
77122394Shartistatic const char *file_prefix = "";
78122394Shartistatic FILE *fp;
79122394Sharti
80122394Sharti/* if true generate local include paths */
81122394Shartistatic int localincs = 0;
82122394Sharti
83122394Shartistatic const char usgtxt[] = "\
84122394ShartiGenerate SNMP tables. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
85122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\
86122394Shartiusage: gensnmptree [-hel] [-p prefix] [name]...\n\
87122394Shartioptions:\n\
88122394Sharti  -h		print this info\n\
89122394Sharti  -e		extrace the named oids\n\
90122394Sharti  -l		generate local include directives\n\
91122394Sharti  -p prefix	prepend prefix to file and variable names\n\
92122394Sharti";
93122394Sharti
94122394Sharti/*
95122394Sharti * A node in the OID tree
96122394Sharti */
97122394Shartienum ntype {
98122394Sharti	NODE_LEAF = 1,
99122394Sharti	NODE_TREE,
100122394Sharti	NODE_ENTRY,
101122394Sharti	NODE_COLUMN
102122394Sharti};
103122394Sharti
104122394Shartienum {
105122394Sharti	FL_GET	= 0x01,
106122394Sharti	FL_SET	= 0x02,
107122394Sharti};
108122394Sharti
109122394Shartistruct node;
110122394ShartiTAILQ_HEAD(node_list, node);
111122394Sharti
112122394Shartistruct node {
113122394Sharti	enum ntype	type;
114122394Sharti	asn_subid_t	id;	/* last element of OID */
115122394Sharti	char		*name;	/* name of node */
116122394Sharti	TAILQ_ENTRY(node) link;
117122394Sharti	u_int		lno;	/* starting line number */
118122394Sharti	u_int		flags;	/* allowed operations */
119122394Sharti
120122394Sharti	union {
121122394Sharti	  struct tree {
122122394Sharti	    struct node_list subs;
123122394Sharti	  }		tree;
124122394Sharti
125122394Sharti	  struct entry {
126122394Sharti	    u_int32_t	index;	/* index for table entry */
127122394Sharti	    char	*func;	/* function for tables */
128122394Sharti	    struct node_list subs;
129122394Sharti	  }		entry;
130122394Sharti
131122394Sharti	  struct leaf {
132122394Sharti	    enum snmp_syntax syntax;	/* syntax for this leaf */
133122394Sharti	    char	*func;		/* function name */
134122394Sharti	  }		leaf;
135122394Sharti
136122394Sharti	  struct column {
137122394Sharti	    enum snmp_syntax syntax;	/* syntax for this column */
138122394Sharti	  }		column;
139122394Sharti	}		u;
140122394Sharti};
141122394Sharti
142122394Shartistruct func {
143122394Sharti	const char	*name;
144122394Sharti	LIST_ENTRY(func) link;
145122394Sharti};
146122394Sharti
147122394Shartistatic LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
148122394Sharti
149122394Sharti/************************************************************
150122394Sharti *
151122394Sharti * Allocate memory and panic just in the case...
152122394Sharti */
153122394Shartistatic void *
154122394Shartixalloc(size_t size)
155122394Sharti{
156122394Sharti	void *ptr;
157122394Sharti
158122394Sharti	if ((ptr = malloc(size)) == NULL)
159122394Sharti		err(1, "allocing %u bytes", size);
160122394Sharti
161122394Sharti	return (ptr);
162122394Sharti}
163122394Sharti
164122394Sharti/************************************************************
165122394Sharti *
166122394Sharti * Parsing input
167122394Sharti */
168122394Shartienum tok {
169122394Sharti	TOK_EOF = 0200,	/* end-of-file seen */
170122394Sharti	TOK_NUM,	/* number */
171122394Sharti	TOK_STR,	/* string */
172122394Sharti	TOK_ACCESS,	/* access operator */
173122394Sharti	TOK_TYPE,	/* type operator */
174122394Sharti};
175122394Sharti
176122394Shartistatic const struct {
177122394Sharti	const char *str;
178122394Sharti	enum tok tok;
179122394Sharti	u_int val;
180122394Sharti} keywords[] = {
181122394Sharti	{ "GET", TOK_ACCESS, FL_GET },
182122394Sharti	{ "SET", TOK_ACCESS, FL_SET },
183122394Sharti	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
184122394Sharti	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
185122394Sharti	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
186122394Sharti	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
187122394Sharti	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
188122394Sharti	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
189122394Sharti	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
190122394Sharti	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
191122394Sharti	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
192122394Sharti	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
193122394Sharti	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
194122394Sharti	{ NULL, 0, 0 }
195122394Sharti};
196122394Sharti
197122394Sharti/* arbitrary upper limit on node names and function names */
198122394Sharti#define	MAXSTR	1000
199122394Shartichar	str[MAXSTR];
200122394Shartiu_long	val;		/* integer values */
201122394Shartiu_int 	lno = 1;	/* current line number */
202122394Sharti
203122394Shartistatic void report(const char *, ...) __dead2 __printflike(1, 2);
204122394Shartistatic void report_node(const struct node *, const char *, ...)
205122394Sharti    __dead2 __printflike(2, 3);
206122394Sharti
207122394Sharti/*
208122394Sharti * Report an error and exit.
209122394Sharti */
210122394Shartistatic void
211122394Shartireport(const char *fmt, ...)
212122394Sharti{
213122394Sharti	va_list ap;
214122394Sharti	int c;
215122394Sharti
216122394Sharti	va_start(ap, fmt);
217122394Sharti	fprintf(stderr, "line %u: ", lno);
218122394Sharti	vfprintf(stderr, fmt, ap);
219122394Sharti	fprintf(stderr, "\n");
220122394Sharti	fprintf(stderr, "context: \"");
221122394Sharti	while ((c = getchar()) != EOF && c != '\n')
222122394Sharti		fprintf(stderr, "%c", c);
223122394Sharti	fprintf(stderr, "\n");
224122394Sharti	va_end(ap);
225122394Sharti	exit(1);
226122394Sharti}
227122394Shartistatic void
228122394Shartireport_node(const struct node *np, const char *fmt, ...)
229122394Sharti{
230122394Sharti	va_list ap;
231122394Sharti
232122394Sharti	va_start(ap, fmt);
233122394Sharti	fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
234122394Sharti	vfprintf(stderr, fmt, ap);
235122394Sharti	fprintf(stderr, "\n");
236122394Sharti	va_end(ap);
237122394Sharti	exit(1);
238122394Sharti}
239122394Sharti
240122394Sharti/*
241122394Sharti * Return a fresh copy of the string constituting the current token.
242122394Sharti */
243122394Shartistatic char *
244122394Shartisavetok(void)
245122394Sharti{
246122394Sharti	return (strcpy(xalloc(strlen(str)+1), str));
247122394Sharti}
248122394Sharti
249122394Sharti/*
250122394Sharti * Get the next token from input.
251122394Sharti */
252122394Shartistatic int
253122394Shartigettoken(void)
254122394Sharti{
255122394Sharti	int c;
256122394Sharti
257122394Sharti  again:
258122394Sharti	/*
259122394Sharti	 * Skip any whitespace before the next token
260122394Sharti	 */
261122394Sharti	while ((c = getchar()) != EOF) {
262122394Sharti		if (c == '\n')
263122394Sharti			lno++;
264122394Sharti		if (!isspace(c))
265122394Sharti			break;
266122394Sharti	}
267122394Sharti	if (c == EOF)
268122394Sharti		return (TOK_EOF);
269122394Sharti	if (!isascii(c))
270122394Sharti		report("unexpected character %#2x", (u_int)c);
271122394Sharti
272122394Sharti	/*
273122394Sharti	 * Skip comments
274122394Sharti	 */
275122394Sharti	if (c == '#') {
276122394Sharti		while ((c = getchar()) != EOF) {
277122394Sharti			if (c == '\n') {
278122394Sharti				lno++;
279122394Sharti				goto again;
280122394Sharti			}
281122394Sharti		}
282122394Sharti		report("unexpected EOF in comment");
283122394Sharti	}
284122394Sharti
285122394Sharti	/*
286122394Sharti	 * Single character tokens
287122394Sharti	 */
288122394Sharti	if (c == ')' || c == '(' || c == ':')
289122394Sharti		return (c);
290122394Sharti
291122394Sharti	/*
292122394Sharti	 * Sort out numbers
293122394Sharti	 */
294122394Sharti	if (isdigit(c)) {
295122394Sharti		ungetc(c, stdin);
296122394Sharti		scanf("%lu", &val);
297122394Sharti		return (TOK_NUM);
298122394Sharti	}
299122394Sharti
300122394Sharti	/*
301122394Sharti	 * So that has to be a string.
302122394Sharti	 */
303122394Sharti	if (isalpha(c) || c == '_') {
304122394Sharti		size_t n = 0;
305122394Sharti		str[n++] = c;
306122394Sharti		while ((c = getchar()) != EOF) {
307122394Sharti			if (!isalnum(c) && c != '_') {
308122394Sharti				ungetc(c, stdin);
309122394Sharti				break;
310122394Sharti			}
311122394Sharti			if (n == sizeof(str) - 1) {
312122394Sharti				str[n++] = '\0';
313122394Sharti				report("string too long '%s...'", str);
314122394Sharti			}
315122394Sharti			str[n++] = c;
316122394Sharti		}
317122394Sharti		str[n++] = '\0';
318122394Sharti
319122394Sharti		/*
320122394Sharti		 * Keywords
321122394Sharti		 */
322122394Sharti		for (c = 0; keywords[c].str != NULL; c++)
323122394Sharti			if (strcmp(keywords[c].str, str) == 0) {
324122394Sharti				val = keywords[c].val;
325122394Sharti				return (keywords[c].tok);
326122394Sharti			}
327122394Sharti
328122394Sharti		return (TOK_STR);
329122394Sharti	}
330122394Sharti	if (isprint(c))
331122394Sharti		errx(1, "%u: unexpected character '%c'", lno, c);
332122394Sharti	else
333122394Sharti		errx(1, "%u: unexpected character 0x%02x", lno, (u_int)c);
334122394Sharti}
335122394Sharti
336122394Sharti/*
337122394Sharti * Parse the next node (complete with all subnodes)
338122394Sharti */
339122394Shartistatic struct node *
340122394Shartiparse(enum tok tok)
341122394Sharti{
342122394Sharti	struct node *node;
343122394Sharti	struct node *sub;
344122394Sharti	u_int index_count;
345122394Sharti
346122394Sharti	node = xalloc(sizeof(struct node));
347122394Sharti	node->lno = lno;
348122394Sharti
349122394Sharti	if (tok != '(')
350122394Sharti		report("'(' expected at begin of node");
351122394Sharti	if (gettoken() != TOK_NUM)
352122394Sharti		report("node id expected after opening '('");
353122394Sharti	if (val > ASN_MAXID)
354122394Sharti		report("subid too large '%lu'", val);
355122394Sharti	node->id = (asn_subid_t)val;
356122394Sharti	if (gettoken() != TOK_STR)
357122394Sharti		report("node name expected after '(' ID");
358122394Sharti	node->name = savetok();
359122394Sharti
360122394Sharti	if ((tok = gettoken()) == TOK_TYPE) {
361122394Sharti		/* LEAF or COLUM */
362122394Sharti		u_int syntax = val;
363122394Sharti
364122394Sharti		if ((tok = gettoken()) == TOK_STR) {
365122394Sharti			/* LEAF */
366122394Sharti			node->type = NODE_LEAF;
367122394Sharti			node->u.leaf.func = savetok();
368122394Sharti			node->u.leaf.syntax = syntax;
369122394Sharti			tok = gettoken();
370122394Sharti		} else {
371122394Sharti			/* COLUMN */
372122394Sharti			node->type = NODE_COLUMN;
373122394Sharti			node->u.column.syntax = syntax;
374122394Sharti		}
375122394Sharti
376122394Sharti		while (tok != ')') {
377122394Sharti			if (tok != TOK_ACCESS)
378122394Sharti				report("access keyword or ')' expected");
379122394Sharti			node->flags |= (u_int)val;
380122394Sharti			tok = gettoken();
381122394Sharti		}
382122394Sharti
383122394Sharti	} else if (tok == ':') {
384122394Sharti		/* ENTRY */
385122394Sharti		node->type = NODE_ENTRY;
386122394Sharti		TAILQ_INIT(&node->u.entry.subs);
387122394Sharti
388122394Sharti		index_count = 0;
389122394Sharti		node->u.entry.index = 0;
390122394Sharti		while ((tok = gettoken()) == TOK_TYPE) {
391122394Sharti			if (index_count++ == SNMP_INDEXES_MAX)
392122394Sharti				report("too many table indexes");
393122394Sharti			node->u.entry.index |=
394122394Sharti			    val << (SNMP_INDEX_SHIFT * index_count);
395122394Sharti		}
396122394Sharti		node->u.entry.index |= index_count;
397122394Sharti		if (index_count == 0)
398122394Sharti			report("need at least one index");
399122394Sharti
400122394Sharti		if (tok != TOK_STR)
401122394Sharti			report("function name expected");
402122394Sharti
403122394Sharti		node->u.entry.func = savetok();
404122394Sharti
405122394Sharti		tok = gettoken();
406122394Sharti
407122394Sharti		while (tok != ')') {
408122394Sharti			sub = parse(tok);
409122394Sharti			TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
410122394Sharti			tok = gettoken();
411122394Sharti		}
412122394Sharti
413122394Sharti	} else {
414122394Sharti		/* subtree */
415122394Sharti		node->type = NODE_TREE;
416122394Sharti		TAILQ_INIT(&node->u.tree.subs);
417122394Sharti
418122394Sharti		while (tok != ')') {
419122394Sharti			sub = parse(tok);
420122394Sharti			TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
421122394Sharti			tok = gettoken();
422122394Sharti		}
423122394Sharti	}
424122394Sharti	return (node);
425122394Sharti}
426122394Sharti
427122394Sharti/*
428122394Sharti * Generate the C-code table part for one node.
429122394Sharti */
430122394Shartistatic void
431122394Shartigen_node(struct node *np, struct asn_oid *oid, u_int idx, const char *func)
432122394Sharti{
433122394Sharti	u_int n;
434122394Sharti	struct node *sub;
435122394Sharti	u_int syntax;
436122394Sharti
437122394Sharti	if (oid->len == ASN_MAXOIDLEN)
438122394Sharti		report_node(np, "OID too long");
439122394Sharti	oid->subs[oid->len++] = np->id;
440122394Sharti
441122394Sharti	if (np->type == NODE_TREE) {
442122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
443122394Sharti			gen_node(sub, oid, 0, NULL);
444122394Sharti		oid->len--;
445122394Sharti		return;
446122394Sharti	}
447122394Sharti	if (np->type == NODE_ENTRY) {
448122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
449122394Sharti			gen_node(sub, oid, np->u.entry.index, np->u.entry.func);
450122394Sharti		oid->len--;
451122394Sharti		return;
452122394Sharti	}
453122394Sharti
454122394Sharti	/* leaf or column */
455122394Sharti	if ((np->flags & (FL_GET|FL_SET)) == 0) {
456122394Sharti		oid->len--;
457122394Sharti		return;
458122394Sharti	}
459122394Sharti
460122394Sharti	fprintf(fp, "    {{ %u, {", oid->len);
461122394Sharti	for (n = 0; n < oid->len; n++)
462122394Sharti		fprintf(fp, " %u,", oid->subs[n]);
463122394Sharti	fprintf(fp, " }}, \"%s\", ", np->name);
464122394Sharti
465122394Sharti	if (np->type == NODE_COLUMN) {
466122394Sharti		syntax = np->u.column.syntax;
467122394Sharti		fprintf(fp, "SNMP_NODE_COLUMN, ");
468122394Sharti	} else {
469122394Sharti		syntax = np->u.leaf.syntax;
470122394Sharti		fprintf(fp, "SNMP_NODE_LEAF, ");
471122394Sharti	}
472122394Sharti
473122394Sharti	switch (syntax) {
474122394Sharti
475122394Sharti	  case SNMP_SYNTAX_NULL:
476122394Sharti		fprintf(fp, "SNMP_SYNTAX_NULL, ");
477122394Sharti		break;
478122394Sharti
479122394Sharti	  case SNMP_SYNTAX_INTEGER:
480122394Sharti		fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
481122394Sharti		break;
482122394Sharti
483122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
484122394Sharti		fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
485122394Sharti		break;
486122394Sharti
487122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
488122394Sharti		fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
489122394Sharti		break;
490122394Sharti
491122394Sharti	  case SNMP_SYNTAX_OID:
492122394Sharti		fprintf(fp, "SNMP_SYNTAX_OID, ");
493122394Sharti		break;
494122394Sharti
495122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
496122394Sharti		fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
497122394Sharti		break;
498122394Sharti
499122394Sharti	  case SNMP_SYNTAX_COUNTER:
500122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
501122394Sharti		break;
502122394Sharti
503122394Sharti	  case SNMP_SYNTAX_GAUGE:
504122394Sharti		fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
505122394Sharti		break;
506122394Sharti
507122394Sharti	  case SNMP_SYNTAX_COUNTER64:
508122394Sharti		fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
509122394Sharti		break;
510122394Sharti
511122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
512122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
513122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
514122394Sharti		abort();
515122394Sharti	}
516122394Sharti
517122394Sharti	if (np->type == NODE_COLUMN)
518122394Sharti		fprintf(fp, "%s, ", func);
519122394Sharti	else
520122394Sharti		fprintf(fp, "%s, ", np->u.leaf.func);
521122394Sharti
522122394Sharti	fprintf(fp, "0");
523122394Sharti	if (np->flags & FL_SET)
524122394Sharti		fprintf(fp, "|SNMP_NODE_CANSET");
525128237Sharti	fprintf(fp, ", %#x, NULL, NULL },\n", idx);
526122394Sharti	oid->len--;
527122394Sharti	return;
528122394Sharti}
529122394Sharti
530122394Sharti/*
531122394Sharti * Generate the header file with the function declarations.
532122394Sharti */
533122394Shartistatic void
534122394Shartigen_header(struct node *np, u_int oidlen, const char *func)
535122394Sharti{
536122394Sharti	char f[MAXSTR + 4];
537122394Sharti	struct node *sub;
538122394Sharti	struct func *ptr;
539122394Sharti
540122394Sharti	oidlen++;
541122394Sharti	if (np->type == NODE_TREE) {
542122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
543122394Sharti			gen_header(sub, oidlen, NULL);
544122394Sharti		return;
545122394Sharti	}
546122394Sharti	if (np->type == NODE_ENTRY) {
547122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
548122394Sharti			gen_header(sub, oidlen, np->u.entry.func);
549122394Sharti		return;
550122394Sharti	}
551122394Sharti
552122394Sharti 	if((np->flags & (FL_GET|FL_SET)) == 0)
553122394Sharti		return;
554122394Sharti
555122394Sharti	if (np->type == NODE_COLUMN)
556122394Sharti		sprintf(f, "%s", func);
557122394Sharti	else
558122394Sharti		sprintf(f, "%s", np->u.leaf.func);
559122394Sharti
560122394Sharti	LIST_FOREACH(ptr, &funcs, link)
561122394Sharti		if (strcmp(ptr->name, f) == 0)
562122394Sharti			break;
563122394Sharti
564122394Sharti	if (ptr == NULL) {
565122394Sharti		ptr = xalloc(sizeof(*ptr));
566122394Sharti		ptr->name = strcpy(xalloc(strlen(f)+1), f);
567122394Sharti		LIST_INSERT_HEAD(&funcs, ptr, link);
568122394Sharti
569122394Sharti		fprintf(fp, "int	%s(struct snmp_context *, "
570122394Sharti		    "struct snmp_value *, u_int, u_int, "
571122394Sharti		    "enum snmp_op);\n", f);
572122394Sharti	}
573122394Sharti
574122394Sharti	fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
575122394Sharti}
576122394Sharti
577122394Sharti/*
578122394Sharti * Generate the OID table.
579122394Sharti */
580122394Shartistatic void
581122394Shartigen_table(struct node *node)
582122394Sharti{
583122394Sharti	struct asn_oid oid;
584122394Sharti
585122394Sharti	fprintf(fp, "#include <sys/types.h>\n");
586122394Sharti	fprintf(fp, "#include <stdio.h>\n");
587122394Sharti	if (localincs) {
588122394Sharti		fprintf(fp, "#include \"asn1.h\"\n");
589122394Sharti		fprintf(fp, "#include \"snmp.h\"\n");
590122394Sharti		fprintf(fp, "#include \"snmpagent.h\"\n");
591122394Sharti	} else {
592122394Sharti		fprintf(fp, "#include <bsnmp/asn1.h>\n");
593122394Sharti		fprintf(fp, "#include <bsnmp/snmp.h>\n");
594122394Sharti		fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
595122394Sharti	}
596122394Sharti	fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
597122394Sharti	fprintf(fp, "\n");
598122394Sharti
599122394Sharti	fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
600122394Sharti
601122394Sharti	oid.len = PREFIX_LEN;
602122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
603122394Sharti	gen_node(node, &oid, 0, NULL);
604122394Sharti
605122394Sharti	fprintf(fp, "};\n\n");
606122394Sharti}
607122394Sharti
608122394Shartistatic int
609122394Shartiextract(const struct node *np, struct asn_oid *oid, const char *obj)
610122394Sharti{
611122394Sharti	struct node *sub;
612122394Sharti	u_long n;
613122394Sharti
614122394Sharti	if (oid->len == ASN_MAXOIDLEN)
615122394Sharti		report_node(np, "OID too long");
616122394Sharti	oid->subs[oid->len++] = np->id;
617122394Sharti
618122394Sharti	if (strcmp(obj, np->name) == 0) {
619122394Sharti		fprintf(fp, "#define OID_%s\t%u\n", np->name, np->id);
620122394Sharti		fprintf(fp, "#define OIDLEN_%s\t%u\n", np->name, oid->len);
621122394Sharti		fprintf(fp, "#define OIDX_%s\t{ %u, {", np->name, oid->len);
622122394Sharti		for (n = 0; n < oid->len; n++)
623122394Sharti			fprintf(fp, " %u,", oid->subs[n]);
624122394Sharti		fprintf(fp, " } }\n");
625122394Sharti		return (0);
626122394Sharti	}
627122394Sharti
628122394Sharti	if (np->type == NODE_TREE) {
629122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
630122394Sharti			if (!extract(sub, oid, obj))
631122394Sharti				return (0);
632122394Sharti	} else if (np->type == NODE_ENTRY) {
633122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link)
634122394Sharti			if (!extract(sub, oid, obj))
635122394Sharti				return (0);
636122394Sharti	}
637122394Sharti	oid->len--;
638122394Sharti	return (1);
639122394Sharti}
640122394Sharti
641122394Shartistatic int
642122394Shartigen_extract(const struct node *root, const char *object)
643122394Sharti{
644122394Sharti	struct asn_oid oid;
645122394Sharti
646122394Sharti	oid.len = PREFIX_LEN;
647122394Sharti	memcpy(oid.subs, prefix, sizeof(prefix));
648122394Sharti	return (extract(root, &oid, object));
649122394Sharti}
650122394Sharti
651122394Sharti
652122394Shartistatic void
653122394Sharticheck_sub_order(const struct node *np, const struct node_list *subs)
654122394Sharti{
655122394Sharti	int first;
656122394Sharti	const struct node *sub;
657122394Sharti	asn_subid_t maxid = 0;
658122394Sharti
659122394Sharti	/* ensure, that subids are ordered */
660122394Sharti	first = 1;
661122394Sharti	TAILQ_FOREACH(sub, subs, link) {
662122394Sharti		if (!first && sub->id <= maxid)
663122394Sharti			report_node(np, "subids not ordered at %s", sub->name);
664122394Sharti		maxid = sub->id;
665122394Sharti		first = 0;
666122394Sharti	}
667122394Sharti}
668122394Sharti
669122394Sharti/*
670122394Sharti * Do some sanity checks on the tree definition and do some computations.
671122394Sharti */
672122394Shartistatic void
673122394Sharticheck_tree(struct node *np)
674122394Sharti{
675122394Sharti	struct node *sub;
676122394Sharti
677122394Sharti	if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
678122394Sharti		if ((np->flags & (FL_GET|FL_SET)) != 0)
679122394Sharti			tree_size++;
680122394Sharti		return;
681122394Sharti	}
682122394Sharti
683122394Sharti	if (np->type == NODE_ENTRY) {
684122394Sharti		check_sub_order(np, &np->u.entry.subs);
685122394Sharti
686122394Sharti		/* ensure all subnodes are columns */
687122394Sharti		TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
688122394Sharti			if (sub->type != NODE_COLUMN)
689122394Sharti				report_node(np, "entry subnode '%s' is not "
690122394Sharti				    "a column", sub->name);
691122394Sharti			check_tree(sub);
692122394Sharti		}
693122394Sharti	} else {
694122394Sharti		check_sub_order(np, &np->u.tree.subs);
695122394Sharti
696122394Sharti		TAILQ_FOREACH(sub, &np->u.tree.subs, link)
697122394Sharti			check_tree(sub);
698122394Sharti	}
699122394Sharti}
700122394Sharti
701122394Shartiint
702122394Shartimain(int argc, char *argv[])
703122394Sharti{
704122394Sharti	int do_extract = 0;
705122394Sharti	int opt;
706122394Sharti	struct node *root;
707122394Sharti	char fname[MAXPATHLEN + 1];
708122394Sharti
709122394Sharti	while ((opt = getopt(argc, argv, "help:")) != EOF)
710122394Sharti		switch (opt) {
711122394Sharti
712122394Sharti		  case 'h':
713122394Sharti			fprintf(stderr, "%s", usgtxt);
714122394Sharti			exit(0);
715122394Sharti
716122394Sharti		  case 'e':
717122394Sharti			do_extract = 1;
718122394Sharti			break;
719122394Sharti
720122394Sharti		  case 'l':
721122394Sharti			localincs = 1;
722122394Sharti			break;
723122394Sharti
724122394Sharti		  case 'p':
725122394Sharti			file_prefix = optarg;
726122394Sharti			if (strlen(file_prefix) + strlen("tree.c") >
727122394Sharti			    MAXPATHLEN)
728122394Sharti				errx(1, "prefix too long");
729122394Sharti			break;
730122394Sharti		}
731122394Sharti
732122394Sharti	if (!do_extract && argc != optind)
733122394Sharti		errx(1, "no arguments allowed");
734122394Sharti	if (do_extract && argc == optind)
735122394Sharti		errx(1, "no objects specified");
736122394Sharti
737122394Sharti	root = parse(gettoken());
738122394Sharti	if (gettoken() != TOK_EOF)
739122394Sharti		report("junk after closing ')'");
740122394Sharti
741122394Sharti	check_tree(root);
742122394Sharti
743122394Sharti	if (do_extract) {
744122394Sharti		fp = stdout;
745122394Sharti		while (optind < argc) {
746122394Sharti			if (gen_extract(root, argv[optind]))
747122394Sharti				errx(1, "object not found: %s", argv[optind]);
748122394Sharti			optind++;
749122394Sharti		}
750122394Sharti
751122394Sharti		return (0);
752122394Sharti	}
753122394Sharti	sprintf(fname, "%stree.h", file_prefix);
754122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
755122394Sharti		err(1, "%s: ", fname);
756122394Sharti	gen_header(root, PREFIX_LEN, NULL);
757122394Sharti
758122394Sharti	fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
759122394Sharti	fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
760122394Sharti
761122394Sharti	fclose(fp);
762122394Sharti
763122394Sharti	sprintf(fname, "%stree.c", file_prefix);
764122394Sharti	if ((fp = fopen(fname, "w")) == NULL)
765122394Sharti		err(1, "%s: ", fname);
766122394Sharti	gen_table(root);
767122394Sharti	fclose(fp);
768122394Sharti
769122394Sharti	return (0);
770122394Sharti}
771