and added files
[bcm963xx.git] / userapps / opensource / net-snmp / local / mib2c
1 #!/usr/bin/perl
2 #!/usr/bin/perl -w
3
4 #
5 # Description: 
6 #
7 # This program, given an OID reference as an argument, creates some
8 # template mib module files to be used with the net-snmp agent.  It is
9 # far from perfect and will not generate working modules, but it
10 # significantly shortens development time by outlining the basic
11 # structure.
12 #
13 # Its up to you to verify what it does and change the default values
14 # it returns.
15 #
16
17 # SNMP
18 my $havesnmp = eval {require SNMP;};
19
20 if (!$havesnmp) {
21     print "
22 ERROR: You don't have the SNMP perl module installed.  Please obtain
23 this by getting the latest source release of the net-snmp toolkit from
24 http://www.net-snmp.org/download/ .  Once you download the source and
25 unpack it, the perl module is contained in the perl/SNMP directory.
26 See the INSTALL file there for instructions.
27
28 ";
29     exit;
30 }
31
32 if ($havesnmp) {
33     eval { import SNMP; }
34 }
35 use FileHandle;
36
37 #use strict 'vars';
38 $SNMP::save_descriptions=1;
39 $SNMP::use_long_names=1;
40 $SNMP::use_enums=1;
41 SNMP::initMib();
42
43 $configfile="mib2c.conf";
44 $debug=0;
45 $quiet=0;
46 $nostats = 0;
47 $noindent = 0;
48
49 sub usage {
50     print "$0 [-h] [-c configfile] [-f prefix] mibNode\n\n";
51     print "  -h\t\tThis message.\n\n";
52     print "  -c configfile\tSpecifies the configuration file to use\n\t\tthat dictates what the output of mib2c will look like.\n\n";
53     print "  -f prefix\tSpecifies the output prefix to use.  All code\n\t\twill be put into prefix.c and prefix.h\n\n";
54     print "  mibNode\tThe name of the top level mib node you want to\n\t\tgenerate code for.  By default, the code will be stored in\n\t\tmibNode.c and mibNode.h (use the -f flag to change this)\n\n";
55     print "  -d\t\tdebugging output (dont do it.  trust me.)\n\n";
56     print "  -s\t\tDon't display statistics at the end\n\n";
57     print "  -S VAR=VAL\tSet $VAR variable to $VAL\n";
58     print "  -i Don't run indent on the resulting code\n";
59     1;
60 }       
61
62 while($#ARGV >= 0) {
63     $_ = shift;
64     $configfile = shift if (/^-c/);
65     $debug = 1 if (/^-d/);
66     if (/-S/) {
67         my $expr = shift;
68         my ($var, $val) = ($expr =~ /([^=]*)=(.*)/);
69         die "no variable specified for -S flag." if (!$var);
70         $vars{$var} = $val;
71     }
72     $quiet = 1 if (/^-q/);
73     $nostats = 1 if (/^-s/);
74     $noindent = 1 if (/^-i/);
75     usage && exit(1) if (/^-h/);
76     $outputName = shift if (/^-f/);
77     $oid = $_ if (/^[^-]/);
78 }
79  
80 #
81 # internal conversion tables
82 #
83
84 %accessToIsWritable = qw(ReadOnly 0 ReadWrite 1 
85                          WriteOnly 1 Create 1);
86 %perltoctypes = qw(OCTETSTR   ASN_OCTET_STR
87                    INTEGER    ASN_INTEGER
88                    INTEGER32  ASN_INTEGER
89                    UNSIGNED32 ASN_UNSIGNED
90                    OBJECTID   ASN_OBJECT_ID
91                    COUNTER64  ASN_COUNTER64
92                    COUNTER    ASN_COUNTER
93                    NETADDR    ASN_COUNTER
94                    UINTEGER   ASN_UINTEGER
95                    IPADDR     ASN_IPADDRESS
96                    BITS       ASN_OCTET_STR
97                    TICKS      ASN_TIMETICKS
98                    GAUGE      ASN_GAUGE
99                    OPAQUE     ASN_OPAQUE);
100 %perltodecl = ("OCTETSTR",  "char",
101                "INTEGER",  "long",
102                "INTEGER32",  "long",
103                "UNSIGNED32", "u_long",
104                "UINTEGER", "u_long",
105                "OBJECTID", "oid",
106                "COUNTER64", "counter64",
107                "COUNTER", "u_long",
108                "IPADDR", "u_long",
109                "BITS", "char",
110                "TICKS", "u_long",
111                "GAUGE", "u_long",
112                "OPAQUE", "char");
113
114 my $mibnode = $SNMP::MIB{$oid};
115 die "you didn't give me a valid OID to start with" if (!$mibnode);
116
117 # setup
118 $outputName = $mibnode->{'label'} if (!defined($outputName));
119 $vars{'name'} = $outputName;
120 $vars{'oid'} = $oid;
121
122 # loop through mib nodes, remembering stuff.
123 setup_data($mibnode);
124
125 # process .conf file
126 $fh = new IO::File;
127 if (-f "$configfile") {
128     $fh->open("$configfile");
129 } elsif(-f "/usr/local/share/snmp/$configfile") {
130     $fh->open("/usr/local/share/snmp/$configfile");
131 } else {
132     print STDERR "Can't find a configuration file called $configfile\n";
133     print STDERR "I looked in . and /usr/local/share/snmp\n";
134 exit;
135 }
136 process();
137 $fh->close;
138
139 if (!$noindent) {
140   foreach $i (keys(%written)) {
141     next if ($i eq "-");
142     print STDERR "running indent on $i\n" if (!$quiet);
143     system("indent -orig -nbc -bap -nut -nfca -T netsnmp_mib_handler -T netsnmp_handler_registration -T netsnmp_delegated_cache -T netsnmp_mib_handler_methods -T netsnmp_old_api_info -T netsnmp_old_api_cache -T netsnmp_set_info -T netsnmp_request_info -T netsnmp_set_info -T netsnmp_tree_cache -T netsnmp_agent_request_info -T netsnmp_cachemap -T netsnmp_agent_session -T netsnmp_array_group_item -T netsnmp_array_group -T netsnmp_table_array_callbacks -T netsnmp_table_row -T netsnmp_table_data -T netsnmp_table_data_set_storage -T netsnmp_table_data_set -T netsnmp_column_info -T netsnmp_table_registration_info -T netsnmp_table_request_info -T netsnmp_iterator_info -T netsnmp_data_list -T netsnmp_oid_array_header -T netsnmp_oid_array_header_wrapper -T netsnmp_oid_stash_node -T netsnmp_pdu -T netsnmp_request_list -T netsnmp_callback_pass -T netsnmp_callback_info -T netsnmp_transport -T netsnmp_transport_list -T netsnmp_tdomain $i");
144   }
145 }
146
147 sub tocommas {
148     my $oid = $_[0];
149     $oid =~ s/\./,/g;
150     $oid =~ s/^\s*,//;
151     return $oid;
152 }
153
154 sub oidlength {
155     return scalar ($_[0] =~ /\./);
156 }
157
158 # replaces $VAR type expressions and $VAR.subcomponent expressions
159 # with data from the mib tree and loop variables.
160 # possible uses:
161 #
162 #   $var               -- as defined by loops, etc.
163 #   ${var}otherstuff   -- appending text to variable contents
164 #   $var.uc            -- all upper case version of $var
165 #
166 # Mib components, $var must first expand to a mib node name:
167 #
168 #   $var.objectID      -- dotted full OID
169 #   $var.commaoid      -- comma separated OID for array init
170 #   $var.subid         -- last number component of oid
171 #   $var.oidlength     -- length of the oid
172 #   $var.type          -- node's ASN_XXX type
173 #   $var.settable      -- 1 if it's writable, 0 if not
174 #   $var.noaccess      -- 1 if not-accessible, 0 if not
175 #   $var.access        -- node's access type
176 #   $var.status        -- node's status
177 #   $var.syntax        -- node's syntax
178 #   $var.decl          -- C data type
179 sub process_vars {
180     my $it = shift;
181
182     # mib substitutions ($var.type -> $mibnode->{'type'})
183     $it =~ s/\$(\w+)\.(uc)/uc($vars{$1})/eg; # make something uppercase
184     $it =~ s/\$(\w+)\.(commaoid)/tocommas($SNMP::MIB{$vars{$1}}{objectID})/eg;
185     $it =~ s/\$(\w+)\.(oidlength)/oidlength($SNMP::MIB{$vars{$1}}{objectID})/eg;
186     $it =~ s/\$(\w+)\.(perltype)/$SNMP::MIB{$vars{$1}}{type}/g;
187     $it =~ s/\$(\w+)\.(type)/$perltoctypes{$SNMP::MIB{$vars{$1}}{$2}}/g;
188     $it =~ s/\$(\w+)\.(subid)/$SNMP::MIB{$vars{$1}}{subID}/g;
189     $it =~ s/\$(\w+)\.(settable)/(($SNMP::MIB{$vars{$1}}{access} =~ \/(ReadWrite|Create|Writeonly)\/)?1:0)/eg;
190     $it =~ s/\$(\w+)\.(noaccess)/(($SNMP::MIB{$vars{$1}}{access} =~ \/(NoAccess)\/)?1:0)/eg;
191     $it =~ s/\$(\w+)\.(objectID|label|subID|access|status|syntax)/$SNMP::MIB{$vars{$1}}{$2}/g;
192     $it =~ s/\$(\w+)\.(decl)/$perltodecl{$SNMP::MIB{$vars{$1}}{type}}/g;
193     # normal variable substitions
194     $it =~ s/\$\{(\w+)\}/$vars{$1}/g;
195     $it =~ s/\$(\w+)/$vars{$1}/g;
196     return $it;
197 }
198
199 # process various types of statements
200 #
201 # which include:
202 #   @open FILE@
203 #     writes generated output to FILE
204 #   @foreach $VAR scalar@
205 #     repeat iterate over code until @end@ setting $VAR to all known scalars
206 #   @foreach $VAR table@
207 #     repeat iterate over code until @end@ setting $VAR to all known tables
208 #   @foreach $VAR column@
209 #     repeat iterate over code until @end@ setting $VAR to all known
210 #     columns within a given table.  Obviously this must be called
211 #     within a foreach-table clause.
212 #   @foreach $VAR index@
213 #     repeat iterate over code until @end@ setting $VAR to all known
214 #     indexes within a given table.  Obviously this must be called
215 #     within a foreach-table clause.
216 #   @eval $VAR = expression@
217 #     evaluates expression and assigns the results to $VAR
218 #   @perleval STUFF@
219 #     evaluates STUFF directly in perl.  Note that all mib2c variables
220 #     interpereted within .conf files are in $vars{NAME}.
221 #   @skip@
222 #     skips everything till the appropriately matched @end@
223 #   @if expression@
224 #      evaluates expression, and if expression is true processes
225 #      contained part until appropriate @end@ is reached.
226 sub skippart {
227     my $endcount = 1;
228     while(<$fh>) {
229         if (/\@end\@/) {
230             return if ($endcount == 1);
231             $endcount--;
232         }
233         if (/\@else\@/) {
234             return if ($endcount == 1);
235         }
236         if (/\@(foreach|if)/) {
237             $endcount++;
238         }
239     }
240 }
241
242
243 sub process {
244     while(<$fh>) {
245         if (/^\#\#/) {
246             # noop, it's a comment
247         } elsif (/\@open\s+([^\@]+)\@/) {
248             my $spec = process_vars($1);
249             $out->close() if ($out);
250             $out = new IO::File;
251             $out->open(">$spec") || die "failed to open $spec";
252             print STDERR "writing to $spec\n" if (!$quiet);
253             $written{$spec} = '1';
254         } elsif (/\@end\@/) {
255             return;
256         } elsif (/\@if\s+([^@]*)\@/) {
257             if (eval(process_vars($1))) {
258                 process();
259             } else {
260                 skippart();
261             }
262         } elsif (/\@eval\s+\$(\w+)\s*=\s*([^\@]*)/) {
263             my ($v, $e) = ($1, $2);
264             my $e = process_vars($e);
265             $vars{$v} = eval($e);
266         } elsif (/\@perleval\s*(.*)\@/) {
267             eval($1);
268         } elsif (/\@skip\@/) {
269             skippart();
270         } elsif (/\@\s*foreach\s+\$([^\@]+)\s+scalars*\s*\@/) {
271             my $var = $1;
272             my $startpos = $fh->tell();
273             my $scalar;
274             my @thekeys = keys(%scalars);
275             if ($#thekeys == -1) {
276               skippart();
277             } else {
278               foreach $scalar (@thekeys) {
279                 $fh->seek($startpos, 0); # go to top of section.
280                 my $oldvar = $vars{$var};
281                 $vars{$var} = $scalar;
282                 my $oldscalar = $currentscalar;
283                 $currentscalar = $scalar;
284                 process();
285                 $vars{$var} = $oldvar;
286                 $currentscalar = $oldscalar;
287               }
288             }
289           } elsif (/\@\s*foreach\s+\$([^\@]+)\s+tables*\s*\@/) {
290             my $var = $1;
291             my $startpos = $fh->tell();
292             my $table;
293             my @thekeys = keys(%tables);
294             if ($#thekeys == -1) {
295               skippart();
296             } else {
297               foreach $table (@thekeys) {
298                 $fh->seek($startpos, 0); # go to top of section.
299                 my $oldvar = $vars{$var};
300                 $vars{$var} = $table;
301                 my $oldtable = $currenttable;
302                 $currenttable = $table;
303                 process();
304                 $vars{$var} = $oldvar;
305                 $currenttable = $oldtable;
306               }
307             }
308           } elsif (/\@\s*foreach\s+\$([^\@]+)\s+(column|index)\s*\@/) {
309             my ($var, $type) = ($1, $2);
310             my $startpos = $fh->tell();
311             my $column;
312             if ($#{$tables{$currenttable}{$type}} == -1) {
313               skippart();
314             } else {
315               foreach $column (@{$tables{$currenttable}{$type}}) {
316                 #               print "looping on $var for $type -> $column\n";
317                 $fh->seek($startpos, 0); # go to top of section.
318                 my $oldvar = $vars{$var};
319                 $vars{$var} = $column;
320                 my $oldcolumn = $currentcolumn;
321                 $currentcolumn = $column;
322                 process();
323                 $vars{$var} = $oldvar;
324                 $currentcolumn = $oldcolumn;
325               }
326             }
327           } elsif (/\@\s*foreach\s+\$([^\@]+)\s+\$([^\@]+)\s+(enums*)\s*\@/) {
328             my ($varvar, $varval, $type) = ($1, $2, $3);
329             my $startpos = $fh->tell();
330             my $enum;
331             my @keys = sort { $SNMP::MIB{$currentcolumn}{'enums'}{$a} <=>
332                                   $SNMP::MIB{$currentcolumn}{'enums'}{$b} } (keys(%{$SNMP::MIB{$currentcolumn}{'enums'}}));
333             if ($#keys > -1) {
334                 foreach $enum (@keys) {
335                     $fh->seek($startpos, 0); # go to top of section.
336                     my $oldvarvar = $vars{$varvar};
337                     my $oldvarval = $vars{$varval};
338                     $vars{$varvar} = $enum;
339                     $vars{$varval} = $SNMP::MIB{$currentcolumn}{'enums'}{$enum};
340                     process();
341                     $vars{$varvar} = $oldvarvar;
342                     $vars{$varval} = $oldvarval;
343                 }
344             } else {
345                 skippart();
346             }
347         } else {
348             die "no output file specified" if (!$out);
349             print $out process_vars($_);
350         }
351     }
352 }
353
354 sub setup_data {
355     my $mib = shift;
356     if ($mib->{label} =~ /Table$/) {
357         my $tablename = $mib->{label};
358         my $entry = $mib->{children};
359         my $columns = $entry->[0]{children};
360         foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
361             # store by numeric key so we can sort them later
362             push @{$tables{$tablename}{'column'}}, $col->{'label'};
363         }
364         foreach my $index (@{$entry->[0]{'indexes'}}) {
365             my $node = $SNMP::MIB{$index} || 
366                 die "can't find info about index $index in table $tablename\n";
367             push @{$tables{$tablename}{'index'}}, $index;
368         }
369     } else {
370         my $children = $mib->{children};
371         if ($#children == -1 && $mib->{type}) {
372             # scalar
373             $scalars{$mib->{label}} = 1;
374         } else {
375             my $i;
376             for($i = 0; $i <= $#$children; $i++) {
377                 setup_data($children->[$i]);
378             }
379         }
380     }
381 }
382
383 sub min {
384     return $_[0] if ($_[0] < $_[1]);
385     return $_[1];
386 }
387
388 sub max {
389     return $_[0] if ($_[0] > $_[1]);
390     return $_[1];
391 }