OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [snmp/] [lib/] [v2_0/] [src/] [parse.c] - Blame information for rev 174

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.