]>
Commit | Line | Data |
---|---|---|
c04fda28 | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
c04fda28 AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
85269fdf | 9 | /*********************************************************** |
f53969cc | 10 | Copyright 1989 by Carnegie Mellon University |
627f6d02 | 11 | |
12 | All Rights Reserved | |
13 | ||
26ac0430 AJ |
14 | Permission to use, copy, modify, and distribute this software and its |
15 | documentation for any purpose and without fee is hereby granted, | |
627f6d02 | 16 | provided that the above copyright notice appear in all copies and that |
26ac0430 | 17 | both that copyright notice and this permission notice appear in |
627f6d02 | 18 | supporting documentation, and that the name of CMU not be |
19 | used in advertising or publicity pertaining to distribution of the | |
26ac0430 | 20 | software without specific, written prior permission. |
627f6d02 | 21 | |
22 | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
23 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
24 | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
25 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
26 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
27 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
28 | SOFTWARE. | |
29 | ******************************************************************/ | |
9aa84e04 | 30 | |
f7f3304a | 31 | #include "squid.h" |
3d41e53a FC |
32 | #include "asn1.h" |
33 | #include "cache_snmp.h" | |
34 | #include "parse.h" | |
35 | #include "snmp_debug.h" | |
36 | #include "snmp_pdu.h" | |
37 | #include "snmp_vars.h" | |
38 | #include "util.h" | |
9aa84e04 | 39 | |
85269fdf | 40 | #if HAVE_UNISTD_H |
41 | #include <unistd.h> | |
9aa84e04 | 42 | #endif |
85269fdf | 43 | #if HAVE_STDLIB_H |
44 | #include <stdlib.h> | |
9aa84e04 | 45 | #endif |
46 | #if HAVE_SYS_TYPES_H | |
627f6d02 | 47 | #include <sys/types.h> |
9aa84e04 | 48 | #endif |
85269fdf | 49 | #if HAVE_CTYPE_H |
50 | #include <ctype.h> | |
627f6d02 | 51 | #endif |
9aa84e04 | 52 | #if HAVE_GNUMALLOC_H |
53 | #include <gnumalloc.h> | |
482aa790 | 54 | #elif HAVE_MALLOC_H |
627f6d02 | 55 | #include <malloc.h> |
9aa84e04 | 56 | #endif |
85269fdf | 57 | #if HAVE_MEMORY_H |
58 | #include <memory.h> | |
59 | #endif | |
32d002cb | 60 | #if HAVE_STRING_H |
85269fdf | 61 | #include <string.h> |
62 | #endif | |
32d002cb | 63 | #if HAVE_STRINGS_H |
85269fdf | 64 | #include <strings.h> |
65 | #endif | |
66 | #if HAVE_BSTRING_H | |
67 | #include <bstring.h> | |
68 | #endif | |
69 | #if HAVE_SYS_SOCKET_H | |
70 | #include <sys/socket.h> | |
71 | #endif | |
72 | #if HAVE_NETINET_IN_H | |
73 | #include <netinet/in.h> | |
74 | #endif | |
75 | #if HAVE_ARPA_INET_H | |
76 | #include <arpa/inet.h> | |
77 | #endif | |
78 | #if HAVE_SYS_TIME_H | |
79 | #include <sys/time.h> | |
80 | #endif | |
81 | #if HAVE_NETDB_H | |
82 | #include <netdb.h> | |
83 | #endif | |
636cbcb8 | 84 | #if HAVE_ASSERT_H |
85 | #include <assert.h> | |
86 | #endif | |
25f98340 AJ |
87 | #if HAVE_ERRNO_H |
88 | #include <errno.h> | |
89 | #endif | |
85269fdf | 90 | |
627f6d02 | 91 | /* |
85269fdf | 92 | * This is one element of an object identifier with either an integer subidentifier, |
93 | * or a textual string label, or both. | |
627f6d02 | 94 | * The subid is -1 if not present, and label is NULL if not present. |
95 | */ | |
96 | struct subid { | |
97 | int subid; | |
98 | char *label; | |
99 | }; | |
100 | ||
85269fdf | 101 | /* |
102 | * A linked list of nodes. | |
103 | */ | |
104 | struct node { | |
105 | struct node *next; | |
f53969cc SM |
106 | char label[64]; /* This node's (unique) textual name */ |
107 | u_int subid; /* This node's integer subidentifier */ | |
108 | char parent[64]; /* The parent's textual name */ | |
109 | int type; /* The type of object this represents */ | |
110 | struct enum_list *enums; /* (optional) list of enumerated integers (otherwise NULL) */ | |
85269fdf | 111 | }; |
627f6d02 | 112 | |
113 | int Line = 1; | |
114 | ||
85269fdf | 115 | /* types of tokens */ |
f53969cc | 116 | #define CONTINUE -1 |
627f6d02 | 117 | #define ENDOFFILE 0 |
f53969cc SM |
118 | #define LABEL 1 |
119 | #define SUBTREE 2 | |
120 | #define SYNTAX 3 | |
9fe245c5 | 121 | #undef OBJID |
f53969cc | 122 | #define OBJID 4 |
85269fdf | 123 | #define OCTETSTR 5 |
9fe245c5 | 124 | #undef INTEGER |
f53969cc SM |
125 | #define INTEGER 6 |
126 | #define NETADDR 7 | |
127 | #define IPADDR 8 | |
128 | #define COUNTER 9 | |
129 | #define GAUGE 10 | |
85269fdf | 130 | #define TIMETICKS 11 |
f53969cc SM |
131 | #define SNMP_OPAQUE 12 |
132 | #define NUL 13 | |
627f6d02 | 133 | #define SEQUENCE 14 |
f53969cc SM |
134 | #define OF 15 /* SEQUENCE OF */ |
135 | #define OBJTYPE 16 | |
136 | #define ACCESS 17 | |
627f6d02 | 137 | #define READONLY 18 |
138 | #define READWRITE 19 | |
f53969cc | 139 | #define WRITEONLY 20 |
9fe245c5 | 140 | #undef NOACCESS |
627f6d02 | 141 | #define NOACCESS 21 |
137a13ea | 142 | #define SNMP_STATUS 22 |
627f6d02 | 143 | #define MANDATORY 23 |
29f69185 | 144 | #define SNMP_OPTIONAL 24 |
627f6d02 | 145 | #define OBSOLETE 25 |
85269fdf | 146 | #define RECOMMENDED 26 |
f53969cc SM |
147 | #define PUNCT 27 |
148 | #define EQUALS 28 | |
149 | #define NUMBER 29 | |
627f6d02 | 150 | #define LEFTBRACKET 30 |
151 | #define RIGHTBRACKET 31 | |
f53969cc | 152 | #define LEFTPAREN 32 |
627f6d02 | 153 | #define RIGHTPAREN 33 |
f53969cc | 154 | #define COMMA 34 |
85269fdf | 155 | /* For SNMPv2 SMI pseudo-compliance */ |
627f6d02 | 156 | #define DESCRIPTION 35 |
85269fdf | 157 | #define INDEX 36 |
158 | #define QUOTE 37 | |
627f6d02 | 159 | |
160 | struct tok { | |
f53969cc SM |
161 | const char *name; /* token name */ |
162 | int len; /* length not counting nul */ | |
163 | int token; /* value */ | |
164 | int hash; /* hash of name */ | |
165 | struct tok *next; /* pointer to next in hash table */ | |
627f6d02 | 166 | }; |
167 | ||
26ac0430 | 168 | struct tok tokens[] = { |
43d4303e | 169 | {"obsolete", sizeof("obsolete") - 1, OBSOLETE}, |
29f69185 | 170 | {"Opaque", sizeof("Opaque") - 1, SNMP_OPAQUE}, |
43d4303e | 171 | {"recommended", sizeof("recommended") - 1, RECOMMENDED}, |
29f69185 | 172 | {"optional", sizeof("optional") - 1, SNMP_OPTIONAL}, |
43d4303e | 173 | {"mandatory", sizeof("mandatory") - 1, MANDATORY}, |
174 | {"current", sizeof("current") - 1, MANDATORY}, | |
175 | {"not-accessible", sizeof("not-accessible") - 1, NOACCESS}, | |
176 | {"write-only", sizeof("write-only") - 1, WRITEONLY}, | |
177 | {"read-write", sizeof("read-write") - 1, READWRITE}, | |
178 | {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS}, | |
179 | {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID}, | |
26ac0430 AJ |
180 | /* |
181 | * This CONTINUE appends the next word onto OBJECT, | |
182 | * hopefully matching OBJECTIDENTIFIER above. | |
183 | */ | |
43d4303e | 184 | {"OBJECT", sizeof("OBJECT") - 1, CONTINUE}, |
185 | {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR}, | |
186 | {"Gauge", sizeof("Gauge") - 1, GAUGE}, | |
187 | {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR}, | |
188 | {"OCTET", sizeof("OCTET") - 1, -1}, | |
189 | {"OF", sizeof("OF") - 1, OF}, | |
190 | {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE}, | |
191 | {"NULL", sizeof("NULL") - 1, NUL}, | |
192 | {"IpAddress", sizeof("IpAddress") - 1, IPADDR}, | |
193 | {"INTEGER", sizeof("INTEGER") - 1, INTEGER}, | |
194 | {"Counter", sizeof("Counter") - 1, COUNTER}, | |
195 | {"read-only", sizeof("read-only") - 1, READONLY}, | |
196 | {"ACCESS", sizeof("ACCESS") - 1, ACCESS}, | |
197 | {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS}, | |
137a13ea | 198 | {"STATUS", sizeof("STATUS") - 1, SNMP_STATUS}, |
43d4303e | 199 | {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX}, |
200 | {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE}, | |
201 | {"{", sizeof("{") - 1, LEFTBRACKET}, | |
202 | {"}", sizeof("}") - 1, RIGHTBRACKET}, | |
203 | {"::=", sizeof("::=") - 1, EQUALS}, | |
204 | {"(", sizeof("(") - 1, LEFTPAREN}, | |
205 | {")", sizeof(")") - 1, RIGHTPAREN}, | |
206 | {",", sizeof(",") - 1, COMMA}, | |
207 | {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION}, | |
208 | {"INDEX", sizeof("INDEX") - 1, INDEX}, | |
209 | {"\"", sizeof("\"") - 1, QUOTE}, | |
210 | {"END", sizeof("END") - 1, ENDOFFILE}, | |
26ac0430 | 211 | /* Hacks for easier MIBFILE coercing */ |
43d4303e | 212 | {"read-create", sizeof("read-create") - 1, READWRITE}, |
213 | {NULL} | |
627f6d02 | 214 | }; |
215 | ||
f53969cc SM |
216 | #define HASHSIZE 32 |
217 | #define BUCKET(x) (x & 0x01F) | |
627f6d02 | 218 | |
43d4303e | 219 | static struct tok *buckets[HASHSIZE]; |
627f6d02 | 220 | |
221 | static void | |
5c52f59a | 222 | hash_init(void) |
627f6d02 | 223 | { |
43d4303e | 224 | register struct tok *tp; |
5c52f59a | 225 | register const char *cp; |
43d4303e | 226 | register int h; |
227 | register int b; | |
228 | ||
229 | memset((char *) buckets, '\0', sizeof(buckets)); | |
230 | for (tp = tokens; tp->name; tp++) { | |
26ac0430 AJ |
231 | for (h = 0, cp = tp->name; *cp; cp++) |
232 | h += *cp; | |
233 | tp->hash = h; | |
234 | b = BUCKET(h); | |
235 | if (buckets[b]) | |
f53969cc | 236 | tp->next = buckets[b]; /* BUG ??? */ |
26ac0430 | 237 | buckets[b] = tp; |
43d4303e | 238 | } |
627f6d02 | 239 | } |
240 | ||
241 | #define NHASHSIZE 128 | |
242 | #define NBUCKET(x) (x & 0x7F) | |
243 | struct node *nbuckets[NHASHSIZE]; | |
244 | ||
80047df2 | 245 | static void |
5c52f59a | 246 | init_node_hash(struct node *nodes) |
627f6d02 | 247 | { |
43d4303e | 248 | register struct node *np, *nextp; |
249 | register char *cp; | |
250 | register int hash; | |
251 | ||
252 | memset((char *) nbuckets, '\0', sizeof(nbuckets)); | |
253 | for (np = nodes; np;) { | |
26ac0430 AJ |
254 | nextp = np->next; |
255 | hash = 0; | |
256 | for (cp = np->parent; *cp; cp++) | |
257 | hash += *cp; | |
258 | np->next = nbuckets[NBUCKET(hash)]; | |
259 | nbuckets[NBUCKET(hash)] = np; | |
260 | np = nextp; | |
43d4303e | 261 | } |
627f6d02 | 262 | } |
263 | ||
627f6d02 | 264 | static void |
5c52f59a | 265 | print_error(const char *string, const char *token, int type) |
627f6d02 | 266 | { |
636cbcb8 | 267 | assert(string != NULL); |
636cbcb8 | 268 | if (type == ENDOFFILE) |
26ac0430 | 269 | snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line); |
627f6d02 | 270 | else if (token) |
26ac0430 | 271 | snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line); |
627f6d02 | 272 | else |
26ac0430 | 273 | snmplib_debug(0, "%s: On or around line %d\n", string, Line); |
627f6d02 | 274 | } |
275 | ||
32d002cb | 276 | #if TEST |
85269fdf | 277 | print_subtree(tree, count) |
26ac0430 AJ |
278 | struct snmp_mib_tree *tree; |
279 | int count; | |
627f6d02 | 280 | { |
85269fdf | 281 | struct snmp_mib_tree *tp; |
627f6d02 | 282 | int i; |
283 | ||
43d4303e | 284 | for (i = 0; i < count; i++) |
26ac0430 | 285 | printf(" "); |
627f6d02 | 286 | printf("Children of %s:\n", tree->label); |
287 | count++; | |
43d4303e | 288 | for (tp = tree->child_list; tp; tp = tp->next_peer) { |
26ac0430 AJ |
289 | for (i = 0; i < count; i++) |
290 | printf(" "); | |
291 | printf("%s\n", tp->label); | |
627f6d02 | 292 | } |
43d4303e | 293 | for (tp = tree->child_list; tp; tp = tp->next_peer) { |
26ac0430 | 294 | print_subtree(tp, count); |
627f6d02 | 295 | } |
296 | } | |
297 | #endif /* TEST */ | |
298 | ||
85269fdf | 299 | int translation_table[40]; |
627f6d02 | 300 | |
80047df2 | 301 | static void |
5c52f59a | 302 | build_translation_table(void) |
43d4303e | 303 | { |
627f6d02 | 304 | int count; |
305 | ||
43d4303e | 306 | for (count = 0; count < 40; count++) { |
26ac0430 AJ |
307 | switch (count) { |
308 | case OBJID: | |
309 | translation_table[count] = TYPE_OBJID; | |
310 | break; | |
311 | case OCTETSTR: | |
312 | translation_table[count] = TYPE_OCTETSTR; | |
313 | break; | |
314 | case INTEGER: | |
315 | translation_table[count] = TYPE_INTEGER; | |
316 | break; | |
317 | case NETADDR: | |
318 | translation_table[count] = TYPE_IPADDR; | |
319 | break; | |
320 | case IPADDR: | |
321 | translation_table[count] = TYPE_IPADDR; | |
322 | break; | |
323 | case COUNTER: | |
324 | translation_table[count] = TYPE_COUNTER; | |
325 | break; | |
326 | case GAUGE: | |
327 | translation_table[count] = TYPE_GAUGE; | |
328 | break; | |
329 | case TIMETICKS: | |
330 | translation_table[count] = TYPE_TIMETICKS; | |
331 | break; | |
332 | case SNMP_OPAQUE: | |
333 | translation_table[count] = TYPE_OPAQUE; | |
334 | break; | |
335 | case NUL: | |
336 | translation_table[count] = TYPE_NULL; | |
337 | break; | |
338 | default: | |
339 | translation_table[count] = TYPE_OTHER; | |
340 | break; | |
341 | } | |
627f6d02 | 342 | } |
627f6d02 | 343 | } |
344 | ||
345 | /* | |
346 | * Find all the children of root in the list of nodes. Link them into the | |
347 | * tree and out of the nodes list. | |
348 | */ | |
349 | static void | |
5c52f59a | 350 | do_subtree(struct snmp_mib_tree *root, struct node **nodes) |
627f6d02 | 351 | { |
85269fdf | 352 | register struct snmp_mib_tree *tp; |
353 | struct snmp_mib_tree *peer = NULL; | |
43d4303e | 354 | register struct node *np = NULL, **headp = NULL; |
627f6d02 | 355 | struct node *oldnp = NULL, *child_list = NULL, *childp = NULL; |
356 | char *cp; | |
357 | int hash; | |
43d4303e | 358 | |
627f6d02 | 359 | tp = root; |
360 | hash = 0; | |
43d4303e | 361 | for (cp = tp->label; *cp; cp++) |
26ac0430 | 362 | hash += *cp; |
627f6d02 | 363 | headp = &nbuckets[NBUCKET(hash)]; |
364 | /* | |
365 | * Search each of the nodes for one whose parent is root, and | |
366 | * move each into a separate list. | |
367 | */ | |
43d4303e | 368 | for (np = *headp; np; np = np->next) { |
26ac0430 AJ |
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". | |
375 | */ | |
376 | break; | |
377 | } | |
378 | oldnp = np; | |
379 | } else { | |
380 | if (child_list == NULL) { | |
f53969cc | 381 | child_list = childp = np; /* first entry in child list */ |
26ac0430 AJ |
382 | } else { |
383 | childp->next = np; | |
384 | childp = np; | |
385 | } | |
386 | /* take this node out of the node list */ | |
387 | if (oldnp == NULL) { | |
f53969cc | 388 | *headp = np->next; /* fix root of node list */ |
26ac0430 | 389 | } else { |
f53969cc | 390 | oldnp->next = np->next; /* link around this node */ |
26ac0430 AJ |
391 | } |
392 | } | |
627f6d02 | 393 | } |
394 | if (childp) | |
f53969cc | 395 | childp->next = 0; /* re-terminate list */ |
627f6d02 | 396 | /* |
397 | * Take each element in the child list and place it into the tree. | |
398 | */ | |
43d4303e | 399 | for (np = child_list; np; np = np->next) { |
26ac0430 AJ |
400 | tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree)); |
401 | tp->parent = root; | |
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; | |
f53969cc | 408 | np->enums = NULL; /* so we don't free them later */ |
26ac0430 AJ |
409 | if (root->child_list == NULL) { |
410 | root->child_list = tp; | |
2082bd1c | 411 | } else if (peer) { |
26ac0430 AJ |
412 | peer->next_peer = tp; |
413 | } | |
414 | peer = tp; | |
415 | /* if (tp->type == TYPE_OTHER) */ | |
f53969cc | 416 | do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */ |
627f6d02 | 417 | } |
418 | /* free all nodes that were copied into tree */ | |
419 | oldnp = NULL; | |
43d4303e | 420 | for (np = child_list; np; np = np->next) { |
26ac0430 AJ |
421 | if (oldnp) |
422 | xfree(oldnp); | |
423 | oldnp = np; | |
627f6d02 | 424 | } |
425 | if (oldnp) | |
26ac0430 | 426 | xfree(oldnp); |
627f6d02 | 427 | } |
428 | ||
32d002cb | 429 | #if !TEST |
85269fdf | 430 | static |
431 | #endif | |
432 | struct snmp_mib_tree * | |
e1381638 | 433 | build_tree(struct node *nodes) { |
85269fdf | 434 | struct node *np; |
435 | struct snmp_mib_tree *tp; | |
436 | int bucket, nodes_left = 0; | |
43d4303e | 437 | |
85269fdf | 438 | /* build root node */ |
43d4303e | 439 | tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree)); |
85269fdf | 440 | tp->parent = NULL; |
441 | tp->next_peer = NULL; | |
442 | tp->child_list = NULL; | |
443 | tp->enums = NULL; | |
444 | strcpy(tp->label, "iso"); | |
445 | tp->subid = 1; | |
446 | tp->type = 0; | |
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); | |
32d002cb | 452 | #if TEST |
85269fdf | 453 | print_subtree(tp, 0); |
454 | #endif /* TEST */ | |
455 | /* If any nodes are left, the tree is probably inconsistent */ | |
43d4303e | 456 | for (bucket = 0; bucket < NHASHSIZE; bucket++) { |
26ac0430 AJ |
457 | if (nbuckets[bucket]) { |
458 | nodes_left = 1; | |
459 | break; | |
460 | } | |
85269fdf | 461 | } |
43d4303e | 462 | if (nodes_left) { |
26ac0430 AJ |
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, | |
469 | np->type); | |
470 | } | |
85269fdf | 471 | } |
472 | return tp; | |
473 | } | |
474 | ||
85269fdf | 475 | /* |
476 | * Parses a token from the file. The type of the token parsed is returned, | |
477 | * and the text is placed in the string pointed to by token. | |
478 | */ | |
479 | static char last = ' '; | |
480 | ||
481 | static int | |
5c52f59a | 482 | get_token(register FILE *fp, register char *token) |
85269fdf | 483 | { |
484 | register int ch; | |
485 | register char *cp = token; | |
486 | register int hash = 0; | |
487 | register struct tok *tp; | |
488 | ||
489 | *cp = 0; | |
ec451a0f | 490 | ch = (unsigned char)last; |
85269fdf | 491 | /* skip all white space */ |
ec451a0f | 492 | while (xisspace(ch) && ch != -1) { |
26ac0430 AJ |
493 | ch = getc(fp); |
494 | if (ch == '\n') | |
495 | Line++; | |
85269fdf | 496 | } |
497 | if (ch == -1) | |
26ac0430 | 498 | return ENDOFFILE; |
85269fdf | 499 | |
500 | /* | |
501 | * Accumulate characters until end of token is found. Then attempt to match this | |
502 | * token as a reserved word. If a match is found, return the type. Else it is | |
503 | * a label. | |
504 | */ | |
505 | do { | |
26ac0430 AJ |
506 | if (ch == '\n') |
507 | Line++; | |
508 | if (xisspace(ch) || ch == '(' || ch == ')' || | |
509 | ch == '{' || ch == '}' || ch == ',' || | |
510 | ch == '"') { | |
511 | if (!xisspace(ch) && *token == 0) { | |
512 | hash += ch; | |
513 | *cp++ = ch; | |
514 | last = ' '; | |
515 | } else { | |
516 | last = ch; | |
517 | } | |
518 | *cp = '\0'; | |
519 | ||
520 | for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) { | |
521 | if ((tp->hash == hash) && (strcmp(tp->name, token) == 0)) | |
522 | break; | |
523 | } | |
524 | if (tp) { | |
525 | if (tp->token == CONTINUE) | |
526 | continue; | |
527 | return (tp->token); | |
528 | } | |
529 | if (token[0] == '-' && token[1] == '-') { | |
530 | /* strip comment */ | |
531 | while ((ch = getc(fp)) != -1) | |
532 | if (ch == '\n') { | |
533 | Line++; | |
534 | break; | |
535 | } | |
536 | if (ch == -1) | |
537 | return ENDOFFILE; | |
538 | last = ch; | |
539 | return get_token(fp, token); | |
540 | } | |
541 | for (cp = token; *cp; cp++) | |
542 | if (!xisdigit(*cp)) | |
543 | return LABEL; | |
544 | return NUMBER; | |
545 | } else { | |
546 | hash += ch; | |
547 | *cp++ = ch; | |
548 | if (ch == '\n') | |
549 | Line++; | |
550 | } | |
43d4303e | 551 | |
85269fdf | 552 | } while ((ch = getc(fp)) != -1); |
553 | return ENDOFFILE; | |
554 | } | |
627f6d02 | 555 | |
556 | /* | |
557 | * Takes a list of the form: | |
558 | * { iso org(3) dod(6) 1 } | |
559 | * and creates several nodes, one for each parent-child pair. | |
560 | * Returns NULL on error. | |
f53969cc SM |
561 | * register struct subid *SubOid; an array of subids |
562 | * int length; the length of the array | |
627f6d02 | 563 | */ |
564 | static int | |
5c52f59a | 565 | getoid(register FILE *fp, register struct subid *SubOid, int length) |
627f6d02 | 566 | { |
85269fdf | 567 | register int count; |
627f6d02 | 568 | int type; |
85269fdf | 569 | char token[128]; |
570 | register char *cp; | |
627f6d02 | 571 | |
43d4303e | 572 | if ((type = get_token(fp, token)) != LEFTBRACKET) { |
26ac0430 AJ |
573 | print_error("Expected \"{\"", token, type); |
574 | return 0; | |
627f6d02 | 575 | } |
576 | type = get_token(fp, token); | |
43d4303e | 577 | for (count = 0; count < length; count++, SubOid++) { |
26ac0430 AJ |
578 | SubOid->label = 0; |
579 | SubOid->subid = -1; | |
580 | if (type == RIGHTBRACKET) { | |
581 | return count; | |
582 | } else if (type != LABEL && type != NUMBER) { | |
583 | print_error("Not valid for object identifier", token, type); | |
584 | return 0; | |
585 | } | |
586 | if (type == LABEL) { | |
587 | /* this entry has a label */ | |
588 | cp = (char *) xmalloc((unsigned) strlen(token) + 1); | |
589 | strcpy(cp, token); | |
590 | SubOid->label = cp; | |
591 | type = get_token(fp, token); | |
592 | if (type == LEFTPAREN) { | |
593 | type = get_token(fp, token); | |
594 | if (type == NUMBER) { | |
595 | SubOid->subid = atoi(token); | |
596 | if ((type = get_token(fp, token)) != RIGHTPAREN) { | |
597 | print_error("Unexpected a closing parenthesis", token, type); | |
598 | return 0; | |
599 | } | |
600 | } else { | |
601 | print_error("Expected a number", token, type); | |
602 | return 0; | |
603 | } | |
604 | } else { | |
605 | continue; | |
606 | } | |
607 | } else { | |
608 | /* this entry has just an integer sub-identifier */ | |
609 | SubOid->subid = atoi(token); | |
610 | } | |
611 | type = get_token(fp, token); | |
627f6d02 | 612 | } |
613 | return count; | |
614 | ||
627f6d02 | 615 | } |
616 | ||
617 | static void | |
5c52f59a | 618 | free_node(struct node *np) |
627f6d02 | 619 | { |
620 | struct enum_list *ep, *tep; | |
621 | ||
622 | ep = np->enums; | |
43d4303e | 623 | while (ep) { |
26ac0430 AJ |
624 | tep = ep; |
625 | ep = ep->next; | |
626 | xfree((char *) tep); | |
627f6d02 | 627 | } |
43d4303e | 628 | xfree((char *) np); |
627f6d02 | 629 | } |
630 | ||
2082bd1c TH |
631 | static void |
632 | free_node_list(struct node *nl) | |
633 | { | |
634 | while (nl) { | |
635 | struct node *t = nl->next; | |
636 | free_node(nl); | |
637 | nl = t; | |
638 | } | |
639 | } | |
640 | ||
627f6d02 | 641 | /* |
642 | * Parse an entry of the form: | |
643 | * label OBJECT IDENTIFIER ::= { parent 2 } | |
644 | * The "label OBJECT IDENTIFIER" portion has already been parsed. | |
645 | * Returns 0 on error. | |
646 | */ | |
647 | static struct node * | |
e1381638 | 648 | parse_objectid(FILE *fp, char *name) { |
627f6d02 | 649 | int type; |
85269fdf | 650 | char token[64]; |
651 | register int count; | |
652 | register struct subid *op, *nop; | |
627f6d02 | 653 | int length; |
85269fdf | 654 | struct subid SubOid[32]; |
627f6d02 | 655 | struct node *np, *root, *oldnp = NULL; |
656 | ||
657 | type = get_token(fp, token); | |
43d4303e | 658 | if (type != EQUALS) { |
26ac0430 AJ |
659 | print_error("Bad format", token, type); |
660 | return 0; | |
627f6d02 | 661 | } |
43d4303e | 662 | if ((length = getoid(fp, SubOid, 32)) != 0) { |
26ac0430 AJ |
663 | np = root = (struct node *) xmalloc(sizeof(struct node)); |
664 | memset((char *) np, '\0', sizeof(struct node)); | |
665 | /* | |
666 | * For each parent-child subid pair in the subid array, | |
667 | * create a node and link it into the node list. | |
668 | */ | |
669 | for (count = 0, op = SubOid, nop = SubOid + 1; count < (length - 2); count++, | |
670 | op++, nop++) { | |
671 | /* every node must have parent's name and child's name or number */ | |
672 | if (op->label && (nop->label || (nop->subid != -1))) { | |
2082bd1c | 673 | strncpy(np->parent, op->label, sizeof(np->parent) - 1); |
26ac0430 | 674 | if (nop->label) |
2082bd1c | 675 | strncpy(np->label, nop->label, sizeof(np->label) - 1); |
26ac0430 AJ |
676 | if (nop->subid != -1) |
677 | np->subid = nop->subid; | |
678 | np->type = 0; | |
679 | np->enums = 0; | |
680 | /* set up next entry */ | |
681 | np->next = (struct node *) xmalloc(sizeof(*np->next)); | |
682 | memset((char *) np->next, '\0', sizeof(struct node)); | |
683 | oldnp = np; | |
684 | np = np->next; | |
685 | } | |
686 | } | |
687 | np->next = (struct node *) NULL; | |
688 | /* | |
689 | * The above loop took care of all but the last pair. This pair is taken | |
690 | * care of here. The name for this node is taken from the label for this | |
691 | * entry. | |
692 | * np still points to an unused entry. | |
693 | */ | |
694 | if (count == (length - 2)) { | |
695 | if (op->label) { | |
268421d1 AJ |
696 | strncpy(np->parent, op->label, sizeof(np->parent)-1); |
697 | strncpy(np->label, name, sizeof(np->label)-1); | |
26ac0430 AJ |
698 | if (nop->subid != -1) |
699 | np->subid = nop->subid; | |
700 | else | |
701 | print_error("Warning: This entry is pretty silly", np->label, type); | |
702 | } else { | |
703 | free_node(np); | |
704 | if (oldnp) | |
705 | oldnp->next = NULL; | |
2082bd1c TH |
706 | else { |
707 | free_node_list(root); // we need to clear the newly allocated list | |
26ac0430 | 708 | return NULL; |
2082bd1c | 709 | } |
26ac0430 AJ |
710 | } |
711 | } else { | |
712 | print_error("Missing end of oid", (char *) NULL, type); | |
2082bd1c | 713 | free_node_list(root); // we need to clear the newly allocated list |
26ac0430 AJ |
714 | if (oldnp) |
715 | oldnp->next = NULL; | |
716 | return NULL; | |
717 | } | |
718 | /* free the oid array */ | |
719 | for (count = 0, op = SubOid; count < length; count++, op++) { | |
720 | if (op->label) | |
721 | xfree(op->label); | |
722 | op->label = 0; | |
723 | } | |
724 | return root; | |
627f6d02 | 725 | } else { |
26ac0430 AJ |
726 | print_error("Bad object identifier", (char *) NULL, type); |
727 | return 0; | |
627f6d02 | 728 | } |
729 | } | |
730 | ||
85269fdf | 731 | /* |
732 | * Parses an asn type. This structure is ignored by this parser. | |
733 | * Returns NULL on error. | |
734 | */ | |
627f6d02 | 735 | static int |
5c52f59a | 736 | parse_asntype(FILE *fp) |
627f6d02 | 737 | { |
85269fdf | 738 | int type; |
739 | char token[64]; | |
627f6d02 | 740 | |
85269fdf | 741 | type = get_token(fp, token); |
43d4303e | 742 | if (type != SEQUENCE) { |
f53969cc | 743 | print_error("Not a sequence", token, type); /* should we handle this */ |
26ac0430 | 744 | return ENDOFFILE; |
627f6d02 | 745 | } |
43d4303e | 746 | while ((type = get_token(fp, token)) != ENDOFFILE) { |
26ac0430 AJ |
747 | if (type == RIGHTBRACKET) |
748 | return type; | |
85269fdf | 749 | } |
750 | print_error("Expected \"}\"", token, type); | |
751 | return ENDOFFILE; | |
627f6d02 | 752 | } |
753 | ||
754 | /* | |
85269fdf | 755 | * Parses an OBJECT TYPE macro. |
756 | * Returns 0 on error. | |
627f6d02 | 757 | */ |
85269fdf | 758 | static struct node * |
e1381638 | 759 | parse_objecttype(register FILE *fp, char *name) { |
85269fdf | 760 | register int type; |
761 | char token[64]; | |
762 | int count, length; | |
763 | struct subid SubOid[32]; | |
764 | char syntax[64]; | |
765 | int nexttype; | |
766 | char nexttoken[64]; | |
43d4303e | 767 | register struct node *np = NULL; |
768 | register struct enum_list *ep = NULL; | |
da2d50d1 | 769 | |
627f6d02 | 770 | type = get_token(fp, token); |
43d4303e | 771 | if (type != SYNTAX) { |
26ac0430 AJ |
772 | print_error("Bad format for OBJECT TYPE", token, type); |
773 | return 0; | |
627f6d02 | 774 | } |
43d4303e | 775 | np = (struct node *) xmalloc(sizeof(struct node)); |
627f6d02 | 776 | np->next = 0; |
777 | np->enums = 0; | |
627f6d02 | 778 | type = get_token(fp, token); |
627f6d02 | 779 | nexttype = get_token(fp, nexttoken); |
85269fdf | 780 | np->type = type; |
43d4303e | 781 | switch (type) { |
782 | case SEQUENCE: | |
26ac0430 AJ |
783 | strcpy(syntax, token); |
784 | if (nexttype == OF) { | |
785 | strcat(syntax, " "); | |
786 | strcat(syntax, nexttoken); | |
787 | nexttype = get_token(fp, nexttoken); | |
788 | strcat(syntax, " "); | |
789 | strcat(syntax, nexttoken); | |
790 | nexttype = get_token(fp, nexttoken); | |
791 | } | |
792 | break; | |
43d4303e | 793 | case INTEGER: |
26ac0430 AJ |
794 | strcpy(syntax, token); |
795 | if (nexttype == LEFTBRACKET) { | |
796 | /* if there is an enumeration list, parse it */ | |
797 | while ((type = get_token(fp, token)) != ENDOFFILE) { | |
798 | if (type == RIGHTBRACKET) | |
799 | break; | |
800 | if (type == LABEL) { | |
801 | /* this is an enumerated label */ | |
802 | if (np->enums == 0) { | |
803 | ep = np->enums = (struct enum_list *) | |
804 | xmalloc(sizeof(struct enum_list)); | |
805 | } else { | |
806 | ep->next = (struct enum_list *) | |
807 | xmalloc(sizeof(struct enum_list)); | |
808 | ep = ep->next; | |
809 | } | |
810 | ep->next = 0; | |
811 | /* a reasonable approximation for the length */ | |
812 | ep->label = (char *) xmalloc((unsigned) strlen(token) + 1); | |
813 | strcpy(ep->label, token); | |
814 | type = get_token(fp, token); | |
815 | if (type != LEFTPAREN) { | |
816 | print_error("Expected \"(\"", token, type); | |
817 | free_node(np); | |
818 | return 0; | |
819 | } | |
820 | type = get_token(fp, token); | |
821 | if (type != NUMBER) { | |
822 | print_error("Expected integer", token, type); | |
823 | free_node(np); | |
824 | return 0; | |
825 | } | |
826 | ep->value = atoi(token); | |
827 | type = get_token(fp, token); | |
828 | if (type != RIGHTPAREN) { | |
829 | print_error("Expected \")\"", token, type); | |
830 | free_node(np); | |
831 | return 0; | |
832 | } | |
833 | } | |
834 | } | |
835 | if (type == ENDOFFILE) { | |
836 | print_error("Expected \"}\"", token, type); | |
837 | free_node(np); | |
838 | return 0; | |
839 | } | |
840 | nexttype = get_token(fp, nexttoken); | |
841 | } else if (nexttype == LEFTPAREN) { | |
842 | /* ignore the "constrained integer" for now */ | |
843 | nexttype = get_token(fp, nexttoken); | |
844 | nexttype = get_token(fp, nexttoken); | |
845 | nexttype = get_token(fp, nexttoken); | |
846 | } | |
847 | break; | |
43d4303e | 848 | case OBJID: |
849 | case OCTETSTR: | |
850 | case NETADDR: | |
851 | case IPADDR: | |
852 | case COUNTER: | |
853 | case GAUGE: | |
854 | case TIMETICKS: | |
29f69185 | 855 | case SNMP_OPAQUE: |
43d4303e | 856 | case NUL: |
857 | case LABEL: | |
26ac0430 AJ |
858 | strcpy(syntax, token); |
859 | break; | |
43d4303e | 860 | default: |
26ac0430 AJ |
861 | print_error("Bad syntax", token, type); |
862 | free_node(np); | |
863 | return 0; | |
627f6d02 | 864 | } |
43d4303e | 865 | if (nexttype != ACCESS) { |
26ac0430 AJ |
866 | print_error("Should be ACCESS", nexttoken, nexttype); |
867 | free_node(np); | |
868 | return 0; | |
627f6d02 | 869 | } |
870 | type = get_token(fp, token); | |
871 | if (type != READONLY && type != READWRITE && type != WRITEONLY | |
26ac0430 AJ |
872 | && type != NOACCESS) { |
873 | print_error("Bad access type", nexttoken, nexttype); | |
874 | free_node(np); | |
875 | return 0; | |
627f6d02 | 876 | } |
877 | type = get_token(fp, token); | |
137a13ea | 878 | if (type != SNMP_STATUS) { |
26ac0430 AJ |
879 | print_error("Should be STATUS", token, nexttype); |
880 | free_node(np); | |
881 | return 0; | |
627f6d02 | 882 | } |
883 | type = get_token(fp, token); | |
29f69185 | 884 | if (type != MANDATORY && type != SNMP_OPTIONAL && type != OBSOLETE && type != RECOMMENDED) { |
26ac0430 AJ |
885 | print_error("Bad status", token, type); |
886 | free_node(np); | |
887 | return 0; | |
627f6d02 | 888 | } |
85269fdf | 889 | /* Fetch next token. Either: |
890 | * | |
891 | * -> EQUALS (Old MIB format) | |
892 | * -> DESCRIPTION, INDEX (New MIB format) | |
627f6d02 | 893 | */ |
894 | type = get_token(fp, token); | |
85269fdf | 895 | if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) { |
26ac0430 AJ |
896 | print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype); |
897 | free_node(np); | |
898 | return 0; | |
43d4303e | 899 | } |
900 | if (type == DESCRIPTION) { | |
627f6d02 | 901 | |
26ac0430 AJ |
902 | type = get_token(fp, token); |
903 | if (type != QUOTE) { | |
904 | print_error("Should be Description open quote", token, nexttype); | |
905 | free_node(np); | |
906 | return 0; | |
907 | } | |
908 | /* Fetch description string */ | |
909 | { | |
910 | int ReadChar; | |
911 | ||
912 | ReadChar = last; | |
913 | /* skip everything until closing quote */ | |
914 | while ((ReadChar != '"') && (ReadChar != -1)) { | |
915 | ReadChar = getc(fp); | |
916 | if (ReadChar == '\n') | |
917 | Line++; | |
918 | } | |
919 | last = ' '; | |
920 | } | |
921 | /* ASSERT: Done with description. */ | |
922 | type = get_token(fp, token); | |
627f6d02 | 923 | } |
85269fdf | 924 | if ((type != INDEX) && (type != EQUALS)) { |
26ac0430 AJ |
925 | print_error("Should be INDEX, or EQUALS", token, nexttype); |
926 | free_node(np); | |
927 | return 0; | |
43d4303e | 928 | } |
929 | if (type == INDEX) { | |
627f6d02 | 930 | |
26ac0430 AJ |
931 | /* Scarf INDEX */ |
932 | ||
933 | type = get_token(fp, token); | |
934 | if (type != LEFTBRACKET) { | |
935 | print_error("Should be INDEX left brace", token, type); | |
936 | free_node(np); | |
937 | return 0; | |
938 | } | |
939 | /* Fetch description string */ | |
940 | { | |
941 | int ReadChar; | |
942 | ||
943 | ReadChar = last; | |
944 | /* skip everything until closing quote */ | |
945 | while ((ReadChar != '}') && (ReadChar != -1)) { | |
946 | ReadChar = getc(fp); | |
947 | if (ReadChar == '\n') | |
948 | Line++; | |
949 | } | |
950 | last = ' '; | |
951 | } | |
952 | /* ASSERT: Done with INDEX. */ | |
953 | type = get_token(fp, token); | |
627f6d02 | 954 | } |
43d4303e | 955 | if (type != EQUALS) { |
26ac0430 AJ |
956 | print_error("Bad format", token, type); |
957 | free_node(np); | |
958 | return 0; | |
627f6d02 | 959 | } |
85269fdf | 960 | length = getoid(fp, SubOid, 32); |
43d4303e | 961 | if (length > 1 && length <= 32) { |
26ac0430 | 962 | /* just take the last pair in the oid list */ |
2082bd1c | 963 | if (SubOid[length - 2].label) { |
26ac0430 | 964 | strncpy(np->parent, SubOid[length - 2].label, 64); |
2082bd1c TH |
965 | np->parent[63] = '\0'; |
966 | } | |
967 | strncpy(np->label, name, sizeof(np->label)); | |
968 | np->label[sizeof(np->label) - 1] = '\0'; | |
26ac0430 AJ |
969 | if (SubOid[length - 1].subid != -1) |
970 | np->subid = SubOid[length - 1].subid; | |
971 | else | |
972 | print_error("Warning: This entry is pretty silly", np->label, type); | |
627f6d02 | 973 | } else { |
26ac0430 AJ |
974 | print_error("No end to oid", (char *) NULL, type); |
975 | free_node(np); | |
976 | np = 0; | |
627f6d02 | 977 | } |
978 | /* free oid array */ | |
43d4303e | 979 | for (count = 0; count < length; count++) { |
26ac0430 AJ |
980 | if (SubOid[count].label) |
981 | xfree(SubOid[count].label); | |
982 | SubOid[count].label = 0; | |
627f6d02 | 983 | } |
984 | return np; | |
985 | } | |
986 | ||
627f6d02 | 987 | /* |
988 | * Parses a mib file and returns a linked list of nodes found in the file. | |
989 | * Returns NULL on error. | |
990 | */ | |
32d002cb | 991 | #if !TEST |
85269fdf | 992 | static |
993 | #endif | |
994 | struct node * | |
e1381638 | 995 | parse(FILE *fp) { |
85269fdf | 996 | char token[64]; |
997 | char name[64]; | |
43d4303e | 998 | int type = 1; |
999 | struct node *np = NULL, *root = NULL; | |
627f6d02 | 1000 | |
1001 | hash_init(); | |
627f6d02 | 1002 | |
43d4303e | 1003 | while (type != ENDOFFILE) { |
26ac0430 AJ |
1004 | type = get_token(fp, token); |
1005 | if (type != LABEL) { | |
1006 | if (type == ENDOFFILE) { | |
1007 | return root; | |
1008 | } | |
1009 | print_error(token, "is a reserved word", type); | |
2082bd1c | 1010 | free_node_list(root); |
26ac0430 AJ |
1011 | return NULL; |
1012 | } | |
1013 | strncpy(name, token, 64); | |
85494816 | 1014 | name[63] = '\0'; |
26ac0430 AJ |
1015 | type = get_token(fp, token); |
1016 | if (type == OBJTYPE) { | |
1017 | if (root == NULL) { | |
1018 | /* first link in chain */ | |
1019 | np = root = parse_objecttype(fp, name); | |
1020 | if (np == NULL) { | |
1021 | print_error("Bad parse of object type", (char *) NULL, type); | |
1022 | return NULL; | |
1023 | } | |
1024 | } else { | |
1025 | np->next = parse_objecttype(fp, name); | |
1026 | if (np->next == NULL) { | |
1027 | print_error("Bad parse of objecttype", (char *) NULL, type); | |
2082bd1c | 1028 | free_node_list(root); |
26ac0430 AJ |
1029 | return NULL; |
1030 | } | |
1031 | } | |
1032 | /* now find end of chain */ | |
1033 | while (np->next) | |
1034 | np = np->next; | |
1035 | } else if (type == OBJID) { | |
1036 | if (root == NULL) { | |
1037 | /* first link in chain */ | |
1038 | np = root = parse_objectid(fp, name); | |
1039 | if (np == NULL) { | |
1040 | print_error("Bad parse of object id", (char *) NULL, type); | |
1041 | return NULL; | |
1042 | } | |
1043 | } else { | |
1044 | np->next = parse_objectid(fp, name); | |
1045 | if (np->next == NULL) { | |
1046 | print_error("Bad parse of object type", (char *) NULL, type); | |
2082bd1c | 1047 | free_node_list(root); |
26ac0430 AJ |
1048 | return NULL; |
1049 | } | |
1050 | } | |
1051 | /* now find end of chain */ | |
1052 | while (np->next) | |
1053 | np = np->next; | |
1054 | } else if (type == EQUALS) { | |
1055 | type = parse_asntype(fp); | |
1056 | } else if (type == ENDOFFILE) { | |
1057 | break; | |
1058 | } else { | |
1059 | print_error("Bad operator", (char *) NULL, type); | |
2082bd1c | 1060 | free_node_list(root); |
26ac0430 AJ |
1061 | return NULL; |
1062 | } | |
627f6d02 | 1063 | } |
32d002cb | 1064 | #if TEST |
43d4303e | 1065 | { |
26ac0430 AJ |
1066 | struct enum_list *ep; |
1067 | ||
1068 | for (np = root; np; np = np->next) { | |
1069 | printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid, | |
1070 | np->type); | |
1071 | if (np->enums) { | |
1072 | printf("Enums: \n"); | |
1073 | for (ep = np->enums; ep; ep = ep->next) { | |
1074 | printf("%s(%d)\n", ep->label, ep->value); | |
1075 | } | |
1076 | } | |
1077 | } | |
627f6d02 | 1078 | } |
627f6d02 | 1079 | #endif /* TEST */ |
1080 | return root; | |
1081 | } | |
1082 | ||
85269fdf | 1083 | struct snmp_mib_tree * |
e1381638 | 1084 | read_mib(char *filename) { |
627f6d02 | 1085 | FILE *fp; |
1086 | struct node *nodes; | |
85269fdf | 1087 | struct snmp_mib_tree *tree; |
f658b0cc | 1088 | char mbuf[256]; |
1089 | char *p; | |
627f6d02 | 1090 | |
1091 | fp = fopen(filename, "r"); | |
b69e9ffa AJ |
1092 | if (!fp) { |
1093 | int xerrno = errno; | |
1094 | snmplib_debug(1, "init_mib: %s: %s\n", filename, xstrerr(xerrno)); | |
26ac0430 | 1095 | return (NULL); |
1f0e06c4 | 1096 | } |
43d4303e | 1097 | mbuf[0] = '\0'; |
019d3d4d | 1098 | while ((p = fgets(mbuf, 256, fp)) && strncmp(mbuf, "DUMMY", |
26ac0430 | 1099 | strlen("DUMMY"))); |
f658b0cc | 1100 | if (!p) { |
26ac0430 | 1101 | snmplib_debug(0, "Bad MIB version or tag missing, install original!\n"); |
2082bd1c | 1102 | fclose(fp); |
26ac0430 | 1103 | return NULL; |
f658b0cc | 1104 | } |
019d3d4d | 1105 | if (!strcmp(mbuf, "DUMMY")) { |
26ac0430 | 1106 | snmplib_debug(0, "You need to update your MIB!\n"); |
2082bd1c | 1107 | fclose(fp); |
26ac0430 | 1108 | return NULL; |
f658b0cc | 1109 | } |
627f6d02 | 1110 | nodes = parse(fp); |
2082bd1c | 1111 | fclose(fp); |
43d4303e | 1112 | if (!nodes) { |
26ac0430 AJ |
1113 | snmplib_debug(0, "Mib table is bad. Exiting\n"); |
1114 | return NULL; | |
627f6d02 | 1115 | } |
1116 | tree = build_tree(nodes); | |
43d4303e | 1117 | return (tree); |
627f6d02 | 1118 | } |
f53969cc | 1119 |