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
13 # Its up to you to verify what it does and change the default values
18 my $havesnmp = eval {require SNMP;};
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.
38 $SNMP::save_descriptions=1;
39 $SNMP::use_long_names=1;
43 $configfile="mib2c.conf";
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";
64 $configfile = shift if (/^-c/);
65 $debug = 1 if (/^-d/);
68 my ($var, $val) = ($expr =~ /([^=]*)=(.*)/);
69 die "no variable specified for -S flag." if (!$var);
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 (/^[^-]/);
81 # internal conversion tables
84 %accessToIsWritable = qw(ReadOnly 0 ReadWrite 1
85 WriteOnly 1 Create 1);
86 %perltoctypes = qw(OCTETSTR ASN_OCTET_STR
89 UNSIGNED32 ASN_UNSIGNED
90 OBJECTID ASN_OBJECT_ID
91 COUNTER64 ASN_COUNTER64
100 %perltodecl = ("OCTETSTR", "char",
103 "UNSIGNED32", "u_long",
104 "UINTEGER", "u_long",
106 "COUNTER64", "counter64",
114 my $mibnode = $SNMP::MIB{$oid};
115 die "you didn't give me a valid OID to start with" if (!$mibnode);
118 $outputName = $mibnode->{'label'} if (!defined($outputName));
119 $vars{'name'} = $outputName;
122 # loop through mib nodes, remembering stuff.
123 setup_data($mibnode);
127 if (-f "$configfile") {
128 $fh->open("$configfile");
129 } elsif(-f "/usr/local/share/snmp/$configfile") {
130 $fh->open("/usr/local/share/snmp/$configfile");
132 print STDERR "Can't find a configuration file called $configfile\n";
133 print STDERR "I looked in . and /usr/local/share/snmp\n";
140 foreach $i (keys(%written)) {
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");
155 return scalar ($_[0] =~ /\./);
158 # replaces $VAR type expressions and $VAR.subcomponent expressions
159 # with data from the mib tree and loop variables.
162 # $var -- as defined by loops, etc.
163 # ${var}otherstuff -- appending text to variable contents
164 # $var.uc -- all upper case version of $var
166 # Mib components, $var must first expand to a mib node name:
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
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;
199 # process various types of statements
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
219 # evaluates STUFF directly in perl. Note that all mib2c variables
220 # interpereted within .conf files are in $vars{NAME}.
222 # skips everything till the appropriately matched @end@
224 # evaluates expression, and if expression is true processes
225 # contained part until appropriate @end@ is reached.
230 return if ($endcount == 1);
234 return if ($endcount == 1);
236 if (/\@(foreach|if)/) {
246 # noop, it's a comment
247 } elsif (/\@open\s+([^\@]+)\@/) {
248 my $spec = process_vars($1);
249 $out->close() if ($out);
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\@/) {
256 } elsif (/\@if\s+([^@]*)\@/) {
257 if (eval(process_vars($1))) {
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*(.*)\@/) {
268 } elsif (/\@skip\@/) {
270 } elsif (/\@\s*foreach\s+\$([^\@]+)\s+scalars*\s*\@/) {
272 my $startpos = $fh->tell();
274 my @thekeys = keys(%scalars);
275 if ($#thekeys == -1) {
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;
285 $vars{$var} = $oldvar;
286 $currentscalar = $oldscalar;
289 } elsif (/\@\s*foreach\s+\$([^\@]+)\s+tables*\s*\@/) {
291 my $startpos = $fh->tell();
293 my @thekeys = keys(%tables);
294 if ($#thekeys == -1) {
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;
304 $vars{$var} = $oldvar;
305 $currenttable = $oldtable;
308 } elsif (/\@\s*foreach\s+\$([^\@]+)\s+(column|index)\s*\@/) {
309 my ($var, $type) = ($1, $2);
310 my $startpos = $fh->tell();
312 if ($#{$tables{$currenttable}{$type}} == -1) {
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;
323 $vars{$var} = $oldvar;
324 $currentcolumn = $oldcolumn;
327 } elsif (/\@\s*foreach\s+\$([^\@]+)\s+\$([^\@]+)\s+(enums*)\s*\@/) {
328 my ($varvar, $varval, $type) = ($1, $2, $3);
329 my $startpos = $fh->tell();
331 my @keys = sort { $SNMP::MIB{$currentcolumn}{'enums'}{$a} <=>
332 $SNMP::MIB{$currentcolumn}{'enums'}{$b} } (keys(%{$SNMP::MIB{$currentcolumn}{'enums'}}));
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};
341 $vars{$varvar} = $oldvarvar;
342 $vars{$varval} = $oldvarval;
348 die "no output file specified" if (!$out);
349 print $out process_vars($_);
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'};
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;
370 my $children = $mib->{children};
371 if ($#children == -1 && $mib->{type}) {
373 $scalars{$mib->{label}} = 1;
376 for($i = 0; $i <= $#$children; $i++) {
377 setup_data($children->[$i]);
384 return $_[0] if ($_[0] < $_[1]);
389 return $_[0] if ($_[0] > $_[1]);