config root man

Current Path : /usr/src/usr.sbin/bsnmpd/tools/libbsnmptools/

FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64
Upload File :
Current File : //usr/src/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c

/*-
 * Copyright (c) 2006 The FreeBSD Project
 * All rights reserved.
 *
 * Author: Shteryana Shopova <syrinx@FreeBSD.org>
 *
 * Redistribution of this software and documentation and use in source and
 * binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *
 * 1. Redistributions of source code or documentation must retain the above
 *    copyright notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: release/9.1.0/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c 216295 2010-12-08 14:30:25Z syrinx $
 */

/*
 * Read file containing table description - reuse magic from gensnmptree.c.
 * Hopefully one day most of the code here will be part of libbsnmp and
 * this duplication won't be necessary.
 *
 * Syntax is:
 * ---------
 * file := top | top file
 *
 * top := tree | typedef | include
 *
 * tree := head elements ')'
 *
 * entry := head ':' index STRING elements ')'
 *
 * leaf := head type STRING ACCESS ')'
 *
 * column := head type ACCESS ')'
 *
 * type := BASETYPE | BASETYPE '|' subtype | enum | bits
 *
 * subtype := STRING
 *
 * enum := ENUM '(' value ')'
 * 
 * bits := BITS '(' value ')'
 *
 * value := INT STRING | INT STRING value
 *
 * head := '(' INT STRING
 *
 * elements := EMPTY | elements element
 *
 * element := tree | leaf | column
 *
 * index := type | index type
 *
 * typedef := 'typedef' STRING type
 *
 * include := 'include' filespec
 *
 * filespec := '"' STRING '"' | '<' STRING '>'
 */

#include <sys/param.h>
#include <sys/queue.h>
#include <sys/uio.h>

#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

#include <bsnmp/asn1.h>
#include <bsnmp/snmp.h>
#include <bsnmp/snmpagent.h>	/* SNMP_INDEXES_MAX */
#include "bsnmptc.h"
#include "bsnmptools.h"

enum snmp_tbl_entry {
	ENTRY_NONE = 0,
	ENTRY_INDEX,
	ENTRY_DATA
};

enum {
	FL_GET	= 0x01,
	FL_SET	= 0x02,
};

/************************************************************
 *
 * Allocate memory and panic just in the case...
 */
static void *
xalloc(size_t size)
{
	void *ptr;

	if ((ptr = malloc(size)) == NULL)
		err(1, "allocing %zu bytes", size);

	return (ptr);
}

static char *
savestr(const char *s)
{
	if (s == NULL)
		return (NULL);

	return (strcpy(xalloc(strlen(s) + 1), s));
}

/************************************************************
 *
 * Input stack
 */
struct input {
	FILE		*fp;
	uint32_t	lno;
	char		*fname;
	char		*path;
	LIST_ENTRY(input) link;
};

LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
struct input *input = NULL;
int32_t pbchar = -1;

#define	MAX_PATHS	100

static const char *paths[MAX_PATHS + 1] = {
	"/usr/share/snmp/defs",
	"/usr/local/share/snmp/defs",
	NULL
};

static void
input_new(FILE *fp, const char *path, const char *fname)
{
	struct input *ip;

	ip = xalloc(sizeof(*ip));
	ip->fp = fp;
	ip->lno = 1;
	ip->fname = savestr(fname);
	ip->path = savestr(path);
	LIST_INSERT_HEAD(&inputs, ip, link);

	input = ip;
}

static void
input_close(void)
{
	if (input == NULL)
		return;

	fclose(input->fp);
	free(input->fname);
	free(input->path);
	LIST_REMOVE(input, link);
	free(input);

	input = LIST_FIRST(&inputs);
}

static FILE *
tryopen(const char *path, const char *fname)
{
	char *fn;
	FILE *fp;

	if (path == NULL)
		fn = savestr(fname);
	else {
		fn = xalloc(strlen(path) + strlen(fname) + 2);
		sprintf(fn, "%s/%s", path, fname);
	}
	fp = fopen(fn, "r");
	free(fn);
	return (fp);
}

static int32_t
input_fopen(const char *fname)
{
	FILE *fp;
	u_int p;

	if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
		if ((fp = tryopen(NULL, fname)) != NULL) {
			input_new(fp, NULL, fname);
			return (0);
		}

	} else {

		for (p = 0; paths[p] != NULL; p++)
			if ((fp = tryopen(paths[p], fname)) != NULL) {
				input_new(fp, paths[p], fname);
				return (0);
			}
	}

	warnx("cannot open '%s'", fname);
	return (-1);
}

