]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bsnmpd/tools/libbsnmptools/bsnmpimport.c
MFstable/11 r310901:
[FreeBSD/stable/10.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 static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
144 static struct input *input = NULL;
145 static 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 static 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 static struct asn_oid current_oid;
312 static char nexttok[MAXSTR];
313 static u_long val;              /* integer values */
314 static int32_t  all_cond;       /* all conditions are true */
315 static 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, int32_t *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, int32_t *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, int32_t *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, tok;
634         enum snmp_tc tc;
635         struct snmp_index_entry *entry;
636
637         if ((entry = calloc(1, sizeof(struct snmp_index_entry))) == NULL) {
638                 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
639                 return (-1);
640         }
641
642         STAILQ_INIT(&(entry->index_list));
643
644         for (i = 0, tok = gettoken(snmptoolctx); i < SNMP_INDEXES_MAX; i++) {
645                 int32_t syntax;
646                 struct enum_pairs *enums = NULL;
647
648                 if (tok != TOK_TYPE && tok != TOK_DEFTYPE && tok != TOK_ENUM &&
649                     tok != TOK_BITS)
650                         break;
651
652                 if ((syntax = parse_type(snmptoolctx, &tok, &tc, &enums)) < 0) {
653                         enum_pairs_free(enums);
654                         snmp_index_listfree(&(entry->index_list));
655                         free(entry);
656                         return (-1);
657                 }
658
659                 if (snmp_syntax_insert(&(entry->index_list), enums, syntax,
660                     tc) < 0) {
661                         snmp_index_listfree(&(entry->index_list));
662                         enum_pairs_free(enums);
663                         free(entry);
664                         return (-1);
665                 }
666         }
667
668         if (i == 0 || i > SNMP_INDEXES_MAX) {
669                 warnx("Bad number of indexes at line %d", input->lno);
670                 snmp_index_listfree(&(entry->index_list));
671                 free(entry);
672                 return (-1);
673         }
674
675         if (tok != TOK_STR) {
676                 warnx("String expected after indexes at line %d", input->lno);
677                 snmp_index_listfree(&(entry->index_list));
678                 free(entry);
679                 return (-1);
680         }
681
682         entry->string = obj->string;
683         entry->strlen = obj->strlen;
684         asn_append_oid(&(entry->var), &(obj->var));
685
686         if ((i = snmp_table_insert(snmptoolctx, entry)) < 0) {
687                 snmp_index_listfree(&(entry->index_list));
688                 free(entry);
689                 return (-1);
690         } else if (i == 0) {
691                 /* Same entry already present in lists. */
692                 free(entry->string);
693                 free(entry);
694                 return (0);
695         }
696
697         (void) snmp_import_update_table(ENTRY_INDEX, entry);
698
699         return (1);
700 }
701
702 /*
703  * Read everything after the syntax type that is certainly a leaf OID info.
704  */
705 static int32_t
706 snmp_import_leaf(struct snmp_toolinfo *snmptoolctx, int32_t *tok,
707     struct snmp_oid2str *oid2str)
708 {
709         int32_t i, syntax;
710
711         if ((syntax = parse_type(snmptoolctx, tok, &(oid2str->tc), &(oid2str->snmp_enum)))
712             < 0)
713                 return(-1);
714
715         oid2str->syntax = syntax;
716         /*
717          * That is the name of the function, corresponding to the entry.
718          * It is used by bsnmpd, but is not interesting for us.
719          */
720         if (*tok == TOK_STR)
721                 *tok = gettoken(snmptoolctx);
722
723         for (i = 0; i < SNMP_ACCESS_GETSET && *tok == TOK_ACCESS; i++) {
724                 oid2str->access |=  (uint32_t) val;
725                 *tok = gettoken(snmptoolctx);
726         }
727
728         if (*tok != ')') {
729                 warnx("')' expected at end of line %d", input->lno);
730                 return (-1);
731         }
732
733         oid2str->table_idx = snmp_import_update_table(ENTRY_DATA,  NULL);
734
735         if ((i = snmp_leaf_insert(snmptoolctx, oid2str)) < 0) {
736                 warnx("Error adding leaf %s to list", oid2str->string);
737                 return (-1);
738         }
739
740         /*
741          * Same entry is already present in the mapping lists and
742          * the new one was not inserted.
743          */
744         if (i == 0)  {
745                 free(oid2str->string);
746                 free(oid2str);
747         }
748
749         (void) snmp_import_update_table(ENTRY_NONE, NULL);
750
751         return (1);
752 }
753
754 static int32_t
755 snmp_import_object(struct snmp_toolinfo *snmptoolctx)
756 {
757         char *string;
758         int i;
759         int32_t tok;
760         struct snmp_oid2str *oid2str;
761
762         if (snmp_import_head(snmptoolctx) < 0)
763                 return (-1);
764
765         if ((oid2str = calloc(1, sizeof(struct snmp_oid2str))) == NULL) {
766                 syslog(LOG_ERR, "calloc() failed: %s", strerror(errno));
767                 return (-1);
768         }
769
770         if ((string = strdup(nexttok)) == NULL) {
771                 syslog(LOG_ERR, "strdup() failed: %s", strerror(errno));
772                 free(oid2str);
773                 return (-1);
774         }
775
776         oid2str->string = string;
777         oid2str->strlen = strlen(nexttok);
778
779         asn_append_oid(&(oid2str->var), &(current_oid));
780         if (snmp_suboid_append(&(oid2str->var), (asn_subid_t) val) < 0)
781                 goto error;
782
783         /*
784          * Prepared the entry - now figure out where to insert it.
785          * After the object we have following options:
786          * 1) new line, blank, ) - then it is an enum oid -> snmp_enumlist;
787          * 2) new line , ( - nonleaf oid -> snmp_nodelist;
788          * 2) ':' - table entry - a variable length SYNTAX_TYPE (one or more)
789          *     may follow and second string must end line -> snmp_tablelist;
790          * 3) OID , string  ) - this is a trap entry or a leaf -> snmp_oidlist;
791          * 4) SYNTAX_TYPE, string (not always), get/set modifier - always last
792          *     and )- this is definitely a leaf.
793          */
794
795         switch (tok = gettoken(snmptoolctx)) {
796             case  ')':
797                 if ((i = snmp_enum_insert(snmptoolctx, oid2str)) < 0)
798                         goto error;
799                 if (i == 0) {
800                         free(oid2str->string);
801                         free(oid2str);
802                 }
803                 return (1);
804
805             case '(':
806                 if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
807                         goto error;
808
809                 /*
810                  * Ignore the error for nodes since the .def files currently
811                  * contain different strings for 1.3.6.1.2.1 - mibII. Only make
812                  * sure the memory is freed and don't complain.
813                  */
814                 if ((i = snmp_node_insert(snmptoolctx, oid2str)) <= 0) {
815                         free(string);
816                         free(oid2str);
817                 }
818                 return (snmp_import_object(snmptoolctx));
819
820             case ':':
821                 if (snmp_suboid_append(&current_oid, (asn_subid_t) val) < 0)
822                         goto error;
823                 if (snmp_import_table(snmptoolctx, oid2str) < 0)
824                         goto error;
825                 /*
826                  * A different table entry type was malloced and the data is
827                  * contained there.
828                  */
829                 free(oid2str);
830                 return (1);
831
832             case TOK_TYPE:
833                 /* FALLTHROUGH */
834             case TOK_DEFTYPE:
835                 /* FALLTHROUGH */
836             case TOK_ENUM:
837                 /* FALLTHROUGH */
838             case TOK_BITS:
839                 if (snmp_import_leaf(snmptoolctx, &tok, oid2str) < 0)
840                                 goto error;
841                 return (1);
842
843             default:
844                 warnx("Unexpected token at line %d - %s", input->lno,
845                     input->fname);
846                 break;
847         }
848
849 error:
850         snmp_mapping_entryfree(oid2str);
851
852         return (-1);
853 }
854
855 static int32_t
856 snmp_import_tree(struct snmp_toolinfo *snmptoolctx, int32_t *tok)
857 {
858         while (*tok != TOK_EOF) {
859                 switch (*tok) {
860                     case TOK_ERR:
861                         return (-1);
862                     case '(':
863                         if (snmp_import_object(snmptoolctx) < 0)
864                             return (-1);
865                         break;
866                     case ')':
867                         if (snmp_suboid_pop(&current_oid) < 0)
868                             return (-1);
869                         (void) snmp_import_update_table(ENTRY_NONE, NULL);
870                         break;
871                     default:
872                         /* Anything else here would be illegal. */
873                         return (-1);
874                 }
875                 *tok = gettoken(snmptoolctx);
876         }
877
878         return (0);
879 }
880
881 static int32_t
882 snmp_import_top(struct snmp_toolinfo *snmptoolctx, int32_t *tok)
883 {
884         enum snmp_tc tc;
885         struct enum_type *t;
886
887         if (*tok == '(')
888                 return (snmp_import_tree(snmptoolctx, tok));
889
890         if (*tok == TOK_TYPEDEF) {
891                 if ((*tok = gettoken(snmptoolctx)) != TOK_STR) {
892                         warnx("type name expected after typedef - %s",
893                             input->fname);
894                         return (-1);
895                 }
896
897                 t = snmp_enumtc_init(nexttok);
898
899                 *tok = gettoken(snmptoolctx);
900                 t->is_enum = (*tok == TOK_ENUM);
901                 t->is_bits = (*tok == TOK_BITS);
902                 t->syntax = parse_type(snmptoolctx, tok, &tc, &(t->snmp_enum));
903                 snmp_enumtc_insert(snmptoolctx, t);
904
905                 return (1);
906         }
907
908         if (*tok == TOK_INCLUDE) {
909                 int i;
910
911                 *tok = gettoken(snmptoolctx);
912                 if (*tok != TOK_FILENAME) {
913                         warnx("filename expected in include directive - %s",
914                             nexttok);
915                         return (-1);
916                 }
917
918                 if (( i = add_filename(snmptoolctx, nexttok, NULL, 1)) == 0) {
919                         *tok = gettoken(snmptoolctx);
920                         return (1);
921                 }
922
923                 if (i == -1)
924                         return (-1);
925
926                 input_fopen(nexttok);
927                 *tok = gettoken(snmptoolctx);
928                 return (1);
929         }
930
931         warnx("'(' or 'typedef' expected - %s", nexttok);
932         return (-1);
933 }
934
935 static int32_t
936 snmp_import(struct snmp_toolinfo *snmptoolctx)
937 {
938         int i;
939         int32_t tok;
940
941         tok = gettoken(snmptoolctx);
942
943         do
944                 i = snmp_import_top(snmptoolctx, &tok);
945         while (i > 0);
946
947         return (i);
948 }
949
950 /*
951  * Read a .def file and import oid<->string mapping.
952  * Mappings are inserted into a global structure containing list for each OID
953  * syntax type.
954  */
955 int32_t
956 snmp_import_file(struct snmp_toolinfo *snmptoolctx, struct fname *file)
957 {
958         int idx;
959
960         snmp_import_init(&(file->cut));
961         input_fopen(file->name);
962         if ((idx = snmp_import(snmptoolctx)) < 0)
963                 warnx("Failed to read mappings from file %s", file->name);
964
965         input_close();
966
967         return (idx);
968 }