mib2c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:39k
- #!/usr/bin/perl
- #!/usr/bin/perl -w
- #
- # $Id: mib2c,v 5.57 2004/09/10 12:30:15 dts12 Exp $
- #
- # Description:
- #
- # This program, given an OID reference as an argument, creates some
- # template mib module files to be used with the net-snmp agent. It is
- # far from perfect and will not generate working modules, but it
- # significantly shortens development time by outlining the basic
- # structure.
- #
- # Its up to you to verify what it does and change the default values
- # it returns.
- #
- # SNMP
- my $havesnmp = eval {require SNMP;};
- my $havenetsnmpoid = eval {require NetSNMP::OID;};
- if (!$havesnmp) {
- print "
- ERROR: You don't have the SNMP perl module installed. Please obtain
- this by getting the latest source release of the net-snmp toolkit from
- http://www.net-snmp.org/download/ . Once you download the source and
- unpack it, the perl module is contained in the perl/SNMP directory.
- See the README file there for instructions.
- ";
- exit;
- }
- if ($havesnmp) {
- eval { import SNMP; }
- }
- if ($havenetsnmp) {
- eval { import NetSNMP::OID; }
- }
- use FileHandle;
- #use strict 'vars';
- $SNMP::save_descriptions=1;
- $SNMP::use_long_names=1;
- $SNMP::use_enums=1;
- SNMP::initMib();
- $configfile="mib2c.conf";
- $debug=0;
- $quiet=0;
- $strict_unk_token = 0;
- $noindent = 0;
- $currentline = 0;
- $currentlevel = -1;
- %assignments;
- %outputs;
- @def_search_dirs = (".");
- @search_dirs = ();
- if($ENV{MIB2C_DIR}) {
- push @def_search_dirs, split(/:/, $ENV{MIB2C_DIR});
- }
- push @def_search_dirs, "/usr/local/share/snmp/";
- push @def_search_dirs, "/usr/local/share/snmp/mib2c-data";
- push @def_search_dirs, "./mib2c-conf.d";
- sub usage {
- print "$0 [-h] [-c configfile] [-f prefix] mibNodenn";
- print " -httThis message.nn";
- print " -c configfiletSpecifies the configuration file to usenttthat dictates what the output of mib2c will look like.nn";
- print " -I PATHtSpecifies a path to look for configuration files innn";
- print " -f prefixtSpecifies the output prefix to use. All codenttwill be put into prefix.c and prefix.hnn";
- print " -dttdebugging output (don't do it. trust me.)nn";
- print " -S VAR=VALtSet $VAR variable to $VALnn";
- print " -ittDon't run indent on the resulting codenn";
- print " mibNodetThe name of the top level mib node you want tonttgenerate code for. By default, the code will be stored innttmibNode.c and mibNode.h (use the -f flag to change this)nn";
- 1;
- }
- my @origargs = @ARGV;
- my $args_done = 0;
- while($#ARGV >= 0) {
- $_ = shift;
- if (/^-/) {
- if ($args_done != 0) {
- warn "all argument must be specified before the mibNode!n";
- usage;
- exit 1;
- } elsif (/^-c/) {
- $configfile = shift;
- } elsif (/^-d/) {
- $debug = 1;
- } elsif (/^-S/) {
- my $expr = shift;
- my ($var, $val) = ($expr =~ /([^=]*)=(.*)/);
- die "no variable specified for -S flag." if (!$var);
- $assignments{$var} = $val;
- } elsif (/^-q/) {
- $quiet = 1;
- } elsif (/^-i/) {
- $noindent = 1;
- } elsif (/^-h/) {
- usage && exit(1);
- } elsif (/^-f/) {
- $outputName = shift;
- } elsif (/^-I/) {
- my $dirs = shift;
- push @search_dirs, split(/,/,$dirs);
- } else {
- warn "Unknown option '$_'n";
- usage;
- exit 1;
- }
- } else {
- $args_done = 1;
- warn "Replacing previous mibNode $oid with $_n" if ($oid);
- $oid = $_ ;
- }
- }
-
- #
- # internal conversion tables
- #
- %accessToIsWritable = qw(ReadOnly 0 ReadWrite 1
- WriteOnly 1 Create 1);
- %perltoctypes = qw(OCTETSTR ASN_OCTET_STR
- INTEGER ASN_INTEGER
- INTEGER32 ASN_INTEGER
- UNSIGNED32 ASN_UNSIGNED
- OBJECTID ASN_OBJECT_ID
- COUNTER64 ASN_COUNTER64
- COUNTER ASN_COUNTER
- NETADDR ASN_COUNTER
- UINTEGER ASN_UINTEGER
- IPADDR ASN_IPADDRESS
- BITS ASN_OCTET_STR
- TICKS ASN_TIMETICKS
- GAUGE ASN_GAUGE
- OPAQUE ASN_OPAQUE);
- %perltodecl = ("OCTETSTR", "char",
- "INTEGER", "long",
- "INTEGER32", "long",
- "UNSIGNED32", "u_long",
- "UINTEGER", "u_long",
- "OBJECTID", "oid",
- "COUNTER64", "U64",
- "COUNTER", "u_long",
- "IPADDR", "u_long",
- "BITS", "char",
- "TICKS", "u_long",
- "GAUGE", "u_long",
- "OPAQUE", "u_char");
- %perltolen = ("OCTETSTR", "1",
- "INTEGER", "0",
- "INTEGER32", "0",
- "UNSIGNED32", "0",
- "UINTEGER", "0",
- "OBJECTID", "1",
- "COUNTER64", "0",
- "COUNTER", "0",
- "IPADDR", "0",
- "BITS", "1",
- "TICKS", "0",
- "GAUGE", "0",
- "OPAQUE", "1");
- my $mibnode = $SNMP::MIB{$oid};
- if (!$mibnode) {
- print STDERR "
- You didn't give mib2c a valid OID to start with. IE, I could not find
- any information about the mib node "$oid". This could be caused
- because you supplied an incorrectly node, or by the MIB that you're
- trying to generate code from isn't loaded. To make sure your mib is
- loaded, run mib2c using this as an example:
- env MIBS="+MY-PERSONAL-MIB" mib2c " . join(" ",@origargs) . "
- You might wish to start by reading the MIB loading tutorial at:
- http://www.net-snmp.org/tutorial-5/commands/mib-options.html
- And making sure you can get snmptranslate to display information about
- your MIB node. Once snmptranslate works, then come back and try mib2c
- again.
- ";
- exit 1;
- }
- # setup
- $outputName = $mibnode->{'label'} if (!defined($outputName));
- $vars{'name'} = $outputName;
- $vars{'oid'} = $oid;
- $vars{'example_start'} = " /*n" .
- " ***************************************************n" .
- " *** START EXAMPLE CODE ***n" .
- " ***---------------------------------------------***/";
- $vars{'example_end'} = " /*n" .
- " ***---------------------------------------------***n" .
- " *** END EXAMPLE CODE ***n" .
- " ***************************************************/";
- # loop through mib nodes, remembering stuff.
- setup_data($mibnode);
- if(($ENV{HOME}) && (-f "$ENV{HOME}/.snmp/mib2c.conf")) {
- $fh = open_conf("$ENV{HOME}/.snmp/mib2c.conf");
- process("-balanced");
- $fh->close;
- }
- my $defaults = find_conf("default-$configfile",1);
- if (-f "$defaults" ) {
- $fh = open_conf($defaults);
- process("-balanced");
- $fh->close;
- }
- my @theassignments = keys(%assignments);
- if ($#theassignments != -1) {
- foreach $var (@theassignments) {
- $vars{$var} = $assignments{$var};
- }
- }
- $configfile = find_conf($configfile,0);
- $fh = open_conf($configfile);
- process("-balanced");
- $fh->close;
- if (!$noindent) {
- foreach $i (keys(%written)) {
- next if ($i eq "-");
- next if (!($i =~ /.[ch]$/));
- print STDERR "running indent on $in" if (!$quiet);
- system("indent -orig -nbc -bap -nut -nfca -T size_t -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");
- }
- }
- sub m2c_die {
- warn "ERROR: ". $_[0] . "n";
- die " at $currentfile:$currentlinen";
- }
- sub tocommas {
- my $oid = $_[0];
- $oid =~ s/./,/g;
- $oid =~ s/^s*,//;
- return $oid;
- }
- sub oidlength {
- return (scalar split(/./, $_[0])) - 1;
- }
- # replaces $VAR type expressions and $VAR.subcomponent expressions
- # with data from the mib tree and loop variables.
- # possible uses:
- #
- # $var -- as defined by loops, etc.
- # ${var}otherstuff -- appending text to variable contents
- # $var.uc -- all upper case version of $var
- #
- # NOTE: THESE ARE AUTO-EXTRACTED/PROCESSED BY ../mib2c.extract.pl for man pages
- #
- # Mib components, $var must first expand to a mib node name:
- #
- # $var.uc -- all upper case version of $var
- #
- # $var.objectID -- dotted, fully-qualified, and numeric OID
- # $var.commaoid -- comma separated numeric OID for array initialization
- # $var.oidlength -- length of the oid
- # $var.subid -- last number component of oid
- # $var.module -- MIB name that the object comes from
- # $var.parent -- contains the label of the parent node of $var.
- #
- # $var.isscalar -- returns 1 if var contains the name of a scalar
- # $var.iscolumn -- returns 1 if var contains the name of a column
- # $var.children -- returns 1 if var has children
- #
- # $var.perltype -- node's perl SYNTAX ($SNMP::MIB{node}{'syntax'})
- # $var.type -- node's ASN_XXX type (Net-SNMP specific #define)
- # $var.decl -- C data type (char, u_long, ...)
- #
- # $var.readable -- 1 if an object is readable, 0 if not
- # $var.settable -- 1 if an object is writable, 0 if not
- # $var.creatable -- 1 if a column object can be created as part of a new row, 0 if not
- # $var.noaccess -- 1 if not-accessible, 0 if not
- # $var.accessible -- 1 if accessible, 0 if not
- # $var.rowstatus -- 1 if an object is a RowStatus object, 0 if not
- # 'settable', 'creatable' and 'rowstatus' can also be used with table variables
- # to indicate whether it contains writable, creatable or RowStatus column objects
- #
- # $var.hasdefval -- returns 1 if var has a DEFVAL clause
- # $var.defval -- node's DEFVAL
- # $var.hashint -- returns 1 if var has a HINT clause
- # $var.hint -- node's HINT
- # $var.ranges -- returns 1 if var has a value range defined
- # $var.enums -- returns 1 if var has enums defined for it.
- # $var.access -- node's access type
- # $var.status -- node's status
- # $var.syntax -- node's syntax
- # $var.reference -- node's reference
- # $var.description -- node's description
- sub process_vars {
- my $it = shift;
- # mib substitutions ($var.type -> $mibnode->{'type'})
- if ( $it =~ /$(w+).(w+)/ ) {
- if ($SNMP::MIB{$vars{$1}} && $SNMP::MIB{$vars{$1}}{'label'} =~ /Table$/) {
- $it =~ s/$(w+).(settable)/(table_is_writable($SNMP::MIB{$vars{$1}}{label}))/eg;
- $it =~ s/$(w+).(creatable)/(table_has_create($SNMP::MIB{$vars{$1}}{label}))/eg;
- $it =~ s/$(w+).(rowstatus)/(table_has_rowstatus($SNMP::MIB{$vars{$1}}{label}))/eg;
- }
- $it =~ s/$(w+).(uc)/uc($vars{$1})/eg; # make something uppercase
- $it =~ s/$(w+).(commaoid)/tocommas($SNMP::MIB{$vars{$1}}{objectID})/eg;
- $it =~ s/$(w+).(oidlength)/oidlength($SNMP::MIB{$vars{$1}}{objectID})/eg;
- $it =~ s/$(w+).(description)/$SNMP::MIB{$vars{$1}}{description}/g;
- $it =~ s/$(w+).(perltype)/$SNMP::MIB{$vars{$1}}{type}/g;
- $it =~ s/$(w+).(type)/$perltoctypes{$SNMP::MIB{$vars{$1}}{$2}}/g;
- $it =~ s/$(w+).(subid)/$SNMP::MIB{$vars{$1}}{subID}/g;
- $it =~ s/$(w+).(module)/$SNMP::MIB{$vars{$1}}{moduleID}/g;
- $it =~ s/$(w+).(settable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(ReadWrite|Create|WriteOnly)/)?1:0)/eg;
- $it =~ s/$(w+).(creatable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(Create)/)?1:0)/eg;
- $it =~ s/$(w+).(readable)/(($SNMP::MIB{$vars{$1}}{access} =~ /(Read|Create)/)?1:0)/eg;
- $it =~ s/$(w+).(noaccess)/(($SNMP::MIB{$vars{$1}}{access} =~ /(NoAccess)/)?1:0)/eg;
- $it =~ s/$(w+).(accessible)/(($SNMP::MIB{$vars{$1}}{access} !~ /(NoAccess)/)?1:0)/eg;
- $it =~ s/$(w+).(objectID|label|subID|access|status|syntax|reference)/$SNMP::MIB{$vars{$1}}{$2}/g;
- $it =~ s/$(w+).(decl)/$perltodecl{$SNMP::MIB{$vars{$1}}{type}}/g;
- $it =~ s/$(w+).(needlength)/$perltolen{$SNMP::MIB{$vars{$1}}{type}}/g;
- $it =~ s/$(w+).(iscolumn)/($SNMP::MIB{$vars{$1}}{'parent'}{'label'} =~ /Entry$/) ? 1 : 0/eg;
- $it =~ s/$(w+).(isscalar)/($SNMP::MIB{$vars{$1}}{'parent'}{'label'} !~ /Entry$/ && $SNMP::MIB{$vars{$1}}{access}) ? 1 : 0/eg;
- $it =~ s/$(w+).(parent)/$SNMP::MIB{$vars{$1}}{'parent'}{'label'}/g;
- $it =~ s/$(w+).(children)/($#{$SNMP::MIB{$vars{$1}}{'children'}} == 0) ? 0 : 1/eg;
- $it =~ s/$(w+).(hasdefval)/(length($SNMP::MIB{$vars{$1}}{'defaultValue'}) == 0) ? 0 : 1/eg;
- $it =~ s/$(w+).(defval)/$SNMP::MIB{$vars{$1}}{'defaultValue'}/g;
- $it =~ s/$(w+).(hashint)/(length($SNMP::MIB{$vars{$1}}{'hint'}) == 0) ? 0 : 1/eg;
- $it =~ s/$(w+).(hint)/$SNMP::MIB{$vars{$1}}{'hint'}/g;
- $it =~ s/$(w+).(ranges)/($#{$SNMP::MIB{$vars{$1}}{'ranges'}} == -1) ? 0 : 1/eg;
- # check for enums
- $it =~ s/$(w+).(enums)/(%{$SNMP::MIB{$vars{$1}}{'enums'}} == 0) ? 0 : 1/eg;
- $it =~ s/$(w+).(enumrange)/%{$SNMP::MIB{$vars{$1}}{'enums'}}/eg;
- $it =~ s/$(w+).(rowstatus)/(($SNMP::MIB{$vars{$1}}{syntax} =~ /(RowStatus)/)?1:0)/eg;
- if ( $it =~ /$(w+).(w+)/ ) {
- warn "Possible unknown variable attribute $$1.$2 at $currentfile:$currentlinen";
- }
- }
- # normal variable substitions
- $it =~ s/${(w+)}/$vars{$1}/g;
- $it =~ s/$(w+)/$vars{$1}/g;
- # use $@var to put literal '$var'
- $it =~ s/$@(w+)/$$1/g;
- return $it;
- }
- # process various types of statements
- #
- # NOTE: THESE ARE AUTO-EXTRACTED/PROCESSED BY ../mib2c.extract.pl for man pages
- # which include:
- # @open FILE@
- # writes generated output to FILE
- # note that for file specifications, opening '-' will print to stdout.
- # @append FILE@
- # appends the given FILE
- # @close FILE@
- # closes the given FILE
- # @push@
- # save the current outputs, then clear outputs. Use with @open@
- # and @pop@ to write to a new file without interfering with current
- # outputs.
- # @pop@
- # pop up the process() stack one level. Use after a @push@ to return to
- # the previous set of open files.
- # @foreach $VAR scalar@
- # repeat iterate over code until @end@ setting $VAR to all known scalars
- # @foreach $VAR table@
- # repeat iterate over code until @end@ setting $VAR to all known tables
- # @foreach $VAR column@
- # repeat iterate over code until @end@ setting $VAR to all known
- # columns within a given table. Obviously this must be called
- # within a foreach-table clause.
- # @foreach $VAR nonindex@
- # repeat iterate over code until @end@ setting $VAR to all known
- # non-index columns within a given table. Obviously this must be called
- # within a foreach-table clause.
- # @foreach $VAR internalindex@
- # repeat iterate over code until @end@ setting $VAR to all known internal
- # index columns within a given table. Obviously this must be called
- # within a foreach-table clause.
- # @foreach $VAR externalindex@
- # repeat iterate over code until @end@ setting $VAR to all known external
- # index columns within a given table. Obviously this must be called
- # within a foreach-table clause.
- # @foreach $VAR index@
- # repeat iterate over code until @end@ setting $VAR to all known
- # indexes within a given table. Obviously this must be called
- # within a foreach-table clause.
- # @foreach $VAR notifications@
- # repeat iterate over code until @end@ setting $VAR to all known notifications
- # @foreach $VAR varbinds@
- # repeat iterate over code until @end@ setting $VAR to all known varbinds
- # Obviously this must be called within a foreach-notifications clause.
- # @foreach $LABEL, $VALUE enum@
- # repeat iterate over code until @end@ setting $LABEL and $VALUE
- # to the label and values from the enum list.
- # @foreach $RANGE_START, $RANGE_END range NODE@
- # repeat iterate over code until @end@ setting $RANGE_START and $RANGE_END
- # to the legal accepted range set for a given mib NODE.
- # @foreach $var stuff a b c d@
- # repeat iterate over values a, b, c, d as assigned generically
- # (ie, the values are taken straight from the list with no
- # mib-expansion, etc).
- # @eval $VAR = expression@
- # evaluates expression and assigns the results to $VAR. This is
- # not a full perl eval, but sort of a "psuedo" eval useful for
- # simple expressions while keeping the same variable name space.
- # See below for a full-blown export to perl.
- # @perleval STUFF@
- # evaluates STUFF directly in perl. Note that all mib2c variables
- # interpereted within .conf files are in $vars{NAME}.
- # @startperl@
- # @endperl@
- # treats everything between these tags as perl code, and evaluates it.
- # @next@
- # restart foreach; should only be used inside a conditional.
- # skips out of current conditional, then continues to skip to
- # end for the current foreach clause.
- # @if expression@
- # evaluates expression, and if expression is true processes
- # contained part until appropriate @end@ is reached. If an @else@
- # clause is found, it will be evaluated instead if expression
- # isn't true.
- # @define NAME@
- # @enddefine@
- # Memorizes "stuff" between the define and enddefine tags for
- # later calling as NAME by @calldefine NAME@.
- # @calldefine NAME@
- # Executes stuff previously memorized as NAME.
- # @printf "expression" stuff1, stuff2, ...@
- # Like all the other printf's you know and love.
- # @run FILE@
- # Sources the contents of FILE as a mib2c file,
- # but does not affect current files opened.
- # @include FILE@
- # Sources the contents of FILE as a mib2c file and appends its
- # output to the current output.
- # @prompt $var QUESTION@
- # Presents the user with QUESTION, expects a response and puts it in $var
- # @print STUFF@
- # Prints stuff directly to the users screen (ie, not to where
- # normal mib2c output goes)
- # @exit@
- # Bail out!
- #
- sub skippart {
- my $endcount = 1;
- my $arg = shift;
- my $rtnelse = 0;
- while ($arg =~ s/-(w+)s*//) {
- $rtnelse = 1 if ($1 eq "else");
- }
- while(get_next_line()) {
- $currentline++;
- $_ = process_vars($_) if ($debug);
- print "$currentfile.$currentline:P$currentlevel:S$endcount.$rtnelse:$_" if ($debug);
- next if ( /^s*##/ ); # noop, it's a comment
- next if (! /^s*@/ ); # output
- if (! /^s*@.*@/ ) {
- warn "$currentfile:$currentline contained a line that started with a @ but did not match any mib2c configuration tokens.n";
- warn "(maybe missing the trailing @?)n";
- warn "$currentfile:$currentline [$_]n";
- }
- elsif (/@s*end@/) {
- return "end" if ($endcount == 1);
- $endcount--;
- }
- elsif (/@s*elseif.*@/) {
- m2c_die "use 'elsif' instead of 'elseif'n";
- }
- elsif (/@s*else@/) {
- return "else" if (($endcount == 1) && ($rtnelse == 1));
- }
- elsif (/@s*elsifs+([^@]+)@/) {
- return "else" if (($endcount == 1) && ($rtnelse == 1) && (eval(process_vars($1))));
- }
- elsif (/@s*(foreach|if)/) {
- $endcount++;
- }
- }
- print "skippart EOFn";
- m2c_die "unbalanced code detected in skippart: EOF when $endcount levels deep" if($endcount != 1);
- return "eof";
- }
- sub close_file {
- my $name = shift;
- if (!$name) {
- print "close_file w/out name!n";
- return;
- }
- if(!$outputs{$name}) {
- print "no handle for $namen";
- return;
- }
- $outputs{$name}->close();
- delete $outputs{$name};
- # print STDERR "closing $namen" if (!$quiet);
- }
- sub close_files {
- foreach $name (keys(%outputs)) {
- close_file($name);
- }
- }
- sub open_file {
- my $multiple = shift;
- my $spec = shift;
- my $name = $spec;
- $name =~ s/>//;
- if ($multiple == 0) {
- close_files();
- }
- return if ($outputs{$name});
- $outputs{$name} = new IO::File;
- $outputs{$name}->open(">$spec") || m2c_die "failed to open $name";
- print STDERR "writing to $namen" if (!$quiet && !$written{$name});
- $written{$name} = '1';
- }
- sub process_file {
- my ($file, $missingok, $keepvars) = (@_);
- my $oldfh = $fh;
- my $oldfile = $currentfile;
- my $oldline = $currentline;
- # keep old copy of @vars and just build on it.
- my %oldvars;
- %oldvars = %vars if ($keepvars != 1);
- $file = find_conf($file,$missingok);
- return if (! $file);
- $fh = open_conf($file);
- $currentline = 0;
- process("-balanced");
- $fh->close();
- $fh = $oldfh;
- $currentfile = $oldfile;
- $currentline = $oldline;
- # don't keep values in replaced vars. Revert to ours.
- %vars = %oldvars if ($keepvars != 1);
- }
- sub get_next_line {
- if ($#process_lines > -1) {
- return $_ = shift @process_lines;
- }
- return $_ = <$fh>;
- }
- sub do_tell {
- my $stash;
- $stash->{'startpos'} = $fh->tell();
- $stash->{'startline'} = $currentline;
- @{$stash->{'lines'}} = @process_lines;
- return $stash;
- }
- sub do_seek {
- my $stash = shift;
- # save current line number
- $currentline = $stash->{'startline'};
- $fh->seek($stash->{'startpos'}, 0); # go to top of section.
- # save current process_lines state.
- @process_lines = @{$stash->{'lines'}};
- # save state of a number of variables (references), and new assignments
- for (my $i = 0; $i <= $#_; $i += 2) {
- push @{$stash->{'vars'}}, $_[$i], ${$_[$i]};
- ${$_[$i]} = $_[$i+1];
- }
- }
- sub do_unseek {
- my $stash = shift;
- for (my $i = 0; $i <= $#{$stash->{'vars'}}; $i += 2) {
- ${$stash->{'vars'}[$i]} = $stash->{'vars'}[$i+1];
- }
- }
- sub do_a_loop {
- my $stash = shift;
- do_seek($stash, @_);
- my $return = process();
- do_unseek($stash);
- return $return;
- }
- sub process {
- my $arg = shift;
- my $elseok = 0;
- my $balanced = 0;
- my $startlevel;
- my $return = "eof";
- while ($arg =~ s/-(w+)s*//) {
- $elseok = 1 if ($1 eq "elseok");
- $balanced = 1 if ($1 eq "balanced");
- }
- $currentlevel++;
- $startlevel = $currentlevel;
- if($balanced) {
- $balanced = $currentlevel;
- }
- while(get_next_line()) {
- $currentline++;
- if ($debug) {
- # my $line = process_vars($_);
- # chop $line;
- print "$currentfile.$currentline:P$currentlevel.$elseok:$return:$_";
- }
- next if (/^s*##/); # noop, it's a comment
- if (! /^s*@/ ) { # output
- my $line = process_vars($_);
- foreach $file (values(%outputs)) {
- print $file "$line";
- }
- } ####################################################################
- elsif (/@s*exit@/) { # EXIT
- close_files;
- die "exiting at conf file ($currentfile:$currentline) requestn";
- } elsif (/@s*debugs+([^@]+)@/) { # DEBUG
- if ($1 eq "on") {
- $debug = 1;
- }
- else {
- $debug = 0;
- }
- } elsif (/@s*strict tokens+([^@]+)@/) { # STRICT
- if ($1 eq "on") {
- $strict_unk_token = 1;
- }
- else {
- $strict_unk_token = 0;
- }
- } elsif (/@s*balanced@/) { # BALANCED
- $balanced = $currentlevel;
- } elsif (/@s*opens+([^@]+)@/) { # OPEN
- my $arg = $1;
- my ($multiple) = (0);
- while ($arg =~ s/-(w+)s+//) {
- $multiple = 1 if ($1 eq 'multiple');
- }
- my $spec = process_vars($arg);
- open_file($multiple, $spec);
- } elsif (/@s*closes+([^@]+)@/) { # CLOSE
- my $spec = process_vars($1);
- close_file($spec);
- } elsif (/@s*appends+([^@]+)@/) { # APPEND
- my $arg = $1;
- my ($multiple) = (0);
- while ($arg =~ s/-(w+)s+//) {
- $multiple = 1 if ($1 eq 'multiple');
- }
- my $spec = process_vars($arg);
- $spec=">$spec";
- open_file($multiple,$spec);
- } elsif (/@s*defines*(.*)@/) { # DEFINE
- my $it = $1;
- while (<$fh>) {
- last if (/@s*enddefines*@/);
- push @{$defines{$it}}, $_;
- }
- } elsif (/@s*calldefines+(w+)@/) {
- if ($#{$defines{$1}} == -1) {
- warn "called a define of $1 which didn't existn";
- warn "$currentfile:$currentline [$_]n";
- } else {
- unshift @process_lines, @{$defines{$1}};
- }
- } elsif (/@s*run (.*)@/) { # RUN
- my $arg = $1;
- my ($again) = (0);
- while ($arg =~ s/-(w+)s+//) {
- $again = 1 if ($1 eq 'again');
- # if ($1 eq 'file') {
- # my ($filearg) = ($arg =~ s/^(w+)//);
- # }
- }
- my $spec = process_vars($arg);
- next if (!$again && $ranalready{$spec});
- $ranalready{$spec} = 1;
- my %oldout = %outputs;
- my %emptyarray;
- %outputs = %emptyoutputs;
- process_file($spec,0,0);
- close_files;
- %outputs = %oldout;
- } elsif (/@s*push@/) { # PUSH
- my %oldout = %outputs;
- my %emptyarray;
- %outputs = %emptyoutputs;
- process($arg);
- close_files;
- %outputs = %oldout;
- } elsif (/@s*pops*@/) { # POP
- $return = "pop";
- last;
- } elsif (/@s*include (.*)@/) { # INCLUDE
- my $arg = $1;
- my ($missingok) = (0);
- while ($arg =~ s/-(w+)s+//) {
- $missingok = 1 if ($1 eq 'ifexists');
- }
- my $spec = process_vars($arg);
- process_file($spec,$missingok,1);
- } elsif (/@s*if([a-z]*)s+([^@]+)@/) { # IF
- my ($type,$arg,$ok) = ($1,$2,0);
- # check condition based on type
- if (! $type) {
- $ok = eval(process_vars($arg));
- } elsif ($type eq conf) {
- my $file = find_conf(process_vars($arg),1); # missingok
- $ok = (-f $file);
- } else {
- m2c_die "unknown if modifier ($type)n";
- }
- # act on condition
- if ($ok) {
- $return = process("-elseok");
- } else {
- $return = skippart("-else");
- $return = process("-elseok") if ($return eq "else");
- }
- if ($return eq "next") {
- $return = skippart();
- m2c_die("unbalanced code detected while exiting next/2 (returned $return)") if ($return ne "end");
- # $return = "next";
- last;
- }
- if (($return ne "end") && ($return ne "else")) {
- m2c_die "unbalanced if / return $returnn";
- }
- } elsif (/@s*elseif.*@/) { # bogus elseif
- m2c_die "error: use 'elsif' instead of 'elseif'n";
- } elsif (/@s*els(e|if).*@/) { # ELSE/ELSIF
- if ($elseok != 1) {
- chop $_;
- m2c_die "unexpected els$1n";
- }
- $return = skippart();
- if ($return ne "end") {
- m2c_die "unbalanced els$1 / rtn $rtnn";
- }
- $return = "else";
- last;
- } elsif (/@s*nexts*@/) { # NEXT
- $return = skippart();
- m2c_die "unbalanced code detected while exiting next/1 (returned $return)" if ($return ne "end");
- $return = "next";
- last;
- } elsif (/@s*end@/) { # END
- $return = "end";
- last;
- } elsif (/@s*evals+$(w+)s*=s*([^@]*)/) { # EVAL
- my ($v, $e) = ($1, $2);
- # print STDERR "eval: $en";
- my $e = process_vars($e);
- $vars{$v} = eval($e);
- if (!defined($vars{$v})) {
- warn "$@";
- warn "$currentfile:$currentline [$_]n";
- }
- } elsif (/@s*perlevals*(.*)@/) { # PERLEVAL
- # print STDERR "perleval: $1n";
- my $res = eval($1);
- if ($res) {
- warn "$@";
- warn "$currentfile:$currentline [$_]n";
- }
- } elsif (/@s*startperls*@/) { # STARTPERL
- my $text;
- while (get_next_line()) {
- last if (/@s*endperls*@/);
- $text .= $_;
- }
- my $res = eval($text);
- if ($res) {
- warn "$@";
- warn "$currentfile:$currentline [$_]n";
- }
- # print STDERR "perleval: $1n";
- } elsif (/@s*printfs+("[^"]+")s*,?(.*)@/) { # PRINTF
- my ($f, $rest) = ($1, $2);
- $rest = process_vars($rest);
- my @args = split(/s*,s*/,$rest);
- $f = eval $f;
- # print STDERR "printf: $f, ", join(", ",@args),"n";
- foreach $file (values(%outputs)) {
- printf $file (eval {$f}, @args);
- }
- } elsif (/@s*foreachs+$([^@]+)s+scalars*s*@/) { # SCALARS
- my $var = $1;
- my $stash = do_tell();
- my $scalar;
- my @thekeys = keys(%scalars);
- if ($#thekeys == -1) {
- $return = skippart();
- } else {
- if ($havenetsnmpoid) {
- @thekeys = sort {
- new NetSNMP::OID($a) <=>
- new NetSNMP::OID($b) } @thekeys;
- }
- foreach $scalar (@thekeys) {
- $return = do_a_loop($stash, $vars{$var}, $scalar,
- $currentscalar, $scalar,
- $currentvar, $scalar);
- }
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+notifications*s*@/) {
- my $var = $1;
- my $stash = do_tell();
- my $notify;
- my @thekeys = keys(%notifications);
- if ($#thekeys == -1) {
- $return = skippart();
- } else {
- if ($havenetsnmpoid) {
- @thekeys = sort {
- new NetSNMP::OID($a) <=>
- new NetSNMP::OID($b) } @thekeys;
- }
- foreach $notify (@thekeys) {
- $return = do_a_loop($stash, $vars{$var}, $notify,
- $currentnotify, $notify);
- }
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+varbindss*@/) {
- my $var = $1;
- my $stash = do_tell();
- my $varbind;
- if ($#{$notifyvars{$currentnotify}} == -1) {
- $return = skippart();
- } else {
- foreach $varbind (@{$notifyvars{$currentnotify}}) {
- # print "looping on $var for $varbindn";
- $return = do_a_loop($stash, $vars{$var}, $varbind,
- $currentvarbind, $varbind);
- }
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+tables*s*@/) {
- my $var = $1;
- my $stash = do_tell();
- my $table;
- my @thekeys = keys(%tables);
- if ($#thekeys == -1) {
- $return = skippart();
- } else {
- if ($havenetsnmpoid) {
- @thekeys = sort {
- new NetSNMP::OID($a) <=>
- new NetSNMP::OID($b) } @thekeys;
- }
- foreach $table (@thekeys) {
- $return = do_a_loop($stash, $vars{$var}, $table,
- $currenttable, $table);
- }
- }
- m2c_die("foreach did not end with @end@ ($return)") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+stuffs*(.*)@/) {
- my $var = $1;
- my $stuff = $2;
- my @stuff = split(/[,s]+/, $stuff);
- my $stash = do_tell();
- if ($#stuff == -1) {
- $return = skippart();
- } else {
- foreach $st (@stuff) {
- $return = do_a_loop($stash, $vars{$var}, $st,
- $currentstuff, $st);
- }
- }
- m2c_die("foreach did not end with @end@ ($return)") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+(column|index|internalindex|externalindex|nonindex)s*@/) {
- my ($var, $type) = ($1, $2);
- my $stash = do_tell();
- my $column;
- if ($#{$tables{$currenttable}{$type}} == -1) {
- $return = skippart();
- } else {
- foreach $column (@{$tables{$currenttable}{$type}}) {
- # print "looping on $var for $type -> $columnn";
- $return = do_a_loop($stash, $vars{$var}, $column,
- $currentcolumn, $column,
- $currentvar, $column);
- }
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*foreachs+$([^@]+)s+$([^@]+)s+ranges+([^@]+)@/) {
- my ($svar, $evar, $node) = ($1, $2, $3);
- my $stash = do_tell();
- my $range;
- $node = $currentcolumn if (!$node);
- my $mibn = $SNMP::MIB{process_vars($node)};
- die "no such mib node: $node" if (!$mibn);
- my @ranges = @{$mibn->{'ranges'}};
- if ($#ranges > -1) {
- foreach $range (@ranges) {
- $return = do_a_loop($stash, $vars{$svar}, $range->{'low'},
- $vars{$evar}, $range->{'high'});
- }
- } else {
- $return = skippart();
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*foreachs+$([^@,]+)s*,*s+$([^@]+)s+(enums*)s*@/) {
- my ($varvar, $varval, $type) = ($1, $2, $3);
- my $stash = do_tell();
- my $enum, $enum2;
- my @keys = sort { $SNMP::MIB{$currentvar}{'enums'}{$a} <=>
- $SNMP::MIB{$currentvar}{'enums'}{$b} } (keys(%{$SNMP::MIB{$currentvar}{'enums'}}));
- if ($#keys > -1) {
- foreach $enum (@keys) {
- ($enum2 = $enum) =~ s/-/_/g;
- $return = do_a_loop($stash, $vars{$varvar}, $enum2,
- $vars{$varval},
- $SNMP::MIB{$currentvar}{'enums'}{$enum});
- }
- } else {
- $return = skippart();
- }
- m2c_die("foreach did not end with @end@") if($return ne "end");
- } elsif (/@s*prompts+$(S+)s*(.*)@/) { # PROMPT
- my ($var, $prompt) = ($1, $2);
- if (!$term) {
- my $haveit = eval { require Term::ReadLine };
- if ($haveit) {
- $term = new Term::ReadLine 'mib2c';
- }
- }
- if ($term) {
- $vars{$var} = $term->readline(process_vars($prompt));
- }
- } elsif (/@s*prints+([^@]*)@/) { # PRINT
- my $line = process_vars($1);
- print "$linen";
- } else {
- my $line = process_vars($_);
- mib2c_output($line);
- chop $_;
- warn "$currentfile:$currentline contained a line that started with a @ but did not match any mib2c configuration tokens.n";
- warn "(maybe missing the trailing @?)n";
- m2c_die if ($strict_unk_token == 1);
- }
- # $return = "eof";
- }
- print "< Balanced $balanced / level $currentlevel / rtn $return / $_n" if($debug);
- if((!$_) && ($return ne "eof")) {
- # warn "switching return of '$return' to EOFn" if($debug);
- $return = "eof";
- }
- if ($balanced) {
- if(($balanced != $currentlevel) || ($return ne "eof")) {
- m2c_die "@balanced@ specified, but processing terminated with '$return' before EOF!";
- }
- }
- $currentlevel--;
- return $return;
- }
- sub mib2c_output {
- my $line = shift;
- foreach $file (values(%outputs)) {
- print $file "$line";
- }
- }
- sub setup_data {
- my $mib = shift;
- if ($mib->{label} =~ /Table$/) {
- my $tablename = $mib->{label};
- my $entry = $mib->{children};
- my $columns = $entry->[0]{children};
- my $augments = $entry->[0]{'augments'};
- foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
- # store by numeric key so we can sort them later
- push @{$tables{$tablename}{'column'}}, $col->{'label'};
- }
- if ($augments) {
- my $mib = $SNMP::MIB{$augments} ||
- die "can't find info about augmented table $augments in table $tablenamen";
- $mib = $mib->{parent} ||
- die "can't find info about augmented table $augments in table $tablenamen";
- my $entry = $mib->{children};
- foreach my $index (@{$entry->[0]{'indexes'}}) {
- my $node = $SNMP::MIB{$index} ||
- die "can't find info about index $index in table $tablenamen";
- push @{$tables{$tablename}{'index'}}, $index;
- push @{$tables{$tablename}{'externalindex'}}, $index;
- }
- my $columns = $entry->[0]{children};
- }
- else {
- foreach my $index (@{$entry->[0]{'indexes'}}) {
- my $node = $SNMP::MIB{$index} ||
- die "can't find info about index $index in table $tablenamen";
- push @{$tables{$tablename}{'index'}}, $index;
- if("@{$tables{$tablename}{'column'}}" =~ /$indexb/ ) {
- # print "idx INT $indexn";
- push @{$tables{$tablename}{'internalindex'}}, $index;
- } else {
- # print "idx EXT $indexn";
- push @{$tables{$tablename}{'externalindex'}}, $index;
- }
- }
- }
- foreach my $col (sort { $a->{'subID'} <=> $b->{'subID'} } @$columns) {
- next if ( "@{$tables{$tablename}{'index'}}" =~ /$col->{'label'}b/ );
- push @{$tables{$tablename}{'nonindex'}}, $col->{'label'};
- }
- # print "indexes: @{$tables{$tablename}{'index'}}n";
- # print "internal indexes: @{$tables{$tablename}{'internalindex'}}n";
- # print "external indexes: @{$tables{$tablename}{'externalindex'}}n";
- # print "non-indexes: @{$tables{$tablename}{'nonindex'}}n";
- } else {
- my $children = $mib->{children};
- if ($#children == -1 && $mib->{type}) {
- # scalar
- if ($mib->{type} eq "NOTIF" ||
- $mib->{type} eq "TRAP") {
- my $notifyname = $mib->{label};
- my @varlist = ();
- $notifications{$notifyname} = 1;
- $notifyvars{$notifyname} = $mib->{varbinds};
- } else {
- $scalars{$mib->{label}} = 1;
- }
- } else {
- my $i;
- for($i = 0; $i <= $#$children; $i++) {
- setup_data($children->[$i]);
- }
- }
- }
- }
- sub min {
- return $_[0] if ($_[0] < $_[1]);
- return $_[1];
- }
- sub max {
- return $_[0] if ($_[0] > $_[1]);
- return $_[1];
- }
- sub find_conf {
- my ($configfile, $missingok) = (@_);
- foreach my $d (@search_dirs, @def_search_dirs) {
- return "$d/$configfile" if (-f "$d/$configfile");
- }
- return $configfile if (-f "$configfile");
- return if ($missingok);
- print STDERR "Can't find a configuration file called $configfilen";
- print STDERR "(referenced at $currentfile:$currentline)n" if ($currentfile);
- print STDERR "I looked in:n";
- print " " . join("n ", @search_dirs, @def_search_dirs), "n";
- exit 1;
- }
- sub open_conf {
- my $configfile = shift;
- # process .conf file
- if (! -f "$configfile") {
- print STDERR "Can't find a configuration file called $configfilen";
- exit 1;
- }
- $currentfile = $configfile;
- my $fh = new IO::File;
- $fh->open("$configfile");
- return $fh;
- }
- sub count_scalars {
- my @k = keys(%scalars);
- return $#k + 1;
- }
- sub count_tables {
- my @k = keys(%tables);
- return $#k + 1;
- }
- sub count_columns {
- my $table = shift;
- return $#{$tables{$table}{'column'}} + 1;
- }
- sub table_is_writable {
- my $table = shift;
- my $column;
- my $result = 0;
- foreach $column (@{$tables{$table}{'column'}}) {
- if($SNMP::MIB{$column}{access} =~ /(ReadWrite|Create|WriteOnly)/) {
- $result = 1;
- last;
- }
- }
- return $result;
- }
- sub table_has_create {
- my $table = shift;
- my $column;
- my $result = 0;
- foreach $column (@{$tables{$table}{'column'}}) {
- if($SNMP::MIB{$column}{access} =~ /(Create)/) {
- $result = 1;
- last;
- }
- }
- return $result;
- }
- sub table_has_rowstatus {
- my $table = shift;
- my $column;
- my $result = 0;
- foreach $column (@{$tables{$table}{'column'}}) {
- if($SNMP::MIB{$column}{syntax} =~ /(RowStatus)/) {
- $result = 1;
- last;
- }
- }
- return $result;
- }
- sub count_indexes {
- my $table = shift;
- return $#{$tables{$table}{'index'}} + 1;
- }
- sub count_external_indexes {
- my $table = shift;
- return $#{$tables{$table}{'externalindex'}} + 1;
- }
- sub count_notifications {
- my @k = keys(%notifications);
- return $#k + 1;
- }
- sub count_varbinds {
- my $notify = shift;
- return $#{$notifyvars{$notify}} + 1;
- }