comparison packages/net/snmp/lib/current/src/parse.c @ 103:95f3e12a6327 ecos-sw-2000-06-23

Merge from eCos master repository on 2000-06-23-16:41:10-BST
author jlarmour
date Fri, 23 Jun 2000 17:06:31 +0000
parents
children e0c0827131d1
comparison
equal deleted inserted replaced
102:6409b6d94dd7 103:95f3e12a6327
1 //==========================================================================
2 //
3 // ./lib/current/src/parse.c
4 //
5 //
6 //==========================================================================
7 //####COPYRIGHTBEGIN####
8 //
9 // -------------------------------------------
10 // The contents of this file are subject to the Red Hat eCos Public License
11 // Version 1.1 (the "License"); you may not use this file except in
12 // compliance with the License. You may obtain a copy of the License at
13 // http://www.redhat.com/
14 //
15 // Software distributed under the License is distributed on an "AS IS"
16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
17 // License for the specific language governing rights and limitations under
18 // the License.
19 //
20 // The Original Code is eCos - Embedded Configurable Operating System,
21 // released September 30, 1998.
22 //
23 // The Initial Developer of the Original Code is Red Hat.
24 // Portions created by Red Hat are
25 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
26 // All Rights Reserved.
27 // -------------------------------------------
28 //
29 //####COPYRIGHTEND####
30 //####UCDSNMPCOPYRIGHTBEGIN####
31 //
32 // -------------------------------------------
33 //
34 // Portions of this software may have been derived from the UCD-SNMP
35 // project, <http://ucd-snmp.ucdavis.edu/> from the University of
36 // California at Davis, which was originally based on the Carnegie Mellon
37 // University SNMP implementation. Portions of this software are therefore
38 // covered by the appropriate copyright disclaimers included herein.
39 //
40 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
41 // -------------------------------------------
42 //
43 //####UCDSNMPCOPYRIGHTEND####
44 //==========================================================================
45 //#####DESCRIPTIONBEGIN####
46 //
47 // Author(s): hmt
48 // Contributors: hmt
49 // Date: 2000-05-30
50 // Purpose: Port of UCD-SNMP distribution to eCos.
51 // Description:
52 //
53 //
54 //####DESCRIPTIONEND####
55 //
56 //==========================================================================
57 /********************************************************************
58 Copyright 1989, 1991, 1992 by Carnegie Mellon University
59
60 Derivative Work -
61 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
62
63 All Rights Reserved
64
65 Permission to use, copy, modify and distribute this software and its
66 documentation for any purpose and without fee is hereby granted,
67 provided that the above copyright notice appears in all copies and
68 that both that copyright notice and this permission notice appear in
69 supporting documentation, and that the name of CMU and The Regents of
70 the University of California not be used in advertising or publicity
71 pertaining to distribution of the software without specific written
72 permission.
73
74 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
75 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
76 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR
77 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
78 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
79 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
80 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
81 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
82 *********************************************************************/
83 /*
84 * parse.c
85 *
86 * Update: 1998-09-22 <mslifcak@iss.net>
87 * Clear nbuckets in init_node_hash.
88 * New method xcalloc returns zeroed data structures.
89 * New method alloc_node encapsulates common node creation.
90 * New method to configure terminate comment at end of line.
91 * New method to configure accept underscore in labels.
92 *
93 * Update: 1998-10-10 <daves@csc.liv.ac.uk>
94 * fully qualified OID parsing patch
95 *
96 * Update: 1998-10-20 <daves@csc.liv.ac.uk>
97 * merge_anon_children patch
98 *
99 * Update: 1998-10-21 <mslifcak@iss.net>
100 * Merge_parse_objectid associates information with last node in chain.
101 */
102 /******************************************************************
103 Copyright 1989, 1991, 1992 by Carnegie Mellon University
104
105 All Rights Reserved
106
107 Permission to use, copy, modify, and distribute this software and its
108 documentation for any purpose and without fee is hereby granted,
109 provided that the above copyright notice appear in all copies and that
110 both that copyright notice and this permission notice appear in
111 supporting documentation, and that the name of CMU not be
112 used in advertising or publicity pertaining to distribution of the
113 software without specific, written prior permission.
114
115 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
116 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
117 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
118 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
119 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
120 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
121 SOFTWARE.
122 ******************************************************************/
123 #include <config.h>
124 #include <snmp_logging.h>
125 #include <stdio.h>
126 #if HAVE_STDLIB_H
127 #include <stdlib.h>
128 #endif
129 #if HAVE_STRING_H
130 #include <string.h>
131 #else
132 #include <strings.h>
133 #endif
134 #include <ctype.h>
135 #include <sys/types.h>
136 #ifndef __ECOS
137 #include <sys/stat.h>
138 #endif
139
140 /* Wow. This is ugly. -- Wes */
141 #if HAVE_DIRENT_H
142 # include <dirent.h>
143 # define NAMLEN(dirent) strlen((dirent)->d_name)
144 #else
145 # define dirent direct
146 # define NAMLEN(dirent) (dirent)->d_namlen
147 # if HAVE_SYS_NDIR_H
148 # include <sys/ndir.h>
149 # endif
150 # if HAVE_SYS_DIR_H
151 # include <sys/dir.h>
152 # endif
153 # if HAVE_NDIR_H
154 # include <ndir.h>
155 # endif
156 #endif
157 #if HAVE_WINSOCK_H
158 #include <winsock.h>
159 #endif
160 #if HAVE_NETINET_IN_H
161 #include <netinet/in.h>
162 #endif
163 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
164 #include <regex.h>
165 #endif
166 #if HAVE_DMALLOC_H
167 #include <dmalloc.h>
168 #endif
169
170 #include "system.h"
171 #include "parse.h"
172 #include "asn1.h"
173 #include "mib.h"
174 #include "snmp_api.h"
175 #include "snmp_debug.h"
176 #include "snmp_logging.h"
177 #include "default_store.h"
178 #include "tools.h"
179
180 /*
181 * This is one element of an object identifier with either an integer
182 * subidentifier, or a textual string label, or both.
183 * The subid is -1 if not present, and label is NULL if not present.
184 */
185 struct subid_s {
186 int subid;
187 int modid;
188 char *label;
189 };
190
191 #define MAXTC 1024
192 struct tc { /* textual conventions */
193 int type;
194 int modid;
195 char *descriptor;
196 char *hint;
197 struct enum_list *enums;
198 struct range_list *ranges;
199 } tclist[MAXTC];
200
201 int Line = 0;
202 const char *File = "(none)";
203 static int anonymous = 0;
204
205 #define SYNTAX_MASK 0x80
206 /* types of tokens
207 Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
208 #define CONTINUE -1
209 #define ENDOFFILE 0
210 #define LABEL 1
211 #define SUBTREE 2
212 #define SYNTAX 3
213 #define OBJID (4 | SYNTAX_MASK)
214 #define OCTETSTR (5 | SYNTAX_MASK)
215 #define INTEGER (6 | SYNTAX_MASK)
216 #define INTEGER32 INTEGER
217 #define NETADDR (7 | SYNTAX_MASK)
218 #define IPADDR (8 | SYNTAX_MASK)
219 #define COUNTER (9 | SYNTAX_MASK)
220 #define GAUGE (10 | SYNTAX_MASK)
221 #define TIMETICKS (11 | SYNTAX_MASK)
222 #define KW_OPAQUE (12 | SYNTAX_MASK)
223 #define NUL (13 | SYNTAX_MASK)
224 #define SEQUENCE 14
225 #define OF 15 /* SEQUENCE OF */
226 #define OBJTYPE 16
227 #define ACCESS 17
228 #define READONLY 18
229 #define READWRITE 19
230 #define WRITEONLY 20
231 #define NOACCESS 21
232 #define STATUS 22
233 #define MANDATORY 23
234 #define KW_OPTIONAL 24
235 #define OBSOLETE 25
236 /* #define RECOMMENDED 26 */
237 #define PUNCT 27
238 #define EQUALS 28
239 #define NUMBER 29
240 #define LEFTBRACKET 30
241 #define RIGHTBRACKET 31
242 #define LEFTPAREN 32
243 #define RIGHTPAREN 33
244 #define COMMA 34
245 #define DESCRIPTION 35
246 #define QUOTESTRING 36
247 #define INDEX 37
248 #define DEFVAL 38
249 #define DEPRECATED 39
250 #define SIZE 40
251 #define BITSTRING (41 | SYNTAX_MASK)
252 #define NSAPADDRESS (42 | SYNTAX_MASK)
253 #define COUNTER64 (43 | SYNTAX_MASK)
254 #define OBJGROUP 44
255 #define NOTIFTYPE 45
256 #define AUGMENTS 46
257 #define COMPLIANCE 47
258 #define READCREATE 48
259 #define UNITS 49
260 #define REFERENCE 50
261 #define NUM_ENTRIES 51
262 #define MODULEIDENTITY 52
263 #define LASTUPDATED 53
264 #define ORGANIZATION 54
265 #define CONTACTINFO 55
266 #define UINTEGER32 (56 | SYNTAX_MASK)
267 #define CURRENT 57
268 #define DEFINITIONS 58
269 #define END 59
270 #define SEMI 60
271 #define TRAPTYPE 61
272 #define ENTERPRISE 62
273 /* #define DISPLAYSTR (63 | SYNTAX_MASK) */
274 #define BEGIN 64
275 #define IMPORTS 65
276 #define EXPORTS 66
277 #define ACCNOTIFY 67
278 #define BAR 68
279 #define RANGE 69
280 #define CONVENTION 70
281 #define DISPLAYHINT 71
282 #define FROM 72
283 #define CAPABILITIES 73
284 #define MACRO 74
285 #define IMPLIED 75
286
287 struct tok {
288 const char *name; /* token name */
289 int len; /* length not counting nul */
290 int token; /* value */
291 int hash; /* hash of name */
292 struct tok *next; /* pointer to next in hash table */
293 };
294
295
296 static struct tok tokens[] = {
297 { "obsolete", sizeof ("obsolete")-1, OBSOLETE },
298 { "Opaque", sizeof ("Opaque")-1, KW_OPAQUE },
299 { "optional", sizeof ("optional")-1, KW_OPTIONAL },
300 { "LAST-UPDATED", sizeof ("LAST-UPDATED")-1, LASTUPDATED },
301 { "ORGANIZATION", sizeof ("ORGANIZATION")-1, ORGANIZATION },
302 { "CONTACT-INFO", sizeof ("CONTACT-INFO")-1, CONTACTINFO },
303 { "MODULE-IDENTITY", sizeof ("MODULE-IDENTITY")-1, MODULEIDENTITY },
304 { "MODULE-COMPLIANCE", sizeof ("MODULE-COMPLIANCE")-1, COMPLIANCE },
305 { "DEFINITIONS", sizeof("DEFINITIONS")-1, DEFINITIONS},
306 { "END", sizeof("END")-1, END},
307 { "AUGMENTS", sizeof ("AUGMENTS")-1, AUGMENTS },
308 { "not-accessible", sizeof ("not-accessible")-1, NOACCESS },
309 { "write-only", sizeof ("write-only")-1, WRITEONLY },
310 { "NsapAddress", sizeof("NsapAddress")-1, NSAPADDRESS},
311 { "UNITS", sizeof("Units")-1, UNITS},
312 { "REFERENCE", sizeof("REFERENCE")-1, REFERENCE},
313 { "NUM-ENTRIES", sizeof("NUM-ENTRIES")-1, NUM_ENTRIES},
314 { "BITSTRING", sizeof("BITSTRING")-1, BITSTRING},
315 { "BIT", sizeof("BIT")-1, CONTINUE},
316 { "BITS", sizeof("BITS")-1, BITSTRING},
317 { "Counter64", sizeof("Counter64")-1, COUNTER64},
318 { "TimeTicks", sizeof ("TimeTicks")-1, TIMETICKS },
319 { "NOTIFICATION-TYPE", sizeof ("NOTIFICATION-TYPE")-1, NOTIFTYPE },
320 { "OBJECT-GROUP", sizeof ("OBJECT-GROUP")-1, OBJGROUP },
321 { "OBJECT-IDENTITY", sizeof ("OBJECT-IDENTITY")-1, OBJGROUP },
322 { "OBJECTIDENTIFIER", sizeof ("OBJECTIDENTIFIER")-1, OBJID },
323 { "OBJECT", sizeof ("OBJECT")-1, CONTINUE },
324 { "NetworkAddress", sizeof ("NetworkAddress")-1, NETADDR },
325 { "Gauge", sizeof ("Gauge")-1, GAUGE },
326 { "Gauge32", sizeof ("Gauge32")-1, GAUGE },
327 { "Unsigned32", sizeof ("Unsigned32")-1, GAUGE },
328 { "read-write", sizeof ("read-write")-1, READWRITE },
329 { "read-create", sizeof ("read-create")-1, READCREATE },
330 { "OCTETSTRING", sizeof ("OCTETSTRING")-1, OCTETSTR },
331 { "OCTET", sizeof ("OCTET")-1, CONTINUE },
332 { "OF", sizeof ("OF")-1, OF },
333 { "SEQUENCE", sizeof ("SEQUENCE")-1, SEQUENCE },
334 { "NULL", sizeof ("NULL")-1, NUL },
335 { "IpAddress", sizeof ("IpAddress")-1, IPADDR },
336 { "UInteger32", sizeof ("UInteger32")-1, UINTEGER32 },
337 { "INTEGER", sizeof ("INTEGER")-1, INTEGER },
338 { "Integer32", sizeof ("Integer32")-1, INTEGER32 },
339 { "Counter", sizeof ("Counter")-1, COUNTER },
340 { "Counter32", sizeof ("Counter32")-1, COUNTER },
341 { "read-only", sizeof ("read-only")-1, READONLY },
342 { "DESCRIPTION", sizeof ("DESCRIPTION")-1, DESCRIPTION },
343 { "INDEX", sizeof ("INDEX")-1, INDEX },
344 { "DEFVAL", sizeof ("DEFVAL")-1, DEFVAL },
345 { "deprecated", sizeof ("deprecated")-1, DEPRECATED },
346 { "SIZE", sizeof ("SIZE")-1, SIZE },
347 { "MAX-ACCESS", sizeof ("MAX-ACCESS")-1, ACCESS },
348 { "ACCESS", sizeof ("ACCESS")-1, ACCESS },
349 { "mandatory", sizeof ("mandatory")-1, MANDATORY },
350 { "current", sizeof ("current")-1, CURRENT },
351 { "STATUS", sizeof ("STATUS")-1, STATUS },
352 { "SYNTAX", sizeof ("SYNTAX")-1, SYNTAX },
353 { "OBJECT-TYPE", sizeof ("OBJECT-TYPE")-1, OBJTYPE },
354 { "TRAP-TYPE", sizeof ("TRAP-TYPE")-1, TRAPTYPE },
355 { "ENTERPRISE", sizeof ("ENTERPRISE")-1, ENTERPRISE },
356 { "BEGIN", sizeof ("BEGIN")-1, BEGIN },
357 { "IMPORTS", sizeof ("IMPORTS")-1, IMPORTS },
358 { "EXPORTS", sizeof ("EXPORTS")-1, EXPORTS },
359 { "accessible-for-notify", sizeof ("accessible-for-notify")-1, ACCNOTIFY },
360 { "TEXTUAL-CONVENTION", sizeof ("TEXTUAL-CONVENTION")-1, CONVENTION },
361 { "NOTIFICATION-GROUP", sizeof ("NOTIFICATION-GROUP")-1, NOTIFTYPE },
362 { "DISPLAY-HINT", sizeof ("DISPLAY-HINT")-1, DISPLAYHINT },
363 { "FROM", sizeof ("FROM")-1, FROM },
364 { "AGENT-CAPABILITIES", sizeof ("AGENT-CAPABILITIES")-1, CAPABILITIES },
365 { "MACRO", sizeof ("MACRO")-1, MACRO },
366 { "IMPLIED", sizeof ("IMPLIED")-1, IMPLIED },
367 { NULL }
368 };
369
370 static struct module_compatability *module_map_head;
371 static struct module_compatability module_map[] = {
372 { "RFC1065-SMI", "RFC1155-SMI", NULL, 0},
373 { "RFC1066-MIB", "RFC1156-MIB", NULL, 0},
374 /* 'mib' -> 'mib-2' */
375 { "RFC1156-MIB", "RFC1158-MIB", NULL, 0},
376 /* 'snmpEnableAuthTraps' -> 'snmpEnableAuthenTraps' */
377 { "RFC1158-MIB", "RFC1213-MIB", NULL, 0},
378 /* 'nullOID' -> 'zeroDotZero' */
379 { "RFC1155-SMI", "SNMPv2-SMI", NULL, 0},
380 { "RFC1213-MIB", "SNMPv2-SMI", "mib-2", 0},
381 { "RFC1213-MIB", "SNMPv2-MIB", "sys", 3},
382 { "RFC1213-MIB", "IF-MIB", "if", 2},
383 { "RFC1213-MIB", "IP-MIB", "ip", 2},
384 { "RFC1213-MIB", "IP-MIB", "icmp", 4},
385 { "RFC1213-MIB", "TCP-MIB", "tcp", 3},
386 { "RFC1213-MIB", "UDP-MIB", "udp", 3},
387 { "RFC1213-MIB", "SNMPv2-SMI", "transmission", 0},
388 { "RFC1213-MIB", "SNMPv2-MIB", "snmp", 4},
389 { "RFC1271-MIB", "RMON-MIB", NULL, 0},
390 { "RFC1286-MIB", "SOURCE-ROUTING-MIB", "dot1dSr", 7},
391 { "RFC1286-MIB", "BRIDGE-MIB", NULL, 0},
392 { "RFC1315-MIB", "FRAME-RELAY-DTE-MIB", NULL, 0},
393 { "RFC1316-MIB", "CHARACTER-MIB", NULL, 0},
394 };
395 #define MODULE_NOT_FOUND 0
396 #define MODULE_LOADED_OK 1
397 #define MODULE_ALREADY_LOADED 2
398 /* #define MODULE_LOAD_FAILED 3 */
399 #define MODULE_LOAD_FAILED MODULE_NOT_FOUND
400
401
402 #define HASHSIZE 32
403 #define BUCKET(x) (x & (HASHSIZE-1))
404
405 #define NHASHSIZE 128
406 #define NBUCKET(x) (x & (NHASHSIZE-1))
407
408 static struct tok *buckets[HASHSIZE];
409
410 static struct node *nbuckets[NHASHSIZE];
411 static struct tree *tbuckets[NHASHSIZE];
412 static struct module *module_head = NULL;
413
414 struct node *orphan_nodes = NULL;
415 struct tree *tree_head = NULL;
416
417 #define NUMBER_OF_ROOT_NODES 3
418 static struct module_import root_imports[NUMBER_OF_ROOT_NODES];
419
420 static int current_module = 0;
421 static int max_module = 0;
422 static char *last_err_module = 0; /* no repeats on "Cannot find module..." */
423
424 static void tree_from_node(struct tree *tp, struct node *np);
425 static void do_subtree (struct tree *, struct node **);
426 static void do_linkup (struct module *, struct node *);
427 static void dump_module_list (void);
428 static int get_token (FILE *, char *, int);
429 static int parseQuoteString (FILE *, char *, int);
430 static int tossObjectIdentifier (FILE *);
431 static int name_hash (const char *);
432 static void init_node_hash (struct node *);
433 static void print_error (const char *, const char *, int);
434 static void free_tree (struct tree *);
435 static void free_partial_tree (struct tree *, int);
436 static void free_node (struct node *);
437 static void build_translation_table (void);
438 static void init_tree_roots (void);
439 static void merge_anon_children (struct tree *, struct tree *);
440 static void unlink_tbucket(struct tree *);
441 static void unlink_tree(struct tree *);
442 static int getoid (FILE *, struct subid_s *, int);
443 static struct node *parse_objectid (FILE *, char *);
444 static int get_tc (const char *, int, int *, struct enum_list **, struct range_list **, char **);
445 static int get_tc_index (const char *, int);
446 static struct enum_list *parse_enumlist (FILE *, struct enum_list **);
447 static struct range_list *parse_ranges(FILE *fp, struct range_list **);
448 static struct node *parse_asntype (FILE *, char *, int *, char *);
449 static struct node *parse_objecttype (FILE *, char *);
450 static struct node *parse_objectgroup (FILE *, char *);
451 static struct node *parse_notificationDefinition (FILE *, char *);
452 static struct node *parse_trapDefinition (FILE *, char *);
453 static struct node *parse_compliance (FILE *, char *);
454 static struct node *parse_capabilities(FILE *, char *);
455 static struct node *parse_moduleIdentity (FILE *, char *);
456 static struct node *parse_macro(FILE *, char *);
457 static void parse_imports (FILE *);
458 static struct node *parse (FILE *, struct node *);
459
460 static int read_module_internal (const char *);
461 static void read_module_replacements (const char *);
462 static void read_import_replacements (const char *, struct module_import *);
463
464 static void new_module (const char *, const char *);
465
466 static struct node *merge_parse_objectid (struct node *, FILE *, char *);
467 static struct index_list *getIndexes(FILE *fp, struct index_list **);
468 static void free_indexes(struct index_list **);
469 static void free_ranges(struct range_list **);
470 static void free_enums(struct enum_list **);
471 static struct range_list * copy_ranges(struct range_list *);
472 static struct enum_list * copy_enums(struct enum_list *);
473 static struct index_list * copy_indexes(struct index_list *);
474
475 /* backwards compatibility wrappers */
476 void snmp_set_mib_errors(int err)
477 {
478 ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_ERRORS, err);
479 }
480
481 void snmp_set_mib_warnings(int warn)
482 {
483 ds_set_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS, warn);
484 }
485
486 void snmp_set_save_descriptions(int save)
487 {
488 ds_set_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS, save);
489 }
490
491 void snmp_set_mib_comment_term(int save)
492 {
493 /* 0=strict, 1=EOL terminated */
494 ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM, save);
495 }
496
497 void snmp_set_mib_parse_label(int save)
498 {
499 /* 0=strict, 1=underscore OK in label */
500 ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL, save);
501 }
502
503 /* end wrappers */
504
505 void snmp_mib_toggle_options_usage(const char *lead, FILE *outf) {
506 fprintf(outf, "%sMIBOPTS values:\n", lead);
507 fprintf(outf, "%s u: %sallow the usage of underlines in mib symbols.\n",
508 lead, ((ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL))?"dis":""));
509 fprintf(outf, "%s c: %sallow the usage of \"--\" to terminate comments.\n",
510 lead, ((ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM))?"":"dis"));
511 fprintf(outf, "%s d: %ssave the descriptions of the mib objects.\n",
512 lead, ((ds_get_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS))?"don't ":""));
513 fprintf(outf, "%s e: Disable mib errors of MIB symbols conflicts\n",
514 lead);
515 fprintf(outf, "%s w: Enable mib warnings of MIB symbols conflicts\n",
516 lead);
517 fprintf(outf, "%s W: Enable detailed warnings of MIB symbols conflicts\n",
518 lead);
519 fprintf(outf, "%s R: Replace MIB symbols from latest module\n",
520 lead);
521 }
522
523 char *snmp_mib_toggle_options(char *options) {
524 if (options) {
525 while(*options) {
526 switch(*options) {
527 case 'u':
528 ds_set_boolean(DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL, !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL));
529 break;
530
531 case 'c':
532 ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM);
533 break;
534
535 case 'e':
536 ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_MIB_ERRORS);
537 break;
538
539 case 'w':
540 ds_set_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS, 1);
541 break;
542
543 case 'W':
544 ds_set_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS, 2);
545 break;
546
547 case 'd':
548 ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS);
549 break;
550
551 case 'R':
552 ds_toggle_boolean(DS_LIBRARY_ID, DS_LIB_MIB_REPLACE);
553 break;
554
555 default:
556 /* return at the unknown option */
557 return options;
558 }
559 options++;
560 }
561 }
562 return NULL;
563 }
564
565 static int
566 name_hash(const char* name)
567 {
568 int hash = 0;
569 const char *cp;
570
571 if (name) {
572 for(cp = name; *cp; cp++) {
573 hash += tolower(*cp);
574 }
575 }
576 return(hash);
577 }
578
579 void
580 init_mib_internals (void)
581 {
582 register struct tok *tp;
583 register int b, i;
584 int max_modc;
585
586 if (tree_head)
587 return;
588
589 /*
590 * Set up hash list of pre-defined tokens
591 */
592 memset(buckets, 0, sizeof(buckets));
593 for (tp = tokens; tp->name; tp++) {
594 tp->hash = name_hash( tp->name );
595 b = BUCKET(tp->hash);
596 if (buckets[b])
597 tp->next = buckets[b]; /* BUG ??? */
598 buckets[b] = tp;
599 }
600
601 /*
602 * Initialise other internal structures
603 */
604
605 max_modc = sizeof(module_map)/sizeof(module_map[0])-1;
606 for ( i = 0; i < max_modc; ++i )
607 module_map[i].next = &(module_map[i+1]);
608 module_map[max_modc].next = NULL;
609 module_map_head = module_map;
610
611 memset(nbuckets, 0, sizeof(nbuckets));
612 memset(tbuckets, 0, sizeof(tbuckets));
613 memset(tclist, 0, MAXTC * sizeof(struct tc));
614 build_translation_table();
615 init_tree_roots(); /* Set up initial roots */
616 /* Relies on 'add_mibdir' having set up the modules */
617 }
618
619 static void
620 init_node_hash(struct node *nodes)
621 {
622 register struct node *np, *nextp;
623 register int hash;
624
625 memset(nbuckets, 0, sizeof(nbuckets));
626 for(np = nodes; np;){
627 nextp = np->next;
628 hash = NBUCKET(name_hash(np->parent));
629 np->next = nbuckets[hash];
630 nbuckets[hash] = np;
631 np = nextp;
632 }
633 }
634
635 static int erroneousMibs = 0;
636
637 int get_mib_parse_error_count(void)
638 {
639 return erroneousMibs;
640 }
641
642
643 static void
644 print_error(const char *string,
645 const char *token,
646 int type)
647 {
648 erroneousMibs++;
649 DEBUGMSGTL(("parse-mibs", "\n"));
650 if (type == ENDOFFILE)
651 snmp_log(LOG_ERR, "%s (EOF): At line %d in %s\n", string, Line,
652 File);
653 else if (token && *token)
654 snmp_log(LOG_ERR, "%s (%s): At line %d in %s\n", string, token,
655 Line, File);
656 else
657 snmp_log(LOG_ERR, "%s: At line %d in %s\n", string, Line, File);
658 }
659
660 static void
661 print_module_not_found(const char *cp)
662 {
663 if (!last_err_module || strcmp(cp, last_err_module))
664 print_error("Cannot find module", cp, CONTINUE);
665 if (last_err_module) free(last_err_module);
666 last_err_module = strdup(cp);
667 }
668
669 static struct node *
670 alloc_node(int modid)
671 {
672 struct node *np;
673 np = (struct node *) calloc(1, sizeof(struct node));
674 if (np) {
675 np->tc_index = -1;
676 np->modid = modid;
677 }
678 return np;
679 }
680
681 static void unlink_tbucket(struct tree *tp)
682 {
683 int hash = NBUCKET(name_hash(tp->label));
684 struct tree *otp = NULL, *ntp = tbuckets[hash];
685
686 while (ntp && ntp != tp) {
687 otp = ntp; ntp = ntp->next;
688 }
689 if (!ntp) snmp_log(LOG_EMERG, "Can't find %s in tbuckets\n", tp->label);
690 else if (otp) otp->next = ntp->next;
691 else tbuckets[hash] = tp->next;
692 }
693
694 static void unlink_tree(struct tree *tp)
695 {
696 struct tree *otp = NULL, *ntp = tp->parent->child_list;
697
698 while (ntp && ntp != tp) {
699 otp = ntp; ntp = ntp->next_peer;
700 }
701 if (!ntp) snmp_log(LOG_EMERG, "Can't find %s in %s's children\n",
702 tp->label, tp->parent->label);
703 else if (otp) otp->next_peer = ntp->next_peer;
704 else tp->parent->child_list = tp->next_peer;
705 }
706
707 static void
708 free_partial_tree(struct tree *tp, int keep_label)
709 {
710 if ( !tp)
711 return;
712
713 /* remove the data from this tree node */
714 free_enums(&tp->enums);
715 free_ranges(&tp->ranges);
716 free_indexes(&tp->indexes);
717 if (!keep_label)
718 SNMP_FREE(tp->label);
719 SNMP_FREE(tp->hint);
720 SNMP_FREE(tp->units);
721 SNMP_FREE(tp->description);
722 }
723
724 /*
725 * free a tree node. Note: the node must already have been unlinked
726 * from the tree when calling this routine
727 */
728 static void
729 free_tree(struct tree *Tree)
730 {
731 if (!Tree)
732 return;
733
734 unlink_tbucket(Tree);
735 free_partial_tree (Tree, FALSE);
736 if (Tree->number_modules > 1 )
737 free((char*)Tree->module_list);
738 free ((char*)Tree);
739 }
740
741 static void
742 free_node(struct node *np)
743 {
744 if ( !np) return;
745
746 free_enums(&np->enums);
747 free_ranges(&np->ranges);
748 free_indexes(&np->indexes);
749 if (np->label) free(np->label);
750 if (np->hint) free(np->hint);
751 if (np->units) free(np->units);
752 if (np->description) free(np->description);
753 if (np->parent) free(np->parent);
754 free((char*)np);
755 }
756
757 #ifdef TEST
758 static void
759 print_nodes(FILE *fp,
760 struct node *root)
761 {
762 extern void xmalloc_stats (FILE *);
763 struct enum_list *ep;
764 struct index_list *ip;
765 struct range_list *rp;
766 struct node *np;
767
768 for(np = root; np; np = np->next){
769 fprintf(fp, "%s ::= { %s %ld } (%d)\n", np->label, np->parent,
770 np->subid, np->type);
771 if (np->tc_index >= 0)
772 fprintf(fp, " TC = %s\n", tclist[np->tc_index].descriptor);
773 if (np->enums){
774 fprintf(fp, " Enums: \n");
775 for(ep = np->enums; ep; ep = ep->next){
776 fprintf(fp, " %s(%d)\n", ep->label, ep->value);
777 }
778 }
779 if (np->ranges){
780 fprintf(fp, " Ranges: \n");
781 for(rp = np->ranges; rp; rp = rp->next){
782 fprintf(fp, " %d..%d\n", rp->low, rp->high);
783 }
784 }
785 if (np->indexes){
786 fprintf(fp, " Indexes: \n");
787 for(ip = np->indexes; ip; ip = ip->next){
788 fprintf(fp, " %s\n", ip->ilabel);
789 }
790 }
791 if (np->hint)
792 fprintf(fp, " Hint: %s\n", np->hint);
793 if (np->units)
794 fprintf(fp, " Units: %s\n", np->units);
795 }
796 }
797 #endif
798
799 void
800 print_subtree(FILE *f,
801 struct tree *tree,
802 int count)
803 {
804 struct tree *tp;
805 int i;
806 char modbuf[256];
807
808 for(i = 0; i < count; i++)
809 fprintf(f, " ");
810 fprintf(f, "Children of %s(%ld):\n", tree->label, tree->subid);
811 count++;
812 for(tp = tree->child_list; tp; tp = tp->next_peer){
813 for(i = 0; i < count; i++)
814 fprintf(f, " ");
815 fprintf(f, "%s:%s(%ld) type=%d",
816 module_name(tp->module_list[0], modbuf),
817 tp->label, tp->subid, tp->type);
818 if (tp->tc_index != -1) fprintf(f, " tc=%d", tp->tc_index);
819 if (tp->hint) fprintf(f, " hint=%s", tp->hint);
820 if (tp->units) fprintf(f, " units=%s", tp->units);
821 if (tp->number_modules > 1) {
822 fprintf(f, " modules:");
823 for (i = 1; i < tp->number_modules; i++)
824 fprintf(f, " %s", module_name(tp->module_list[i], modbuf));
825 }
826 fprintf(f, "\n");
827 }
828 for(tp = tree->child_list; tp; tp = tp->next_peer){
829 if (tp->child_list)
830 print_subtree(f, tp, count);
831 }
832 }
833
834 void
835 print_ascii_dump_tree(FILE *f,
836 struct tree *tree,
837 int count)
838 {
839 struct tree *tp;
840
841 count++;
842 for(tp = tree->child_list; tp; tp = tp->next_peer){
843 fprintf(f, "%s OBJECT IDENTIFIER ::= { %s %ld }\n", tp->label, tree->label, tp->subid);
844 }
845 for(tp = tree->child_list; tp; tp = tp->next_peer){
846 if (tp->child_list)
847 print_ascii_dump_tree(f, tp, count);
848 }
849 }
850
851 static int translation_table[256];
852
853 static void
854 build_translation_table()
855 {
856 int count;
857
858 for(count = 0; count < 256; count++){
859 switch(count){
860 case OBJID:
861 translation_table[count] = TYPE_OBJID;
862 break;
863 case OCTETSTR:
864 translation_table[count] = TYPE_OCTETSTR;
865 break;
866 case INTEGER:
867 translation_table[count] = TYPE_INTEGER;
868 break;
869 case NETADDR:
870 translation_table[count] = TYPE_IPADDR;
871 break;
872 case IPADDR:
873 translation_table[count] = TYPE_IPADDR;
874 break;
875 case COUNTER:
876 translation_table[count] = TYPE_COUNTER;
877 break;
878 case GAUGE:
879 translation_table[count] = TYPE_GAUGE;
880 break;
881 case TIMETICKS:
882 translation_table[count] = TYPE_TIMETICKS;
883 break;
884 case KW_OPAQUE:
885 translation_table[count] = TYPE_OPAQUE;
886 break;
887 case NUL:
888 translation_table[count] = TYPE_NULL;
889 break;
890 case COUNTER64:
891 translation_table[count] = TYPE_COUNTER64;
892 break;
893 case BITSTRING:
894 translation_table[count] = TYPE_BITSTRING;
895 break;
896 case NSAPADDRESS:
897 translation_table[count] = TYPE_NSAPADDRESS;
898 break;
899 case UINTEGER32:
900 translation_table[count] = TYPE_UINTEGER;
901 break;
902 default:
903 translation_table[count] = TYPE_OTHER;
904 break;
905 }
906 }
907 }
908
909 static void
910 init_tree_roots()
911 {
912 struct tree *tp, *lasttp;
913 int base_modid;
914 int hash;
915
916 base_modid = which_module("SNMPv2-SMI");
917 if (base_modid == -1 )
918 base_modid = which_module("RFC1155-SMI");
919 if (base_modid == -1 )
920 base_modid = which_module("RFC1213-MIB");
921
922 /* build root node */
923 tp = (struct tree *) calloc(1, sizeof(struct tree));
924 if (tp == NULL) return;
925 tp->label = strdup("joint-iso-ccitt");
926 tp->modid = base_modid;
927 tp->number_modules = 1;
928 tp->module_list = &(tp->modid);
929 tp->subid = 2;
930 tp->tc_index = -1;
931 set_function(tp); /* from mib.c */
932 hash = NBUCKET(name_hash(tp->label));
933 tp->next = tbuckets[hash];
934 tbuckets[hash] = tp;
935 lasttp = tp;
936 root_imports[0].label = strdup( tp->label );
937 root_imports[0].modid = base_modid;
938
939 /* build root node */
940 tp = (struct tree *) calloc(1, sizeof(struct tree));
941 if (tp == NULL) return;
942 tp->next_peer = lasttp;
943 tp->label = strdup("ccitt");
944 tp->modid = base_modid;
945 tp->number_modules = 1;
946 tp->module_list = &(tp->modid);
947 tp->subid = 0;
948 tp->tc_index = -1;
949 set_function(tp); /* from mib.c */
950 hash = NBUCKET(name_hash(tp->label));
951 tp->next = tbuckets[hash];
952 tbuckets[hash] = tp;
953 lasttp = tp;
954 root_imports[1].label = strdup( tp->label );
955 root_imports[1].modid = base_modid;
956
957 /* build root node */
958 tp = (struct tree *) calloc(1, sizeof(struct tree));
959 if (tp == NULL) return;
960 tp->next_peer = lasttp;
961 tp->label = strdup("iso");
962 tp->modid = base_modid;
963 tp->number_modules = 1;
964 tp->module_list = &(tp->modid);
965 tp->subid = 1;
966 tp->tc_index = -1;
967 set_function(tp); /* from mib.c */
968 hash = NBUCKET(name_hash(tp->label));
969 tp->next = tbuckets[hash];
970 tbuckets[hash] = tp;
971 lasttp = tp;
972 root_imports[2].label = strdup( tp->label );
973 root_imports[2].modid = base_modid;
974
975 tree_head = tp;
976 }
977
978 #ifdef STRICT_MIB_PARSEING
979 #define label_compare strcasecmp
980 #else
981 #define label_compare strcmp
982 #endif
983
984
985 struct tree *
986 find_tree_node(const char *name,
987 int modid)
988 {
989 struct tree *tp, *headtp;
990 int count, *int_p;
991
992 if (!name || !*name)
993 return(NULL);
994
995 headtp = tbuckets[NBUCKET(name_hash(name))];
996 for ( tp = headtp ; tp ; tp=tp->next ) {
997 if ( !label_compare(tp->label, name) ) {
998
999 if ( modid == -1 ) /* Any module */
1000 return(tp);
1001
1002 for (int_p = tp->module_list, count=0 ;
1003 count < tp->number_modules ;
1004 ++count, ++int_p )
1005 if ( *int_p == modid )
1006 return(tp);
1007 }
1008 }
1009
1010 return(NULL);
1011 }
1012
1013 /* computes a value which represents how close name1 is to name2.
1014 * high scores mean a worse match.
1015 * (yes, the algorithm sucks!)
1016 */
1017 #define MAX_BAD 0xffffff
1018
1019 u_int
1020 compute_match(const char *search_base, const char *key) {
1021 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1022 int rc;
1023 regex_t parsetree;
1024 regmatch_t pmatch;
1025
1026 rc=regcomp(&parsetree, key, REG_ICASE | REG_EXTENDED);
1027 if (rc == 0)
1028 rc=regexec(&parsetree, search_base, 1, &pmatch, 0);
1029 regfree(&parsetree);
1030 if (rc == 0) {
1031 /* found */
1032 return pmatch.rm_so;
1033 }
1034 #else /* use our own wildcard matcher */
1035 /* first find the longest matching substring (ick) */
1036 char *first = NULL, *result = NULL, *entry;
1037 const char *position;
1038 char *newkey = strdup(key);
1039
1040
1041 entry = strtok( newkey, "*" );
1042 position = search_base;
1043 while ( entry ) {
1044 result = strcasestr(position, entry);
1045
1046 if (result == NULL) {
1047 free(newkey);
1048 return MAX_BAD;
1049 }
1050
1051 if (first == NULL)
1052 first = result;
1053
1054 position = result + strlen(entry);
1055 entry = strtok( NULL, "*" );
1056 }
1057 free(newkey);
1058 if (result)
1059 return(first-search_base);
1060 #endif
1061
1062 /* not found */
1063 return MAX_BAD;
1064 }
1065
1066 /*
1067 * Find the tree node that best matches the pattern string.
1068 * Use the "reported" flag such that only one match
1069 * is attempted for every node.
1070 *
1071 * Warning! This function may recurse.
1072 *
1073 * Caller _must_ invoke clear_tree_flags before first call
1074 * to this function. This function may be called multiple times
1075 * to ensure that the entire tree is traversed.
1076 */
1077
1078 struct tree *
1079 find_best_tree_node(const char *pattrn, struct tree *tree_top, u_int *match)
1080 {
1081 struct tree *tp, *best_so_far = NULL, *retptr;
1082 u_int old_match=MAX_BAD, new_match=MAX_BAD;
1083
1084 if (!pattrn || !*pattrn)
1085 return(NULL);
1086
1087 if (!tree_top)
1088 tree_top = get_tree_head();
1089
1090 for ( tp = tree_top ; tp ; tp=tp->next_peer ) {
1091 if (!tp->reported)
1092 new_match = compute_match(tp->label, pattrn);
1093 tp->reported = 1;
1094
1095 if (new_match < old_match) {
1096 best_so_far = tp;
1097 old_match = new_match;
1098 }
1099 if (new_match == 0)
1100 break; /* this is the best result we can get */
1101 if (tp->child_list) {
1102 retptr = find_best_tree_node(pattrn, tp->child_list, &new_match);
1103 if (new_match < old_match) {
1104 best_so_far = retptr;
1105 old_match = new_match;
1106 }
1107 if (new_match == 0)
1108 break; /* this is the best result we can get */
1109 }
1110 }
1111
1112 if (match)
1113 *match = old_match;
1114 return(best_so_far);
1115 }
1116
1117
1118 static void
1119 merge_anon_children(struct tree *tp1,
1120 struct tree *tp2)
1121 /* NB: tp1 is the 'anonymous' node */
1122 {
1123 struct tree *child1, *child2, *previous;
1124
1125 for ( child1 = tp1->child_list ; child1 ; ) {
1126
1127 for ( child2 = tp2->child_list, previous = NULL ;
1128 child2 ; previous = child2, child2 = child2->next_peer ) {
1129
1130 if ( child1->subid == child2->subid ) {
1131 /*
1132 * Found 'matching' children,
1133 * so merge them
1134 */
1135 if ( !strncmp( child1->label, ANON, ANON_LEN)) {
1136 merge_anon_children( child1, child2 );
1137
1138 child1->child_list = NULL;
1139 previous = child1; /* Finished with 'child1' */
1140 child1 = child1->next_peer;
1141 free_tree( previous );
1142 goto next;
1143 }
1144
1145 else if ( !strncmp( child2->label, ANON, ANON_LEN)) {
1146 merge_anon_children( child2, child1 );
1147
1148 if ( previous )
1149 previous->next_peer = child2->next_peer;
1150 else
1151 tp2->child_list = child2->next_peer;
1152 free_tree(child2);
1153
1154 previous = child1; /* Move 'child1' to 'tp2' */
1155 child1 = child1->next_peer;
1156 previous->next_peer = tp2->child_list;
1157 tp2->child_list = previous;
1158 for ( previous = tp2->child_list ;
1159 previous ;
1160 previous = previous->next_peer )
1161 previous->parent = tp2;
1162 goto next;
1163 }
1164 else if ( !label_compare( child1->label, child2->label) ) {
1165 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
1166 snmp_log(LOG_WARNING, "Warning: %s.%ld is both %s and %s (%s)\n",
1167 tp2->label, child1->subid,
1168 child1->label, child2->label, File);
1169 continue;
1170 }
1171 else {
1172 /*
1173 * Two copies of the same node.
1174 * 'child2' adopts the children of 'child1'
1175 */
1176
1177 if ( child2->child_list ) {
1178 for ( previous = child2->child_list ;
1179 previous->next_peer ;
1180 previous = previous->next_peer )
1181 ; /* Find the end of the list */
1182 previous->next_peer = child1->child_list;
1183 }
1184 else
1185 child2->child_list = child1->child_list;
1186 for ( previous = child1->child_list ;
1187 previous ;
1188 previous = previous->next_peer )
1189 previous->parent = child2;
1190 child1->child_list = NULL;
1191
1192 previous = child1; /* Finished with 'child1' */
1193 child1 = child1->next_peer;
1194 free_tree( previous );
1195 goto next;
1196 }
1197 }
1198 }
1199 /*
1200 * If no match, move 'child1' to 'tp2' child_list
1201 */
1202 if ( child1 ) {
1203 previous = child1;
1204 child1 = child1->next_peer;
1205 previous->parent = tp2;
1206 previous->next_peer = tp2->child_list;
1207 tp2->child_list = previous;
1208 }
1209 next:;
1210 }
1211 }
1212
1213
1214 /*
1215 * Find all the children of root in the list of nodes. Link them into the
1216 * tree and out of the nodes list.
1217 */
1218 static void
1219 do_subtree(struct tree *root,
1220 struct node **nodes)
1221 {
1222 register struct tree *tp, *anon_tp=NULL;
1223 register struct node *np, **headp;
1224 struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
1225 int hash;
1226 int *int_p;
1227
1228 tp = root;
1229 headp = &nbuckets[NBUCKET(name_hash(tp->label))];
1230 /*
1231 * Search each of the nodes for one whose parent is root, and
1232 * move each into a separate list.
1233 */
1234 for(np = *headp; np; np = np->next){
1235 if ( !label_compare(tp->label, np->parent)){
1236 /* take this node out of the node list */
1237 if (oldnp == NULL){
1238 *headp = np->next; /* fix root of node list */
1239 } else {
1240 oldnp->next = np->next; /* link around this node */
1241 }
1242 if (child_list) childp->next = np;
1243 else child_list = np;
1244 childp = np;
1245 }
1246 else {
1247 oldnp = np;
1248 }
1249
1250 }
1251 if (childp) childp->next = NULL;
1252 /*
1253 * Take each element in the child list and place it into the tree.
1254 */
1255 for(np = child_list; np; np = np->next){
1256 anon_tp = NULL;
1257 tp = root->child_list;
1258 while (tp)
1259 if (tp->subid == np->subid) break;
1260 else tp = tp->next_peer;
1261 if (tp) {
1262 if (!label_compare (tp->label, np->label)) {
1263 /* Update list of modules */
1264 int_p = (int *) malloc((tp->number_modules+1) * sizeof(int));
1265 if (int_p == NULL) return;
1266 memcpy(int_p, tp->module_list, tp->number_modules*sizeof(int));
1267 int_p[tp->number_modules] = np->modid;
1268 if (tp->number_modules > 1 )
1269 free((char*)tp->module_list);
1270 ++tp->number_modules;
1271 tp->module_list = int_p;
1272
1273 if ( ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_REPLACE) ) {
1274 /* Replace from node */
1275 tree_from_node(tp,np);
1276 }
1277 /* Handle children */
1278 do_subtree(tp, nodes);
1279 continue;
1280 }
1281 if (!strncmp( np->label, ANON, ANON_LEN) ||
1282 !strncmp( tp->label, ANON, ANON_LEN)) {
1283 anon_tp = tp; /* Need to merge these two trees later */
1284 }
1285 else if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
1286 snmp_log(LOG_WARNING, "Warning: %s.%ld is both %s and %s (%s)\n",
1287 root->label, np->subid, tp->label, np->label, File);
1288 }
1289
1290 tp = (struct tree *) calloc(1, sizeof(struct tree));
1291 if (tp == NULL) return;
1292 tp->parent = root;
1293 tp->modid = np->modid;
1294 tp->number_modules = 1;
1295 tp->module_list = &(tp->modid);
1296 tree_from_node(tp, np);
1297 tp->next_peer = root->child_list;
1298 root->child_list = tp;
1299 hash = NBUCKET(name_hash(tp->label));
1300 tp->next = tbuckets[hash];
1301 tbuckets[hash] = tp;
1302 /* if (tp->type == TYPE_OTHER) */
1303 do_subtree(tp, nodes); /* recurse on this child if it isn't
1304 an end node */
1305 if ( anon_tp ) {
1306 if (!strncmp( tp->label, ANON, ANON_LEN)) {
1307 /*
1308 * The new node is anonymous,
1309 * so merge it with the existing one.
1310 */
1311 merge_anon_children( tp, anon_tp );
1312
1313 /* unlink and destroy tp */
1314 unlink_tree(tp);
1315 free_tree(tp);
1316 }
1317 else if (!strncmp( anon_tp->label, ANON, ANON_LEN)) {
1318 struct tree *ntp;
1319 /*
1320 * The old node was anonymous,
1321 * so merge it with the existing one,
1322 * and fill in the full information.
1323 */
1324 merge_anon_children( anon_tp, tp );
1325
1326 /* unlink anon_tp from the hash */
1327 unlink_tbucket(anon_tp);
1328
1329 /* get rid of old contents of anon_tp */
1330 free_partial_tree(anon_tp, FALSE);
1331
1332 /* put in the current information */
1333 anon_tp->label = tp->label;
1334 anon_tp->child_list = tp->child_list;
1335 anon_tp->modid = tp->modid;
1336 anon_tp->tc_index = tp->tc_index;
1337 anon_tp->type = tp->type;
1338 anon_tp->enums = tp->enums;
1339 anon_tp->indexes = tp->indexes;
1340 anon_tp->ranges = tp->ranges;
1341 anon_tp->hint = tp->hint;
1342 anon_tp->units = tp->units;
1343 anon_tp->description = tp->description;
1344 anon_tp->parent = tp->parent;
1345 set_function(anon_tp);
1346
1347 /* update parent pointer in moved children */
1348 ntp = anon_tp->child_list;
1349 while (ntp) {
1350 ntp->parent = anon_tp;
1351 ntp = ntp->next_peer;
1352 }
1353
1354 /* hash in anon_tp in its new place */
1355 hash = NBUCKET(name_hash(anon_tp->label));
1356 anon_tp->next = tbuckets[hash];
1357 tbuckets[hash] = anon_tp;
1358
1359 /* unlink and destroy tp */
1360 unlink_tbucket(tp);
1361 unlink_tree(tp);
1362 free(tp);
1363 }
1364 else {
1365 /* Uh? One of these two should have been anonymous! */
1366 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
1367 snmp_log(LOG_WARNING,
1368 "Warning: expected anonymous node (either %s or %s) in %s\n",
1369 tp->label, anon_tp->label, File);
1370 }
1371 anon_tp = NULL;
1372 }
1373 }
1374 /* free all nodes that were copied into tree */
1375 oldnp = NULL;
1376 for(np = child_list; np; np = np->next){
1377 if (oldnp)
1378 free_node(oldnp);
1379 oldnp = np;
1380 }
1381 if (oldnp)
1382 free_node(oldnp);
1383 }
1384
1385 static void do_linkup(struct module *mp,
1386 struct node *np)
1387 {
1388 struct module_import *mip;
1389 struct node *onp;
1390 struct tree *tp;
1391 int i;
1392 /*
1393 * All modules implicitly import
1394 * the roots of the tree
1395 */
1396 if (snmp_get_do_debugging() > 1) dump_module_list();
1397 DEBUGMSGTL(("parse-mibs", "Processing IMPORTS for module %d %s\n", mp->modid, mp->name));
1398 if ( mp->no_imports == 0 ) {
1399 mp->no_imports = NUMBER_OF_ROOT_NODES;
1400 mp->imports = root_imports;
1401 }
1402
1403 /*
1404 * Build the tree
1405 */
1406 init_node_hash( np );
1407 for ( i=0, mip=mp->imports ; i < mp->no_imports ; ++i, ++mip ) {
1408 char modbuf[256];
1409 DEBUGMSGTL(("parse-mibs", " Processing import: %s\n", mip->label));
1410 if (get_tc_index( mip->label, mip->modid ) != -1)
1411 continue;
1412 tp = find_tree_node( mip->label, mip->modid );
1413 if (!tp) {
1414 if (mip->modid != -1)
1415 snmp_log(LOG_WARNING, "Did not find '%s' in module %s (%s)\n",
1416 mip->label, module_name(mip->modid, modbuf), File);
1417 continue;
1418 }
1419 do_subtree( tp, &np );
1420 }
1421
1422 /*
1423 * If any nodes left over,
1424 * check that they're not the result of a "fully qualified"
1425 * name, and then add them to the list of orphans
1426 */
1427
1428 if (!np) return;
1429 for ( tp = tree_head ; tp ; tp=tp->next_peer )
1430 do_subtree( tp, &np );
1431 if (!np) return;
1432 for ( np = orphan_nodes ; np && np->next ; np = np->next )
1433 ; /* find the end of the orphan list */
1434 for (i = 0; i < NHASHSIZE; i++)
1435 if ( nbuckets[i] ) {
1436 if ( orphan_nodes )
1437 onp = np->next = nbuckets[i];
1438 else
1439 onp = orphan_nodes = nbuckets[i];
1440 nbuckets[i] = NULL;
1441 while (onp) {
1442 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
1443 snmp_log(LOG_WARNING,
1444 "Unlinked OID in %s: %s ::= { %s %ld }\n",
1445 (mp->name ? mp->name : "<no module>"),
1446 (onp->label ? onp->label : "<no label>"),
1447 (onp->parent ? onp->parent : "<no parent>"),
1448 onp->subid);
1449 np = onp;
1450 onp = onp->next;
1451 }
1452 }
1453
1454 return;
1455 }
1456
1457
1458 /*
1459 * Takes a list of the form:
1460 * { iso org(3) dod(6) 1 }
1461 * and creates several nodes, one for each parent-child pair.
1462 * Returns 0 on error.
1463 */
1464 static int
1465 getoid(FILE *fp,
1466 struct subid_s *id, /* an array of subids */
1467 int length) /* the length of the array */
1468 {
1469 register int count;
1470 int type;
1471 char token[MAXTOKEN];
1472
1473 if ((type = get_token(fp, token, MAXTOKEN)) != LEFTBRACKET){
1474 print_error("Expected \"{\"", token, type);
1475 return 0;
1476 }
1477 type = get_token(fp, token, MAXTOKEN);
1478 for(count = 0; count < length; count++, id++){
1479 id->label = NULL;
1480 id->modid = current_module;
1481 id->subid = -1;
1482 if (type == RIGHTBRACKET){
1483 return count;
1484 } else if (type != LABEL && type != NUMBER){
1485 print_error("Not valid for object identifier", token, type);
1486 return 0;
1487 }
1488 if (type == LABEL){
1489 /* this entry has a label */
1490 id->label = strdup(token);
1491 type = get_token(fp, token, MAXTOKEN);
1492 if (type == LEFTPAREN){
1493 type = get_token(fp, token, MAXTOKEN);
1494 if (type == NUMBER){
1495 id->subid = atoi(token);
1496 if ((type = get_token(fp, token, MAXTOKEN)) != RIGHTPAREN){
1497 print_error("Expected a closing parenthesis",
1498 token, type);
1499 return 0;
1500 }
1501 } else {
1502 print_error("Expected a number", token, type);
1503 return 0;
1504 }
1505 } else {
1506 continue;
1507 }
1508 } else if (type == NUMBER) {
1509 /* this entry has just an integer sub-identifier */
1510 id->subid = atoi(token);
1511 }
1512 else {
1513 print_error("Expected label or number", token, type);
1514 return 0;
1515 }
1516 type = get_token(fp, token, MAXTOKEN);
1517 }
1518 print_error ("Too long OID", token, type);
1519 return 0;
1520 }
1521
1522 /*
1523 * Parse a sequence of object subidentifiers for the given name.
1524 * The "label OBJECT IDENTIFIER ::=" portion has already been parsed.
1525 *
1526 * The majority of cases take this form :
1527 * label OBJECT IDENTIFIER ::= { parent 2 }
1528 * where a parent label and a child subidentifier number are specified.
1529 *
1530 * Variations on the theme include cases where a number appears with
1531 * the parent, or intermediate subidentifiers are specified by label,
1532 * by number, or both.
1533 *
1534 * Here are some representative samples :
1535 * internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
1536 * mgmt OBJECT IDENTIFIER ::= { internet 2 }
1537 * rptrInfoHealth OBJECT IDENTIFIER ::= { snmpDot3RptrMgt 0 4 }
1538 *
1539 * Here is a very rare form :
1540 * iso OBJECT IDENTIFIER ::= { 1 }
1541 *
1542 * Returns NULL on error. When this happens, memory may be leaked.
1543 */
1544 static struct node *
1545 parse_objectid(FILE *fp,
1546 char *name)
1547 {
1548 register int count;
1549 register struct subid_s *op, *nop;
1550 int length;
1551 struct subid_s loid[32];
1552 struct node *np, *root = NULL, *oldnp = NULL;
1553 struct tree *tp;
1554
1555 if ((length = getoid(fp, loid, 32)) == 0){
1556 print_error("Bad object identifier", NULL, CONTINUE);
1557 return NULL;
1558 }
1559
1560 /*
1561 * Handle numeric-only object identifiers,
1562 * by labelling the first sub-identifier
1563 */
1564 op = loid;
1565 if ( !op->label )
1566 for ( tp = tree_head ; tp ; tp=tp->next_peer )
1567 if ( (int)tp->subid == op->subid ) {
1568 op->label = strdup(tp->label);
1569 break;
1570 }
1571
1572 /*
1573 * Handle "label OBJECT-IDENTIFIER ::= { subid }"
1574 */
1575 if (length == 1) {
1576 op = loid;
1577 np = alloc_node(op->modid);
1578 if (np == NULL) return(NULL);
1579 np->subid = op->subid;
1580 np->label = strdup(name);
1581 if (op->label) free(op->label);
1582 return np;
1583 }
1584
1585 /*
1586 * For each parent-child subid pair in the subid array,
1587 * create a node and link it into the node list.
1588 */
1589 for(count = 0, op = loid, nop=loid+1; count < (length - 1);
1590 count++, op++, nop++){
1591 /* every node must have parent's name and child's name or number */
1592 /* XX the next statement is always true -- does it matter ?? */
1593 if (op->label && (nop->label || (nop->subid != -1))){
1594 np = alloc_node(nop->modid);
1595 if (np == NULL) return(NULL);
1596 if (root == NULL) root = np;
1597
1598 np->parent = strdup (op->label);
1599 if (count == (length - 2)) {
1600 /* The name for this node is the label for this entry */
1601 np->label = strdup (name);
1602 }
1603 else {
1604 if (!nop->label) {
1605 nop->label = (char *) malloc(20 + ANON_LEN);
1606 if (nop->label == NULL) return(NULL);
1607 sprintf(nop->label, "%s%d", ANON, anonymous++);
1608 }
1609 np->label = strdup (nop->label);
1610 }
1611 if (nop->subid != -1)
1612 np->subid = nop->subid;
1613 else
1614 print_error("Warning: This entry is pretty silly",
1615 np->label, CONTINUE);
1616
1617 /* set up next entry */
1618 if (oldnp) oldnp->next = np;
1619 oldnp = np;
1620 } /* end if(op->label... */
1621 }
1622
1623 /* free the loid array */
1624 for(count = 0, op = loid; count < length; count++, op++){
1625 if (op->label)
1626 free(op->label);
1627 }
1628
1629 return root;
1630 }
1631
1632 static int
1633 get_tc(const char *descriptor,
1634 int modid,
1635 int *tc_index,
1636 struct enum_list **ep,
1637 struct range_list **rp,
1638 char **hint)
1639 {
1640 int i;
1641 struct tc *tcp;
1642
1643 i = get_tc_index(descriptor, modid);
1644 if (tc_index) *tc_index = i;
1645 if (i != -1)
1646 {
1647 tcp = &tclist[i];
1648 if (ep) {
1649 free_enums(ep);
1650 *ep = copy_enums(tcp->enums);
1651 }
1652 if (rp) {
1653 free_ranges(rp);
1654 *rp = copy_ranges(tcp->ranges);
1655 }
1656 if (hint) {
1657 if (*hint) free(*hint);
1658 *hint = (tcp->hint ? strdup(tcp->hint) : NULL);
1659 }
1660 return tcp->type;
1661 }
1662 return LABEL;
1663 }
1664
1665 /* return index into tclist of given TC descriptor
1666 return -1 if not found
1667 */
1668 static int
1669 get_tc_index(const char *descriptor,
1670 int modid)
1671 {
1672 int i;
1673 struct tc *tcp;
1674 struct module *mp;
1675 struct module_import *mip;
1676
1677 /*
1678 * Check that the descriptor isn't imported
1679 * by searching the import list
1680 */
1681
1682 for ( mp = module_head ; mp ; mp = mp->next )
1683 if ( mp->modid == modid )
1684 break;
1685 if ( mp )
1686 for ( i=0, mip=mp->imports ; i < mp->no_imports ; ++i, ++mip ) {
1687 if ( !label_compare( mip->label, descriptor )) {
1688 /* Found it - so amend the module ID */
1689 modid = mip->modid;
1690 break;
1691 }
1692 }
1693
1694
1695 for(i=0, tcp=tclist; i < MAXTC; i++, tcp++){
1696 if (tcp->type == 0)
1697 break;
1698 if (!label_compare(descriptor, tcp->descriptor) &&
1699 ((modid == tcp->modid) || (modid == -1))){
1700 return i;
1701 }
1702 }
1703 return -1;
1704 }
1705
1706 /* translate integer tc_index to string identifier from tclist
1707 *
1708 * Returns pointer to string in table (should not be modified) or NULL
1709 */
1710 const char *
1711 get_tc_descriptor(int tc_index)
1712 {
1713 if (tc_index < 0 || tc_index >= MAXTC) return NULL;
1714 return (tclist[tc_index].descriptor);
1715 }
1716
1717
1718 /*
1719 * Parses an enumeration list of the form:
1720 * { label(value) label(value) ... }
1721 * The initial { has already been parsed.
1722 * Returns NULL on error.
1723 */
1724
1725 static struct enum_list *
1726 parse_enumlist(FILE *fp, struct enum_list **retp)
1727 {
1728 register int type;
1729 char token [MAXTOKEN];
1730 struct enum_list *ep = NULL, **epp = &ep;
1731
1732 free_enums(retp);
1733
1734 while((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE){
1735 if (type == RIGHTBRACKET)
1736 break;
1737 if (type == LABEL){
1738 /* this is an enumerated label */
1739 *epp = (struct enum_list *) calloc(1, sizeof(struct enum_list));
1740 if (*epp == NULL) return(NULL);
1741 /* a reasonable approximation for the length */
1742 (*epp)->label = strdup(token);
1743 type = get_token(fp, token, MAXTOKEN);
1744 if (type != LEFTPAREN) {
1745 print_error("Expected \"(\"", token, type);
1746 return NULL;
1747 }
1748 type = get_token(fp, token, MAXTOKEN);
1749 if (type != NUMBER) {
1750 print_error("Expected integer", token, type);
1751 return NULL;
1752 }
1753 (*epp)->value = atoi(token);
1754 type = get_token(fp, token, MAXTOKEN);
1755 if (type != RIGHTPAREN) {
1756 print_error("Expected \")\"", token, type);
1757 return NULL;
1758 }
1759 epp = &(*epp)->next;
1760 }
1761 }
1762 if (type == ENDOFFILE){
1763 print_error("Expected \"}\"", token, type);
1764 return NULL;
1765 }
1766 *retp = ep;
1767 return ep;
1768 }
1769
1770 static struct range_list *parse_ranges(FILE *fp, struct range_list **retp)
1771 { int low, high;
1772 char nexttoken[MAXTOKEN];
1773 int nexttype;
1774 struct range_list *rp = NULL, **rpp = &rp;
1775 int size = 0, taken = 1;
1776
1777 free_ranges(retp);
1778
1779 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1780 if (nexttype == SIZE) {
1781 size = 1;
1782 taken = 0;
1783 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1784 if (nexttype != LEFTPAREN)
1785 print_error("Expected \"(\" after SIZE", nexttoken, nexttype);
1786 }
1787
1788 do {
1789 if (!taken) nexttype = get_token(fp, nexttoken, MAXTOKEN);
1790 else taken = 0;
1791 high = low = atol(nexttoken);
1792 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1793 if (nexttype == RANGE) {
1794 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1795 high = atol(nexttoken);
1796 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1797 }
1798 *rpp = (struct range_list *)calloc (1, sizeof(struct range_list));
1799 if (*rpp == NULL) break;
1800 (*rpp)->low = low;
1801 (*rpp)->high = high;
1802 rpp = &(*rpp)->next;
1803
1804 } while (nexttype == BAR);
1805 if (size) {
1806 if (nexttype != RIGHTPAREN)
1807 print_error ("Expected \")\" after SIZE", nexttoken, nexttype);
1808 nexttype = get_token(fp, nexttoken, nexttype);
1809 }
1810 if (nexttype != RIGHTPAREN)
1811 print_error ("Expected \")\"", nexttoken, nexttype);
1812
1813 *retp = rp;
1814 return rp;
1815 }
1816
1817 /*
1818 * Parses an asn type. Structures are ignored by this parser.
1819 * Returns NULL on error.
1820 */
1821 static struct node *
1822 parse_asntype(FILE *fp,
1823 char *name,
1824 int *ntype,
1825 char *ntoken)
1826 {
1827 int type, i;
1828 char token[MAXTOKEN];
1829 char quoted_string_buffer[MAXQUOTESTR];
1830 char *hint = NULL;
1831 struct tc *tcp;
1832 int level;
1833
1834 type = get_token(fp, token, MAXTOKEN);
1835 if (type == SEQUENCE){
1836 level = 0;
1837 while((type = get_token(fp, token, MAXTOKEN)) != ENDOFFILE){
1838 if (type == LEFTBRACKET){
1839 level++;
1840 }
1841 else if (type == RIGHTBRACKET && --level == 0){
1842 *ntype = get_token(fp, ntoken, MAXTOKEN);
1843 return NULL;
1844 }
1845 }
1846 print_error("Expected \"}\"", token, type);
1847 return NULL;
1848 } else if (type == LEFTBRACKET) {
1849 struct node *np;
1850 int ch_next = '{';
1851 ungetc(ch_next, fp);
1852 np = parse_objectid (fp, name);
1853 if (np != NULL) {
1854 *ntype = get_token(fp, ntoken, MAXTOKEN);
1855 return np;
1856 }
1857 return NULL;
1858 } else {
1859 if (type == CONVENTION) {
1860 while (type != SYNTAX && type != ENDOFFILE) {
1861 if (type == DISPLAYHINT) {
1862 type = get_token(fp, token, MAXTOKEN);
1863 if (type != QUOTESTRING) print_error("DISPLAY-HINT must be string", token, type);
1864 else hint = strdup (token);
1865 }
1866 else
1867 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
1868 }
1869 type = get_token(fp, token, MAXTOKEN);
1870 }
1871
1872 if (type == LABEL)
1873 {
1874 type = get_tc(token, current_module, NULL, NULL, NULL, NULL);
1875 }
1876
1877 /* textual convention */
1878 for(i = 0; i < MAXTC; i++){
1879 if (tclist[i].type == 0)
1880 break;
1881 }
1882
1883 if (i == MAXTC){
1884 print_error("Too many textual conventions", token, type);
1885 SNMP_FREE(hint);
1886 return NULL;
1887 }
1888 if (!(type & SYNTAX_MASK)){
1889 print_error("Textual convention doesn't map to real type", token,
1890 type);
1891 SNMP_FREE(hint);
1892 return NULL;
1893 }
1894 tcp = &tclist[i];
1895 tcp->modid = current_module;
1896 tcp->descriptor = strdup(name);
1897 tcp->hint = hint;
1898 tcp->type = type;
1899 *ntype = get_token(fp, ntoken, MAXTOKEN);
1900 if (*ntype == LEFTPAREN){
1901 tcp->ranges = parse_ranges(fp, &tcp->ranges);
1902 *ntype = get_token(fp, ntoken, MAXTOKEN);
1903 } else if (*ntype == LEFTBRACKET) {
1904 /* if there is an enumeration list, parse it */
1905 tcp->enums = parse_enumlist(fp, &tcp->enums);
1906 *ntype = get_token(fp, ntoken, MAXTOKEN);
1907 }
1908 return NULL;
1909 }
1910 }
1911
1912
1913 /*
1914 * Parses an OBJECT TYPE macro.
1915 * Returns 0 on error.
1916 */
1917 static struct node *
1918 parse_objecttype(FILE *fp,
1919 char *name)
1920 {
1921 register int type;
1922 char token[MAXTOKEN];
1923 char nexttoken[MAXTOKEN];
1924 char quoted_string_buffer[MAXQUOTESTR];
1925 int nexttype, tctype;
1926 register struct node *np;
1927
1928 type = get_token(fp, token, MAXTOKEN);
1929 if (type != SYNTAX){
1930 print_error("Bad format for OBJECT-TYPE", token, type);
1931 return NULL;
1932 }
1933 np = alloc_node(current_module);
1934 if (np == NULL) return(NULL);
1935 type = get_token(fp, token, MAXTOKEN);
1936 if (type == LABEL){
1937 int tmp_index;
1938 tctype = get_tc(token, current_module, &tmp_index,
1939 &np->enums, &np->ranges, &np->hint);
1940 if (tctype == LABEL &&
1941 ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS) > 1){
1942 print_error("Warning: No known translation for type", token, type);
1943 }
1944 type = tctype;
1945 np->tc_index = tmp_index; /* store TC for later reference */
1946 }
1947 np->type = type;
1948 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1949 switch(type){
1950 case SEQUENCE:
1951 if (nexttype == OF){
1952 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1953 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1954 }
1955 break;
1956 case INTEGER:
1957 case UINTEGER32:
1958 case COUNTER:
1959 case GAUGE:
1960 case BITSTRING:
1961 case LABEL:
1962 if (nexttype == LEFTBRACKET) {
1963 /* if there is an enumeration list, parse it */
1964 np->enums = parse_enumlist(fp, &np->enums);
1965 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1966 } else if (nexttype == LEFTPAREN){
1967 /* if there is a range list, parse it */
1968 np->ranges = parse_ranges(fp, &np->ranges);
1969 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1970 }
1971 break;
1972 case OCTETSTR:
1973 case KW_OPAQUE:
1974 /* parse any SIZE specification */
1975 if (nexttype == LEFTPAREN) {
1976 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1977 if (nexttype == SIZE) {
1978 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1979 if (nexttype == LEFTPAREN) {
1980 np->ranges = parse_ranges(fp, &np->ranges);
1981 nexttype = get_token(fp, nexttoken, MAXTOKEN); /* ) */
1982 if (nexttype == RIGHTPAREN)
1983 {
1984 nexttype = get_token(fp, nexttoken, MAXTOKEN);
1985 break;
1986 }
1987 }
1988 }
1989 print_error("Bad SIZE syntax", token, type);
1990 free_node(np);
1991 return NULL;
1992 }
1993 break;
1994 case OBJID:
1995 case NETADDR:
1996 case IPADDR:
1997 case TIMETICKS:
1998 case NUL:
1999 case NSAPADDRESS:
2000 case COUNTER64:
2001 break;
2002 default:
2003 print_error("Bad syntax", token, type);
2004 free_node(np);
2005 return NULL;
2006 }
2007 if (nexttype == UNITS){
2008 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2009 if (type != QUOTESTRING) {
2010 print_error("Bad UNITS", quoted_string_buffer, type);
2011 free_node(np);
2012 return NULL;
2013 }
2014 np->units = strdup (quoted_string_buffer);
2015 nexttype = get_token(fp, nexttoken, MAXTOKEN);
2016 }
2017 if (nexttype != ACCESS){
2018 print_error("Should be ACCESS", nexttoken, nexttype);
2019 free_node(np);
2020 return NULL;
2021 }
2022 type = get_token(fp, token, MAXTOKEN);
2023 if (type != READONLY && type != READWRITE && type != WRITEONLY
2024 && type != NOACCESS && type != READCREATE && type != ACCNOTIFY){
2025 print_error("Bad ACCESS type", token, type);
2026 free_node(np);
2027 return NULL;
2028 }
2029 np->access = type;
2030 type = get_token(fp, token, MAXTOKEN);
2031 if (type != STATUS){
2032 print_error("Should be STATUS", token, type);
2033 free_node(np);
2034 return NULL;
2035 }
2036 type = get_token(fp, token, MAXTOKEN);
2037 if (type != MANDATORY && type != CURRENT && type != KW_OPTIONAL &&
2038 type != OBSOLETE && type != DEPRECATED){
2039 print_error("Bad STATUS", token, type);
2040 free_node(np);
2041 return NULL;
2042 }
2043 np->status = type;
2044 /*
2045 * Optional parts of the OBJECT-TYPE macro
2046 */
2047 type = get_token(fp, token, MAXTOKEN);
2048 while (type != EQUALS && type != ENDOFFILE) {
2049 switch (type) {
2050 case DESCRIPTION:
2051 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2052 if (type != QUOTESTRING) {
2053 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2054 free_node(np);
2055 return NULL;
2056 }
2057 if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS)) {
2058 np->description = strdup (quoted_string_buffer);
2059 }
2060 break;
2061
2062 case REFERENCE:
2063 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2064 if (type != QUOTESTRING) {
2065 print_error("Bad REFERENCE", quoted_string_buffer, type);
2066 free_node(np);
2067 return NULL;
2068 }
2069 break;
2070 case INDEX:
2071 np->indexes = getIndexes(fp, &np->indexes);
2072 if (np->indexes == NULL) {
2073 print_error("Bad Index List",token,type);
2074 free_node(np);
2075 return NULL;
2076 }
2077 break;
2078
2079 case DEFVAL:
2080 case AUGMENTS:
2081 case NUM_ENTRIES:
2082 if (tossObjectIdentifier(fp) != OBJID) {
2083 print_error("Bad Object Identifier", token, type);
2084 free_node(np);
2085 return NULL;
2086 }
2087 break;
2088
2089 default:
2090 print_error("Bad format of optional clauses", token, type);
2091 free_node(np);
2092 return NULL;
2093
2094 }
2095 type = get_token(fp, token, MAXTOKEN);
2096 }
2097 if (type != EQUALS){
2098 print_error("Bad format", token, type);
2099 free_node(np);
2100 return NULL;
2101 }
2102 return merge_parse_objectid(np, fp, name);
2103 }
2104
2105 /*
2106 * Parses an OBJECT GROUP macro.
2107 * Returns 0 on error.
2108 *
2109 * Also parses object-identity, since they are similar (ignore STATUS).
2110 * - WJH 10/96
2111 */
2112 static struct node *
2113 parse_objectgroup(FILE *fp,
2114 char *name)
2115 {
2116 register int type;
2117 char token[MAXTOKEN];
2118 char quoted_string_buffer[MAXQUOTESTR];
2119 register struct node *np;
2120
2121 np = alloc_node(current_module);
2122 if (np == NULL) return(NULL);
2123 type = get_token(fp, token, MAXTOKEN);
2124 while (type != EQUALS && type != ENDOFFILE) {
2125 switch (type) {
2126 case DESCRIPTION:
2127 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2128 if (type != QUOTESTRING) {
2129 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2130 free_node(np);
2131 return NULL;
2132 }
2133 if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS)) {
2134 np->description = strdup (quoted_string_buffer);
2135 }
2136 break;
2137
2138 case REFERENCE:
2139 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2140 if (type != QUOTESTRING) {
2141 print_error("Bad REFERENCE", quoted_string_buffer, type);
2142 free_node(np);
2143 return NULL;
2144 }
2145 break;
2146
2147 default:
2148 /* NOTHING */
2149 break;
2150 }
2151 type = get_token(fp, token, MAXTOKEN);
2152 }
2153 return merge_parse_objectid(np, fp, name);
2154 }
2155
2156 /*
2157 * Parses a NOTIFICATION-TYPE macro.
2158 * Returns 0 on error.
2159 */
2160 static struct node *
2161 parse_notificationDefinition(FILE *fp,
2162 char *name)
2163 {
2164 register int type;
2165 char token[MAXTOKEN];
2166 char quoted_string_buffer[MAXQUOTESTR];
2167 register struct node *np;
2168
2169 np = alloc_node(current_module);
2170 if (np == NULL) return(NULL);
2171 type = get_token(fp, token, MAXTOKEN);
2172 while (type != EQUALS && type != ENDOFFILE) {
2173 switch (type) {
2174 case DESCRIPTION:
2175 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2176 if (type != QUOTESTRING) {
2177 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2178 free_node(np);
2179 return NULL;
2180 }
2181 if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS)) {
2182 np->description = strdup (quoted_string_buffer);
2183 }
2184 break;
2185
2186 default:
2187 /* NOTHING */
2188 break;
2189 }
2190 type = get_token(fp, token, MAXTOKEN);
2191 }
2192 return merge_parse_objectid(np, fp, name);
2193 }
2194
2195 /*
2196 * Parses a TRAP-TYPE macro.
2197 * Returns 0 on error.
2198 */
2199 static struct node *
2200 parse_trapDefinition(FILE *fp,
2201 char *name)
2202 {
2203 register int type;
2204 char token[MAXTOKEN];
2205 char quoted_string_buffer[MAXQUOTESTR];
2206 register struct node *np;
2207
2208 np = alloc_node(current_module);
2209 if (np == NULL) return(NULL);
2210 type = get_token(fp, token, MAXTOKEN);
2211 while (type != EQUALS && type != ENDOFFILE) {
2212 switch (type) {
2213 case DESCRIPTION:
2214 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2215 if (type != QUOTESTRING) {
2216 print_error("Bad DESCRIPTION", quoted_string_buffer, type);
2217 free_node(np);
2218 return NULL;
2219 }
2220 if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_SAVE_MIB_DESCRS)) {
2221 np->description = strdup (quoted_string_buffer);
2222 }
2223 break;
2224 case ENTERPRISE:
2225 type = get_token(fp, token, MAXTOKEN);
2226 if (type == LEFTBRACKET) {
2227 type = get_token(fp, token, MAXTOKEN);
2228 if (type != LABEL) {
2229 print_error("Bad Trap Format", token, type);
2230 free_node(np);
2231 return NULL;
2232 }
2233 np->parent = strdup(token);
2234 /* Get right bracket */
2235 type = get_token(fp, token, MAXTOKEN);
2236 }
2237 else if (type == LABEL)
2238 np->parent = strdup(token);
2239 break;
2240 default:
2241 /* NOTHING */
2242 break;
2243 }
2244 type = get_token(fp, token, MAXTOKEN);
2245 }
2246 type = get_token(fp, token, MAXTOKEN);
2247
2248 np->label = strdup(name);
2249
2250 if (type != NUMBER) {
2251 print_error("Expected a Number", token, type);
2252 free_node(np);
2253 return NULL;
2254 }
2255 np->subid = atoi(token);
2256 np->next = alloc_node(current_module);
2257 if (np->next == NULL) {
2258 free_node(np);
2259 return(NULL);
2260 }
2261 np->next->parent = np->parent;
2262 np->parent = (char *)malloc(strlen(np->parent)+2);
2263 if (np->parent == NULL) {
2264 free_node(np->next); free_node(np);
2265 return(NULL);
2266 }
2267 strcpy(np->parent, np->next->parent);
2268 strcat(np->parent, "#");
2269 np->next->label = strdup(np->parent);
2270 return np;
2271 }
2272
2273
2274 /*
2275 * Parses a compliance macro
2276 * Returns 0 on error.
2277 */
2278 static struct node *
2279 parse_compliance(FILE *fp,
2280 char *name)
2281 {
2282 register int type;
2283 char token[MAXTOKEN];
2284 char quoted_string_buffer[MAXQUOTESTR];
2285 register struct node *np;
2286
2287 np = alloc_node(current_module);
2288 if (np == NULL) return(NULL);
2289 type = get_token(fp, token, MAXTOKEN);
2290 while (type != EQUALS && type != ENDOFFILE) {
2291 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2292 }
2293 return merge_parse_objectid(np, fp, name);
2294 }
2295
2296
2297 /*
2298 * Parses a capabilities macro
2299 * Returns 0 on error.
2300 */
2301 static struct node *
2302 parse_capabilities(FILE *fp,
2303 char *name)
2304 {
2305 register int type;
2306 char token[MAXTOKEN];
2307 char quoted_string_buffer[MAXQUOTESTR];
2308 register struct node *np;
2309
2310 np = alloc_node(current_module);
2311 if (np == NULL) return(NULL);
2312 type = get_token(fp, token, MAXTOKEN);
2313 while (type != EQUALS && type != ENDOFFILE) {
2314 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2315 }
2316 return merge_parse_objectid(np, fp, name);
2317 }
2318
2319 /*
2320 * Parses a module identity macro
2321 * Returns 0 on error.
2322 */
2323 static struct node *
2324 parse_moduleIdentity(FILE *fp,
2325 char *name)
2326 {
2327 register int type;
2328 char token[MAXTOKEN];
2329 char quoted_string_buffer[MAXQUOTESTR];
2330 register struct node *np;
2331
2332 np = alloc_node(current_module);
2333 if (np == NULL) return(NULL);
2334 type = get_token(fp, token, MAXTOKEN);
2335 while (type != EQUALS && type != ENDOFFILE) {
2336 type = get_token(fp, quoted_string_buffer, MAXQUOTESTR);
2337 }
2338 return merge_parse_objectid(np, fp, name);
2339 }
2340
2341
2342 /*
2343 * Parses a MACRO definition
2344 * Expect BEGIN, discard everything to end.
2345 * Returns 0 on error.
2346 */
2347 static struct node *
2348 parse_macro(FILE *fp,
2349 char *name)
2350 {
2351 register int type;
2352 char token[MAXTOKEN];
2353 struct node *np;
2354 int iLine = Line;
2355
2356 np = alloc_node(current_module);
2357 if (np == NULL) return(NULL);
2358 type = get_token(fp, token, sizeof(token));
2359 while (type != EQUALS && type != ENDOFFILE) {
2360 type = get_token(fp, token, sizeof(token));
2361 }
2362 if (type != EQUALS) return NULL;
2363 while (type != BEGIN && type != ENDOFFILE) {
2364 type = get_token(fp, token, sizeof(token));
2365 }
2366 if (type != BEGIN) return NULL;
2367 while (type != END && type != ENDOFFILE) {
2368 type = get_token(fp, token, sizeof(token));
2369 }
2370 if (type != END) return NULL;
2371
2372 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
2373 snmp_log(LOG_WARNING,
2374 "%s MACRO (lines %d..%d parsed and ignored).\n", name, iLine, Line);
2375
2376 return np;
2377 }
2378
2379 /*
2380 * Parses a module import clause
2381 * loading any modules referenced
2382 */
2383 static void
2384 parse_imports(FILE *fp)
2385 {
2386 register int type;
2387 char token[MAXTOKEN];
2388 char modbuf[256];
2389 #define MAX_IMPORTS 256
2390 struct module_import import_list[MAX_IMPORTS];
2391 int this_module, old_current_module;
2392 const char *old_File;
2393 int old_line;
2394 struct module *mp;
2395
2396 int import_count=0; /* Total number of imported descriptors */
2397 int i=0, old_i; /* index of first import from each module */
2398
2399 type = get_token(fp, token, MAXTOKEN);
2400
2401 /*
2402 * Parse the IMPORTS clause
2403 */
2404 while (type != SEMI && type != ENDOFFILE) {
2405 if (type == LABEL ) {
2406 if (import_count == MAX_IMPORTS ) {
2407 print_error("Too many imported symbols", token, type);
2408 do {
2409 type = get_token(fp, token, MAXTOKEN);
2410 } while (type != SEMI && type != ENDOFFILE);
2411 return;
2412 }
2413 import_list[import_count++].label = strdup(token);
2414 }
2415 else if ( type == FROM ) {
2416 type = get_token(fp, token, MAXTOKEN);
2417 if ( import_count == i ) { /* All imports are handled internally */
2418 type = get_token(fp, token, MAXTOKEN);
2419 continue;
2420 }
2421 this_module = which_module(token);
2422
2423 for ( old_i=i ; i<import_count ; ++i)
2424 import_list[i].modid = this_module;
2425
2426 old_current_module = current_module; /* Save state */
2427 old_File = File;
2428 old_line = Line;
2429 current_module = this_module;
2430
2431 /*
2432 * Recursively read any pre-requisite modules
2433 */
2434 if (read_module_internal(token) == MODULE_NOT_FOUND ) {
2435 for ( ; old_i<import_count ; ++old_i ) {
2436 read_import_replacements( token, &import_list[old_i]);
2437 }
2438 }
2439
2440 current_module = old_current_module; /* Restore state */
2441 File = old_File;
2442 Line = old_line;
2443 }
2444 type = get_token(fp, token, MAXTOKEN);
2445 }
2446
2447 /*
2448 * Save the import information
2449 * in the global module table
2450 */
2451 for ( mp=module_head ; mp ; mp=mp->next )
2452 if ( mp->modid == current_module) {
2453 if ( import_count == 0)
2454 return;
2455 if (mp->imports && (mp->imports != root_imports))
2456 {
2457 /* this can happen if all modules are in one source file. */
2458 for ( i=0 ; i<mp->no_imports; ++i ) {
2459 DEBUGMSGTL(("parse-mibs", "#### freeing Module %d '%s' %d\n",
2460 mp->modid, mp->imports[i].label, mp->imports[i].modid));
2461 free((char *)mp->imports[i].label);
2462 }
2463 free((char*)mp->imports);
2464 }
2465 mp->imports = (struct module_import *)
2466 calloc(import_count, sizeof(struct module_import));
2467 if (mp->imports == NULL) return;
2468 for ( i=0 ; i<import_count ; ++i ) {
2469 mp->imports[i].label = import_list[i].label;
2470 mp->imports[i].modid = import_list[i].modid;
2471 DEBUGMSGTL(("parse-mibs", "#### adding Module %d '%s' %d\n",
2472 mp->modid, mp->imports[i].label, mp->imports[i].modid));
2473 }
2474 mp->no_imports = import_count;
2475 return;
2476 }
2477
2478 /*
2479 * Shouldn't get this far
2480 */
2481 print_module_not_found(module_name(current_module,modbuf));
2482 return;
2483 }
2484
2485
2486
2487 /*
2488 * MIB module handling routines
2489 */
2490
2491 static void dump_module_list (void)
2492 {
2493 struct module *mp = module_head;
2494
2495 DEBUGMSGTL(("parse-mibs", "Module list:\n"));
2496 while (mp) {
2497 DEBUGMSGTL(("parse-mibs", " %s %d %s %d\n", mp->name, mp->modid, mp->file, mp->no_imports));
2498 mp = mp->next;
2499 }
2500 }
2501
2502 int
2503 which_module(const char *name)
2504 {
2505 struct module *mp;
2506
2507 for ( mp=module_head ; mp ; mp=mp->next )
2508 if ( !label_compare(mp->name, name))
2509 return(mp->modid);
2510
2511 DEBUGMSGTL(("parse-mibs", "Module %s not found\n", name));
2512 return(-1);
2513 }
2514
2515 /*
2516 * module_name - copy module name to user buffer, return ptr to same.
2517 */
2518 char *
2519 module_name (int modid,
2520 char *cp)
2521 {
2522 struct module *mp;
2523
2524 for ( mp=module_head ; mp ; mp=mp->next )
2525 if ( mp->modid == modid )
2526 {
2527 strcpy(cp, mp->name);
2528 return(cp);
2529 }
2530
2531 DEBUGMSGTL(("parse-mibs", "Module %d not found\n", modid));
2532 sprintf(cp, "#%d", modid);
2533 return(cp);
2534 }
2535
2536 /*
2537 * Backwards compatability
2538 * Read newer modules that replace the one specified:-
2539 * either all of them (read_module_replacements),
2540 * or those relating to a specified identifier (read_import_replacements)
2541 * plus an interface to add new replacement requirements
2542 */
2543 void
2544 add_module_replacement(const char *old_module,
2545 const char *new_module_name,
2546 const char *tag,
2547 int len)
2548 {
2549 struct module_compatability *mcp;
2550
2551 mcp = (struct module_compatability *)
2552 calloc(1, sizeof( struct module_compatability));
2553 if (mcp == NULL) return;
2554
2555 mcp->old_module = strdup( old_module );
2556 mcp->new_module = strdup( new_module_name );
2557 if (tag)
2558 mcp->tag = strdup( tag );
2559 mcp->tag_len = len;
2560
2561 mcp->next = module_map_head;
2562 module_map_head = mcp;
2563 }
2564
2565 static void
2566 read_module_replacements(const char *name)
2567 {
2568 struct module_compatability *mcp;
2569
2570 for ( mcp=module_map_head ; mcp; mcp=mcp->next ) {
2571 if ( !label_compare( mcp->old_module, name )) {
2572 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
2573 snmp_log(LOG_WARNING,
2574 "Loading replacement module %s for %s (%s)\n",
2575 mcp->new_module, name, File);
2576 (void)read_module( mcp->new_module );
2577 return;
2578 }
2579 }
2580 if (!ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_ERRORS))
2581 print_module_not_found(name);
2582
2583 }
2584
2585 static void
2586 read_import_replacements(const char *old_module_name,
2587 struct module_import *identifier)
2588 {
2589 struct module_compatability *mcp;
2590
2591 /*
2592 * Look for matches first
2593 */
2594 for ( mcp=module_map_head ; mcp; mcp=mcp->next ) {
2595 if ( !label_compare( mcp->old_module, old_module_name )) {
2596
2597 if ( /* exact match */
2598 ( mcp->tag_len==0 &&
2599 (mcp->tag == NULL ||
2600 !label_compare( mcp->tag, identifier->label ))) ||
2601 /* prefix match */
2602 ( mcp->tag_len!=0 &&
2603 !strncmp( mcp->tag, identifier->label, mcp->tag_len ))
2604 ) {
2605
2606 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
2607 snmp_log(LOG_WARNING,
2608 "Importing %s from replacement module %s instead of %s (%s)\n",
2609 identifier->label, mcp->new_module, old_module_name, File);
2610 (void)read_module( mcp->new_module );
2611 identifier->modid = which_module(mcp->new_module);
2612 return; /* finished! */
2613 }
2614 }
2615 }
2616
2617 /*
2618 * If no exact match, load everything relevant
2619 */
2620 read_module_replacements( old_module_name );
2621 }
2622
2623
2624 /*
2625 * Read in the named module
2626 * Returns the root of the whole tree
2627 * (by analogy with 'read_mib')
2628 */
2629 static int
2630 read_module_internal (const char *name)
2631 {
2632 struct module *mp;
2633 FILE *fp;
2634 struct node *np;
2635
2636 if ( tree_head == NULL )
2637 init_mib_internals(); /* was init_mib */
2638
2639 for ( mp=module_head ; mp ; mp=mp->next )
2640 if ( !label_compare(mp->name, name)) {
2641 const char *oldFile = File;
2642 int oldLine = Line;
2643
2644 if ( mp->no_imports != -1 ) {
2645 DEBUGMSGTL(("parse-mibs", "Module %s already loaded\n", name));
2646 return MODULE_ALREADY_LOADED;
2647 }
2648 if ((fp = fopen(mp->file, "r")) == NULL) {
2649 snmp_log_perror(mp->file);
2650 return MODULE_LOAD_FAILED;
2651 }
2652 mp->no_imports=0; /* Note that we've read the file */
2653 File = mp->file;
2654 Line = 1;
2655 /*
2656 * Parse the file
2657 */
2658 np = parse( fp, NULL );
2659 fclose(fp);
2660 File = oldFile;
2661 Line = oldLine;
2662 return MODULE_LOADED_OK;
2663 }
2664
2665 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS) > 1)
2666 snmp_log(LOG_WARNING, "Module %s not found\n", name);
2667 return MODULE_NOT_FOUND;
2668 }
2669
2670 void
2671 adopt_orphans (void)
2672 {
2673 struct node *np, *onp;
2674 struct tree *tp;
2675 int i, adopted;
2676
2677 if ( !orphan_nodes )
2678 return;
2679 init_node_hash(orphan_nodes);
2680 orphan_nodes = NULL;
2681
2682 while (1) {
2683 adopted = 0;
2684 for ( i = 0; i < NHASHSIZE; i++)
2685 if ( nbuckets[i] ) {
2686 for ( np = nbuckets[i] ; np!= NULL ; np=np->next )
2687 tp = find_tree_node( np->parent, -1 );
2688 if ( tp ) {
2689 do_subtree( tp, &np );
2690 adopted = 1;
2691 }
2692 }
2693 if ( adopted == 0 )
2694 break;
2695 }
2696
2697 /*
2698 * Report on outstanding orphans
2699 * and link them back into the orphan list
2700 */
2701 for (i = 0; i < NHASHSIZE; i++)
2702 if ( nbuckets[i] ) {
2703 if ( orphan_nodes )
2704 onp = np->next = nbuckets[i];
2705 else
2706 onp = orphan_nodes = nbuckets[i];
2707 nbuckets[i] = NULL;
2708 while (onp) {
2709 char modbuf[256];
2710 snmp_log (LOG_WARNING,
2711 "Unlinked OID in %s: %s ::= { %s %ld }\n",
2712 module_name(onp->modid, modbuf),
2713 (onp->label ? onp->label : "<no label>"),
2714 (onp->parent ? onp->parent : "<no parent>"),
2715 onp->subid);
2716
2717 np = onp;
2718 onp = onp->next;
2719 }
2720 }
2721 }
2722
2723 struct tree *
2724 read_module(const char *name)
2725 {
2726 if ( read_module_internal(name) == MODULE_NOT_FOUND )
2727 read_module_replacements( name );
2728 return tree_head;
2729 }
2730
2731 void
2732 unload_module_by_ID( int modID, struct tree *tree_top )
2733 {
2734 struct tree *tp, *prev, *next;
2735 int i;
2736
2737 prev = NULL;
2738 for ( tp=tree_top ; tp ; tp=next ) {
2739 next = tp->next_peer;
2740 /*
2741 * This next section looks rather complex.
2742 * Essentially, this is equivalent to the code fragment:
2743 * if (tp->modID = modID)
2744 * tp->number_modules--;
2745 * but handles one tree node being part of several modules.
2746 */
2747 for ( i=0 ; i<tp->number_modules ; i++ ) {
2748 if ( tp->module_list[i] == modID ) {
2749 tp->number_modules--;
2750 switch ( tp->number_modules ) {
2751
2752 case 0: /* That was the only module */
2753 tp->modid = -1; /* Mark as unused */
2754 break;
2755
2756 case 1: /* We did have a list of two, but this is no
2757 longer needed. Transfer the other entry
2758 ( i.e. module_list[1-i] - think about it! )
2759 to the 'single' slot tp->modid, and discard
2760 the list.
2761 */
2762 tp->modid = tp->module_list[1-i];
2763 free(tp->module_list);
2764 tp->module_list = NULL; /* let's be tidy */
2765 break;
2766
2767 default: /* We still need the list, so shuffle down
2768 all following entries to close up the gap */
2769 while ( i < tp->number_modules ) {
2770 tp->module_list[i] = tp->module_list[i+1];
2771 i++;
2772 }
2773 break;
2774 }
2775 break; /* Don't need to look through the rest of the list */
2776 }
2777 }
2778
2779 /*
2780 * OK - that's dealt with *this* node.
2781 * Now let's look at the children.
2782 * (Isn't recursion wonderful!)
2783 */
2784 if ( tp->child_list )
2785 unload_module_by_ID( modID, tp->child_list );
2786
2787
2788 if ( tp->number_modules == 0 ) {
2789 /* This node isn't needed any more (except perhaps
2790 for the sake of the children) */
2791 if ( tp->child_list == NULL ) {
2792 if ( prev )
2793 prev->next_peer = tp->next_peer;
2794 else
2795 tp->parent->child_list = tp->next_peer;
2796 free_tree( tp );
2797 }
2798 else
2799 free_partial_tree( tp, TRUE );
2800 }
2801 else
2802 prev = tp;
2803 }
2804 }
2805
2806 int
2807 unload_module(const char *name)
2808 {
2809 struct module *mp;
2810 int modID = -1;
2811
2812 for ( mp=module_head ; mp ; mp=mp->next )
2813 if ( !label_compare(mp->name, name)) {
2814 modID = mp->modid;
2815 break;
2816 }
2817
2818 if ( modID == -1 ) {
2819 DEBUGMSGTL(("unload-mib", "Module %s not found to unload\n", name));
2820 return MODULE_NOT_FOUND;
2821 }
2822 unload_module_by_ID( modID, tree_head );
2823 mp->no_imports = -1; /* mark as unloaded */
2824 return MODULE_LOADED_OK; /* Well, you know what I mean! */
2825 }
2826
2827 static void
2828 new_module (const char *name,
2829 const char *file)
2830 {
2831 struct module *mp;
2832
2833 for ( mp=module_head ; mp ; mp=mp->next )
2834 if ( !label_compare(mp->name, name)) {
2835 DEBUGMSGTL(("parse-mibs", "Module %s already noted\n", name));
2836 /* Not the same file */
2837 if (label_compare(mp->file, file)) {
2838 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
2839 snmp_log(LOG_WARNING,
2840 "Warning: Module %s was in %s now is %s\n",
2841 name, mp->file, file);
2842
2843 /* Use the new one in preference */
2844 free(mp->file);
2845 mp->file = strdup(file);
2846 }
2847 return;
2848 }
2849
2850 /* Add this module to the list */
2851 DEBUGMSGTL(("parse-mibs", " Module %d %s is in %s\n", max_module, name, file));
2852 mp = (struct module *) calloc(1, sizeof(struct module));
2853 if (mp == NULL) return;
2854 mp->name = strdup(name);
2855 mp->file = strdup(file);
2856 mp->imports = NULL;
2857 mp->no_imports = -1; /* Not yet loaded */
2858 mp->modid = max_module;
2859 ++max_module;
2860
2861 mp->next = module_head; /* Or add to the *end* of the list? */
2862 module_head = mp;
2863 }
2864
2865
2866
2867
2868 /*
2869 * Parses a mib file and returns a linked list of nodes found in the file.
2870 * Returns NULL on error.
2871 */
2872 static struct node *
2873 parse(FILE *fp,
2874 struct node *root)
2875 {
2876 char token[MAXTOKEN];
2877 char name[MAXTOKEN];
2878 int type = LABEL;
2879 int lasttype = LABEL;
2880
2881 #define BETWEEN_MIBS 1
2882 #define IN_MIB 2
2883 int state = BETWEEN_MIBS;
2884 struct node *np, *nnp;
2885
2886 DEBUGMSGTL(("parse-file", "Parsing file: %s...\n", File));
2887
2888 if (last_err_module) free(last_err_module); last_err_module = 0;
2889
2890 np = root;
2891 if (np != NULL) {
2892 /* now find end of chain */
2893 while(np->next)
2894 np = np->next;
2895 }
2896
2897 while (type != ENDOFFILE){
2898 if (lasttype == CONTINUE) lasttype = type;
2899 else type = lasttype = get_token(fp, token, MAXTOKEN);
2900
2901 switch (type) {
2902 case END:
2903 if (state != IN_MIB){
2904 print_error("Error, END before start of MIB", NULL, type);
2905 return NULL;
2906 }
2907 else {
2908 struct module *mp;
2909 #ifdef TEST
2910 printf("\nNodes for Module %s:\n", name);
2911 print_nodes( stdout, np );
2912 #endif
2913 for (mp = module_head; mp; mp = mp->next)
2914 if (mp->modid == current_module) break;
2915 do_linkup(mp, root);
2916 np = root = NULL;
2917 }
2918 state = BETWEEN_MIBS;
2919 #ifdef TEST
2920 if (ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS))
2921 xmalloc_stats (stderr);
2922 #endif
2923 continue;
2924 case IMPORTS:
2925 parse_imports( fp );
2926 continue;
2927 case EXPORTS:
2928 while (type != SEMI && type != ENDOFFILE)
2929 type = get_token(fp, token, MAXTOKEN);
2930 continue;
2931 case LABEL:
2932 break;
2933 case ENDOFFILE:
2934 continue;
2935 default:
2936 strcpy(name, token);
2937 type = get_token(fp, token, MAXTOKEN);
2938 nnp = NULL;
2939 if (type == MACRO) {
2940 nnp = parse_macro(fp, name);
2941 if (nnp == NULL){
2942 print_error("Bad parse of MACRO", NULL, type);
2943 /*return NULL;*/
2944 }
2945 free_node(nnp); /* IGNORE */
2946 nnp = NULL;
2947 }
2948 else
2949 print_error(name, "is a reserved word", lasttype);
2950 continue; /* see if we can parse the rest of the file */
2951 }
2952 strcpy(name, token);
2953 type = get_token(fp, token, MAXTOKEN);
2954 nnp = NULL;
2955
2956 /* Handle obsolete method to assign an object identifier to a
2957 module*/
2958 if (lasttype == LABEL && type == LEFTBRACKET) {
2959 while (type != RIGHTBRACKET && type != ENDOFFILE)
2960 type = get_token(fp, token, MAXTOKEN);
2961 if (type == ENDOFFILE){
2962 print_error("Expected \"}\"", token, type);
2963 return NULL;
2964 }
2965 type = get_token(fp, token, MAXTOKEN);
2966 }
2967
2968 switch (type) {
2969 case DEFINITIONS:
2970 if (state != BETWEEN_MIBS){
2971 print_error("Error, nested MIBS", NULL, type);
2972 return NULL;
2973 }
2974 state = IN_MIB;
2975 current_module = which_module( name );
2976 if ( current_module == -1 ) {
2977 new_module(name, File);
2978 current_module = which_module(name);
2979 }
2980 DEBUGMSGTL(("parse-mibs", "Parsing MIB: %d %s\n", current_module, name));
2981 while ((type = get_token (fp, token, MAXTOKEN)) != ENDOFFILE)
2982 if (type == BEGIN) break;
2983 break;
2984 case OBJTYPE:
2985 nnp = parse_objecttype(fp, name);
2986 if (nnp == NULL){
2987 print_error("Bad parse of OBJECT-TYPE", NULL, type);
2988 return NULL;
2989 }
2990 break;
2991 case OBJGROUP:
2992 nnp = parse_objectgroup(fp, name);
2993 if (nnp == NULL){
2994 print_error("Bad parse of OBJECT-GROUP", NULL, type);
2995 return NULL;
2996 }
2997 break;
2998 case TRAPTYPE:
2999 nnp = parse_trapDefinition(fp, name);
3000 if (nnp == NULL){
3001 print_error("Bad parse of TRAP-TYPE", NULL, type);
3002 return NULL;
3003 }
3004 break;
3005 case NOTIFTYPE:
3006 nnp = parse_notificationDefinition(fp, name);
3007 if (nnp == NULL){
3008 print_error("Bad parse of NOTIFICATION-TYPE", NULL, type);
3009 return NULL;
3010 }
3011 break;
3012 case COMPLIANCE:
3013 nnp = parse_compliance(fp, name);
3014 if (nnp == NULL){
3015 print_error("Bad parse of MODULE-COMPLIANCE", NULL, type);
3016 return NULL;
3017 }
3018 break;
3019 case CAPABILITIES:
3020 nnp = parse_capabilities(fp, name);
3021 if (nnp == NULL){
3022 print_error("Bad parse of AGENT-CAPABILITIES", NULL, type);
3023 return NULL;
3024 }
3025 break;
3026 case MACRO:
3027 nnp = parse_macro(fp, name);
3028 if (nnp == NULL){
3029 print_error("Bad parse of MACRO", NULL, type);
3030 /*return NULL;*/
3031 }
3032 free_node(nnp); /* IGNORE */
3033 nnp = NULL;
3034 break;
3035 case MODULEIDENTITY:
3036 nnp = parse_moduleIdentity(fp, name);
3037 if (nnp == NULL){
3038 print_error("Bad parse of MODULE-IDENTITY", NULL, type);
3039 return NULL;
3040 }
3041 break;
3042 case OBJID:
3043 type = get_token(fp, token, MAXTOKEN);
3044 if (type != EQUALS){
3045 print_error("Expected \"::=\"", token, type);
3046 return NULL;
3047 }
3048 nnp = parse_objectid(fp, name);
3049 if (nnp == NULL){
3050 print_error("Bad parse of OBJECT IDENTIFIER", NULL, type);
3051 return NULL;
3052 }
3053 break;
3054 case EQUALS:
3055 nnp = parse_asntype(fp, name, &type, token);
3056 lasttype = CONTINUE;
3057 break;
3058 case ENDOFFILE:
3059 break;
3060 default:
3061 print_error("Bad operator", token, type);
3062 return NULL;
3063 }
3064 if (nnp) {
3065 if (np) np->next = nnp;
3066 else np = root = nnp;
3067 while (np->next) np = np->next;
3068 }
3069 }
3070 DEBUGMSGTL(("parse-file", "End of file (%s)\n", File));
3071 return root;
3072 }
3073
3074 /* return zero if character is not a label character. */
3075 static int
3076 is_labelchar (int ich)
3077 {
3078 if ((isalnum(ich)) || (ich == '-'))
3079 return 1;
3080 if (ich == '_' && ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_PARSE_LABEL))
3081 return 1;
3082
3083 return 0;
3084 }
3085
3086 /*
3087 * Parses a token from the file. The type of the token parsed is returned,
3088 * and the text is placed in the string pointed to by token.
3089 * Warning: this method may recurse.
3090 */
3091 static int
3092 get_token(FILE *fp,
3093 char *token,
3094 int maxtlen)
3095 {
3096 register int ch, ch_next;
3097 register char *cp = token;
3098 register int hash = 0;
3099 register struct tok *tp;
3100 int too_long = 0;
3101
3102 /* skip all white space */
3103 do {
3104 ch = getc(fp);
3105 if (ch == '\n')
3106 Line++;
3107 }
3108 while(isspace(ch) && ch != EOF);
3109 *cp++ = ch; *cp = '\0';
3110 switch (ch) {
3111 case EOF:
3112 return ENDOFFILE;
3113 case '"':
3114 return parseQuoteString(fp, token, maxtlen);
3115 case '\'': /* binary or hex constant */
3116 while ((ch = getc(fp)) != EOF && ch != '\'' && cp-token < maxtlen-2)
3117 *cp++ = ch;
3118 if (ch == '\'') {
3119 unsigned long val = 0;
3120 *cp++ = '\'';
3121 *cp++ = ch = getc(fp);
3122 *cp = 0;
3123 cp = token+1;
3124 switch (ch) {
3125 case EOF:
3126 return ENDOFFILE;
3127 case 'b':
3128 case 'B':
3129 while ((ch = *cp++) != '\'')
3130 if (ch != '0' && ch != '1') return LABEL;
3131 else val = val * 2 + ch - '0';
3132 break;
3133 case 'h':
3134 case 'H':
3135 while ((ch = *cp++) != '\'')
3136 if ('0' <= ch && ch <= '9') val = val*16+ch-'0';
3137 else if ('a' <= ch && ch <= 'f') val = val*16+ch-'a'+10;
3138 else if ('A' <= ch && ch <= 'F') val = val*16+ch-'A'+10;
3139 else return LABEL;
3140 break;
3141 default:
3142 return LABEL;
3143 }
3144 sprintf(token, "%ld", val);
3145 return NUMBER;
3146 }
3147 else return LABEL;
3148 case '(':
3149 return LEFTPAREN;
3150 case ')':
3151 return RIGHTPAREN;
3152 case '{':
3153 return LEFTBRACKET;
3154 case '}':
3155 return RIGHTBRACKET;
3156 case ';':
3157 return SEMI;
3158 case ',':
3159 return COMMA;
3160 case '|':
3161 return BAR;
3162 case '.':
3163 ch_next = getc(fp);
3164 if (ch_next == '.') return RANGE;
3165 ungetc(ch_next, fp);
3166 return LABEL;
3167 case ':':
3168 ch_next = getc(fp);
3169 if (ch_next != ':') {
3170 ungetc(ch_next, fp);
3171 return LABEL;
3172 }
3173 ch_next = getc(fp);
3174 if (ch_next != '=') {
3175 ungetc(ch_next, fp);
3176 return LABEL;
3177 }
3178 return EQUALS;
3179 case '-':
3180 ch_next = getc(fp);
3181 if (ch_next == '-') {
3182 if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_MIB_COMMENT_TERM)) {
3183 /* Treat the rest of this line as a comment. */
3184 while ((ch_next != EOF) && (ch_next != '\n'))
3185 ch_next = getc(fp);
3186 } else {
3187 /* Treat the rest of the line or until another '--' as a comment */
3188 /* (this is the "technically" correct way to parse comments) */
3189 ch = ' ';
3190 ch_next = getc(fp);
3191 while (ch_next != EOF && ch_next != '\n' &&
3192 (ch != '-' || ch_next != '-')) {
3193 ch = ch_next; ch_next = getc(fp);
3194 }
3195 }
3196 if (ch_next == EOF) return ENDOFFILE;
3197 if (ch_next == '\n') Line++;
3198 return get_token (fp, token, maxtlen);
3199 }
3200 ungetc(ch_next, fp);
3201 default:
3202 /*
3203 * Accumulate characters until end of token is found. Then attempt to
3204 * match this token as a reserved word. If a match is found, return the
3205 * type. Else it is a label.
3206 */
3207 if (!is_labelchar(ch)) return LABEL;
3208 hash += tolower(ch);
3209 more:
3210 while (is_labelchar(ch_next = getc(fp))) {
3211 hash += tolower(ch_next);
3212 if (cp - token < maxtlen - 1) *cp++ = ch_next;
3213 else too_long = 1;
3214 }
3215 ungetc(ch_next, fp);
3216 *cp = '\0';
3217
3218 if (too_long)
3219 print_error("Warning: token too long", token, CONTINUE);
3220 for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
3221 if ((tp->hash == hash) && (!label_compare(tp->name, token)))
3222 break;
3223 }
3224 if (tp) {
3225 if (tp->token != CONTINUE) return (tp->token);
3226 while (isspace((ch_next = getc(fp))))
3227 if (ch_next == '\n') Line++;
3228 if (ch_next == EOF) return ENDOFFILE;
3229 if (isalnum(ch_next)) {
3230 *cp++ = ch_next;
3231 hash += tolower(ch_next);
3232 goto more;
3233 }
3234 }
3235 if (token[0] == '-' || isdigit(token[0])) {
3236 for(cp = token+1; *cp; cp++)
3237 if (!isdigit(*cp))
3238 return LABEL;
3239 return NUMBER;
3240 }
3241 return LABEL;
3242 }
3243 }
3244
3245 int
3246 snmp_get_token(FILE *fp,
3247 char *token,
3248 int maxtlen)
3249 {
3250 return get_token(fp, token, maxtlen);
3251 }
3252
3253 int
3254 add_mibdir(const char *dirname)
3255 {
3256 #ifndef ECOSFIXME_NEEDFILESYSTEM
3257 FILE *fp, *ip;
3258 DIR *dir, *dir2;
3259 const char *oldFile = File;
3260 struct dirent *file;
3261 char token[MAXTOKEN];
3262 char tmpstr[300];
3263 int count = 0;
3264 #ifndef WIN32
3265 struct stat dir_stat, idx_stat;
3266 char tmpstr1[300];
3267 #endif
3268
3269 DEBUGMSGTL(("parse-mibs", "Scanning directory %s\n", dirname));
3270 #ifndef WIN32
3271 sprintf(token, "%s/%s", dirname, ".index");
3272 if (stat(token, &idx_stat) == 0 && stat(dirname, &dir_stat) == 0) {
3273 if (dir_stat.st_mtime < idx_stat.st_mtime) {
3274 DEBUGMSGTL(("parse-mibs", "The index is good\n"));
3275 if ((ip = fopen(token, "r")) != NULL) {
3276 while (fscanf(ip, "%s %s\n", token, tmpstr) == 2) {
3277 sprintf(tmpstr1, "%s/%s", dirname, tmpstr);
3278 new_module(token, tmpstr1);
3279 count++;
3280 }
3281 fclose(ip);
3282 return count;
3283 }
3284 else DEBUGMSGTL(("parse-mibs", "Can't read index\n"));
3285 }
3286 else DEBUGMSGTL(("parse-mibs", "Index outdated\n"));
3287 }
3288 else DEBUGMSGTL(("parse-mibs", "No index\n"));
3289 #endif
3290
3291 if ((dir = opendir(dirname))) {
3292 sprintf(tmpstr, "%s/.index", dirname);
3293 ip = fopen(tmpstr, "w");
3294 while ((file = readdir(dir))) {
3295 /* Only parse file names not beginning with a '.' */
3296 if (file->d_name != NULL && file->d_name[0] != '.') {
3297 sprintf(tmpstr, "%s/%s", dirname, file->d_name);
3298 if ((dir2 = opendir(tmpstr))) {
3299 /* file is a directory, don't read it */
3300 closedir(dir2);
3301 } else {
3302 /* which module is this */
3303 if ((fp = fopen(tmpstr, "r")) == NULL) {
3304 snmp_log_perror(tmpstr);
3305 continue;
3306 }
3307 DEBUGMSGTL(("parse-mibs", "Checking file: %s...\n", tmpstr));
3308 Line = 1;
3309 File = tmpstr;
3310 get_token( fp, token, MAXTOKEN);
3311 new_module(token, tmpstr);
3312 count++;
3313 fclose (fp);
3314 if (ip) fprintf(ip, "%s %s\n", token, file->d_name);
3315 }
3316 }
3317 }
3318 File = oldFile;
3319 closedir(dir);
3320 if (ip) fclose(ip);
3321 return(count);
3322 }
3323 return(-1);
3324
3325 #else
3326 // __ECOS
3327
3328 #if 0 // MIBS not needed for agent use of library.
3329 int count = 0;
3330 int i;
3331
3332 static const char *snmp_miblist[] = {
3333 "EtherLike-MIB",
3334 "IANAifType-MIB",
3335 "IF-MIB",
3336 "IP-MIB",
3337 "RFC-1215",
3338 "SNMPv2-CONF",
3339 "SNMPv2-MIB",
3340 "SNMPv2-SMI",
3341 "SNMPv2-TC",
3342 "SNMPv2-TM",
3343 "TCP-MIB",
3344 "UDP-MIB",
3345 };
3346
3347 for ( i = 0;
3348 i < sizeof(snmp_miblist)/sizeof(snmp_miblist[0]);
3349 i++ ) {
3350
3351 new_module(snmp_miblist[i],snmp_miblist[i]);
3352 count++;
3353 }
3354 return(count);
3355 #else
3356 return 0;
3357 #endif
3358
3359 #endif
3360 }
3361
3362
3363 /*
3364 * Returns the root of the whole tree
3365 * (for backwards compatability)
3366 */
3367 struct tree *
3368 read_mib(const char *filename)
3369 {
3370 FILE *fp;
3371 char token[MAXTOKEN];
3372
3373 fp = fopen(filename, "r");
3374 if (fp == NULL) {
3375 snmp_log_perror(filename);
3376 return NULL;
3377 }
3378 Line = 1;
3379 File = filename;
3380 DEBUGMSGTL(("parse-mibs", "Parsing file: %s...\n", filename));
3381 get_token( fp, token, MAXTOKEN);
3382 fclose(fp);
3383 new_module(token, filename);
3384 (void) read_module(token);
3385
3386 return tree_head;
3387 }
3388
3389
3390 struct tree *
3391 read_all_mibs()
3392 {
3393 struct module *mp;
3394
3395 for ( mp=module_head ; mp ; mp=mp->next )
3396 if ( mp->no_imports == -1 )
3397 read_module( mp->name );
3398 adopt_orphans();
3399
3400 return tree_head;
3401 }
3402
3403
3404 #ifdef TEST
3405 main(int argc, char *argv[])
3406 {
3407 int i;
3408 struct tree *tp;
3409 ds_set_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS, 2);
3410
3411 init_mib();
3412
3413 if ( argc == 1 )
3414 (void) read_all_mibs();
3415 else
3416 for ( i=1 ; i<argc ; i++ )
3417 read_mib( argv[i] );
3418
3419 for ( tp = tree_head ; tp ; tp=tp->next_peer )
3420 print_subtree( stdout, tp, 0 );
3421 free_tree( tree_head );
3422
3423 return 0;
3424 }
3425 #endif /* TEST */
3426
3427 static int
3428 parseQuoteString(FILE *fp,
3429 char *token,
3430 int maxtlen)
3431 {
3432 register int ch;
3433 int count = 0;
3434 int too_long = 0;
3435 char *token_start = token;
3436
3437 for (ch = getc(fp); ch != EOF; ch = getc(fp)) {
3438 if (ch == '\r') continue;
3439 if (ch == '\n') {
3440 Line++;
3441 }
3442 else if (ch == '"') {
3443 *token = '\0';
3444 if (too_long &&
3445 ds_get_int(DS_LIBRARY_ID, DS_LIB_MIB_WARNINGS) > 1)
3446 {
3447 /* show short form for brevity sake */
3448 char ch_save = *(token_start + 50);
3449 *(token_start + 50) = '\0';
3450 print_error ("Warning: string too long",
3451 token_start, QUOTESTRING);
3452 *(token_start + 50) = ch_save;
3453 }
3454 return QUOTESTRING;
3455 }
3456 /* maximum description length check. If greater, keep parsing
3457 but truncate the string */
3458 if (++count < maxtlen)
3459 *token++ = ch;
3460 else too_long = 1;
3461 }
3462
3463 return 0;
3464 }
3465
3466 /*
3467 * struct index_list *
3468 * getIndexes(FILE *fp):
3469 * This routine parses a string like { blah blah blah } and returns a
3470 * list of the strings enclosed within it.
3471 *
3472 */
3473 static struct index_list *
3474 getIndexes(FILE *fp, struct index_list **retp) {
3475 int type;
3476 char token[MAXTOKEN];
3477 char nextIsImplied = 0;
3478
3479 struct index_list *mylist = NULL;
3480 struct index_list **mypp = &mylist;
3481
3482 free_indexes(retp);
3483
3484 type = get_token(fp, token, MAXTOKEN);
3485
3486 if (type != LEFTBRACKET) {
3487 return NULL;
3488 }
3489
3490 type = get_token(fp, token, MAXTOKEN);
3491 while (type != RIGHTBRACKET && type != ENDOFFILE) {
3492 if ((type == LABEL) || (type & SYNTAX_MASK)) {
3493 *mypp = (struct index_list *) calloc(1, sizeof(struct index_list));
3494 if (*mypp) {
3495 (*mypp)->ilabel = strdup(token);
3496 (*mypp)->isimplied = nextIsImplied;
3497 mypp = &(*mypp)->next;
3498 nextIsImplied = 0;
3499 }
3500 } else if (type == IMPLIED) {
3501 nextIsImplied = 1;
3502 }
3503 type = get_token(fp, token, MAXTOKEN);
3504 }
3505
3506 *retp = mylist;
3507 return mylist;
3508 }
3509
3510 static void
3511 free_indexes(struct index_list **spp) {
3512 if (spp && *spp) {
3513 struct index_list *pp, *npp;
3514
3515 pp = *spp; *spp = NULL;
3516
3517 while(pp) {
3518 npp = pp->next;
3519 if (pp->ilabel) free(pp->ilabel);
3520 free(pp);
3521 pp = npp;
3522 }
3523 }
3524 }
3525
3526 static void
3527 free_ranges(struct range_list **spp) {
3528 if (spp && *spp) {
3529 struct range_list *pp, *npp;
3530
3531 pp = *spp; *spp = NULL;
3532
3533 while(pp) {
3534 npp = pp->next;
3535 free(pp);
3536 pp = npp;
3537 }
3538 }
3539 }
3540
3541 static void
3542 free_enums(struct enum_list **spp)
3543 {
3544 if (spp && *spp) {
3545 struct enum_list *pp, *npp;
3546
3547 pp = *spp; *spp = NULL;
3548
3549 while(pp)
3550 {
3551 npp = pp->next;
3552 if (pp->label) free(pp->label);
3553 free(pp);
3554 pp = npp;
3555 }
3556 }
3557 }
3558
3559 static struct enum_list *
3560 copy_enums (struct enum_list *sp)
3561 {
3562 struct enum_list *xp = NULL, **spp = &xp;
3563
3564 while (sp) {
3565 *spp = (struct enum_list *) calloc(1, sizeof(struct enum_list));
3566 if (!*spp) break;
3567 (*spp)->label = strdup(sp->label);
3568 (*spp)->value = sp->value;
3569 spp = &(*spp)->next;
3570 sp = sp->next;
3571 }
3572 return (xp);
3573 }
3574
3575 static struct range_list *
3576 copy_ranges (struct range_list *sp)
3577 {
3578 struct range_list *xp = NULL, **spp = &xp;
3579
3580 while (sp) {
3581 *spp = (struct range_list *) calloc(1, sizeof(struct range_list));
3582 if (!*spp) break;
3583 (*spp)->low = sp->low;
3584 (*spp)->high = sp->high;
3585 spp = &(*spp)->next;
3586 sp = sp->next;
3587 }
3588 return (xp);
3589 }
3590
3591 static struct index_list *
3592 copy_indexes (struct index_list *sp)
3593 {
3594 struct index_list *xp = NULL, **spp = &xp;
3595
3596 while (sp) {
3597 *spp = (struct index_list *) calloc(1, sizeof(struct index_list));
3598 if (!*spp) break;
3599 (*spp)->ilabel = strdup(sp->ilabel);
3600 spp = &(*spp)->next;
3601 sp = sp->next;
3602 }
3603 return (xp);
3604 }
3605
3606 /*
3607 * This routine parses a string like { blah blah blah } and returns OBJID if
3608 * it is well formed, and NULL if not.
3609 */
3610 static int
3611 tossObjectIdentifier(FILE *fp)
3612 {
3613 int type;
3614 char token[MAXTOKEN];
3615 int bracketcount = 1;
3616
3617 type = get_token(fp, token, MAXTOKEN);
3618
3619 if (type != LEFTBRACKET)
3620 return 0;
3621 while ((type != RIGHTBRACKET || bracketcount > 0) && type != ENDOFFILE )
3622 {
3623 type = get_token(fp, token, MAXTOKEN);
3624 if (type == LEFTBRACKET)
3625 bracketcount++;
3626 else if (type == RIGHTBRACKET)
3627 bracketcount--;
3628 }
3629
3630 if (type == RIGHTBRACKET)
3631 return OBJID;
3632 else
3633 return 0;
3634 }
3635
3636 struct tree *
3637 find_node(const char *name,
3638 struct tree *subtree) /* Unused */
3639 {
3640 return( find_tree_node( name, -1 ));
3641 }
3642
3643 struct module *
3644 find_module(int mid)
3645 {
3646 struct module *mp;
3647
3648 for(mp=module_head; mp!=NULL; mp = mp->next) {
3649 if (mp->modid == mid)
3650 break;
3651 }
3652 if (mp != 0)
3653 return mp;
3654 return NULL;
3655 }
3656
3657
3658 static char leave_indent[256];
3659 static int leave_was_simple;
3660
3661 static void print_mib_leaves(FILE *f, struct tree *tp, int width)
3662 { struct tree *ntp;
3663 char *ip = leave_indent+strlen(leave_indent)-1;
3664 char last_ipch = *ip;
3665
3666 *ip = '+';
3667 if (tp->type == 0)
3668 fprintf(f, "%s--%s(%ld)\n", leave_indent, tp->label, tp->subid);
3669 else {
3670 const char *acc, *typ;
3671 int size = 0;
3672 switch (tp->access) {
3673 case MIB_ACCESS_NOACCESS: acc = "----"; break;
3674 case MIB_ACCESS_READONLY: acc = "-R--"; break;
3675 case MIB_ACCESS_WRITEONLY: acc = "--W-"; break;
3676 case MIB_ACCESS_READWRITE: acc = "-RW-"; break;
3677 case MIB_ACCESS_NOTIFY: acc = "---N"; break;
3678 case MIB_ACCESS_CREATE: acc = "CR--"; break;
3679 default: acc = " "; break;
3680 }
3681 switch (tp->type) {
3682 case TYPE_OBJID: typ = "ObjID "; break;
3683 case TYPE_OCTETSTR: typ = "String "; size = 1; break;
3684 case TYPE_INTEGER:
3685 if (tp->enums) typ = "EnumVal ";
3686 else typ = "Integer "; break;
3687 case TYPE_NETADDR: typ = "NetAddr "; break;
3688 case TYPE_IPADDR: typ = "IpAddr "; break;
3689 case TYPE_COUNTER: typ = "Counter "; break;
3690 case TYPE_GAUGE: typ = "Gauge "; break;
3691 case TYPE_TIMETICKS: typ = "TimeTicks"; break;
3692 case TYPE_OPAQUE: typ = "Opaque "; size = 1; break;
3693 case TYPE_NULL: typ = "Null "; break;
3694 case TYPE_COUNTER64: typ = "Counter64"; break;
3695 case TYPE_BITSTRING: typ = "BitString"; break;
3696 case TYPE_NSAPADDRESS: typ = "NsapAddr "; break;
3697 case TYPE_UINTEGER: typ = "UInteger "; break;
3698 default: typ = " "; break;
3699 }
3700 fprintf(f, "%s-- %s %s %s(%ld)\n", leave_indent, acc, typ, tp->label, tp->subid);
3701 *ip = last_ipch;
3702 if (tp->tc_index >= 0)
3703 fprintf(f, "%s Textual Convention: %s\n", leave_indent,
3704 tclist[tp->tc_index].descriptor);
3705 if (tp->enums) {
3706 struct enum_list *ep = tp->enums;
3707 int cpos = 0, cmax = width - strlen(leave_indent) - 16;
3708 fprintf(f, "%s Values: ", leave_indent);
3709 while (ep) {
3710 char buf[80];
3711 int bufw;
3712 if (ep != tp->enums) fprintf(f, ", ");
3713 sprintf(buf, "%s(%d)", ep->label, ep->value);
3714 cpos += (bufw = strlen(buf) + 2);
3715 if (cpos >= cmax) {
3716 fprintf(f, "\n%s ", leave_indent);
3717 cpos = bufw;
3718 }
3719 fprintf(f, "%s", buf);
3720 ep = ep->next;
3721 }
3722 fprintf(f, "\n");
3723 }
3724 if (tp->ranges) {
3725 struct range_list *rp = tp->ranges;
3726 if (size) fprintf(f, "%s Size: ", leave_indent);
3727 else fprintf(f, "%s Range: ", leave_indent);
3728 while (rp) {
3729 if (rp != tp->ranges) fprintf(f, " | ");
3730 if (rp->low == rp->high) fprintf(f, "%d", rp->low);
3731 else fprintf(f, "%d..%d", rp->low, rp->high);
3732 rp = rp->next;
3733 }
3734 fprintf(f, "\n");
3735 }
3736 }
3737 *ip = last_ipch;
3738 strcat(leave_indent, " |");
3739 leave_was_simple = tp->type != 0;
3740
3741 { int i, j, count = 0;
3742 struct leave {
3743 oid id;
3744 struct tree *tp;
3745 } *leaves, *lp;
3746
3747 for (ntp = tp->child_list; ntp; ntp = ntp->next_peer) count++;
3748 if (count) {
3749 leaves = (struct leave *)calloc(count, sizeof(struct leave));
3750 if (!leaves) return;
3751 for (ntp = tp->child_list, count = 0; ntp; ntp = ntp->next_peer) {
3752 for (i = 0, lp = leaves; i < count; i++, lp++)
3753 if (lp->id >= ntp->subid) break;
3754 for (j = count; j > i; j--) leaves[j] = leaves[j-1];
3755 lp->id = ntp->subid;
3756 lp->tp = ntp;
3757 count++;
3758 }
3759 for (i = 1, lp = leaves; i <= count; i++, lp++) {
3760 if (!leave_was_simple || lp->tp->type == 0)
3761 fprintf(f, "%s\n", leave_indent);
3762 if (i == count) ip[3] = ' ';
3763 print_mib_leaves(f, lp->tp, width);
3764 }
3765 free(leaves);
3766 leave_was_simple = 0;
3767 }
3768 }
3769 ip[1] = 0;
3770 }
3771
3772 void print_mib_tree(FILE *f, struct tree *tp, int width)
3773 {
3774 leave_indent[0] = ' ';
3775 leave_indent[1] = 0;
3776 leave_was_simple = 1;
3777 print_mib_leaves(f, tp, width);
3778 }
3779
3780
3781 /*
3782 * Merge the parsed object identifier with the existing node.
3783 * If there is a problem with the identifier, release the existing node.
3784 */
3785 static struct node *
3786 merge_parse_objectid(struct node *np,
3787 FILE *fp,
3788 char *name)
3789 {
3790 struct node *nnp;
3791
3792 nnp = parse_objectid(fp, name);
3793 if (nnp) {
3794 /* apply last OID sub-identifier data to the information */
3795 /* already collected for this node. */
3796 struct node *headp, *nextp;
3797 int ncount = 0;
3798 nextp = headp = nnp;
3799 while (nnp->next) {
3800 nextp = nnp;
3801 ncount++;
3802 nnp = nnp->next;
3803 }
3804
3805 np->label = nnp->label;
3806 np->subid = nnp->subid;
3807 np->modid = nnp->modid;
3808 np->parent = nnp->parent;
3809 free(nnp);
3810
3811 if (ncount) {
3812 nextp->next = np;
3813 np = headp;
3814 }
3815 }
3816 else {
3817 free_node(np); np = NULL;
3818 }
3819
3820 return np;
3821 }
3822
3823 /*
3824 * transfer data to tree from node
3825 *
3826 * move pointers for alloc'd data from np to tp.
3827 * this prevents them from being freed when np is released.
3828 * parent member is not moved.
3829 *
3830 * CAUTION: nodes may be repeats of existing tree nodes.
3831 * This can happen especially when resolving IMPORT clauses.
3832 *
3833 */
3834 static void
3835 tree_from_node(struct tree *tp, struct node *np)
3836 {
3837 free_partial_tree(tp, FALSE);
3838
3839 tp->label = np->label; np->label = NULL;
3840 tp->enums = np->enums; np->enums = NULL;
3841 tp->ranges = np->ranges; np->ranges = NULL;
3842 tp->indexes = np->indexes; np->indexes = NULL;
3843 tp->hint = np->hint; np->hint = NULL;
3844 tp->units = np->units; np->units = NULL;
3845 tp->description = np->description; np->description = NULL;
3846
3847 tp->subid = np->subid;
3848 tp->tc_index = np->tc_index;
3849 tp->type = translation_table[np->type];
3850 tp->access = np->access;
3851 tp->status = np->status;
3852 set_function(tp);
3853 }
3854