static int32_t
tgetc(void)
{
	int c;

	if (pbchar != -1) {
		c = pbchar;
		pbchar = -1;
		return (c);
	}

	for (;;) {
		if (input == NULL)
			return (EOF);

		if ((c = getc(input->fp)) != EOF)
			return (c);

		input_close();
	}
}

static int32_t
tungetc(int c)
{

	if (pbchar != -1)
		return (-1);

	pbchar = c;
	return (1);
}

/************************************************************
 *
 * Parsing input
 */
enum tok {
	TOK_EOF = 0200,	/* end-of-file seen */
	TOK_NUM,	/* number */
	TOK_STR,	/* string */
	TOK_ACCESS,	/* access operator */
	TOK_TYPE,	/* type operator */
	TOK_ENUM,	/* enum token (kind of a type) */
	TOK_TYPEDEF,	/* typedef directive */
	TOK_DEFTYPE,	/* defined type */
	TOK_INCLUDE,	/* include directive */
	TOK_FILENAME,	/* filename ("foo.bar" or <foo.bar>) */
	TOK_BITS,	/* bits token (kind of a type) */
	TOK_ERR		/* unexpected char - exit */
};

static const struct {
	const char	*str;
	enum tok	tok;
	uint32_t	val;
} keywords[] = {
	{ "GET", TOK_ACCESS, FL_GET },
	{ "SET", TOK_ACCESS, FL_SET },
	{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
	{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
	{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
	{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
	{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
	{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
	{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
	{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
	{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
	{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
	{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
	{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
	{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
	{ "typedef", TOK_TYPEDEF, 0 },
	{ "include", TOK_INCLUDE, 0 },
	{ NULL, 0, 0 }
};

struct {
	/* Current OID type, regarding table membership. */
	enum snmp_tbl_entry	tbl_type;
	/* A pointer to a structure in table list to add to its members. */
	struct snmp_index_entry	*table_idx;
} table_data;

struct asn_oid current_oid;
char nexttok[MAXSTR];
u_long val;		/* integer values */
int32_t	all_cond;	/* all conditions are true */
int32_t saved_token = -1;

/* Prepare the global data before parsing a new file. */
static void
snmp_import_init(struct asn_oid *append)
{
	memset(&table_data, 0, sizeof(table_data));
	memset(&current_oid, 0, sizeof(struct asn_oid));
	memset(nexttok, 0, MAXSTR);

	if (append != NULL)
		asn_append_oid(&current_oid, append);

	all_cond = 0;
	val = 0;
	saved_token = -1;
}

static int32_t
gettoken(struct snmp_toolinfo *snmptoolctx)
{
	int c;
	struct enum_type *t;

	if (saved_token != -1) {
		c = saved_token;
		saved_token = -1;
		return (c);
	}

  again:
	/*
	 * Skip any whitespace before the next token.
	 */
	while ((c = tgetc()) != EOF) {
		if (c == '\n')
			input->lno++;
		if (!isspace(c))
			break;
	}
	if (c == EOF)
		return (TOK_EOF);

	if (!isascii(c)) {
		warnx("unexpected character %#2x", (u_int) c);
		return (TOK_ERR);
	}

	/*
	 * Skip comments.
	 */
	if (c == '#') {
		while ((c = tgetc()) != EOF) {
			if (c == '\n') {
				input->lno++;
				goto again;
			}
		}
		warnx("unexpected EOF in comment");
		return (TOK_ERR);
	}

	/*
	 * Single character tokens.
	 */
	if (strchr("():|", c) != NULL)
		return (c);

	if (c == '"' || c == '<') {
		int32_t end = c;
		size_t n = 0;

		val = 1;
		if (c == '<') {
			val = 0;
			end = '>';
		}

		while ((c = tgetc()) != EOF) {
			if (c == end)
				break;
			if (n == sizeof(nexttok) - 1) {
				nexttok[n++] = '\0';
				warnx("filename too long '%s...'", nexttok);
				return (TOK_ERR);
			}
			nexttok[n++] = c;
		}
		nexttok[n++] = '\0';
		return (TOK_FILENAME);
	}

	/*
	 * Sort out numbers.
	 */
	if (isdigit(c)) {
		size_t n = 0;
		nexttok[n++] = c;
		while ((c = tgetc()) != EOF) {
			if (!isdigit(c)) {
				if (tungetc(c) < 0)
					return (TOK_ERR);
				break;
			}
			if (n == sizeof(nexttok) - 1) {
				nexttok[n++] = '\0';
				warnx("number too long '%s...'", nexttok);
				return (TOK_ERR);
			}
			nexttok[n++] = c;
		}
		nexttok[n++] = '\0';
		sscanf(nexttok, "%lu", &val);
		return (TOK_NUM);
	}

	/*
	 * So that has to be a string.
	 */
	if (isalpha(c) || c == '_' || c == '-') {
		size_t n = 0;
		nexttok[n++] = c;
		while ((c = tgetc()) != EOF) {
			if (!isalnum(c) && c != '_' && c != '-') {
				if (tungetc (c) < 0)
					return (TOK_ERR);
				break;
			}
			if (n == sizeof(nexttok) - 1) {
				nexttok[n++] = '\0';
				warnx("string too long '%s...'", nexttok);
				return (TOK_ERR);
			}
			nexttok[n++] = c;
		}
		nexttok[n++] = '\0';

		/*
		 * Keywords.
		 */
		for (c = 0; keywords[c].str != NULL; c++)
			if (strcmp(keywords[c].str, nexttok) == 0) {
				val = keywords[c].val;
				return (keywords[c].tok);
			}

		if ((t = snmp_enumtc_lookup(snmptoolctx, nexttok)) != NULL) {
			val = t->syntax;
			return (TOK_DEFTYPE);
		}

		return (TOK_STR);
	}

	if (isprint(c))
		warnx("%u: unexpected character '%c'", input->lno, c);
	else
		warnx("%u: unexpected character 0x%02x", input->lno, (u_int) c);

	return (TOK_ERR);
}

/*
 * Update table information.
 */
static struct snmp_index_entry *
snmp_import_update_table(enum snmp_tbl_entry te, struct snmp_index_entry *tbl)
{
	switch (te) {
		case ENTRY_NONE:
			if (table_data.tbl_type == ENTRY_NONE)
				return (NULL);	
			if (table_data.tbl_type == ENTRY_INDEX)
				table_data.table_idx = NULL;
			table_data.tbl_type--;
			return (NULL);

		case ENTRY_INDEX:
			if (tbl == NULL)
				warnx("No table_index to add!!!");
			table_data.table_idx = tbl;
			table_data.tbl_type = ENTRY_INDEX;
			return (tbl);

		case ENTRY_DATA:
			if (table_data.tbl_type == ENTRY_INDEX) {
				table_data.tbl_type = ENTRY_DATA;
				return (table_data.table_idx);
			}
			return (NULL);

		default:
			/* NOTREACHED */
			warnx("Unknown table entry type!!!");
			break;
	}

	return (NULL);
}

static int32_t
parse_enum(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
    struct enum_pairs *enums)
{
	while ((*tok = gettoken(snmptoolctx)) == TOK_STR) {
		if (enum_pair_insert(enums, val, nexttok) < 0)
			return (-1);
		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM)
			break;
	}

	if (*tok != ')') {
		warnx("')' at end of enums");
		return (-1);
	}

	return (1);
}

static int32_t
parse_subtype(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
    enum snmp_tc *tc)
{
	if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
		warnx("subtype expected after '|'");
		return (-1);
	}
	
	*tc = snmp_get_tc(nexttok);
	*tok = gettoken(snmptoolctx);

	return (1);
}

static int32_t
parse_type(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
    enum snmp_tc *tc, struct enum_pairs **snmp_enum)
{
	int32_t syntax, mem;

	syntax = val;
	*tc = 0;

	if (*tok == TOK_ENUM || *tok == TOK_BITS) {
		if (*snmp_enum == NULL) {
			if ((*snmp_enum = enum_pairs_init()) == NULL)
				return (-1);
			mem = 1;
			*tc = SNMP_TC_OWN;
		} else
			mem = 0;

		if (gettoken(snmptoolctx) != '(') {
			warnx("'(' expected after ENUM/BITS");
			return (-1);
		}

		if ((*tok = gettoken(snmptoolctx)) != TOK_NUM) {
			warnx("need value for ENUM//BITS");
			if (mem == 1) {
				free(*snmp_enum);
				*snmp_enum = NULL;
			}
			return (-1);
		}

		if (parse_enum(snmptoolctx, tok, *snmp_enum) < 0) {
			enum_pairs_free(*snmp_enum);
			*snmp_enum = NULL;
			return (-1);
		}

		*tok = gettoken(snmptoolctx);

	} else if (*tok == TOK_DEFTYPE) {
		struct enum_type *t;

		*tc = 0;
		t = snmp_enumtc_lookup(snmptoolctx, nexttok);
		if (t != NULL)
			*snmp_enum = t->snmp_enum;

		*tok = gettoken(snmptoolctx);

	} else {
		if ((*tok = gettoken(snmptoolctx)) == '|') {
			if (parse_subtype(snmptoolctx, tok, tc) < 0)
				return (-1);
		}
	}

	return (syntax);
}

static int32_t
snmp_import_head(struct snmp_toolinfo *snmptoolctx)
{
	enum tok tok;

	if ((tok = gettoken(snmptoolctx)) == '(')
		tok = gettoken(snmptoolctx);

	if (tok != TOK_NUM  || val > ASN_MAXID ) {
		warnx("Suboid expected - line %d", input->lno);
		return (-1);
	}

	if (gettoken(snmptoolctx) != TOK_STR) {
		warnx("Node name expected at line %d", input->lno);
		return (-1);
	}

	return (1);
}

static int32_t
snmp_import_table(struct snmp_toolinfo *snmptoolctx, struct snmp_oid2str *obj)
{
	int32_t i;
	enum snmp_tc tc;
	enum tok tok;
	struct snmp_index_entry *entry;

	if ((entry = malloc(sizeof(struct snmp_index_entry))) == NULL) {
		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
		return (-1);
	}

	memset(entry, 0, sizeof(struct snmp_index_entry));
	STAILQ_INIT(&(entry->index_list));

	for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
		int32_t syntax;
		struct enum_pairs *enums = NULL;

		if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
		    tok != TOK_BITS)
			break;

		if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
			enum_pairs_free(enums);
			snmp_index_listfree(&(entry->index_list));
			free(entry);
			return (-1);
		}

		if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
		    tc) < 0) {
			snmp_index_listfree(&(entry->index_list));
			enum_pairs_free(enums);
			free(entry);
			return (-1);
		}
	}

	if (i == 0 || i > SNMP_INDEXES_MAX) {
		warnx("Bad number of indexes at line %d", input->lno);
		snmp_index_listfree(&(entry->index_list));
		free(entry);
		return (-1);
	}

	if (tok != TOK_STR) {
		warnx("String expected after indexes at line %d", input->lno);
		snmp_index_listfree(&(entry->index_list));
		free(entry);
		return (-1);
	}

	entry->string = obj->string;
	entry->strlen = obj->strlen;
	asn_append_oid(&(entry->var), &(obj->var));

	if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
		snmp_index_listfree(&(entry->index_list));
		free(entry);
		return (-1);
	} else if (i == 0) {
		/* Same entry already present in lists. */
		free(entry->string);
		free(entry);
	}

	(void) snmp_import_update_table(ENTRY_INDEX, entry);

	return (1);
}

/*
 * Read everything after the syntax type that is certainly a leaf OID info.
 */
static int32_t
snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, enum tok *tok,
    struct snmp_oid2str *oid2str)
{
	int32_t i, syntax;

	if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
	    < 0)
		return(-1);

	oid2str->syntax = syntax;
	/*
	 * That is the name of the function, corresponding to the entry.
	 * It is used by bsnmpd, but is not interesting for us.
	 */
	if (*tok == TOK_STR)
		*tok = gettoken(snmptoolctx);

	for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
		oid2str->access |=  (uint32_t) val;
		*tok = gettoken(snmptoolctx);
	}

	if (*tok != ')') {
		warnx("')' expected at end of line %d", input->lno);
		return (-1);
	}

	oid2str->table_idx = snmp_import_update_table(ENTRY_DATA,  NULL);

	if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
		warnx("Error adding leaf %s to list", oid2str->string);
		return (-1);
	}

	/*
	 * Same entry is already present in the mapping lists and
	 * the new one was not inserted.
	 */
	if (i == 0)  {
		free(oid2str->string);
		free(oid2str);
	}

	(void) snmp_import_update_table(ENTRY_NONE, NULL);

	return (1);
}

static int32_t
snmp_import_object(struct snmp_toolinfo *snmptoolctx)
{
	char *string;
	int i;
	enum tok tok;
	struct snmp_oid2str *oid2str;

	if (snmp_import_head(snmptoolctx) < 0)
		return (-1);

	if ((oid2str = malloc(sizeof(struct snmp_oid2str))) == NULL) {
		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
		return (-1);
	}

	if ((string = malloc(strlen(nexttok) + 1)) == NULL) {
		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
		free(oid2str);
		return (-1);
	}

	memset(oid2str, 0, sizeof(struct snmp_oid2str));
	strlcpy(string, nexttok, strlen(nexttok) + 1);
	oid2str->string = string;
	oid2str->strlen = strlen(nexttok);

	asn_append_oid(&(oid2str->var), &(current_oid));
	if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
		goto error;

	/*
	 * Prepared the entry - now figure out where to insert it.
	 * After the object we have following options:
	 * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
	 * 2) new line , ( - nonleaf oid -> snmp_nodelist;
	 * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
	 *     may follow and second string must end line -> snmp_tablelist;
	 * 3) OID , string  ) - this is a trap entry or a leaf -> snmp_oidlist;
	 * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
	 *     and )- this is definitely a leaf.
	 */

	switch (tok = gettoken(snmptoolctx)) {
	    case  ')':
		if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
			goto error;
		if (i == 0) {
			free(oid2str->string);
			free(oid2str);
		}
		return (1);

	    case '(':
		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
			goto error;

		/* 
		 * Ignore the error for nodes since the .def files currently
		 * contain different strings for 1.3.6.1.2.1 - mibII. Only make
		 * sure the memory is freed and don't complain.
		 */
		if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
			free(string);
			free(oid2str);
		}
		return (snmp_import_object(snmptoolctx));

	    case ':':
		if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
			goto error;
		if (snmp_import_table(snmptoolctx, oid2str) < 0)
			goto error;
		/*
		 * A different table entry type was malloced and the data is
		 * contained there.
		 */
		free(oid2str);
		return (1);

	    case TOK_TYPE:
		/* FALLTHROUGH */
	    case TOK_DEFTYPE:
		/* FALLTHROUGH */
	    case TOK_ENUM:
	    	/* FALLTHROUGH */
	    case TOK_BITS:
		if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
				goto error;
		return (1);

	    default:
		warnx("Unexpected token at line %d - %s", input->lno,
		    input->fname);
		break;
	}

error:
	snmp_mapping_entryfree(oid2str);

	return (-1);
}

