1124758Semax/*-
2124758Semax * Copyright (c) 2006 The FreeBSD Project
3124758Semax * All rights reserved.
4124758Semax *
5124758Semax * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6124758Semax *
7124758Semax * Redistribution of this software and documentation and use in source and
8124758Semax * binary forms, with or without modification, are permitted provided that
9124758Semax * the following conditions are met:
10124758Semax *
11124758Semax * 1. Redistributions of source code or documentation must retain the above
12124758Semax *    copyright notice, this list of conditions and the following disclaimer.
13124758Semax * 2. Redistributions in binary form must reproduce the above copyright
14124758Semax *    notice, this list of conditions and the following disclaimer in the
15124758Semax *    documentation and/or other materials provided with the distribution.
16124758Semax *
17124758Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20124758Semax * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27124758Semax * SUCH DAMAGE.
28124758Semax *
29124758Semax * $FreeBSD: releng/10.3/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c 216295 2010-12-08 14:30:25Z syrinx $
30124758Semax */
31124758Semax
32124758Semax/*
33124758Semax * Read file containing table description - reuse magic from gensnmptree.c.
34124758Semax * Hopefully one day most of the code here will be part of libbsnmp and
35124758Semax * this duplication won't be necessary.
36124758Semax *
37124758Semax * Syntax is:
38124758Semax * ---------
39124758Semax * file := top | top file
40124758Semax *
41124758Semax * top := tree | typedef | include
42124758Semax *
43124758Semax * tree := head elements ')'
44124758Semax *
45124758Semax * entry := head ':' index STRING elements ')'
46124758Semax *
47124758Semax * leaf := head type STRING ACCESS ')'
48124758Semax *
49124758Semax * column := head type ACCESS ')'
50124758Semax *
51124758Semax * type := BASETYPE | BASETYPE '|' subtype | enum | bits
52124758Semax *
53124758Semax * subtype := STRING
54124758Semax *
55124758Semax * enum := ENUM '(' value ')'
56124758Semax *
57124758Semax * bits := BITS '(' value ')'
58124758Semax *
59124758Semax * value := INT STRING | INT STRING value
60124758Semax *
61124758Semax * head := '(' INT STRING
62124758Semax *
63124758Semax * elements := EMPTY | elements element
64124758Semax *
65124758Semax * element := tree | leaf | column
66124758Semax *
67124758Semax * index := type | index type
68124758Semax *
69124758Semax * typedef := 'typedef' STRING type
70124758Semax *
71124758Semax * include := 'include' filespec
72124758Semax *
73124758Semax * filespec := '"' STRING '"' | '<' STRING '>'
74124758Semax */
75124758Semax
76124758Semax#include <sys/param.h>
77124758Semax#include <sys/queue.h>
78124758Semax#include <sys/uio.h>
79124758Semax
80124758Semax#include <ctype.h>
81124758Semax#include <err.h>
82124758Semax#include <errno.h>
83124758Semax#include <fcntl.h>
84124758Semax#include <stdio.h>
85124758Semax#include <stdlib.h>
86124758Semax#include <string.h>
87124758Semax#include <syslog.h>
88124758Semax#include <unistd.h>
89124758Semax
90124758Semax#include <bsnmp/asn1.h>
91124758Semax#include <bsnmp/snmp.h>
92124758Semax#include <bsnmp/snmpagent.h>	/* SNMP_INDEXES_MAX */
93124758Semax#include "bsnmptc.h"
94124758Semax#include "bsnmptools.h"
95124758Semax
96124758Semaxenum snmp_tbl_entry {
97124758Semax	ENTRY_NONE = 0,
98124758Semax	ENTRY_INDEX,
99124758Semax	ENTRY_DATA
100124758Semax};
101124758Semax
102124758Semaxenum {
103124758Semax	FL_GET	= 0x01,
104124758Semax	FL_SET	= 0x02,
105124758Semax};
106124758Semax
107124758Semax/************************************************************
108124758Semax *
109124758Semax * Allocate memory and panic just in the case...
110124758Semax */
111124758Semaxstatic void *
112124758Semaxxalloc(size_t size)
113124758Semax{
114124758Semax	void *ptr;
115124758Semax
116124758Semax	if ((ptr = malloc(size)) == NULL)
117124758Semax		err(1, "allocing %zu bytes", size);
118124758Semax
119124758Semax	return (ptr);
120124758Semax}
121124758Semax
122124758Semaxstatic char *
123124758Semaxsavestr(const char *s)
124124758Semax{
125124758Semax	if (s == NULL)
126124758Semax		return (NULL);
127124758Semax
128124758Semax	return (strcpy(xalloc(strlen(s) + 1), s));
129124758Semax}
130124758Semax
131124758Semax/************************************************************
132124758Semax *
133124758Semax * Input stack
134124758Semax */
135124758Semaxstruct input {
136124758Semax	FILE		*fp;
137124758Semax	uint32_t	lno;
138124758Semax	char		*fname;
139124758Semax	char		*path;
140124758Semax	LIST_ENTRY(input) link;
141124758Semax};
142124758Semax
143124758SemaxLIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
144124758Semaxstruct input *input = NULL;
145124758Semaxint32_t pbchar = -1;
146124758Semax
147124758Semax#define	MAX_PATHS	100
148124758Semax
149124758Semaxstatic const char *paths[MAX_PATHS + 1] = {
150124758Semax	"/usr/share/snmp/defs",
151124758Semax	"/usr/local/share/snmp/defs",
152124758Semax	NULL
153124758Semax};
154124758Semax
155124758Semaxstatic void
156124758Semaxinput_new(FILE *fp, const char *path, const char *fname)
157124758Semax{
158124758Semax	struct input *ip;
159124758Semax
160124758Semax	ip = xalloc(sizeof(*ip));
161124758Semax	ip->fp = fp;
162124758Semax	ip->lno = 1;
163124758Semax	ip->fname = savestr(fname);
164124758Semax	ip->path = savestr(path);
165124758Semax	LIST_INSERT_HEAD(&inputs, ip, link);
166124758Semax
167124758Semax	input = ip;
168124758Semax}
169124758Semax
170124758Semaxstatic void
171124758Semaxinput_close(void)
172124758Semax{
173124758Semax	if (input == NULL)
174124758Semax		return;
175124758Semax
176124758Semax	fclose(input->fp);
177124758Semax	free(input->fname);
178124758Semax	free(input->path);
179124758Semax	LIST_REMOVE(input, link);
180124758Semax	free(input);
181124758Semax
182124758Semax	input = LIST_FIRST(&inputs);
183124758Semax}
184124758Semax
185124758Semaxstatic FILE *
186124758Semaxtryopen(const char *path, const char *fname)
187124758Semax{
188124758Semax	char *fn;
189124758Semax	FILE *fp;
190124758Semax
191124758Semax	if (path == NULL)
192124758Semax		fn = savestr(fname);
193124758Semax	else {
194124758Semax		fn = xalloc(strlen(path) + strlen(fname) + 2);
195124758Semax		sprintf(fn, "%s/%s", path, fname);
196124758Semax	}
197124758Semax	fp = fopen(fn, "r");
198124758Semax	free(fn);
199124758Semax	return (fp);
200124758Semax}
201124758Semax
202124758Semaxstatic int32_t
203124758Semaxinput_fopen(const char *fname)
204124758Semax{
205124758Semax	FILE *fp;
206124758Semax	u_int p;
207124758Semax
208124758Semax	if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
209124758Semax		if ((fp = tryopen(NULL, fname)) != NULL) {
210124758Semax			input_new(fp, NULL, fname);
211124758Semax			return (0);
212124758Semax		}
213124758Semax
214124758Semax	} else {
215124758Semax
216124758Semax		for (p = 0; paths[p] != NULL; p++)
217124758Semax			if ((fp = tryopen(paths[p], fname)) != NULL) {
218124758Semax				input_new(fp, paths[p], fname);
219124758Semax				return (0);
220124758Semax			}
221124758Semax	}
222124758Semax
223124758Semax	warnx("cannot open '%s'", fname);
224124758Semax	return (-1);
225124758Semax}
226124758Semax
227124758Semaxstatic int32_t
228124758Semaxtgetc(void)
229124758Semax{
230124758Semax	int c;
231124758Semax
232124758Semax	if (pbchar != -1) {
233124758Semax		c = pbchar;
234124758Semax		pbchar = -1;
235124758Semax		return (c);
236	}
237
238	for (;;) {
239		if (input == NULL)
240			return (EOF);
241
242		if ((c = getc(input->fp)) != EOF)
243			return (c);
244
245		input_close();
246	}
247}
248
249static int32_t
250tungetc(int c)
251{
252
253	if (pbchar != -1)
254		return (-1);
255
256	pbchar = c;
257	return (1);
258}
259
260/************************************************************
261 *
262 * Parsing input
263 */
264enum tok {
265	TOK_EOF = 0200,	/* end-of-file seen */
266	TOK_NUM,	/* number */
267	TOK_STR,	/* string */
268	TOK_ACCESS,	/* access operator */
269	TOK_TYPE,	/* type operator */
270	TOK_ENUM,	/* enum token (kind of a type) */
271	TOK_TYPEDEF,	/* typedef directive */
272	TOK_DEFTYPE,	/* defined type */
273	TOK_INCLUDE,	/* include directive */
274	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
275	TOK_BITS,	/* bits token (kind of a type) */
276	TOK_ERR		/* unexpected char - exit */
277};
278
279static const struct {
280	const char	*str;
281	enum tok	tok;
282	uint32_t	val;
283} keywords[] = {
284	{ "GET", TOK_ACCESS, FL_GET },
285	{ "SET", TOK_ACCESS, FL_SET },
286	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
287	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
288	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
289	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
290	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
291	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
292	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
293	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
294	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
295	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
296	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
297	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
298	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
299	{ "typedef", TOK_TYPEDEF, 0 },
300	{ "include", TOK_INCLUDE, 0 },
301	{ NULL, 0, 0 }
302};
303
304struct {
305	/* Current OID type, regarding table membership. */
306	enum snmp_tbl_entry	tbl_type;
307	/* A pointer to a structure in table list to add to its members. */
308	struct snmp_index_entry	*table_idx;
309} table_data;
310
311struct asn_oid current_oid;
312char nexttok[MAXSTR];
313u_long val;		/* integer values */
314int32_t	all_cond;	/* all conditions are true */
315int32_t saved_token = -1;
316
317/* Prepare the global data before parsing a new file. */
318static void
319snmp_import_init(struct asn_oid *append)
320{
321	memset(&table_data, 0, sizeof(table_data));
322	memset(&current_oid, 0, sizeof(struct asn_oid));
323	memset(nexttok, 0, MAXSTR);
324
325	if (append != NULL)
326		asn_append_oid(&current_oid, append);
327
328	all_cond = 0;
329	val = 0;
330	saved_token = -1;
331}
332
333static int32_t
334gettoken(struct snmp_toolinfo *snmptoolctx)
335{
336	int c;
337	struct enum_type *t;
338
339	if (saved_token != -1) {
340		c = saved_token;
341		saved_token = -1;
342		return (c);
343	}
344
345  again:
346	/*
347	 * Skip any whitespace before the next token.
348	 */
349	while ((c = tgetc()) != EOF) {
350		if (c == '\n')
351			input->lno++;
352		if (!isspace(c))
353			break;
354	}
355	if (c == EOF)
356		return (TOK_EOF);
357
358	if (!isascii(c)) {
359		warnx("unexpected character %#2x", (u_int) c);
360		return (TOK_ERR);
361	}
362
363	/*
364	 * Skip comments.
365	 */
366	if (c == '#') {
367		while ((c = tgetc()) != EOF) {
368			if (c == '\n') {
369				input->lno++;
370				goto again;
371			}
372		}
373		warnx("unexpected EOF in comment");
374		return (TOK_ERR);
375	}
376
377	/*
378	 * Single character tokens.
379	 */
380	if (strchr("():|", c) != NULL)
381		return (c);
382
383	if (c == '"' || c == '<') {
384		int32_t end = c;
385		size_t n = 0;
386
387		val = 1;
388		if (c == '<') {
389			val = 0;
390			end = '>';
391		}
392
393		while ((c = tgetc()) != EOF) {
394			if (c == end)
395				break;
396			if (n == sizeof(nexttok) - 1) {
397				nexttok[n++] = '\0';
398				warnx("filename too long '%s...'", nexttok);
399				return (TOK_ERR);
400			}
401			nexttok[n++] = c;
402		}
403		nexttok[n++] = '\0';
404		return (TOK_FILENAME);
405	}
406
407	/*
408	 * Sort out numbers.
409	 */
410	if (isdigit(c)) {
411		size_t n = 0;
412		nexttok[n++] = c;
413		while ((c = tgetc()) != EOF) {
414			if (!isdigit(c)) {
415				if (tungetc(c) < 0)
416					return (TOK_ERR);
417				break;
418			}
419			if (n == sizeof(nexttok) - 1) {
420				nexttok[n++] = '\0';
421				warnx("number too long '%s...'", nexttok);
422				return (TOK_ERR);
423			}
424			nexttok[n++] = c;
425		}
426		nexttok[n++] = '\0';
427		sscanf(nexttok, "%lu", &val);
428		return (TOK_NUM);
429	}
430
431	/*
432	 * So that has to be a string.
433	 */
434	if (isalpha(c) || c == '_' || c == '-') {
435		size_t n = 0;
436		nexttok[n++] = c;
437		while ((c = tgetc()) != EOF) {
438			if (!isalnum(c) && c != '_' && c != '-') {
439				if (tungetc (c) < 0)
440					return (TOK_ERR);
441				break;
442			}
443			if (n == sizeof(nexttok) - 1) {
444				nexttok[n++] = '\0';
445				warnx("string too long '%s...'", nexttok);
446				return (TOK_ERR);
447			}
448			nexttok[n++] = c;
449		}
450		nexttok[n++] = '\0';
451
452		/*
453		 * Keywords.
454		 */
455		for (c = 0; keywords[c].str != NULL; c++)
456			if (strcmp(keywords[c].str, nexttok) == 0) {
457				val = keywords[c].val;
458				return (keywords[c].tok);
459			}
460
461		if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) {
462			val = t->syntax;
463			return (TOK_DEFTYPE);
464		}
465
466		return (TOK_STR);
467	}
468
469	if (isprint(c))
470		warnx("%u: unexpected character '%c'", input->lno, c);
471	else
472		warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c);
473
474	return (TOK_ERR);
475}
476
477/*
478 * Update table information.
479 */
480static struct snmp_index_entry *
481snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl)
482{
483	switch (te) {
484		case ENTRY_NONE:
485			if (table_data.tbl_type == ENTRY_NONE)
486				return (NULL);
487			if (table_data.tbl_type == ENTRY_INDEX)
488				table_data.table_idx = NULL;
489			table_data.tbl_type--;
490			return (NULL);
491
492		case ENTRY_INDEX:
493			if (tbl == NULL)
494				warnx("No table_index to add!!!");
495			table_data.table_idx = tbl;
496			table_data.tbl_type = ENTRY_INDEX;
497			return (tbl);
498
499		case ENTRY_DATA:
500			if (table_data.tbl_type == ENTRY_INDEX) {
501				table_data.tbl_type = ENTRY_DATA;
502				return (table_data.table_idx);
503			}
504			return (NULL);
505
506		default:
507			/* NOTREACHED */
508			warnx("Unknown table entry type!!!");
509			break;
510	}
511
512	return (NULL);
513}
514
515static int32_t
516parse_enum(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
517    struct enum_pairs *enums)
518{
519	while ((*tok = gettoken(snmptoolctx)) == TOK_STR) {
520		if (enum_pair_insert(enums, val, nexttok) < 0)
521			return (-1);
522		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM)
523			break;
524	}
525
526	if (*tok != ')') {
527		warnx("')' at end of enums");
528		return (-1);
529	}
530
531	return (1);
532}
533
534static int32_t
535parse_subtype(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
536    enum snmp_tc *tc)
537{
538	if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
539		warnx("subtype expected after '|'");
540		return (-1);
541	}
542
543	*tc = snmp_get_tc(nexttok);
544	*tok = gettoken(snmptoolctx);
545
546	return (1);
547}
548
549static int32_t
550parse_type(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
551    enum snmp_tc *tc, struct enum_pairs **snmp_enum)
552{
553	int32_t syntax, mem;
554
555	syntax = val;
556	*tc = 0;
557
558	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
559		if (*snmp_enum == NULL) {
560			if ((*snmp_enum = enum_pairs_init()) == NULL)
561				return (-1);
562			mem = 1;
563			*tc = SNMP_TC_OWN;
564		} else
565			mem = 0;
566
567		if (gettoken(snmptoolctx) != '(') {
568			warnx("'(' expected after ENUM/BITS");
569			return (-1);
570		}
571
572		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) {
573			warnx("need value for ENUM//BITS");
574			if (mem == 1) {
575				free(*snmp_enum);
576				*snmp_enum = NULL;
577			}
578			return (-1);
579		}
580
581		if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) {
582			enum_pairs_free(*snmp_enum);
583			*snmp_enum = NULL;
584			return (-1);
585		}
586
587		*tok = gettoken(snmptoolctx);
588
589	} else if (*tok == TOK_DEFTYPE) {
590		struct enum_type *t;
591
592		*tc = 0;
593		t = snmp_enumtc_lookup(snmptoolctx, nexttok);
594		if (t != NULL)
595			*snmp_enum = t->snmp_enum;
596
597		*tok = gettoken(snmptoolctx);
598
599	} else {
600		if ((*tok = gettoken(snmptoolctx)) == '|') {
601			if (parse_subtype(snmptoolctx, tok, tc) < 0)
602				return (-1);
603		}
604	}
605
606	return (syntax);
607}
608
609static int32_t
610snmp_import_head(struct snmp_toolinfo *snmptoolctx)
611{
612	enum tok tok;
613
614	if ((tok = gettoken(snmptoolctx)) == '(')
615		tok = gettoken(snmptoolctx);
616
617	if (tok != TOK_NUM  || val > ASN_MAXID ) {
618		warnx("Suboid expected - line %d", input->lno);
619		return (-1);
620	}
621
622	if (gettoken(snmptoolctx) != TOK_STR) {
623		warnx("Node name expected at line %d", input->lno);
624		return (-1);
625	}
626
627	return (1);
628}
629
630static int32_t
631snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj)
632{
633	int32_t i;
634	enum snmp_tc tc;
635	enum tok tok;
636	struct snmp_index_entry *entry;
637
638	if ((entry = malloc(sizeof(struct snmp_index_entry))) == NULL) {
639		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
640		return (-1);
641	}
642
643	memset(entry, 0, sizeof(struct snmp_index_entry));
644	STAILQ_INIT(&(entry->index_list));
645
646	for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
647		int32_t syntax;
648		struct enum_pairs *enums = NULL;
649
650		if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
651		    tok != TOK_BITS)
652			break;
653
654		if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
655			enum_pairs_free(enums);
656			snmp_index_listfree(&(entry->index_list));
657			free(entry);
658			return (-1);
659		}
660
661		if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
662		    tc) < 0) {
663			snmp_index_listfree(&(entry->index_list));
664			enum_pairs_free(enums);
665			free(entry);
666			return (-1);
667		}
668	}
669
670	if (i == 0 || i > SNMP_INDEXES_MAX) {
671		warnx("Bad number of indexes at line %d", input->lno);
672		snmp_index_listfree(&(entry->index_list));
673		free(entry);
674		return (-1);
675	}
676
677	if (tok != TOK_STR) {
678		warnx("String expected after indexes at line %d", input->lno);
679		snmp_index_listfree(&(entry->index_list));
680		free(entry);
681		return (-1);
682	}
683
684	entry->string = obj->string;
685	entry->strlen = obj->strlen;
686	asn_append_oid(&(entry->var), &(obj->var));
687
688	if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
689		snmp_index_listfree(&(entry->index_list));
690		free(entry);
691		return (-1);
692	} else if (i == 0) {
693		/* Same entry already present in lists. */
694		free(entry->string);
695		free(entry);
696	}
697
698	(void) snmp_import_update_table(ENTRY_INDEX, entry);
699
700	return (1);
701}
702
703/*
704 * Read everything after the syntax type that is certainly a leaf OID info.
705 */
706static int32_t
707snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
708    struct snmp_oid2str *oid2str)
709{
710	int32_t i, syntax;
711
712	if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
713	    < 0)
714		return(-1);
715
716	oid2str->syntax = syntax;
717	/*
718	 * That is the name of the function, corresponding to the entry.
719	 * It is used by bsnmpd, but is not interesting for us.
720	 */
721	if (*tok == TOK_STR)
722		*tok = gettoken(snmptoolctx);
723
724	for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
725		oid2str->access |=  (uint32_t) val;
726		*tok = gettoken(snmptoolctx);
727	}
728
729	if (*tok != ')') {
730		warnx("')' expected at end of line %d", input->lno);
731		return (-1);
732	}
733
734	oid2str->table_idx = snmp_import_update_table(ENTRY_DATA,  NULL);
735
736	if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
737		warnx("Error adding leaf %s to list", oid2str->string);
738		return (-1);
739	}
740
741	/*
742	 * Same entry is already present in the mapping lists and
743	 * the new one was not inserted.
744	 */
745	if (i == 0)  {
746		free(oid2str->string);
747		free(oid2str);
748	}
749
750	(void) snmp_import_update_table(ENTRY_NONE, NULL);
751
752	return (1);
753}
754
755static int32_t
756snmp_import_object(struct snmp_toolinfo *snmptoolctx)
757{
758	char *string;
759	int i;
760	enum tok tok;
761	struct snmp_oid2str *oid2str;
762
763	if (snmp_import_head(snmptoolctx) < 0)
764		return (-1);
765
766	if ((oid2str = malloc(sizeof(struct snmp_oid2str))) == NULL) {
767		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
768		return (-1);
769	}
770
771	if ((string = malloc(strlen(nexttok) + 1)) == NULL) {
772		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
773		free(oid2str);
774		return (-1);
775	}
776
777	memset(oid2str, 0, sizeof(struct snmp_oid2str));
778	strlcpy(string, nexttok, strlen(nexttok) + 1);
779	oid2str->string = string;
780	oid2str->strlen = strlen(nexttok);
781
782	asn_append_oid(&(oid2str->var), &(current_oid));
783	if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
784		goto error;
785
786	/*
787	 * Prepared the entry - now figure out where to insert it.
788	 * After the object we have following options:
789	 * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
790	 * 2) new line , ( - nonleaf oid -> snmp_nodelist;
791	 * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
792	 *     may follow and second string must end line -> snmp_tablelist;
793	 * 3) OID , string  ) - this is a trap entry or a leaf -> snmp_oidlist;
794	 * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
795	 *     and )- this is definitely a leaf.
796	 */
797
798	switch (tok = gettoken(snmptoolctx)) {
799	    case  ')':
800		if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
801			goto error;
802		if (i == 0) {
803			free(oid2str->string);
804			free(oid2str);
805		}
806		return (1);
807
808	    case '(':
809		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
810			goto error;
811
812		/*
813		 * Ignore the error for nodes since the .def files currently
814		 * contain different strings for 1.3.6.1.2.1 - mibII. Only make
815		 * sure the memory is freed and don't complain.
816		 */
817		if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
818			free(string);
819			free(oid2str);
820		}
821		return (snmp_import_object(snmptoolctx));
822
823	    case ':':
824		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
825			goto error;
826		if (snmp_import_table(snmptoolctx, oid2str) < 0)
827			goto error;
828		/*
829		 * A different table entry type was malloced and the data is
830		 * contained there.
831		 */
832		free(oid2str);
833		return (1);
834
835	    case TOK_TYPE:
836		/* FALLTHROUGH */
837	    case TOK_DEFTYPE:
838		/* FALLTHROUGH */
839	    case TOK_ENUM:
840	    	/* FALLTHROUGH */
841	    case TOK_BITS:
842		if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
843				goto error;
844		return (1);
845
846	    default:
847		warnx("Unexpected token at line %d - %s", input->lno,
848		    input->fname);
849		break;
850	}
851
852error:
853	snmp_mapping_entryfree(oid2str);
854
855	return (-1);
856}
857
858static int32_t
859snmp_import_tree(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
860{
861	while (*tok != TOK_EOF) {
862		switch (*tok) {
863		    case TOK_ERR:
864			return (-1);
865		    case '(':
866			if (snmp_import_object(snmptoolctx) < 0)
867			    return (-1);
868			break;
869		    case ')':
870			if (snmp_suboid_pop(&current_oid) < 0)
871			    return (-1);
872			(void) snmp_import_update_table(ENTRY_NONE, NULL);
873			break;
874		    default:
875			/* Anything else here would be illegal. */
876			return (-1);
877		}
878		*tok = gettoken(snmptoolctx);
879	}
880
881	return (0);
882}
883
884static int32_t
885snmp_import_top(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
886{
887	enum snmp_tc tc;
888	struct enum_type *t;
889
890	if (*tok == '(')
891		return (snmp_import_tree(snmptoolctx, tok));
892
893	if (*tok == TOK_TYPEDEF) {
894		if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
895			warnx("type name expected after typedef - %s",
896			    input->fname);
897			return (-1);
898		}
899
900		t = snmp_enumtc_init(nexttok);
901
902		*tok = gettoken(snmptoolctx);
903		t->is_enum = (*tok == TOK_ENUM);
904		t->is_bits = (*tok == TOK_BITS);
905		t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
906		snmp_enumtc_insert(snmptoolctx, t);
907
908		return (1);
909	}
910
911	if (*tok == TOK_INCLUDE) {
912		int i;
913
914		*tok = gettoken(snmptoolctx);
915		if (*tok != TOK_FILENAME) {
916			warnx("filename expected in include directive - %s",
917			    nexttok);
918			return (-1);
919		}
920
921		if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
922			*tok = gettoken(snmptoolctx);
923			return (1);
924		}
925
926		if (i == -1)
927			return (-1);
928
929		input_fopen(nexttok);
930		*tok = gettoken(snmptoolctx);
931		return (1);
932	}
933
934	warnx("'(' or 'typedef' expected - %s", nexttok);
935	return (-1);
936}
937
938static int32_t
939snmp_import(struct snmp_toolinfo *snmptoolctx)
940{
941	int i;
942	enum tok tok;
943
944	tok = gettoken(snmptoolctx);
945
946	do
947		i = snmp_import_top(snmptoolctx, &tok);
948	while (i > 0);
949
950	return (i);
951}
952
953/*
954 * Read a .def file and import oid<->string mapping.
955 * Mappings are inserted into a global structure containing list for each OID
956 * syntax type.
957 */
958int32_t
959snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
960{
961	int idx;
962
963	snmp_import_init(&(file->cut));
964	input_fopen(file->name);
965	if ((idx = snmp_import(snmptoolctx)) < 0)
966		warnx("Failed to read mappings from file %s", file->name);
967
968	input_close();
969
970	return (idx);
971}
972