]>
git.ipfire.org Git - thirdparty/squid.git/blob - snmplib/parse.c
1 /***********************************************************
2 Copyright 1989 by Carnegie Mellon University
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of CMU not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
14 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21 ******************************************************************/
37 #include <sys/types.h>
43 #include <gnumalloc.h>
60 #include <sys/socket.h>
63 #include <netinet/in.h>
66 #include <arpa/inet.h>
82 #include "snmp_vars.h"
84 #include "snmp_debug.h"
88 #include "cache_snmp.h"
90 * This is one element of an object identifier with either an integer subidentifier,
91 * or a textual string label, or both.
92 * The subid is -1 if not present, and label is NULL if not present.
100 * A linked list of nodes.
104 char label
[64]; /* This node's (unique) textual name */
105 u_int subid
; /* This node's integer subidentifier */
106 char parent
[64]; /* The parent's textual name */
107 int type
; /* The type of object this represents */
108 struct enum_list
*enums
; /* (optional) list of enumerated integers (otherwise NULL) */
113 /* types of tokens */
129 #define SNMP_OPAQUE 12
132 #define OF 15 /* SEQUENCE OF */
140 #define SNMP_STATUS 22
142 #define SNMP_OPTIONAL 24
144 #define RECOMMENDED 26
148 #define LEFTBRACKET 30
149 #define RIGHTBRACKET 31
151 #define RIGHTPAREN 33
153 /* For SNMPv2 SMI pseudo-compliance */
154 #define DESCRIPTION 35
159 const char *name
; /* token name */
160 int len
; /* length not counting nul */
161 int token
; /* value */
162 int hash
; /* hash of name */
163 struct tok
*next
; /* pointer to next in hash table */
167 struct tok tokens
[] = {
168 {"obsolete", sizeof("obsolete") - 1, OBSOLETE
},
169 {"Opaque", sizeof("Opaque") - 1, SNMP_OPAQUE
},
170 {"recommended", sizeof("recommended") - 1, RECOMMENDED
},
171 {"optional", sizeof("optional") - 1, SNMP_OPTIONAL
},
172 {"mandatory", sizeof("mandatory") - 1, MANDATORY
},
173 {"current", sizeof("current") - 1, MANDATORY
},
174 {"not-accessible", sizeof("not-accessible") - 1, NOACCESS
},
175 {"write-only", sizeof("write-only") - 1, WRITEONLY
},
176 {"read-write", sizeof("read-write") - 1, READWRITE
},
177 {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS
},
178 {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID
},
180 * This CONTINUE appends the next word onto OBJECT,
181 * hopefully matching OBJECTIDENTIFIER above.
183 {"OBJECT", sizeof("OBJECT") - 1, CONTINUE
},
184 {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR
},
185 {"Gauge", sizeof("Gauge") - 1, GAUGE
},
186 {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR
},
187 {"OCTET", sizeof("OCTET") - 1, -1},
188 {"OF", sizeof("OF") - 1, OF
},
189 {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE
},
190 {"NULL", sizeof("NULL") - 1, NUL
},
191 {"IpAddress", sizeof("IpAddress") - 1, IPADDR
},
192 {"INTEGER", sizeof("INTEGER") - 1, INTEGER
},
193 {"Counter", sizeof("Counter") - 1, COUNTER
},
194 {"read-only", sizeof("read-only") - 1, READONLY
},
195 {"ACCESS", sizeof("ACCESS") - 1, ACCESS
},
196 {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS
},
197 {"STATUS", sizeof("STATUS") - 1, SNMP_STATUS
},
198 {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX
},
199 {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE
},
200 {"{", sizeof("{") - 1, LEFTBRACKET
},
201 {"}", sizeof("}") - 1, RIGHTBRACKET
},
202 {"::=", sizeof("::=") - 1, EQUALS
},
203 {"(", sizeof("(") - 1, LEFTPAREN
},
204 {")", sizeof(")") - 1, RIGHTPAREN
},
205 {",", sizeof(",") - 1, COMMA
},
206 {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION
},
207 {"INDEX", sizeof("INDEX") - 1, INDEX
},
208 {"\"", sizeof("\"") - 1, QUOTE
},
209 {"END", sizeof("END") - 1, ENDOFFILE
},
210 /* Hacks for easier MIBFILE coercing */
211 {"read-create", sizeof("read-create") - 1, READWRITE
},
216 #define BUCKET(x) (x & 0x01F)
218 static struct tok
*buckets
[HASHSIZE
];
223 register struct tok
*tp
;
224 register const char *cp
;
228 memset((char *) buckets
, '\0', sizeof(buckets
));
229 for (tp
= tokens
; tp
->name
; tp
++) {
230 for (h
= 0, cp
= tp
->name
; *cp
; cp
++)
235 tp
->next
= buckets
[b
]; /* BUG ??? */
240 #define NHASHSIZE 128
241 #define NBUCKET(x) (x & 0x7F)
242 struct node
*nbuckets
[NHASHSIZE
];
245 init_node_hash(struct node
*nodes
)
247 register struct node
*np
, *nextp
;
251 memset((char *) nbuckets
, '\0', sizeof(nbuckets
));
252 for (np
= nodes
; np
;) {
255 for (cp
= np
->parent
; *cp
; cp
++)
257 np
->next
= nbuckets
[NBUCKET(hash
)];
258 nbuckets
[NBUCKET(hash
)] = np
;
265 print_error(const char *string
, const char *token
, int type
)
267 assert(string
!= NULL
);
268 if (type
== ENDOFFILE
)
269 snmplib_debug(0, "%s(EOF): On or around line %d\n", string
, Line
);
271 snmplib_debug(0, "%s(%s): On or around line %d\n", string
, token
, Line
);
273 snmplib_debug(0, "%s: On or around line %d\n", string
, Line
);
277 print_subtree(tree
, count
)
278 struct snmp_mib_tree
*tree
;
281 struct snmp_mib_tree
*tp
;
284 for (i
= 0; i
< count
; i
++)
286 printf("Children of %s:\n", tree
->label
);
288 for (tp
= tree
->child_list
; tp
; tp
= tp
->next_peer
) {
289 for (i
= 0; i
< count
; i
++)
291 printf("%s\n", tp
->label
);
293 for (tp
= tree
->child_list
; tp
; tp
= tp
->next_peer
) {
294 print_subtree(tp
, count
);
299 int translation_table
[40];
302 build_translation_table(void)
306 for (count
= 0; count
< 40; count
++) {
309 translation_table
[count
] = TYPE_OBJID
;
312 translation_table
[count
] = TYPE_OCTETSTR
;
315 translation_table
[count
] = TYPE_INTEGER
;
318 translation_table
[count
] = TYPE_IPADDR
;
321 translation_table
[count
] = TYPE_IPADDR
;
324 translation_table
[count
] = TYPE_COUNTER
;
327 translation_table
[count
] = TYPE_GAUGE
;
330 translation_table
[count
] = TYPE_TIMETICKS
;
333 translation_table
[count
] = TYPE_OPAQUE
;
336 translation_table
[count
] = TYPE_NULL
;
339 translation_table
[count
] = TYPE_OTHER
;
346 * Find all the children of root in the list of nodes. Link them into the
347 * tree and out of the nodes list.
350 do_subtree(struct snmp_mib_tree
*root
, struct node
**nodes
)
352 register struct snmp_mib_tree
*tp
;
353 struct snmp_mib_tree
*peer
= NULL
;
354 register struct node
*np
= NULL
, **headp
= NULL
;
355 struct node
*oldnp
= NULL
, *child_list
= NULL
, *childp
= NULL
;
361 for (cp
= tp
->label
; *cp
; cp
++)
363 headp
= &nbuckets
[NBUCKET(hash
)];
365 * Search each of the nodes for one whose parent is root, and
366 * move each into a separate list.
368 for (np
= *headp
; np
; np
= np
->next
) {
369 if ((*tp
->label
!= *np
->parent
) || strcmp(tp
->label
, np
->parent
)) {
370 if ((*tp
->label
== *np
->label
) && !strcmp(tp
->label
, np
->label
)) {
371 /* if there is another node with the same label, assume that
372 * any children after this point in the list belong to the other node.
373 * This adds some scoping to the table and allows vendors to
374 * reuse names such as "ip".
380 if (child_list
== NULL
) {
381 child_list
= childp
= np
; /* first entry in child list */
386 /* take this node out of the node list */
388 *headp
= np
->next
; /* fix root of node list */
390 oldnp
->next
= np
->next
; /* link around this node */
395 childp
->next
= 0; /* re-terminate list */
397 * Take each element in the child list and place it into the tree.
399 for (np
= child_list
; np
; np
= np
->next
) {
400 tp
= (struct snmp_mib_tree
*) xmalloc(sizeof(struct snmp_mib_tree
));
402 tp
->next_peer
= NULL
;
403 tp
->child_list
= NULL
;
404 strcpy(tp
->label
, np
->label
);
405 tp
->subid
= np
->subid
;
406 tp
->type
= translation_table
[np
->type
];
407 tp
->enums
= np
->enums
;
408 np
->enums
= NULL
; /* so we don't free them later */
409 if (root
->child_list
== NULL
) {
410 root
->child_list
= tp
;
412 peer
->next_peer
= tp
;
415 /* if (tp->type == TYPE_OTHER) */
416 do_subtree(tp
, nodes
); /* recurse on this child if it isn't an end node */
418 /* free all nodes that were copied into tree */
420 for (np
= child_list
; np
; np
= np
->next
) {
432 struct snmp_mib_tree
*
433 build_tree(struct node
*nodes
) {
435 struct snmp_mib_tree
*tp
;
436 int bucket
, nodes_left
= 0;
438 /* build root node */
439 tp
= (struct snmp_mib_tree
*) xmalloc(sizeof(struct snmp_mib_tree
));
441 tp
->next_peer
= NULL
;
442 tp
->child_list
= NULL
;
444 strcpy(tp
->label
, "iso");
447 build_translation_table();
448 /* grow tree from this root node */
449 init_node_hash(nodes
);
450 /* XXX nodes isn't needed in do_subtree() ??? */
451 do_subtree(tp
, &nodes
);
453 print_subtree(tp
, 0);
455 /* If any nodes are left, the tree is probably inconsistent */
456 for (bucket
= 0; bucket
< NHASHSIZE
; bucket
++) {
457 if (nbuckets
[bucket
]) {
463 snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
464 snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
465 snmplib_debug(0, "these nodes are left:\n");
466 for (bucket
= 0; bucket
< NHASHSIZE
; bucket
++) {
467 for (np
= nbuckets
[bucket
]; np
; np
= np
->next
)
468 snmplib_debug(5, "%s ::= { %s %d } (%d)\n", np
->label
, np
->parent
, np
->subid
,
477 * Parses a token from the file. The type of the token parsed is returned,
478 * and the text is placed in the string pointed to by token.
480 static char last
= ' ';
483 get_token(register FILE *fp
, register char *token
)
486 register char *cp
= token
;
487 register int hash
= 0;
488 register struct tok
*tp
;
491 ch
= (unsigned char)last
;
492 /* skip all white space */
493 while (xisspace(ch
) && ch
!= -1) {
502 * Accumulate characters until end of token is found. Then attempt to match this
503 * token as a reserved word. If a match is found, return the type. Else it is
509 if (xisspace(ch
) || ch
== '(' || ch
== ')' ||
510 ch
== '{' || ch
== '}' || ch
== ',' ||
512 if (!xisspace(ch
) && *token
== 0) {
521 for (tp
= buckets
[BUCKET(hash
)]; tp
; tp
= tp
->next
) {
522 if ((tp
->hash
== hash
) && (strcmp(tp
->name
, token
) == 0))
526 if (tp
->token
== CONTINUE
)
530 if (token
[0] == '-' && token
[1] == '-') {
532 while ((ch
= getc(fp
)) != -1)
540 return get_token(fp
, token
);
542 for (cp
= token
; *cp
; cp
++)
553 } while ((ch
= getc(fp
)) != -1);
558 * Takes a list of the form:
559 * { iso org(3) dod(6) 1 }
560 * and creates several nodes, one for each parent-child pair.
561 * Returns NULL on error.
562 * register struct subid *SubOid; an array of subids
563 * int length; the length of the array
566 getoid(register FILE *fp
, register struct subid
*SubOid
, int length
)
573 if ((type
= get_token(fp
, token
)) != LEFTBRACKET
) {
574 print_error("Expected \"{\"", token
, type
);
577 type
= get_token(fp
, token
);
578 for (count
= 0; count
< length
; count
++, SubOid
++) {
581 if (type
== RIGHTBRACKET
) {
583 } else if (type
!= LABEL
&& type
!= NUMBER
) {
584 print_error("Not valid for object identifier", token
, type
);
588 /* this entry has a label */
589 cp
= (char *) xmalloc((unsigned) strlen(token
) + 1);
592 type
= get_token(fp
, token
);
593 if (type
== LEFTPAREN
) {
594 type
= get_token(fp
, token
);
595 if (type
== NUMBER
) {
596 SubOid
->subid
= atoi(token
);
597 if ((type
= get_token(fp
, token
)) != RIGHTPAREN
) {
598 print_error("Unexpected a closing parenthesis", token
, type
);
602 print_error("Expected a number", token
, type
);
609 /* this entry has just an integer sub-identifier */
610 SubOid
->subid
= atoi(token
);
612 type
= get_token(fp
, token
);
620 free_node(struct node
*np
)
622 struct enum_list
*ep
, *tep
;
634 * Parse an entry of the form:
635 * label OBJECT IDENTIFIER ::= { parent 2 }
636 * The "label OBJECT IDENTIFIER" portion has already been parsed.
637 * Returns 0 on error.
640 parse_objectid(FILE *fp
, char *name
) {
644 register struct subid
*op
, *nop
;
646 struct subid SubOid
[32];
647 struct node
*np
, *root
, *oldnp
= NULL
;
649 type
= get_token(fp
, token
);
650 if (type
!= EQUALS
) {
651 print_error("Bad format", token
, type
);
654 if ((length
= getoid(fp
, SubOid
, 32)) != 0) {
655 np
= root
= (struct node
*) xmalloc(sizeof(struct node
));
656 memset((char *) np
, '\0', sizeof(struct node
));
658 * For each parent-child subid pair in the subid array,
659 * create a node and link it into the node list.
661 for (count
= 0, op
= SubOid
, nop
= SubOid
+ 1; count
< (length
- 2); count
++,
663 /* every node must have parent's name and child's name or number */
664 if (op
->label
&& (nop
->label
|| (nop
->subid
!= -1))) {
665 strcpy(np
->parent
, op
->label
);
667 strcpy(np
->label
, nop
->label
);
668 if (nop
->subid
!= -1)
669 np
->subid
= nop
->subid
;
672 /* set up next entry */
673 np
->next
= (struct node
*) xmalloc(sizeof(*np
->next
));
674 memset((char *) np
->next
, '\0', sizeof(struct node
));
679 np
->next
= (struct node
*) NULL
;
681 * The above loop took care of all but the last pair. This pair is taken
682 * care of here. The name for this node is taken from the label for this
684 * np still points to an unused entry.
686 if (count
== (length
- 2)) {
688 strcpy(np
->parent
, op
->label
);
689 strcpy(np
->label
, name
);
690 if (nop
->subid
!= -1)
691 np
->subid
= nop
->subid
;
693 print_error("Warning: This entry is pretty silly", np
->label
, type
);
702 print_error("Missing end of oid", (char *) NULL
, type
);
703 free_node(np
); /* the last node allocated wasn't used */
708 /* free the oid array */
709 for (count
= 0, op
= SubOid
; count
< length
; count
++, op
++) {
716 print_error("Bad object identifier", (char *) NULL
, type
);
722 * Parses an asn type. This structure is ignored by this parser.
723 * Returns NULL on error.
726 parse_asntype(FILE *fp
)
731 type
= get_token(fp
, token
);
732 if (type
!= SEQUENCE
) {
733 print_error("Not a sequence", token
, type
); /* should we handle this */
736 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
737 if (type
== RIGHTBRACKET
)
740 print_error("Expected \"}\"", token
, type
);
745 * Parses an OBJECT TYPE macro.
746 * Returns 0 on error.
749 parse_objecttype(register FILE *fp
, char *name
) {
753 struct subid SubOid
[32];
757 register struct node
*np
= NULL
;
758 register struct enum_list
*ep
= NULL
;
760 type
= get_token(fp
, token
);
761 if (type
!= SYNTAX
) {
762 print_error("Bad format for OBJECT TYPE", token
, type
);
765 np
= (struct node
*) xmalloc(sizeof(struct node
));
768 type
= get_token(fp
, token
);
769 nexttype
= get_token(fp
, nexttoken
);
773 strcpy(syntax
, token
);
774 if (nexttype
== OF
) {
776 strcat(syntax
, nexttoken
);
777 nexttype
= get_token(fp
, nexttoken
);
779 strcat(syntax
, nexttoken
);
780 nexttype
= get_token(fp
, nexttoken
);
784 strcpy(syntax
, token
);
785 if (nexttype
== LEFTBRACKET
) {
786 /* if there is an enumeration list, parse it */
787 while ((type
= get_token(fp
, token
)) != ENDOFFILE
) {
788 if (type
== RIGHTBRACKET
)
791 /* this is an enumerated label */
792 if (np
->enums
== 0) {
793 ep
= np
->enums
= (struct enum_list
*)
794 xmalloc(sizeof(struct enum_list
));
796 ep
->next
= (struct enum_list
*)
797 xmalloc(sizeof(struct enum_list
));
801 /* a reasonable approximation for the length */
802 ep
->label
= (char *) xmalloc((unsigned) strlen(token
) + 1);
803 strcpy(ep
->label
, token
);
804 type
= get_token(fp
, token
);
805 if (type
!= LEFTPAREN
) {
806 print_error("Expected \"(\"", token
, type
);
810 type
= get_token(fp
, token
);
811 if (type
!= NUMBER
) {
812 print_error("Expected integer", token
, type
);
816 ep
->value
= atoi(token
);
817 type
= get_token(fp
, token
);
818 if (type
!= RIGHTPAREN
) {
819 print_error("Expected \")\"", token
, type
);
825 if (type
== ENDOFFILE
) {
826 print_error("Expected \"}\"", token
, type
);
830 nexttype
= get_token(fp
, nexttoken
);
831 } else if (nexttype
== LEFTPAREN
) {
832 /* ignore the "constrained integer" for now */
833 nexttype
= get_token(fp
, nexttoken
);
834 nexttype
= get_token(fp
, nexttoken
);
835 nexttype
= get_token(fp
, nexttoken
);
848 strcpy(syntax
, token
);
851 print_error("Bad syntax", token
, type
);
855 if (nexttype
!= ACCESS
) {
856 print_error("Should be ACCESS", nexttoken
, nexttype
);
860 type
= get_token(fp
, token
);
861 if (type
!= READONLY
&& type
!= READWRITE
&& type
!= WRITEONLY
862 && type
!= NOACCESS
) {
863 print_error("Bad access type", nexttoken
, nexttype
);
867 type
= get_token(fp
, token
);
868 if (type
!= SNMP_STATUS
) {
869 print_error("Should be STATUS", token
, nexttype
);
873 type
= get_token(fp
, token
);
874 if (type
!= MANDATORY
&& type
!= SNMP_OPTIONAL
&& type
!= OBSOLETE
&& type
!= RECOMMENDED
) {
875 print_error("Bad status", token
, type
);
879 /* Fetch next token. Either:
881 * -> EQUALS (Old MIB format)
882 * -> DESCRIPTION, INDEX (New MIB format)
884 type
= get_token(fp
, token
);
885 if ((type
!= DESCRIPTION
) && (type
!= INDEX
) && (type
!= EQUALS
)) {
886 print_error("Should be DESCRIPTION, INDEX, or EQUALS", token
, nexttype
);
890 if (type
== DESCRIPTION
) {
892 type
= get_token(fp
, token
);
894 print_error("Should be Description open quote", token
, nexttype
);
898 /* Fetch description string */
903 /* skip everything until closing quote */
904 while ((ReadChar
!= '"') && (ReadChar
!= -1)) {
906 if (ReadChar
== '\n')
911 /* ASSERT: Done with description. */
912 type
= get_token(fp
, token
);
914 if ((type
!= INDEX
) && (type
!= EQUALS
)) {
915 print_error("Should be INDEX, or EQUALS", token
, nexttype
);
923 type
= get_token(fp
, token
);
924 if (type
!= LEFTBRACKET
) {
925 print_error("Should be INDEX left brace", token
, type
);
929 /* Fetch description string */
934 /* skip everything until closing quote */
935 while ((ReadChar
!= '}') && (ReadChar
!= -1)) {
937 if (ReadChar
== '\n')
942 /* ASSERT: Done with INDEX. */
943 type
= get_token(fp
, token
);
945 if (type
!= EQUALS
) {
946 print_error("Bad format", token
, type
);
950 length
= getoid(fp
, SubOid
, 32);
951 if (length
> 1 && length
<= 32) {
952 /* just take the last pair in the oid list */
953 if (SubOid
[length
- 2].label
)
954 strncpy(np
->parent
, SubOid
[length
- 2].label
, 64);
955 strcpy(np
->label
, name
);
956 if (SubOid
[length
- 1].subid
!= -1)
957 np
->subid
= SubOid
[length
- 1].subid
;
959 print_error("Warning: This entry is pretty silly", np
->label
, type
);
961 print_error("No end to oid", (char *) NULL
, type
);
966 for (count
= 0; count
< length
; count
++) {
967 if (SubOid
[count
].label
)
968 xfree(SubOid
[count
].label
);
969 SubOid
[count
].label
= 0;
976 * Parses a mib file and returns a linked list of nodes found in the file.
977 * Returns NULL on error.
987 struct node
*np
= NULL
, *root
= NULL
;
991 while (type
!= ENDOFFILE
) {
992 type
= get_token(fp
, token
);
994 if (type
== ENDOFFILE
) {
997 print_error(token
, "is a reserved word", type
);
1000 strncpy(name
, token
, 64);
1001 type
= get_token(fp
, token
);
1002 if (type
== OBJTYPE
) {
1004 /* first link in chain */
1005 np
= root
= parse_objecttype(fp
, name
);
1007 print_error("Bad parse of object type", (char *) NULL
, type
);
1011 np
->next
= parse_objecttype(fp
, name
);
1012 if (np
->next
== NULL
) {
1013 print_error("Bad parse of objecttype", (char *) NULL
, type
);
1017 /* now find end of chain */
1020 } else if (type
== OBJID
) {
1022 /* first link in chain */
1023 np
= root
= parse_objectid(fp
, name
);
1025 print_error("Bad parse of object id", (char *) NULL
, type
);
1029 np
->next
= parse_objectid(fp
, name
);
1030 if (np
->next
== NULL
) {
1031 print_error("Bad parse of object type", (char *) NULL
, type
);
1035 /* now find end of chain */
1038 } else if (type
== EQUALS
) {
1039 type
= parse_asntype(fp
);
1040 } else if (type
== ENDOFFILE
) {
1043 print_error("Bad operator", (char *) NULL
, type
);
1049 struct enum_list
*ep
;
1051 for (np
= root
; np
; np
= np
->next
) {
1052 printf("%s ::= { %s %d } (%d)\n", np
->label
, np
->parent
, np
->subid
,
1055 printf("Enums: \n");
1056 for (ep
= np
->enums
; ep
; ep
= ep
->next
) {
1057 printf("%s(%d)\n", ep
->label
, ep
->value
);
1066 struct snmp_mib_tree
*
1067 read_mib(char *filename
) {
1070 struct snmp_mib_tree
*tree
;
1074 fp
= fopen(filename
, "r");
1076 snmplib_debug(1, "init_mib: %s: %s\n", filename
, xstrerror());
1080 while ((p
= fgets(mbuf
, 256, fp
)) && strncmp(mbuf
, "DUMMY",
1083 snmplib_debug(0, "Bad MIB version or tag missing, install original!\n");
1086 if (!strcmp(mbuf
, "DUMMY")) {
1087 snmplib_debug(0, "You need to update your MIB!\n");
1092 snmplib_debug(0, "Mib table is bad. Exiting\n");
1095 tree
= build_tree(nodes
);