static int32_t
snmp_import_tree(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
{
	while (*tok != TOK_EOF) {
		switch (*tok) {
		    case TOK_ERR:
			return (-1);
		    case '(':
			if (snmp_import_object(snmptoolctx) < 0)
			    return (-1);
			break;
		    case ')':
			if (snmp_suboid_pop(&current_oid) < 0)
			    return (-1);
			(void) snmp_import_update_table(ENTRY_NONE, NULL);
			break;
		    default:
			/* Anything else here would be illegal. */
			return (-1);
		}
		*tok = gettoken(snmptoolctx);
	}

	return (0);
}

static int32_t
snmp_import_top(struct snmp_toolinfo *snmptoolctx, enum tok *tok)
{
	enum snmp_tc tc;
	struct enum_type *t;

	if (*tok == '(')
		return (snmp_import_tree(snmptoolctx, tok));

	if (*tok == TOK_TYPEDEF) {
		if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
			warnx("type name expected after typedef - %s",
			    input->fname);
			return (-1);
		}

		t = snmp_enumtc_init(nexttok);

		*tok = gettoken(snmptoolctx);
		t->is_enum = (*tok == TOK_ENUM);
		t->is_bits = (*tok == TOK_BITS);
		t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
		snmp_enumtc_insert(snmptoolctx, t);

		return (1);
	}

	if (*tok == TOK_INCLUDE) {
		int i;

		*tok = gettoken(snmptoolctx);
		if (*tok != TOK_FILENAME) {
			warnx("filename expected in include directive - %s",
			    nexttok);
			return (-1);
		}

		if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
			*tok = gettoken(snmptoolctx);
			return (1);
		}

		if (i == -1)
			return (-1);

		input_fopen(nexttok);
		*tok = gettoken(snmptoolctx);
		return (1);
	}

	warnx("'(' or 'typedef' expected - %s", nexttok);
	return (-1);
}

static int32_t
snmp_import(struct snmp_toolinfo *snmptoolctx)
{
	int i;
	enum tok tok;

	tok = gettoken(snmptoolctx);

	do
		i = snmp_import_top(snmptoolctx, &tok);
	while (i > 0);

	return (i);
}

/*
 * Read a .def file and import oid<->string mapping.
 * Mappings are inserted into a global structure containing list for each OID
 * syntax type.
 */
int32_t
snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
{
	int idx;

	snmp_import_init(&(file->cut));
	input_fopen(file->name);
	if ((idx = snmp_import(snmptoolctx)) < 0)
		warnx("Failed to read mappings from file %s", file->name);

	input_close();

	return (idx);
}

Man Man