]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bsnmpd / tools / libbsnmptools / bsnmpimport.c
1 /*-
2  * Copyright (c) 2006 The FreeBSD Project
3  * All rights reserved.
4  *
5  * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6  *
7  * Redistribution of this software and documentation and use in source and
8  * binary forms, with or without modification, are permitted provided that
9  * the following conditions are met:
10  *
11  * 1. Redistributions of source code or documentation must retain the above
12  *    copyright notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /*
33  * Read file containing table description - reuse magic from gensnmptree.c.
34  * Hopefully one day most of the code here will be part of libbsnmp and
35  * this duplication won't be necessary.
36  *
37  * Syntax is:
38  * ---------
39  * file := top | top file
40  *
41  * top := tree | typedef | include
42  *
43  * tree := head elements ')'
44  *
45  * entry := head ':' index STRING elements ')'
46  *
47  * leaf := head type STRING ACCESS ')'
48  *
49  * column := head type ACCESS ')'
50  *
51  * type := BASETYPE | BASETYPE '|' subtype | enum | bits
52  *
53  * subtype := STRING
54  *
55  * enum := ENUM '(' value ')'
56  * 
57  * bits := BITS '(' value ')'
58  *
59  * value := INT STRING | INT STRING value
60  *
61  * head := '(' INT STRING
62  *
63  * elements := EMPTY | elements element
64  *
65  * element := tree | leaf | column
66  *
67  * index := type | index type
68  *
69  * typedef := 'typedef' STRING type
70  *
71  * include := 'include' filespec
72  *
73  * filespec := '"' STRING '"' | '<' STRING '>'
74  */
75
76 #include <sys/param.h>
77 #include <sys/queue.h>
78 #include <sys/uio.h>
79
80 #include <ctype.h>
81 #include <err.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <syslog.h>
88 #include <unistd.h>
89
90 #include <bsnmp/asn1.h>
91 #include <bsnmp/snmp.h>
92 #include <bsnmp/snmpagent.h>    /* SNMP_INDEXES_MAX */
93 #include "bsnmptc.h"
94 #include "bsnmptools.h"
95
96 enum snmp_tbl_entry {
97         ENTRY_NONE = 0,
98         ENTRY_INDEX,
99         ENTRY_DATA
100 };
101
102 enum {
103         FL_GET  = 0x01,
104         FL_SET  = 0x02,
105 };
106
107 /************************************************************
108  *
109  * Allocate memory and panic just in the case...
110  */
111 static void *
112 xalloc(size_t size)
113 {
114         void *ptr;
115
116         if ((ptr = malloc(size)) == NULL)
117                 err(1, "allocing %zu bytes", size);
118
119         return (ptr);
120 }
121
122 static char *
123 savestr(const char *s)
124 {
125         if (s == NULL)
126                 return (NULL);
127
128         return (strcpy(xalloc(strlen(s) + 1), s));
129 }
130
131 /************************************************************
132  *
133  * Input stack
134  */
135 struct input {
136         FILE            *fp;
137         uint32_t        lno;
138         char            *fname;
139         char            *path;
140         LIST_ENTRY(input) link;
141 };
142
143 LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
144 struct input *input = NULL;
145 int32_t pbchar = -1;
146
147 #define MAX_PATHS       100
148
149 static const char *paths[MAX_PATHS + 1] = {
150         "/usr/share/snmp/defs",
151         "/usr/local/share/snmp/defs",
152         NULL
153 };
154
155 static void
156 input_new(FILE *fp, const char *path, const char *fname)
157 {
158         struct input *ip;
159
160         ip = xalloc(sizeof(*ip));
161         ip->fp = fp;
162         ip->lno = 1;
163         ip->fname = savestr(fname);
164         ip->path = savestr(path);
165         LIST_INSERT_HEAD(&inputs, ip, link);
166
167         input = ip;
168 }
169
170 static void
171 input_close(void)
172 {
173         if (input == NULL)
174                 return;
175
176         fclose(input->fp);
177         free(input->fname);
178         free(input->path);
179         LIST_REMOVE(input, link);
180         free(input);
181
182         input = LIST_FIRST(&inputs);
183 }
184
185 static FILE *
186 tryopen(const char *path, const char *fname)
187 {
188         char *fn;
189         FILE *fp;
190
191         if (path == NULL)
192                 fn = savestr(fname);
193         else {
194                 fn = xalloc(strlen(path) + strlen(fname) + 2);
195                 sprintf(fn, "%s/%s", path, fname);
196         }
197         fp = fopen(fn, "r");
198         free(fn);
199         return (fp);
200 }
201
202 static int32_t
203 input_fopen(const char *fname)
204 {
205         FILE *fp;
206         u_int p;
207
208         if (fname[0] == '/' || fname[0] == '.' || fname[0] == '~') {
209                 if ((fp = tryopen(NULL, fname)) != NULL) {
210                         input_new(fp, NULL, fname);
211                         return (0);
212                 }
213
214         } else {
215
216                 for (p = 0; paths[p] != NULL; p++)
217                         if ((fp = tryopen(paths[p], fname)) != NULL) {
218                                 input_new(fp, paths[p], fname);
219                                 return (0);
220                         }
221         }
222
223         warnx("cannot open '%s'", fname);
224         return (-1);
225 }
226
227 static int32_t
228 tgetc(void)
229 {
230         int c;
231
232         if (pbchar != -1) {
233                 c = pbchar;
234                 pbchar = -1;
235                 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
249 static int32_t
250 tungetc(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  */
264 enum 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
279 static 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
304 struct {
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
311 struct asn_oid current_oid;
312 char nexttok[MAXSTR];
313 u_long val;             /* integer values */
314 int32_t all_cond;       /* all conditions are true */
315 int32_t saved_token = -1;
316
317 /* Prepare the global data before parsing a new file. */
318 static void
319 snmp_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
333 static int32_t
334 gettoken(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  */
480 static struct snmp_index_entry *
481 snmp_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
515 static int32_t
516 parse_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
534 static int32_t
535 parse_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
549 static int32_t
550 parse_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
609 static int32_t
610 snmp_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
630 static int32_t
631 snmp_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  */
706 static int32_t
707 snmp_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
755 static int32_t
756 snmp_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
852 error:
853         snmp_mapping_entryfree(oid2str);
854
855         return (-1);
856 }
857
858 static int32_t
859 snmp_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
884 static int32_t
885 snmp_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
938 static int32_t
939 snmp_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  */
958 int32_t
959 snmp_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 }