From e30beeedd5cbe6f72008c32122b3b8b617fd5ab2 Mon Sep 17 00:00:00 2001 From: Hideki Yamane Date: Thu, 11 Apr 2013 10:21:22 +0900 Subject: Imported Upstream version 5.4.3~dfsg --- local/FAQ2HTML | 113 ++ local/Makefile.in | 156 ++ local/README.mib2c | 224 +++ local/Version-Munge.pl | 195 +++ local/convertcode | 132 ++ local/fixproc | 694 ++++++++ local/html-add-header-footer.pl | 212 +++ local/html-textfile-fix.pl | 60 + local/ipf-mod.pl | 227 +++ local/mib2c | 1252 ++++++++++++++ local/mib2c-conf.d/default-mfd-top.m2c | 141 ++ local/mib2c-conf.d/details-enums.m2i | 80 + local/mib2c-conf.d/details-node.m2i | 102 ++ local/mib2c-conf.d/details-table.m2i | 25 + local/mib2c-conf.d/generic-ctx-copy.m2i | 33 + local/mib2c-conf.d/generic-ctx-get.m2i | 106 ++ local/mib2c-conf.d/generic-ctx-set.m2i | 29 + local/mib2c-conf.d/generic-data-allocate.m2i | 62 + local/mib2c-conf.d/generic-data-context.m2i | 51 + local/mib2c-conf.d/generic-get-char.m2i | 49 + local/mib2c-conf.d/generic-get-decl-bot.m2i | 22 + local/mib2c-conf.d/generic-get-decl.m2i | 43 + local/mib2c-conf.d/generic-get-long.m2i | 14 + local/mib2c-conf.d/generic-get-oid.m2i | 18 + local/mib2c-conf.d/generic-header-bottom.m2i | 21 + local/mib2c-conf.d/generic-header-top.m2i | 22 + local/mib2c-conf.d/generic-source-includes.m2i | 23 + local/mib2c-conf.d/generic-table-constants.m2c | 44 + local/mib2c-conf.d/generic-table-enums.m2c | 63 + .../generic-table-indexes-from-oid.m2i | 70 + local/mib2c-conf.d/generic-table-indexes-set.m2i | 123 ++ .../mib2c-conf.d/generic-table-indexes-to-oid.m2i | 53 + .../generic-table-indexes-varbind-setup.m2i | 51 + local/mib2c-conf.d/generic-table-indexes.m2i | 67 + local/mib2c-conf.d/generic-table-oids.m2c | 113 ++ local/mib2c-conf.d/generic-value-map-func.m2i | 104 ++ local/mib2c-conf.d/generic-value-map-reverse.m2i | 49 + local/mib2c-conf.d/generic-value-map.m2i | 46 + local/mib2c-conf.d/m2c-internal-warning.m2i | 21 + local/mib2c-conf.d/m2c_setup_enum.m2i | 24 + local/mib2c-conf.d/m2c_setup_node.m2i | 260 +++ local/mib2c-conf.d/m2c_setup_table.m2i | 48 + local/mib2c-conf.d/m2c_table_save_defaults.m2i | 117 ++ .../mfd-access-container-cached-defines.m2i | 576 +++++++ .../mfd-access-unsorted-external-defines.m2i | 1198 ++++++++++++++ local/mib2c-conf.d/mfd-data-access.m2c | 331 ++++ local/mib2c-conf.d/mfd-data-get.m2c | 168 ++ local/mib2c-conf.d/mfd-data-set.m2c | 142 ++ local/mib2c-conf.d/mfd-doxygen.m2c | 60 + local/mib2c-conf.d/mfd-interactive-setup.m2c | 332 ++++ local/mib2c-conf.d/mfd-interface.m2c | 1716 ++++++++++++++++++++ local/mib2c-conf.d/mfd-makefile.m2m | 139 ++ local/mib2c-conf.d/mfd-persistence.m2i | 478 ++++++ local/mib2c-conf.d/mfd-readme.m2c | 846 ++++++++++ local/mib2c-conf.d/mfd-top.m2c | 605 +++++++ local/mib2c-conf.d/node-get.m2i | 107 ++ local/mib2c-conf.d/node-set.m2i | 236 +++ local/mib2c-conf.d/node-storage.m2i | 21 + local/mib2c-conf.d/node-validate.m2i | 71 + local/mib2c-conf.d/node-varbind-validate.m2i | 54 + local/mib2c-conf.d/parent-dependencies.m2i | 63 + local/mib2c-conf.d/parent-set.m2i | 417 +++++ local/mib2c-conf.d/subagent.m2c | 183 +++ local/mib2c-conf.d/syntax-COUNTER64-get.m2i | 35 + local/mib2c-conf.d/syntax-DateAndTime-get.m2d | 9 + local/mib2c-conf.d/syntax-DateAndTime-get.m2i | 54 + local/mib2c-conf.d/syntax-DateAndTime-readme.m2i | 4 + local/mib2c-conf.d/syntax-InetAddress-get.m2i | 100 ++ local/mib2c-conf.d/syntax-InetAddress-set.m2i | 22 + local/mib2c-conf.d/syntax-InetAddressType-get.m2i | 25 + local/mib2c-conf.d/syntax-InetAddressType-set.m2i | 25 + .../mib2c-conf.d/syntax-RowStatus-dependencies.m2i | 113 ++ local/mib2c-conf.d/syntax-RowStatus-get.m2i | 65 + .../syntax-RowStatus-varbind-validate.m2i | 16 + .../syntax-StorageType-dependencies.m2i | 19 + local/mib2c-conf.d/syntax-TestAndIncr-get.m2i | 22 + local/mib2c-update | 358 ++++ local/mib2c.access_functions.conf | 183 +++ local/mib2c.array-user.conf | 1305 +++++++++++++++ local/mib2c.check_values.conf | 154 ++ local/mib2c.check_values_local.conf | 72 + local/mib2c.column_defines.conf | 15 + local/mib2c.column_enums.conf | 34 + local/mib2c.column_storage.conf | 23 + local/mib2c.conf | 284 ++++ local/mib2c.container.conf | 569 +++++++ local/mib2c.create-dataset.conf | 112 ++ local/mib2c.emulation.conf | 246 +++ local/mib2c.genhtml.conf | 370 +++++ local/mib2c.int_watch.conf | 107 ++ local/mib2c.iterate.conf | 668 ++++++++ local/mib2c.iterate_access.conf | 423 +++++ local/mib2c.mfd.conf | 32 + local/mib2c.notify.conf | 84 + local/mib2c.old-api.conf | 345 ++++ local/mib2c.perl.conf | 314 ++++ local/mib2c.row.conf | 282 ++++ local/mib2c.scalar.conf | 142 ++ local/mib2c.table_data.conf | 647 ++++++++ local/pass_persisttest | 77 + local/passtest | 41 + local/passtest.pl | 74 + local/snmp-ucd.sh | 187 +++ local/snmpcheck.def | 1224 ++++++++++++++ local/snmpconf | 933 +++++++++++ local/snmpconf.dir/snmp-data/authopts | 77 + local/snmpconf.dir/snmp-data/debugging | 39 + local/snmpconf.dir/snmp-data/mibs | 56 + local/snmpconf.dir/snmp-data/output | 79 + local/snmpconf.dir/snmp-data/snmpconf-config | 1 + local/snmpconf.dir/snmpd-data/acl | 36 + local/snmpconf.dir/snmpd-data/basic_setup | 17 + local/snmpconf.dir/snmpd-data/extending | 68 + local/snmpconf.dir/snmpd-data/monitor | 72 + local/snmpconf.dir/snmpd-data/operation | 32 + local/snmpconf.dir/snmpd-data/snmpconf-config | 1 + local/snmpconf.dir/snmpd-data/system | 43 + local/snmpconf.dir/snmpd-data/trapsinks | 46 + local/snmpconf.dir/snmptrapd-data/authentication | 8 + local/snmpconf.dir/snmptrapd-data/formatting | 15 + local/snmpconf.dir/snmptrapd-data/logging | 26 + local/snmpconf.dir/snmptrapd-data/runtime | 13 + local/snmpconf.dir/snmptrapd-data/snmpconf-config | 1 + local/snmpconf.dir/snmptrapd-data/traphandle | 17 + local/snmpdump.pl | 107 ++ local/tkmib | 994 ++++++++++++ local/traptoemail | 74 + 127 files changed, 24738 insertions(+) create mode 100755 local/FAQ2HTML create mode 100644 local/Makefile.in create mode 100644 local/README.mib2c create mode 100755 local/Version-Munge.pl create mode 100755 local/convertcode create mode 100755 local/fixproc create mode 100755 local/html-add-header-footer.pl create mode 100755 local/html-textfile-fix.pl create mode 100755 local/ipf-mod.pl create mode 100755 local/mib2c create mode 100644 local/mib2c-conf.d/default-mfd-top.m2c create mode 100644 local/mib2c-conf.d/details-enums.m2i create mode 100644 local/mib2c-conf.d/details-node.m2i create mode 100644 local/mib2c-conf.d/details-table.m2i create mode 100644 local/mib2c-conf.d/generic-ctx-copy.m2i create mode 100644 local/mib2c-conf.d/generic-ctx-get.m2i create mode 100644 local/mib2c-conf.d/generic-ctx-set.m2i create mode 100644 local/mib2c-conf.d/generic-data-allocate.m2i create mode 100644 local/mib2c-conf.d/generic-data-context.m2i create mode 100644 local/mib2c-conf.d/generic-get-char.m2i create mode 100644 local/mib2c-conf.d/generic-get-decl-bot.m2i create mode 100644 local/mib2c-conf.d/generic-get-decl.m2i create mode 100644 local/mib2c-conf.d/generic-get-long.m2i create mode 100644 local/mib2c-conf.d/generic-get-oid.m2i create mode 100644 local/mib2c-conf.d/generic-header-bottom.m2i create mode 100644 local/mib2c-conf.d/generic-header-top.m2i create mode 100644 local/mib2c-conf.d/generic-source-includes.m2i create mode 100644 local/mib2c-conf.d/generic-table-constants.m2c create mode 100644 local/mib2c-conf.d/generic-table-enums.m2c create mode 100644 local/mib2c-conf.d/generic-table-indexes-from-oid.m2i create mode 100644 local/mib2c-conf.d/generic-table-indexes-set.m2i create mode 100644 local/mib2c-conf.d/generic-table-indexes-to-oid.m2i create mode 100644 local/mib2c-conf.d/generic-table-indexes-varbind-setup.m2i create mode 100644 local/mib2c-conf.d/generic-table-indexes.m2i create mode 100644 local/mib2c-conf.d/generic-table-oids.m2c create mode 100644 local/mib2c-conf.d/generic-value-map-func.m2i create mode 100644 local/mib2c-conf.d/generic-value-map-reverse.m2i create mode 100644 local/mib2c-conf.d/generic-value-map.m2i create mode 100644 local/mib2c-conf.d/m2c-internal-warning.m2i create mode 100644 local/mib2c-conf.d/m2c_setup_enum.m2i create mode 100644 local/mib2c-conf.d/m2c_setup_node.m2i create mode 100644 local/mib2c-conf.d/m2c_setup_table.m2i create mode 100644 local/mib2c-conf.d/m2c_table_save_defaults.m2i create mode 100644 local/mib2c-conf.d/mfd-access-container-cached-defines.m2i create mode 100644 local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i create mode 100644 local/mib2c-conf.d/mfd-data-access.m2c create mode 100644 local/mib2c-conf.d/mfd-data-get.m2c create mode 100644 local/mib2c-conf.d/mfd-data-set.m2c create mode 100644 local/mib2c-conf.d/mfd-doxygen.m2c create mode 100644 local/mib2c-conf.d/mfd-interactive-setup.m2c create mode 100644 local/mib2c-conf.d/mfd-interface.m2c create mode 100644 local/mib2c-conf.d/mfd-makefile.m2m create mode 100644 local/mib2c-conf.d/mfd-persistence.m2i create mode 100644 local/mib2c-conf.d/mfd-readme.m2c create mode 100644 local/mib2c-conf.d/mfd-top.m2c create mode 100644 local/mib2c-conf.d/node-get.m2i create mode 100644 local/mib2c-conf.d/node-set.m2i create mode 100644 local/mib2c-conf.d/node-storage.m2i create mode 100644 local/mib2c-conf.d/node-validate.m2i create mode 100644 local/mib2c-conf.d/node-varbind-validate.m2i create mode 100644 local/mib2c-conf.d/parent-dependencies.m2i create mode 100644 local/mib2c-conf.d/parent-set.m2i create mode 100644 local/mib2c-conf.d/subagent.m2c create mode 100644 local/mib2c-conf.d/syntax-COUNTER64-get.m2i create mode 100644 local/mib2c-conf.d/syntax-DateAndTime-get.m2d create mode 100644 local/mib2c-conf.d/syntax-DateAndTime-get.m2i create mode 100644 local/mib2c-conf.d/syntax-DateAndTime-readme.m2i create mode 100644 local/mib2c-conf.d/syntax-InetAddress-get.m2i create mode 100644 local/mib2c-conf.d/syntax-InetAddress-set.m2i create mode 100644 local/mib2c-conf.d/syntax-InetAddressType-get.m2i create mode 100644 local/mib2c-conf.d/syntax-InetAddressType-set.m2i create mode 100644 local/mib2c-conf.d/syntax-RowStatus-dependencies.m2i create mode 100644 local/mib2c-conf.d/syntax-RowStatus-get.m2i create mode 100644 local/mib2c-conf.d/syntax-RowStatus-varbind-validate.m2i create mode 100644 local/mib2c-conf.d/syntax-StorageType-dependencies.m2i create mode 100644 local/mib2c-conf.d/syntax-TestAndIncr-get.m2i create mode 100755 local/mib2c-update create mode 100644 local/mib2c.access_functions.conf create mode 100644 local/mib2c.array-user.conf create mode 100644 local/mib2c.check_values.conf create mode 100644 local/mib2c.check_values_local.conf create mode 100644 local/mib2c.column_defines.conf create mode 100644 local/mib2c.column_enums.conf create mode 100644 local/mib2c.column_storage.conf create mode 100644 local/mib2c.conf create mode 100644 local/mib2c.container.conf create mode 100644 local/mib2c.create-dataset.conf create mode 100644 local/mib2c.emulation.conf create mode 100644 local/mib2c.genhtml.conf create mode 100644 local/mib2c.int_watch.conf create mode 100644 local/mib2c.iterate.conf create mode 100644 local/mib2c.iterate_access.conf create mode 100644 local/mib2c.mfd.conf create mode 100644 local/mib2c.notify.conf create mode 100644 local/mib2c.old-api.conf create mode 100755 local/mib2c.perl.conf create mode 100755 local/mib2c.row.conf create mode 100644 local/mib2c.scalar.conf create mode 100644 local/mib2c.table_data.conf create mode 100644 local/pass_persisttest create mode 100755 local/passtest create mode 100755 local/passtest.pl create mode 100755 local/snmp-ucd.sh create mode 100755 local/snmpcheck.def create mode 100755 local/snmpconf create mode 100644 local/snmpconf.dir/snmp-data/authopts create mode 100644 local/snmpconf.dir/snmp-data/debugging create mode 100644 local/snmpconf.dir/snmp-data/mibs create mode 100644 local/snmpconf.dir/snmp-data/output create mode 100644 local/snmpconf.dir/snmp-data/snmpconf-config create mode 100644 local/snmpconf.dir/snmpd-data/acl create mode 100644 local/snmpconf.dir/snmpd-data/basic_setup create mode 100644 local/snmpconf.dir/snmpd-data/extending create mode 100644 local/snmpconf.dir/snmpd-data/monitor create mode 100644 local/snmpconf.dir/snmpd-data/operation create mode 100644 local/snmpconf.dir/snmpd-data/snmpconf-config create mode 100644 local/snmpconf.dir/snmpd-data/system create mode 100644 local/snmpconf.dir/snmpd-data/trapsinks create mode 100644 local/snmpconf.dir/snmptrapd-data/authentication create mode 100644 local/snmpconf.dir/snmptrapd-data/formatting create mode 100644 local/snmpconf.dir/snmptrapd-data/logging create mode 100644 local/snmpconf.dir/snmptrapd-data/runtime create mode 100644 local/snmpconf.dir/snmptrapd-data/snmpconf-config create mode 100644 local/snmpconf.dir/snmptrapd-data/traphandle create mode 100755 local/snmpdump.pl create mode 100755 local/tkmib create mode 100755 local/traptoemail (limited to 'local') diff --git a/local/FAQ2HTML b/local/FAQ2HTML new file mode 100755 index 0000000..746ea6e --- /dev/null +++ b/local/FAQ2HTML @@ -0,0 +1,113 @@ +#!/usr/bin/perl -w + +$TOCHEADER=" TABLE OF CONTENTS"; + +open(O, ">FAQ.html"); + + +# Load FAQ into memory +while(<>) { + push (@faqfile, $_); +} +my $current_line = 0; +my $version; + +# Skip header up to table of contents +while($current_line <= $#faqfile) { + $_ = $faqfile[$current_line]; + $current_line++; + + if (/net-snmp Version: (.*)/) { + $version = $1; + } + + last if (/$TOCHEADER/); +} + +print O '

+FAQ +

+FAQ Maintainer: Dave Shield
+Email: net-snmp-coders@list.sourceforge.net
+'; +print O "Version: $version
\n"; +print O '
+

Table of Contents

+'; + +# Create table of contents +while($current_line <= $#faqfile) { + $_ = $faqfile[$current_line]; + + #Skip blank lines + if (/^\s*$/) { + $current_line++; + last; + } + + chomp(); + + # Remove white space at start of line + $_ =~ s/^ *//; + + $x = $_; + + # Remove white space at start of line + $x =~ s/^ *//g; + + # Replace all non alpha characters with _ + $x =~ s/[^a-zA-Z]/_/g; + + # Save cleaned up line + $xlate{$_} = $x; + + if ( /&/ ) { $_ =~ s/&/&/g; } + if ( // ) { $_ =~ s/>/>/g; } + if (/^[ A-Z]+$/) { + # Section header (eg: GENERAL) + print O "$_
\n";
+
+# Print contents with targets defined
+while($current_line <= $#faqfile) {
+    $_ = $faqfile[$current_line];
+    $current_line++;
+
+    chomp();
+
+    $y = $_;
+
+    if (defined($xlate{$y})) {
+	print O "\n";
+    }
+    if ( /&/ ) { $_ =~ s/&/&/g; }
+    if ( // ) { $_ =~ s/>/>/g; }
+    print O "$_\n";
+}
+
+print O '
+
+'; + diff --git a/local/Makefile.in b/local/Makefile.in new file mode 100644 index 0000000..ea67246 --- /dev/null +++ b/local/Makefile.in @@ -0,0 +1,156 @@ +# +# local (scripts) directory Makefile +# +top_builddir=.. + +VPATH = @srcdir@ + +# +# stuff to install +# +OTHERINSTALL=localinstall +OTHERUNINSTALL=localuninstall + +# +# local info +# +SNMPCONFPATH=@SNMPCONFPATH@ +PERSISTENT_DIRECTORY=@PERSISTENT_DIRECTORY@ +PERLSCRIPTS=snmpcheck tkmib mib2c fixproc ipf-mod.pl snmpconf traptoemail +SHELLSCRIPTS=mib2c-update +SCRIPTSMADEFORPERL=snmpcheck.made tkmib.made mib2c.made fixproc.made \ + ipf-mod.pl.made snmpconf.made traptoemail.made +DATASRCS=mib2c.conf mib2c.iterate.conf mib2c.iterate_access.conf \ + mib2c.create-dataset.conf mib2c.mfd.conf \ + mib2c.array-user.conf mib2c.column_enums.conf \ + mib2c.column_defines.conf mib2c.column_storage.conf \ + mib2c.old-api.conf mib2c.scalar.conf \ + mib2c.check_values.conf mib2c.check_values_local.conf \ + mib2c.access_functions.conf mib2c.notify.conf \ + mib2c.int_watch.conf mib2c.genhtml.conf \ + mib2c.table_data.conf mib2c.container.conf mib2c.perl.conf +MIB2CINSTALLDIR=$(snmplibdir)/mib2c-data +MIB2CDATASRC=mib2c-conf.d +MIB2CFILES=default-mfd-top.m2c details-enums.m2i details-node.m2i \ + details-table.m2i generic-ctx-copy.m2i generic-ctx-get.m2i \ + generic-ctx-set.m2i generic-data-allocate.m2i generic-data-context.m2i \ + generic-get-char.m2i generic-get-decl-bot.m2i generic-get-decl.m2i \ + generic-get-long.m2i generic-get-oid.m2i generic-header-bottom.m2i \ + generic-header-top.m2i generic-source-includes.m2i \ + generic-table-constants.m2c generic-table-enums.m2c \ + generic-table-indexes-from-oid.m2i generic-table-indexes-set.m2i \ + generic-table-indexes-to-oid.m2i \ + generic-table-indexes-varbind-setup.m2i generic-table-indexes.m2i \ + generic-table-oids.m2c generic-value-map-func.m2i \ + generic-value-map-reverse.m2i generic-value-map.m2i \ + m2c-internal-warning.m2i \ + m2c_setup_enum.m2i m2c_setup_node.m2i m2c_setup_table.m2i \ + m2c_table_save_defaults.m2i \ + mfd-access-container-cached-defines.m2i \ + mfd-access-unsorted-external-defines.m2i \ + mfd-data-access.m2c mfd-data-get.m2c mfd-data-set.m2c \ + mfd-doxygen.m2c mfd-interactive-setup.m2c mfd-interface.m2c \ + mfd-makefile.m2m mfd-readme.m2c mfd-top.m2c \ + mfd-persistence.m2i \ + node-get.m2i node-set.m2i node-storage.m2i \ + node-validate.m2i node-varbind-validate.m2i \ + parent-dependencies.m2i parent-set.m2i \ + subagent.m2c \ + syntax-COUNTER64-get.m2i syntax-DateAndTime-get.m2d \ + syntax-DateAndTime-get.m2i syntax-DateAndTime-readme.m2i \ + syntax-InetAddress-get.m2i syntax-InetAddress-set.m2i \ + syntax-InetAddressType-get.m2i syntax-InetAddressType-set.m2i \ + syntax-RowStatus-dependencies.m2i syntax-RowStatus-get.m2i \ + syntax-RowStatus-varbind-validate.m2i \ + syntax-StorageType-dependencies.m2i \ + syntax-TestAndIncr-get.m2i + +CONFINSTALLDIR=$(snmplibdir)/snmpconf-data +CONFDATASRC=snmpconf.dir +CONFDIRS=snmp-data snmpd-data snmptrapd-data +CONFFILES=snmpd-data/system snmpd-data/acl snmpd-data/trapsinks \ + snmpd-data/monitor snmpd-data/extending snmpd-data/operation \ + snmpd-data/basic_setup snmpd-data/snmpconf-config \ + snmp-data/authopts snmp-data/debugging snmp-data/output snmp-data/mibs \ + snmp-data/snmpconf-config \ + snmptrapd-data/formatting snmptrapd-data/traphandle \ + snmptrapd-data/authentication snmptrapd-data/logging snmptrapd-data/runtime \ + snmptrapd-data/snmpconf-config + +OTHERCLEANTARGETS=snmpcheck $(SCRIPTSMADEFORPERL) + +all: $(SCRIPTSMADEFORPERL) standardall + +snmpcheck: $(srcdir)/snmpcheck.def ../sedscript + $(SED) -f ../sedscript $(srcdir)/snmpcheck.def > snmpcheck + +snmpcheck.made: snmpcheck + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%' snmpcheck > snmpcheck.made ; \ + else \ + touch snmpcheck.made ; \ + fi + +tkmib.made: $(srcdir)/tkmib + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%' ${srcdir}/tkmib > tkmib.made; \ + else \ + touch tkmib.made; \ + fi + +mib2c.made: $(srcdir)/mib2c + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%;s#/usr/local/share/snmp#$(snmplibdir)#;' ${srcdir}/mib2c > mib2c.made; \ + else \ + touch mib2c.made; \ + fi + + +ipf-mod.pl.made: $(srcdir)/ipf-mod.pl + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%' ${srcdir}/ipf-mod.pl > ipf-mod.pl.made; \ + else \ + touch ipf-mod.pl.made; \ + fi + +fixproc.made: $(srcdir)/fixproc + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%' ${srcdir}/fixproc > fixproc.made; \ + else \ + touch fixproc.made; \ + fi + +snmpconf.made: $(srcdir)/snmpconf + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%; s#/usr/local/share#$(datadir)#g; s#/usr/local/etc/snmp#$(SNMPCONFPATH)#g; s#/var/net-snmp#$(PERSISTENT_DIRECTORY)#g' ${srcdir}/snmpconf > snmpconf.made; \ + else \ + touch snmpconf.made; \ + fi + +traptoemail.made: $(srcdir)/traptoemail + if test "x$(PERL)" != "x" ; then \ + $(PERL) -p -e 's%^#!.*/perl.*%#!$(PERL)%; s#/usr/local/share#$(datadir)#g; s#/usr/local/etc/snmp#$(TRAPTOEMAILPATH)#g' ${srcdir}/traptoemail > traptoemail.made; \ + else \ + touch traptoemail.made; \ + fi + +localinstall: $(SCRIPTSMADEFORPERL) + @if test "x$(PERL)" != "x" ; then \ + for i in $(PERLSCRIPTS) ; do $(INSTALL) $$i.made $(INSTALL_PREFIX)$(bindir)/$$i ; echo "install: installed $$i in $(INSTALL_PREFIX)$(bindir)" ; done ; \ + for i in $(SHELLSCRIPTS) ; do $(INSTALL) $(srcdir)/$$i $(INSTALL_PREFIX)$(bindir)/$$i ; echo "install: installed $$i in $(INSTALL_PREFIX)$(bindir)" ; done ; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(INSTALL_PREFIX)$(snmplibdir) ; \ + for i in $(DATASRCS) ; do $(INSTALL_DATA) $(srcdir)/$$i $(INSTALL_PREFIX)$(snmplibdir)/$$i ; echo "install: installed $$i in $(INSTALL_PREFIX)$(snmplibdir)" ; done ; \ + for i in $(CONFDIRS); do $(SHELL) $(srcdir)/../mkinstalldirs $(INSTALL_PREFIX)$(CONFINSTALLDIR)/$$i ; done ; \ + for i in $(CONFFILES); do $(INSTALL_DATA) $(srcdir)/$(CONFDATASRC)/$$i $(INSTALL_PREFIX)$(CONFINSTALLDIR)/$$i; echo "install: installed $$i in $(INSTALL_PREFIX)$(CONFINSTALLDIR)"; done ; \ + $(SHELL) $(srcdir)/../mkinstalldirs $(INSTALL_PREFIX)$(MIB2CINSTALLDIR) ; \ + for i in $(MIB2CFILES); do $(INSTALL_DATA) $(srcdir)/$(MIB2CDATASRC)/$$i $(INSTALL_PREFIX)$(MIB2CINSTALLDIR)/$$i; echo "install: installed $$i in $(INSTALL_PREFIX)$(MIB2CINSTALLDIR)"; done \ + fi + +localuninstall: + @if test "x$(PERL)" != "x" ; then \ + for i in $(PERLSCRIPTS) ; do rm -f $(INSTALL_PREFIX)$(bindir)/$$i ; echo "removed $$i from $(INSTALL_PREFIX)$(bindir)" ; done ; \ + for i in $(SHELLSCRIPTS) ; do rm -f $(INSTALL_PREFIX)$(bindir)/$$i ; echo "removed $$i from $(INSTALL_PREFIX)$(bindir)" ; done ; \ + for i in $(DATASRCS) ; do rm -f $(INSTALL_PREFIX)$(snmplibdir)/$$i ; echo "removed $$i from $(INSTALL_PREFIX)$(snmplibdir)" ; done ; \ + for i in $(CONFFILES); do rm -f $(INSTALL_PREFIX)$(CONFINSTALLDIR)/$$i; echo "removed $$i from $(INSTALL_PREFIX)$(CONFINSTALLDIR)"; done ; \ + for i in $(MIB2CFILES); do rm -f $(INSTALL_PREFIX)$(MIB2CINSTALLDIR)/$$i; echo "removed $$i from $(INSTALL_PREFIX)$(MIB2CINSTALLDIR)"; done \ + fi diff --git a/local/README.mib2c b/local/README.mib2c new file mode 100644 index 0000000..6b28770 --- /dev/null +++ b/local/README.mib2c @@ -0,0 +1,224 @@ +This README describes the ./local/mib2c script. + +Author: Derek Simkowiak + dereks@kd-dev.com + http://www.kd-dev.com + (please mail questions to net-snmp-coders@lists.sourceforge.net, + not to the author directly. Thanks!) + +Date: Wed Jan 20 02:51:06 PST 1999 +----------------------------------------------------------------------- +mib2c + +OVERVIEW + + mib2c is a Perl script that takes a MIB (such as those files found +in ./mibs/ ) and converts it into C code. That C code can then be used as a +"template" to implement your MIB. Then, when you are done editing the C +code and recompiling, the UCD-SNMP agent (snmpd) will support your MIB. +mib2c takes the place of "MIB Compilers" that come with commercial SNMP +agents. + + +REQUIREMENTS/INSTALLATION + + mib2c requires the SNMP.pm Perl module. As of this writing the +latest version of the SNMP.pm module is 1.8. + + The SNMP.pm module can be downloaded from CPAN at + +http://www.cpan.org/modules/by-module/SNMP/ + + ...the file that you want is probably SNMP-1.8b5.tar.gz . +If you didn't know that already, most every Perl module can be downloaded +from CPAN (www.cpan.org). Follow the installation instructions for the +module. + + NOTE: If you are running Redhat Linux 5.2 (and perhaps other +versions), you might get the following errors during the "make test" phase +of the installation of the SNMP.pm module: + +[root@olly SNMP-1.8b5]# make test # This is the command... +PERL_DL_NONLAZY=1 /usr/bin/perl -I./blib/arch -I./blib/lib +-I/usr/lib/perl5/i386-linux/5.00404 -I/usr/lib/perl5 -e 'use Test::Harness +qw(&runtests $verbose); $verbose=0; runtests @ARGV;' t/*.t +t/mib...............ok +t/session...........FAILED tests 7-8 + Failed 2/14 tests, 85.71% okay +t/translate.........ok +Failed Test Status Wstat Total Fail Failed List of failed +------------------------------------------------------------------------------- +t/session.t 14 2 14.29% 7-8 +Failed 1/3 test scripts, 66.67% okay. 2/24 subtests failed, 91.67% okay. +make: *** [test_dynamic] Error 9 + + + If the "make" went okay, then you can ignore these test failures. +These indicate you don't have write access to the portions of the mib +tree that the test script is trying to use. Please don't email the +UCD-SNMP list with other errors regarding the SNMP.pm module. +comp.lang.perl.modules is probably the most appropriate spot to +discuss problems with the SNMP.pm perl module itself. Interelated +problems between net-snmp and SNMP could be discussed on the net-snmp +mailing lists though. + + +USAGE + + mib2c takes one argument: an OID. It then traces down that OID +and generates the template C code. Here is the documentation, from the +top of the script: + +# 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. +# +# You *must* correct the beginning of the var_XXX() function to +# correctly determine mib ownership of the incoming request. + + +FINDING YOUR MIB + + Before you can specify the OID for your enterprise/MIB on the +command line, the script needs to be able to find your MIB so that it can +read it in and generate template code. Joe Marzot (gmarzot@nortelnetworks.com) +tells us: +-------------------------------------- +you should read (man mib_api). The default behaviour for mib loading +from within the perl interface uses the environment variables described +there. You can also override these and explicitly define mibdirs and +load modules through the perl/SNMP api. + +the easiest thing to do is toss the mibs in /usr/local/share/snmp/mibs +and set the env. var., MIBS, to 'ALL'. +-------------------------------------- + + I recommend following the last two lines of advice. I simply did + +# cp /home/dereks/MY-MIB-FILE.txt /usr/local/share/snmp/mibs/ +# export MIBS=ALL + + ...on my Redhat system (with a BASH shell) and it was able to find +my MIB just fine. + + +EXAMPLES + + Here are some examples from Wes Hardaker (wjhardaker@ucdavis.edu). +He's using a C shell. Wes writes: +-------------------------------------- +Ok, in order to run the thing, you actually need to do something like +this: + +setenv MIBS MY-ITEM-MIB # assumes csh +mib2c itemNode + +Where, "itemNode" should be a node in the mib tree that you want to +generate C code for. Note, pick small pieces not large ones. Yes, it +will generate code for the entire mibII tree if you ask it to, in one +very large mib file. + +Examples: + +% mib2c interfaces +outputing to interfaces.c and interfaces.h ... + depth: 3 + Number of Lines Created: +178 interfaces.c +84 interfaces.h +262 total +Done. + +% mib2c mib-2 # Don't ever do this. +outputing to mib-2.c and mib-2.h ... + depth: 5 + Number of Lines Created: +2783 mib-2.c +617 mib-2.h +3400 total +Done. + +It may have some sorting problems with multiple level mib tree +branches being generated into one piece of code (reorder the .h file +structure to be in OID lexical order if needed). +-------------------------------------- + +WHAT TO DO WITH THE CODE THAT GETS GENERATED + + You will need to edit your generated code to work with your +hardware. For instance, if your MIB is for a refrigerator, you will need +to write the code that talks to the refridgerator (through the serial +port, maybe?) in Fridge Protocol. + + See the files in ./agent/mibgroup/examples/ and +./agent/mibgroup/dummy/ for heavily-commented example code. Don't ask me +questions about this stuff--I'm just now figuring it out myself... + + [NOTE: If anyone out there has tips about necessary options to +./configure, or re-compiling snmpd with custom MIB support, please add +them here...] + +WARNING + + As of this writing, the mib2c compiler is a bit outdated and needs +some work. Wes writes: +-------------------------------------- +It already needs changing, because the architecture has changed in the +3.6 line (though its backwards compatible, I'd prefer to generate +code from newer models than older ones). +-------------------------------------- + When I asked him to elaborate on the new 3.6 archictecture, all I +got was: +-------------------------------------- +It hopefully will be in the new documentation about mib module api +that Dave Shield is putting together (which is also currently wrong, +for that matter)... +-------------------------------------- + ...so I don't know what the hell he's talking about. + + +SOME ERRORS AND THEIR MEANING + + If you get a large number of errors that look like: + +[...] +unknown type: INTEGER for prIndex +unknown type: OCTETSTR for prNames +unknown type: INTEGER for prMin +[...] + + ...then you are trying to use an old version of the mib2c script +that does not support the SNMP.pm module version 1.8. Get the latest +version of the script. + + If you get the error + +Couldn't find mib reference: myEnterpriseOID + + ...when you know that it should be finding your MIB file(s), then +you forgot to put the word "END" at the very end of your MIB. (Uh...I'm +not speaking from experience here. Really.) + +ACKNOWLEGMENTS + + Many thanks to the people on the UCD-SNMP mailing list +(net-snmp-users@lists.sourceforge.net). In particular, many thanks to + +Wes Hardaker +Ken McNamara +Joe Marzot + + ...since about half this document is just cut'n'pasted from emails +they sent me. + + Good luck with your project. + +Derek Simkowiak +dereks@kd-dev.com +http://www.kd-dev.com + diff --git a/local/Version-Munge.pl b/local/Version-Munge.pl new file mode 100755 index 0000000..fde5939 --- /dev/null +++ b/local/Version-Munge.pl @@ -0,0 +1,195 @@ +#!/usr/bin/perl + +use Getopt::Std; + +sub usage { + print " +$0 [-v VERSION] -R -C -M -D -h + + -M Modify the files with a new version (-v required) + -v VERSION Use VERSION as the version string + -T TAG Use TAG as SVN tag (must being with Ext-) + -C Commit changes to the files + -R Revert changes to the files + -D Compare files (svn diff) + -f FILE Just do a particular file + -t TYPE Just do a particular type of file + -P Print resulting modified lines + -V verbose +"; + exit 1; +} + +getopts("Pv:T:RCMDhnf:t:V",\%opts) || usage(); +if ($opts{'h'}) { usage(); } + +if (!$opts{'v'} && $opts{'M'} && !$opts{'T'}) { + warn "no version (-v or -T) specified"; + usage; +} +if (!$opts{'R'} && !$opts{'M'} && !$opts{'C'} && !$opts{'D'}) { + warn "nothing to do (need -R -C -D or -M)\n"; + usage; +} + +my @exprs = ( + # c files with a equal sign and a specific variable + { type => 'c', + expr => 'VersionInfo(\s*=\s*[^"]*)"(.*)"', + repl => 'VersionInfo$1"$VERSION"', + files => [qw(snmplib/snmp_version.c)]}, + + # documentation files + { type => 'docs', + expr => 'Version: [\.0-9a-zA-Z]+', + repl => 'Version: $VERSION', + files => [qw(README FAQ dist/net-snmp.spec)], + not_required => {'dist/net-snmp.spec' => 1} + }, + + # sed files + { type => 'sed', + expr => '^s\/VERSIONINFO\/[^\/]*', + repl => 's\/VERSIONINFO\/$VERSION', + files => [qw(sedscript.in)]}, + + # Makefiles + { type => 'Makefile', + expr => 'VERSION = [\.0-9a-zA-Z]+', + repl => 'VERSION = $VERSION', + files => [qw(dist/Makefile)], + not_required => {'dist/Makefile' => 1} + }, + + # Doxygen config + { type => 'doxygen', + expr => 'PROJECT_NUMBER(\s+)=(\s+)\'(.*)\'', + repl => 'PROJECT_NUMBER$1=$2\'$VERSION\'', + files => [qw(doxygen.conf)] + }, + + # perl files + { type => 'perl', + expr => 'VERSION = \'(.*)\'', + repl => 'VERSION = \'$VERSION_FLOAT\'', + files => [qw(perl/SNMP/SNMP.pm + perl/agent/agent.pm + perl/agent/Support/Support.pm + perl/agent/default_store/default_store.pm + perl/default_store/default_store.pm + perl/OID/OID.pm + perl/ASN/ASN.pm + perl/AnyData_SNMP/Storage.pm + perl/AnyData_SNMP/Format.pm + perl/TrapReceiver/TrapReceiver.pm + )], + not_required => {'perl/agent/Support/Support.pm' => 1} + }, + + # configure script files + { type => 'configure', + expr => 'AC_INIT\\(\\[Net-SNMP\\], \\[([^\\]]+)\\]', + repl => 'AC_INIT([Net-SNMP], [$VERSION]', + files => [qw(configure.in)], + exec => 'autoconf', + exfiles => [qw(configure)], + }, + + # configure script files + { type => 'doxygen', + expr => 'PROJECT_NUMBER\s*= (.*)', + repl => 'PROJECT_NUMBER = $VERSION', + files => [qw(doxygen.conf)], + }, + ); + +# +# set up versioning information +# +if ($opts{'T'} && !$opts{'v'}) { + $opts{'v'} = $opts{'T'}; + die "usage error: version tag must begin with Ext-" if ($opts{'T'} !~ /^Ext-/); + $opts{'v'} =~ s/^Ext-//; + $opts{'v'} =~ s/-/./g; +} +$VERSION = $opts{'v'}; +$VERSION_FLOAT = floatize_version($VERSION); + + +# +# loop through all the expression types +# +my @files; +for ($i = 0; $i <= $#exprs; $i++) { + + # drop other file types if only one was requested. + next if ($opts{'t'} && $exprs[$i]{'type'} ne $opts{'t'}); + + # loop through each file and process + foreach my $f (@{$exprs[$i]->{'files'}}) { + + # skip files that weren't specifically in the todo list if need be + next if ($opts{'f'} && $f ne $opts{'f'}); + + # remove the changes and revert to SVN + if ($opts{'R'}) { + print "removing changes and updating $f\n" if ($opts{'V'}); + system("svn revert $f"); + } + + # make sure it exists + if (! -f $f) { + if (!exists($exprs[$i]->{'not_required'}{$f})) { + print STDERR "FAILED to find file $f\n"; + exit(1); + } else { + print STDERR "SKIPPING file $f\n"; + next; + } + } + + # modify the files with the version + if ($opts{'M'}) { + rename ($f,"$f.bak"); + open(I,"$f.bak"); + open(O,">$f"); + while () { + my $res = eval "s/$exprs[$i]->{'expr'}/$exprs[$i]->{'repl'}/"; + if ($res && $opts{'P'}) { + my $shortened = $_; + $shortened =~ s/^\s*//; + printf("%s:\n %s", $f, $shortened); + } + print O; + } + close(I); + close(O); + unlink("$f.bak"); + push @files, $f; + print "modified $f using s/$exprs[$i]->{'expr'}/$exprs[$i]->{'repl'}/\n" if ($opts{'V'}); + } + + # run diff if requested. + if ($opts{'D'}) { + print "diffing $f\n" if ($opts{'V'}); + system("svn diff $f"); + } + } + system($exprs[$i]->{'exec'}) if ($exprs[$i]->{'exec'}); + push @files, @{$exprs[$i]->{'exfiles'}} if ($exprs[$i]->{'exfiles'}); +} + +# +# commit the modified files +# +if ($opts{'C'}) { + my $files = join(" ",@files); + print "committing $files\n" if ($opts{'V'}); + $ret = system("svn commit -m \"- version tag ( $VERSION )\" $files"); + exit($ret); +} + +sub floatize_version { + my ($major, $minor, $patch, $opps) = ($_[0] =~ /^(\d+)\.(\d+)\.?(\d*)\.?(\d*)/); + return $major + $minor/100 + $patch/10000 + $opps/100000; +} diff --git a/local/convertcode b/local/convertcode new file mode 100755 index 0000000..314ea06 --- /dev/null +++ b/local/convertcode @@ -0,0 +1,132 @@ +#!/usr/bin/perl -p -i.snmpbak + +# this script should convert header files included based on the +# ucd-snmp header file names and convert them to their new net-snmp +# names, assuming the code was originally intended to be compiled +# within the ucd-snmp source tree. + +s/include "config.h"/include /; +s/include "asn1.h"/include /; +s/include "callback.h"/include /; +s/include "data_list.h"/include /; +s/include "default_store.h"/include /; +s/include "getopt.h"/include /; +s/include "int64.h"/include /; +s/include "keytools.h"/include /; +s/include "lcd_time.h"/include /; +s/include "libsnmp.h"/include /; +s/include "md5.h"/include /; +s/include "mib.h"/include /; +s/include "mt_support.h"/include /; +s/include "net-snmp-config.h"/include /; +s/include "net-snmp-includes.h"/include /; +s/include "oid_array.h"/include /; +s/include "oid_stash.h"/include /; +s/include "parse.h"/include /; +s/include "read_config.h"/include /; +s/include "scapi.h"/include /; +s/include "snmpAAL5PVCDomain.h"/include /; +s/include "snmp_alarm.h"/include /; +s/include "snmp_api.h"/include /; +s/include "snmpCallbackDomain.h"/include /; +s/include "snmp_client.h"/include /; +s/include "snmp_debug.h"/include /; +s/include "snmp_enum.h"/include /; +s/include "snmp.h"/include /; +s/include "snmp_impl.h"/include /; +s/include "snmpIPXDomain.h"/include /; +s/include "snmpksm.h"/include /; +s/include "snmp_locking.h"/include /; +s/include "snmp_logging.h"/include /; +s/include "snmp_parse_args.h"/include /; +s/include "snmp_secmod.h"/include /; +s/include "snmp-tc.h"/include /; +s/include "snmpTCPDomain.h"/include /; +s/include "snmpTCPIPv6Domain.h"/include /; +s/include "snmp_transport.h"/include /; +s/include "snmpUDPDomain.h"/include /; +s/include "snmpUDPIPv6Domain.h"/include /; +s/include "snmpUnixDomain.h"/include /; +s/include "snmpusm.h"/include /; +s/include "snmpusm_init.h"/include /; +s/include "snmpv3.h"/include /; +s/include "system.h"/include /; +s/include "tools.h"/include /; +s/include "transform_oids.h"/include /; +s/include "vacm.h"/include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/include /include /; +s/\"agent_read_config.h\"//; +s/\"agent_registry.h\"//; +s/\"agent_index.h\"//; +s/\"agent_trap.h\"//; +s/\"auto_nlist.h\"//; +s/\"ds_agent.h\"//; +s/\"snmp_agent.h\"//; +s/\"snmp_vars.h\"//; +s/\"var_struct.h\"//; +s/\"agent_handler.h\"//; +s/\"ucd-snmp-agent-includes.h\"//; +s/\"agent_handler.h\"//; +s/\"agent_callbacks.h\"//; +s/\"mib_modules.h\"//; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; +s///; diff --git a/local/fixproc b/local/fixproc new file mode 100755 index 0000000..b79630b --- /dev/null +++ b/local/fixproc @@ -0,0 +1,694 @@ +#!/usr/bin/perl +# +# fixproc [-min n] [-max n] [-check | -kill | -restart | -exist | -fix] proc ... +# +# fixproc exit code: +# 0 ok +# 1 check failed +# 2 cannot restart +# 3 cannot kill +# 4 fix failed if fix is defined as kill or restart, then +# cannot kill or cannot restart is return instead +# 10 fixproc error +# +# +# Fixes a process named "proc" by performing the specified action. The +# actions can be check, kill, restart, exist, or fix. The action is specified +# on the command line or is read from a default database, which describes +# the default action to take for each process. The database format and +# the meaning of each action are described below. +# +# database format +# --------------- +# +# name foo required +# cmd /a/b/name args required +# min number optional, defaults to 1 +# max number optional, defaults to 1 +# +# check {null, exist, shell} optional, defaults to exist if not defined +# [shell command shell commands needed only if check=shell +# ... +# shell command +# end_shell] keyword end_shell marks end of shell commands +# fix {kill, restart, shell} required +# [shell command shell commands needed only if fix=shell +# ... +# shell command +# end_shell] keyword end_shell marks end of shell commands +# +# Blank lines and lines beginning with "#" are ignored. +# +# +# Example: +# +# name test1 +# cmd nice /home/kong/z/test1 > /dev/null & +# max 2 +# fix shell +# xterm& +# nice /home/kong/z/test1 > /dev/null & +# end_shell +# +# +# actions +# ------- +# There are 5 possible actions: kill, restart, fix, exist, check. Fix is +# defined to be the kill action, the restart action, or a series of shell +# commands. Check is optionally defined in the database. If check is not +# defined, it defaults to exist. +# +# If the action is specified on the cmd line, it is executed regardless of +# check. The commands executed for each action type is as follow: +# +# switch action: +# kill: +# kill process, wait 5 seconds, kill -9 if still exist +# if still exist +# return "cannot kill" +# else +# return "ok" +# +# restart: +# execute kill +# if kill returned "cannot kill" +# return "cannot kill" +# restart by issuing cmd to shell +# if check defined +# execute check +# if check succeeds +# return "ok" +# else +# return "cannot restart" +# +# fix: +# if fix=kill +# execute kill +# else if fix=restart +# execute restart +# else +# execute shell commands +# execute check +# +# check: +# if check defined as null +# return "fixproc error" +# else +# execute check +# if check succeeds +# return (execute exist) +# return "check failed" +# +# exist: +# if proc exists in ps && (min <= num. of processes <= max) +# return "ok" +# else +# return "check failed" +# +# +# If the action is not specified on the cmd line, the default action is the +# fix action defined in the database. Fix is only executed if check fails: +# +# if fix defined +# if check is not defined as null +# execute check +# if check succeeds +# return "ok" +# execute action defined for fix +# else +# return "fixproc error" +# +# +# If proc is not specified on the command line, return "fixproc error." +# Multiple proc's can be defined on the cmd line. When an error occurs +# when multiple proc's are specified, the first error encountered halts the +# script. +# +# For check shell scripts, any non-zero exit code means the check has failed. +# +# +# Timothy Kong 3/1995 + +use File::Temp qw(tempfile); + +$database_file = '/local/etc/fixproc.conf'; + +$debug = 0; # specify debug level using -dN + # currently defined: -d1 + +$no_error = 0; +$check_failed_error = 1; +$cannot_restart_error = 2; +$cannot_kill_error = 3; +$cannot_fix_error = 4; +$fixproc_error = 10; + +$min = 1; +$max = 1; +$cmd_line_action = ''; +%min = (); +%max = (); +%cmd = (); +%check = (); +%fix = (); +$shell_lines = (); +@proc_list = (); + +$shell_header = "#!/bin/sh\n"; +$shell_end_marker = 'shell_end_marker'; + +&read_args(); +&read_database(); +# &dump_database(); # debug only + +# change the default min. and max. number of processes allowed +if ($min != 1) + { + for $name ( keys (%min) ) + { + $min{$name} = $min; + } + } +if ($max != 1) + { + for $name ( keys (%max) ) + { + $max{$name} = $max; + } + } + +# work on one process at a time +for $proc ( @proc_list ) + { + $error_code = &work_on_proc ($proc); + +############# uncomment next line when fully working ############ +# exit $error_code if ($error_code); + + die "error_code = $error_code\n" if ($error_code); + } + + +# create an executable shell script file +sub create_sh_script +{ + local ($file) = pop (@_); + local ($fh) = pop (@_); + local ($i) = pop (@_); + + printf (STDERR "create_sh_script\n") if ($debug > 0); + + $! = $fixproc_error; + while ( $shell_lines[$i] ne $shell_end_marker ) + { + printf ($fh "%s", $shell_lines[$i]); + $i++; + } + close ($fh); + chmod 0755, $file; +} + + +sub do_fix +{ + local ($proc) = pop(@_); + + printf (STDERR "do_fix\n") if ($debug > 0); + + if ($fix{$proc} eq '') + { + $! = $fixproc_error; + die "$0: internal error 4\n"; + } + if ($fix{$proc} eq 'kill') + { + return &do_kill ($proc); + } + elsif ($fix{$proc} eq 'restart') + { + return &do_restart ($proc); + } + else + { + # it must be "shell", so execute the shell script defined in database + local ($tmpfh, $tmpfile) = tempfile("fix_XXXXXXXX", DIR => "/tmp"); + + &create_sh_script ($fix{$proc}, $tmpfh, $tmpfile); + + # return code is number divided by 256 + $error_code = (system "$tmpfile") / 256; + unlink($tmpfile); + return ($fix_failed_error) if ($error_code != 0); + # sleep needed here? + return &do_exist ($proc); + } +} + + +sub do_check +{ + local ($proc) = pop(@_); + + printf (STDERR "do_check\n") if ($debug > 0); + + if ($check{$proc} eq '') + { + $! = $fixproc_error; + die "$0: internal error 2\n"; + } + + if ($check{$proc} ne 'exist') + { + # if not "exist", then it must be "shell", so execute the shell script + # defined in database + + local ($tmpfh, $tmpfile) = tempfile("check_XXXXXXXX", DIR => "/tmp"); + + &create_sh_script ($fix{$proc}, $tmpfh, $tmpfile); + + # return code is number divided by 256 + $error_code = (system "$tmpfile") / 256; + unlink($tmpfile); + return ($check_failed_error) if ($error_code != 0); + + # check passed, continue + } + return &do_exist ($proc); +} + + +sub do_exist +{ + local ($proc) = pop(@_); + + printf (STDERR "do_exist\n") if ($debug > 0); + + # do ps, check to see if min <= no. of processes <= max + $! = $fixproc_error; + open (COMMAND, "/bin/ps -e | /bin/grep $proc | /bin/wc -l |") + || die "$0: can't run ps-grep-wc command\n"; + $proc_count = ; + if (($proc_count < $min{$proc}) || ($proc_count > $max{$proc})) + { + return $check_failed_error; + } + return $no_error; +} + + +sub do_kill +{ + local ($proc) = pop(@_); + local ($second_kill_needed); + + printf (STDERR "do_kill\n") if ($debug > 0); + + # first try kill + $! = $fixproc_error; + open (COMMAND, "/bin/ps -e | /bin/grep $proc |") + || die "$0: can't run ps-grep-awk command\n"; + while () + { + # match the first field of ps -e + $! = $fixproc_error; + /^\s*(\d+)\s/ || die "$0: can't match ps -e output\n"; + system "kill $1"; + } + + # if process still exist, try kill -9 + sleep 2; + $! = $fixproc_error; + open (COMMAND, "/bin/ps -e | /bin/grep $proc |") + || die "$0: can't run ps-grep-awk command\n"; + $second_kill_needed = 0; + while () + { + # match the first field of ps -e + $! = $fixproc_error; + /^\s*(\d+)\s/ || die "$0: can't match ps -e output\n"; + system "kill -9 $1"; + $second_kill_needed = 1; + } + return ($no_error) if ($second_kill_needed == 0); + + # see if kill -9 worked + sleep 2; + $! = $fixproc_error; + open (COMMAND, "/bin/ps -e | /bin/grep $proc |") + || die "$0: can't run ps-grep-awk command\n"; + while () + { # a process still exist, return error + return $cannot_kill_error; + } + return $no_error; # good, all dead +} + + +sub do_restart +{ + local ($proc) = pop(@_); + local ($error_code); + + printf (STDERR "do_restart\n") if ($debug > 0); + + $error_code = &do_kill ($proc); + return $error_code if ($error_code != $no_error); + die "$0: internal error 3\n" if ($cmd{$proc} eq ''); + system "$cmd{$proc}"; + # sleep needed here? + if ($check{$proc} ne 'null') + { + return $no_error if (&do_check($proc) == $no_error); + return $cannot_restart_error; + } +} + + +sub work_on_proc +{ + local ($proc) = pop(@_); + local ($error_code); + + printf (STDERR "work_on_proc\n") if ($debug > 0); + + if ($cmd_line_action eq '') + { + # perform action from database + + if ($check{$proc} ne 'null') + { + $error_code = &do_check ($proc); + if ($error_code != $check_failed_error) + { + return $error_code; + } + } + return &do_fix ($proc); + } + else + { + # perform action from command line + + $error_code = $no_error; + if ($cmd_line_action eq 'kill') + { + $error_code = &do_kill ($proc); + } + elsif ($cmd_line_action eq 'restart') + { + $error_code = &do_restart ($proc); + } + elsif ($cmd_line_action eq 'fix') + { + $error_code = &do_fix ($proc); + } + elsif ($cmd_line_action eq 'check') + { + if ( $check{$proc} eq 'null' ) + { + exit $fixproc_error; + } + $error_code = &do_check ($proc); + } + elsif ($cmd_line_action eq 'exist') + { + $error_code = &do_exist ($proc); + } + else + { + $! = $fixproc_error; + die "$0: internal error 1\n"; + } + } +} + + +sub dump_database +{ + local ($name); + + for $name (keys(%cmd)) + { + printf ("name\t%s\n", $name); + printf ("cmd\t%s\n", $cmd{$name}); + printf ("min\t%s\n", $min{$name}); + printf ("max\t%s\n", $max{$name}); + if ( $check{$name} =~ /[0-9]+/ ) + { + printf ("check\tshell\n"); + $i = $check{$name}; + while ( $shell_lines[$i] ne $shell_end_marker ) + { + printf ("%s", $shell_lines[$i]); + $i++; + } + } + else + { + printf ("check\t%s\n", $check{$name}); + } + if ( $fix{$name} =~ /[0-9]+/ ) + { + printf ("fix\tshell\n"); + $i = $fix{$name}; + while ( $shell_lines[$i] ne $shell_end_marker ) + { + printf ("%s", $shell_lines[$i]); + $i++; + } + } + else + { + printf ("fix\t%s\n", $fix{$name}); + } + printf ("\n"); + } +} + + +sub read_database +{ + local ($in_check_shell_lines) = 0; + local ($in_fix_shell_lines) = 0; + local ($name) = ''; + local ($str1); + local ($str2); + + $! = $fixproc_error; + open (DB, $database_file) || die 'cannot open database file $database_file\n'; + while () + { + if ((! /\S/) || (/^[ \t]*#.*$/)) + { + # ignore blank lines or lines beginning with "#" + } + elsif ($in_check_shell_lines) + { + if ( /^\s*end_shell\s*$/ ) + { + $in_check_shell_lines = 0; + push (@shell_lines, $shell_end_marker); + } + else + { + push (@shell_lines, $_); + } + } + elsif ($in_fix_shell_lines) + { + if ( /^\s*end_shell\s*$/ ) + { + $in_fix_shell_lines = 0; + push (@shell_lines, $shell_end_marker); + } + else + { + push (@shell_lines, $_); + } + } + else + { + if ( ! /^\s*(\S+)\s+(\S.*)\s*$/ ) + { + $! = $fixproc_error; + die "$0: syntax error in database\n$_"; + } + $str1 = $1; + $str2 = $2; + if ($str1 eq 'name') + { + &finish_db_entry($name); + $name = $str2; + } + elsif ($str1 eq 'cmd') + { + $! = $fixproc_error; + die "$0: cmd specified before name in database\n$_\n" + if ($name eq ''); + die "$0: cmd specified multiple times for $name in database\n" + if ($cmd{$name} ne ''); + $cmd{$name} = $str2; + } + elsif ($str1 eq 'min') + { + $! = $fixproc_error; + die "$0: min specified before name in database\n$_\n" + if ($name eq ''); + die "$0: min specified multiple times in database\n$_\n" + if ($min{$name} ne ''); + die "$0: non-numeric min value in database\n$_\n" + if ( ! ($str2 =~ /[0-9]+/ )); + $min{$name} = $str2; + } + elsif ($str1 eq 'max') + { + $! = $fixproc_error; + die "$0: max specified before name in database\n$_\n" + if ($name eq ''); + die "$0: max specified multiple times in database\n$_\n" + if ($max{$name} ne ''); + die "$0: non-numeric max value in database\n$_\n" + if ( ! ($str2 =~ /[0-9]+/ )); + $max{$name} = $str2; + } + elsif ($str1 eq 'check') + { + $! = $fixproc_error; + die "$0: check specified before name in database\n$_\n" + if ($name eq ''); + die "$0: check specified multiple times in database\n$_\n" + if ($check{$name} ne ''); + if ( $str2 eq 'shell' ) + { + # if $check{$name} is a number, it is a pointer into + # $shell_lines[] where the shell commands are kept + $shell_lines[$#shell_lines+1] = $shell_header; + $check{$name} = $#shell_lines; + $in_check_shell_lines = 1; + } + else + { + $check{$name} = $str2; + } + } + elsif ($str1 eq 'fix') + { + $! = $fixproc_error; + die "$0: fix specified before name in database\n$_\n" + if ($name eq ''); + die "$0: fix specified multiple times in database\n$_\n" + if ($fix{$name} ne ''); + if ( $str2 eq 'shell' ) + { + # if $fix{$name} is a number, it is a pointer into + # $shell_lines[] where the shell commands are kept + $shell_lines[$#shell_lines+1] = $shell_header; + $fix{$name} = $#shell_lines; + $in_fix_shell_lines = 1; + } + else + { + $fix{$name} = $str2; + } + } + } + } + &finish_db_entry($name); +} + + +sub finish_db_entry +{ + local ($name) = pop(@_); + + if ($name ne '') + { + $! = $fixproc_error; + die "$0: fix not defined for $name in database\n" + if ($fix{$name} eq ''); + die "$0: cmd not defined for $name in database\n" + if ($cmd{$name} eq ''); + $check{$name} = 'exist' if ($check{$name} eq ''); + $max{$name} = 1 if ($max{$name} eq ''); + $min{$name} = 1 if ($min{$name} eq ''); + } +} + + +sub read_args +{ + local ($i) = 0; + local ($arg); + local ($action_arg_count) = 0; + + while ( $i <= $#ARGV ) + { + $arg = $ARGV[$i]; + if (($arg eq '-min') || ($arg eq '-max')) + { + if (($i == $#ARGV - 1) || ($ARGV[$i+1] =~ /\D/)) # \D is non-numeric + { + $! = $fixproc_error; + die "$0: numeric arg missing after -min or -max\n"; + } + if ($arg eq '-min') + { + $min = $ARGV[$i+1]; + } + else + { + $max = $ARGV[$i+1]; + } + $i += 2; + } + elsif ($arg eq '-kill') + { + $cmd_line_action = 'kill'; + $action_arg_count++; + $i++; + } + elsif ($arg eq '-check') + { + $cmd_line_action = 'check'; + $action_arg_count++; + $i++; + } + elsif ($arg eq '-restart') + { + $cmd_line_action = 'restart'; + $action_arg_count++; + $i++; + } + elsif ($arg eq '-exist') + { + $cmd_line_action = 'exist'; + $action_arg_count++; + $i++; + } + elsif ($arg eq '-fix') + { + $cmd_line_action = 'fix'; + $action_arg_count++; + $i++; + } + elsif ($arg =~ /-d(\d)$/) + { + $debug = $1; + $i++; + } + elsif ($arg =~ /^-/) + { + $! = $fixproc_error; + die "$0: unknown switch $arg\n"; + } + else + { + push (@proc_list, $arg); + $i++; + } + } + $! = $fixproc_error; + die "$0: no process specified\n" if ($#proc_list == -1); + die "$0: more than one action specified\n" if ($action_arg_count > 1); + } + diff --git a/local/html-add-header-footer.pl b/local/html-add-header-footer.pl new file mode 100755 index 0000000..96e46a5 --- /dev/null +++ b/local/html-add-header-footer.pl @@ -0,0 +1,212 @@ +#!/usr/bin/perl -w +############################################################################## +# +# Alex Burger - Oct 28th, 2004 +# +# Purpose: Modify .html files to add a header and footer for use +# on the Net-SNMP web site. +# +# Can also be used to change the 'section' variable +# for use in the menu system. +# +# Notes: A backup of each file is made to *.old. +# +# Any DOS newlines are removed from the destination file. +# +# Permissions are maintained. +# +############################################################################## +# +use File::Copy; +use File::stat; +use Getopt::Long; + +my $tidy_options = '-f /dev/null -m -i -asxhtml -wrap 130 -quiet'; + +my $pattern = ''; +my $section = ''; +my $tidy = 0; +my $body = 0; +my $help = 0; +my @files = (); + +GetOptions ('pattern=s' => \$pattern, + 'section=s' => \$section, + 'tidy' => \$tidy, + 'body' => \$body, + 'help' => \$help); + +if ($help == 1) +{ +$USAGE = qq/ +Usage: + add-header-footer [] file1 file2 file3 ... +Options: + --section= Menu section + --tidy Run tidy on input file before processing (turns on --body) + --body Remove everything before and after <\/body> + --help Display this message + +Examples: + + add-header-footer.pl --section=tutorial --body cat.html dog.html mouse.html + + find . -name '*.html' | add-header-footer.pl --section=tutorial --body + +/; + print $USAGE; + exit 0; +} + +if ($ARGV[0]) { + # Files listed on command line + foreach my $arg (@ARGV) { + chomp $arg; + push @files, $arg; + #print "$arg\n"; + } +} +else { + # No arguments, so accept STDIN + while () { + chomp; + push @files, $_; + #print "$_\n"; + } +} + +if (! (@files) ) { + exit 0; +} + +#print "@files"; + +foreach my $file (@files) { + chomp $file; + print "Processing file: $file\n"; + + # Grab current permissions + my $sb = stat($file); + my $stat_permissions = sprintf ("%04o", $sb->mode & 07777); + my $stat_uid = $sb->uid; + my $stat_gid = $sb->gid; + + my @old_file = (); + my @new_file = (); + + my $body_count = 0; + + # Backup old file + if (! (copy ("$file", "$file.old"))) { + print "Could not backup existing file $file to $file.new. Aborting.\n"; + next; + } + # Set permissions on old file to match original file + chmod oct($stat_permissions), "$file.old"; + chown $stat_uid, $stat_uid, "$file.old"; + + + if ($tidy == 1) { + $body = 1; # Enable body, as tidy will add it in. + my $tidy_command = "tidy $tidy_options $file"; + `$tidy_command`; + } + + if (open (I, "<$file")) { + # Load entire file + while () { + s/\015//g; # Remove any DOS newlines + chomp; + push (@old_file, $_); + } + } + else { + print "Could not open file $file. Aborting\n"; + next; + } + + if (!@old_file) { + print "Empty file. Skipping\n"; + next; + } + + # Remove empty lines at start + while (1) { + if ($old_file[0] eq "") { + splice (@old_file, 0, 1); + } + else { + last; + } + } + + # Remove empty lines at end + while (1) { + if ($old_file[$#old_file] eq "") { + splice (@old_file, -1, 1); + } + else { + last; + } + } + + if ($body == 1) { + # Count the number of 0) { + while (! ($old_file[0] =~ /\n"); + push (@new_file, '' . "\n"); + push (@new_file, '' . "\n"); + + # Add in old file, skipping existing header and footer and stopping at + for (my $i = 0; $i <= $#old_file; $i++) { + if (!(defined($old_file[$i]))) { next; } + if ($body == 1 && ($old_file[$i] =~ /<\/body>/)) { last; } + elsif ($old_file[$i] =~ //) { next; } + elsif ($old_file[$i] =~ //) { next; } + elsif ($old_file[$i] =~ //) { next; } + elsif ($old_file[$i] =~ //) { next; } + + push (@new_file, $old_file[$i] . "\n"); + } + + # Finish to building new file in memory with footer + push (@new_file, '' . "\n"); + push (@new_file, '' . "\n"); + + # Save new file + if (open (O, ">$file")) { + for (my $i = 0; $i <= $#new_file; $i++) { + print O "$new_file[$i]"; + } + print O "\n"; + close O; + + # Set permissions + chmod oct($stat_permissions), $file; + chown $stat_uid, $stat_uid, $file; + } + else { + print "Could not create new file: $file.new\n" + } + close I; +} + + diff --git a/local/html-textfile-fix.pl b/local/html-textfile-fix.pl new file mode 100755 index 0000000..f941197 --- /dev/null +++ b/local/html-textfile-fix.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +use File::Copy; +# +# This program adds some HTML entities to the text files. This will help prevent +# missing characters when including text documents in HTML. +# +# Written by: Alex Burger +# Date: December 29th, 2005 +# +@files = qw" +ERRATA +INSTALL +NEWS +PORTING +README +README.agent-mibs +README.agentx +README.aix +README.hpux11 +README.krb5 +README.mib2c +README.mibs +README.osX +README.Panasonic_AM3X.txt +README.smux +README.snmpv3 +README.solaris +README.thread +README.tru64 +README.win32 +TODO +perl/AnyData_SNMP/README +perl/default_store/README +perl/OID/README +perl/SNMP/README +perl/TrapReceiver/README +"; + + +foreach my $file (@files) { + open (FILEIN, $file) || die "Could not open file \'$file\' for reading. $!"; + open (FILEOUT, ">$file.new") || die "Could not open file \'$file.new\' for writing. $!"; + + while ($line = ) { + $line =~ s/&(?!lt|gt|quot|amp)/\&/g; + $line =~ s//\>/g; + $line =~ s/\"/\"/g; + print FILEOUT "$line"; + } + close FILE; + + if (! (move ("$file", "$file.old"))) { + die "Could not move $file to $file.old\n"; + } + if (! (move ("$file.new", "$file"))) { + die "Could not move $file.new to $file\n"; + } +} + diff --git a/local/ipf-mod.pl b/local/ipf-mod.pl new file mode 100755 index 0000000..285e779 --- /dev/null +++ b/local/ipf-mod.pl @@ -0,0 +1,227 @@ +#!/usr/bin/perl -s +## +## IP Filter UCD-SNMP pass module +## +## Allows read IP Filter's tables (In, Out, AccIn, AccOut), +## fetching rules, hits and bytes (for accounting tables only). +## +## Author: Yaroslav Terletsky +## Date: $ Tue Dec 1 10:24:08 EET 1998 $ +## Version: 1.1a + +# Put this file in /usr/local/bin/ipf-mod.pl and then add the following +# line to your snmpd.conf file (without the # at the front): +# +# pass .1.3.6.1.4.1.2021.13.2 /usr/local/bin/ipf-mod.pl + +# enterprises.ucdavis.ucdExperimental.ipFilter = .1.3.6.1.4.1.2021.13.2 +# ipfInTable.ipfInEntry.ipfInIndex integer = 1.1.1 +# ipfInTable.ipfInEntry.ipfInRule string = 1.1.2 +# ipfInTable.ipfInEntry.ipfInHits counter = 1.1.3 +# ipfOutTable.ipfOutEntry.ipfOutIndex integer = 1.2.1 +# ipfOutTable.ipfOutEntry.ipfOutRule string = 1.2.2 +# ipfOutTable.ipfOutEntry.ipfOutHits counter = 1.2.3 +# ipfAccInTable.ipfAccInEntry.ipfAccInIndex integer = 1.3.1 +# ipfAccInTable.ipfAccInEntry.ipfAccInRule string = 1.3.2 +# ipfAccInTable.ipfAccInEntry.ipfAccInHits counter = 1.3.3 +# ipfAccInTable.ipfAccInEntry.ipfAccInBytes counter = 1.3.4 +# ipfAccOutTable.ipfAccOutEntry.ipfAccOutIndex integer = 1.4.1 +# ipfAccOutTable.ipfAccOutEntry.ipfAccOutRule string = 1.4.2 +# ipfAccOutTable.ipfAccOutEntry.ipfAccOutHits counter = 1.4.3 +# ipfAccOutTable.ipfAccOutEntry.ipfAccOutBytes counter = 1.4.4 + +# variables types +%type = ('1.1.1', 'integer', '1.1.2', 'string', '1.1.3', 'counter', + '2.1.1', 'integer', '2.1.2', 'string', '2.1.3', 'counter', + '3.1.1', 'integer', '3.1.2', 'string', '3.1.3', 'counter', + '3.1.4', 'counter', + '4.1.1', 'integer', '4.1.2', 'string', '4.1.3', 'counter', + '4.1.4', 'counter'); + +# getnext sequence +%next = ('1.1.1', '1.1.2', '1.1.2', '1.1.3', '1.1.3', '2.1.1', + '2.1.1', '2.1.2', '2.1.2', '2.1.3', '2.1.3', '3.1.1', + '3.1.1', '3.1.2', '3.1.2', '3.1.3', '3.1.3', '3.1.4', + '3.1.4', '4.1.1', + '4.1.1', '4.1.2', '4.1.2', '4.1.3', '4.1.3', '4.1.4'); + +# ipfilter's commands to fetch needed information +$ipfstat_comm="/sbin/ipfstat"; +$ipf_in="$ipfstat_comm -ih 2>/dev/null"; +$ipf_out="$ipfstat_comm -oh 2>/dev/null"; +$ipf_acc_in="$ipfstat_comm -aih 2>/dev/null"; +$ipf_acc_out="$ipfstat_comm -aoh 2>/dev/null"; + +$OID=$ARGV[0]; +$IPF_OID='.1.3.6.1.4.1.2021.13.2'; +$IPF_OID_NO_DOTS='\.1\.3\.6\.1\.4\.1\.2021\.13\.2'; + +# exit if OID is not one of IPF-MIB's +exit if $OID !~ /^$IPF_OID_NO_DOTS(\D|$)/; + +# get table, entry, column and row numbers +$tecr = $OID; +$tecr =~ s/^$IPF_OID_NO_DOTS(\D|$)//; +($table, $entry, $col, $row, $rest) = split(/\./, $tecr); + +# parse 'get' request +if($g) { + # exit if OID is wrong specified + if(!defined $table or !defined $entry or !defined $col or !defined $row or defined $rest) { + print "[1] NO-SUCH NAME\n" if $d; + exit; + } + + # get the OID's value + $value = &get_value($table, $entry, $col, $row); + print "value=$value\n" if $d; + + # exit if OID does not exist + print "[2] NO-SUCH NAME\n" if $d and !defined $value; + exit if !defined $value; + + # set ObjectID and reply with response + $tec = "$table.$entry.$col"; + $ObjectID = "${IPF_OID}.${tec}.${row}"; + &response; +} + +# parse 'get-next' request +if($n) { + # set values if 0 or unspecified + $table = 1, $a = 1 if !$table or !defined $table; + $entry = 1, $a = 1 if !$entry or !defined $entry; + $col = 1, $a = 1 if !$col or !defined $col; + $row = 1, $a = 1 if !$row or !defined $row; + + if($a) { + # get the OID's value + $value = &get_value($table, $entry, $col, $row); + print "value=$value\n" if $d; + + # set ObjectID and reply with response + $tec = "$table.$entry.$col"; + $ObjectID = "${IPF_OID}.${tec}.${row}"; + &response; + } + + # get next OID's value + $row++; + $value = &get_value($table, $entry, $col, $row); + + # choose new table/column if rows exceeded + if(!defined $value) { + $tec = "$table.$entry.$col"; + $tec = $next{$tec} if !$a; + $table = $tec; + $entry = $tec; + $col = $tec; + $table =~ s/\.\d\.\d$//; + $entry =~ s/^\d\.(\d)\.\d$/$1/; + $col =~ s/^\d\.\d\.//; + $row = 1; + + # get the OID's value + $value = &get_value($table, $entry, $col, $row); + print "value=$value\n" if $d; + } + + # set ObjectID and reply with response + $tec = "$table.$entry.$col"; + $ObjectID = "${IPF_OID}.${tec}.${row}"; + &response; +} + +############################################################################## + +# fetch values from 'ipfInTable' and 'ipfOutTable' tables +sub fetch_hits_n_rules { + local($row, $col, $ipf_output) = @_; + local($asdf, $i, @ipf_lines, $length); + + # create an entry if no rule exists + $ipf_output = "0 empty list for ipfilter" if !$ipf_output; + + @ipf_lines = split("\n", $ipf_output); + $length = $#ipf_lines + 1; + + for($i = 1; $i < $length + 1; $i++) { + $hits{$i} = $ipf_lines[$i-1]; + $hits{$i} =~ s/^(\d+).*$/$1/; + $rule{$i} = $ipf_lines[$i-1]; + $rule{$i} =~ s/^\d+ //; + if($i == $row) { + return $i if $col == 1; + return $rule{$i} if $col == 2; + return $hits{$i} if $col == 3; + } + } + # return undefined value + undef $asdf; + return $asdf; +} + +# fetch values from 'ipfAccInTable' and 'ipfAccOutTable' tables +sub fetch_hits_bytes_n_rules { + local($row, $col, $ipf_output) = @_; + local($asdf, $i, @ipf_lines, $length); + + # create an entry if no rule exists + $ipf_output = "0 0 empty list for ipacct" if !$ipf_output; + + @ipf_lines = split("\n", $ipf_output); + $length = $#ipf_lines + 1; + + for($i = 1; $i < $length + 1; $i++) { + $hits{$i} = $ipf_lines[$i-1]; + $hits{$i} =~ s/^(\d+) .*$/$1/; + $bytes{$i} = $ipf_lines[$i-1]; + $bytes{$i} =~ s/^\d+ (\d+) .*/$1/; + $rule{$i} = $ipf_lines[$i-1]; + $rule{$i} =~ s/^\d+ \d+ //; + if($i == $row) { + return $i if $col == 1; + return $rule{$i} if $col == 2; + return $hits{$i} if $col == 3; + return $bytes{$i} if $col == 4; + } + } + # return undefined value + undef $asdf; + return $asdf; +} + +# get the values from ipfilter's tables +sub get_value { + local($table, $entry, $col, $row) = @_; + + if($table == 1) { + # fetch ipfInTable data + $ipf_output = `$ipf_in`; + $value = &fetch_hits_n_rules($row, $col, $ipf_output); + } elsif($table == 2) { + # fetch ipfOutTable data + $ipf_output = `$ipf_out`; + $value = &fetch_hits_n_rules($row, $col, $ipf_output); + } elsif($table == 3) { + # fetch ipfAccInTable data + $ipf_output = `$ipf_acc_in`; + $value = &fetch_hits_bytes_n_rules($row, $col, $ipf_output); + } elsif($table == 4) { + # fetch ipfAccOutTable data + $ipf_output = `$ipf_acc_out`; + $value = &fetch_hits_bytes_n_rules($row, $col, $ipf_output); + } + return $value; +} + +# generate response to 'get' or 'get-next' request +sub response { + # print ObjectID, its type and the value + if(defined $ObjectID and defined $type{$tec} and defined $value) { + print "$ObjectID\n"; + print "$type{$tec}\n"; + print "$value\n"; + } + exit; +} diff --git a/local/mib2c b/local/mib2c new file mode 100755 index 0000000..4ed7587 --- /dev/null +++ b/local/mib2c @@ -0,0 +1,1252 @@ +#!/usr/bin/perl +#!/usr/bin/perl -w + +# +# $Id: mib2c 17684 2009-07-10 07:46:43Z jsafranek $ +# +# 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] mibNode\n\n"; + print " -h\t\tThis message.\n\n"; + print " -c configfile\tSpecifies the configuration file to use\n\t\tthat dictates what the output of mib2c will look like.\n\n"; + print " -I PATH\tSpecifies a path to look for configuration files in\n\n"; + print " -f prefix\tSpecifies the output prefix to use. All code\n\t\twill be put into prefix.c and prefix.h\n\n"; + print " -d\t\tdebugging output (don't do it. trust me.)\n\n"; + print " -S VAR=VAL\tSet \$VAR variable to \$VAL\n\n"; + print " -i\t\tDon't run indent on the resulting code\n\n"; + 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"; + 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", "in_addr_t", + "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)); +$outputName =~ s/-/_/g; +$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 $i\n" 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:$currentline\n"; +} + +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+)\.(lastchange)/(table_has_lastchange($SNMP::MIB{$vars{$1}}{label}))/eg; + $it =~ s/\$(\w+)\.(storagetype)/(table_has_storagetype($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:$currentline\n"; + } + } + # 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). +# @while expression@ +# repeat iterate over code until the expression is false +# @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} and that +# a warning will be printed if STUFF does not return 0. (adding a +# 'return 0;' at the end of STUFF is a workaround. +# @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 the +# expression is false, the next @elsif expression@ expression +# (if it exists) will be evaluated, until an expression is +# true. If no such expression exists and an @else@ +# clause is found, it will be evaluated. +# @ifconf file@ +# If the specified file can be found in the conf file search path, +# and if found processes contained part until an appropriate @end@ is +# found. As with a regular @if expression@, @elsif expression@ and +# @else@ can be used. +# @ifdir dir@ +# If the specified directory exists, process contained part until an +# appropriate @end@ is found. As with a regular @if expression@, +# @elsif expression@ and @else@ can be used. +# @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) +# @quit@ +# Bail out (silently) +# @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*elsif\s+([^\@]+)\@/) { + return "else" if (($endcount == 1) && ($rtnelse == 1) && (eval(process_vars($1)))); + } + elsif (/\@\s*(foreach|if|while)/) { + $endcount++; + } + } + print "skippart EOF\n"; + 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 $name\n"; + return; + } + $outputs{$name}->close(); + delete $outputs{$name}; +# print STDERR "closing $name\n" 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 $name\n" 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) request\n"; + } elsif (/\@\s*quit\@/) { # QUIT + close_files; + exit; + } elsif (/\@\s*debug\s+([^\@]+)\@/) { # DEBUG + if ($1 eq "on") { + $debug = 1; + } + else { + $debug = 0; + } + } elsif (/\@\s*strict token\s+([^\@]+)\@/) { # STRICT + if ($1 eq "on") { + $strict_unk_token = 1; + } + else { + $strict_unk_token = 0; + } + } elsif (/\@\s*balanced\@/) { # BALANCED + $balanced = $currentlevel; + } elsif (/\@\s*open\s+([^\@]+)\@/) { # 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*close\s+([^\@]+)\@/) { # CLOSE + my $spec = process_vars($1); + close_file($spec); + } elsif (/\@\s*append\s+([^\@]+)\@/) { # 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*define\s*(.*)\@/) { # DEFINE + my $it = $1; + while (<$fh>) { + last if (/\@\s*enddefine\s*@/); + push @{$defines{$it}}, $_; + } + } elsif (/\@\s*calldefine\s+(\w+)@/) { + if ($#{$defines{$1}} == -1) { + warn "called a define of $1 which didn't exist\n"; + 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*pop\s*\@/) { # 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); + } elsif ($type eq dir) { + $ok = (-d $arg); + } 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 $return\n"; + } + } 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$1\n"; + } + $return = skippart(); + if ($return ne "end") { + m2c_die "unbalanced els$1 / rtn $rtn\n"; + } + $return = "else"; + last; + } elsif (/\@\s*next\s*\@/) { # 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*eval\s+\$(\w+)\s*=\s*([^\@]*)/) { # EVAL + my ($v, $e) = ($1, $2); +# print STDERR "eval: $e\n"; + my $e = process_vars($e); + $vars{$v} = eval($e); + if (!defined($vars{$v})) { + warn "$@"; + warn "$currentfile:$currentline [$_]\n"; + } + } elsif (/\@\s*perleval\s*(.*)\@/) { # PERLEVAL +# print STDERR "perleval: $1\n"; + my $res = eval($1); + if ($res) { + warn "$@"; + warn "$currentfile:$currentline [$_]\n"; + } + } elsif (/\@\s*startperl\s*\@/) { # STARTPERL + my $text; + while (get_next_line()) { + last if (/\@\s*endperl\s*\@/); + $text .= $_; + } + my $res = eval($text); + if ($res) { + warn "$@"; + warn "$currentfile:$currentline [$_]\n"; + } +# print STDERR "perleval: $1\n"; + } elsif (/\@\s*printf\s+(\"[^\"]+\")\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*foreach\s+\$([^\@]+)\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*foreach\s+\$([^\@]+)\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*foreach\s+\$([^\@]+)\s+varbinds\s*\@/) { + 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 $varbind\n"; + $return = do_a_loop($stash, \$vars{$var}, $varbind, + \$currentvarbind, $varbind); + } + } + m2c_die("foreach did not end with \@end@") if($return ne "end"); + } elsif (/\@\s*foreach\s+\$([^\@]+)\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*foreach\s+\$([^\@]+)\s+stuff\s*(.*)\@/) { + 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*foreach\s+\$([^\@]+)\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 -> $column\n"; + $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*foreach\s+\$([^\@]+)\s+\$([^\@]+)\s+range\s+([^\@]+)\@/) { + 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*foreach\s+\$([^\@,]+)\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*while([a-z]*)\s+([^@]+)\@/) { # WHILE + my ($type,$arg,$ok) = ($1,$2,0); + my $stash = do_tell(); + my $loop = 1; + + while ($loop) { + # 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); + } elsif ($type eq dir) { + $ok = (-d $arg); + } else { + m2c_die "unknown while modifier ($type)\n"; + } + + # act on condition + if ($ok) { + $return = do_a_loop($stash, \$vars{$type}, $ok, \$vars{$args}); + } else { + $loop = 0; + } + } + } elsif (/\@\s*prompt\s+\$(\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*print\s+([^@]*)\@/) { # PRINT + my $line = process_vars($1); + print "$line\n"; + } 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"; + warn "$currentfile:$currentline [$_]\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 EOF\n" 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 $tablename\n"; + $mib = $mib->{parent} || + die "can't find info about augmented table $augments in table $tablename\n"; + 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 $tablename\n"; + 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 $tablename\n"; + push @{$tables{$tablename}{'index'}}, $index; + if("@{$tables{$tablename}{'column'}}" =~ /$index\b/ ) { +# print "idx INT $index\n"; + push @{$tables{$tablename}{'internalindex'}}, $index; + } else { +# print "idx EXT $index\n"; + 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 if ($mib->{'access'} ne 'Notify'); + } + } 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) { +# print STDERR "using $d/$configfile" if (-f "$d/$configfile"); + return "$d/$configfile" if (-f "$d/$configfile"); + } + return $configfile if (-f "$configfile"); + return if ($missingok); + + print STDERR "Can't find a configuration file called $configfile\n"; + 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 $configfile\n"; + 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 table_has_lastchange { + my $table = shift; + my $column; + my $result = 0; + foreach $column (@{$tables{$table}{'column'}}) { + if(($SNMP::MIB{$column}{syntax} =~ /(TimeStamp)/) && + ($SNMP::MIB{$column}{label} =~ /(LastChange)/)) { + $result = 1; + last; + } + } + return $result; +} + +sub table_has_storagetype { + my $table = shift; + my $column; + my $result = 0; + foreach $column (@{$tables{$table}{'column'}}) { + if($SNMP::MIB{$column}{syntax} =~ /(StorageType)/) { + $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; +} diff --git a/local/mib2c-conf.d/default-mfd-top.m2c b/local/mib2c-conf.d/default-mfd-top.m2c new file mode 100644 index 0000000..c2e2964 --- /dev/null +++ b/local/mib2c-conf.d/default-mfd-top.m2c @@ -0,0 +1,141 @@ +######################################################################## +## +## DEFAULTS (no blank lines allowed) +## +######################################################################## +## mark boundarys +@if "x$m2c_mark_boundary" eq "x"@ +@ eval $m2c_mark_boundary = 0@ +@end@ +## +@if "x$mfd_readme_verbose" eq "x"@ +@ eval $mfd_readme_verbose = 1@ +@end@ +@if "x$m2c_create_fewer_files" eq "x"@ +@ eval $m2c_create_fewer_files = 0@ +@end@ +@if "x$mfd_processing_types" eq "x"@ +@ eval $mfd_processing_types = "#"@ +@end@ +@if "x$m2c_code_verbose" eq "x"@ +@ eval $m2c_code_verbose = 0@ +@end@ +@if "x$m2c_defaults_dir" eq "x"@ +@ eval $m2c_defaults_dir = "defaults/"@ +@end@ +######################################################################## +## enum constants upper or lower case? (NODE_NAME vs node_name) +@if "x$m2c_const_lc" eq "x"@ +@ eval $m2c_const_lc = 0@ +@end@ +## +######################################################################## +## prefix for all enums (NODE_NAME vs XYZ_NODE_NAME) +@if "x$m2c_const_pfx" eq "x"@ +@ eval $m2c_const_pfx = ""@ # or "XYZ_" +@end@ +## +######################################################################## +## use temporary values in get routines, or direct pointers? +@if "x$m2c_get_use_temp" eq "x"@ +@ eval $m2c_get_use_temp = 0@ +@end@ +## +######################################################################## +######################################################################## +## +## CODING STYLE +## +######################################################################## +######################################################################## +## allow for different style enums (#define vs const) +@if "x$m2c_const_dcl" eq "x"@ +@ eval $m2c_const_dcl = "#define"@ # or "const int" +@end@ +@if "m2c_const_del" eq "x"@ +@ eval $m2c_const_del = ""@ # or "=" +@end@ +@if "x$m2c_const_sfx" eq "x"@ +@ eval $m2c_const_sfx = ""@ # or ";" +@end@ +## +## set defaults for mfd +## +@if "x$user_mfd_default_table_access" eq "x" @ +@ eval $mfd_default_table_access = "container-cached"@ +@else@ +@ eval $mfd_default_table_access = "$user_mfd_default_table_access"@ +@end@ +## +@if "x$user_mfd_default_table_skip_mapping" eq "x" @ +@ eval $mfd_default_table_skip_mapping = 1@ +@else@ +@ eval $mfd_default_table_skip_mapping = $user_mfd_default_table_skip_mapping@ +@end@ +## +@if "x$user_mfd_default_data_context" eq "x" @ +@ eval $mfd_default_data_context = "generated"@ +@else@ +@ eval $mfd_default_data_context = "$user_mfd_default_data_context"@ +@end@ +## +@if "x$user_mfd_default_context_reg" eq "x" @ +@ eval $mfd_default_context_reg = "netsnmp_data_list"@ +@else@ +@ eval $mfd_default_context_reg = "$user_mfd_default_context_reg"@ +@end@ +## +@if "x$user_mfd_default_data_allocate" eq "x" @ +@ eval $mfd_default_data_allocate = 0@ +@else@ +@ eval $mfd_default_data_allocate = $user_mfd_default_data_allocate@ +@end@ +## +@if "x$user_mfd_default_data_cache" eq "x" @ +@ eval $mfd_default_data_cache = 1@ +@else@ +@ eval $mfd_default_data_cache = $user_mfd_default_data_cache@ +@end@ +## +@if "x$user_mfd_default_data_sparse" eq "x" @ +@ eval $mfd_default_data_sparse = 0@ +@else@ +@ eval $mfd_default_data_sparse = $user_mfd_default_data_sparse@ +@end@ +@if "x$user_mfd_default_undo_embed" eq "x" @ +@ eval $mfd_default_undo_embed = 0@ +@else@ +@ eval $mfd_default_undo_embed = $user_mfd_default_undo_embed@ +@end@ +## +@if "x$user_mfd_default_data_init" eq "x" @ +@ eval $mfd_default_data_init = 1@ +@else@ +@ eval $mfd_default_data_init = $user_mfd_default_data_init@ +@end@ +## +@if "x$user_mfd_default_data_transient" eq "x" @ +@ eval $mfd_default_data_transient = 2@ # TRANSIENT +@else@ +@ eval $mfd_default_data_transient = $user_mfd_default_data_transient@ +@end@ +## +@if "x$user_mfd_default_include_examples" eq "x" @ +@ eval $mfd_default_include_examples = 1@ +@else@ +@ eval $mfd_default_include_examples = $user_mfd_default_include_examples@ +@end@ +@if "x$m2c_data_cache" eq "x"@ +@ eval $m2c_data_cache = 0@ +@end@ +## +@if "x$user_mfd_default_generate_makefile" eq "x" @ +@ eval $mfd_default_generate_makefile = 0@ +@else@ +@ eval $mfd_default_generate_makefile = $user_mfd_default_generate_makefile@ +@end@ +@if "x$user_mfd_default_generate_subagent" eq "x" @ +@ eval $mfd_default_generate_subagent = 0@ +@else@ +@ eval $mfd_default_generate_subagent = $user_mfd_default_generate_subagent@ +@end@ diff --git a/local/mib2c-conf.d/details-enums.m2i b/local/mib2c-conf.d/details-enums.m2i new file mode 100644 index 0000000..ee6140c --- /dev/null +++ b/local/mib2c-conf.d/details-enums.m2i @@ -0,0 +1,80 @@ +############################################################# -*- c -*- +## generic include for enums. Do not use directly. +## +## $Id: details-enums.m2i 12011 2005-03-18 23:01:44Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12011 $ */ +@end@ +######################################################################## +@ifconf $node.syntax.m2i@ +@ include $node.syntax.m2i@ +@else@ +## +## Generating enums +## +## Examples: +## +## enums syntax perltype net-snmp type cdecl m2c_decl +## ----- -------- -------- ------------- ----- ------- +## 1 SomeTC BITS ASN_OCTET_STR char u_long +## 1 INTEGER INTEGER ASN_INTEGER long u_long +## 1 RowStatus INTEGER ASN_INTEGER long u_long +## +/************************************************************* + * constants for enums for the MIB node + * $node ($node.syntax / $node.type) + * + * since a Textual Convention may be referenced more than once in a + * MIB, protect againt redefinitions of the enum values. + */ +## +#ifndef ${m2c_de_pfx}_ENUMS +#define ${m2c_de_pfx}_ENUMS + +@ eval $m2c_mask=""@ +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ +@ if "$node.perltype" eq "BITS"@ +@ if $v > 31@ +@ print ** ACK! I cannot handle BITS longer than 4 bytes!@ +@ exit@ +@ end@ +@ if "x$m2c_mask" eq "x"@ +@ eval $m2c_mask="$m2c_ename"@ +@ else@ +@ eval $m2c_mask="$m2c_mask | $m2c_ename"@ +@ end@ +$m2c_const_dcl $m2c_ename $m2c_const_del (1 << (31-$v)) $m2c_const_sfx +@ else@ +$m2c_const_dcl $m2c_ename $m2c_const_del $v $m2c_const_sfx +@ end@ +@ end@ # for each + +#endif /* ${m2c_de_pfx}_ENUMS */ + +@ if "$node.perltype" eq "BITS"@ +$m2c_const_dcl $m2c_enum_mask $m2c_const_del ($m2c_mask) + +@ end@ +@ if ($m2c_node_skip_mapping != 1) && ($node.enums == 1)@ + /* + * TODO:140:o: Define your interal representation of $node enums. + * (used for value mapping; see notes at top of file) + */ +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ +@ if ("$node.perltype" ne "BITS")@ +$m2c_const_dcl INTERNAL_$context.uc_$m2c_iname $m2c_const_del $v $m2c_const_sfx +@ else@ +$m2c_const_dcl INTERNAL_$context.uc_$m2c_iname $m2c_const_del (0x01 << $v) $m2c_const_sfx +@ end@ +@ end@ // foreach + +@ end@ // skip mapping / enums + +@end@ # ! syntax include +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12011 $ */ +@end@ diff --git a/local/mib2c-conf.d/details-node.m2i b/local/mib2c-conf.d/details-node.m2i new file mode 100644 index 0000000..139336d --- /dev/null +++ b/local/mib2c-conf.d/details-node.m2i @@ -0,0 +1,102 @@ +############################################################# -*- c -*- +## Generic include for columns. Do not use directly. +## +## $Id: details-node.m2i 13790 2005-12-02 18:12:52Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 13790 $ */ +@end@ +######################################################################## +/*--------------------------------------------------------------------- + * $node.module::$node.parent.$node + * $node is subid $node.subid of $node.parent. + * Its status is $node.status, and its access level is $node.access. + * OID: $node.objectID + * Description: +$node.description + * +@if $m2c_node_detail == 1@ + * node -- name $node + * node.parent -- label of the parent $node.parent + * node.objectID -- dotted full OID $node.objectID + * node.commaoid -- comma separated OID $node.commaoid + * node.subid -- last oid component $node.subid + * node.oidlength-- length of the oid $node.oidlength + * node.syntax -- node's syntax $node.syntax + * node.perltype -- node's perl type $node.perltype + * node.type -- node's ASN_XXX type $node.type + * node.decl -- C data type $m2c_decl ($node.decl) + * node.settable -- 1 if it's writable $node.settable + * node.noaccess -- 1 if not-accessible $node.noaccess + * node.access -- node's access type $node.access + * node.status -- node's status $node.status + * node.isscalar -- returns 1 if scalar $node.isscalar + * node.iscolumn -- returns 1 if column $node.iscolumn + * node.enums -- $node.enums + * +@end@ + * Attributes: + * accessible $node.accessible isscalar $node.isscalar enums $node.enums hasdefval $node.hasdefval + * readable $node.readable iscolumn $node.iscolumn ranges $node.ranges hashint $node.hashint + * settable $node.settable +@if $node.hasdefval == 1@ + * defval: $node.defval +@end@ +@if $node.hashint == 1@ + * hint: $node.hint +@end@ + * +@if $node.enums == 1@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $e $v enum@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ eval $m2c_evals = "$m2c_evals $e($v)"@ +@ end@ + * Enum range: $node.enumrange. Values: $m2c_evals +@elsif $node.ranges == 1@ +@ eval $m2c_range_max = 0@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $a $b range $node@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ if $a == $b@ +@ eval $m2c_evals = "$m2c_evals $a"@ +@ else@ +@ eval $m2c_evals = "$m2c_evals $a - $b"@ +@ end@ +@ eval $m2c_range_max = max($m2c_range_max,$b)@ +@ end@ + * Ranges: $m2c_evals; +@end@ #ranges + * + * Its syntax is $node.syntax (based on perltype $node.perltype) + * The net-snmp type is $node.type. The C type decl is $node.decl ($m2c_decl) +@if $node.needlength == 1@ +@ if $node.ranges == 1@ + * This data type requires a length. (Max $m2c_range_max) +@ else@ + * This data type requires a length. +@ end@ +@end@ +@if $node.noaccess@ + * + * + * + * NOTE: NODE $node IS NOT ACCESSIBLE + * + * +@end@ + */ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 13790 $ */ +@end@ diff --git a/local/mib2c-conf.d/details-table.m2i b/local/mib2c-conf.d/details-table.m2i new file mode 100644 index 0000000..cb73702 --- /dev/null +++ b/local/mib2c-conf.d/details-table.m2i @@ -0,0 +1,25 @@ +############################################################# -*- c -*- +## generic include for tables. Do not use directly. +## +## $Id: details-table.m2i 12023 2005-03-24 00:42:15Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12023 $ */ +@end@ +######################################################################## +/********************************************************************** + ********************************************************************** + *** + *** Table $context + *** + ********************************************************************** + **********************************************************************/ +/* + * $context.module::$context is subid $context.subid of $context.parent. + * Its status is $context.status. + * OID: $context.objectID, length: $context.oidlength +*/ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12023 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-ctx-copy.m2i b/local/mib2c-conf.d/generic-ctx-copy.m2i new file mode 100644 index 0000000..a447c46 --- /dev/null +++ b/local/mib2c-conf.d/generic-ctx-copy.m2i @@ -0,0 +1,33 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-ctx-copy.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## + /* +@if $m2c_node_needlength == 1@ + * copy $node and ${node}_len data +@else@ + * copy $node data +@end@ + * set ${m2c_ctx_lh} from ${m2c_ctx_rh} + */ +@if ($m2c_include_examples != 0) || ("$m2c_data_context" eq "generated")@ +@ if $m2c_node_needlength == 0@ + ${m2c_ctx_lh} = ${m2c_ctx_rh}; +@ else@ + memcpy( ${m2c_ctx_lh}, ${m2c_ctx_rh}, + (${m2c_ctx_rhs} * sizeof(${m2c_ctx_lh}[0]))); + ${m2c_ctx_lhs} = ${m2c_ctx_rhs}; +@ end@ # need length +@end@ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-ctx-get.m2i b/local/mib2c-conf.d/generic-ctx-get.m2i new file mode 100644 index 0000000..5828f26 --- /dev/null +++ b/local/mib2c-conf.d/generic-ctx-get.m2i @@ -0,0 +1,106 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-ctx-get.m2i 12865 2005-09-27 17:05:53Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12865 $ */ +@end@ +######################################################################## +##/* +## This include will generate the code needed to assign data from +## a generated data context to a parameter reference. +## +## EXAMPLE (prototype generated elsewhere) +## int +## ifName_get(ifXTable_ctx * ctx, char **ifName_ptr_ptr, +## size_t * ifName_len_ptr) { +## +## +## m2c_node_lh : temp_ifName / (*ifName_ptr_ptr) +## m2c_node_lhs: temp_ifName_len / (*ifName_len_ptr); +## m2c_ctx_rh : ctx->data. +## node : ifName +## +## if (temp_ifName_len < ctx->data.ifName_len) { +## temp_ifName = malloc(ctx->data.ifName_len); +## } +## temp_ifName_len = ctx->data.ifName_len; +## memcpy(temp_ifName, ctx->data.ifName, temp_ifName_len); +##*/ +@if "$m2c_data_context" ne "generated"@ + /** WARNING: this code might not work for $m2c_data_context */ +@end@ +##/* set up for length/copy conversions for various cases. +## length mod applies to left hand side. copy mod applies to right hand side +## +##*/ +@if ("$m2c_ctx_rhu" ne "elements") && ("$m2c_ctx_rhu" ne "bytes")@ +@ print Invalid rh units '$m2c_ctx_rhu'@ +@ exit@ +@end@ +@if ("$m2c_ctx_lhu" ne "elements") && ("$m2c_ctx_lhu" ne "bytes")@ +@ print Invalid lh units '$m2c_ctx_lhu'@ +@ exit@ +@end@ +@if "$m2c_ctx_rhu" ne "$m2c_ctx_lhu"@ +##/* elements = bytes, length mod="/sizeof", copy mult="" */ +@ if "$m2c_ctx_lhu" eq "elements"@ +@ eval $m2c_ctx_lm = "/ sizeof($m2c_ctx_rh[0])"@ +@ eval $m2c_ctx_cm = ""@ +@ else@ +##/* bytes = elements, length mod="*sizeof", copy mult="sizeof" */ +@ eval $m2c_ctx_lm = "* sizeof($m2c_ctx_rh[0])"@ +@ eval $m2c_ctx_cm = "* sizeof($m2c_ctx_rh[0])"@ +@ end@ +@else@ +##/* elements = elements, length mod="", copy mult="sizeof" */ +@ if "$m2c_ctx_lhu" eq "elements"@ +@ eval $m2c_ctx_lm = ""@ +@ eval $m2c_ctx_cm = "* sizeof($m2c_ctx_rh[0])"@ +@ else@ +##/* bytes = bytes, length mod="", copy mult="" */ +@ eval $m2c_ctx_lm = ""@ +@ eval $m2c_ctx_cm = ""@ +@ end@ +@end@ +@if $m2c_node_needlength == 1@ + /* + * make sure there is enough space for $node data + */ + if ((NULL == $m2c_ctx_lh) || + ($m2c_ctx_lhs < + ($m2c_ctx_rhs$m2c_ctx_lm))) { +@ if $m2c_node_realloc == 0@ + snmp_log(LOG_ERR,"not enough space for value\n"); + return MFD_ERROR; +@ else@ + /* + * allocate space for $node data + */ +@ if $m2c_node_realloc == 1@ + $m2c_ctx_lh = realloc($m2c_ctx_lh, $m2c_ctx_rhs$m2c_ctx_cm ); +@ else@ + $m2c_ctx_lh = malloc($m2c_ctx_rhs$m2c_ctx_cm); +@ end@ + if(NULL == $m2c_ctx_lh) { + snmp_log(LOG_ERR,"could not allocate memory\n"); + return MFD_ERROR; + } +@ end@ + } + $m2c_ctx_lhs = $m2c_ctx_rhs$m2c_ctx_lm; + memcpy( $m2c_ctx_lh, $m2c_ctx_rh, $m2c_ctx_rhs$m2c_ctx_cm ); +@else@ +@ if $node.decl =~ /U64/i@ # ASN_COUNTER64 + ${m2c_ctx_lh}.high = ${m2c_ctx_rh}.high; + ${m2c_ctx_lh}.low = ${m2c_ctx_rh}.low; +@ else@ + $m2c_ctx_lh = $m2c_ctx_rh; +@ end@ +@end@ # length +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12865 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-ctx-set.m2i b/local/mib2c-conf.d/generic-ctx-set.m2i new file mode 100644 index 0000000..554fa14 --- /dev/null +++ b/local/mib2c-conf.d/generic-ctx-set.m2i @@ -0,0 +1,29 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-ctx-set.m2i 12586 2005-07-25 23:25:54Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12586 $ */ +@end@ +######################################################################## +## + /* + * TODO:461:M: |-> Set $node value. + * set $node value in $m2c_data_item_base + */ +@if ($m2c_include_examples != 0) || ("$m2c_data_context" eq "generated")@ +@ if $m2c_node_needlength == 0@ + ${m2c_data_item}$node = $m2c_node_srh; +@ else@ + memcpy( ${m2c_data_item}$node, $m2c_node_srh, $m2c_node_srhs ); + /** convert bytes to number of $m2c_decl */ + ${m2c_data_item}${node}_len = $m2c_node_srhs / sizeof(${m2c_node_srh}[0]); +@ end@ # need length +@end@ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12586 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-data-allocate.m2i b/local/mib2c-conf.d/generic-data-allocate.m2i new file mode 100644 index 0000000..b852933 --- /dev/null +++ b/local/mib2c-conf.d/generic-data-allocate.m2i @@ -0,0 +1,62 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-data-allocate.m2i 11948 2005-02-25 22:36:30Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11948 $ */ +@end@ +######################################################################## +## +/* + * ${context}_allocate_data + * + * Purpose: create new ${context}_data. + */ +${context}_data * +${context}_allocate_data(void) +{ +@if $m2c_gda_todo_suppress != 1@ + /* + * TODO:201:r: |-> allocate memory for the $context data context. + */ +@end@ +@if $m2c_data_context != "generated"@ + /** this might not be right for $m2c_data_context */ +@end@ + ${context}_data *rtn = SNMP_MALLOC_TYPEDEF(${context}_data); + + DEBUGMSGTL(("verbose:${context}:${context}_allocate_data","called\n")); + + if(NULL == rtn) { + snmp_log(LOG_ERR, "unable to malloc memory for new " + "${context}_data.\n"); + } + + return rtn; +} /* ${context}_allocate_data */ + +/* + * ${context}_release_data + * + * Purpose: release ${context} data. + */ +void +${context}_release_data(${context}_data *data) +{ + DEBUGMSGTL(("verbose:${context}:${context}_release_data","called\n")); + +@if $m2c_gda_todo_suppress != 1@ + /* + * TODO:202:r: |-> release memory for the $context data context. + */ +@end@ + free(data); +} /* ${context}_release_data */ + +@eval $m2c_gda_todo_suppress = 0@ # reset +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11948 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-data-context.m2i b/local/mib2c-conf.d/generic-data-context.m2i new file mode 100644 index 0000000..de2e74a --- /dev/null +++ b/local/mib2c-conf.d/generic-data-context.m2i @@ -0,0 +1,51 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-data-context.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## +/**********************************************************************/ +/* + * TODO:110:r: |-> Review ${context} data context structure. + * This structure is used to represent the data for $context. + */ +## +@if "$m2c_data_context" eq "generated"@ +/* + * This structure contains storage for all the columns defined in the + * $context. + */ +typedef struct ${context}_data_s { + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * $m2c_node_summary + */ +@ if $m2c_node_needlength == 0@ + $m2c_decl $node; +@ else@ + $m2c_decl $node[$m2c_node_maxlen]; +size_t ${node}_len; /* # of $m2c_decl elements, not bytes */ +@ end@ + +@ end@ # foreach nonindex +} ${context}_data; +@elsif "$m2c_data_context" eq "unknown"@ + /* + * update typedef to correct pointer type. + * (or add @eval $@m2c_data_context = "TYPE"@ and regenerate code) */ +typedef void ${context}_data; +@else@ +typedef $m2c_data_context ${context}_data; +@end@ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-get-char.m2i b/local/mib2c-conf.d/generic-get-char.m2i new file mode 100644 index 0000000..0893e97 --- /dev/null +++ b/local/mib2c-conf.d/generic-get-char.m2i @@ -0,0 +1,49 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-get-char.m2i 12011 2005-03-18 23:01:44Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12011 $ */ +@end@ +######################################################################## +## +## enums first +@if $m2c_node_skip_mapping == -1@ +@ eval $m2c_node_skip_mapping = 1@ +@end@ +@if ($node.enums == 1) && ("$node.perltype" eq "BITS")@ + /* + * TODO:242:o: update or replace BITS tests (get). + * If $node data is stored in SNMP BIT order, individual + * bit tests are redundant, and you can do a straight copy. If not, then + * update each if condition to test the correct bit. + * + * NOTE WELL: setting bit '0' for: + * C 0x0000001 + * SNMP 0x8000000 + * +@ if $m2c_node_skip_mapping != 1@ + * define correct bit to test for all INTERNAL_* defines in the + * ${context} enum or contants header file. + */ +$example_start + $m2c_node_lh = 0; +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ + if ($m2c_ctx_rh & INTERNAL_$context.uc_$m2c_iname) { + $m2c_node_lh |= $m2c_ename; + } +@ end@ # for each +$example_end +@ else@ + * assuming generated code keeps $node BITS in SNMP order. + */ + $m2c_node_lh = @m2c_ctx_rh; +@ end@ +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12011 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-get-decl-bot.m2i b/local/mib2c-conf.d/generic-get-decl-bot.m2i new file mode 100644 index 0000000..4dbda2b --- /dev/null +++ b/local/mib2c-conf.d/generic-get-decl-bot.m2i @@ -0,0 +1,22 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-get-decl-bot.m2i 9366 2004-02-02 15:56:14Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 9366 $ */ +@end@ +######################################################################## +## +@if $m2c_get_use_temp == 1@ + /* copy temporary value to passed parameter */ + (* $m2c_node_param_ref_name) = $m2c_node_lh; +@ if $m2c_node_needlength == 1@ + (* $m2c_node_param_ref_lname) = $m2c_node_lhs; +@ end@ +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 9366 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-get-decl.m2i b/local/mib2c-conf.d/generic-get-decl.m2i new file mode 100644 index 0000000..b95c369 --- /dev/null +++ b/local/mib2c-conf.d/generic-get-decl.m2i @@ -0,0 +1,43 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-get-decl.m2i 9366 2004-02-02 15:56:14Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 9366 $ */ +@end@ +######################################################################## +## +@if $m2c_get_use_temp == 1@ + /* + * Define temporary variable(s). If speed/efficency is an issue, + * remove this code and deal with the pointer directly. + * (set $@m2c_get_use_temp = 0 in your conf file to turn off) + */ +@ if $m2c_node_needlength == 1@ + $m2c_decl * $m2c_node_lh; + size_t $m2c_node_lhs; +@ else@ + $m2c_decl $m2c_node_lh; +@ end@ + +@end@ +@if $m2c_node_needlength == 1@ + /** we should have a non-NULL pointer and enough storage */ + netsnmp_assert( (NULL != $m2c_node_param_ref_name) && (NULL != *$m2c_node_param_ref_name)); + netsnmp_assert( NULL != $m2c_node_param_ref_lname ); +@else@ + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != $m2c_node_param_ref_name ); +@end@ + +@if ($m2c_get_use_temp == 1) && ($m2c_node_needlength == 1)@ + $m2c_node_lh = (* $m2c_node_param_ref_name); + $m2c_node_lhs = (* $m2c_node_param_ref_lname); + +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 9366 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-get-long.m2i b/local/mib2c-conf.d/generic-get-long.m2i new file mode 100644 index 0000000..0aed597 --- /dev/null +++ b/local/mib2c-conf.d/generic-get-long.m2i @@ -0,0 +1,14 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-get-long.m2i 8830 2003-09-30 13:34:57Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ +######################################################################## +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-get-oid.m2i b/local/mib2c-conf.d/generic-get-oid.m2i new file mode 100644 index 0000000..44fdd3a --- /dev/null +++ b/local/mib2c-conf.d/generic-get-oid.m2i @@ -0,0 +1,18 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-get-oid.m2i 10598 2004-07-03 17:10:41Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 10598 $ */ +@end@ +######################################################################## +## +@if $m2c_node_skip_mapping == -1@ +@ eval $m2c_node_skip_mapping = 0@ +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 10598 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-header-bottom.m2i b/local/mib2c-conf.d/generic-header-bottom.m2i new file mode 100644 index 0000000..744a086 --- /dev/null +++ b/local/mib2c-conf.d/generic-header-bottom.m2i @@ -0,0 +1,21 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-header-bottom.m2i 11068 2004-09-14 02:29:16Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11068 $ */ +@end@ +######################################################################## +## + +#ifdef __cplusplus +} +#endif + +#endif /* $name.uc_H */ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11068 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-header-top.m2i b/local/mib2c-conf.d/generic-header-top.m2i new file mode 100644 index 0000000..1dea958 --- /dev/null +++ b/local/mib2c-conf.d/generic-header-top.m2i @@ -0,0 +1,22 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-header-top.m2i 8830 2003-09-30 13:34:57Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ +######################################################################## +## +#ifndef $name.uc_H +#define $name.uc_H + +#ifdef __cplusplus +extern "C" { +#endif + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-source-includes.m2i b/local/mib2c-conf.d/generic-source-includes.m2i new file mode 100644 index 0000000..8b737c9 --- /dev/null +++ b/local/mib2c-conf.d/generic-source-includes.m2i @@ -0,0 +1,23 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-source-includes.m2i 8830 2003-09-30 13:34:57Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ +######################################################################## +## +/* standard Net-SNMP includes */ +#include +#include +#include + +/* include our parent header */ +#include "${name}.h" + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-constants.m2c b/local/mib2c-conf.d/generic-table-constants.m2c new file mode 100644 index 0000000..8133b5c --- /dev/null +++ b/local/mib2c-conf.d/generic-table-constants.m2c @@ -0,0 +1,44 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-constants.m2c 12526 2005-07-15 22:41:16Z rstory $ +######################################################################## +@if $m2c_create_fewer_files != 1@ +@ foreach $table table@ +@ include m2c_setup_table.m2i@ +@ run generic-table-oids.m2c@ +@ run generic-table-enums.m2c@ +@ end@ # table +######################################################################## +@else@ +@ eval $hack = "Id"@ +@ eval $m2c_save = "$name"@ +@ eval $name = "${m2c_save}_constants"@ +@ open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: generic-table-constants.m2c 12526 2005-07-15 22:41:16Z rstory $ + * + * $$hack:$ + */ +######################################################################## +@ if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 12526 $ */ +@ end@ +######################################################################## +@ include generic-header-top.m2i@ +@ eval $name = "$m2c_save"@ +@ foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include generic-table-oids.m2c@ +@ include generic-table-enums.m2c@ +@ end@ # table +@ eval $m2c_save = "$name"@ +@ eval $name = "${m2c_save}_oids"@ +@ include generic-header-bottom.m2i@ +@ eval $name = "$m2c_save"@ +######################################################################## +@ if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 12526 $ */ +@ end@ +@end@ // m2c_create_fewer_files diff --git a/local/mib2c-conf.d/generic-table-enums.m2c b/local/mib2c-conf.d/generic-table-enums.m2c new file mode 100644 index 0000000..a31643a --- /dev/null +++ b/local/mib2c-conf.d/generic-table-enums.m2c @@ -0,0 +1,63 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-enums.m2c 12526 2005-07-15 22:41:16Z rstory $ +######################################################################## +@if $m2c_create_fewer_files != 1@ +@eval $hack = "Id"@ +@eval $m2c_save = "$name"@ +@eval $name = "${name}_enums"@ +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: generic-table-enums.m2c 12526 2005-07-15 22:41:16Z rstory $ + * + * $$hack:$ + */ +@include generic-header-top.m2i@ +@eval $name = "$m2c_save"@ +@end@ // m2c_create_fewer_files +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 12526 $ */ +@end@ +## + /* + * NOTES on enums + * ============== + * + * Value Mapping + * ------------- + * If the values for your data type don't exactly match the + * possible values defined by the mib, you should map them + * below. For example, a boolean flag (1/0) is usually represented + * as a TruthValue in a MIB, which maps to the values (1/2). + * + */ +## +## +/************************************************************************* + ************************************************************************* + * + * enum definitions for table $context + * + ************************************************************************* + *************************************************************************/ + +@ foreach $node column@ +@ include m2c_setup_node.m2i@ +@ if $node.enums == 1@ +@ include details-enums.m2i@ +@ end@ +@ end@ # column + +@if $m2c_create_fewer_files != 1@ +@eval $m2c_save = "$name"@ +@eval $name = "${name}_enums"@ +@include generic-header-bottom.m2i@ +@eval $name = "$m2c_save"@ +@end@ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 12526 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-indexes-from-oid.m2i b/local/mib2c-conf.d/generic-table-indexes-from-oid.m2i new file mode 100644 index 0000000..7ec0b5d --- /dev/null +++ b/local/mib2c-conf.d/generic-table-indexes-from-oid.m2i @@ -0,0 +1,70 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-indexes-from-oid.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## +/** + * extract ${context} indexes from a netsnmp_index + * + * @retval SNMP_ERR_NOERROR : no error + * @retval SNMP_ERR_GENERR : error + */ +int +${context}_index_from_oid(netsnmp_index *oid_idx, + ${context}_mib_index *mib_idx) +{ +@include generic-table-indexes-varbind-setup.m2i@ + + DEBUGMSGTL(("verbose:${context}:${context}_index_from_oid","called\n")); + + /* + * parse the oid into the individual index components + */ + err = parse_oid_indexes( oid_idx->oids, oid_idx->len, + &var_$m2c_dii_first ); + if (err == SNMP_ERR_NOERROR) { + /* + * copy out values + */ +@ eval $m2c_node_name = ""@ # purge node name to re-eval $m2c_node_var_name +@ foreach $node index@ +@ eval $m2c_node_var_name = "var_${node}."@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + /* + * NOTE: val_len is in bytes, ${node}_len might not be + */ + if(var_${node}.val_len > sizeof(mib_idx->$node)) + err = SNMP_ERR_GENERR; + else { + memcpy(mib_idx->${node}, var_${node}.val.string, var_${node}.val_len); + mib_idx->${node}_len = var_${node}.val_len / sizeof(mib_idx->${node}[0]); + } +@ else@ + mib_idx->$node = $m2c_node_var_val; +@ end@ +@ end@ # foreach +@ eval $m2c_node_var_name = ""@ #reset custom name +@ eval $m2c_node_name = ""@ # purge node name to re-eval $m2c_node_var_name + + + } + + /* + * parsing may have allocated memory. free it. + */ + snmp_reset_var_buffers( &var_$m2c_dii_first ); + + return err; +} /* ${context}_index_from_oid */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-indexes-set.m2i b/local/mib2c-conf.d/generic-table-indexes-set.m2i new file mode 100644 index 0000000..c48f73d --- /dev/null +++ b/local/mib2c-conf.d/generic-table-indexes-set.m2i @@ -0,0 +1,123 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-indexes-set.m2i 14170 2006-01-26 17:02:48Z dts12 $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +######################################################################## +## +@eval $gtis_tmp=""@ +@foreach $node index@ +@ include m2c_setup_node.m2i@ +@ eval $gtis_tmp="$gtis_tmp, $m2c_node_param_val"@ +@end@ # for each index +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'h'@ + +int ${context}_indexes_set_tbl_idx(${context}_mib_index *tbl_idx$gtis_tmp); +int ${context}_indexes_set(${context}_rowreq_ctx *rowreq_ctx$gtis_tmp); + +@end@ // m2c_processing_type eq 'h' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'c'@ +/** + * set mib index(es) + * + * @param tbl_idx mib index structure +@foreach $node index@ +@ if $node.needlength == 1@ + * @param ${node}_ptr + * @param ${node}_ptr_len +@else@ + * @param ${node}_val +@end@ +@end@ + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : other error. + * + * @remark + * This convenience function is useful for setting all the MIB index + * components with a single function call. It is assume that the C values + * have already been mapped from their native/rawformat to the MIB format. + */ +int +${context}_indexes_set_tbl_idx(${context}_mib_index *tbl_idx$gtis_tmp) +{ + DEBUGMSGTL(("verbose:${context}:${context}_indexes_set_tbl_idx","called\n")); + +@foreach $node index@ +@ include m2c_setup_node.m2i@ +## table indexes are not allocated pointers, so do not allow realloc here +@eval $m2c_node_realloc = 0@ // fail + /* $m2c_node_summary */ +@ eval $m2c_ctx_lh = "tbl_idx->$node"@ +@ eval $m2c_ctx_lhs = "tbl_idx->${node}_len"@ +@ eval $m2c_ctx_lhu="elements"@ +@ eval $m2c_ctx_rh = "$m2c_node_param_val_name"@ +@ eval $m2c_ctx_rhs = "$m2c_node_param_val_lname"@ +@ eval $m2c_ctx_rhu="elements"@ +@ if $m2c_node_needlength == 1@ + $m2c_ctx_lhs = sizeof($m2c_ctx_lh)/sizeof($m2c_ctx_lh[0]); /* max length */ +@ end@ +## also, assume mapping already done +@ include generic-ctx-get.m2i@ +##@ include generic-value-map.m2i@ + +@end@ // for each column + + return MFD_SUCCESS; +} /* ${context}_indexes_set_tbl_idx */ + +/** + * @internal + * set row context indexes + * + * @param reqreq_ctx the row context that needs updated indexes + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : other error. + * + * @remark + * This function sets the mib indexs, then updates the oid indexs + * from the mib index. + */ +int +${context}_indexes_set(${context}_rowreq_ctx *rowreq_ctx$gtis_tmp) +{ + DEBUGMSGTL(("verbose:${context}:${context}_indexes_set","called\n")); + + if(MFD_SUCCESS != ${context}_indexes_set_tbl_idx(&rowreq_ctx->tbl_idx +@foreach $node index@ +@ include m2c_setup_node.m2i@ + , $m2c_node_param_val_call +@end@ # for each index + )) + return MFD_ERROR; + + /* + * convert mib index to oid index + */ + rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx->oid_tmp) / sizeof(oid); + if(0 != ${context}_index_to_oid(&rowreq_ctx->oid_idx, + &rowreq_ctx->tbl_idx)) { + return MFD_ERROR; + } + + return MFD_SUCCESS; +} /* ${context}_indexes_set */ + +@end@ // m2c_processing_type eq 'c' +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-indexes-to-oid.m2i b/local/mib2c-conf.d/generic-table-indexes-to-oid.m2i new file mode 100644 index 0000000..78a47eb --- /dev/null +++ b/local/mib2c-conf.d/generic-table-indexes-to-oid.m2i @@ -0,0 +1,53 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-indexes-to-oid.m2i 12019 2005-03-22 22:27:57Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12019 $ */ +@end@ +######################################################################## +## +/** + * @internal + * convert the index component stored in the context to an oid + */ +int +${context}_index_to_oid(netsnmp_index *oid_idx, + ${context}_mib_index *mib_idx) +{ +@include generic-table-indexes-varbind-setup.m2i@ + + DEBUGMSGTL(("verbose:${context}:${context}_index_to_oid","called\n")); + +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* $m2c_node_summary */ +@ if $m2c_node_needlength == 1@ + snmp_set_var_value(&var_$node, (u_char*)&mib_idx->$node, + mib_idx->${node}_len * sizeof(mib_idx->${node}[0])); +@ else@ + snmp_set_var_value(&var_$node, (u_char*)&mib_idx->$node, + sizeof(mib_idx->$node)); +@ end@ + +@ end@ # for each column + + err = build_oid_noalloc(oid_idx->oids, oid_idx->len, &oid_idx->len, + NULL, 0, &var_$m2c_dii_first); + if(err) + snmp_log(LOG_ERR,"error %d converting index to oid\n", err); + + /* + * parsing may have allocated memory. free it. + */ + snmp_reset_var_buffers( &var_$m2c_dii_first ); + + return err; +} /* ${context}_index_to_oid */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12019 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-indexes-varbind-setup.m2i b/local/mib2c-conf.d/generic-table-indexes-varbind-setup.m2i new file mode 100644 index 0000000..844bbde --- /dev/null +++ b/local/mib2c-conf.d/generic-table-indexes-varbind-setup.m2i @@ -0,0 +1,51 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-indexes-varbind-setup.m2i 10286 2004-05-18 17:35:47Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 10286 $ */ +@end@ +######################################################################## +## + int err = SNMP_ERR_NOERROR; + + /* + * temp storage for parsing indexes + */ +@ eval $m2c_dii_first = ""@ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if "x$m2c_dii_first" eq "x"@ +@ eval $m2c_dii_first = $node@ +@ eval $m2c_dii_tmp = "var_${node}.next_variable = "@ +@ else@ +@ eval $m2c_dii_tmp = "$m2c_dii_tmp &var_${node}; var_${node}.next_variable = "@ +@ end@ + /* + * $m2c_node_summary + */ + netsnmp_variable_list var_$node; +@ end@ +@ eval $m2c_dii_tmp = "$m2c_dii_tmp NULL;"@ + + /* + * set up varbinds + */ +@ eval $mfd_temp = "idx_vars"@ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + memset( &var_$node, 0x00, sizeof(var_$node) ); + var_${node}.type = $node.type; +@ end@ + + /* + * chain temp index varbinds together + */ + $m2c_dii_tmp + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 10286 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-indexes.m2i b/local/mib2c-conf.d/generic-table-indexes.m2i new file mode 100644 index 0000000..37522ea --- /dev/null +++ b/local/mib2c-conf.d/generic-table-indexes.m2i @@ -0,0 +1,67 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-indexes.m2i 11360 2004-10-15 00:49:24Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11360 $ */ +@end@ +######################################################################## +## +/* + * TODO:120:r: |-> Review $context mib index. + * This structure is used to represent the index for $context. + */ +@eval $m2c_gi_others = (count_indexes($context) - 1)@ +@eval $m2c_gi_len = 0@ +@eval $m2c_gi_warn = 0@ +typedef struct ${context}_mib_index_s { + +@foreach $node index@ +@ include m2c_setup_node.m2i@ +##@ include details-node.m2i@ + /* + * $m2c_node_summary + */ +@ if $m2c_node_needlength == 1@ +@ eval $m2c_gi_warn = 1@ +@ eval $m2c_gi_maxlen = (128 - $node.oidlength - $m2c_gi_others - 1)@ +@ if $m2c_node_maxlen > $m2c_gi_maxlen@ +@ eval $m2c_node_maxlen = $m2c_gi_maxlen@ + /** 128 - $m2c_gi_others(other indexes) - oid length($node.oidlength) = $m2c_node_maxlen */ +@ end@ +@ eval $m2c_gi_len = $m2c_gi_len + $m2c_node_maxlen + 1@ +@ elsif "$node.type" eq "ASN_IPADDRESS"@ +@ eval $m2c_gi_len = $m2c_gi_len + 4@ +@ else@ +@ eval $m2c_gi_len = $m2c_gi_len + 1@ +@ end@ # needlength +@ include node-storage.m2i@ + +@end@ # foreach + +} ${context}_mib_index; + + /* + * TODO:121:r: | |-> Review $context max index length. + * If you KNOW that your indexes will never exceed a certain + * length, update this macro to that length. +@ if $m2c_gi_warn == 1@ + * + * BE VERY CAREFUL TO TAKE INTO ACCOUNT THE MAXIMUM + * POSSIBLE LENGHT FOR EVERY VARIABLE LENGTH INDEX! + * Guessing 128 - col/entry(2) - oid len($context.oidlength) +@ if $m2c_gi_len > 126@ +@ eval $m2c_gi_len = 126 - $context.oidlength@ +@ end@ +##@ else@ +##@ eval $m2c_gi_len = count_indexes($context)@ +@ end@ +*/ +#define MAX_${context}_IDX_LEN $m2c_gi_len + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11360 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-table-oids.m2c b/local/mib2c-conf.d/generic-table-oids.m2c new file mode 100644 index 0000000..48e754c --- /dev/null +++ b/local/mib2c-conf.d/generic-table-oids.m2c @@ -0,0 +1,113 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-table-oids.m2c 17548 2009-04-23 16:35:18Z hardaker $ +######################################################################## +@if $m2c_create_fewer_files != 1@ +@eval $hack = "Id"@ +@eval $m2c_save = "$name"@ +@eval $name = "${m2c_save}_oids"@ +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: generic-table-oids.m2c 17548 2009-04-23 16:35:18Z hardaker $ + * + * $$hack:$ + */ +@include generic-header-top.m2i@ +@eval $name = "$m2c_save"@ +@end@ // m2c_create_fewer_files +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 17548 $ */ +@end@ +## + +/* column number definitions for table $context */ +#define $context.uc_OID $context.commaoid + + @eval $minv = 0xffffffff@ + @eval $maxv = 0@ + @eval $gto_flag_req = ""@ + @eval $gto_flag_set = ""@ + @eval $m2c_tmp_gto = 0@ + + @foreach $node column@ +#define COLUMN_$node.uc $node.subid + @if $node.accessible == 1@ + @if ($node.settable == 1) || ($m2c_table_sparse == 1)@ +@ if "x$gto_flag_set" eq "x"@ +@ eval $gto_flag_set = "COLUMN_$node.uc_FLAG"@ +@ else@ +@ eval $gto_flag_set = "$gto_flag_set | COLUMN_$node.uc_FLAG"@ +@ end@ + @if $m2c_tmp_gto > 31@ +#define COLUMN_$node.uc_FLAG (((uint64_t)0x1) << $m2c_tmp_gto) + @else@ +#define COLUMN_$node.uc_FLAG (0x1 << $m2c_tmp_gto) + @end@ + @eval $m2c_tmp_gto = $m2c_tmp_gto + 1@ + @end@ + @if ($m2c_table_row_creation == 1) && ($node.settable == 1) && ("x$node.defval" eq "x")@ + @if "x$gto_flag_req" eq "x"@ + @eval $gto_flag_req = "COLUMN_$node.uc_FLAG"@ + @else@ + @eval $gto_flag_req = "$gto_flag_req | COLUMN_$node.uc_FLAG"@ + @end@ + @end@ + @if $node.subid < $minv@ + @eval $minv = $node.subid@ + @eval $minn = "COLUMN_$node.uc"@ + @end@ + @if $node.subid > $maxv@ + @eval $maxv = $node.subid@ + @eval $maxn = "COLUMN_$node.uc"@ + @end@ + @end@ + + @end@ # column + +#define $context.uc_MIN_COL $minn +#define $context.uc_MAX_COL $maxn +## +## column_set_flags and column_exist_flags are unsigned ints, to 32 is +## the limit. Could try something with a 'long long' to see if that +## can get us to 64, or do something like FD_SET, which would let us +## be pretty unlimited. +## + @if $maxn > 31@ + @ print ERROR: more than 32 columns not supported yet.@ + @ exit@ + @end@ + + +@ if $m2c_table_settable@ + @if "x$gto_flag_set" ne "x"@ + /* + * TODO:405:r: Review $context.uc_SETTABLE_COLS macro. + * OR together all the writable cols. + */ +#define $context.uc_SETTABLE_COLS ($gto_flag_set) + @end@ + @if $m2c_table_row_creation@ + @if "x$gto_flag_req" ne "x"@ + /* + * TODO:405:r: Review $context.uc_REQUIRED_COLS macro. + * OR together all the required rows for row creation. + * default is writable cols w/out defaults. + */ +#define $context.uc_REQUIRED_COLS ($gto_flag_req) + + @end@ + @end@ +@ end@ # settable +@if $m2c_create_fewer_files != 1@ +@eval $m2c_save = "$name"@ +@eval $name = "${m2c_save}_oids"@ +@include generic-header-bottom.m2i@ +@eval $name = "$m2c_save"@ +@end@ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 17548 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-value-map-func.m2i b/local/mib2c-conf.d/generic-value-map-func.m2i new file mode 100644 index 0000000..49ed332 --- /dev/null +++ b/local/mib2c-conf.d/generic-value-map-func.m2i @@ -0,0 +1,104 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-value-map-func.m2i 12095 2005-04-18 22:14:01Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12095 $ */ +@end@ +######################################################################## +## } +/** + * map a value from its original native format to the MIB format. + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : Any other error + * + * @note parameters follow the memset convention (dest, src). + * + * @note generation and use of this function can be turned off by re-running + * mib2c after adding the following line to the file + * ${m2c_defaults_dir}node-${node}.m2d : + * @eval $@m2c_node_skip_mapping = 1@ + * + * @remark + * If the values for your data type don't exactly match the + * possible values defined by the mib, you should map them here. + * Otherwise, just do a direct copy. + */ +int +${node}_map($m2c_node_map_param) +{ +@if $m2c_node_needlength == 1@ + int converted_len; + + netsnmp_assert(NULL != raw_$m2c_node_param_val_name); + netsnmp_assert((NULL != mib_$m2c_node_param_ref_name) && (NULL != mib_$m2c_node_param_ref_lname)); +@else@ + netsnmp_assert(NULL != mib_$m2c_node_param_ref_name); +@end@ + + DEBUGMSGTL(("verbose:${context}:${node}_map","called\n")); + +@if $m2c_node_needlength == 1@ + /* + * TODO:241:r: |-> Implement $node non-integer mapping + * it is hard to autogenerate code for mapping types that are not simple + * integers, so here is an idea of what you might need to do. It will + * probably need some tweaking to get right. + */ + /* + * if the length of the raw data doesn't directly correspond with + * the length of the mib data, set converted_len to the + * space required. + */ + converted_len = raw_$m2c_node_param_val_lname; /* assume equal */ + if((NULL == *mib_$m2c_node_param_ref_name) || (*mib_$m2c_node_param_ref_lname < converted_len)) { + if(! allow_realloc) { + snmp_log(LOG_ERR,"not enough space for value mapping\n"); + return SNMP_ERR_GENERR; + } + *mib_$m2c_node_param_ref_name = realloc( *mib_$m2c_node_param_ref_name, converted_len * sizeof(**mib_$m2c_node_param_ref_name)); + if(NULL == *mib_$m2c_node_param_ref_name) { + snmp_log(LOG_ERR,"could not allocate memory\n"); + return SNMP_ERR_GENERR; + } + } + *mib_$m2c_node_param_ref_lname = converted_len; + memcpy( *mib_$m2c_node_param_ref_name, raw_$m2c_node_param_val_name, converted_len ); +## +@elsif ($node.enums == 1) && ("$node.perltype" eq "INTEGER")@ + /* + * TODO:241:o: |-> Implement $node enum mapping. + * uses INTERNAL_* macros defined in the header files + */ + switch(raw_$m2c_node_param_val_name) { +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ + case INTERNAL_$context.uc_$m2c_iname: + *mib_$m2c_node_param_ref_name = $m2c_ename; + break; + +@ end@ # foreach + default: + snmp_log(LOG_ERR, "couldn't map value %ld for $node\n", raw_$m2c_node_param_val_name ); + return MFD_ERROR; + } +## +@else@ + /* + * TODO:241:o: |-> Implement $node mapping. + * If the values for your data type don't exactly match the + * possible values defined by the mib, you should map them here. + */ + (*mib_$m2c_node_param_ref_name) = raw_$m2c_node_param_val_name; +@end@ + + return MFD_SUCCESS; +} /* ${node}_map */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12095 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-value-map-reverse.m2i b/local/mib2c-conf.d/generic-value-map-reverse.m2i new file mode 100644 index 0000000..16baaa0 --- /dev/null +++ b/local/mib2c-conf.d/generic-value-map-reverse.m2i @@ -0,0 +1,49 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-value-map-reverse.m2i 12587 2005-07-25 23:26:53Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12587 $ */ +@end@ +######################################################################## +## +/* + * TODO:245:o: |-> Implement $node reverse mapping. + * If the values for your data type don't exactly match the + * possible values defined by the mib, you should map them here. + */ +@if ($node.enums == 1)@ +$example_start +@ if ("$node.perltype" eq "BITS")@ + $m2c_ctx_rh = 0; +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ + if ($m2c_node_srh & $m2c_ename) { + $m2c_ctx_rh |= INTERNAL_$context.uc_$m2c_iname; + } +@ end@ # for each +@ elsif ("$node.perltype" eq "INTEGER")@ + switch($m2c_node_srh) { +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ + case $m2c_ename: + $m2c_ctx_rh = INTERNAL_$context.uc_$m2c_iname; + break; + +@ end@ # foreach + default: + snmp_log(LOG_ERR, "couldn't reverse map value %ld for $node\n", $m2c_node_srh ); + return SNMP_ERR_GENERR; + } +@ end@ # integers/bits +$example_end +@else@ +@ include generic-ctx-set.m2i@ +@end@ # enums + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12587 $ */ +@end@ diff --git a/local/mib2c-conf.d/generic-value-map.m2i b/local/mib2c-conf.d/generic-value-map.m2i new file mode 100644 index 0000000..1fbe42d --- /dev/null +++ b/local/mib2c-conf.d/generic-value-map.m2i @@ -0,0 +1,46 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: generic-value-map.m2i 11593 2004-12-10 14:46:09Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11593 $ */ +@end@ +######################################################################## +## } +@if $m2c_node_skip_mapping == 1@ + /** no mapping */ +@ include generic-ctx-get.m2i@ +@else@ // mapping + /* + * TODO:246:r: |-> Define $node mapping. + * Map values between raw/native values and MIB values + * +@ if $m2c_node_needlength == 1@ + * if(MFD_SUCCESS != + * ${node}_map(&$m2c_ctx_lh, &$m2c_ctx_lhs, + * $m2c_ctx_rh, $m2c_ctx_rhs, $m2c_node_realloc)) { + * return MFD_ERROR; + * } + */ +@ include generic-ctx-get.m2i@ +## +@ elsif ($node.enums == 1) && ("$node.perltype" eq "INTEGER")@ +## + * enums usually need mapping. + */ + if(MFD_SUCCESS != + ${node}_map(&${m2c_ctx_lh}, ${m2c_ctx_rh} )) { + return MFD_ERROR; + } +@ else@ // enums + * Integer based value can usually just do a direct copy. + */ +@ include generic-ctx-get.m2i@ +@ end@ +@end@ // mapping +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11593 $ */ +@end@ diff --git a/local/mib2c-conf.d/m2c-internal-warning.m2i b/local/mib2c-conf.d/m2c-internal-warning.m2i new file mode 100644 index 0000000..8e685e6 --- /dev/null +++ b/local/mib2c-conf.d/m2c-internal-warning.m2i @@ -0,0 +1,21 @@ +/* + * ********************************************************************* + * ********************************************************************* + * ********************************************************************* + * *** *** + * *** NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE *** + * *** *** + * *** *** + * *** THIS FILE DOES NOT CONTAIN ANY USER EDITABLE CODE. *** + * *** *** + * *** *** + * *** THE GENERATED CODE IS INTERNAL IMPLEMENTATION, AND *** + * *** *** + * *** *** + * *** IS SUBJECT TO CHANGE WITHOUT WARNING IN FUTURE RELEASES. *** + * *** *** + * *** *** + * ********************************************************************* + * ********************************************************************* + * ********************************************************************* + */ diff --git a/local/mib2c-conf.d/m2c_setup_enum.m2i b/local/mib2c-conf.d/m2c_setup_enum.m2i new file mode 100644 index 0000000..faaef73 --- /dev/null +++ b/local/mib2c-conf.d/m2c_setup_enum.m2i @@ -0,0 +1,24 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: m2c_setup_enum.m2i 11987 2005-03-04 19:58:28Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11987 $ */ +@end@ +######################################################################## +## +## the iname enum should be unique per column, so always use node name +## +@ if $m2c_const_lc == 1@ +@ eval $m2c_ename = "${m2c_de_pfx}_${e}${m2c_enum_sfx}"@ +@ eval $m2c_iname = "${m2c_const_pfx}${node}_${e}${m2c_enum_sfx}"@ +@ else@ +@ eval $m2c_ename = "${m2c_de_pfx}_$e.uc${m2c_enum_sfx}"@ +@ eval $m2c_iname = "${m2c_const_pfx}$node.uc_$e.uc${m2c_enum_sfx}"@ +@ end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11987 $ */ +@end@ diff --git a/local/mib2c-conf.d/m2c_setup_node.m2i b/local/mib2c-conf.d/m2c_setup_node.m2i new file mode 100644 index 0000000..719193b --- /dev/null +++ b/local/mib2c-conf.d/m2c_setup_node.m2i @@ -0,0 +1,260 @@ +############################################################# -*- c -*- +## Defaults +## $Id: m2c_setup_node.m2i 12856 2005-09-27 15:58:00Z rstory $ +######################################################################## +@if "$m2c_node_name" ne "$node"@ +## if $node.accessible != 1, might be inaccessible index node +@ eval $m2c_node_name = $node@ +@ eval $m2c_node_skip_mapping = $m2c_table_skip_mapping@ +@ eval $m2c_node_needlength = $node.needlength@ +@ eval $m2c_node_get_comments = ""@ +@ eval $m2c_node_set_comments = ""@ +@ eval $m2c_node_skip_get = 0@ +##//how should a function handle a pointer to a buffer that is to small? +@ eval $m2c_node_realloc = 0@ // 0=fail, 1=realloc, 2=malloc +######################################################################## +## fix some declarations +######################################################################## +@ if $node.enums == 1@ +## +@ if $m2c_node_skip_mapping == -1@ +@ eval $m2c_node_skip_mapping = 0@ +@ end@ +## +## validate some assumptions +## +@ if ("$node.perltype" ne "INTEGER") && ("$node.perltype" ne "BITS")@ +@ print "$node had enums, but isn't INTEGER or BITS! ($node.perltype)\n"@ +@ exit@ +@ end@ +@ if $node.ranges == 1@ +@ print "$node has enums and ranges!\n"@ +@ exit@ +@ end@ +## +## for a TC, prefix definition w/syntax to reduce collisions +## +@ if $node.syntax ne $node.perltype@ +@ eval $m2c_de_pfx = "${m2c_const_pfx}$node.syntax"@ +@ else@ +@ eval $m2c_de_pfx = "${m2c_const_pfx}$node"@ +@ end@ +@ if $m2c_const_lc == 0@ +@ eval $m2c_de_pfx = uc($m2c_de_pfx)@ +@ end@ +@ if "$node.perltype" eq "BITS"@ +@ eval $m2c_enum_sfx="_flag"@ +@ eval $m2c_enum_mask="${m2c_de_pfx}_flag"@ +@ if $m2c_const_lc == 0@ +@ eval $m2c_enum_sfx = uc($m2c_enum_sfx)@ +@ eval $m2c_enum_mask = uc($m2c_enum_mask)@ +@ end@ +@ else@ +@ eval $m2c_enum_sfx=""@ +@ end@ +## +## use longs for enums (w/out length) +## +@ eval $m2c_decl = "u_long"@ +@ eval $m2c_node_needlength = 0@ +@ if "$node.perltype" eq "BITS"@ +@ eval $m2c_node_skip_get = 1@ +@ end@ +@ else@ +@ eval $m2c_decl = $node.decl@ + @ end@ // enums +######################################################################## +## find max size +######################################################################## +@ if $node.ranges == 1@ +## +## I do not *think* you can have both... +## +@ if $node.enums == 1@ +@ print "$node has enums and ranges!\n"@ +@ exit@ +@ end@ +@ eval $m2c_node_maxlen = 0@ +@ foreach $a $b range $node@ +@ eval $m2c_node_maxlen = max($m2c_node_maxlen,$b)@ +@ end@ +@ elsif "$node.type" eq "ASN_OBJECT_ID"@ +@ eval $m2c_node_maxlen = 128@ +@ else@ #ranges +@ eval $m2c_node_maxlen = 65535@ +@ end@ #ranges +##/*#################################################################### +## set up extra params, based on if we need length +######################################################################## +## VAR_VAL : variable value. +## VAR_VAL_PTR : pointer to variable value. +## VAR_REF : variable reference. (pointer to pointer to variable value) +##*/ +@ if "x$m2c_node_var_name" eq "x"@ +@ eval $m2c_node_var_name="var->"@ +@ end@ +@ eval $m2c_node_var_val_ptr = "($m2c_decl *)${m2c_node_var_name}val.string"@ +@ if $m2c_node_needlength == 1@ +@ eval $m2c_XX = "($m2c_decl **)&${m2c_node_var_name}val.string,"@ +@ eval $m2c_node_var_ref = "$m2c_XX &${m2c_node_var_name}val_len"@ +@ eval $m2c_node_var_val = "$m2c_node_var_val_ptr, ${m2c_node_var_name}val_len"@ +@ else@ +@ eval $m2c_node_var_ref = "($m2c_decl *)${m2c_node_var_name}val.string"@ +@ eval $m2c_node_var_val = "*($m2c_node_var_val_ptr)"@ +@ end@ +## +## +@ eval $m2c_node_param_val_name = "${node}_val"@ +@ eval $m2c_node_param_val_lname = "${m2c_node_param_val_name}_len"@ +@ eval $m2c_node_param_ref_name = "${m2c_node_param_val_name}_ptr"@ +@ if $m2c_node_needlength == 1@ +@ eval $m2c_node_param_val_name = "${m2c_node_param_val_name}_ptr"@ +@ eval $m2c_node_param_val_lname = "${m2c_node_param_val_name}_len"@ +@ eval $m2c_node_param_val_call = "${m2c_node_param_val_name}, ${m2c_node_param_val_lname}"@ +@ eval $m2c_node_param_ref_name = "${m2c_node_param_ref_name}_ptr"@ +@ eval $m2c_node_param_ref_lname = "${m2c_node_param_val_lname}_ptr"@ +@ eval $m2c_XX = "$m2c_decl **$m2c_node_param_ref_name,"@ +@ eval $m2c_node_param_ref = "$m2c_XX size_t *$m2c_node_param_ref_lname"@ +@ eval $m2c_XX = "$m2c_decl *$m2c_node_param_val_name,"@ +@ eval $m2c_node_param_val = "$m2c_XX size_t $m2c_node_param_val_lname"@ +@ else@ +@ eval $m2c_node_param_ref = "$m2c_decl * $m2c_node_param_ref_name"@ +@ eval $m2c_node_param_val = "$m2c_decl $m2c_node_param_val_name"@ +@ eval $m2c_node_param_val_call = "$m2c_node_param_val_name"@ +## +@ end@ +## +######################################################################## +## include user overrides +######################################################################## +@ include -ifexists ${m2c_defaults_dir}node-${node}.m2d@ +######################################################################## +## +######################################################################## +@ if $m2c_get_use_temp == 1@ +@ eval $m2c_node_lh = "temp_$node"@ +@ eval $m2c_node_lhs = "temp_${node}_len"@ +@ else@ +@ eval $m2c_node_lh = "(* $m2c_node_param_ref_name )"@ +@ eval $m2c_node_lhs = "(* $m2c_node_param_ref_lname )"@ +@ end@ +@ eval $m2c_ctx_lh="$m2c_node_lh"@ +@ eval $m2c_ctx_lhs="$m2c_node_lhs"@ +@ eval $m2c_ctx_lhu="bytes"@ +@ eval $m2c_ctx_rh="${m2c_data_item}${node}"@ +@ eval $m2c_ctx_rhs="${m2c_data_item}${node}_len"@ +@ eval $m2c_ctx_rhu="elements"@ +######################################################################## +## +######################################################################## +@ if $m2c_node_skip_mapping != 1@ +@ if $m2c_node_needlength == 1@ +@ eval $m2c_XX="$m2c_decl **mib_$m2c_node_param_ref_name,"@ +@ eval $m2c_XX="$m2c_XX size_t *mib_$m2c_node_param_ref_lname,"@ +@ eval $m2c_XX="$m2c_XX $m2c_decl *raw_$m2c_node_param_val_name,"@ +@ eval $m2c_XX="$m2c_XX size_t raw_$m2c_node_param_val_lname,"@ +@ eval $m2c_node_map_param="$m2c_XX int allow_realloc"@ +@ else@ +@ eval $m2c_XX="$m2c_decl *mib_$m2c_node_param_ref_name,"@ +@ eval $m2c_node_map_param="$m2c_XX $m2c_decl raw_$m2c_node_param_val_name"@ +@ end@ +@ end@ +######################################################################## +## +######################################################################## +@ eval $m2c_node_srh = "$m2c_node_param_val_name"@ +@ eval $m2c_node_srhs = "$m2c_node_param_val_lname"@ +@end@ +######################################################################## +## +@eval $m2c_node_summary="$node($node.subid)/$node.syntax/$node.type/$node.decl($m2c_decl)/"@ +@if $node.needlength == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/l"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/L"@ +@end@ +@if $node.noaccess == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/A"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/a"@ +@end@ +@if $node.settable == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/w"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/W"@ +@end@ +@if $node.enums == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/e"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/E"@ +@end@ +@if $node.ranges == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/r"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/R"@ +@end@ +@if $node.hasdefval == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/d"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/D"@ +@end@ +@if $node.hashint == 0@ +@ eval $m2c_node_summary="$m2c_node_summary/h"@ +@else@ +@ eval $m2c_node_summary="$m2c_node_summary/H"@ +@end@ +######################################################################## +@ ifconf ${m2c_defaults_dir}node-${node}.m2d@ +@ else@ +@ push@ +@ open ${m2c_defaults_dir}node-${node}.m2d@ +@ eval $m2c_conf_comment = "##"@ +@ eval $m2c_conf_comment_divider = "########################################################################"@ +$m2c_conf_comment_divider +$m2c_conf_comment +$m2c_conf_comment mib2c node setting for $node +$m2c_conf_comment +$m2c_conf_comment Remove the '##' comment delimeter to change settings +$m2c_conf_comment +$m2c_conf_comment_divider +$m2c_conf_comment Node declaration type? This is the C type to be used when +$m2c_conf_comment declaring a variable to hold a value for this column. It +$m2c_conf_comment is strongly recommended that you do not change this value. +$m2c_conf_comment If you do, it is likely to break lots of generated code that +$m2c_conf_comment you will have to fix. +$m2c_conf_comment +$m2c_conf_comment @eval $@m2c_decl = $m2c_decl@ +$m2c_conf_comment +$m2c_conf_comment_divider +$m2c_conf_comment Generate/use mapping functions? Useful if the MIB defines +$m2c_conf_comment a different format or enumerations than you data store uses. +$m2c_conf_comment +$m2c_conf_comment @eval $@m2c_node_skip_mapping = $m2c_node_skip_mapping@ +$m2c_conf_comment +$m2c_conf_comment_divider +$m2c_conf_comment Need a length for the value? Most OCTET-STRING based values will +$m2c_conf_comment need a length, most other types will not. Do not change this one +$m2c_conf_comment unless you know what you are doing! You will almost certainly need +$m2c_conf_comment to fix lots of generated code if you do. +$m2c_conf_comment +$m2c_conf_comment @eval $@m2c_node_needlength = $m2c_node_needlength@ +$m2c_conf_comment +$m2c_conf_comment_divider +$m2c_conf_comment Skip get? Set this to 1 if you do not want to implement a value +$m2c_conf_comment for this column. +$m2c_conf_comment +$m2c_conf_comment @eval $@m2c_node_skip_get = $m2c_node_skip_get@ +$m2c_conf_comment +@ if $m2c_node_needlength == 1@ +$m2c_conf_comment_divider +$m2c_conf_comment Allow realloc when data size exceeds length? If your data +$m2c_conf_comment store for this node is a pointer allocated with one of the +$m2c_conf_comment alloc family functions, you can set this to 1 to use realloc +$m2c_conf_comment when a new value length exceeds the old lenght. If you are +$m2c_conf_comment using a fixed size buffer, this value should be 0. +$m2c_conf_comment +$m2c_conf_comment @eval $@m2c_node_realloc = $m2c_node_realloc@ +@ end@ +@ close ${m2c_defaults_dir}node-${node}.m2d@ +@ pop@ +@ end@ diff --git a/local/mib2c-conf.d/m2c_setup_table.m2i b/local/mib2c-conf.d/m2c_setup_table.m2i new file mode 100644 index 0000000..cca31af --- /dev/null +++ b/local/mib2c-conf.d/m2c_setup_table.m2i @@ -0,0 +1,48 @@ +######################################################################## +## generic include for XXX. Do not use directly. +## +## $Id: m2c_setup_table.m2i 12086 2005-04-18 21:53:05Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12086 $ */ +@end@ +######################################################################## +## +@if "$m2c_context_name" ne "$table"@ +@ eval $m2c_context_name = $table@ +@ eval $context = $table@ +@ if $m2c_report_progress == 1@ +@ print | +-> Processing table $context@ +@ end@ +@ eval $m2c_context_item = "rowreq_ctx->"@ +@ eval $m2c_table_external_indexes = count_external_indexes($context)@ +## +@ eval $m2c_undo_embed = $mfd_default_undo_embed@ +@ eval $m2c_gda_todo_suppress = 0@ # todo comments +## +## user override +## +@ include ${m2c_defaults_dir}table-${context}.m2d@ +## +@ eval $m2c_data_item_base = "${m2c_context_item}data"@ +@ if $m2c_data_allocate == 1@ +@ eval $m2c_data_item = "${m2c_data_item_base}->"@ +@ else@ +@ eval $m2c_data_item = "${m2c_data_item_base}."@ +@ end@ +@ if $m2c_table_settable == 0@ +@ eval $m2c_undo_embed = 1@ +@ end@ +@ eval $m2c_undo_item_base = "${m2c_context_item}undo"@ +@ if $m2c_undo_embed == 1@ +@ eval $m2c_undo_item = "${m2c_undo_item_base}."@ +@ else@ +@ eval $m2c_undo_item = "${m2c_undo_item_base}->"@ +@ end@ +@end@ +@eval $m2c_node_name = ""@ +######################################################################## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12086 $ */ +@end@ diff --git a/local/mib2c-conf.d/m2c_table_save_defaults.m2i b/local/mib2c-conf.d/m2c_table_save_defaults.m2i new file mode 100644 index 0000000..bdd03e4 --- /dev/null +++ b/local/mib2c-conf.d/m2c_table_save_defaults.m2i @@ -0,0 +1,117 @@ +####################################################################### +## generic include for XXX. Do not use directly. +## +## $Id: m2c_table_save_defaults.m2i 12577 2005-07-25 15:37:02Z dts12 $ +######################################################################## +## +## +## Note: if you add a var here, add it in mfd-interactive-setup.m2c too +## +## +@open ${m2c_defaults_dir}table-${context}.m2d@ +@eval $m2c_tmp_cc = "##"@ +@eval $tmp_cc = ""@ # hack to prevet mib2c eval +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc mib2c Table setting for $context +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc User context structure type +$m2c_tmp_cc +$tmp_cc@eval $@m2c_context_reg = "$m2c_context_reg"@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Allocate data structure in row structure? (vs embedd) +$m2c_tmp_cc +$tmp_cc@eval $@m2c_data_allocate = $m2c_data_allocate@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate code to cache data? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_data_cache = $m2c_data_cache@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Data context structure type +$m2c_tmp_cc +$tmp_cc@eval $@m2c_data_context = "$m2c_data_context"@ [generated|NAME] +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate function to initialize row context when created? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_data_init = $m2c_data_init@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Persistence of data context +$m2c_tmp_cc // 0:persistent, 1:semi-transient, 2:transient +$m2c_tmp_cc +$tmp_cc@eval $@m2c_data_transient = $m2c_data_transient@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Include some example code? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_include_examples = $m2c_include_examples@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate code for irreversible_commit mode? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_irreversible_commit = $m2c_irreversible_commit@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Data access method +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_access = "$m2c_table_access"@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate row dependency function? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_dependencies = $m2c_table_dependencies@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate data store/restore functions for persistent storage? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_persistent = $m2c_table_persistent@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate code for dynamic row creation? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_row_creation = $m2c_table_row_creation@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate code for settable objects? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_settable = $m2c_table_settable@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Skip mapping between data context and MIB formats? +$m2c_tmp_cc // 0:generate maps, 1:skip maps, -1:skip unless enum/oid +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_skip_mapping = $m2c_table_skip_mapping@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate code for sparse tables? +$m2c_tmp_cc +$tmp_cc@eval $@m2c_table_sparse = $m2c_table_sparse@ +$m2c_tmp_cc +$m2c_tmp_cc ######################################################################## +$m2c_tmp_cc +$m2c_tmp_cc Generate Makefile/AgentX code? +$m2c_tmp_cc +$tmp_cc@eval $@mfd_generate_makefile = $mfd_generate_makefile@ +$tmp_cc@eval $@mfd_generate_subagent = $mfd_generate_subagent@ +$m2c_tmp_cc +@close ${m2c_defaults_dir}table-${context}.m2d@ diff --git a/local/mib2c-conf.d/mfd-access-container-cached-defines.m2i b/local/mib2c-conf.d/mfd-access-container-cached-defines.m2i new file mode 100644 index 0000000..f774720 --- /dev/null +++ b/local/mib2c-conf.d/mfd-access-container-cached-defines.m2i @@ -0,0 +1,576 @@ +####################################################################### +###generic include for XXX. Do not use directly. +### +### $Id: mfd-access-container-cached-defines.m2i 14170 2006-01-26 17:02:48Z dts12 $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'h'@ + +@ if $m2c_data_cache != 1@ +void ${context}_container_init(netsnmp_container **container_ptr_ptr); +@ else@ + /* + * TODO:180:o: Review ${context} cache timeout. + * The number of seconds before the cache times out + */ +#define $context.uc_CACHE_TIMEOUT 60 + +void ${context}_container_init(netsnmp_container **container_ptr_ptr, + netsnmp_cache *cache); +@ end@ # data cache +void ${context}_container_shutdown(netsnmp_container *container_ptr); + +int ${context}_container_load(netsnmp_container *container); +void ${context}_container_free(netsnmp_container *container); + +@ if $m2c_data_cache == 1@ +int ${context}_cache_load(netsnmp_container *container); +void ${context}_cache_free(netsnmp_container *container); + +@ end@ +@ if $m2c_include_examples == 1@ +$example_start +/* ********************************************************************* + * Since we have no idea how you really access your data, we'll go with + * a worst case example: a flat text file. + */ +#define MAX_LINE_SIZE 256 +$example_end +@ end@ // example +@end@ // m2c_processing_type eq 'h' +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'c'@ +/** + * container overview + * + */ + +/** + * container initialization + * + * @param container_ptr_ptr A pointer to a container pointer. If you + * create a custom container, use this parameter to return it + * to the MFD helper. If set to NULL, the MFD helper will + * allocate a container for you. +@ if $m2c_data_cache == 1@ + * @param cache A pointer to a cache structure. You can set the timeout + * and other cache flags using this pointer. +@ end@ + * + * This function is called at startup to allow you to customize certain + * aspects of the access method. For the most part, it is for advanced + * users. The default code should suffice for most cases. If no custom + * container is allocated, the MFD code will create one for your. + * +@ if $m2c_data_cache == 1@ + * This is also the place to set up cache behavior. The default, to + * simply set the cache timeout, will work well with the default + * container. If you are using a custom container, you may want to + * look at the cache helper documentation to see if there are any + * flags you want to set. + * +@ end@ + * @remark + * This would also be a good place to do any initialization needed + * for you data source. For example, opening a connection to another + * process that will supply the data, opening a database, etc. + */ +void +@ if $m2c_data_cache != 1@ +${context}_container_init(netsnmp_container **container_ptr_ptr) +@ else@ +${context}_container_init(netsnmp_container **container_ptr_ptr, + netsnmp_cache *cache) +@ end@ +{ + DEBUGMSGTL(("verbose:${context}:${context}_container_init","called\n")); + + if (NULL == container_ptr_ptr) { + snmp_log(LOG_ERR,"bad container param to ${context}_container_init\n"); + return; + } + + /* + * For advanced users, you can use a custom container. If you + * do not create one, one will be created for you. + */ + *container_ptr_ptr = NULL; + +@if $m2c_data_cache == 1@ + if (NULL == cache) { + snmp_log(LOG_ERR,"bad cache param to ${context}_container_init\n"); + return; + } + + /* + * TODO:345:A: Set up $context cache properties. + * + * Also for advanced users, you can set parameters for the + * cache. Do not change the magic pointer, as it is used + * by the MFD helper. To completely disable caching, set + * cache->enabled to 0. + */ + cache->timeout = $context.uc_CACHE_TIMEOUT; /* seconds */ +@end@ +} /* ${context}_container_init */ + +/** + * container shutdown + * + * @param container_ptr A pointer to the container. + * + * This function is called at shutdown to allow you to customize certain + * aspects of the access method. For the most part, it is for advanced + * users. The default code should suffice for most cases. + * + * This function is called before ${context}_container_free(). + * + * @remark + * This would also be a good place to do any cleanup needed + * for you data source. For example, closing a connection to another + * process that supplied the data, closing a database, etc. + */ +void +${context}_container_shutdown(netsnmp_container *container_ptr) +{ + DEBUGMSGTL(("verbose:${context}:${context}_container_shutdown","called\n")); + + if (NULL == container_ptr) { + snmp_log(LOG_ERR,"bad params to ${context}_container_shutdown\n"); + return; + } + +} /* ${context}_container_shutdown */ + +/** + * load initial data + * + * TODO:350:M: Implement $context data load +@ if $m2c_data_cache == 1@ + * This function will also be called by the cache helper to load + * the container again (after the container free function has been + * called to free the previous contents). +@ end@ + * + * @param container container to which items should be inserted + * + * @retval MFD_SUCCESS : success. + * @retval MFD_RESOURCE_UNAVAILABLE : Can't access data source + * @retval MFD_ERROR : other error. + * + * This function is called to load the index(es) (and data, optionally) + * for the every row in the data set. + * + * @remark + * While loading the data, the only important thing is the indexes. + * If access to your data is cheap/fast (e.g. you have a pointer to a + * structure in memory), it would make sense to update the data here. + * If, however, the accessing the data invovles more work (e.g. parsing + * some other existing data, or peforming calculations to derive the data), + * then you can limit yourself to setting the indexes and saving any + * information you will need later. Then use the saved information in + * ${context}_row_prep() for populating data. + * + * @note + * If you need consistency between rows (like you want statistics + * for each row to be from the same time frame), you should set all + * data here. + * + */ +int +${context}_container_load(netsnmp_container *container) +{ + ${context}_rowreq_ctx *rowreq_ctx; + size_t count = 0; + + /* + * temporary storage for index values + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* + * $m2c_node_summary + */ +@ if $m2c_node_needlength == 1@ +@ eval $m2c_gi_maxlen = (126 - $node.oidlength - $m2c_gi_others)@ +@ if $m2c_node_maxlen > $m2c_gi_maxlen@ +@ eval $m2c_node_maxlen = $m2c_gi_maxlen@ + /** 128 - 1(entry) - 1(col) - $m2c_gi_others(other indexes) = $m2c_node_maxlen */ +@ end@ +@ end@ # needlength +@ include node-storage.m2i@ +@ end@ // foreach + +@if $m2c_include_examples == 1@ + + /* + * this example code is based on a data source that is a + * text file to be read and parsed. + */ + FILE *filep; + char line[MAX_LINE_SIZE]; +@end@ // examples + + DEBUGMSGTL(("verbose:${context}:${context}_container_load","called\n")); + +@if $m2c_include_examples == 1@ +$example_start + /* + * open our data file. + */ + filep = fopen("/etc/dummy.conf", "r"); + if(NULL == filep) { + return MFD_RESOURCE_UNAVAILABLE; + } + +$example_end +@end@ // example + /* + * TODO:351:M: |-> Load/update data in the $context container. + * loop over your $context data, allocate a rowreq context, + * set the index(es) [and data, optionally] and insert into + * the container. + */ + while( 1 ) { +@ if $m2c_include_examples == 0@ + /* + * check for end of data; bail out if there is no more data + */ + if( 1 ) + break; +@ else@ +$example_start + /* + * get a line (skip blank lines) + */ + do { + if (!fgets(line, sizeof(line), filep)) { + /* we're done */ + fclose(filep); + filep = NULL; + } + } while (filep && (line[0] == '\n')); + + /* + * check for end of data + */ + if(NULL == filep) + break; + + /* + * parse line into variables + */ +$example_end +@ end@ # example + + /* + * TODO:352:M: | |-> set indexes in new $context rowreq context. +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ + * data context will be set from the first param (unless NULL, + * in which case a new data context will be allocated) + * the second param will be passed, with the row context, to + * ${context}rowreq_ctx_init. +@ else@ + * data context will be set from the param (unless NULL, + * in which case a new data context will be allocated) +@ @end@ +@ end@ + */ + rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if (NULL == rowreq_ctx) { + snmp_log(LOG_ERR, "memory allocation failed\n"); + return MFD_RESOURCE_UNAVAILABLE; + } + if(MFD_SUCCESS != ${context}_indexes_set(rowreq_ctx +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + , $node, ${node}_len +@ else@ + , $node +@ end@ +@ end@ # foreach index + )) { + snmp_log(LOG_ERR,"error setting index while loading " + "${context} data.\n"); + ${context}_release_rowreq_ctx(rowreq_ctx); + continue; + } + + /* + * TODO:352:r: | |-> populate $context data context. + * Populate data context here. (optionally, delay until row prep) + */ +@if $m2c_data_transient == 0@ # persistent + /* non-TRANSIENT data: no need to copy. set pointer to data */ +@else@ + /* + * TRANSIENT or semi-TRANSIENT data: + * copy data or save any info needed to do it in row_prep. + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * setup/save data for $node + * $m2c_node_summary + */ +@ if "$m2c_data_context" eq "generated"@ +@ eval $m2c_ctx_lh = "$m2c_ctx_rh"@ +@ eval $m2c_ctx_lhs = "$m2c_ctx_rhs"@ +@ eval $m2c_ctx_rh = "$node"@ +@ eval $m2c_ctx_rhs = "${node}_len"@ +@ include generic-value-map.m2i@ + +@ end@ # data_context ! generated +@ end@ // for each +@end@ # transient + + /* + * insert into table container + */ + CONTAINER_INSERT(container, rowreq_ctx); + ++count; + } +@if $m2c_include_examples == 1@ + +$example_start + if(NULL != filep) + fclose(filep); +$example_end +@end@ # example + + DEBUGMSGT(("verbose:${context}:${context}_container_load", + "inserted %d records\n", count)); + + return MFD_SUCCESS; +} /* ${context}_container_load */ + +/** + * container clean up + * + * @param container container with all current items + * + * This optional callback is called prior to all + * item's being removed from the container. If you + * need to do any processing before that, do it here. + * + * @note + * The MFD helper will take care of releasing all the row contexts. +@ if ($m2c_data_allocate == 1) && ($m2c_data_transient == 0)@ + * If you did not pass a data context pointer when allocating + * the rowreq context, the one that was allocated will be deleted. + * If you did pass one in, it will not be deleted and that memory + * is your responsibility. +@ end@ + * + */ +void +${context}_container_free(netsnmp_container *container) +{ + DEBUGMSGTL(("verbose:${context}:${context}_container_free","called\n")); + + /* + * TODO:380:M: Free $context container data. + */ +} /* ${context}_container_free */ + +@end@ // m2c_processing_type eq 'c' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'i'@ +@ if $m2c_data_cache == 1@ +static void _container_free(netsnmp_container *container); + +/** + * @internal + */ +static int +_cache_load(netsnmp_cache *cache, void *vmagic) +{ + DEBUGMSGTL(("internal:${context}:_cache_load","called\n")); + + if((NULL == cache) || (NULL == cache->magic)) { + snmp_log(LOG_ERR, "invalid cache for ${context}_cache_load\n"); + return -1; + } + + /** should only be called for an invalid or expired cache */ + netsnmp_assert((0 == cache->valid) || (1 == cache->expired)); + + /* + * call user code + */ + return ${context}_container_load((netsnmp_container*)cache->magic); +} /* _cache_load */ + +/** + * @internal + */ +static void +_cache_free(netsnmp_cache *cache, void *magic) +{ + netsnmp_container *container; + + DEBUGMSGTL(("internal:${context}:_cache_free","called\n")); + + if((NULL == cache) || (NULL == cache->magic)) { + snmp_log(LOG_ERR, "invalid cache in ${context}_cache_free\n"); + return; + } + + container = (netsnmp_container*)cache->magic; + + _container_free(container); +} /* _cache_free */ + +@ end@ # cache +/** + * @internal + */ +static void +_container_item_free(${context}_rowreq_ctx *rowreq_ctx, void *context) +{ + DEBUGMSGTL(("internal:${context}:_container_item_free","called\n")); + + if(NULL == rowreq_ctx) + return; + + ${context}_release_rowreq_ctx(rowreq_ctx); +} /* _container_item_free */ + +/** + * @internal + */ +static void +_container_free(netsnmp_container *container) +{ + DEBUGMSGTL(("internal:${context}:_container_free","called\n")); + + if (NULL == container) { + snmp_log(LOG_ERR, "invalid container in ${context}_container_free\n"); + return; + } + + /* + * call user code + */ + ${context}_container_free(container); + + /* + * free all items. inefficient, but easy. + */ + CONTAINER_CLEAR(container, + (netsnmp_container_obj_func *)_container_item_free, + NULL); +} /* _container_free */ + +/** + * @internal + * initialize the container with functions or wrappers + */ +void +_${context}_container_init(${context}_interface_ctx *if_ctx) +{ + DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n")); + +@ if $m2c_data_cache == 1@ + /* + * cache init + */ +@ if 0@ + if_ctx->cache = + netsnmp_cache_find_by_oid(PARTNER_oid, OID_LENGTH(PARTNER_oid)); +@ else@ + if_ctx->cache = netsnmp_cache_create(30, /* timeout in seconds */ + _cache_load, _cache_free, + ${context}_oid, + ${context}_oid_size); +@ end@ // shared cache + + if(NULL == if_ctx->cache) { + snmp_log(LOG_ERR, "error creating cache for ${context}\n"); + return; + } + + if_ctx->cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET; + + ${context}_container_init(&if_ctx->container, if_ctx->cache); +@ else@ + /* + * container init + */ + ${context}_container_init(&if_ctx->container); +@ end@ data cache + if(NULL == if_ctx->container) + if_ctx->container = netsnmp_container_find("${context}:table_container"); + if(NULL == if_ctx->container) { + snmp_log(LOG_ERR,"error creating container in " + "${context}_container_init\n"); + return; + } + +@ if $m2c_data_cache == 1@ + if (NULL != if_ctx->cache) + if_ctx->cache->magic = (void*)if_ctx->container; +@ end@ +} /* _${context}_container_init */ + +/** + * @internal + * shutdown the container with functions or wrappers + */ +void +_${context}_container_shutdown(${context}_interface_ctx *if_ctx) +{ + DEBUGMSGTL(("internal:${context}:_${context}_container_shutdown","called\n")); + + ${context}_container_shutdown(if_ctx->container); + + _container_free(if_ctx->container); + +} /* _${context}_container_shutdown */ + +@end@ // m2c_processing_type eq 'i' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'r'@ +## + container summary + ------------------------ + The container data access code is for cases when you want to + store your data in the agent/sub-agent. + + ... to be continued... + + +@ if $m2c_data_cache == 1@ + cache summary + ------------------------ + The container-cached data access code is for cases when you want to + cache your data in the agent/sub-agent. + + ... to be continued... + + +@ end@ +@end@ // m2c_processing_type eq 'r' +######################################################################## +##//#################################################################### +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i new file mode 100644 index 0000000..841798a --- /dev/null +++ b/local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i @@ -0,0 +1,1198 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: mfd-access-unsorted-external-defines.m2i 17717 2009-08-04 21:59:16Z dts12 $ +######################################################################## +## +@eval $mfd_aue_wrap_param = "wrap_ctx"@ +@eval $mfd_aue_wrap_param_type = "${context}_interface_ctx *"@ +@eval $mfd_aue_wrap_param_decl = "$mfd_aue_wrap_param_type $mfd_aue_wrap_param"@ +## +@eval $mfd_aue_param = "${context}_reg"@ +@eval $mfd_aue_param_type = "${context}_registration *"@ +@eval $mfd_aue_param_decl = "$mfd_aue_param_type $mfd_aue_param"@ +@eval $mfd_aue_param_cmt = "$mfd_aue_param Pointer to a $mfd_aue_param_type" +## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 17717 $ */ +@end@ +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'h'@ +## +@if $m2c_include_examples == 1@ +$example_start +/* ********************************************************************* + * Since we have no idea how you really access your data, we'll go with + * a worst case example: a flat text file. + @ if $m2c_data_transient != 2@ + @ print Example code is for fully transient data. Either turn off@ + @ print m2c_include_examples or set m2c_data_transient to 2.@ + @ exit@ + @ end@ + */ +#define MAX_LINE_SIZE 256 +$example_end + +@end@ +/** + * loop context + * + * ToDo: + * define loop context structure + * + * Since the actual loop is in the MFD handler, a loop contex parameter + * is provided to help you keep track of where you are in between calls + * to functions that you wrote and the master MFD handler calls. The + * structure of this context is user defineable, and is defined in the + * file ${table}_data_access.h. + * + * E.G., if your data is stored in a linked list, the obvious thing you + * want to know from one function call to the next is your current + * position in the linked list. Thus the easiest context to use is a + * pointer within the linked list. For an array, the current index to + * that array would be easiest. + * + * The funtion calls are actually passed a reference to the loop + * context, to allow the loop context to be allocated memory. Here are + * some simple examples definitions for various data formats. These + * definitions are used in examples later on. + * + */ +typedef struct ${context}_loop_context_s { + /* + * temporary context used during iteration + */ + ${context}_rowreq_ctx *rowreq_ctx; +@if $m2c_include_examples == 1@ + + /* + * this example code is based on a data source that is a + * text file to be read and parsed. + */ + FILE *filep; + char line[MAX_LINE_SIZE]; +@end@ +} ${context}_loop_context; + +/* + * define a reference to the loop context + * + * NOTE: DO NOT ADD ITEMS TO THIS STRUCTURE! + */ +typedef struct ${context}_ref_loop_ctx_s { + ${context}_loop_context *loop_ctx; +} ${context}_ref_loop_ctx; + +int ${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref); +int ${context}_loop_save_position($mfd_aue_param_decl, + ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_loop_ctx *save_loop_ctx_ref, int reuse); +int ${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *ref); + +## +@end@ // m2c_processing_type eq 'h' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'i'@ +/** + * @internal + * wrapper around clean up a loop reference + */ +static int +_${context}_loop_cleanup_context( $mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx *ref) +{ + DEBUGMSGTL(("internal:${context}:_${context}_loop_cleanup_context","called\n")); + + return ${context}_loop_cleanup_context($mfd_aue_wrap_param->user_ctx, ref); +} /* _${context}_loop_cleanup_context */ + +/** + * @internal + * wrapper around save position + */ +static int +_${context}_loop_save_position( $mfd_aue_wrap_param_decl, ${context}_ref_loop_ctx *ref, + ${context}_ref_loop_ctx *ref_copy, int reuse) +{ + DEBUGMSGTL(("internal:${context}:_${context}_loop_save_position","called\n")); + + return ${context}_loop_save_position($mfd_aue_wrap_param->user_ctx, ref, + ref_copy, reuse); +} /* _${context}_loop_save_position */ + +/** + * @internal + * wrapper around user get_first to setup the index oid + */ +static int +_${context}_loop_get_first_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ + int rc; + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_first_wrapper","called\n")); + + rc = ${context}_loop_get_first($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, + rowreq_ctx_ref); + /* + * convert index to OID + */ + if(SNMPERR_SUCCESS == rc ) { + netsnmp_assert((NULL != rowreq_ctx_ref) && + (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp); + rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx, + &rowreq_ctx_ref->rowreq_ctx->tbl_idx); + netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len != + sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + } + + return rc; +} /* _${context}_loop_get_first_wrapper */ + +/** + * @internal + * wrapper around user get_next to setup the index oid + */ +static int +_${context}_loop_get_next_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ + int rc; + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_next_wrapper","called\n")); + + rc = ${context}_loop_get_next($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, + rowreq_ctx_ref); + /* + * convert index to OID + */ + if(SNMPERR_SUCCESS == rc ) { + netsnmp_assert((NULL != rowreq_ctx_ref) && + (rowreq_ctx_ref->rowreq_ctx->oid_idx.oids == rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + rowreq_ctx_ref->rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp); + rc = ${context}_index_to_oid(&rowreq_ctx_ref->rowreq_ctx->oid_idx, + &rowreq_ctx_ref->rowreq_ctx->tbl_idx); + netsnmp_assert(rowreq_ctx_ref->rowreq_ctx->oid_idx.len != + sizeof(rowreq_ctx_ref->rowreq_ctx->oid_tmp)); + } + + return rc; +} /* _${context}_loop_get_next_wrapper */ + +@if $m2c_data_transient != 0@ # +/** + * @internal + * get data wrapper to allocate context for the user + */ +static int +_${context}_loop_get_data_wrapper($mfd_aue_wrap_param_decl, + ${context}_ref_loop_ctx * loop_ctx_ref, + ${context}_ref_rowreq_ctx * rowreq_ctx_ref) +{ +// ${context}_rowreq_ctx *orig_ctx = rowreq_ctx_ref->rowreq_ctx; + + DEBUGMSGTL(("internal:${context}:_${context}_loop_get_data_wrapper","called\n")); + + return ${context}_loop_get_data($mfd_aue_wrap_param->user_ctx, loop_ctx_ref, rowreq_ctx_ref); +} /* _${context}_loop_get_data_wrapper */ + +@end@ // transient != 0 +/** + * @internal + * initialize the iterator container with functions or wrappers + */ +void +_${context}_container_init(${context}_interface_ctx *if_ctx) +{ + DEBUGMSGTL(("internal:${context}:_${context}_container_init","called\n")); + + if_ctx->container = netsnmp_container_iterator_get(/** registration */ + if_ctx, + /** compare */ + NULL, + /** get_first */ + (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_first_wrapper, + /** get_next */ + (Netsnmp_Iterator_Loop_Key*)_${context}_loop_get_next_wrapper, + /** get_data */ +@if $m2c_data_transient != 0@ # + (Netsnmp_Iterator_Loop_Data*)_${context}_loop_get_data_wrapper, +@else@ + NULL, +@end@ + /** save_pos */ + (Netsnmp_Iterator_Ctx_Dup*)_${context}_loop_save_position, + /** init_context */ + (Netsnmp_Iterator_Ctx*)NULL, + /** cleanup_context */ + (Netsnmp_Iterator_Ctx*)_${context}_loop_cleanup_context, + /** free_user_ctx */ + NULL, + /** sorted */ + 0); +} /* _${context}_container_init */ + +## +@end@ // m2c_processing_type eq 'i' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'c'@ +/** + * unsorted-external overview + * + * The unsorted external data access code works by calling a few simple + * functions to get the index value for each row. Once the agent determines + * which row is needed to process an incoming request, another function + * is called to retrieve the data for that row. + * + * A simplified version of the pseudo-code looks like this: + * + * ${context}_loop_get_first(loop,data) + * while( no_error ) { + * if( best_match(data, key) + * ${context}_loop_save_position(loop,pos); + * ${context}_loop_get_next(loop,data) + * } + * ${context}_loop_get_data(pos,data) + * ${context}_loop_cleanup_context(loop) + */ + +/*********************************************************************** + * + * ITERATION + * + ***********************************************************************/ + +/** + * get the first data index + * + * Summary + * ------- + * This function is called to initialize the iterator loop context for a + * new iteration loop and return the index(es) for the first + * ${context}_data in the data set. + * + * Note that during the loop, the only important thing is the indexes. + * If access to your data is cheap/fast (e.g. you have a pointer to a + * structure in memory), it would make sense to update the data here. + * If, however, the accessing the data invovles more work (e.g. parsing + * some other existing data, or peforming calculations to derive the data), + * then you should limit yourself to setting the indexes. Extracting the + * can be put off until the desired row is found. See the notes on + * ${context}_loop_get_data(). + * + * Note that this function does not correspond to a SNMP GET pdu, and + * you should return data items in whatever order they are already in. + * (In fact, if your data is already ordered in the same order as the + * SNMP indexes, you shouldn't be using the unsorted-access code). + * + * This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + * values for the raw data (rowreq_ctx_ref->rowreq_ctx->data). + * + * More Details + * ------------ + * If there is currently no data available, return MFD_END_OF_DATA. + * Otherwise, you should set rowreq_ctx_ref->rowreq_ctx and its indexes. + * + * rowreq_ctx_ref->rowreq_ctx will be NULL. You should allocate a new context + * for this loop. [Alternatively, you could allocate one in + * ${context}_loop_init_context, save it in your + * ${context}_ref_loop_ctx, and use it here.] + * + * Once you have your context pointer, you should set the index (or indexes) + * in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the appropriate value for this row. [If you + * use your loop_ctx_ref cleverly, you might be able to put this work in + * ${context}_loop_get_next, and simply call that function.] + * + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * @param rowreq_ctx_ref Pointer to a context reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_END_OF_DATA : no data available + * @retval MFD_ERROR : error. + */ +int +${context}_loop_get_first( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_first","called\n")); + + netsnmp_assert(rowreq_ctx_ref); + netsnmp_assert(loop_ctx_ref); + + /* + * allocate memory for new structure + */ + loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + if(NULL == loop_ctx_ref->loop_ctx) + return MFD_ERROR; + + /* + * allocate a temporary context to use during iteration + */ +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ +@ @end@ +@ end@ + loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) { + SNMP_FREE(loop_ctx_ref->loop_ctx); + return MFD_RESOURCE_UNAVAILABLE; + } + + /* + * ToDo: + * set up loop context + */ +@if $m2c_include_examples == 1@ +$example_start + /* + * open our data file. + */ + loop_ctx_ref->loop_ctx->filep = fopen("/etc/dummy.conf", "r"); + if(NULL == loop_ctx_ref->loop_ctx->filep) { + return MFD_RESOURCE_UNAVAILABLE; + } + +$example_end +@end@ + +@ifconf ${table}_update_idx.m2i@ +@ include ${table}_update_idx.m2i@ +@else@ +@ if $m2c_include_examples == 1@ +$example_start + /* + * in this example, after opening the file, get next does the same thing + * as get first, we let's just call get next... + */ + return ${context}_loop_get_next($mfd_aue_param, loop_ctx_ref, rowreq_ctx_ref); +$example_end +@ else@ + /* + * we just need the index for now. Reuse the one in the loop context's + * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + + /* + * ToDo: + * set local vars for index from loop_ctx_ref->loop_ctx + * this can be done in one of two ways: + */ + + /* + * 1) individually + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node +@ if $m2c_node_needlength == 1@ + * and rowreq_ctx_ref->tbl_idx->${node}_len +@ end@ + */ +@ end@ #foreach + + /* + * OR + */ + + /* + * 2) by calling ${context}_indexes_set() + * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx, +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + * ${node}_ptr, ${node}_len +@ else@ + * $node +@ end@ +@ end@ # foreach index + * ); + */ +@ end@ # example +@end@ #ifconf + + return MFD_SUCCESS; +} /* ${context}_loop_get_first */ + +/** + * get the next data index + * + * Summary + * ------- + * This function returns the next data item in the data set. The same + * caveat applies here as did above. The indexes are the important parts + * during loop processing. + * + * Note that this function does not correspond to a SNMP GET-NEXT pdu, and + * you should return data items in whatever order they are already in. + * (In fact, if your data is already ordered in the same order as the + * SNMP indexes, you shouldn't be using the unsorted-access code). + * + * More Details + * ------------ + * rowreq_ctx_ref->rowreq_ctx will have been set in ${context}_loop_get_first. + * + * If there is currently no data available, return MFD_END_OF_DATA. + * Otherwise, you should set the indexes in rowreq_ctx_ref->rowreq_ctx->tbl_idx. + * + * You should set the index (or indexes) in rowreq_ctx_ref->rowreq_ctx->tbl_idx to the + * appropriate value for this row. + * + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * @param rowreq_ctx_ref Pointer to a context reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_END_OF_DATA : no more data available + * @retval MFD_ERROR : error. + */ +int +${context}_loop_get_next( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_next","called\n")); + + netsnmp_assert(loop_ctx_ref && loop_ctx_ref->loop_ctx); + netsnmp_assert(rowreq_ctx_ref); + + /* + * we just need the index for now. Reuse the one in the loop context's + * temporary row request context. (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + +@ if $m2c_include_examples == 1@ +$example_start + /* + * get a line (skip blank lines) + */ + do { + if (!fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->filep)) { + /* we're done */ + fclose(loop_ctx_ref->loop_ctx->filep); + loop_ctx_ref->loop_ctx->filep = NULL; + } + } while (loop_ctx_ref->loop_ctx->filep && (loop_ctx_ref->loop_ctx->line[0] == '\n')); + + /* + * check for end of data + */ + if(NULL == loop_ctx_ref->loop_ctx->filep) + return MFD_END_OF_DATA; + + /* + * ToDo: + * set local vars for index from loop_ctx_ref->loop_ctx + * this can be done in one of two ways: + */ + + /* + * 1) individually + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->rowreq_ctx->tbl_idx->$node +@ if $m2c_node_needlength == 1@ + * and rowreq_ctx_ref->tbl_idx->${node}_len +@ end@ + */ +@ end@ #foreach + + /* + * OR + */ + + /* + * 2) by calling ${context}_indexes_set() + * ${context}_indexes_set(rowreq_ctx_ref->tbl_idx, +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_needlength == 1@ + * ${node}_ptr, ${node}_len +@ else@ + * $node +@ end@ +@ end@ # foreach index + * ); + */ +$example_end +@ end@ # example + + return MFD_SUCCESS; +} /* ${context}_loop_get_next */ + +/** + * duplicate the current loop reference + * + * Summary + * ------- + * During loop iteration, the iterator keeps track of the row that + * is the current best match. This function is called when the + * current row is a better match than any previous row. + * + * You should save any information you need to be able to locate this row + * again from the current loop context to a new loop context. + * + * At the end of the loop, when the best match has been found, the saved + * loop context will be used to get the data for the row by calling + * ${context}_loop_get_data(). +@if $m2c_data_transient != 0@ # persistent + * + * Since your data is transient, you need to make a copy of it before + * the iterator moves on to the next row. +@end@ + * +@if $m2c_data_transient != 0@ # persistent + * More Details + * ------------ +@ if $m2c_data_transient == 1@ # short term + * Since your data is semi-TRANSIENT data, you could just keep a pointer + * to the data in the loop reference. The data should then be copied in + * ${context}_loop_get_data(). +@ else@ # $m2c_data_transient == 2@ # copy immediately + * One idea would be to copy it space allocated in the loop reference + * structure. Another would be to simply have a pointer in the loop + * reference structure, and allocate memory here. + * +@ end@ +@end@ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Reference to current loop context. + * @param save_loop_ctx_ref Reference to a loop context for saving the current + * position. If reuse is not set or + * save_loop_ctx_ref->loop_ctx is NULL, allocate + * a new one. If reuse is set, you may reuse the existing + * loop_ctx. + * @param reuse Indicates if an existing save_loop_ctx_ref->loop_ctx + * may be reused. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : error. + */ +int +${context}_loop_save_position($mfd_aue_param_decl, + ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_loop_ctx *save_loop_ctx_ref, + int reuse) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_save_position","called\n")); + + netsnmp_assert(loop_ctx_ref && save_loop_ctx_ref); + + /* + * ToDo: + * 1) allocate new loop context, unless you can reuse a previous pointer. + * 2) save information for the position of loop_ctx_ref in save_loop_ctx_ref. + */ + if((0 == reuse) || (NULL == save_loop_ctx_ref->loop_ctx)) + save_loop_ctx_ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + if(NULL == save_loop_ctx_ref->loop_ctx) { + snmp_log(LOG_ERR, "could not allocate memory\n"); + return MFD_ERROR; + } + + /* + * if you can reuse a previously saved contex, just swap + * it out with the loop iterator + */ + if(reuse && save_loop_ctx_ref->loop_ctx->rowreq_ctx) { + ${context}_rowreq_ctx * tmp_rowreq_ctx = save_loop_ctx_ref->loop_ctx->rowreq_ctx; + save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + loop_ctx_ref->loop_ctx->rowreq_ctx = tmp_rowreq_ctx; + } + else { + /* + * take the current pointer + */ + save_loop_ctx_ref->loop_ctx->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + + /* + * allocate a new context to replace the one you just took. + */ +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ +@ @end@ +@ end@ + loop_ctx_ref->loop_ctx->rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if(NULL == loop_ctx_ref->loop_ctx->rowreq_ctx) { + SNMP_FREE(loop_ctx_ref->loop_ctx); + return MFD_ERROR; + } + } + +@if $m2c_data_transient == 0@ # persistent + /** non-TRANSIENT data: no need to copy */ +@elsif $m2c_data_transient == 1@ # short term + /** semi-TRANSIENT data: will copy data when index found */ + /** only need to copy pertinent data from loop context */ +@elsif $m2c_data_transient == 2@ # copy immediately + /* + * TRANSIENT data: copy all the data. + */ +@end@ +@if $m2c_include_examples == 1@ +$example_start +@ if $m2c_data_transient == 1@ # short term + /** save line to do that */ + memcpy(save_loop_ctx_ref->loop_ctx->line, loop_ctx_ref->loop_ctx->line, + sizeof(loop_ctx_ref->loop_ctx->line)); +@ elsif $m2c_data_transient == 2@ # copy immediately +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * ToDo: + * set rowreq_ctx_ref->${m2c_data_item}$node + * from the loop context + */ +@ end@ +@ end@ +$example_end +@end@ # example + + return MFD_SUCCESS; +} /* ${context}_loop_save_position */ + +@if $m2c_data_transient != 0@ # semi-transient +/** + * set ${context}_data from a data context + * + * Summary + * ------- + * At the end of the loop, when the best match has been found, the saved + * loop context will be used to get the data for the row by calling + * ${context}_loop_get_data(). + * + * You should return a fully populated row request context in + * rowreq_ctx_ref->rowreq_ctx. + * + * More Details + * ------------ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref pointer to your loop reference. + * @param rowreq_ctx_ref pointer to a context reference. + */ +int +${context}_loop_get_data( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref, + ${context}_ref_rowreq_ctx *rowreq_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_get_data","called\n")); + + netsnmp_assert((NULL != loop_ctx_ref) && (NULL != loop_ctx_ref->loop_ctx)); + netsnmp_assert(NULL != rowreq_ctx_ref); + netsnmp_assert(NULL != rowreq_ctx_ref->rowreq_ctx); + + /* + * take temporary row request context from loop context + */ + rowreq_ctx_ref->rowreq_ctx = loop_ctx_ref->loop_ctx->rowreq_ctx; + loop_ctx_ref->loop_ctx->rowreq_ctx = NULL; + + /* + * copy data to the data context (rowreq_ctx_ref->${m2c_data_item}) +@ if $m2c_include_examples == 1@ + * in loop_save_position, we saved line to do that +@ end@ + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + /* + * $m2c_node_summary + */ +@ eval $m2c_ctx_lh = "rowreq_ctx_ref->$m2c_ctx_rh"@ +@ eval $m2c_ctx_lhs = "rowreq_ctx_ref->$m2c_ctx_rhs"@ +@ eval $m2c_ctx_rh = "loop_ctx_ref->loop_ctx->$node"@ +@ eval $m2c_ctx_rhs = "loop_ctx_ref->loop_ctx->${node}_len"@ +@ include generic-value-map.m2i@ + +@ end@ + + return MFD_SUCCESS; +} /* ${context}_loop_get_data */ + +@end@ // if $m2c_data_transient != 0 + +/** + * clean up a loop reference + * + * Summary + * ------- + * This function will be called once the loop iteration has completed + * to release any memory or resources allocated for the loop context. + * + * More Details + * ------------ + * @param $mfd_aue_param_cmt + * @param loop_ctx_ref Pointer to your loop reference. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : error. + */ +int +${context}_loop_cleanup_context( $mfd_aue_param_decl, ${context}_ref_loop_ctx *loop_ctx_ref) +{ + DEBUGMSGTL(("verbose:${context}:${context}_loop_cleanup_context","called\n")); + + netsnmp_assert(loop_ctx_ref); + + if(!loop_ctx_ref->loop_ctx) + return MFD_ERROR; + + /* + * release the row request context, if it wasn't taken + */ + if(loop_ctx_ref->loop_ctx->rowreq_ctx) + ${context}_release_rowreq_ctx(loop_ctx_ref->loop_ctx->rowreq_ctx); + + /* + * ToDo: + * release resources + */ +@if $m2c_include_examples == 1@ +$example_start + /* + * close file + */ + if(loop_ctx_ref->loop_ctx->filep) + fclose(loop_ctx_ref->loop_ctx->filep); +$example_end + +@end@ + /* + * free loop context + */ + free(loop_ctx_ref->loop_ctx); + + return MFD_SUCCESS; +} /* ${context}_loop_cleanup_context */ + +@end@ // m2c_processing_type eq 'c' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'r'@ +## + unsorted-external summary + ------------------------- + The unsorted-external data access code is for cases when you data is + kept UNSORTED and EXTERNAL to the agent/sub-agent. + + This code was generated based on the following assumptions or settings: + + 1) The raw data for this table is UNSORTED. + @if $mfd_readme_verbose != 0@ + + UNSORTED data is data that is not kept in the same order as the way + SNMP expects the index(es) for the table to be kept. [It could very + well be sorted in some other order, but for the purpose of SNMP, the + order is incorrect.] If you're not sure if your data is sorted + in an SNMP compliant way, its likely not. + + Because the raw data is unsorted, to satisfy a particular request, the + entire data set must be examined to find the apropriate index. This + is done via a simple loop. The MFD handler will call your get_first + function and the call the get_next function repeatedly, until it + returns SNMPERR_NO_VARS. + @end@ + + 2) The raw data for this table is EXTERNAL. + @if $mfd_readme_verbose != 0@ + + EXTERNAL data is data that is owned by some other process, + device, file or mechanism. The agent must use some interface to + read or modify the data. An external process may modify the data + without the agent's knowledge. For example, the Net-SNMP agent + implements the interface table (ifTable), which reports on + network interfaces. The host operating system owns this data, and + Net-SNMP must use system calls to report or manipulate the data. + Examples of external data include data stored in kernel space, in + files, in another non-memory shared process, and data stored in + devices. + @end@ + + 3) The raw data for this table is TRANSIENT. + @if $mfd_readme_verbose != 0@ + + TRANSIENT data is data that may be overwritten by another funtion + or process. For example, many OS functions return data in a + static buffer that will be reused the next time the function is + called. Because of this, we will assume that you will copy the + raw data retrieved from these other sources to a generated + structure for use within the Net-SNMP agent. (Don't worry, we'll + help you) + @end@ + + +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + The unsorted external data access code works by calling a few simple + functions to get the index value for each row. Once the agent determines + which row is needed to process an incoming request, another function + is called to retrieve the data for that row. + + A simplified version of the pseudo-code looks like this: + + ${context}_loop_init_context(loop) + ${context}_loop_get_first(loop,data) + while( no_error ) { + if( best_match(data, key) + ${context}_loop_save_position(loop,pos); + ${context}_loop_get_next(loop,data) + } + ${context}_loop_get_data(pos,data) + ${context}_loop_cleanup_context(loop) +## +## end sync +## + + We will talk about each individual step below. + + +######################################################################## + Defining context for the loop + ----------------------------- + ToDo : typedef ${context}_loop_context + WHERE: ${table}_data_access.h + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + Since the actual loop is in the MFD handler, a loop contex parameter + is provided to help you keep track of where you are in between calls + to functions that you wrote and the master MFD handler calls. The + structure of this context is user defineable, and is defined in the + file ${table}_data_access.h. + + E.G., if your data is stored in a linked list, the obvious thing you + want to know from one function call to the next is your current + position in the linked list. Thus the easiest context to use is a + pointer within the linked list. For an array, the current index to + that array would be easiest. + + The funtion calls are actually passed a reference to the loop + context, to allow the loop context to be allocated memory. Here are + some simple examples definitions for various data formats. These + definitions are used in examples later on. +## +## end sync +## + + Linked list + ----------- + typedef list_node ${context}_loop_context; + + Array + ----- + typedef integer ${context}_loop_context; + + File + ---- + typedef struct ${context}_loop_context_s { + char * file_name; + FILE * f; + char line[128]; + } ${context}_loop_context; + + @end@ + +######################################################################## + Initialization + -------------- + ToDo : Initialization + FUNC : ${context}_loop_init_data + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ + The ${context}_loop_init_data function will be called during startup to + allow for any initialization needed for the data access routines. + + @end@ + +######################################################################## + Preparing for the loop + ---------------------- + ToDo : initialize loop context + FUNC : ${context}_loop_init_context + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function will be called before the start of a new itertion over + the data. The loop context that is initialized here will be passed to + ${context}_loop_get_first and ${context}_loop_get_next. + + Set the loop context variable ref->loop_ctx so that the iteration + functions (get_first and get_next) can locate the apropriate data + context. +## +## end sync +## + + The primary purpose of the loop_init_context call is to initialize + the loop context data (ref). Here are some simple examples, based on the + earlier example loop contexts. + + Linked list + ----------- + ref->loop_ctx = my_table_head_ptr; + + Array + ----- + /* instead of actually allocating memory, just use the pointer */ + /* as an integer */ + (integer)(ref->loop_ctx) = 0; + + File + ---- + ref->loop_ctx = SNMP_MALLOC_TYPEDEF(${context}_loop_context); + /* error checking here */ + ref->loop_ctx->file_name = (char*) reg->mfd_user_ctx; + ref->loop_ctx->f = fopen( ref->loop_ctx->file_name, "r+" ); + + @end@ + +######################################################################## + The Loop + -------- + ToDo : return raw data + FUNC : ${context}_loop_get_first + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function is called to return set the index(es) for the first + ${context}_data in the data set. + + Note that during the loop, the only important thing is the indexes. + If access to your data is cheap/fast (e.g. you have a pointer to a + structure in memory), it would make sense to update the data here. + If, however, the accessing the data invovles more work (e.g. parsing + some other existing data, or peforming calculations to derive the data), + then you should limit yourslef to setting the indexes. Extracting the + can be put off until the desired row is found See the notes on + ${context}_loop_get_data(). + + Note that this function does not correspond to a SNMP GET pdu, and + you should return data items in whatever order they are already in. + (In fact, if your data is already ordered in the same order as the + SNMP indexes, you shouldn't be using the unsorted-access code). + + This function should update the table index (rowreq_ctx_ref->rowreq_ctx->tbl_idx) + values for the raw data (rowreq_ctx_ref->rowreq_ctx->data). +## +## end sync +## + + Linked list + ----------- + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx; + + Array + ----- + /* assuming registration has array of pointers */ + rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)]; + + File + ---- + fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->f); + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line; + + @end@ + + ToDo : return raw data + FUNC : ${context}_loop_get_next + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function returns the next data item in the data set. The same + caveat applies here as did above. The indexes are the important parts + during loop processing. + + Note that this function does not correspond to a SNMP GET-NEXT pdu, and + you should return data items in whatever order they are already in. + (In fact, if your data is already ordered in the same order as the + SNMP indexes, you shouldn't be using the unsorted-access code). +## +## end sync +## + + Linked list + ----------- + loop_ctx_ref->loop_ctx = loop_ctx_ref->loop_ctx->next; + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx; + + Array + ----- + ++((integer)(ref->loop_ctx)); + /* assuming registration has array of pointers */ + rowreq_ctx_ref->rowreq_ctx->data = reg->mfd_user_ctx[(integer)(ref->loop_ctx)]; + + File + ---- + fgets(loop_ctx_ref->loop_ctx->line, sizeof(loop_ctx_ref->loop_ctx->line), + loop_ctx_ref->loop_ctx->f); + rowreq_ctx_ref->rowreq_ctx->data = loop_ctx_ref->loop_ctx->line; + + @end@ + +######################################################################## + Updating the Index + ------------------ + ToDo : update index for the raw data + FUNC : ${context}_indexes_set + WHERE: ${table}_data_access.c + + This is a convenience function for setting the index context from + the native C data. Where necessary, value mapping should be done. + + @if $mfd_readme_verbose == 1@ + This function should update the table index values (found in + tbl_idx) for the given raw data. + + @end@ + +######################################################################## + Saving a position in the loop + ----------------------------- + ToDo : Saving a position in the loop + FUNC : ${context}_loop_save_position + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + During loop iteration, the iterator keeps track of the row that + is the current best match. This function is called when the + current row is a better match than any previous row. + + You should save any information you need to be able to locate this row + again from the current loop context to a new loop context. + + At the end of the loop, when the best match has been found, the saved + loop context will be used to get the data for the row by calling + ${context}_loop_get_data(). +@if $m2c_data_transient != 0@ # persistent + + Since your data is transient, you need to make a copy of it before + the iterator moves on to the next row. +@end@ +## +## end sync +## + + @end@ + +######################################################################## + Returning Data For an Index + --------------------------- + ToDo : copy transient raw data to generated structure + FUNC : ${context}_loop_get_data + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + At the end of the loop, when the best match has been found, the saved + loop context will be used to get the data for the row by calling + ${context}_loop_get_data(). +## +## end sync +## + + @end@ + +######################################################################## + Cleaning up after the loop + -------------------------- + ToDo : release any allocated memory + FUNC : ${context}_loop_cleanup_context + WHERE: ${table}_data_access.c + + @if $mfd_readme_verbose != 0@ +## +## this should be syncronized with master version of comments in +## mfd-access-unsorted-external-body.m2i You should be able to copy +## the comments here and replace " * " with " ". +## + This function will be called once the loop iteration has completed + to release any memory allocated for loop reference. +## +## end sync +## + The purpose of the loop_cleanup_context call is to release any memory + allocated for the loop context data. Here are some simple examples, based + on the earlier example loop contexts. + + Linked list + ----------- + /* nothing to do */ + + Array + ----- + /* nothing to do */ + + File + ---- + free(ref->loop_ctx); + + @end@ + +## +@end@ // m2c_processing_type eq 'r +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 17717 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-data-access.m2c b/local/mib2c-conf.d/mfd-data-access.m2c new file mode 100644 index 0000000..78aad57 --- /dev/null +++ b/local/mib2c-conf.d/mfd-data-access.m2c @@ -0,0 +1,331 @@ +##//######################################################### -*- c -*- +##//generic include for XXX. Do not use directly. +## +##//$Id: mfd-data-access.m2c 14170 2006-01-26 17:02:48Z dts12 $ +##//#################################################################### +##//#################################################################### +## +## lower conf files get confused with multiple processing types, so +## set single options +@eval $mfd_data_access_processing_type = "$m2c_processing_type"@ +@eval $m2c_processing_type = 'h'@ +@open ${name}_data_access.h@ +@eval $hack = "Id"@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 14170 $ of $RCSfile$ + * + * $$hack:$ + */ +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +@eval $m2c_save = "$name"@ +@eval $name = "${name}_DATA_ACCESS"@ +@include generic-header-top.m2i@ +@eval $name = "$m2c_save"@ + +/* ********************************************************************* + * function declarations + */ + +/* ********************************************************************* + * Table declarations + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ + +##@ eval $m2c_tmp=""@ +##@ foreach $node index@ +##@ include m2c_setup_node.m2i@ +##@ eval $m2c_tmp="$m2c_tmp, $m2c_node_param_val"@ +##@ end@ // for each index + + int ${context}_init_data(${context}_registration * ${context}_reg); + +@ include mfd-access-${m2c_table_access}-defines.m2i@ + int ${context}_row_prep( ${context}_rowreq_ctx *rowreq_ctx); + +@ if ($m2c_table_row_creation == 1) || ($m2c_table_persistent == 1)@ +int ${context}_validate_index( ${context}_registration * ${context}_reg, + ${context}_rowreq_ctx *rowreq_ctx); +@ foreach $node externalindex@ +@ include m2c_setup_node.m2i@ + int ${context}_${node}_check_index( ${context}_rowreq_ctx *rowreq_ctx ); /* external */ +@ end@ # foreach externalindex +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ +int ${node}_check_index( ${context}_rowreq_ctx *rowreq_ctx ); /* internal */ +@ end@ # foreach internalindex +@ end@ # row creation/persistent +@end@ + +@eval $m2c_save = "$name"@ +@eval $name = "${name}_DATA_ACCESS"@ +@include generic-header-bottom.m2i@ +@eval $name = "$m2c_save"@ +##//################################################################## +##//Do the .c file +##//################################################################## +@eval $m2c_processing_type = 'c'@ +@open ${name}_data_access.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 14170 $ of $RCSfile$ + * + * $$hack:$ + */ +@include generic-source-includes.m2i@ + +#include "${name}_data_access.h" + +/** @ingroup interface + * @addtogroup data_access data_access: Routines to access data + * + * These routines are used to locate the data used to satisfy + * requests. + * + * @{ + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ + +/** + * initialization for ${context} data access + * + * This function is called during startup to allow you to + * allocate any resources you need for the data table. + * + * @param ${context}_reg + * Pointer to ${context}_registration + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : unrecoverable error. + */ +int +${context}_init_data(${context}_registration * ${context}_reg) +{ + DEBUGMSGTL(("verbose:${context}:${context}_init_data","called\n")); + + /* + * TODO:303:o: Initialize $context data. + */ +@ifconf ${table}_init_data.m2i@ +@ include ${table}_init_data.m2i@ +@else@ +@ if $m2c_include_examples == 1@ +$example_start + /* + * if you are the sole writer for the file, you could + * open it here. However, as stated earlier, we are assuming + * the worst case, which in this case means that the file is + * written to by someone else, and might not even exist when + * we start up. So we can't do anything here. + */ +$example_end +@ end@ + + return MFD_SUCCESS; +@end@ #ifconf +} /* ${context}_init_data */ + +@ include mfd-access-${m2c_table_access}-defines.m2i@ +/** + * prepare row for processing. + * + * When the agent has located the row for a request, this function is + * called to prepare the row for processing. If you fully populated + * the data context during the index setup phase, you may not need to + * do anything. + * + * @param rowreq_ctx pointer to a context. + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : other error. + */ +int +${context}_row_prep( ${context}_rowreq_ctx *rowreq_ctx) +{ + DEBUGMSGTL(("verbose:${context}:${context}_row_prep","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:390:o: Prepare row for request. + * If populating row data was delayed, this is the place to + * fill in the row for this request. + */ + + return MFD_SUCCESS; +} /* ${context}_row_prep */ + +##//#################################################################### +@ if ($m2c_table_row_creation == 1) || ($m2c_table_persistent == 1)@ +/* + * TODO:420:r: Implement $context index validation. + */ +@ foreach $node externalindex@ +@ include m2c_setup_node.m2i@ +@ if $m2c_report_progress == 1@ +@ print | | +-> Processing index $node@ +@ end@ +@ include details-node.m2i@ +/** + * check validity of ${node} external index portion + * + * NOTE: this is not the place to do any checks for the sanity + * of multiple indexes. Those types of checks should be done in the + * ${context}_validate_index() function. + * + * @retval MFD_SUCCESS : the incoming value is legal + * @retval MFD_ERROR : the incoming value is NOT legal + */ +int +${context}_${node}_check_index( ${context}_rowreq_ctx *rowreq_ctx ) +{ + DEBUGMSGTL(("verbose:${context}:${context}_${node}_check_index","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:424:M: |-> Check $context external index $node. + * check that index value in the table context (rowreq_ctx) + * for the external index $node is legal. + */ + + return MFD_SUCCESS; /* external index $node ok */ +} /* ${context}_${node}_check_index */ + +@ end@ # foreach externalindex +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ +@ if $m2c_report_progress == 1@ +@ print | | +-> Processing index $node@ +@ end@ +@ include details-node.m2i@ +/** + * check validity of ${node} index portion + * + * @retval MFD_SUCCESS : the incoming value is legal + * @retval MFD_ERROR : the incoming value is NOT legal + * + * @note this is not the place to do any checks for the sanity + * of multiple indexes. Those types of checks should be done in the + * ${context}_validate_index() function. + * + * @note Also keep in mind that if the index refers to a row in this or + * some other table, you can't check for that row here to make + * decisions, since that row might not be created yet, but may + * be created during the processing this request. If you have + * such checks, they should be done in the check_dependencies + * function, because any new/deleted/changed rows should be + * available then. + * + * The following checks have already been done for you: +@if $node.enums == 1@ + * The value is one of $m2c_evals +@elsif $node.ranges == 1@ +@ if ("$node.decl" eq "long") || ("$node.decl" eq "u_long")@ +@ eval $m2c_tmp_ns = "value"@ +@ else@ +@ eval $m2c_tmp_ns = "length"@ +@ end@ + * The $m2c_tmp_ns is in (one of) the range set(s): $m2c_evals +@end@ + * + * If there a no other checks you need to do, simply return MFD_SUCCESS. + */ +int +${node}_check_index( ${context}_rowreq_ctx *rowreq_ctx ) +{ + DEBUGMSGTL(("verbose:${context}:${node}_check_index","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:426:M: |-> Check $context index $node. + * check that index value in the table context is legal. + * (rowreq_ctx->tbl_index.$node) + */ + + return MFD_SUCCESS; /* $node index ok */ +} /* ${node}_check_index */ + +@ end@ # foreach internalindex +/** + * verify specified index is valid. + * + * This check is independent of whether or not the values specified for + * the columns of the new row are valid. Column values and row consistency + * will be checked later. At this point, only the index values should be + * checked. + * + * All of the individual index validation functions have been called, so this + * is the place to make sure they are valid as a whole when combined. If + * you only have one index, then you probably don't need to do anything else + * here. + * + * @note Keep in mind that if the indexes refer to a row in this or + * some other table, you can't check for that row here to make + * decisions, since that row might not be created yet, but may + * be created during the processing this request. If you have + * such checks, they should be done in the check_dependencies + * function, because any new/deleted/changed rows should be + * available then. + * + * + * @param ${context}_reg + * Pointer to the user registration data + * @param ${context}_rowreq_ctx + * Pointer to the users context. + * @retval MFD_SUCCESS : success + * @retval MFD_CANNOT_CREATE_NOW : index not valid right now + * @retval MFD_CANNOT_CREATE_EVER : index never valid + */ +int +${context}_validate_index( ${context}_registration * ${context}_reg, + ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("verbose:${context}:${context}_validate_index","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:430:M: |-> Validate potential $context index. + */ + if(1) { + snmp_log(LOG_WARNING,"invalid index for a new row in the " + "${context} table.\n"); + /* + * determine failure type. + * + * If the index could not ever be created, return MFD_NOT_EVER + * If the index can not be created under the present circumstances + * (even though it could be created under other circumstances), + * return MFD_NOT_NOW. + */ + if(0) { + return MFD_CANNOT_CREATE_EVER; + } + else { + return MFD_CANNOT_CREATE_NOW; + } + } + + return rc; +} /* ${context}_validate_index */ + +@ end@ # persistent/row creation +@end@ +## +/** @} */ +##//#################################################################### +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +@eval $m2c_processing_type = "$mfd_data_access_processing_type"@ diff --git a/local/mib2c-conf.d/mfd-data-get.m2c b/local/mib2c-conf.d/mfd-data-get.m2c new file mode 100644 index 0000000..7fa67f2 --- /dev/null +++ b/local/mib2c-conf.d/mfd-data-get.m2c @@ -0,0 +1,168 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: mfd-data-get.m2c 12088 2005-04-18 21:58:42Z rstory $ +######################################################################## +######################################################################## +## lower conf files get confused with multiple processing types, so +## set single options +@eval $mfd_data_get_processing_type_save = "$m2c_processing_type"@ +@if "$mfd_processing_types" =~ /h/@ +@eval $m2c_processing_type = 'h'@ +@if $m2c_create_fewer_files != 1@ +@ open ${name}_data_get.h@ +@ eval $hack = "Id"@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 12088 $ of $RCSfile$ + * + * $$hack:$ + * + * @file ${name}_data_get.h + * + * @addtogroup get + * + * Prototypes for get functions + * + * @{ + */ +@ eval $m2c_tmp = "$name"@ +@ eval $name = "${name}_DATA_GET"@ +@ include generic-header-top.m2i@ +@ eval $name = "$m2c_tmp"@ +@end@ // m2c_create_fewer_files +@if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 12088 $ */ +@end@ +######################################################################## +## +/* ********************************************************************* + * GET function declarations + */ + +/* ********************************************************************* + * GET Table declarations + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ + /* + * indexes + */ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_skip_mapping != 1@ + int ${node}_map($m2c_node_map_param); +@ end@ # // skip mapping +@ end@ # index + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_skip_mapping != 1@ + int ${node}_map($m2c_node_map_param); +@ end@ # // skip mapping + int ${node}_get( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_ref ); +@ end@ // nonindex + +@ include generic-table-indexes-set.m2i@ + +@end@ // table + +@if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 12088 $ */ +@end@ +@if $m2c_create_fewer_files != 1@ +@ eval $m2c_tmp = "$name"@ +@ eval $name = "${name}_DATA_GET"@ +@ include generic-header-bottom.m2i@ +@ eval $name = "$m2c_tmp"@ +/** @} */ +@end@ // m2c_create_fewer_files +###################################################################### +@end@ // $mfd_processing_types =~ /h/ +###################################################################### +###################################################################### +###################################################################### +@if "$mfd_processing_types" =~ /c/@ +@eval $m2c_processing_type = 'c'@ +@if $m2c_create_fewer_files != 1@ +@open ${name}_data_get.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 12088 $ of $RCSfile$ + * + * $$hack:$ + */ +@include generic-source-includes.m2i@ + +/** @defgroup data_get data_get: Routines to get data + * + * TODO:230:M: Implement $context get routines. + * TODO:240:M: Implement $context mapping routines (if any). + * + * These routine are used to get the value for individual objects. The + * row context is passed, along with a pointer to the memory where the + * value should be copied. + * + * @{ + */ +@end@ // m2c_create_fewer_files +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12088 $ */ +@end@ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ + +/* --------------------------------------------------------------------- + * TODO:200:r: Implement $context data context functions. + */ +@ if (($m2c_data_allocate == 1) || ($m2c_undo_embed == 0)) && ("$m2c_data_context" ne "generated")@ +@ include generic-data-allocate.m2i@ +@ end@ + +## +## do nodes +## +##// internal only? how to know how to map external? +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if $m2c_node_skip_mapping != 0@ +@ next@ +@ end@ +@ include details-node.m2i@ +@ if $m2c_report_progress == 1@ +@ print | | +-> Processing index $node@ +@ end@ +@ include generic-value-map-func.m2i@ +@ end@ # foreach column + +@ include generic-table-indexes-set.m2i@ + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ include details-node.m2i@ +@ if $node.noaccess == 1@ +@ next@ # skip to next column +@ end@ +@ if $m2c_report_progress == 1@ +@ print | | +-> Processing nonindex $node@ +@ end@ +@ if $m2c_node_skip_mapping == 0@ +@ include generic-value-map-func.m2i@ +@ end@ +@ include node-get.m2i@ +@ end@ # foreach column + +@end@ # foreach table + +## +/** @} */ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12088 $ */ +@end@ +######################################################################## +@end@ // $mfd_processing_types =~ /c/ +## restore original processing types +@eval $m2c_processing_type = "$mfd_data_get_processing_type_save"@ diff --git a/local/mib2c-conf.d/mfd-data-set.m2c b/local/mib2c-conf.d/mfd-data-set.m2c new file mode 100644 index 0000000..b3e447e --- /dev/null +++ b/local/mib2c-conf.d/mfd-data-set.m2c @@ -0,0 +1,142 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: mfd-data-set.m2c 12077 2005-04-14 02:47:19Z rstory $ +######################################################################## +## lower conf files get confused with multiple processing types, so +## set single options +@eval $mfd_data_set_processing_type_save = "$m2c_processing_type"@ +@if "$mfd_processing_types" =~ /h/@ +@eval $m2c_processing_type = 'h'@ +@if $m2c_create_fewer_files != 1@ +@ eval $hack = "Id"@ +@open ${name}_data_set.h@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 12077 $ of $RCSfile$ + * + * $$hack:$ + */ +@eval $m2c_save = "$name"@ +@eval $name = "${name}_DATA_SET"@ +@include generic-header-top.m2i@ +@eval $name = "$m2c_save"@ +@end@ // m2c_create_fewer_files +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 12077 $ */ +@end@ +## +/* ********************************************************************* + * SET function declarations + */ + +/* ********************************************************************* + * SET Table declarations + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ if $m2c_table_settable == 0@ +@ next@ # skip to next table +@ end@ +@ include details-table.m2i@ + +@ include parent-set.m2i@ + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +int ${node}_check_value( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_val); +int ${node}_undo_setup( ${context}_rowreq_ctx *rowreq_ctx ); +int ${node}_set( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_val ); +int ${node}_undo( ${context}_rowreq_ctx *rowreq_ctx ); + +@ end@ # foreach nonindex + +int ${context}_check_dependencies(${context}_rowreq_ctx *ctx); +@end@ # foreach table + +@if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 12077 $ */ +@end@ +@if $m2c_create_fewer_files != 1@ +@eval $m2c_save = "$name"@ +@eval $name = "${name}_DATA_SET"@ +@include generic-header-bottom.m2i@ +@eval $name = "$m2c_save"@ +@end@ // m2c_create_fewer_files +###################################################################### +@end@ // mfd_processing_types =~ /h/ +###################################################################### +###################################################################### +###################################################################### +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if "$mfd_processing_types" =~ /c/@ +@eval $m2c_processing_type = 'c'@ +@if $m2c_create_fewer_files != 1@ +@open ${name}_data_set.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 12077 $ of $RCSfile$ + * + * $$hack:$ + * + */ +@include generic-source-includes.m2i@ + +/** @defgroup data_set data_set: Routines to set data + * + * These routines are used to set the value for individual objects. The + * row context is passed, along with the new value. + * + * @{ + */ +@end@ // m2c_create_fewer_files +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12077 $ */ +@end@ +######################################################################## +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ if $m2c_table_settable == 0@ +@ next@ # skip to next table +@ end@ +@ include details-table.m2i@ +######################################################################## +@ include parent-set.m2i@ +######################################################################## +######################################################################## +/* + * TODO:440:M: Implement $context node value checks. + * TODO:450:M: Implement $context undo functions. + * TODO:460:M: Implement $context set functions. + * TODO:480:M: Implement $context commit functions. + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 0@ +@ next@ # skip to next column +@ end@ +@ if $m2c_report_progress == 1@ +@ print | | +-> Processing nonindex $node@ +@ end@ +@ include details-node.m2i@ +@ include node-set.m2i@ +@ end@ # foreach column +######################################################################## +@ if $m2c_table_dependencies == 1@ +@ include parent-dependencies.m2i@ +@ end@ +######################################################################## +@end@ # foreach table +## +######################################################################## +/** @} */ +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12077 $ */ +@end@ +######################################################################## +@end@ // mfd_processing_type =~ /c/ +## restore original processing types +@eval $m2c_processing_type = "$mfd_data_set_processing_type_save"@ diff --git a/local/mib2c-conf.d/mfd-doxygen.m2c b/local/mib2c-conf.d/mfd-doxygen.m2c new file mode 100644 index 0000000..25406a0 --- /dev/null +++ b/local/mib2c-conf.d/mfd-doxygen.m2c @@ -0,0 +1,60 @@ +######################################################################## +@foreach $table table@ +@ ifconf ${context}_doxygen.conf +@ print "${context}_doxygen.conf exists, skipping.@ +@ else@ +@ include m2c_setup_table.m2i@ +@ open ${context}_doxygen.conf@ +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = ${context} + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 0.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +FILE_PATTERNS = *.c *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = +@ end@ # conf file exists +@end@ # foreach table diff --git a/local/mib2c-conf.d/mfd-interactive-setup.m2c b/local/mib2c-conf.d/mfd-interactive-setup.m2c new file mode 100644 index 0000000..3361553 --- /dev/null +++ b/local/mib2c-conf.d/mfd-interactive-setup.m2c @@ -0,0 +1,332 @@ +####################################################################### +## generic include for XXX. Do not use directly. +## +## $Id: mfd-interactive-setup.m2c 16380 2007-05-17 18:06:33Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 16380 $ */ +@end@ +######################################################################## +@eval $m2c_temp_writable = table_is_writable($context)@ +@eval $m2c_temp_create = table_has_create($context)@ +@eval $m2c_temp_dependencies = $m2c_temp_writable@ +@eval $m2c_temp_context_reg = "$mfd_default_context_reg"@ +@eval $m2c_temp_data_context = "$mfd_default_data_context"@ +@eval $m2c_temp_data_allocate = $mfd_default_data_allocate@ +@eval $m2c_temp_data_cache = $mfd_default_data_cache@ +@eval $m2c_temp_undo_embed = $mfd_default_undo_embed@ +@eval $m2c_temp_data_init = $mfd_default_data_init@ +@eval $m2c_temp_persistent = $m2c_temp_writable@ +@eval $m2c_temp_table_access = "$mfd_default_table_access"@ +@eval $m2c_temp_data_transient = $mfd_default_data_transient@ +@eval $m2c_temp_include_examples = $mfd_default_include_examples@ +@eval $m2c_temp_table_skip_mapping = $mfd_default_table_skip_mapping@ +@eval $m2c_temp_table_sparse = $mfd_default_data_sparse@ +@eval $m2c_temp_generate_makefile = $mfd_default_generate_makefile@ +@eval $m2c_temp_generate_subagent = $mfd_default_generate_subagent@ +## +@if $mfd_interactive_setup != 0@ +@open -@ +@ if $mfd_interactive_setup != -1@ +There are no defaults for ${context}. Would you like to + + 1) Accept hard-coded defaults + 2) Set defaults now [DEFAULT] + +@ eval $ans = 2@ +@ prompt $ans Select your choice : @ +@ else@ +@ eval $ans = 2@ +@ end@ +@ if $ans == 1@ +@ else@ + + +## --------------------------------------------------- +@ if $m2c_temp_writable == 1@ +This table has writable columns. Do you want to generate +code for writeable columns, or restrict the table to read-only? + + 1) generate code with writeable columns [DEFAULT] + 2) generate code with read-only columns + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_writable = 0@ +@ eval $m2c_temp_create = 0@ +@ eval $m2c_temp_dependencies = 0@ +@ eval $m2c_temp_persistent = 0@ +@ end@ + + +@ end@ # writable +## --------------------------------------------------- +@ if $m2c_temp_persistent == 1@ +@ eval $m2c_temp_persistent = 0@ +Since your table is writable, do you want to generate code to save and +restore rows in the Net-SNMP persistent store? You should only use this +option if the agent 'owns' the data, and doesn't get the data from an +external source. + + 1) do not generate persistent store code [DEFAULT] + 2) generate persistent store code + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_persistent = 1@ +@ end@ + + +@ end@ # persistent +## --------------------------------------------------- +@ if $m2c_temp_dependencies == 1@ +@ eval $m2c_temp_dependencies = 0@ +Writable tables sometimes have dependencies beteen columns +or with other tables. If there are no dependencies in this table, you +probably do not want the extra code. + + 1) do not generate dependency code [DEFAULT] + 2) generate dependency code + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_dependencies = 1@ +@ end@ + + +@ end@ # dependencies +## --------------------------------------------------- +@ if $m2c_temp_create == 1@ +This table has read-create columns. Do you want to generate +code for dynamic row creation? + + 1) generate code for row creation [DEFAULT] + 2) do not generate code for row creation + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_create = 0@ +@ end@ + + +@ end@ # create +## --------------------------------------------------- +Do you want to use an existing data structure for the USER context? +This would be a structure used to track data for the entire table, +(similar to a global variable) not individual rows. + + 1) No, use $m2c_temp_context_reg [DEFAULT] + 2) Yes, use my own structure + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ prompt $m2c_temp_context_reg Enter your USER context : @ +@ end@ + + +## --------------------------------------------------- +Do you want to use an existing data structure for the DATA context? +The DATA context holds the data for each MIB column. By default, a new +data structure will be created with an element for each column. + + 1) No, use $m2c_temp_data_context [DEFAULT] + 2) Yes, use my own structure + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ + + +Note: Do not enter a pointer type. Use the base structure name. For +example, use 'struct widget', not 'struct widget *'. If you will be +using pointer to the structure, select dynamic allocation in the +next question. + +@ prompt $m2c_temp_data_context Enter your DATA context : @ +@ end@ + + +## --------------------------------------------------- +@ if "x$m2c_temp_data_context" ne "x$mfd_default_data_context"@ +Do you want to allocate your '$m2c_temp_data_context' DATA context, or +embed it directly? If your data is INTERNAL (controlled by the agent), you +probably want embedded. If your data is EXTERNAL (controlled by another +process) and you have pointers to the data, you probably want allocated. + + 1) directly embed structure [DEFAULT] + 2) dynamically allocate structure + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_data_allocate = 1@ +@ end@ + + +@ end@ # ! default (generated) +## --------------------------------------------------- +Do you need to initialize elements in the '$m2c_temp_data_context' DATA +context when a new instance is created (eg default values, or other structures +you are going to add that might need initialization to the row request context? +(The most common reasons you might need to do this is are if you want to keep +some non-MIB data for every row, or some columns have default values.) + + 1) no, no initialization needed + 2) yes, initilization is needed [DEFAULT] + +@ prompt $ans Select your choice : @ +@ if $ans == 1@ +@ eval $m2c_temp_data_init = 0@ +@ end@ + + +## --------------------------------------------------- +Do you plan on keeping all data in the format defined by the MIB? If so, +no functions will be generated to map values. If some data will be +stored in a different format, the mapping functions will be generated. +If your MIB has integers with enumerations, mapping functions are more +likely to be needed. (e.g. A TruthValue object will hold the value +1 or 2, but a C boolean would be 1 or 0.) + + 1) All values will be stored as defined by the MIB [DEFAULT] + 2) I need to map values to the format defined by the MIB. + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_table_skip_mapping = -1@ +@ end@ + + +## --------------------------------------------------- +Which method would you like to use to gather data about available rows? + + 1) container : [DEFAULT] This access method uses a netsnmp_container + to store all row data in memory. This method is best for: + - Internal data (maintained by the agent) + - Access speed is important + - Sufficient memory exists to contain all rows + + 2) container-cached : This access method uses a netsnmp_container + to keep track of the indexes (and data, usually) for each + row. This method is best for: + - External data (maintained by another process/the kernel) + - Access speed is important + - Sufficient memory exists to contain all indexes + + 3) unsorted-external : This access method iterates over all of your data + to find the row with the appropriate index. This method is good for + - External data (maintained by another process/the kernel) + - Using less memory is much more important than access speed + +@ prompt $ans Select your choice : @ +@ if $ans == 3@ +@ eval $m2c_temp_table_access = "unsorted-external"@ +@ elsif $ans == 2@ +@ eval $m2c_temp_table_access = "container-cached"@ +@ eval $m2c_temp_data_cache = 1@ +@ else@ +@ eval $m2c_temp_table_access = "container-cached"@ +@ eval $m2c_temp_data_cache = 0@ +@ end@ + + +## --------------------------------------------------- +When accessing your data, is your data TRANSIENT? + + 1) Yes. My data is TRANSIENT (e.g. a pointer to a static buffer that + my be overwritten during a request) and needs to be copied during + processing. + + 2) Yes. My data is SEMI-TRANSIENT (e.g. an allocated pointer to a + copy of the data). + + 3) No, my data is PERSISTENT (e.g. an allocated pointer to the actual + data, which is under the agent's control) +## ' + +@ prompt $ans Select your choice [DEFAULT=1] : @ +@ if $ans == 3@ +@ eval $m2c_temp_data_transient = 0@ +@ elsif $ans == 2@ +@ eval $m2c_temp_data_transient = 1@ +@ else@ +@ eval $m2c_temp_data_transient = 2@ +@ end@ + + +## --------------------------------------------------- +Do you want example code to be generated? This will generate example code +for reading data from a text file. + + 1) generate example code [DEFAULT] + 2) do not generate example code + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_include_examples = 0@ +@ else@ +@ eval $m2c_temp_include_examples = 1@ +@ end@ + +## --------------------------------------------------- +Is your table sparse? A sparse table is a table where some +columns might not exist for all rows. Note that if your table +contains a RowStaus column and it supports createAndWait, you +will need sparse table support. + + 1) No, all columns always exist for every row [DEFAULT] + 2) Yes, my table is sparse + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_table_sparse = 1@ +@ end@ + +## --------------------------------------------------- +Do you want a makefile and AgentX subagent source file generated? +This will let you test your table without having to link it into +snmpd. (You can still link it in later.) + + 1) do not generate makefile/AgentX code [DEFAULT] + 2) generate makefile/AgentX code + +@ prompt $ans Select your choice : @ +@ if $ans == 2@ +@ eval $m2c_temp_generate_makefile = 1@ +@ eval $m2c_temp_generate_subagent = 1@ +@ else@ +@ eval $m2c_temp_generate_makefile = 0@ +@ eval $m2c_temp_generate_subagent = 0@ +@ end@ + +@ end@ # do not use hardcoded +@end@ # $mfd_interactive_setup == 1 +################################## +## +## save values +## Note: if you add a var here, add it in m2c_table_save_defaults.m2i too +## +@eval $m2c_context_reg = "$m2c_temp_context_reg"@ +@eval $m2c_data_allocate = $m2c_temp_data_allocate@ +@eval $m2c_data_cache = $m2c_temp_data_cache@ +@eval $m2c_data_context = "$m2c_temp_data_context"@ +@eval $m2c_data_init = $m2c_temp_data_init@ +@eval $m2c_data_transient = $m2c_temp_data_transient@ +@eval $m2c_include_examples = $m2c_temp_include_examples@ +@eval $m2c_irreversible_commit = $m2c_irreversible_commit@ +@eval $m2c_table_access = "$m2c_temp_table_access"@ +@eval $m2c_table_dependencies = $m2c_temp_dependencies@ +@eval $m2c_table_persistent = $m2c_temp_persistent@ +@eval $m2c_table_row_creation = $m2c_temp_create@ +@eval $m2c_table_settable = $m2c_temp_writable@ +@eval $m2c_table_skip_mapping = $m2c_temp_table_skip_mapping@ +@eval $m2c_table_sparse = $m2c_temp_table_sparse@ +@eval $mfd_generate_makefile = $m2c_temp_generate_makefile@ +@eval $mfd_generate_subagent = $m2c_temp_generate_subagent@ +## +## write them back +## +@include m2c_table_save_defaults.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 16380 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-interface.m2c b/local/mib2c-conf.d/mfd-interface.m2c new file mode 100644 index 0000000..6a3cd0b --- /dev/null +++ b/local/mib2c-conf.d/mfd-interface.m2c @@ -0,0 +1,1716 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: mfd-interface.m2c 15899 2007-02-27 13:08:24Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 15899 $ */ +@end@ +######################################################################## +## +######################################################################## +@eval $m2c_processing_type = 'h'@ +@open ${name}_interface.h@ +@eval $hack = "Id"@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 15899 $ of $RCSfile$ + * + * $$hack:$ + */ +/** @ingroup interface: Routines to interface to Net-SNMP + * + * \warning This code should not be modified, called directly, + * or used to interpret functionality. It is subject to + * change at any time. + * + * @{ + */ +@include m2c-internal-warning.m2i@ +## +@eval $m2c_save = "$name"@ +@eval $name = "${name}_INTERFACE"@ +@include generic-header-top.m2i@ +@eval $name = "$m2c_save"@ + +#include "${name}.h" + + +/* ******************************************************************** + * Table declarations + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ + +/* PUBLIC interface initialization routine */ +void _${context}_initialize_interface(${context}_registration * user_ctx, + u_long flags); +void _${context}_shutdown_interface(${context}_registration * user_ctx); + +${context}_registration * +${context}_registration_get( void ); + +${context}_registration * +${context}_registration_set( ${context}_registration * newreg ); + +netsnmp_container *${context}_container_get( void ); +int ${context}_container_size( void ); + +@ if $m2c_table_settable@ +u_int ${context}_dirty_get( void ); +void ${context}_dirty_set( u_int status ); + +@ end@ +@ if $m2c_data_allocate == 1@ +@ eval $m2c_tmp = "${context}_data *"@ +@ if $m2c_data_init == 1@ +@ eval $m2c_tmp = "$m2c_tmp, void *"@ +@ @end@ +@ elsif $m2c_data_init == 1@ +@ eval $m2c_tmp = "void *"@ +@ else@ +@ eval $m2c_tmp = "void"@ +@ end@ + ${context}_rowreq_ctx * ${context}_allocate_rowreq_ctx($m2c_tmp); +void ${context}_release_rowreq_ctx(${context}_rowreq_ctx *rowreq_ctx); + +int ${context}_index_to_oid(netsnmp_index *oid_idx, + ${context}_mib_index *mib_idx); +int ${context}_index_from_oid(netsnmp_index *oid_idx, + ${context}_mib_index *mib_idx); + +@ if $m2c_table_persistent == 1@ +@ include mfd-persistence.m2i@ + +@ end@ +/* + * access to certain internals. use with caution! + */ +void ${context}_valid_columns_set(netsnmp_column_info *vc); + +@end@ # for each +@eval $m2c_save = "$name"@ +@eval $name = "${name}_INTERFACE"@ +@include generic-header-bottom.m2i@ +/** @} */ +@eval $name = "$m2c_save"@ +######################################################################## +######################################################################## +######################################################################## +######################################################################## +######################################################################## +######################################################################## +######################################################################## +## +@open ${name}_interface.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 15899 $ of $RCSfile$ + * + * $$hack:$ + */ +@include m2c-internal-warning.m2i@ + +@include generic-source-includes.m2i@ + +#include +#include + +#include "${name}_interface.h" + +#include + +@eval $m2c_processing_type = 'i'@ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ +######################################################################## +typedef struct ${context}_interface_ctx_s { + + netsnmp_container *container; +@ if $m2c_data_cache == 1@ + netsnmp_cache *cache; +@ end@ + + ${context}_registration * user_ctx; + + netsnmp_table_registration_info tbl_info; + + netsnmp_baby_steps_access_methods access_multiplexer; + +@ if $m2c_table_settable@ + u_int table_dirty; + +@ end@ +} ${context}_interface_ctx; + +static ${context}_interface_ctx ${context}_if_ctx; + +static void _${context}_container_init( + ${context}_interface_ctx *if_ctx); +static void _${context}_container_shutdown( + ${context}_interface_ctx *if_ctx); + + +netsnmp_container * +${context}_container_get( void ) +{ + return ${context}_if_ctx.container; +} + +${context}_registration * +${context}_registration_get( void ) +{ + return ${context}_if_ctx.user_ctx; +} + +${context}_registration * +${context}_registration_set( ${context}_registration * newreg ) +{ + ${context}_registration * old = ${context}_if_ctx.user_ctx; + ${context}_if_ctx.user_ctx = newreg; + return old; +} + +int +${context}_container_size( void ) +{ + return CONTAINER_SIZE(${context}_if_ctx.container); +} + +@ if $m2c_table_settable@ +u_int +${context}_dirty_get( void ) +{ + return ${context}_if_ctx.table_dirty; +} + +void +${context}_dirty_set( u_int status ) +{ + DEBUGMSGTL(("${context}:${context}_dirty_set", + "called. was %d, now %d\n", + ${context}_if_ctx.table_dirty, status)); + ${context}_if_ctx.table_dirty = status; +} + +@end@ +/* + * mfd multiplexer modes + */ +static Netsnmp_Node_Handler _mfd_${context}_pre_request; +static Netsnmp_Node_Handler _mfd_${context}_post_request; +static Netsnmp_Node_Handler _mfd_${context}_object_lookup; +static Netsnmp_Node_Handler _mfd_${context}_get_values; +@ if $m2c_table_settable@ +static Netsnmp_Node_Handler _mfd_${context}_check_objects; +static Netsnmp_Node_Handler _mfd_${context}_undo_setup; +static Netsnmp_Node_Handler _mfd_${context}_set_values; +static Netsnmp_Node_Handler _mfd_${context}_undo_cleanup; +static Netsnmp_Node_Handler _mfd_${context}_undo_values; +static Netsnmp_Node_Handler _mfd_${context}_commit; +static Netsnmp_Node_Handler _mfd_${context}_undo_commit; +static Netsnmp_Node_Handler _mfd_${context}_irreversible_commit; +@ if $m2c_table_dependencies == 1@ +static Netsnmp_Node_Handler _mfd_${context}_check_dependencies; +@ end@ + +NETSNMP_STATIC_INLINE int _${context}_undo_column( ${context}_rowreq_ctx *rowreq_ctx, + netsnmp_variable_list *var, int column ); + +@ end@ # writable +@if ($m2c_table_persistent == 1) || ($m2c_table_row_creation == 1)@ +NETSNMP_STATIC_INLINE int _${context}_check_indexes(${context}_rowreq_ctx * rowreq_ctx); + +@end@ +@ if ("$m2c_data_context" eq "generated") && (($m2c_undo_embed == 0) || ($m2c_data_allocate == 1))@ +${context}_data *${context}_allocate_data(void); + +@ end@ +/** + * @internal + * Initialize the table $context + * (Define its contents and how it's structured) + */ +void +_${context}_initialize_interface(${context}_registration * reg_ptr, u_long flags) +{ + netsnmp_baby_steps_access_methods *access_multiplexer = + &${context}_if_ctx.access_multiplexer; + netsnmp_table_registration_info *tbl_info = &${context}_if_ctx.tbl_info; + netsnmp_handler_registration *reginfo; + netsnmp_mib_handler *handler; + int mfd_modes = 0; + + DEBUGMSGTL(("internal:${context}:_${context}_initialize_interface","called\n")); + + + /************************************************* + * + * save interface context for ${context} + */ + /* + * Setting up the table's definition + */ + netsnmp_table_helper_add_indexes(tbl_info, + @foreach $tabledx index@ + $tabledx.type, /** index: $tabledx */ + @end@ + 0); + + /* Define the minimum and maximum accessible columns. This + optimizes retrival. */ + tbl_info->min_column = $context.uc_MIN_COL; + tbl_info->max_column = $context.uc_MAX_COL; + + /* + * save users context + */ + ${context}_if_ctx.user_ctx = reg_ptr; + + /* + * call data access initialization code + */ + ${context}_init_data(reg_ptr); + + /* + * set up the container + */ + _${context}_container_init(&${context}_if_ctx); + if (NULL == ${context}_if_ctx.container) { + snmp_log(LOG_ERR,"could not initialize container for ${context}\n"); + return; + } + + /* + * access_multiplexer: REQUIRED wrapper for get request handling + */ + access_multiplexer->object_lookup = _mfd_${context}_object_lookup; + access_multiplexer->get_values = _mfd_${context}_get_values; + + /* + * no wrappers yet + */ + access_multiplexer->pre_request = _mfd_${context}_pre_request; + access_multiplexer->post_request = _mfd_${context}_post_request; + +## +@ if $m2c_table_settable@ + + /* + * REQUIRED wrappers for set request handling + */ + access_multiplexer->object_syntax_checks = _mfd_${context}_check_objects; + access_multiplexer->undo_setup = _mfd_${context}_undo_setup; + access_multiplexer->undo_cleanup = _mfd_${context}_undo_cleanup; + access_multiplexer->set_values = _mfd_${context}_set_values; + access_multiplexer->undo_sets = _mfd_${context}_undo_values; + + /* + * no wrappers yet + */ + access_multiplexer->commit = _mfd_${context}_commit; + access_multiplexer->undo_commit = _mfd_${context}_undo_commit; + access_multiplexer->irreversible_commit = _mfd_${context}_irreversible_commit; +## +@ if $m2c_table_dependencies == 1@ + + /* + * REQUIRED for tables with dependencies + */ + access_multiplexer->consistency_checks = _mfd_${context}_check_dependencies; +@ end@ +@ end@ # writable + + /************************************************* + * + * Create a registration, save our reg data, register table. + */ + DEBUGMSGTL(("$name:init_$context", + "Registering $context as a mibs-for-dummies table.\n")); + handler = netsnmp_baby_steps_access_multiplexer_get(access_multiplexer); + reginfo = netsnmp_handler_registration_create("${context}", handler, + ${context}_oid, + ${context}_oid_size, + HANDLER_CAN_BABY_STEP | +@if $m2c_table_settable == 1@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + if(NULL == reginfo) { + snmp_log(LOG_ERR,"error registering table ${context}\n"); + return; + } + reginfo->my_reg_void = &${context}_if_ctx; + + /************************************************* + * + * set up baby steps handler, create it and inject it + */ + if( access_multiplexer->object_lookup ) + mfd_modes |= BABY_STEP_OBJECT_LOOKUP; + if( access_multiplexer->set_values ) + mfd_modes |= BABY_STEP_SET_VALUES; + if( access_multiplexer->irreversible_commit ) + mfd_modes |= BABY_STEP_IRREVERSIBLE_COMMIT; + if( access_multiplexer->object_syntax_checks ) + mfd_modes |= BABY_STEP_CHECK_OBJECT; + + if( access_multiplexer->pre_request ) + mfd_modes |= BABY_STEP_PRE_REQUEST; + if( access_multiplexer->post_request ) + mfd_modes |= BABY_STEP_POST_REQUEST; + + if( access_multiplexer->undo_setup ) + mfd_modes |= BABY_STEP_UNDO_SETUP; + if( access_multiplexer->undo_cleanup ) + mfd_modes |= BABY_STEP_UNDO_CLEANUP; + if( access_multiplexer->undo_sets ) + mfd_modes |= BABY_STEP_UNDO_SETS; + + if( access_multiplexer->row_creation ) + mfd_modes |= BABY_STEP_ROW_CREATE; + if( access_multiplexer->consistency_checks ) + mfd_modes |= BABY_STEP_CHECK_CONSISTENCY; + if( access_multiplexer->commit ) + mfd_modes |= BABY_STEP_COMMIT; + if( access_multiplexer->undo_commit ) + mfd_modes |= BABY_STEP_UNDO_COMMIT; + + handler = netsnmp_baby_steps_handler_get(mfd_modes); + netsnmp_inject_handler(reginfo, handler); + + /************************************************* + * + * inject row_merge helper with prefix rootoid_len + 2 (entry.col) + */ + handler = netsnmp_get_row_merge_handler(reginfo->rootoid_len + 2); + netsnmp_inject_handler(reginfo, handler); + + /************************************************* + * + * inject container_table helper + */ + handler = + netsnmp_container_table_handler_get(tbl_info, + ${context}_if_ctx.container, + TABLE_CONTAINER_KEY_NETSNMP_INDEX); + netsnmp_inject_handler( reginfo, handler ); + +@ if $m2c_data_cache == 1@ + /************************************************* + * + * inject cache helper + */ + if(NULL != ${context}_if_ctx.cache) { + handler = netsnmp_cache_handler_get(${context}_if_ctx.cache); + netsnmp_inject_handler( reginfo, handler ); + } + +@ end@ + /* + * register table + */ + netsnmp_register_table(reginfo, tbl_info); + +@if $m2c_table_persistent == 1@ + /* + * register config/persistence callbacks + */ + ${context}_container_init_persistence(${context}_if_ctx.container); + +@end@ +} /* _${context}_initialize_interface */ + +/** + * @internal + * Shutdown the table $context + */ +void +_${context}_shutdown_interface(${context}_registration * reg_ptr) +{ + /* + * shutdown the container + */ + _${context}_container_shutdown(&${context}_if_ctx); +} + +void +${context}_valid_columns_set(netsnmp_column_info *vc) +{ + ${context}_if_ctx.tbl_info.valid_columns = vc; +} /* ${context}_valid_columns_set */ + +@include generic-table-indexes-to-oid.m2i@ +@include generic-table-indexes-from-oid.m2i@ + +######################################################################## +## +@ if (($m2c_data_allocate == 1) || ($m2c_undo_embed == 0)) && ("$m2c_data_context" eq "generated")@ +@ eval $m2c_gda_todo_suppress = 1@ # no todo comments +@ include generic-data-allocate.m2i@ # resets suppress +@ end@ +######################################################################## +/* ********************************************************************* + * @internal + * allocate resources for a ${context}_rowreq_ctx + */ +${context}_rowreq_ctx * +@if $m2c_data_allocate == 1@ +@ eval $m2c_tmp = "${context}_data *data"@ +@ if $m2c_data_init == 1@ +@ eval $m2c_tmp = "$m2c_tmp, void *user_init_ctx"@ +@ end@ +@elsif $m2c_data_init == 1@ +@ eval $m2c_tmp = "void *user_init_ctx"@ +@else@ +@ eval $m2c_tmp = "void"@ +@end@ +${context}_allocate_rowreq_ctx($m2c_tmp) +{ + ${context}_rowreq_ctx *rowreq_ctx = + SNMP_MALLOC_TYPEDEF(${context}_rowreq_ctx); + + DEBUGMSGTL(("internal:${context}:${context}_allocate_rowreq_ctx","called\n")); + + if(NULL == rowreq_ctx) { + snmp_log(LOG_ERR,"Couldn't allocate memory for a " + "${context}_rowreq_ctx.\n"); + return NULL; + } +@if $m2c_data_allocate == 1@ + else { + if(NULL != data) { + /* + * track if we got data from user + */ + rowreq_ctx->rowreq_flags |= MFD_ROW_DATA_FROM_USER; + rowreq_ctx->data = data; + } + else if (NULL == (rowreq_ctx->data = ${context}_allocate_data())) { + SNMP_FREE(rowreq_ctx); + return NULL; + } + } + + /* + * undo context will be allocated when needed (in *_undo_setup) + */ +@end@ + + rowreq_ctx->oid_idx.oids = rowreq_ctx->oid_tmp; + + rowreq_ctx->${context}_data_list = NULL; + +@if $m2c_data_init == 1@ + /* + * if we allocated data, call init routine + */ + if (!(rowreq_ctx->rowreq_flags & MFD_ROW_DATA_FROM_USER)) { + if(SNMPERR_SUCCESS != + ${context}_rowreq_ctx_init(rowreq_ctx, user_init_ctx)) { + ${context}_release_rowreq_ctx(rowreq_ctx); + rowreq_ctx = NULL; + } + } +@end@ + + return rowreq_ctx; +} /* ${context}_allocate_rowreq_ctx */ + +/* + * @internal + * release resources for a ${context}_rowreq_ctx + */ +void +${context}_release_rowreq_ctx(${context}_rowreq_ctx *rowreq_ctx) +{ + DEBUGMSGTL(("internal:${context}:${context}_release_rowreq_ctx","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +@if $m2c_data_init == 1@ + ${context}_rowreq_ctx_cleanup(rowreq_ctx); +@end@ + +@if $m2c_data_allocate == 1@ + /* + * for non-transient data, don't free data we got from the user + */ + if ((rowreq_ctx->data) && + !(rowreq_ctx->rowreq_flags & MFD_ROW_DATA_FROM_USER)) + ${context}_release_data(rowreq_ctx->data); + +@end@ +@if $m2c_undo_embed == 0@ + if(rowreq_ctx->undo) + ${context}_release_data(rowreq_ctx->undo); + +@end@ + /* + * free index oid pointer + */ + if(rowreq_ctx->oid_idx.oids != rowreq_ctx->oid_tmp) + free(rowreq_ctx->oid_idx.oids); + + SNMP_FREE(rowreq_ctx); +} /* ${context}_release_rowreq_ctx */ + +######################################################################## +## +/** + * @internal + * wrapper + */ +static int +_mfd_${context}_pre_request(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_pre_request", + "called\n")); + + if (1 != netsnmp_row_merge_status_first(reginfo, agtreq_info)) { + DEBUGMSGTL(("internal:${context}", + "skipping additional pre_request\n")); + return SNMP_ERR_NOERROR; + } + + rc = ${context}_pre_request(${context}_if_ctx.user_ctx); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}","error %d from " + "${context}_pre_request\n", rc)); + netsnmp_request_set_error_all(requests, SNMP_VALIDATE_ERR(rc)); + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_pre_request */ + +/** + * @internal + * wrapper + */ +static int +_mfd_${context}_post_request(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + int rc, packet_rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_post_request", + "called\n")); + + /* + * release row context, if deleted + */ + if (rowreq_ctx && (rowreq_ctx->rowreq_flags & MFD_ROW_DELETED)) + ${context}_release_rowreq_ctx(rowreq_ctx); + + /* + * wait for last call before calling user + */ + if (1 != netsnmp_row_merge_status_last(reginfo, agtreq_info)) { + DEBUGMSGTL(("internal:${context}", + "waiting for last post_request\n")); + return SNMP_ERR_NOERROR; + } + + packet_rc = netsnmp_check_all_requests_error(agtreq_info->asp, 0); +@ if $m2c_table_settable@ + if ((MFD_SUCCESS != packet_rc) && ${context}_dirty_get()) { + /* + * we shouldn't get here. the undo steps should also clear + * the dirty flags. + */ + snmp_log(LOG_WARNING, "${context} dirty flag set in post_request " + "but status != SUCCESS.\n"); + } + +@ end@ + rc = ${context}_post_request(${context}_if_ctx.user_ctx,packet_rc); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}","error %d from " + "${context}_post_request\n", rc)); + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_post_request */ + +######################################################################## +## +@if ($m2c_table_row_creation == 1) || ($m2c_table_persistent == 1)@ +/** + * @internal + * wrapper + */ +static ${table}_rowreq_ctx * +_mfd_${context}_rowreq_from_index(netsnmp_index *oid_idx, int * rc_ptr) +{ + ${context}_rowreq_ctx * rowreq_ctx; + ${context}_mib_index mib_idx; + int rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_rowreq_from_index", + "called\n")); + + if (NULL == rc_ptr) + rc_ptr = &rc; + *rc_ptr = MFD_SUCCESS; + + memset(&mib_idx, 0x0, sizeof(mib_idx)); + + /* + * try to parse oid + */ + *rc_ptr = ${context}_index_from_oid(oid_idx, &mib_idx); + if(MFD_SUCCESS != *rc_ptr) { + DEBUGMSGT(("$context", "error parsing index\n")); + return NULL; + } + + /* + * allocate new context + */ +@ eval $m2c_tmp = ""@ +@ if ($m2c_data_allocate == 1) || ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "NULL"@ +@ if ($m2c_data_allocate == 1) && ($m2c_data_init == 1)@ +@ eval $m2c_tmp = "$m2c_tmp, NULL"@ +@ @end@ +@ end@ + rowreq_ctx = ${context}_allocate_rowreq_ctx($m2c_tmp); + if (NULL == rowreq_ctx) { + *rc_ptr = MFD_ERROR; + return NULL; /* msg already logged */ + } + + memcpy(&rowreq_ctx->tbl_idx, &mib_idx, sizeof(mib_idx)); + + /* + * check indexes + */ + *rc_ptr = _${context}_check_indexes(rowreq_ctx); + if(MFD_SUCCESS != *rc_ptr) { + netsnmp_assert((*rc_ptr == SNMP_ERR_NOCREATION) || + (*rc_ptr == SNMP_ERR_INCONSISTENTNAME)); + ${context}_release_rowreq_ctx(rowreq_ctx); + return NULL; + } + + /* + * copy indexes + */ + rowreq_ctx->oid_idx.len = oid_idx->len; + memcpy(rowreq_ctx->oid_idx.oids, oid_idx->oids, oid_idx->len * sizeof(oid)); + + return rowreq_ctx; +} /* _mfd_${context}_rowreq_from_index */ + + +@end@ # row creation +/** + * @internal + * wrapper + */ +static int +_mfd_${context}_object_lookup(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc = SNMP_ERR_NOERROR; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_object_lookup","called\n")); + + /* + * get our context from mfd + * ${context}_interface_ctx *if_ctx = + * (${context}_interface_ctx *)reginfo->my_reg_void; + */ + + if(NULL == rowreq_ctx) { +@ if $m2c_table_row_creation == 0@ + rc = SNMP_ERR_NOCREATION; +@ else@ + netsnmp_table_request_info *tblreq_info; + netsnmp_index oid_idx; + + tblreq_info = netsnmp_extract_table_info(requests); + if(NULL == tblreq_info) { + snmp_log(LOG_ERR, "request had no table info\n"); + return MFD_ERROR; + } + + /* + * try create rowreq + */ + oid_idx.oids = tblreq_info->index_oid; + oid_idx.len = tblreq_info->index_oid_len; + + rowreq_ctx = _mfd_${context}_rowreq_from_index(&oid_idx, &rc); + if(MFD_SUCCESS == rc) { + netsnmp_assert(NULL != rowreq_ctx); + rowreq_ctx->rowreq_flags |= MFD_ROW_CREATED; + /* + * add rowreq_ctx to request data lists + */ + netsnmp_container_table_row_insert(requests, (netsnmp_index*)rowreq_ctx); + } +@ end@ // row creation + } + + if (MFD_SUCCESS != rc) + netsnmp_request_set_error_all(requests, rc); + else + ${context}_row_prep(rowreq_ctx); + + return SNMP_VALIDATE_ERR(rc); +} /* _mfd_${context}_object_lookup */ + +######################################################################## +## +/*********************************************************************** + * + * GET processing + * + ***********************************************************************/ +/* + * @internal + * Retrieve the value for a particular column + */ +NETSNMP_STATIC_INLINE int +_${context}_get_column( ${context}_rowreq_ctx *rowreq_ctx, + netsnmp_variable_list *var, int column ) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_get_column", + "called for %d\n", column)); + + + netsnmp_assert(NULL != rowreq_ctx); + + switch(column) { +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ +@ if $node.accessible == 1@ + + /* (INDEX) $m2c_node_summary */ + case COLUMN_$node.uc: + var->type = $node.type; +@ if $m2c_node_needlength == 1@ + /* + * NOTE: val_len is in bytes, ${node}_len might not be (e.g. oids) + */ + if (var->val_len < (rowreq_ctx->tbl_idx.${node}_len * + sizeof(rowreq_ctx->tbl_idx.${node}[0]))) { + var->val.string = malloc(rowreq_ctx->tbl_idx.${node}_len * + sizeof(rowreq_ctx->tbl_idx.${node}[0])); + } + var->val_len = rowreq_ctx->tbl_idx.${node}_len * sizeof(rowreq_ctx->tbl_idx.${node}[0]); + memcpy( var->val.string, rowreq_ctx->tbl_idx.$node, var->val_len ); +@ else@ + var->val_len = sizeof($m2c_decl); + (*var->val.integer) = rowreq_ctx->tbl_idx.$node; +@ end@ + break; +@ end@ ## accessible +@ end@ ## index +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.accessible == 1@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: +@ if $m2c_table_sparse == 1@ + if (! (COLUMN_$node.uc_FLAG & rowreq_ctx->column_exists_flags)) { + DEBUGMSGTL(("internal:${context}:_mfd_${context}_get_column", + "column %d ($node) doesn't exist\n", column)); + return MFD_SKIP; + } + +@ end@ +## use sizeof except for BITS +@ if $m2c_node_needlength == 0@ +@ if "$node.perltype" eq "BITS"@ + { + $m2c_decl mask = 0xff << ((sizeof($m2c_decl) - 1) * 8); + int idx = 0; +@ else@ + var->val_len = sizeof($m2c_decl); +@ end@ +@ end@ + var->type = $node.type; +rc = ${node}_get(rowreq_ctx, $m2c_node_var_ref ); +@ if ($m2c_node_needlength == 0) && ("$node.perltype" eq "BITS")@ + /* + * check for length of bits string + */ + var->val_len = 0; + while( 0 != mask ) { + ++idx; + if ( *(($m2c_decl *) var->val.string) & mask ) + var->val_len = idx; + mask = mask >> 8; + } + } +@ end@ + break; + @ end@ # accessible +@ end@ # for each column + + default: + if ($context.uc_MIN_COL <= column && column <= $context.uc_MAX_COL) { + DEBUGMSGTL(("internal:${context}:_mfd_${context}_get_column", + "assume column %d is reserved\n", column)); + rc = MFD_SKIP; + } else { + snmp_log(LOG_ERR, + "unknown column %d in _${context}_get_column\n", column); + } + break; + } + + return rc; +} /* _${context}_get_column */ + +######################################################################## +## +int +_mfd_${context}_get_values(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + netsnmp_table_request_info * tri; + u_char * old_string; + void (*dataFreeHook)(void *); + int rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_get_values","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +@if $m2c_table_sparse == 1@ + DEBUGMSGTL(("9:${context}:_mfd_${context}_get_values", + "exists %p\n", (void*)rowreq_ctx->column_exists_flags)); + +@end@ + for(;requests; requests = requests->next) { + /* + * save old pointer, so we can free it if replaced + */ + old_string = requests->requestvb->val.string; + dataFreeHook = requests->requestvb->dataFreeHook; + if(NULL == requests->requestvb->val.string) { + requests->requestvb->val.string = requests->requestvb->buf; + requests->requestvb->val_len = sizeof(requests->requestvb->buf); + } + else if(requests->requestvb->buf == requests->requestvb->val.string) { + if(requests->requestvb->val_len != sizeof(requests->requestvb->buf)) + requests->requestvb->val_len = sizeof(requests->requestvb->buf); + } + + /* + * get column data + */ + tri = netsnmp_extract_table_info(requests); + if(NULL == tri) + continue; + + rc = _${context}_get_column(rowreq_ctx, requests->requestvb, tri->colnum); + if(rc) { + if(MFD_SKIP == rc) { + requests->requestvb->type = SNMP_NOSUCHINSTANCE; + rc = SNMP_ERR_NOERROR; + } + } + else if (NULL == requests->requestvb->val.string) { + snmp_log(LOG_ERR,"NULL varbind data pointer!\n"); + rc = SNMP_ERR_GENERR; + } + if(rc) + netsnmp_request_set_error(requests, SNMP_VALIDATE_ERR(rc)); + + /* + * if the buffer wasn't used previously for the old data (i.e. it + * was allcoated memory) and the get routine replaced the pointer, + * we need to free the previous pointer. + */ + if(old_string && (old_string != requests->requestvb->buf) && + (requests->requestvb->val.string != old_string)) { + if(dataFreeHook) + (*dataFreeHook)(old_string); + else + free(old_string); + } + } /* for results */ + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_get_values */ + +##---------------------------------------------------------------------- +@if ($m2c_table_row_creation == 1) || ($m2c_table_persistent == 1)@ +NETSNMP_STATIC_INLINE int +_${context}_check_indexes(${context}_rowreq_ctx * rowreq_ctx) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_${context}_check_indexes","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +## +@if $m2c_table_external_indexes != 0@ + /* + * check that the corresponding EXTERNAL row exists + */ +@ foreach $node externalindex@ +@ include m2c_setup_node.m2i@ + + /* (INDEX) $m2c_node_summary */ + rc = ${context}_${node}_check_index( rowreq_ctx ); + if(MFD_SUCCESS != rc) + return SNMP_ERR_NOCREATION; +@ end@ # for each nonindex + +@end@ # external index +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ + + /* (INDEX) $m2c_node_summary */ +@ eval $m2c_nv_val = "rowreq_ctx->tbl_idx.$node"@ +@ eval $m2c_nv_len = "rowreq_ctx->tbl_idx.${node}_len"@ +@ eval $m2c_nv_str = "rowreq_ctx->tbl_idx.$node"@ +@ include node-validate.m2i@ + if (MFD_SUCCESS != rc) + return rc; + rc = ${node}_check_index( rowreq_ctx ); + if(MFD_SUCCESS != rc) + return SNMP_ERR_NOCREATION; +@ end@ # for each internalindex + + /* + * if individual parts look ok, check them as a whole + */ + return ${context}_validate_index( ${context}_if_ctx.user_ctx, rowreq_ctx ); +} /* _${context}_check_indexes */ +@end@ # $m2c_table_row_creation + +######################################################################## +## +/*********************************************************************** + * + * SET processing + * + ***********************************************************************/ + +@if $m2c_table_settable == 0@ +/* + * SET PROCESSING NOT APPLICABLE (per MIB or user setting) + */ +@else@ +/*---------------------------------------------------------------------- + * + * SET: Syntax checks + * + *---------------------------------------------------------------------*/ +/* + * @internal + * Check the syntax for a particular column + */ +NETSNMP_STATIC_INLINE int +_${context}_check_column( ${context}_rowreq_ctx *rowreq_ctx, + netsnmp_variable_list *var, int column ) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_${context}_check_column", + "called for %d\n", column)); + + netsnmp_assert(NULL != rowreq_ctx); + + switch(column) { +@ eval $m2c_nvv_item = "${m2c_context_item}tbl_idx."@ +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ + /* (INDEX) $m2c_node_summary */ + case COLUMN_$node.uc: + rc = SNMP_ERR_NOTWRITABLE; /* can not change index of active row */ + break; +@ end@ ## index +@ eval $m2c_nvv_item = "$m2c_data_item"@ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 0@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: + rc = SNMP_ERR_NOTWRITABLE; + break; +@ next@ +@ end@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: +@ include node-varbind-validate.m2i@ + if(SNMPERR_SUCCESS != rc) { + DEBUGMSGTL(("${context}:_${context}_check_column:$node", + "varbind validation failed (eg bad type or size)\n")); + } + else { + rc = ${node}_check_value( rowreq_ctx, $m2c_node_var_val ); + if((MFD_SUCCESS != rc) && (MFD_NOT_VALID_EVER != rc) && + (MFD_NOT_VALID_NOW != rc)) { + snmp_log(LOG_ERR, "bad rc %d from ${node}_check_value\n", rc); + rc = SNMP_ERR_GENERR; + } + } + break; +@ end@ # for each nonindex + + default: /** We shouldn't get here */ + rc = SNMP_ERR_GENERR; + snmp_log(LOG_ERR, "unknown column %d in _${context}_check_column\n", column); + } + + return rc; +} /* _${context}_check_column */ + +##---------------------------------------------------------------------- +int +_mfd_${context}_check_objects(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + netsnmp_table_request_info * tri; + int rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_check_objects","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + for(;requests; requests = requests->next) { + + /* + * get column number from table request info, and check that column + */ + tri = netsnmp_extract_table_info(requests); + if(NULL == tri) + continue; + + rc = _${context}_check_column(rowreq_ctx, requests->requestvb, tri->colnum); + if(rc) { + netsnmp_request_set_error(requests, SNMP_VALIDATE_ERR(rc)); + break; + } + + } /* for results */ + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_check_objects */ + + +@ if $m2c_table_dependencies == 1@ +/*---------------------------------------------------------------------- + * + * SET: check dependencies + * + *---------------------------------------------------------------------*/ +/* + * @internal + * Check dependencies wrapper + */ +static int +_mfd_${context}_check_dependencies(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + DEBUGMSGTL(("internal:${context}:_mfd_${context}_check_dependencies","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + rc = ${context}_check_dependencies(rowreq_ctx); + if(rc){ + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_check_dependencies\n", rc)); + netsnmp_request_set_error_all(requests, SNMP_VALIDATE_ERR(rc)); + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_check_dependencies */ + +@end@ // dependencies +/*---------------------------------------------------------------------- + * + * SET: Undo setup + * + *---------------------------------------------------------------------*/ +/* + * @internal + * Set the value for a particular column + */ +NETSNMP_STATIC_INLINE int +_${context}_undo_setup_column( ${context}_rowreq_ctx *rowreq_ctx, int column ) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_${context}_undo_setup_column", + "called for %d\n", column)); + + netsnmp_assert(NULL != rowreq_ctx); + + switch(column) { +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 1@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: + rowreq_ctx->column_set_flags |= COLUMN_$node.uc_FLAG; + rc = ${node}_undo_setup(rowreq_ctx ); + break; + @ end@ # settable +@ end@ # for each column + + default: + snmp_log(LOG_ERR,"unknown column %d in _${context}_undo_setup_column\n", column); + break; + } + + return rc; +} /* _${context}_undo_setup_column */ + + +##---------------------------------------------------------------------- +/** + * @internal + * undo setup + */ +int +_mfd_${context}_undo_setup(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_undo_setup","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +@if $m2c_undo_embed == 0@ + /* + * allocate undo context + */ + rowreq_ctx->undo = ${context}_allocate_data(); + if(NULL == rowreq_ctx->undo) { + /** msg already logged */ + netsnmp_request_set_error_all(requests, SNMP_ERR_RESOURCEUNAVAILABLE); + return SNMP_ERR_NOERROR; + } + +@end@ + /* + * row undo setup + */ + rowreq_ctx->column_set_flags = 0; + rc = ${context}_undo_setup(rowreq_ctx); + if (MFD_SUCCESS != rc) { + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo_setup\n", rc)); + netsnmp_request_set_error_all(requests, SNMP_VALIDATE_ERR(rc)); + } + else { + /* + * column undo setup + */ + netsnmp_table_request_info * tri; + for(;requests; requests = requests->next) { + /* + * set column data + */ + tri = netsnmp_extract_table_info(requests); + if(NULL == tri) + continue; + + rc = _${context}_undo_setup_column(rowreq_ctx, tri->colnum); + if(MFD_SUCCESS != rc) { + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo_setup_column\n", rc)); + netsnmp_set_request_error(agtreq_info, requests, SNMP_VALIDATE_ERR(rc)); + } + } /* for results */ + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_undo_setup */ + +/** + * @internal + * undo setup + */ +int +_mfd_${context}_undo_cleanup(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + int rc; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_undo_cleanup","called\n")); + + /* + * failed row create in early stages has no rowreq_ctx + */ + if (NULL == rowreq_ctx) + return MFD_SUCCESS; + + /* + * call user cleanup + */ + rc = ${context}_undo_cleanup(rowreq_ctx); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo_cleanup\n", rc)); + } + +@if $m2c_undo_embed == 0@ + /* + * release undo context, if needed + */ + if(rowreq_ctx->undo) { + ${context}_release_data(rowreq_ctx->undo); + rowreq_ctx->undo = NULL; + } + +@end@ + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_undo_cleanup */ + +/*---------------------------------------------------------------------- + * + * SET: Set values + * + *---------------------------------------------------------------------*/ +/* + * @internal + * Set the value for a particular column + */ +NETSNMP_STATIC_INLINE int +_${context}_set_column( ${context}_rowreq_ctx *rowreq_ctx, + netsnmp_variable_list *var, int column ) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_${context}_set_column", + "called for %d\n", column)); + + netsnmp_assert(NULL != rowreq_ctx); + + switch(column) { +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 1@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: + rowreq_ctx->column_set_flags |= COLUMN_$node.uc_FLAG; + rc = ${node}_set(rowreq_ctx, $m2c_node_var_val ); + break; + @ end@ # settable +@ end@ # for each column + + default: + snmp_log(LOG_ERR,"unknown column %d in _${context}_set_column\n", column); + rc = SNMP_ERR_GENERR; + break; + } + + return rc; +} /* _${context}_set_column */ + +######################################################################## +## +int +_mfd_${context}_set_values(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + netsnmp_table_request_info * tri; + int rc = SNMP_ERR_NOERROR; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_set_values","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + rowreq_ctx->column_set_flags = 0; + for(;requests; requests = requests->next) { + /* + * set column data + */ + tri = netsnmp_extract_table_info(requests); + if(NULL == tri) + continue; + + rc = _${context}_set_column(rowreq_ctx, + requests->requestvb, tri->colnum); + if(MFD_SUCCESS != rc) { + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_set_column\n", rc)); + netsnmp_set_request_error(agtreq_info, requests, SNMP_VALIDATE_ERR(rc)); + } + } /* for results */ + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_set_values */ + +/*---------------------------------------------------------------------- + * + * SET: commit + * + *---------------------------------------------------------------------*/ +/** + * @internal + * commit the values + */ +int +_mfd_${context}_commit(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_commit","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + rc = ${context}_commit(rowreq_ctx); + if (MFD_SUCCESS != rc) { + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_commit\n", rc)); + netsnmp_request_set_error_all(requests, SNMP_VALIDATE_ERR(rc)); + } + + if (rowreq_ctx->rowreq_flags & MFD_ROW_DIRTY) { + /* + * if we successfully commited this row, set the dirty flag. Use the + * current value + 1 (i.e. dirty = # rows changed). + * this is checked in post_request... + */ + ${context}_dirty_set( ${context}_dirty_get() + 1 ); /* set table dirty flag */ + } + + return SNMP_ERR_NOERROR; +} + +int +_mfd_${context}_undo_commit(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_undo_commit","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + if (rowreq_ctx->rowreq_flags & MFD_ROW_DIRTY) { + u_int d = ${context}_dirty_get(); + + netsnmp_assert(d != 0); + if(d) + ${context}_dirty_set( d - 1 ); + } + + rc = ${context}_undo_commit(rowreq_ctx); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo_commit\n", rc)); + } + + if (rowreq_ctx->rowreq_flags & MFD_ROW_DIRTY) { + snmp_log(LOG_WARNING, "${context} row dirty flag still set after undo_commit\n"); + rowreq_ctx->rowreq_flags &= ~MFD_ROW_DIRTY; + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_commit */ + +/*---------------------------------------------------------------------- + * + * SET: Undo + * + *---------------------------------------------------------------------*/ +/** + * @internal + * undo the value for a particular column + */ +NETSNMP_STATIC_INLINE int +_${context}_undo_column( ${context}_rowreq_ctx *rowreq_ctx, + netsnmp_variable_list *var, int column ) +{ + int rc = SNMPERR_SUCCESS; + + DEBUGMSGTL(("internal:${context}:_${context}_undo_column", + "called for %d\n", column)); + + netsnmp_assert(NULL != rowreq_ctx); + + switch(column) { +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 1@ + + /* $m2c_node_summary */ + case COLUMN_$node.uc: + rc = ${node}_undo(rowreq_ctx); + break; + @ end@ # settable +@ end@ # for each column + + default: + snmp_log(LOG_ERR,"unknown column %d in _${context}_undo_column\n", column); + break; + } + + return rc; +} /* _${context}_undo_column */ + +######################################################################## +## +int +_mfd_${context}_undo_values(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ + int rc; + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + netsnmp_table_request_info * tri; + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_undo_values","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + rc = ${context}_undo(rowreq_ctx); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo\n", rc)); + } + + for(;requests; requests = requests->next) { + /* + * set column data + */ + tri = netsnmp_extract_table_info(requests); + if(NULL == tri) + continue; + + rc = _${context}_undo_column(rowreq_ctx, requests->requestvb, + tri->colnum); + if (MFD_SUCCESS != rc) { + /* + * nothing we can do about it but log it + */ + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_undo_column\n", rc)); + } + } /* for results */ + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_undo_values */ + +/*---------------------------------------------------------------------- + * + * SET: irreversible commit + * + *---------------------------------------------------------------------*/ +/** + * @internal + * commit irreversible actions + */ +int +_mfd_${context}_irreversible_commit(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *agtreq_info, + netsnmp_request_info *requests) +{ +@ if $m2c_irreversible_commit == 1@ + int rc; +@ end@ + ${context}_rowreq_ctx *rowreq_ctx = + netsnmp_container_table_row_extract(requests); + + DEBUGMSGTL(("internal:${context}:_mfd_${context}_irreversible:commit","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +@ if $m2c_irreversible_commit == 1@ + rc = ${context}_irreversible_commit(rowreq_ctx); + if (MFD_SUCCESS != rc) { + netsnmp_request_set_error_all(requests, SNMP_ERR_COMMITFAILED); + DEBUGMSGTL(("${context}:mfd","error %d from " + "${context}_irreversible_commit\n", rc)); + } + +@ end@ + /* + * check for and handle row creation/deletion + * and update column exist flags... + */ + if (rowreq_ctx->rowreq_flags & MFD_ROW_DELETED) { + if (! (rowreq_ctx->rowreq_flags & MFD_ROW_CREATED)) + CONTAINER_REMOVE(${context}_if_ctx.container, rowreq_ctx); + } + else { + if (rowreq_ctx->column_set_flags) { +@if $m2c_table_sparse == 1@ + DEBUGMSGTL(("internal:${context}:_mfd_irreversible_commit", + "updating exists (%p) w/set (%p) = %p\n", + rowreq_ctx->column_exists_flags, + rowreq_ctx->column_set_flags, + (rowreq_ctx->column_exists_flags | + rowreq_ctx->column_set_flags))); + rowreq_ctx->column_exists_flags |= + rowreq_ctx->column_set_flags; +@end@ # sparse + rowreq_ctx->column_set_flags = 0; + } +@if ($m2c_table_row_creation == 1)@ + if (rowreq_ctx->rowreq_flags & MFD_ROW_CREATED) { + rowreq_ctx->rowreq_flags &= ~MFD_ROW_CREATED; + CONTAINER_INSERT(${context}_if_ctx.container, rowreq_ctx); + } +@end@ # creation + } + + return SNMP_ERR_NOERROR; +} /* _mfd_${context}_irreversible_commit */ + +@end@ # settable +/*********************************************************************** + * + * DATA ACCESS + * + ***********************************************************************/ +@ include mfd-access-${m2c_table_access}-defines.m2i@ +@ if $m2c_table_persistent == 1@ +@ include mfd-persistence.m2i@ +@ end@ + +${context}_rowreq_ctx * +${context}_row_find_by_mib_index(${context}_mib_index *mib_idx) +{ + ${context}_rowreq_ctx *rowreq_ctx; + oid oid_tmp[MAX_OID_LEN]; + netsnmp_index oid_idx; + int rc; + + /* + * set up storage for OID + */ + oid_idx.oids = oid_tmp; + oid_idx.len = sizeof(oid_tmp)/sizeof(oid); + + /* + * convert + */ + rc = ${context}_index_to_oid(&oid_idx, mib_idx); + if (MFD_SUCCESS != rc) + return NULL; + + rowreq_ctx = CONTAINER_FIND(${context}_if_ctx.container, &oid_idx); + + return rowreq_ctx; +} + +@ if $m2c_table_refcounts == 1@ +int +${context}_row_ref_increment(${context}_rowreq_ctx *rowreq_ctx) +{ + if (NULL == rowreq_ctx) + return -1; + + ++rowreq_ctx->ref_count; + DEBUGMSGTL(("${context}:${context}_row_ref_increment", + "row %p ref count is %d\n",rowreq_ctx, + rowreq_ctx->ref_count)); + + return MFD_SUCCESS; +} + +int +${context}_row_ref_decrement(${context}_rowreq_ctx *rowreq_ctx) +{ + if (NULL == rowreq_ctx) + return -1; + + if (0 == rowreq_ctx->ref_count) { + snmp_log(LOG_WARNING,"attempt to decrement ref_count below 0\n"); + return -2; + } + --rowreq_ctx->ref_count; + DEBUGMSGTL(("${context}:${context}_row_ref_decrement", + "row %p ref count is %d\n",rowreq_ctx, + rowreq_ctx->ref_count)); + + return MFD_SUCCESS; +} + +@ end@ // refcounts +@end@ # foreach table +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 15899 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-makefile.m2m b/local/mib2c-conf.d/mfd-makefile.m2m new file mode 100644 index 0000000..d94951c --- /dev/null +++ b/local/mib2c-conf.d/mfd-makefile.m2m @@ -0,0 +1,139 @@ +####################################################### -*- Makefile -*- +## $Id: mfd-makefile.m2m 12577 2005-07-25 15:37:02Z dts12 $ +## +######################################################################## +## +@strict token off@ +@ifconf ${name}_Makefile@ +@ print ${name}_Makefile exists, skipping@ +@else@ +@ if "x$m2c_create_fewer_files" eq "x"@ +@ eval $m2c_create_fewer_files = 0@ +@ end@ +@ open ${name}_Makefile@ +@ ifconf ${name}_Makefile.m2m@ +@ include ${name}_Makefile.m2m@ +@ else@ +######################################################################## +@ if $m2c_mark_boundary == 1@ +# START code generated by $RCSfile$ $Revision: 12577 $ +@ end@ +######################################################################## + +CC=gcc +TABLE_PREFIX=${name} + +@ if "$mfd_netsnmp_dir" ne ""@ +NETSNMPDIR=$mfd_netsnmp_dir +NETSNMPCONFIG=$(NETSNMPDIR)/net-snmp-config +@ else@ +NETSNMPCONFIG=net-snmp-config +@ end@ + +@ if "$mfd_netsnmp_dir" ne ""@ + +# Assuming we're linking against a Net-SNMP build tree (which may or +# may not be the same as the source tree) and not an installed package. + +# Note: to do this we REQUIRE gnu-make. + +NETSNMPBASECFLAGS := $(shell $(NETSNMPCONFIG) --base-cflags) +NETSNMPINCLUDES := $(shell $(NETSNMPCONFIG) --build-includes $(NETSNMPDIR)) +# base flags after build/src include, in case it has /usr/local/include +NETSNMPCFLAGS=$(NETSNMPINCLUDES) $(NETSNMPBASECFLAGS) + +NETSNMPBASELIBS := $(shell $(NETSNMPCONFIG) --base-agent-libs) +NETSNMPEXTLIBS := $(shell $(NETSNMPCONFIG) --external-agent-libs) +NETSNMPLIBDIRS := $(shell $(NETSNMPCONFIG) --build-lib-dirs $(NETSNMPDIR)) +NETSNMPLIBDEPS := $(shell $(NETSNMPCONFIG) --build-lib-deps $(NETSNMPDIR)) +LIB_DEPS=$(NETSNMPLIBDEPS) +LIBS=$(NETSNMPLIBDIRS) -Wl,-Bstatic $(NETSNMPBASELIBS) -Wl,-Bdynamic $(NETSNMPEXTLIBS) + +@ else@ + +# uncomment this if you have GNU make +#NETSNMPCFLAGS := $(shell $(NETSNMPCONFIG) --base-cflags) +#NETSNMPLIBS := $(shell $(NETSNMPCONFIG) --agent-libs) +NETSNMPCFLAGS=`$(NETSNMPCONFIG) --base-cflags` +NETSNMPLIBS=`$(NETSNMPCONFIG) --agent-libs` + +LIBS=$(NETSNMPLIBS) + +@ end@ + +STRICT_FLAGS = -Wall -Wstrict-prototypes +CFLAGS=-I. $(NETSNMPCFLAGS) $(STRICT_FLAGS) + +USER_SRCS = \ +@ if $m2c_create_fewer_files != 1@ + $(TABLE_PREFIX)_data_get.c \ + $(TABLE_PREFIX)_data_set.c \ +@ end@ + $(TABLE_PREFIX)_data_access.c + +SRCS = $(USER_SRCS) \ + $(TABLE_PREFIX).c \ + $(TABLE_PREFIX)_subagent.c \ + $(TABLE_PREFIX)_interface.c + +USER_OBJS = \ +@ if $m2c_create_fewer_files != 1@ + $(TABLE_PREFIX)_data_get.o \ + $(TABLE_PREFIX)_data_set.o \ +@ end@ + $(TABLE_PREFIX)_data_access.o + +OBJS = $(USER_OBJS) \ + $(TABLE_PREFIX).o \ + $(TABLE_PREFIX)_subagent.o \ + $(TABLE_PREFIX)_interface.o + +TARGETS=$(TABLE_PREFIX) + +.SUFFIXES: +.SUFFIXES: .c .o .deps + + +all: $(TARGETS) + +user: $(USER_OBJS) + +$(TARGETS): $(LIB_DEPS) + +$(TABLE_PREFIX): $(OBJS) $(TABLE_PREFIX)_Makefile + $(CC) -o $(TABLE_PREFIX) $(OBJS) $(LIBS) + +clean: + rm -f $(OBJS) $(TARGETS) + +@if "$mfd_netsnmp_dir" ne ""@ + +$(TABLE_PREFIX).deps $(TABLE_PREFIX)_subagent.deps $(TABLE_PREFIX)_interface.deps: $(TABLE_PREFIX)_Makefile +$(TABLE_PREFIX)_data_access.deps: $(TABLE_PREFIX)_Makefile +@if $m2c_create_fewer_files != 1@ +$(TABLE_PREFIX)_data_get.deps: $(TABLE_PREFIX)_Makefile +$(TABLE_PREFIX)_data_set.deps: $(TABLE_PREFIX)_Makefile +@end@ + +%.deps : %.c + \@echo "Generating makefile $\@ ..." + \@set -e; $(CC) -M $(COPTS) $(CFLAGS) $(CPPFLAGS) $< \ + | sed 's/\($*\)\.o[ :]*/\1.o $\@ : /g' > $\@; \ + [ -s $\@ ] || $(RM) $(RMFLAGS) $\@ + +include $(TABLE_PREFIX).deps +include $(TABLE_PREFIX)_subagent.deps +include $(TABLE_PREFIX)_interface.deps +include $(TABLE_PREFIX)_data_access.deps +@ if $m2c_create_fewer_files != 1@ +include $(TABLE_PREFIX)_data_get.deps +include $(TABLE_PREFIX)_data_set.deps +@ end@ +@end@ +######################################################################## +@ if $m2c_mark_boundary == 1@ +# END code generated by $RCSfile$ $Revision: 12577 $ +@ end@ +@ end@ # not including ${name}_Makefile.m2m +@ close ${name}_Makefile@ +@end@ # no existing makefile diff --git a/local/mib2c-conf.d/mfd-persistence.m2i b/local/mib2c-conf.d/mfd-persistence.m2i new file mode 100644 index 0000000..fc551af --- /dev/null +++ b/local/mib2c-conf.d/mfd-persistence.m2i @@ -0,0 +1,478 @@ +######################################################################## +## generic include for XXX. Do not use directly. +## $Id: mfd-persistence.m2i 15990 2007-03-23 09:19:51Z dts12 $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 15990 $ */ +@end@ +######################################################################## +@if $m2c_processing_type eq 'h'@ +/* ********************************************************************* + * Persistent declarations + */ +/* + * persistence + */ +#define LINE_TERM_CHAR '$' + +void ${context}_container_init_persistence( netsnmp_container * container ); +int ${context}_container_should_save(${context}_rowreq_ctx * rowreq_ctx); + +@end@ // m2c_processing_type eq 'h' +###################################################################### +###################################################################### +###################################################################### +@if $m2c_processing_type eq 'c'@ +/************************************************************ + * the *_should_save routine is called to determine if a row + * should be stored persistently. + * + * Note that this is not a 'dirty' check (i.e. if a row has changed), + * but a check for volatile rows that should not be saved between + * restarts. + * + * return 1 if the row should be stored + * return 0 if the row should not be stored + */ +int +${context}_container_should_save(${context}_rowreq_ctx * rowreq_ctx) +{ +@ foreach $node column@ +@ if "$node.syntax" eq "StorageType"@ +@ include m2c_setup_node.m2i@ + if (SNMP_STORAGE_VOLATILE == $m2c_ctx_rh ) + return 0; +@ end@ +@ end@ + + return 1; /* save the row */ +} + +@end@ // m2c_processing_type eq 'h' +###################################################################### +###################################################################### +###################################################################### +@if $m2c_processing_type eq 'i'@ +/*********************************************************************** + * + * PERSISTENCE + * + ***********************************************************************/ + +static int _${context}_container_save_rows(int majorID, int minorID, void *serverarg, void *clientarg); +static void _${context}_container_row_restore(const char *token, char *buf); +static int _${context}_container_row_save( + ${context}_rowreq_ctx *rowreq_ctx, + void *type); +static char * _${context}_container_col_restore( + ${context}_rowreq_ctx *rowreq_ctx, + u_int col, char* buf); +static char * _${context}_container_col_save( + ${context}_rowreq_ctx *rowreq_ctx, + u_int col, char* buf); + +static char row_token[] = "${context}"; + +/************************************************************ + * *_init_persistence should be called from the main table + * init routine. + * + * If your table depends on rows in another table, + * you should register your callback after the other table, + * which should ensure the rows on which you depend are saved + * (and re-created) before the dependent rows. + */ +void +${context}_container_init_persistence( netsnmp_container * container ) +{ + int rc; + + register_config_handler(NULL, row_token, + _${context}_container_row_restore, NULL, NULL); + rc = snmp_register_callback( SNMP_CALLBACK_LIBRARY, + SNMP_CALLBACK_STORE_DATA, + _${context}_container_save_rows, + container); + + if( rc != SNMP_ERR_NOERROR ) + snmp_log(LOG_ERR, "error registering for STORE_DATA callback " + "in _${context}_container_init_persistence\n"); +} + +static int +_${context}_container_save_rows(int majorID, int minorID, void *serverarg, void *clientarg) +{ + char sep[] = + "##############################################################"; + char buf[] = + "#\n" + "# $context persistent data\n" + "#"; + char *type = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_APPTYPE); + + read_config_store((char*)type, sep); + read_config_store((char*)type, buf); + + /* + * save all rows + */ + CONTAINER_FOR_EACH((netsnmp_container*)clientarg, + (netsnmp_container_obj_func*)_${context}_container_row_save, + type); + + read_config_store((char*)type, sep); + read_config_store((char*)type, "\n"); + + /* + * never fails + */ + return SNMPERR_SUCCESS; +} + + + +/************************************************************ + * _${context}_container_row_save + */ +static int +_${context}_container_row_save( + ${context}_rowreq_ctx *rowreq_ctx, + void *type) +{ + /* + * Allocate space for a line with all data for a row. An + * attempt is made to come up with a default maximum size, but + * there is no guarantee it will be enough. It probably will be, + * unless you are dealing with large values or you have external + * indexes. + * + * 1) allocate space for each column. Comment out columns you don't + * intend to save. You may also need to add room for any non- + * column data you want to store. Remeber, data will be stored in + * ASCII form, so you need to allow for that. Here are some + * general guidelines: + * + * Object ID : 12 * len [ASCII len of max int + 1 for .] + * Octet String: (2 * len) + 2 [2 ASCII chars per byte + "0x"] + * Integers : 12 [ASCII len for smallest negative number] + * + * 2) You also need to allocate space for the row index. This will + * be stored as an OID, which means that Octet Strings need to + * be treated a little differently. Specifically, you will need + * (4 * len) + 4 [3 ASCII chars per byte + 1 for ., + 4 for len]. + * + * 3) Also, remeber to add space for the identifier and seperator + * characters (for example, each column is prefixed by the + * column number and a semicolon. To allow for the maximum + * column values, 12 bytes [11 for oid + 1 for ':'] per + * column are added). + */ + /** xxx: add storage for external index(s)! */ +#define MAX_ROW_SIZE (sizeof(row_token) + 1 + \ +@ if $ext_index != 0@ + ( 12 * 128 ) + /* external interfaces - max 128 subids */ \ +@ end@ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if ($node.settable == 1)@ +@ if "$node.type" eq "ASN_OBJECT_ID"@ + ( ( 12 * sizeof(${m2c_ctx_rh}) ) + 3 ) + /* $node.type */ \ +@ elsif "$node.type" eq "ASN_OCTET_STR"@ + ( ( 2 * sizeof(${m2c_ctx_rh}) ) + 3 ) + /* $node.type */ \ +@ else@ + ( 12 ) + /* $node.type $node */ \ +@ end@ +@ end@ +@ end@ + ( $table.uc_MAX_COL * 12 ) + /* column num prefix + : */ \ + 2 /* LINE_TERM_CHAR + \n */ ) + + char buf[MAX_ROW_SIZE], *pos = buf, *max = &buf[MAX_ROW_SIZE-1]; + char *tmp; + int i; + + if (${context}_container_should_save(rowreq_ctx) == 0) { + return SNMP_ERR_NOERROR; + } + + /* + * build the line + */ + pos += sprintf(pos, "%s ", row_token); + pos = read_config_save_objid(pos, rowreq_ctx->oid_idx.oids, + rowreq_ctx->oid_idx.len); + if(NULL == pos) { + snmp_log(LOG_ERR,"error saving ${context} row " + "to persistent file\n"); + return SNMP_ERR_GENERR; + } + *pos++ = ' '; + if(pos > max) { + snmp_log(LOG_ERR,"error saving ${context} row " + "to persistent file (too long)\n"); + return SNMP_ERR_GENERR; + } + + /* + * add each column + */ + for(i = $table.uc_MIN_COL; i <= $table.uc_MAX_COL; ++i ) { + + if ((0x1 << (i-1)) & ~$context.uc_SETTABLE_COLS) + continue; + + tmp = pos; + pos = _${context}_container_col_save(rowreq_ctx, i, pos); + if(NULL == pos) + pos = tmp; + else + *pos++ = ' '; + if(pos > max) { + snmp_log(LOG_ERR,"error saving ${context} row " + "to persistent file (too long)\n"); + return SNMP_ERR_GENERR; + } + } + + /* + * if you have non-column data, add it here + */ + + + /* + * store the line + */ + pos += sprintf(pos, "%c", LINE_TERM_CHAR); + if(pos > max) { + snmp_log(LOG_ERR,"error saving ${context} row " + "to persistent file (too long)\n"); + return SNMP_ERR_GENERR; + } + read_config_store((char*)type, buf); + + DEBUGMSGTL(("internal:${context}:_${context}_container_row_save", + "saving line '%s'\n", buf)); + + return SNMP_ERR_NOERROR; +} + +static void +_${context}_container_row_restore(const char *token, char *buf) +{ + ${context}_rowreq_ctx * rowreq_ctx; + netsnmp_index index; + oid tmp_oid[ MAX_${context}_IDX_LEN]; + u_int col = 0, found = 0; + + + if (strncmp(token, row_token, sizeof(row_token)) != 0) { + snmp_log(LOG_ERR, "unknown token in _${context}_container_row_restore\n"); + return; + } + + DEBUGMSGTL(("internal:${context}:_${context}_container_row_restore", + "parsing line '%s'\n", buf)); + + /* + * pull out index and create default row + */ + index.oids = tmp_oid; + index.len = OID_LENGTH(tmp_oid); + buf = read_config_read_objid(buf, &index.oids, + &index.len); + if (NULL == buf) { + snmp_log(LOG_ERR, "error reading row index in " + "_${context}_container_row_restore\n"); + return; + } + rowreq_ctx = _mfd_${context}_rowreq_from_index( &index, NULL ); + if (NULL == rowreq_ctx) { + snmp_log(LOG_ERR, "error creating row index in " + "_${context}_container_row_restore\n"); + return; + } + + /* + * loop through and get each column + */ + buf = skip_white(buf); + while ( (NULL != buf) && isdigit(*buf) ) { + /* + * extract column, skip ':' + */ + col = (u_int)strtol(buf, &buf, 10); + if (NULL == buf) + break; + if (*buf != ':') { + buf = NULL; + break; + } + ++buf; /* skip : */ + + /* + * parse value + */ + DEBUGMSGTL(("_${context}_container_row_restore", + "parsing column %d\n", col)); + buf = _${context}_container_col_restore( rowreq_ctx, col, buf ); + ++found; + } + if (0 == found) { + snmp_log(LOG_ERR, "error parsing ${context} row; no columns found\n"); + ${context}_release_rowreq_ctx( rowreq_ctx ); + return; + } + + /* + * if you added any non-column data, this is where + * you should handle it. + */ + + /* + * if the pointer is NULL and we didn't reach the + * end of the line, something went wrong. Log message, + * delete the row and bail. + */ + if ((buf == NULL) || (*buf != LINE_TERM_CHAR)) { + snmp_log(LOG_ERR, "error parsing ${context} row around column %d\n", + col); + ${context}_release_rowreq_ctx( rowreq_ctx ); + return; + } + + DEBUGMSGTL(("internal:${context}:_${context}_container_row_restore", + "inserting row\n")); + + /* + * copy oid index and insert row + */ + rowreq_ctx->oid_idx.len = index.len; + memcpy(rowreq_ctx->oid_idx.oids, index.oids, index.len * sizeof(oid)); + + CONTAINER_INSERT(${context}_if_ctx.container, rowreq_ctx); +} + +/************************************************************ + * _${context}_container_col_save + */ +static char * +_${context}_container_col_save( + ${context}_rowreq_ctx *rowreq_ctx, + u_int col, char* buf) +{ + if( ( NULL == rowreq_ctx ) || ( NULL == buf )) { + snmp_log(LOG_ERR, "bad parameter in " + "_${context}_container_col_save\n"); + return NULL; + } + + DEBUGMSGTL(("internal:${context}:_${context}_container_col_save", + "processing column %d\n", col)); + + /* + * prefix with column number, so we don't ever depend on + * order saved. + */ + buf += sprintf(buf, "%u:", col); + + /* + * save data for the column + */ + switch(col) { + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + case COLUMN_$node.uc: /** $node.syntax = $node.type */ +@ if $m2c_node_needlength == 1@ +@ if "$node.type" eq "ASN_OBJECT_ID"@ + buf = read_config_save_objid(buf, ${m2c_ctx_rh}, + ${m2c_ctx_rhs} ); +@ else@ # "$node.type" eq "ASN_OCTET_STR"@ + buf = read_config_save_octet_string(buf, ${m2c_ctx_rh}, + ${m2c_ctx_rhs} ); +@ end@ +@ elsif "$node.type" eq "ASN_INTEGER"@ + buf += sprintf(buf,"%ld",${m2c_ctx_rh}); +@ else@ + buf += sprintf(buf,"%lu",${m2c_ctx_rh}); +@ end@ + break; + +@ end@ # for each + default: /** We shouldn't get here */ + snmp_log(LOG_ERR, "unknown column %d in " + "_${context}_container_col_save\n", col); + return NULL; + } + + return buf; +} + +/************************************************************ + * _${context}_container_col_restore + */ +static char * +_${context}_container_col_restore( + ${context}_rowreq_ctx *rowreq_ctx, + u_int col, char* buf) +{ + size_t len; + if( ( NULL == rowreq_ctx ) || ( NULL == buf )) { + snmp_log(LOG_ERR, "bad parameter in " + "_${context}_container_col_restore\n"); + return NULL; + } + + DEBUGMSGTL(("verbose:${context}:_${context}_container_col_restore", + "processing column %d\n", col)); + + /* + * restore data for the column + */ + switch(col) { + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ + case COLUMN_$node.uc: /** $node.syntax = $node.type */ +@ if $m2c_node_needlength == 1@ + ${m2c_ctx_rhs} = sizeof(${m2c_ctx_rh}); + buf = read_config_read_memory($node.type,buf, + (char*)&${m2c_ctx_rh}, + (size_t*)&${m2c_ctx_rhs} ); +@ if "$node.type" eq "ASN_OBJECT_ID"@ + ${m2c_ctx_rhs} /= sizeof(oid); +@ end@ +@ else@ + len = sizeof(${m2c_ctx_rh}); +@ if "$node.type" eq "ASN_OCTET_STR"@ # BITS +@ eval $m2c_tmp = "ASN_INTEGER"@ +@ else@ +@ eval $m2c_tmp = $node.type@ +@ end@ + buf = read_config_read_memory($m2c_tmp, buf, + (char*)&${m2c_ctx_rh}, + &len); +@ end@ +@ if $m2c_table_sparse == 1@ + if (NULL != buf) + rowreq_ctx->column_exists_flags |= COLUMN_$node.uc_FLAG; +@ end@ # table sparse + break; + +@ end@ # foreach col + default: /** We shouldn't get here */ + snmp_log(LOG_ERR, "unknown column %d in " + "_${context}_container_col_restore\n", col); + return NULL; + } + + return buf; +} + +## +@end@ // $m2c_processing_type eq 'i' +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 15990 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-readme.m2c b/local/mib2c-conf.d/mfd-readme.m2c new file mode 100644 index 0000000..9aeef10 --- /dev/null +++ b/local/mib2c-conf.d/mfd-readme.m2c @@ -0,0 +1,846 @@ +######################################################################## +## generic include for XXX. Don't use directly. +## +## $Id: mfd-readme.m2c 12091 2005-04-18 22:05:47Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12091 $ */ +@end@ +######################################################################## +## +@open ${name}-README-FIRST.txt@ +************************************************************************ +${name} README +------------------------------------------------------------------------ +This document describes the results of the mib2c code generation +system using the mfd code generation template. The resulting files +are documented both in this README file as well as per-table specific +README files. All of the files generated by this run of mib2c will +begin with the ${name} prefix. + +Quick Start +----------- +For those interested in a quick start, to get a pseudo-todo list, try +this command in directory with the generated code: + + grep -n "TODO:" *.[ch] | sed 's/\([^ ]*\) \(.*\)TODO\(.*\)/\3 (\1)/' | sort -n + +Key: + :o: Optional + :r: Recommended + :M: Mandatory + :A: Advanced users + +This will give you and ordered list of places in the code that you +may (or must) take a closer look at). + +You may also want to take a look at the on-line tutorial, found here: + + http://www.net-snmp.org/tutorial/tutorial-5/toolkit/mfd/index.html + + +MIBs For Dummies Overview +------------------------- +The MIBs For Dummies (MFD) configuration files have been written to help +SNMP novices implement SNMP MIBs. This section will be a brief +introduction to some of the general concepts you should be familar with. + + Managed Information Base (MIB) + ------------------------------ + A SNMP MIB (Managed information base) is a text file that describes the + syntax for some set of data objects. The MIB creates a correlation + between an ASCII name for an object and a number OID (Object Identifier). + The SNMP protocol communicates information using the OIDs, and the MIB + allows tools to display a name, which we humans find easier to deal with. + + To use an analogy, a MIB is much like a menu at a restaurant. If you've + ever been to a reataurant and ordered a meal, and later received a bill + that simply had '#6' on it, you get the idea. The name is easier for + the customers to remember, and the waiters and chefs use the number for + efficency. + + + Scalars + ------- + A scalar variable is a unique object in a MIB which can represent + a single value. For example, the SNMP standard MIB-II defines a + variable, sysContact.0, which is a string containing the contact + information for the person in charge of a particular agent. Note + that scalar variable always end with '.0'. + + + Rows and Tables + --------------- + When a group of related attributes occur more than once, they can be + grouped together in a table. A table has an index, which uniquely + identifies a particular row, and data columns, which contain the + attributes for that row. + + For example, the SNMP standard MIB-II defines a table, ifTable, which + contains information on the ethernet interfaces on a system. + + + Data Structures + --------------- + The code generated by the MFD configuration files has a few important + structures. + + + The Data Context + ---------------- + The data context structure should contain the necessary information + to provide the data for the columns in a given row. As long as you + can extract the data for a column for the data context, the data context + can be anything you want: a pointer to an existing structure, the + parameters needed for a function call or an actual copy of the data. + + By default, a data context structure is generated with storage for + all the data in a row. Information on changing the default is presented + later on in this help. + + + The MIB Context + --------------- + The MIB context structure is generated with storage for all the + indexes of a table. This data will be used when searching for the + correct row to process for a request. + + + The Row Request Context + ----------------------- + Each table will have a unique data structure for holding data during + the processing of a particular row. The row request context contains + the registration context (that you supply during initilization), + the data context, the MIB context, the undo context (for settable + tables) and other data. There is also a netsnmp_data_list, which can + be used to temporary storage during processing. + + + The Table Registration Pointer + ------------------------------ + During initilization, you may provide a pointer to arbitrary data for + you own use. This pointer will be saved in the row request context, + and is passed as a parameter to several functions. It is not required, + and is provided as a way for you to access table specific data in + the generated code. + + + +These files are top-level files potentially useful for all the tables: +------------------------------------------------------------------------ + + File : ${name}_Makefile + ---------------------------------------------------------------------- + Purpose : Make file for compiling a (sub)agent. This file is only + useful if you don't want to compile your code directly + into the Net-SNMP master agent. + Editable: Optional + Usage : make -f ${name}_Makefile + + + File : ${name}_subagent.c + ---------------------------------------------------------------------- + Purpose : This file contains a main() function for an agent or + sub-agent and is compiled using the Makefile above. + + + + +Table specific README files +------------------------------------------------------------------------ +Each table for which code was generated has its own README file +describing the files specifically associated with each table. You +should probably read these next: + +@foreach $table table@ +@ include m2c_setup_table.m2i@ + ${name}-README-${table}.txt +@end@ + + + +These are miscellaneous auto-generated code files you generally +shouldn't edit. They contain code that ties your code together with +the Net-SNMP agent. +------------------------------------------------------------------------ +@if $m2c_create_fewer_files == 1@ + File : ${name}.c + Purpose : Initilization for the entire module set, including the + SNMP tables. + +@end@ + File : ${name}.h + Purpose : Header file for the module set. Includes config_require + macros to auto-load the other code pieces when compiled + into the agent. + +@if $m2c_create_fewer_files != 1@ + File : ${name}_oids.h + Purpose : C #define definitions of the tables, columns, and OIDs + + File : ${name}_enums.h + Purpose : C #define definitions of the enumerated type values for + each column of each table that requires them. +@else@ + File : ${name}_constants.h + Purpose : C #define definitions of the tables, columns, OIDs, enumerated + type values for each column of each table that requires them. +@end@ + + File : ${name}_interface.c + Purpose : MFD interface to Net-SNMP. This auto-generated code ties the + functions you will fill out to the code that the agent needs. + +######################################################################## +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ open ${name}-README-${table}.txt@ +************************************************************************ +${context} README +------------------------------------------------------------------------ + This readme file describes the code generated by mib2c (using the MIBs + for Dummies (MFD) configuration file). The code generated was + generated specifically for the following SNMP table: + + ${context} + + Your code will be called when the snmp agent receives requests for + the ${context} table. The agent will start by looking for the right + row in your existing data to operate on, if one exists. + + + Configuration Variables + ------------------------------------------------------------ + Some variables used for code generation may be set to affect the code + generation. You may override these variables by setting them in the + file ${m2c_defaults_dir}table-${context}.m2d, and then re-running mib2c. + + m2c_table_settable (currently '$m2c_table_settable') + -------------------------------------------------------- + This variable determines whether or not code is generated to support + MIB object which have an access of read-write or read-create. The + default is set based on whether or not the table contains writable + objects, but can be over-ridden. + + Syntax: @eval $@m2c_table_settable = 0@ + + + m2c_table_dependencies (currently '$m2c_table_dependencies') + -------------------------------------------------------- + This variable determines whether or not code is generated to support + checking dependencies between columns, rows or tables. The default + is set based on whether or not the table contains writable objects, + but can be over-ridden. + + Syntax: @eval $@m2c_table_dependencies = 0@ + + + m2c_table_row_creation (currently '$m2c_table_row_creation') + -------------------------------------------------------- + This variable determines whether or not code is generated to support + checking creation of new rows via SNMP. The default is set based on + whether or not the table contains read-create objects, but can be + over-ridden. + + Syntax: @eval $@m2c_table_row_creation = 0@ + + + m2c_context_reg (currently '$m2c_context_reg') + -------------------------------------------------------- + This variable contains the structure name to typedef for the + ${context}_registration. + + During initilization, you will provide a pointer to a structure of + this type. This pointer is used as a parameter to many functions so + that you have access to your registration data. The default is a + netsnmp_data_list pointer, which will allow you to keep multiple + pointers tagged by a text name. If you have a new or existing structure + you would rather use, you can redefine this variable. + + + To avoid regenerating code, you may also change this typedef directly + in the ${table}.h header. + + Syntax: @eval $@m2c_context_reg = "struct my_registration_context@ + + + m2c_data_context (currently '$m2c_data_context') + -------------------------------------------------------- + This variable contains the structure name to typedef for the + ${context}_data. + + This typedef is used in the row request context structure for the table, + ${context}_rowreq_ctx. + + The typedef in the primary table context will be used for the data and + undo structure types. This structure should contain all the data + needed for all the columns in the table. The default is 'generated', + which will cuase a new data strcuture to be generated with data members + for each column. + + To avoid regenerating code, you may also change this typedef directly + in the ${table}.h header. + + Syntax: @eval $@m2c_data_context = "struct my_data_context"@ + + + m2c_data_allocate (currently '$m2c_data_allocate') + -------------------------------------------------------- + This variable determines whether or not the data context (see above) + requires memory to be allocated. The default generated data structure + does not. If you are using a custom data context which needs to + allocate memory, override this value and two additional functions + will be generated: + + ${context}_allocate_data + ${context}_release_data + + Syntax: @eval $@m2c_data_allocate = 1@ + + + m2c_data_init (currently '$m2c_data_init') + -------------------------------------------------------- + This variable determines whether or not the data context (see above) + or any other items you have added to the table context requires + initialization. The default generated data structure does not. If you + are using a custom data context or have added items needing initialization + to the table context, override this value and two additional functions + will be generated: + + ${context}_rowreq_ctx_init + ${context}_rowreq_ctx_cleanup + + Syntax: @eval $m2c_data_init = 1@ + + + m2c_table_access (currently '$m2c_table_access') + ------------------------------------------------------------------ + This variable determines which data interface will be use to generate + code for looking up data for a given index. The default is the + 'container-cached' access code, which caches the data in a netsnmp- + container (usually a sorted array). + + Available options can be determined by checking for mib2c configuration + files that begin with 'mfd-access-*'. + + Syntax: @eval $@m2c_table_access = '$m2c_table_access'@ + + + m2c_include_examples (currently '$m2c_include_examples') + ------------------------------------------------------------------ + This variable determines whether or not to generate example code. The + default is to generate example code. + + Syntax: @eval $@m2c_include_examples = 0@ + + + m2c_data_transient (currently '$m2c_data_transient') + ------------------------------------------------------------------ + This variable determines how the generated example code deals with the + data during data lookup. See the table readme file for details on how + the current table access method interprets this value. In general, + a value of 0 indicates persistent data, 1 indicates semi-transient and + 2 indicates transient data. + + Syntax: @eval $@m2c_data_transient = 0@ + + + Index(es) for the ${context} table + ------------------------------------------------------------ + The index(es) for the ${context} table are: + +@foreach $node index@ +@ include m2c_setup_node.m2i@ + $node: + Syntax: $node.syntax + DataType: $node.perltype + ASN type: $node.type + C-code type: $m2c_decl +@end@ # foreach + + You should know how to set all these values from your data context, + ${context}_data. + + +************************************************************************ +${context} File Overview +------------------------------------------------------------------------ + Several files have been generated to implement the ${context} + table. We'll go through these files, one by one, explaining each and + letting you know which you need to edit. + + +File: ${name}_data_access.[c|h] +------------------------------------------------------------------------ + The ${name}_data_access file contains the interface to your data in + its raw format. These functions are used to build the row cache or + locate the row (depending on the table access method). + + Set MIB context + ----------------- + TODO : Set MIB index values + FUNC : ${context}_indexes_set + WHERE: ${context}_data_access.c + + This is a convenience function for setting the index context from + the native C data. Where necessary, value mapping should be done. + +@if $mfd_readme_verbose == 1@ + This function should update the table index values (found in + tbl_idx) for the given raw data. + +@end@ + +@ eval $m2c_processing_type = 'r'@ +@ include mfd-access-${m2c_table_access}-defines.m2i@ + + +@if $m2c_create_fewer_files != 1@ +File: ${name}_enums.h +@else@ +File: ${name}_constants.h +@end@ +------------------------------------------------------------------------ + This file contains macros for mapping enumeration values when the + enumerated values defined by the MIB do not match the values used + internally. + + Review this file to see if any values need to be updated. + + +@if $m2c_create_fewer_files != 1@ +File: ${name}_data_get.c +@else@ +File: ${name}.c; GET support +@end@ +------------------------------------------------------------------------ +@ if ("$m2c_data_allocate" eq "yes") && ("$m2c_data_context" ne "generated")@ + Allocate data context + --------------------- + TODO : allocate memory for a data context + FUNC : ${context}_allocate_data + + This function will be called to allocate memory for a data context + when a new row request context is being created, or to create an + undo context while processing a set request. + + Release data context + ------- + TODO : release memory allocated for a data context + FUNC : ${context}_release_data + + This function will be called to release any resources held by a + data or undo context. It will be called when a row request context + is released, or during cleanup after a set request. + + +@ end@ +@ foreach $node index@ +@ include m2c_setup_node.m2i@ +@ if ($m2c_skip_mapping != 1)@ + Map native data to MIB format + ----------------------------- + TODO : convert data from its native format to the format required by the MIB + FUNC : ${node}_map + + This function should map between the native format of the node data to + the format or values required by the MIB. For example, a C boolean value + for a MIB node with the TruthValue syntax needs to map the value C + false(0) to TruthValue false(2). + +@ end@ #// skip mapping +@ end@ // foreach index +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if ($m2c_skip_mapping != 1)@ + Map native data to MIB format + ----------------------------- + TODO : convert data from its native format to the format required by the MIB + FUNC : ${node}_map + + This function should map between the native format of the node data to + the format or values required by the MIB. For example, a C boolean value + for a MIB node with the TruthValue syntax needs to map the value C + false(0) to TruthValue false(2). + +@ end@ #// skip mapping + Get data for column + ------------------- + TODO : retrieve column data from raw data + FUNC : ${node}_get + +@ ifconf syntax-$node.syntax-readme.m2i@ +@ include syntax-$node.syntax-readme.m2i@ +@ elsif ($node.enums == 1) && ("$node.perltype" eq "BITS")@ + Since this column has enumerated BITS, you should update or replace the + IS_SET_* macros to properly determine whether or not a particular bit + should be set. + +@ end@ +@ end@ + + +@if $m2c_create_fewer_files != 1@ +File: ${name}_data_set.c +@else@ +File: ${name}.c; SET support +@end@ +------------------------------------------------------------------------ + +@if $m2c_table_settable == 0@ + This table does not support set requests. +@else@ + This code was generated based on the following assumptions or settings: + +@ if $m2c_table_dependencies == 1@ + 1) None of the values for this table have DEPENDENCIES on other objects. +@ else@ + 1) Some of the values for this table have DEPENDENCIES on other objects. +@ end@ + +@ if $mfd_readme_verbose != 0@ + DEPENDENCIES on other objects complicates SET request processing. When + one or more columns in a table depend on another object (in the same + table, or in another table), a DEPENDENCY exists. For example, if you + have a table that determine a color with three columns (red, green and + blue) that define the percentage of each primary color, the total for + the three columns must equal 100 percent. So, in addition to checking + that each colums has a valid value between 0 and 100, the total of + all three columns must equal 100. + + Set $@m2c_table_dependencies = 0 in ${m2c_defaults_dir}table-${table}.m2d + and regenerate code if this assumption is incorrect. +@ end@ + +@if $m2c_table_row_creation == 1@ + 2) This table supports ROW CREATION. +@else@ + 2) This table does not support ROW CREATION. +@end@ + +@if $mfd_readme_verbose != 0@ + Supporting ROW CREATION allows new rows to be created via SNMP requests. +@end@ +@if $m2c_table_row_creation == 1@ + + To support row creation, the index component of an incoming set request must + be validated. A funciton is generated for each individual index component, + and another for validating all the index components together. + +@ foreach $node externalindex@ +@ include m2c_setup_node.m2i@ + Validate external index + ----------------------- + TODO : validate the specified external index component + FUNC : ${context}_${node}_check_index + +@ end@ # foreach externalindex + +@ foreach $node internalindex@ +@ include m2c_setup_node.m2i@ + Validate index component + ------------------------ + TODO : validate the specified index component + FUNC : ${node}_check_index + +@ end@ + + Validate index + -------------- + TODO : check that all index components are valid + FUNC : ${context}_validate_index +@end@ + + +@ if $m2c_table_dependencies == 1@ + Check dependencies + ------------------ + TODO : check that all dependencies have been satisfied + FUNC : ${context}_check_dependencies + + This function will be called after all the individual columns have been + set to their new values. Check for any dependencies between rows or + tables in this function. + +@ end@ + + Undo setup + ---------- + TODO : save data for undo + FUNC : ${context}_undo_setup + + This function will be called before the individual undo_setup functions are + called. This is where you should save any undo information which is not + directly related to a particular column. This function will only be called + once per row. After this function is called, any column which is being + set will have its individual node undo_setup function called. + + + +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 0@ +@ next@ # skip to next column +@ end@ + Check value for column + ---------------------- + TODO : perform additional validations on values for a set request + FUNC : ${node}_check_value + + The generated code will automatically validate incoming requests against + all the requirements specified by the syntax of the MIB. However, it is + often the case that additional requirements are specified in the + description of a MIB object. Those type of validations should be checked + in this function. + + + Undo setup for column + --------------------- + TODO : save the value for column + FUNC : ${node}_undo_setup + + After the table level undo setup function has been called, the individual + node undo setup functions will be called for columns which are being set. + + + Set value for column + -------------------- + TODO : set the value for column + FUNC : ${node}_set + + After all the validations have been passed, this function will be called to + set the new value. + + + Undo value for column + --------------------- + TODO : undo set for column + FUNC : ${node}_undo + + If an error occurs after a column has been set, this function will be called + to undo the set and restore the previous state. + +@ end@ # nonindex + + + Commit changes + -------------- + TODO : commit changes + FUNC : ${context}_commit + + After all values have been set, the commit function will be called. + + +@ if $m2c_irreversible_commit == 1@ + Commit irreversible changes + --------------------------- + FUNC: ${context}_irreversible_commit + + This special mode is reserved for committing changes which can not be undone. + (e.g. launching a rocket). It is called after all normal commits have + succeeded. +@ end@ + +@end@ # settable + + +************************************************************************ +${context} Reference +------------------------------------------------------------------------ + +Function flow +---------------------------------------------------- +To give you the general idea of how the functions flow works, this +example flow is from a complete table implementation. + +NOTE: Depending on your configuration, some of the functions used in the + examples below may not have been generated for the + ${context} table. + + Conversely, the examples below may not include some functions that + were generated for the ${context} table. + +To watch the flow of the ${context} table, use the +following debug tokens: + + snmp_agent + helper:table:req + ${context} + verbose:${context} + internal:${context} + +e.g. + snmpd -f -Le -D${context},verbose:${context},internal:${context} + + +@if $m2c_create_fewer_files == 1@ +@ eval $tmp_mfd_rm_set = "xxx.c"@ +@ eval $tmp_mfd_rm_get = "xxx.c"@ +@else@ +@ eval $tmp_mfd_rm_set = "xxx_data_set.c"@ +@ eval $tmp_mfd_rm_get = "xxx_data_get.c"@ +@end@ +Initialization +-------------------------------- +init_xxxTable: called xxx.c + initialize_table_xxxTable xxx.c + _xxxTable_initialize_interface xxx_interface.c + xxxTable_init_data xxx_data_access.c + _xxxTable_container_init xxx_interface.c + xxxTable_container_init xxx_data_access.c + + +GET Request +-------------------------------- +_cache_load xxx_interface.c + xxxTable_cache_load xxx_data_access.c + xxxTable_allocate_rowreq_ctx xxx_interface.c + xxxTable_allocate_data $tmp_mfd_rm_get + xxxTable_rowreq_ctx_init $tmp_mfd_rm_get + xxxTable_indexes_set $tmp_mfd_rm_get + xxxTable_indexes_set_tbl_idx $tmp_mfd_rm_get + +xxxTable_pre_request + +_mfd_xxxTable_object_lookup xxx_interface.c + xxxTable_row_prep xxx_data_access.c + +_mfd_xxxTable_get_values xxx_interface.c + _mfd_xxxTable_get_column xxx_interface.c + yyy_get $tmp_mfd_rm_get + +xxxTable_post_request + + +GETNEXT Request +-------------------------------- +_cache_load ... +xxxTable_pre_request ... +_mfd_xxxTable_object_lookup ... +_mfd_xxxTable_get_values ... +xxxTable_post_request ... + + +SET Request: success +-------------------------------- +_cache_load ... +xxxTable_pre_request +_mfd_xxxTable_object_lookup ... + +_mfd_xxxTable_check_objects xxx_interface.c + _xxxTable_check_column xxx_interface.c + yyy_check_value $tmp_mfd_rm_set + +_mfd_xxxTable_undo_setup xxx_interface.c + xxxTable_allocate_data ... + xxxTable_undo_setup xxx_interface.c + _xxxTable_undo_setup_column xxx_interface.c + yyy_undo_setup $tmp_mfd_rm_set + +_mfd_xxxTable_set_values xxx_interface.c + _xxxTable_set_column xxx_interface.c + yyy_set $tmp_mfd_rm_set + +_mfd_xxxTable_check_dependencies xxx_interface.c + xxxTable_check_dependencies $tmp_mfd_rm_set + +_mfd_xxxTable_commit xxx_interface.c + xxxTable_commit $tmp_mfd_rm_set + +_mfd_xxxTable_undo_cleanup xxx_interface.c + xxxTable_undo_cleanup $tmp_mfd_rm_set + xxxTable_release_data ... + +xxxTable_post_request ... + + +SET Request: row creation +-------------------------------- +_cache_load ... +xxxTable_pre_request + +_mfd_xxxTable_object_lookup ... + xxxTable_index_from_oid xxx_interface.c + xxxTable_allocate_rowreq_ctx ... + ... + _xxxTable_check_indexes xxx_interface.c + yyy_check_index $tmp_mfd_rm_set + xxxTable_validate_index $tmp_mfd_rm_set + +_mfd_xxxTable_check_objects ... + _xxxTable_check_column ... + yyy_check_value ... + _xxxTable_check_column ... + yyy_check_value ... + +_mfd_xxxTable_undo_setup ... +_mfd_xxxTable_set_values ... +_mfd_xxxTable_check_dependencies ... +_mfd_xxxTable_commit ... +_mfd_xxxTable_undo_cleanup ... +xxxTable_post_request ... + + +SET Resuest: value error +-------------------------------- +_cache_load ... +xxxTable_pre_request ... +_mfd_xxxTable_object_lookup ... + +_mfd_xxxTable_check_objects ... + _xxxTable_check_column ... + yyy_check_value ... + ERROR:"yyy value not supported" + +xxxTable_post_request ... + + +SET Request: commit failure +-------------------------------- +_cache_load ... +xxxTable_pre_request ... +_mfd_xxxTable_object_lookup ... +_mfd_xxxTable_check_objects ... +_mfd_xxxTable_undo_setup ... +_mfd_xxxTable_set_values ... +_mfd_xxxTable_check_dependencies ... + +_mfd_xxxTable_commit ... + xxxTable_commit ... + ERROR: bad rc -1 + +_mfd_xxxTable_undo_commit xxx_interface.c + xxxTable_undo_commit $tmp_mfd_rm_set + +_mfd_xxxTable_undo_values xxx_interface.c + _xxxTable_undo_column xxx_interface.c + yyy_undo $tmp_mfd_rm_set + +_mfd_xxxTable_undo_cleanup ... +xxxTable_post_request ... + + +Row release (user initiated) +-------------------------------- +xxxTable_release_rowreq_ctx xxx_interface.c + xxxTable_rowreq_ctx_cleanup $tmp_mfd_rm_get + xxxTable_release_data $tmp_mfd_rm_get + + + +Table / column details +---------------------------------------------------- +@ include details-table.m2i@ + +@ foreach $node column@ +@ include m2c_setup_node.m2i@ +@ include details-node.m2i@ +@ end@ + +@end@ # foreach table + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12091 $ */ +@end@ diff --git a/local/mib2c-conf.d/mfd-top.m2c b/local/mib2c-conf.d/mfd-top.m2c new file mode 100644 index 0000000..2d236b2 --- /dev/null +++ b/local/mib2c-conf.d/mfd-top.m2c @@ -0,0 +1,605 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## $Id: mfd-top.m2c 14170 2006-01-26 17:02:48Z dts12 $ +######################################################################## +######################################################################## +## +## mfd function params +## +@ifconf ${name}.m2d@ +@ include ${name}.m2d@ +@end@ +## +## set up defaults +## +@foreach $table table@ +@ include default-mfd-top.m2c@ # get defaults +@ eval $context = $table@ +## +## set up defaults +## +@ print Defaults for $table...@ +@ eval $m2c_context_reg = "$mfd_default_context_reg"@ +@ eval $m2c_data_allocate = $mfd_default_data_allocate@ +@ eval $m2c_data_cache = $mfd_default_data_cache@ +@ eval $m2c_data_context = "$mfd_default_data_context"@ +@ eval $m2c_data_init = $mfd_default_data_init@ +@ eval $m2c_data_transient = $mfd_default_data_transient@ +@ eval $m2c_include_examples = $mfd_default_include_examples@ +@ eval $m2c_irreversible_commit = 0@ +@ eval $m2c_table_access = "$mfd_default_table_access"@ +@ eval $m2c_table_dependencies = table_is_writable($context)@ +@ eval $m2c_table_persistent = 0@ +@ eval $m2c_table_row_creation = table_has_create($context)@ +@ eval $m2c_table_settable = table_is_writable($context)@ +@ eval $m2c_table_skip_mapping = -1@ # -1 = no default; based on type +@ eval $m2c_table_sparse = 0@ +@ eval $mfd_generate_makefile = $mfd_default_generate_makefile@ +@ eval $mfd_generate_subagent = $mfd_default_generate_subagent@ +## +## allow for user override, or save defaults +## +@ ifconf default-table-${context}.m2d@ +@ print Warning: using defaults in current directory. Consider moving@ +@ print them to $m2c_defaults_dir.@ +@ eval $m2c_defaults_dir = "default-"@ +@ end@ +@ ifconf ${m2c_defaults_dir}table-${context}.m2d@ +@ if $mfd_interactive_setup == 1@ +@ print There are existing defaults for $context (${m2c_defaults_dir}table-${context}.m2d).@ +@ prompt $ans r)econfigure or u)se existing [default=u] : @ +@ if "x$ans" eq "xr"@ +@ eval $mfd_interactive_setup = -1@ # already asked to overwrite +@ run -again mfd-interactive-setup.m2c@ +@ eval $mfd_interactive_setup = 1@ +@ else@ +## ## read in old, write them back (this should add any new vars +@ include ${m2c_defaults_dir}table-${context}.m2d@ +@ include m2c_table_save_defaults.m2i@ +@ end@ +@ end@ +@ else@ # no existing defaults +@ ifdir defaults@ +## NOP +@ else@ +@ perleval my $rc = mkdir(defaults,0775); return $rc != 1 @ +@ end@ +@ run mfd-interactive-setup.m2c@ +@ end@ # no conf file +@end@ # foreach table +@if $m2c_gen_table_defaults == 1@ +@ exit@ +@end@ +@print Starting MFD code generation...@ +######################################################################## +@eval $m2c_processing_type = 'h'@ +@open ${name}.h@ +@eval $hack = "Id"@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 14170 $ of $RCSfile$ + * + * $$hack:$ + */ +@include generic-header-top.m2i@ + +/** @addtogroup misc misc: Miscellaneous routines + * + * @{ + */ +@if $m2c_mark_boundary == 1@ +/** START header generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +#include + +/* other required module components */ + /* *INDENT-OFF* */ +config_add_mib($name.module) +config_require($name.module/${name}/${name}_interface) +config_require($name.module/${name}/${name}_data_access) +@if $m2c_create_fewer_files != 1@ +config_require($name.module/${name}/${name}_data_get) +config_require($name.module/${name}/${name}_data_set) + /* *INDENT-ON* */ + +/* OID and column number definitions for $context */ +#include "${name}_oids.h" + +/* enum definions */ +#include "${name}_enums.h" +@else@ + /* *INDENT-ON* */ + +/* OID, column number and enum definions for $context */ +#include "${name}_constants.h" +@end@ // m2c_create_fewer_files + +/* ********************************************************************* + * function declarations + */ +void init_$name(void); +void shutdown_$context(void); + +/* ********************************************************************* + * Table declarations + */ +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ include details-table.m2i@ +/* ********************************************************************* + * When you register your mib, you get to provide a generic + * pointer that will be passed back to you for most of the + * functions calls. + * + * TODO:100:r: Review all context structures + */ + /* + * TODO:101:o: |-> Review $context registration context. + */ +@ if "x$m2c_context_reg" eq "x"@ +@ eval $m2c_context_reg = "netsnmp_data_list"@ +@ end@ +typedef $m2c_context_reg ${context}_registration; + +@ include generic-data-context.m2i@ + +@ if $m2c_table_settable@ +/* ********************************************************************* + * TODO:115:o: |-> Review $context undo context. + * We're just going to use the same data structure for our + * undo_context. If you want to do something more efficent, + * define your typedef here. + */ +typedef ${context}_data ${context}_undo_data; + +@ end@ +@ include generic-table-indexes.m2i@ + +/* ********************************************************************* + * TODO:130:o: |-> Review $context Row request (rowreq) context. + * When your functions are called, you will be passed a + * ${context}_rowreq_ctx pointer. + */ +typedef struct ${context}_rowreq_ctx_s { + + /** this must be first for container compare to work */ + netsnmp_index oid_idx; +## /* xxx-rks: shrink index oid_tmp? */ + oid oid_tmp[MAX_${context}_IDX_LEN]; + + ${context}_mib_index tbl_idx; + +@ if $m2c_data_allocate == 1@ +@ eval $mfd_tmp = "*"@ +@ else@ +@ eval $mfd_tmp = " "@ +@ end@ + ${context}_data $mfd_tmp data; +@ if $m2c_table_sparse == 1@ + unsigned int column_exists_flags; /* flags for existence */ +@ end@ +@ if $m2c_table_settable@ +@ if $m2c_undo_embed == 1@ +@ eval $mfd_tmp = " "@ +@ else@ +@ eval $mfd_tmp = "*"@ +@ end@ # embed + ${context}_undo_data $mfd_tmp undo; + unsigned int column_set_flags; /* flags for set columns */ + +@ end@ # settable + + /* + * flags per row. Currently, the first (lower) 8 bits are reserved + * for the user. See mfd.h for other flags. + */ + u_int rowreq_flags; +@ if $m2c_table_refcounts == 1@ + u_int ref_count; +@ end@ + + /* + * TODO:131:o: | |-> Add useful data to $context rowreq context. + */ + + /* + * storage for future expansion + */ + netsnmp_data_list *${context}_data_list; + +} ${context}_rowreq_ctx; + +typedef struct ${context}_ref_rowreq_ctx_s { + ${context}_rowreq_ctx *rowreq_ctx; +} ${context}_ref_rowreq_ctx; + +/* ********************************************************************* + * function prototypes + */ +## { + int ${context}_pre_request(${context}_registration * user_context); + int ${context}_post_request(${context}_registration * user_context, + int rc); + +@ if $m2c_data_init == 1@ + int ${context}_rowreq_ctx_init(${context}_rowreq_ctx *rowreq_ctx, + void *user_init_ctx); + void ${context}_rowreq_ctx_cleanup(${context}_rowreq_ctx *rowreq_ctx); + +@ end@ +@ if "$m2c_data_context" ne "generated"@ +@ if ($m2c_data_allocate == 1) || ($m2c_undo_embed == 1)@ + ${context}_data * ${context}_allocate_data(void); + void ${context}_release_data(${context}_data *data); + +@ end@ +@ end@ +@ if $m2c_table_settable@ +@ if $m2c_table_dependencies == 1@ + int ${context}_check_dependencies(${context}_rowreq_ctx * rowreq_ctx); +@ end@ + int ${context}_commit(${context}_rowreq_ctx * rowreq_ctx); +@ if $m2c_irreversible_commit == 1@ + int ${context}_irreversible_commit(${context}_rowreq_ctx * rowreq_ctx); +@ end@ +@ end@ # writable + + ${context}_rowreq_ctx * + ${context}_row_find_by_mib_index(${context}_mib_index *mib_idx); + +@ if $m2c_table_refcounts == 1@ +int ${context}_row_ref_increment(${context}_rowreq_ctx *rowreq_ctx); +int ${context}_row_ref_decrement(${context}_rowreq_ctx *rowreq_ctx); + +@ end@ +extern oid ${context}_oid[]; +extern int ${context}_oid_size; + +@end@ # for each + +#include "${name}_interface.h" +#include "${name}_data_access.h" +@if $m2c_create_fewer_files != 1@ +#include "${name}_data_get.h" +#include "${name}_data_set.h" +@else@ +@ eval $mfd_processing_types = "h"@ +@ include mfd-data-get.m2c@ +@ include mfd-data-set.m2c@ +@end@ // m2c_create_fewer_files + +/* + * DUMMY markers, ignore + * + * TODO:099:x: ************************************************************* + * TODO:199:x: ************************************************************* + * TODO:299:x: ************************************************************* + * TODO:399:x: ************************************************************* + * TODO:499:x: ************************************************************* + */ +@if $m2c_mark_boundary == 1@ +/** END header generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +@include generic-header-bottom.m2i@ +/** @} */ +###################################################################### +## Do the .c file +###################################################################### +@eval $m2c_processing_type = 'c'@ +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 14170 $ of $RCSfile$ + * + * $$hack:$ + */ +/** \page MFD helper for ${name} + * + * \section intro Introduction + * Introductory text. + * + */ +@include generic-source-includes.m2i@ +#include + +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +#include "${name}_interface.h" + +@foreach $table table@ +@ include m2c_setup_table.m2i@ +oid ${context}_oid[] = { $context.uc_OID }; +int ${context}_oid_size = OID_LENGTH(${context}_oid); + +@ if "x$m2c_context_reg" ne "x"@ + ${context}_registration ${context}_user_context; +@ end@ + +void initialize_table_$context(void); +void shutdown_table_$context(void); + +@end@ + +/** + * Initializes the $name module + */ +void +init_$name(void) +{ + DEBUGMSGTL(("verbose:$name:init_$name","called\n")); + + /* + * TODO:300:o: Perform $name one-time module initialization. + */ + + /* + * here we initialize all the tables we're planning on supporting + */ + @foreach $table table@ + if (should_init("$context")) + initialize_table_$context(); + + @end@ +} /* init_$name */ + +/** + * Shut-down the $name module (agent is exiting) + */ +void +shutdown_$name(void) +{ + @foreach $table table@ + if (should_init("$context")) + shutdown_table_$context(); + + @end@ +} + +######################################################################## +## +@foreach $table table@ +@ include m2c_setup_table.m2i@ +/** + * Initialize the table $context + * (Define its contents and how it's structured) + */ +void +initialize_table_$context(void) +{ + ${context}_registration * user_context; + u_long flags; + + DEBUGMSGTL(("verbose:$context:initialize_table_$context","called\n")); + + /* + * TODO:301:o: Perform $context one-time table initialization. + */ + + /* + * TODO:302:o: |->Initialize $context user context + * if you'd like to pass in a pointer to some data for this + * table, allocate or set it up here. + */ +@ if "$m2c_context_reg" eq "netsnmp_data_list"@ + /* + * a netsnmp_data_list is a simple way to store void pointers. A simple + * string token is used to add, find or remove pointers. + */ + user_context = netsnmp_create_data_list("$context", NULL, NULL); +@ else@ + user_context = &${context}_user_context; +@ end@ + + /* + * No support for any flags yet, but in the future you would + * set any flags here. + */ + flags = 0; + + /* + * call interface initialization code + */ + _${context}_initialize_interface(user_context, flags); +} /* initialize_table_$context */ + +/** + * Shutdown the table $context + */ +void +shutdown_table_$context(void) +{ + /* + * call interface shutdown code + */ + _${context}_shutdown_interface(&${context}_user_context); +} + +######################################################################## +@ if $m2c_data_init == 1@ +/** + * extra context initialization (eg default values) + * + * @param rowreq_ctx : row request context + * @param user_init_ctx : void pointer for user (parameter to rowreq_ctx_allocate) + * + * @retval MFD_SUCCESS : no errors + * @retval MFD_ERROR : error (context allocate will fail) + */ +int +${context}_rowreq_ctx_init(${context}_rowreq_ctx *rowreq_ctx, + void *user_init_ctx) +{ + DEBUGMSGTL(("verbose:$context:${context}_rowreq_ctx_init","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:210:o: |-> Perform extra $context rowreq initialization. (eg DEFVALS) + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.hasdefval == 0@ +@ next@ +@ end@ +##------------------------------------------------------ +@ if $node.needlength == 1@ + /* + * strings and oids are hard to handle automagically. + * so all we've got for you is a hint: + * + * memcpy($m2c_data_item$node, $node.defval, + * len($node.defval) * sizeof($m2c_data_itme$node[0]); + */ +@ elsif $node.enums == 1@ +@ if "$node.perltype" ne "BITS"@ +@ eval $m2c_tmp_mt = $node.defval@ +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ +@ if $e eq $node.defval@ +@ eval $m2c_tmp_mt = $m2c_ename@ +@ end@ +@ end@ # for each +@ end@ # ! bits + $m2c_data_item$node = $m2c_tmp_mt; +@ elsif ("$node.decl" eq "long") || ("$node.decl" eq "u_long")@ + $m2c_data_item$node = $node.defval; +@ else@ + /** $m2c_data_item$node = $node.defval; */ +@ end@ + +@ end@ foreach nonindex + + return MFD_SUCCESS; +} /* ${context}_rowreq_ctx_init */ + +/** + * extra context cleanup + * + */ +void ${context}_rowreq_ctx_cleanup(${context}_rowreq_ctx *rowreq_ctx) +{ + DEBUGMSGTL(("verbose:$context:${context}_rowreq_ctx_cleanup","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:211:o: |-> Perform extra $context rowreq cleanup. + */ +} /* ${context}_rowreq_ctx_cleanup */ + +@ end@ // data_init +######################################################################## +@if $m2c_table_persistent == 1@ +@ include mfd-persistence.m2i@ +@end@ +######################################################################## +/** + * pre-request callback + * + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : other error + */ +int +${context}_pre_request(${context}_registration * user_context) +{ + DEBUGMSGTL(("verbose:${context}:${context}_pre_request","called\n")); + + /* + * TODO:510:o: Perform $context pre-request actions. + */ + + return MFD_SUCCESS; +} /* ${context}_pre_request */ + +/** + * post-request callback + * + * Note: + * New rows have been inserted into the container, and + * deleted rows have been removed from the container and + * released. + * + * @param user_context + * @param rc : MFD_SUCCESS if all requests succeeded + * + * @retval MFD_SUCCESS : success. + * @retval MFD_ERROR : other error (ignored) + */ +int +${context}_post_request(${context}_registration * user_context, int rc) +{ + DEBUGMSGTL(("verbose:${context}:${context}_post_request","called\n")); + + /* + * TODO:511:o: Perform $context post-request actions. + */ + +@ if $m2c_table_settable@ + /* + * check to set if any rows were changed. + */ + if (${context}_dirty_get()) { + /* + * check if request was successful. If so, this would be + * a good place to save data to its persistent store. + */ + if (MFD_SUCCESS == rc) { + /* + * save changed rows, if you haven't already + */ +@ if $m2c_table_persistent@ + snmp_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_APPTYPE)); +@ end@ + } + + ${context}_dirty_set(0); /* clear table dirty flag */ + } + +@ end@ + return MFD_SUCCESS; +} /* ${context}_post_request */ + +@end@ // table + +######################################################################## +@if $m2c_create_fewer_files == 1@ +@ eval $mfd_processing_types = "c"@ +@ include mfd-data-get.m2c@ +@ include mfd-data-set.m2c@ +@else@ +@ eval $mfd_processing_types = "chi"@ +@ run mfd-data-get.m2c@ +@ run mfd-data-set.m2c@ +@end@ +######################################################################## +/** @{ */ +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 14170 $ */ +@end@ +## +######################################################################## +## +## Do support files +## +######################################################################## +@run generic-table-constants.m2c@ +@run mfd-interface.m2c@ +@run mfd-data-access.m2c@ +## +@run mfd-readme.m2c@ +## +@if $mfd_generate_doxygen == 1@ +@ run mfd-doxygen.m2c@ +@end@ +## +@if $mfd_generate_makefile == 1@ +@ run mfd-makefile.m2m@ +@end@ +## +@if $mfd_generate_subagent == 1@ +@ run subagent.m2c@ +@end@ +## diff --git a/local/mib2c-conf.d/node-get.m2i b/local/mib2c-conf.d/node-get.m2i new file mode 100644 index 0000000..96ee8e4 --- /dev/null +++ b/local/mib2c-conf.d/node-get.m2i @@ -0,0 +1,107 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: node-get.m2i 12704 2005-08-30 00:38:54Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12704 $ */ +@end@ +######################################################################## +## +@include m2c_setup_node.m2i@ +@eval $m2c_node_realloc = 2@ // malloc +/** + * Extract the current value of the $node data. + * + * Set a value using the data context for the row. + * +@if $m2c_node_get_comments ne ""@ +$m2c_node_get_comments +* +@end@ + * @param rowreq_ctx + * Pointer to the row request context. + * @param $m2c_node_param_ref_name + * Pointer to storage for a $node.decl variable +@if $m2c_node_needlength == 1@ + * @param $m2c_node_param_ref_lname + * Pointer to a size_t. On entry, it will contain the size (in bytes) + * pointed to by $node. + * On exit, this value should contain the data size (in bytes). +@end@ + * + * @retval MFD_SUCCESS : success + * @retval MFD_SKIP : skip this node (no value for now) + * @retval MFD_ERROR : Any other error +@if $m2c_node_needlength == 1@ +* + * @note If you need more than (*$m2c_node_param_ref_lname) bytes of memory, + * allocate it using malloc() and update $m2c_node_param_ref_name. + * DO NOT free the previous pointer. + * The MFD helper will release the memory you allocate. + * + * @remark If you call this function yourself, you are responsible + * for checking if the pointer changed, and freeing any + * previously allocated memory. (Not necessary if you pass + * in a pointer to static memory, obviously.) +@end@ + */ +int +${node}_get( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_ref ) +{ +@ifconf syntax-$node.syntax-get.m2i@ +@ include syntax-$node.syntax-get.m2i@ +@else@ +@ include generic-get-decl.m2i@ + + DEBUGMSGTL(("verbose:${context}:${node}_get","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + +/* + * TODO:231:o: |-> Extract the current value of the $node data. +@if $m2c_node_needlength == 0@ + * copy $m2c_node_lh from $m2c_data_item_base +@else@ + * copy $m2c_node_lh data and $m2c_node_lhs from $m2c_data_item_base +@end@ + */ +@ if ("$m2c_data_context" eq "generated") && ($m2c_node_skip_get != 1)@ +@ include generic-ctx-get.m2i@ +@ else@ +@ if ($m2c_node_skip_get != 1)@ + /* + * TODO:235:M: |-> Remove log message/SKIP once you've set $node data + */ + snmp_log(LOG_ERR,"${context} node $node not implemented: skipping\n"); +@ end@ + return MFD_SKIP; +@ end@ +## ------------------------------------------------------------------ +@ if $node.decl =~ /long/i@ # ASN_INTEGER ASN_COUNTER ASN_GAUGE +@ include generic-get-long.m2i@ +@ elsif $node.decl =~ /char/i@ # ASN_OCTET_STR ASN_OPAQUE +@ include generic-get-char.m2i@ +@ elsif $node.decl =~ /oid/i@ # ASN_OBJECT_ID +@ include generic-get-oid.m2i@ +@ elsif $node.decl =~ /U64/i@ # ASN_COUNTER64 +@ include generic-get-U64.m2i@ +@ else@ +@ print ERROR: unknown node.decl: $node.decl@ +@ exit@ +@ end@ +## ------------------------------------------------------------------ +@ if ($m2c_node_skip_mapping != 1) && ("$m2c_data_context" ne "generated")@ +@ include generic-value-map.m2i@ +@ end@ +@ include generic-get-decl-bot.m2i@ // copy value out +@end@ # no syntax include + + return MFD_SUCCESS; +} /* ${node}_get */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12704 $ */ +@end@ diff --git a/local/mib2c-conf.d/node-set.m2i b/local/mib2c-conf.d/node-set.m2i new file mode 100644 index 0000000..6108631 --- /dev/null +++ b/local/mib2c-conf.d/node-set.m2i @@ -0,0 +1,236 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: node-set.m2i 11991 2005-03-04 20:10:14Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11991 $ */ +@end@ +######################################################################## +## +##---------------------------------------------------------------------- +/** + * Check that the proposed new value is potentially valid. + * + * @param rowreq_ctx + * Pointer to the row request context. + * @param $m2c_node_param_val_name + * A $node.decl containing the new value. +@ if $m2c_node_needlength == 1@ + * @param $m2c_node_param_val_lname + * The size (in bytes) of the data pointed to by $m2c_node_param_val_name +@ end@ + * + * @retval MFD_SUCCESS : incoming value is legal + * @retval MFD_NOT_VALID_NOW : incoming value is not valid now + * @retval MFD_NOT_VALID_EVER : incoming value is never valid + * + * This is the place to check for requirements that are not + * expressed in the mib syntax (for example, a requirement that + * is detailed in the description for an object). + * +@if ("$m2c_data_context" ne "generated") && ($m2c_node_needlength == 1)@ + * Since you aren't using a generated data context, you also need to + * check the length, to make sure you don't overflow your storage space. + * +@end@ + * You should check that the requested change between the undo value and the + * new value is legal (ie, the transistion from one value to another + * is legal). + * + *@note + * This check is only to determine if the new value + * is \b potentially valid. This is the first check of many, and + * is one of the simplest ones. + * + *@note + * this is not the place to do any checks for values + * which depend on some other value in the mib. Those + * types of checks should be done in the + * ${context}_check_dependencies() function. + * + * The following checks have already been done for you: + * The syntax is $node.type +@if ("$m2c_data_context" eq "generated") && ($m2c_node_needlength == 1)@ + * The length is < sizeof($m2c_data_item$node). +@end@ +@if $node.enums == 1@ + * The value is one of $m2c_evals +@elsif $node.ranges == 1@ +@ if ("$node.decl" eq "long") || ("$node.decl" eq "u_long")@ +@ eval $m2c_tmp_ns = "value"@ +@ else@ +@ eval $m2c_tmp_ns = "length"@ +@ end@ + * The $m2c_tmp_ns is in (one of) the range set(s): $m2c_evals +@end@ + * + * If there a no other checks you need to do, simply return MFD_SUCCESS. + * +@ if $mfd_code_verbose == 1@ +@ if ("$node.decl" eq "long") || ("$node.decl" eq "u_long")@ + * For example, an object with the syntax INTEGER(0..500) will + * have already been checked for a value between 0 and 500. But + * if the description also specifies that the value must be an + * even number, you would enforce that requirement here. If and odd + * numer is set, return MFD_NOT_VALID_EVER. If the description also + * specified that changed must be made in single steps of 2, then a set + * to change the value 10 to an even value other than 8 or 12 should + * return MFD_NOT_VALID_NOW. +@ else@ + * For example, and object with the syntax DisplayString(0..40) + * will have already been checked for a length between 0 and 40. + * But if the description also specified that the value must + * be all uppercase letters, you would enforce that requirement here + * by returning MFD_NOT_VALID_EVER for a set containing lowercase + * letters. If the description also specified that the value can not + * change by more than one letter at a time, an attempt to change + * "ABBY" to "ANNIE" should return MFD_NOT_VALID_NOW. +@ end@ + * +@ end@ + */ +int +${node}_check_value( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_val) +{ + DEBUGMSGTL(("verbose:${context}:${node}_check_value","called\n")); + + /** should never get a NULL pointer */ + netsnmp_assert(NULL != rowreq_ctx); +@if $m2c_node_needlength == 1@ + netsnmp_assert(NULL != $m2c_node_param_val_name); +@end@ + + /* + * TODO:441:o: |-> Check for valid $node value. + */ + + return MFD_SUCCESS; /* $node value not illegal */ +} /* ${node}_check_value */ + +##---------------------------------------------------------------------- +/** + * Save old value information + * + * @param rowreq_ctx + * Pointer to the table context (${context}_rowreq_ctx) + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error. set will fail. + * + * This function will be called after the table level undo setup function + * ${context}_undo_setup has been called. + * + *@note + * this function will only be called if a new value is set for this column. + * + * If there is any setup specific to a particular column (e.g. allocating + * memory for a string), you should do that setup in this function, so it + * won't be done unless it is necessary. + */ +int +${node}_undo_setup( ${context}_rowreq_ctx *rowreq_ctx) +{ + DEBUGMSGTL(("verbose:${context}:${node}_undo_setup","called\n")); + +@ifconf syntax-$node.syntax-undo-setup.m2i@ +@ include syntax-$node.syntax-undo-setup.m2i@ +@else@ + /** should never get a NULL pointer */ + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:455:o: |-> Setup $node undo. + */ +@ eval $m2c_ctx_lh = "${m2c_undo_item}${node}"@ +@ eval $m2c_ctx_lhs = "${m2c_undo_item}${node}_len"@ +@ eval $m2c_ctx_rh = "${m2c_data_item}${node}"@ +@ eval $m2c_ctx_rhs = "${m2c_data_item}${node}_len"@ +@ include generic-ctx-copy.m2i@ +@end@ + + return MFD_SUCCESS; +} /* ${node}_undo_setup */ + +##---------------------------------------------------------------------- +/** + * Set the new value. + * +@if $m2c_node_set_comments ne ""@ +$m2c_node_set_comments +* +@end@ + * @param rowreq_ctx + * Pointer to the users context. You should know how to + * manipulate the value from this object. + * @param $m2c_node_param_val_name + * A $node.decl containing the new value. +@ if $m2c_node_needlength == 1@ + * @param $m2c_node_param_val_lname + * The size (in bytes) of the data pointed to by $m2c_node_param_val_name +@ end@ + */ +int +${node}_set( ${context}_rowreq_ctx *rowreq_ctx, $m2c_node_param_val ) +{ +@ifconf syntax-$node.syntax-set.m2i@ +@ include syntax-$node.syntax-set.m2i@ +@else@ + + DEBUGMSGTL(("verbose:${context}:${node}_set","called\n")); + + /** should never get a NULL pointer */ + netsnmp_assert(NULL != rowreq_ctx); +@if $m2c_node_needlength == 1@ + netsnmp_assert(NULL != $m2c_node_param_val_name); +@end@ + +@ if $m2c_node_skip_mapping != 1@ +@ include generic-value-map-reverse.m2i@ +@ else@ +@ include generic-ctx-set.m2i@ +@ end@ +@end@ # no syntax include + return MFD_SUCCESS; +} /* ${node}_set */ + +##---------------------------------------------------------------------- +/** + * undo the previous set. + * +@if $m2c_node_undo_comments ne ""@ +$m2c_node_undo_comments +* +@end@ + * @param rowreq_ctx + * Pointer to the users context. + */ +int +${node}_undo( ${context}_rowreq_ctx *rowreq_ctx) +{ +@ifconf syntax-$node.syntax-undo.m2i@ +@ include syntax-$node.syntax-undo.m2i@ +@else@ + + DEBUGMSGTL(("verbose:${context}:${node}_undo","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:456:o: |-> Clean up $node undo. + */ +@ eval $m2c_ctx_rh = "${m2c_undo_item}${node}"@ +@ eval $m2c_ctx_rhs = "${m2c_undo_item}${node}_len"@ +@ eval $m2c_ctx_lh = "${m2c_data_item}${node}"@ +@ eval $m2c_ctx_lhs = "${m2c_data_item}${node}_len"@ +@ include generic-ctx-copy.m2i@ +@end@ # no syntax include + + return MFD_SUCCESS; +} /* ${node}_undo */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11991 $ */ +@end@ diff --git a/local/mib2c-conf.d/node-storage.m2i b/local/mib2c-conf.d/node-storage.m2i new file mode 100644 index 0000000..eb90675 --- /dev/null +++ b/local/mib2c-conf.d/node-storage.m2i @@ -0,0 +1,21 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: node-storage.m2i 8830 2003-09-30 13:34:57Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ +######################################################################## +## +@if $m2c_node_needlength == 0@ + $m2c_decl $node; +@else@ + $m2c_decl $node[$m2c_node_maxlen]; + size_t ${node}_len; +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 8830 $ */ +@end@ diff --git a/local/mib2c-conf.d/node-validate.m2i b/local/mib2c-conf.d/node-validate.m2i new file mode 100644 index 0000000..fd9c606 --- /dev/null +++ b/local/mib2c-conf.d/node-validate.m2i @@ -0,0 +1,71 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: node-validate.m2i 12101 2005-04-20 22:45:01Z rstory $ +## +## assumes an integer rc is available and will be tested by caller +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12101 $ */ +@end@ +######################################################################## +##---------------------------------------------------------------------- +## setup +##---------------------------------------------------------------------- +@if $node.enums == 1@ +##------------------------------------------------------ +@ if "$node.perltype" ne "BITS"@ + /* check that the value is one of defined enums */ + if( (SNMPERR_SUCCESS == rc) +@ foreach $e $v enum@ +@ include m2c_setup_enum.m2i@ + && ( $m2c_nv_val != $m2c_ename ) +@ end@ # for each + ) { + rc = SNMP_ERR_WRONGVALUE; + } +##------------------------------------------------------ +@ else@ # BITS +## { + if($m2c_nv_len > 4) { + snmp_log(LOG_ERR,"I can not handle BITS > 4 bytes\n"); + rc = SNMP_ERR_GENERR; + } + else if (SNMPERR_SUCCESS == rc){ + u_long bits = 0; + /* check that value is within enum mask */ + memcpy( &bits, $m2c_nv_str, $m2c_nv_len); + if( (bits | $m2c_enum_mask) != $m2c_enum_mask) + rc = SNMP_ERR_WRONGVALUE; + } +@ end@ +##---------------------------------------------------------------------- +## check RANGES +##---------------------------------------------------------------------- +@elsif $node.ranges == 1@ +@ if ("$node.decl" eq "long") || ("$node.decl" eq "u_long")@ +@ eval $m2c_nv_rc = "SNMP_ERR_WRONGVALUE"@ +@ eval $m2c_nv_tmp = "$m2c_nv_val"@ +@ else@ +@ eval $m2c_nv_rc = "SNMP_ERR_WRONGLENGTH"@ +@ eval $m2c_nv_tmp = "$m2c_nv_len"@ +@ end@ + /* check defined range(s). */ + if( (SNMPERR_SUCCESS == rc) +@ foreach $a $b range $node@ +@ if $a == $b@ + && ($m2c_nv_tmp != $a) +@ else@ + && (($m2c_nv_tmp < $a) || ($m2c_nv_tmp > $b)) +@ end@ +@ end@ + ) { + rc = $m2c_nv_rc; + } +@end@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12101 $ */ +@end@ diff --git a/local/mib2c-conf.d/node-varbind-validate.m2i b/local/mib2c-conf.d/node-varbind-validate.m2i new file mode 100644 index 0000000..ed2f933 --- /dev/null +++ b/local/mib2c-conf.d/node-varbind-validate.m2i @@ -0,0 +1,54 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: node-varbind-validate.m2i 12101 2005-04-20 22:45:01Z rstory $ +## +## Tests a netsnmp_variable_list pointer (var) against known +## contstraints. If none are found, calls the user supplied funtion +## ${node}_check_value. +## +## Sets the variable rc to a SNMP_ERR. +## +## Requirements +## ------------ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12101 $ */ +@end@ +######################################################################## +##---------------------------------------------------------------------- +## setup +##---------------------------------------------------------------------- +@if $m2c_paranoid == 1@ +netsnmp_assert(rc == SNMP_ERR_NOERROR); /* paranoia */ +@end@ +##---------------------------------------------------------------------- +## syntax specific +##---------------------------------------------------------------------- +@ifconf syntax-$node.syntax-varbind-validate.m2i@ +@ include syntax-$node.syntax-varbind-validate.m2i@ +@else@ +##---------------------------------------------------------------------- +## Check type +##---------------------------------------------------------------------- +## if not generated code, length checks are up to user +@ if "$m2c_data_context" ne "generated"@ + rc = netsnmp_check_vb_type( var, $node.type ); +@ elsif ($m2c_node_needlength == 1) || ("$node.perltype" eq "BITS")@ + rc = netsnmp_check_vb_type_and_max_size( var, $node.type, + sizeof( $m2c_nvv_item$node ) ); +@ else@ + rc = netsnmp_check_vb_type_and_size( var, $node.type, + sizeof( $m2c_nvv_item$node ) ); +@ end@ +@ eval $m2c_nv_val = "*var->val.integer"@ +@ eval $m2c_nv_len = "var->val_len"@ +@ eval $m2c_nv_str = "var->val.string"@ +@ include node-validate.m2i@ +@end@ # not syntax specific +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12101 $ */ +@end@ diff --git a/local/mib2c-conf.d/parent-dependencies.m2i b/local/mib2c-conf.d/parent-dependencies.m2i new file mode 100644 index 0000000..bc912b3 --- /dev/null +++ b/local/mib2c-conf.d/parent-dependencies.m2i @@ -0,0 +1,63 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: parent-dependencies.m2i 11989 2005-03-04 20:02:42Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11989 $ */ +@end@ # ; +######################################################################## +## +/** + * check dependencies + * + * This is useful for for tables which have dependencies between columns + * (or rows, or tables). For example, two columns allocating a percentage + * of something add up 100%. + * + * Should you need different behavior depending on which columns were + * set, rowreq_ctx->column_set_flags will indicate which writeable columns were + * set. The definitions for the COLUMN_*_FLAG bits can be found in +@if $m2c_create_fewer_files != 1@ + * ${context}_oids.h. +@else@ + * ${context}.h. +@end@ + * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags. + * + * @retval MFD_SUCCESS all the changes to the row are legal + * @retval MFD_ERROR one or more changes are not legal + * + * (see README-table-${table} if you don't have dependencies) + */ +int +${context}_check_dependencies(${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("internal:${context}:${context}_check_dependencies","called\n")); + + netsnmp_assert(NULL != rowreq_ctx); + + /* + * TODO:470:o: Check $context row dependencies. + * check that all new value are legal and consistent with each other + */ +## } +@foreach $node nonindex@ +@ ifconf syntax-$node.syntax-dependencies.m2i@ +@ include syntax-$node.syntax-dependencies.m2i@ + if ( MFD_SUCCESS != rc ) + return rc; + +@ end@ +@end@ # for each +## { + return rc; +} /* ${context}_check_dependencies */ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11989 $ */ +@end@ diff --git a/local/mib2c-conf.d/parent-set.m2i b/local/mib2c-conf.d/parent-set.m2i new file mode 100644 index 0000000..bb02522 --- /dev/null +++ b/local/mib2c-conf.d/parent-set.m2i @@ -0,0 +1,417 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: parent-set.m2i 12851 2005-09-27 15:43:39Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12851 $ */ +@end@ +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'h'@ + +int ${context}_undo_setup( ${context}_rowreq_ctx *rowreq_ctx); +int ${context}_undo_cleanup( ${context}_rowreq_ctx *rowreq_ctx); +int ${context}_undo( ${context}_rowreq_ctx *rowreq_ctx); +int ${context}_commit( ${context}_rowreq_ctx *rowreq_ctx); +int ${context}_undo_commit( ${context}_rowreq_ctx *rowreq_ctx); +@ if $m2c_irreversible_commit == 1@ +int ${context}_irreversible_commit( ${context}_rowreq_ctx *rowreq_ctx); +@ end@ + +@end@ // m2c_processing_type eq 'h' +######################################################################## +##//#################################################################### +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +##//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@if $m2c_processing_type eq 'c'@ +## +## MASTER COPY OF THIS FLOWCHART IS IN agent/helpers/baby_steps.c +## + /* + * NOTE: if you update this chart, please update the versions in + * local/mib2c-conf.d/parent-set.m2i + * agent/mibgroup/helpers/baby_steps.c + * while you're at it. + */ + /* + *********************************************************************** + * Baby Steps Flow Chart (2004.06.05) * + * * + * +--------------+ +================+ U = unconditional path * + * |optional state| ||required state|| S = path for success * + * +--------------+ +================+ E = path for error * + *********************************************************************** + * + * +--------------+ + * | pre | + * | request | + * +--------------+ + * | U +@if $m2c_table_row_creation == 1@ + * +-------------+ +==============+ + * | row |f|<-------|| object || + * | create |1| E || lookup || + * +-------------+ +==============+ + * E | | S | S + * | +------------------>| + * | +==============+ + * | E || check || + * |<---------------|| values || +@else@ + * +==============+ + * +----------------|| object || + * | E || lookup || + * | +==============+ + * | | S + * | +==============+ + * | E || check || + * |<---------------|| values || +@end@ # row creation + * | +==============+ + * | | S + * | +==============+ + * | +<-------|| undo || + * | | E || setup || + * | | +==============+ + * | | | S + * | | +==============+ + * | | || set ||-------------------------->+ + * | | || value || E | + * | | +==============+ | + * | | | S | + * | | +--------------+ | + * | | | check |-------------------------->| + * | | | consistency | E | + * | | +--------------+ | + * | | | S | + * | | +==============+ +==============+ | + * | | || commit ||-------->|| undo || | + * | | || || E || commit || | + * | | +==============+ +==============+ | + * | | | S U |<--------+ + * | | +--------------+ +==============+ + * | | | irreversible | || undo || + * | | | commit | || set || + * | | +--------------+ +==============+ + * | | | U U | + * | +-------------->|<------------------------+ + * | +==============+ + * | || undo || + * | || cleanup || + * | +==============+ + * +---------------------->| U +@if $m2c_table_row_creation == 1@ + * | + * (err && f1)------------------->+ + * | | + * +--------------+ +--------------+ + * | post |<--------| row | + * | request | U | release | + * +--------------+ +--------------+ +@else@ + * +--------------+ + * | post | + * | request | + * +--------------+ +@end@ # row creation + * + */ + +##---------------------------------------------------------------------- +/** + * Setup up context with information needed to undo a set request. + * + * This function will be called before the individual node undo setup + * functions are called. If you need to do any undo setup that is not + * related to a specific column, you can do it here. + * +@if $m2c_undo_embed == 0@ +@ if $m2c_data_init == 1@ + * Note that the undo context has been allocated with + * ${context}_allocate_data(), but may need extra + * initialization similar to what you may have done in + * ${context}_rowreq_ctx_init(). +@ end@ +@end@ + * Note that an individual node's undo_setup function will only be called + * if that node is being set to a new value. + * + * If there is any setup specific to a particular column (e.g. allocating + * memory for a string), you should do that setup in the node's undo_setup + * function, so it won't be done unless it is necessary. + * + * @param rowreq_ctx + * Pointer to the table context (${context}_rowreq_ctx) + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error. set will fail. + */ +int +${context}_undo_setup( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("verbose:${context}:${context}_undo_setup","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:451:M: |-> Setup $context undo. + * set up $context undo information, in preparation for a set. + * Undo storage is in ${m2c_ctx_lh}* + */ + + return rc; +} /* ${context}_undo_setup */ + +/** + * Undo a set request. + * + * This function will be called before the individual node undo + * functions are called. If you need to do any undo that is not + * related to a specific column, you can do it here. + * + * Note that an individual node's undo function will only be called + * if that node is being set to a new value. + * + * If there is anything specific to a particular column (e.g. releasing + * memory for a string), you should do that setup in the node's undo + * function, so it won't be done unless it is necessary. + * + * @param rowreq_ctx + * Pointer to the table context (${context}_rowreq_ctx) + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error. set will fail. + */ +int +${context}_undo( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("verbose:${context}:${context}_undo","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:451:M: |-> $context undo. + * $context undo information, in response to a failed set. + * Undo storage is in ${m2c_ctx_lh}* + */ + + return rc; +} /* ${context}_undo_setup */ + +/** + * Cleanup up context undo information. + * + * This function will be called after set/commit processing. If you + * allocated any resources in undo_setup, this is the place to release + * those resources. + * + * This function is called regardless of the success or failure of the set + * request. If you need to perform different steps for cleanup depending + * on success or failure, you can add a flag to the rowreq_ctx. + * + * @param rowreq_ctx + * Pointer to the table context (${context}_rowreq_ctx) + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error + */ +int +${context}_undo_cleanup( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("verbose:${context}:${context}_undo_cleanup","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:452:M: |-> Cleanup $context undo. + * Undo storage is in ${m2c_ctx_lh}* + */ + + return rc; +} /* ${context}_undo_cleanup */ + +##---------------------------------------------------------------------- +/** + * commit new values. + * + * At this point, you should have done everything you can to ensure that + * this commit will not fail. + * + * Should you need different behavior depending on which columns were + * set, rowreq_ctx->column_set_flags will indicate which writeable columns were + * set. The definitions for the COLUMN_*_FLAG bits can be found in +@if $m2c_create_fewer_files != 1@ + * ${context}_oids.h. +@else@ + * ${context}.h. +@end@ + * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags. + * + * @param ${context}_rowreq_ctx + * Pointer to the users context. + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error + */ +int +${context}_commit( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + int save_flags; + + DEBUGMSGTL(("verbose:${context}:${context}_commit","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * save flags, then clear until we actually do something + */ + save_flags = rowreq_ctx->column_set_flags; + rowreq_ctx->column_set_flags = 0; + + /* + * commit $context data + * 1) check the column's flag in save_flags to see if it was set. + * 2) clear the flag when you handle that column + * 3) set the column's flag in column_set_flags if it needs undo + * processing in case of a failure. + */ +@ foreach $node nonindex@ +@ include m2c_setup_node.m2i@ +@ if $node.settable == 0@ +@ next@ +@ end@ + if (save_flags & COLUMN_$node.uc_FLAG) { + save_flags &= ~COLUMN_$node.uc_FLAG; /* clear $node */ + /* + * TODO:482:o: |-> commit column $node. + */ + rc = -1; + if(-1 == rc) { + snmp_log(LOG_ERR,"$context column $node commit failed\n"); + } + else { + /* + * set flag, in case we need to undo $node + */ + rowreq_ctx->column_set_flags |= COLUMN_$node.uc_FLAG; + } + } + +@ end@ # foreach $node + /* + * if we successfully commited this row, set the dirty flag. + */ + if (MFD_SUCCESS == rc) { + rowreq_ctx->rowreq_flags |= MFD_ROW_DIRTY; + } + + if (save_flags) { + snmp_log(LOG_ERR, "unhandled columns (0x%x) in commit\n", save_flags); + return MFD_ERROR; + } + + return rc; +} /* ${context}_commit */ + +/** + * undo commit new values. + * + * Should you need different behavior depending on which columns were + * set, rowreq_ctx->column_set_flags will indicate which writeable columns were + * set. The definitions for the COLUMN_*_FLAG bits can be found in +@if $m2c_create_fewer_files != 1@ + * ${context}_oids.h. +@else@ + * ${context}.h. +@end@ + * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags. + * + * @param ${context}_rowreq_ctx + * Pointer to the users context. + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : error + */ +int +${context}_undo_commit( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc = MFD_SUCCESS; + + DEBUGMSGTL(("verbose:${context}:${context}_undo_commit","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:485:M: |-> Undo $context commit. + * check the column's flag in rowreq_ctx->column_set_flags to see + * if it was set during commit, then undo it. + * + * eg: if (rowreq_ctx->column_set_flags & COLUMN_$node.uc_FLAG) {} + */ + + + /* + * if we successfully un-commited this row, clear the dirty flag. + */ + if (MFD_SUCCESS == rc) { + rowreq_ctx->rowreq_flags &= ~MFD_ROW_DIRTY; + } + + return rc; +} /* ${context}_undo_commit */ + +@if $m2c_irreversible_commit == 1@ +##---------------------------------------------------------------------- +/** + * perform commit actions that are not reversible + * + * THERE IS NO ATTEMPT AT RECOVERY FOR ERRORS FROM THIS STATE! + * + * @param ${context}_rowreq_ctx + * Pointer to the users context. + * + * @retval MFD_SUCCESS : success + * @retval MFD_ERROR : other error + */ +int +${context}_irreversible_commit( ${context}_rowreq_ctx *rowreq_ctx) +{ + int rc; + + DEBUGMSGTL(("verbose:${context}:${context}_irreversible_commit","called\n")); + + /** we should have a non-NULL pointer */ + netsnmp_assert( NULL != rowreq_ctx ); + + /* + * TODO:495:o: Irreversible $context commit. + */ +##$example_start +##$example_end + + return MFD_SUCCESS; +} /* ${context}_irreversible_commit */ + +@end@ // irreversable commit +## +######################################################################## +@end@ // m2c_processing_type eq 'c' +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12851 $ */ +@end@ diff --git a/local/mib2c-conf.d/subagent.m2c b/local/mib2c-conf.d/subagent.m2c new file mode 100644 index 0000000..6159838 --- /dev/null +++ b/local/mib2c-conf.d/subagent.m2c @@ -0,0 +1,183 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## $Id: subagent.m2c 15795 2007-01-25 22:07:06Z tanders $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 15795 $ */ +@end@ +######################################################################## +## +@if 0@ +@open ${name}_subagent.h@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 15795 $ of $RCSfile$ + */ +@include generic-header-top.m2i@ +@include generic-header-bottom.m2i@ +@end@ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}_subagent.c@ +/* + * Note: this file originally auto-generated by mib2c using + * version $Revision: 15795 $ of $RCSfile$ + */ +@include generic-source-includes.m2i@ +#include + +static int keep_running; + +static RETSIGTYPE +stop_server(int a) { + keep_running = 0; +} + +static void usage(void) { + printf("usage: $name [-D] [-f] [-L] [-M] [-H] [LISTENING ADDRESSES]\n" + "\t-f Do not fork() from the calling shell.\n" + "\t-DTOKEN[,TOKEN,...]\n" + "\t\tTurn on debugging output for the given TOKEN(s).\n" + "\t\tWithout any tokens specified, it defaults to printing\n" + "\t\tall the tokens (which is equivalent to the keyword 'ALL').\n" + "\t\tYou might want to try ALL for extremely verbose output.\n" + "\t\tNote: You can't put a space between the -D and the TOKENs.\n" + "\t-H\tDisplay a list of configuration file directives\n" + "\t\tunderstood by the agent and then exit.\n" + "\t-M\tRun as a normal SNMP Agent instead of an AgentX sub-agent.\n" + "\t-x ADDRESS\tconnect to master agent at ADDRESS (default /var/agentx/master).\n" + "\t-L\tDo not open a log file; print all messages to stderr.\n"); + exit(0); +} + +int +main (int argc, char **argv) { + int agentx_subagent=1; /* change this if you want to be a SNMP master agent */ + /* Defs for arg-handling code: handles setting of policy-related variables */ + int ch; + extern char *optarg; + int dont_fork = 0, use_syslog = 0; + char *agentx_socket = NULL; + + while ((ch = getopt(argc, argv, "D:fHLMx:")) != EOF) + switch(ch) { + case 'D': + debug_register_tokens(optarg); + snmp_set_do_debugging(1); + break; + case 'f': + dont_fork = 1; + break; + case 'H': + netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); + init_agent("$name"); /* register our .conf handlers */ + init_$name(); + init_snmp("$name"); + fprintf(stderr, "Configuration directives understood:\n"); + read_config_print_usage(" "); + exit(0); + case 'M': + agentx_subagent = 0; + break; + case 'L': + use_syslog = 0; /* use stderr */ + break; + case 'x': + agentx_socket = optarg; + break; + default: + fprintf(stderr,"unknown option %c\n", ch); + usage(); + } + + if (optind < argc) { + int i; + /* + * There are optional transport addresses on the command line. + */ + DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc)); + for (i = optind; i < argc; i++) { + char *c, *astring; + if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_PORTS))) { + astring = malloc(strlen(c) + 2 + strlen(argv[i])); + if (astring == NULL) { + fprintf(stderr, "malloc failure processing argv[%d]\n", i); + exit(1); + } + sprintf(astring, "%s,%s", c, argv[i]); + netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_PORTS, astring); + SNMP_FREE(astring); + } else { + netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_PORTS, argv[i]); + } + } + DEBUGMSGTL(("snmpd/main", "port spec: %s\n", + netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_PORTS))); + } + + /* we're an agentx subagent? */ + if (agentx_subagent) { + /* make us a agentx client. */ + netsnmp_enable_subagent(); + if (NULL != agentx_socket) + netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_X_SOCKET, agentx_socket); + } + + snmp_disable_log(); + if (use_syslog) + snmp_enable_calllog(); + else + snmp_enable_stderrlog(); + + /* daemonize */ + if(!dont_fork) { + int rc = netsnmp_daemonize(1,!use_syslog); + if(rc) + exit(-1); + } + + /* initialize tcp/ip if necessary */ + SOCK_STARTUP; + + /* initialize the agent library */ + init_agent("$name"); + + /* init $name mib code */ + init_$name(); + + /* read ${name}.conf files. */ + init_snmp("$name"); + + /* If we're going to be a snmp master agent, initial the ports */ + if (!agentx_subagent) + init_master_agent(); /* open the port to listen on (defaults to udp:161) */ + + /* In case we recevie a request to stop (kill -TERM or kill -INT) */ + keep_running = 1; + signal(SIGTERM, stop_server); + signal(SIGINT, stop_server); + + /* you're main loop here... */ + while(keep_running) { + /* if you use select(), see snmp_select_info() in snmp_api(3) */ + /* --- OR --- */ + agent_check_and_process(1); /* 0 == don't block */ + } + + /* at shutdown time */ + snmp_shutdown("$name"); + SOCK_CLEANUP; + exit(0); +} + +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 15795 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-COUNTER64-get.m2i b/local/mib2c-conf.d/syntax-COUNTER64-get.m2i new file mode 100644 index 0000000..af05f10 --- /dev/null +++ b/local/mib2c-conf.d/syntax-COUNTER64-get.m2i @@ -0,0 +1,35 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-COUNTER64-get.m2i 11363 2004-10-15 00:52:14Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11363 $ */ + ## } +@end@ +######################################################################## +## +@include generic-get-decl.m2i@ +/* + * TODO:231:o: |-> copy $node data. + * get ${m2c_node_lh}.low and ${m2c_node_lh}.high from $m2c_data_item_base + */ +@if ("$m2c_data_context" eq "generated")@ + ${m2c_node_lh}.high = ${m2c_data_item}${node}.high; + ${m2c_node_lh}.low = ${m2c_data_item}${node}.low; +@else@ + return MFD_SKIP; /* TODO:235:M: |-> Remove SKIP once you've set $node data */ +@end@ +## spirit of @include generic-get-decl-bot.m2i@ +@if $m2c_get_use_temp == 1@ + + /* copy temporary value to passed parameter */ + ${node}_ptr->high = ${m2c_node_lh}.high; + ${node}_ptr->low = ${m2c_node_lh}.low; +@end@ + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11363 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-DateAndTime-get.m2d b/local/mib2c-conf.d/syntax-DateAndTime-get.m2d new file mode 100644 index 0000000..dfb2a21 --- /dev/null +++ b/local/mib2c-conf.d/syntax-DateAndTime-get.m2d @@ -0,0 +1,9 @@ +## +## +@eval $m2c_node_needlength = 0@ +@eval $m2c_decl = "u_char *"@ +## +@eval $m2c_node_proto_parms = "u_char * ${node}"@ +## +@eval $m2c_node_proto_comments = "$m2c_node_proto_comments * Param: ${node}\n"@ +@eval $m2c_node_proto_comments = "$m2c_node_proto_comments * Pointer to storage for a DateAndTime value\n"@ diff --git a/local/mib2c-conf.d/syntax-DateAndTime-get.m2i b/local/mib2c-conf.d/syntax-DateAndTime-get.m2i new file mode 100644 index 0000000..a2131fe --- /dev/null +++ b/local/mib2c-conf.d/syntax-DateAndTime-get.m2i @@ -0,0 +1,54 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-DateAndTime-get.m2i 12079 2005-04-14 02:52:09Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12079 $ */ +@end@ +######################################################################## +## + /* temporary storage for date. If you have any of this data available + directly, use it instead. */ + int year, month, day, hour, minutes, seconds, deci_seconds; + int rc, utc_offset_direction, utc_offset_hours, utc_offset_minutes; + + /** we should have a pointer and enough storage */ + netsnmp_assert( (NULL != $m2c_node_param_ref_name) && (NULL != *$m2c_node_param_ref_name)); + netsnmp_assert( (NULL != $m2c_node_param_ref_lname) && ((* $m2c_node_param_ref_lname) >= 11)); + + /* + * TODO:231:o: |-> copy $node data. + * get the date from your context pointer. + */ + return MFD_SKIP; /* TODO:234:M: |-> Remove SKIP once you've set $node data */ + + year = 0; /* 0..65536 */ + month = 0; /* 1..12 */ + day = 0; /* 1..31 */ + hour = 0; /* 0..23 */ + minutes = 0; /* 0..59 */ + seconds = 0; /* 0..60 (60 indicates a leap-second) */ + deci_seconds = 0; /* 0..9 */ + + /* setting utc offset is optional. Leave the values as is if you + want to exclude this information. */ + utc_offset_direction = 0; /* -1, +1 */ + utc_offset_hours = -1; /* 0..13 */ + utc_offset_minutes = -1; /* 0..59 */ + + /* call convenience function to set data */ + rc = netsnmp_dateandtime_set_buf_from_vars(*$m2c_node_param_ref_name, + $m2c_node_param_ref_lname, + year, month, day, + hour, minutes, seconds, deci_seconds, + utc_offset_direction, utc_offset_hours, + utc_offset_minutes ); + if(rc != SNMP_ERR_NOERROR) + return rc; + +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12079 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-DateAndTime-readme.m2i b/local/mib2c-conf.d/syntax-DateAndTime-readme.m2i new file mode 100644 index 0000000..cc678ac --- /dev/null +++ b/local/mib2c-conf.d/syntax-DateAndTime-readme.m2i @@ -0,0 +1,4 @@ + This column is a DataAndTime object. The local local variables year, + month, day, hour, minues, seconds, deci_seconds, utc_offset_direction, + utc_offset_hours and utc_offset_minutes should be set from the data + context before the netsnmp_dateandtime_set_buf_from_vars function call. diff --git a/local/mib2c-conf.d/syntax-InetAddress-get.m2i b/local/mib2c-conf.d/syntax-InetAddress-get.m2i new file mode 100644 index 0000000..2b19f8d --- /dev/null +++ b/local/mib2c-conf.d/syntax-InetAddress-get.m2i @@ -0,0 +1,100 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-InetAddress-get.m2i 11795 2005-01-06 14:49:39Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11795 $ */ +@end@ +######################################################################## +## + /* + * TODO:231:M: |-> copy $node data. + * TODO:231:M: | |-> get address type from your context pointer. + */ + int addressType = -1; + size_t actual_size = 0; + + return MFD_SKIP; /* TODO:235:M: |-> Remove SKIP once you've set $node data */ + + switch (addressType) { + case INETADDRESSTYPE_UNKNOWN: + /* + * An unknown address type. This value MUST be used if the value + * of the InetAddress object is a zero-length string. It may also be + * used to indicate an IP address which is not in one of the formats + * defined below. + */ + actual_size = ${m2c_ctx_rhs}; + break; + + case INETADDRESSTYPE_IPV4: + /* + * Represents an IPv4 network address: + * octets contents encoding + * 1-4 IPv4 address network-byte order + */ + actual_size = 4; + break; + + case INETADDRESSTYPE_IPV6: + /* + * Represents an IPv6 network address: + * + * octets contents encoding + * 1-16 IPv6 address network-byte order + */ + actual_size = 16; + break; + + case INETADDRESSTYPE_IPV4Z: + /* + * Represents a non-global IPv4 network address together + * with its zone index: + * + * octets contents encoding + * 1-4 IPv4 address network-byte order + * 5-8 zone index network-byte order + */ + actual_size = 8; + break; + + case INETADDRESSTYPE_IPV6Z: + /* + * Represents a non-global IPv6 network address together + * with its zone index: + * + * octets contents encoding + * 1-16 IPv6 address network-byte order + * 17-20 zone index network-byte order + */ + actual_size = 20; + break; + + case INETADDRESSTYPE_DNS: + /* + * Represents a DNS domain name. The name SHOULD be fully + * qualified whenever possible. + */ + actual_size = ${m2c_ctx_rhs}; + break; + + default: + snmp_log(LOG_ERR, "unknown InetAddressType %d for $node\n", + addressType); + return SNMP_ERR_GENERR; + } + + if ( actual_size > ${m2c_ctx_lhs} ) { + snmp_log(LOG_ERR, "actual size %d too big for $node\n", + addressType); + return SNMP_ERR_GENERR; + } + + memcpy( ${m2c_ctx_lh}, ${m2c_ctx_rh}, actual_size); + ${m2c_ctx_lhs} = actual_size; +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11795 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-InetAddress-set.m2i b/local/mib2c-conf.d/syntax-InetAddress-set.m2i new file mode 100644 index 0000000..9ab9cbb --- /dev/null +++ b/local/mib2c-conf.d/syntax-InetAddress-set.m2i @@ -0,0 +1,22 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-InetAddress-set.m2i 9070 2003-11-04 15:32:23Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 9070 $ */ +@end@ +######################################################################## +## + /* + * Note: if there is a corresponding InetAddressType object, we don't + * know if they'll be set together, or which order they will be set. + * So we just accept the value here, and check that both values are + * consistent in ${context}_check_dependencies(). + */ +@include generic-ctx-set.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 9070 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-InetAddressType-get.m2i b/local/mib2c-conf.d/syntax-InetAddressType-get.m2i new file mode 100644 index 0000000..792e221 --- /dev/null +++ b/local/mib2c-conf.d/syntax-InetAddressType-get.m2i @@ -0,0 +1,25 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-InetAddressType-get.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## +@include generic-get-decl.m2i@ +@include generic-ctx-get.m2i@ + /* the ${context}_rowreq_ctx->data pointer should be pointer to the data you + supplied during the data lookup, so you should know how to + determine the InetAddressType from this pointer. */ + + return MFD_SKIP; /* TODO:235:M: |-> Remove SKIP once you've set $node data */ + +@include generic-value-map.m2i@ +@include generic-get-decl-bot.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-InetAddressType-set.m2i b/local/mib2c-conf.d/syntax-InetAddressType-set.m2i new file mode 100644 index 0000000..091ccc9 --- /dev/null +++ b/local/mib2c-conf.d/syntax-InetAddressType-set.m2i @@ -0,0 +1,25 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-InetAddressType-set.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## + /* + * TODO:230:o: Set $node data + * set data context from $m2c_ctx_rh + * + * Note: if there is a corresponding InetAddress object, we don't + * know if they'll be set together, or which order they will be set. + * So we just accept the value here, and check that both values are + * consistent in ${context}_check_dependencies(). + */ +@include generic-ctx-set.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-RowStatus-dependencies.m2i b/local/mib2c-conf.d/syntax-RowStatus-dependencies.m2i new file mode 100644 index 0000000..121006c --- /dev/null +++ b/local/mib2c-conf.d/syntax-RowStatus-dependencies.m2i @@ -0,0 +1,113 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-RowStatus-dependencies.m2i 12850 2005-09-27 15:42:43Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12850 $ */ +@end@ +######################################################################## +## { + /* + * check RowStatus dependencies + */ + if (rowreq_ctx->column_set_flags & COLUMN_$node.uc_FLAG) { + /* + * check for valid RowStatus transition (old, new) + * (Note: move transition check to $node_check_value + * to catch errors earlier) + */ + rc = check_rowstatus_transition( ${m2c_undo_item}$node, + ${m2c_data_item}$node ); + if (MFD_SUCCESS != rc) + return rc; + +@if $m2c_table_row_creation == 1@ + /* + * row creation requirements + */ + if (rowreq_ctx->rowreq_flags & MFD_ROW_CREATED) { + if (ROWSTATUS_DESTROY == ${m2c_data_item}$node) { + rowreq_ctx->rowreq_flags |= MFD_ROW_DELETED; + } + else if (ROWSTATUS_CREATEANDGO == ${m2c_data_item}$node) { + if ((rowreq_ctx->column_set_flags & $context.uc_REQUIRED_COLS) + != $context.uc_REQUIRED_COLS) { + DEBUGMSGTL(("${context}", + "required columns missing (0x%0x != 0x%0x)\n", + rowreq_ctx->column_set_flags, $context.uc_REQUIRED_COLS)); + return MFD_CANNOT_CREATE_NOW; + } + ${m2c_data_item}$node = ROWSTATUS_ACTIVE; + } + } /* row creation */ + else { +@end@ + /* + * row change requirements + */ + /* + * don't allow a destroy if any other value was changed, since + * that might call data access routines with bad info. + * + * you may or may not require the row be notInService before it + * can be destroyed. + */ + if (ROWSTATUS_DESTROY == ${m2c_data_item}$node) { +@if $m2c_table_refcounts == 1@ + if (0 != rowreq_ctx->ref_count) { + DEBUGMSGTL(("$context", + "can't delete row, %d references\n", + rowreq_ctx->ref_count)); + return MFD_NOT_VALID_NOW; + } +@end@ + if (rowreq_ctx->column_set_flags & ~COLUMN_$node.uc_FLAG) { + DEBUGMSGTL(("$context", + "destroy must be only varbind for row\n")); + return MFD_NOT_VALID_NOW; + } + rowreq_ctx->rowreq_flags |= MFD_ROW_DELETED; + + } /* row destroy */ +@if $m2c_table_refcounts == 1@ + else if(ROWSTATUS_NOTINSERVICE == ${m2c_data_item}$node) { + if (0 != rowreq_ctx->ref_count) { + DEBUGMSGTL(("$context", + "can't deactivate row, %d references\n", + rowreq_ctx->ref_count)); + return MFD_NOT_VALID_NOW; + } + } /* notInService */ +@end@ +@if $m2c_table_row_creation == 1@ + } /* row change */ +@end@ + } + else { +@if $m2c_table_row_creation == 1@ + /* + * must have row status to create a row + */ + if (rowreq_ctx->rowreq_flags & MFD_ROW_CREATED) { + DEBUGMSGTL(("$context", + "must use RowStatus to create rows\n")); + return MFD_CANNOT_CREATE_NOW; + } +@else@ + /* + * row creation not supported + */ + if (rowreq_ctx->rowreq_flags & MFD_ROW_CREATED) { + DEBUGMSGTL(("$context", + "row creation not supported\n")); + return MFD_CANNOT_CREATE_EVER; + } +@end@ + } /* row status not set */ + +## } +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12850 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-RowStatus-get.m2i b/local/mib2c-conf.d/syntax-RowStatus-get.m2i new file mode 100644 index 0000000..1a418de --- /dev/null +++ b/local/mib2c-conf.d/syntax-RowStatus-get.m2i @@ -0,0 +1,65 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-RowStatus-get.m2i 12090 2005-04-18 22:04:52Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 12090 $ */ +@end@ +######################################################################## +## +@include generic-get-decl.m2i@ +@include generic-ctx-get.m2i@ +@if $m2c_node_skip_mapping != 1@ + /* + * TODO:245:o: |-> Implement $context RowStatus mapping +@if $mfd_code_verbose == 1@ + * + * If the values for your data type don't exactly match the + * possible values defined by the mib, you should map them here. +@end@ + */ + /* + * update INTERNAL_* macros defined in the header, if neccessary + */ + switch ($m2c_node_lh) { + + /* `active', which indicates that the conceptual row is + available for use by the managed device */ + case INTERNAL_$context.uc_$node.uc_ACTIVE: + $m2c_node_lh = ROWSTATUS_ACTIVE; + break; + + /* `notInService', which indicates that the conceptual + row exists in the agent, but is unavailable for use by + the managed device (see NOTE below); 'notInService' has + no implication regarding the internal consistency of + the row, availability of resources, or consistency with + the current state of the managed device */ + case INTERNAL_$context.uc_$node.uc_NOTINSERVICE: + $m2c_node_lh = ROWSTATUS_NOTINSERVICE; + break; + + /* `notReady', which indicates that the conceptual row + exists in the agent, but is missing information + necessary in order to be available for use by the + managed device (i.e., one or more required columns in + the conceptual row have not been instanciated) */ + case INTERNAL_$context.uc_$node.uc_NOTREADY: + $m2c_node_lh = ROWSTATUS_NOTREADY; + break; + + default: + snmp_log(LOG_ERR, + "couldn't map value %ld for $node RowStatus\n", + $m2c_node_lh); + return SNMP_ERR_GENERR; + } + +@end@ +@include generic-get-decl-bot.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 12090 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-RowStatus-varbind-validate.m2i b/local/mib2c-conf.d/syntax-RowStatus-varbind-validate.m2i new file mode 100644 index 0000000..79cec51 --- /dev/null +++ b/local/mib2c-conf.d/syntax-RowStatus-varbind-validate.m2i @@ -0,0 +1,16 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-RowStatus-varbind-validate.m2i 8857 2003-10-01 00:20:35Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 8857 $ */ +@end@ +######################################################################## +## +rc = netsnmp_check_vb_rowstatus_value(var); +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 8857 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-StorageType-dependencies.m2i b/local/mib2c-conf.d/syntax-StorageType-dependencies.m2i new file mode 100644 index 0000000..a2ee74f --- /dev/null +++ b/local/mib2c-conf.d/syntax-StorageType-dependencies.m2i @@ -0,0 +1,19 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-StorageType-dependencies.m2i 11057 2004-09-10 21:39:36Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11057 $ */ +@end@ +######################################################################## +## { + /* + * check for valid StorageType transition (old, new) + */ + rc = check_storage_transition( ${m2c_undo_item}$node, ${m2c_data_item}$node ); +## } +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11057 $ */ +@end@ diff --git a/local/mib2c-conf.d/syntax-TestAndIncr-get.m2i b/local/mib2c-conf.d/syntax-TestAndIncr-get.m2i new file mode 100644 index 0000000..6da07f9 --- /dev/null +++ b/local/mib2c-conf.d/syntax-TestAndIncr-get.m2i @@ -0,0 +1,22 @@ +############################################################# -*- c -*- +## generic include for XXX. Do not use directly. +## +## $Id: syntax-TestAndIncr-get.m2i 11300 2004-10-08 23:39:17Z rstory $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ +######################################################################## +## +@include generic-get-decl.m2i@ + + return MFD_SKIP; /* TODO:235:M: Remove SKIP once you've set $node data */ + +@include generic-ctx-get.m2i@ +@include generic-get-long.m2i@ +@include generic-get-decl-bot.m2i@ +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11300 $ */ +@end@ diff --git a/local/mib2c-update b/local/mib2c-update new file mode 100755 index 0000000..ebdfd34 --- /dev/null +++ b/local/mib2c-update @@ -0,0 +1,358 @@ +#!/bin/bash +# +# $Id: mib2c-update 16702 2007-09-16 09:51:41Z magfr $ +# +# script to merge custom code into updated mib2c code +# +#----- example .mib2c-updaterc ----- +#UPDATE_OID=ipAddressTable +#UPDATE_CONF=mib2c.mfd.conf +#UPDATE_MIB2C_OPTS= +#UPDATE_NOPROBE=1 +#----- example .mib2c-updaterc ----- + +#---------------------------------------------------------------------- +# +# defaults +# +UPDATE_CURR=$PWD +UPDATE_ORIG=$PWD/.orig +UPDATE_NEW=$PWD/.new +UPDATE_MERGED=$PWD/.merged +UPDATE_BACKUP=$PWD/.backup +UPDATE_PATCH=$PWD/.patch + +# +# number of diff context lines / patch fuzz factor +# +FUZZ=5 +FIRST_RUN=0 + +#---------------------------------------------------------------------- +# +debug() +{ + if [ $UPDATE_DEBUG -ge 1 ]; then + echo $1 + fi +} + +error() +{ + echo "ERROR: $@" > /dev/stderr +} + +die() +{ + error "$@" + exit 99 +} + +safecd() +{ + cd $1 + if [ $? -ne 0 ]; then + die "changing to directory $1 from $PWD failed!" + fi +} + +safecp() +{ + cp $@ + if [ $? -ne 0 ]; then + die "'cp $@' failed!" + fi +} + +#---------------------------------------------------------------------- +# +check_setup() +{ + rc=1 + for d in $UPDATE_CURR $UPDATE_ORIG $UPDATE_NEW $UPDATE_MERGED $UPDATE_PATCH $UPDATE_BACKUP $UPDATE_BACKUP/curr $UPDATE_BACKUP/orig + do + if [ ! -d $d ]; then + echo "Creating missing directory $d" + mkdir -p $d + if [ $? -ne 0 ]; then + error "Could not create directory $d" + rc=0 + fi + fi + done + + if [ -z "$UPDATE_OID" ]; then + error "Environment variable missing! Set UPDATE_OID in .mib2c-updaterc" + rc=0 + fi + + if [ -z "$UPDATE_CONF" ]; then + error "Environment variable missing! Set UPDATE_CONF in .mib2c-updaterc" + rc=0 + fi + +# if [ -z "$UPDATE_" ]; then +# error "Environment variable missing! Set UPDATE_ in .mib2c-updaterc" +# rc=0 +# fi + + if [ $rc -eq 0 ] && [ $UPDATE_NOPROBE -ne 1 ]; then + mib2c -c unknown > /dev/null 2>&1 + if [ $? -eq 0 ]; then + error "WARNING: mib2c returns 0 on error conditions!" + rc=0 + fi + fi + + return $rc +} + +#---------------------------------------------------------------------- +# +do_diff() +{ + DD_ORIG=$1 + DD_CURR=$2 + DD_OUTPUT=$3 + # u | c unified | context + # r recursive + # b ignore blank lines + # w ignore white space + # p Show which C function each change is in. + # d smaller changes + # --exclude='*Makefile' --unidirectional-new-file + local rc=0 + local rcs=0 + safecd $DD_ORIG + echo " checking files in $1 ($PWD)" + files=`ls *$UPDATE_OID* 2>/dev/null` + if [ ! -z "$files" ]; then + for f in $files; do + diff -U $FUZZ -p -b -w --show-c-function \ + -I "$""Id:" $f $DD_CURR/$f >> $DD_OUTPUT + rc=$? + rcs=`expr $rcs + $rc` + if [ $rc -eq 1 ]; then + echo " $f is different" + fi + done + fi + if [ $rcs -eq 0 ]; then + rm -f $DD_OUTPUT + fi + safecd - + return $rcs +} + +#---------------------------------------------------------------------- +# +do_cp() +{ + src=$1 + dest=$2 + if [ ! -d $dest ]; then + die "dest $dest is not a directory" + fi + if [ ! -d $src ]; then + die "src $src is not a directory" + fi + safecd $src + files=`ls *$UPDATE_OID* 2>/dev/null| egrep "(file|onf|m2d|txt|\.c|\.h)$"` + if [ -z "$files" ]; then + echo " no files to copy from $src" + else + safecp $files $dest + if [ $? -ne 0 ]; then + die "error while copying files from $src to $dest in $PWD" + fi + fi + safecd - +} + +#---------------------------------------------------------------------- +# +save_diff() +{ + echo "Creating patch for your custom code" + cnt=`ls $UPDATE_CURR/*$UPDATE_OID* 2>/dev/null | egrep "(file|onf|m2d|txt|\.c|\.h)$" | wc -l` + if [ $cnt -eq 0 ]; then + echo " no custom code!" + FIRST_RUN=1 + return + fi + + do_diff $UPDATE_ORIG/ $UPDATE_CURR/ $UPDATE_PATCH/custom.$UPDATE_DATE + if [ $? -eq 0 ]; then + echo " no custom code changes found." + fi +} + +#---------------------------------------------------------------------- +# +gen_code() +{ + copy_defaults . $UPDATE_NEW + + safecd $UPDATE_NEW + files=`ls *$UPDATE_OID* 2>/dev/null | grep -v "^default"` + if [ ! -z "$files" ]; then + rm -f $files > /dev/null 2>&1 + fi + echo "mib2c $@ -c $UPDATE_CONF $UPDATE_MIB2C_OPTS $UPDATE_OID" + mib2c $@ -c $UPDATE_CONF $UPDATE_MIB2C_OPTS $UPDATE_OID + if [ $? -ne 0 ]; then + die "bad rc $rc from mib2 while generation new code." + fi + safecd - +} + +#---------------------------------------------------------------------- +# +check_new() +{ + echo "Checking for updates to generated code" + do_diff $UPDATE_ORIG/ $UPDATE_NEW/ $UPDATE_PATCH/generated.$UPDATE_DATE + if [ $? -eq 0 ]; then + echo "Generated code has not changed." + safecd $UPDATE_PATCH + files=`ls *.$UPDATE_DATE 2>/dev/null ` + if [ ! -z "$files" ]; then + rm $files + fi + exit 0 + fi +} + +#---------------------------------------------------------------------- +# +merge_code() +{ + files=`ls $UPDATE_MERGED/* 2>/dev/null ` + if [ ! -z "$files" ]; then + rm $UPDATE_MERGED/* + fi + do_cp $UPDATE_NEW $UPDATE_MERGED + + if [ -f $UPDATE_PATCH/custom.$UPDATE_DATE ]; then + touch .M2C-UPDATE-MERGE-FAILED + echo "Patching new generated code in $UPDATE_MERGED ($PWD)" + # --forward = ignore already applied + patch --forward -F $FUZZ -N -d $UPDATE_MERGED -i $UPDATE_PATCH/custom.$UPDATE_DATE + if [ $? -ne 0 ]; then + error "Could not apply custom code patch to new generated code" + die "You must fix the problem in $UPDATE_MERGED, and then re-run mib2c-update." + fi + rm .M2C-UPDATE-MERGE-FAILED + fi +} + +copy_defaults() +{ + SRC=$1 + DST=$2 + if [ -d $SRC/defaults ]; then + safecp -a $SRC/defaults $DST + else + files=`ls $SRC/default-*.m2d 2>/dev/null ` + if [ ! -z "$files" ]; then + safecp $files $DST + fi + fi + +} + +copy_merged() +{ + echo "Backing up current code to $UPDATE_BACKUP/curr" + do_cp $UPDATE_CURR $UPDATE_BACKUP/curr/ + copy_defaults . $UPDATE_BACKUP/curr/ + + echo "Copying merged code to $UPDATE_CURR" + do_cp $UPDATE_MERGED $UPDATE_CURR/ + + + echo "Backing up original code to $UPDATE_BACKUP/orig" + do_cp $UPDATE_ORIG $UPDATE_BACKUP/orig/ + echo "Saving new original code to $UPDATE_ORIG" + do_cp $UPDATE_NEW $UPDATE_ORIG/ +} + +copy_new() +{ + echo "Copying code to $UPDATE_CURR" + do_cp $UPDATE_NEW $UPDATE_CURR/ + # copy defaults back to current dir (which may not be UPDATE_CURR) + copy_defaults $UPDATE_NEW . + + echo "Saving original code to $UPDATE_ORIG" + do_cp $UPDATE_NEW $UPDATE_ORIG/ +} + +copy_code() +{ + if [ $FIRST_RUN -ne 1 ]; then + copy_merged + else + copy_new + fi + + # always get defaults from UPDATE_NEW, since those are what were used. + copy_defaults $UPDATE_NEW . +} + + +#---------------------------------------------------------------------- +UPDATE_NOPROBE=0 + +if [ -f $HOME/.mib2c-updaterc ]; then + . $HOME/.mib2c-updaterc +fi + +if [ -f .mib2c-updaterc ]; then + . .mib2c-updaterc +fi + +check_setup +if [ $? -ne 1 ]; then + exit 1 +fi + +UPDATE_DATE=`date "+%F_%I.%M"` +echo "Starting regneration of $UPDATE_OID using $UPDATE_CONF at $UPDATE_DATE" + +if [ -f .M2C-UPDATE-MERGE-FAILED ]; then + echo "It appears that the last run of mib2c-update was not able to merge" + echo "your changes automatically. Do you want to:" + echo + while : ; do + echo "[c)opy merged files to $UPDATE_CURR]" + echo "[r)e-run from scratch]" + echo "[q)uit]" + echo "(c|r|q) ?" + read ans + if [ "x$ans" = "xr" ]; then + rm .M2C-UPDATE-MERGE-FAILED + break + elif [ "x$ans" = "xc" ]; then + echo "Have you have manually merged all the" + echo "changes into the merged directory?" + echo "(y|n)" + read ans + if [ "x$ans" != "xy" ]; then + echo "Ok. Try again after you've done that." + exit 1 + fi + rm .M2C-UPDATE-MERGE-FAILED + copy_code + exit 0 + fi + done +fi + +save_diff +gen_code $@ +if [ $FIRST_RUN -ne 1 ]; then + check_new + merge_code +fi +copy_code diff --git a/local/mib2c.access_functions.conf b/local/mib2c.access_functions.conf new file mode 100644 index 0000000..0f2780b --- /dev/null +++ b/local/mib2c.access_functions.conf @@ -0,0 +1,183 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}_access.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.access_functions.conf 11358 2004-10-14 12:57:34Z dts12 $ + */ +#ifndef $name.uc_ACCESS_H +#define $name.uc_ACCESS_H + +@foreach $t table@ +/** User-defined data access functions for data in table $t */ +/** row level accessors */ +Netsnmp_First_Data_Point ${t}_get_first_data_point; +Netsnmp_Next_Data_Point ${t}_get_next_data_point; +int ${t}_commit_row(void **my_data_context, int new_or_del); +void * ${t}_create_data_context(netsnmp_variable_list *index_data, int column); + +/** column accessors */ + @foreach $c column@ + @if $c.access =~ /(Read|Create)/@ + $c.decl *get_$c(void *data_context, size_t *ret_len); + @end@ + @if $c.access =~ /(Write|Create)/@ + int set_$c(void *data_context, $c.decl *val, size_t val_len); + @end@ + @end@ +@end@ + +#endif /* $name.uc_ACCESS_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}_access.c@ + +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.access_functions.conf 11358 2004-10-14 12:57:34Z dts12 $ + */ + +#include +#include +#include +#include "${name}_access.h" +#include "${name}_enums.h" + +@foreach $t table@ + +/** returns the first data point within the $t table data. + + Set the my_loop_context variable to the first data point structure + of your choice (from which you can find the next one). This could + be anything from the first node in a linked list, to an integer + pointer containing the beginning of an array variable. + + Set the my_data_context variable to something to be returned to + you later that will provide you with the data to return in a given + row. This could be the same pointer as what my_loop_context is + set to, or something different. + + The put_index_data variable contains a list of snmp variable + bindings, one for each index in your table. Set the values of + each appropriately according to the data matching the first row + and return the put_index_data variable at the end of the function. +*/ +netsnmp_variable_list * +${t}_get_first_data_point(void **my_loop_context, void **my_data_context, + netsnmp_variable_list *put_index_data, + netsnmp_iterator_info *mydata) +{ + + netsnmp_variable_list *vptr; + + *my_loop_context = /** XXX */; + *my_data_context = /** XXX */; + + vptr = put_index_data; + + @foreach $idx index@ + snmp_set_var_value(vptr, (u_char *) /** XXX: $idx data */, /** XXX: length of $idx data */); + vptr = vptr->next_variable; + @end@ + + return put_index_data; +} + +/** functionally the same as ${t}_get_first_data_point, but + my_loop_context has already been set to a previous value and should + be updated to the next in the list. For example, if it was a + linked list, you might want to cast it to your local data type and + then return my_loop_context->next. The my_data_context pointer + should be set to something you need later and the indexes in + put_index_data updated again. */ +netsnmp_variable_list * +${t}_get_next_data_point(void **my_loop_context, void **my_data_context, + netsnmp_variable_list *put_index_data, + netsnmp_iterator_info *mydata) +{ + + netsnmp_variable_list *vptr; + + *my_loop_context = /** XXX */; + *my_data_context = /** XXX */; + + vptr = put_index_data; + + @foreach $idx index@ + snmp_set_var_value(vptr, (u_char *) /** XXX: $idx data */, /** XXX: length of $idx data */); + vptr = vptr->next_variable; + @end@ + + return put_index_data; +} + +/** Create a data_context for non-existent rows that SETs are performed on. + * return a void * pointer which will be passed to subsequent get_XXX + * and set_XXX functions for data retrival and modification during + * this SET request. + * + * The indexes are encoded (in order) into the index_data pointer, + * and the column object which triggered the row creation is available + * via the column parameter, if it would be helpful to use that information. + */ +void * +${t}_create_data_context(netsnmp_variable_list *index_data, int column) { + return NULL; /* XXX: you likely want to return a real pointer */ +} + +/** If the implemented set_* functions don't operate directly on the + real-live data (which is actually recommended), then this function + can be used to take a given my_data_context pointer and "commit" it + to whereever the modified data needs to be put back to. For + example, if this was a routing table you could publish the modified + routes back into the kernel at this point. + + new_or_del will be set to 1 if new, or -1 if it should be deleted + or 0 if it is just a modification of an existing row. + + If you free the data yourself, make sure to *my_data_context = NULL */ +int +${t}_commit_row(void **my_data_context, int new_or_del) +{ + /** Add any necessary commit code here */ + /* */ + + /* return no errors. And there shouldn't be any!!! Ever!!! You + should have checked the values long before this. */ + return SNMP_ERR_NOERROR; +} + + +/* User-defined data access functions (per column) for data in table $t */ +/* + * NOTE: + * - these get_ routines MUST return data that will not be freed (ie, + * use static variables or persistent data). It will be copied, if + * needed, immediately after the get_ routine has been called. + * - these SET routines must copy the incoming data and can not take + * ownership of the memory passed in by the val pointer. + */ + @foreach $c column@ + @if $c.access =~ /(Read|Create)/@ +/** XXX: return a data pointer to the data for the $c column and set + ret_len to its proper size in bytes. */ + $c.decl *get_$c(void *data_context, size_t *ret_len) { + return NULL; /** XXX: replace this with a pointer to a real value */ + } + @end@ + @if $c.access =~ /(Write|Create)/@ +/** XXX: Set the value of the $c column and return + SNMP_ERR_NOERROR on success + SNMP_ERR_XXX for SNMP deterministic error codes + SNMP_ERR_GENERR on generic failures (a last result response). */ + int set_$c(void *data_context, $c.decl *val, size_t val_len) { + return SNMP_ERR_NOERROR; /** XXX: change if an error occurs */ + } + @end@ + @end@ + +@end@ + diff --git a/local/mib2c.array-user.conf b/local/mib2c.array-user.conf new file mode 100644 index 0000000..9ad42f7 --- /dev/null +++ b/local/mib2c.array-user.conf @@ -0,0 +1,1305 @@ +## -*- c -*- +## +## For documentation on the code generated by this configuration file, +## see the file agent/helpers/table_array.c. +## +###################################################################### +## Do the .h file +## @perleval $vars{shortname} =~ s/([A-Z])[a-z]+/$1/g@ +###################################################################### +@foreach $i table@ +@open ${i}.h@ +@eval $hack = "Id" +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.array-user.conf 15997 2007-03-25 22:28:35Z dts12 $ + * + * $$hack:$ + * + * Yes, there is lots of code here that you might not use. But it is much + * easier to remove code than to add it! + */ +#ifndef $i.uc_H +#define $i.uc_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include +#include + + @eval $ext_index = 0@ + @foreach $idx index@ + @if "$idx" ne ""@ + @eval $found = "external"@ + @foreach $c column@ + @if "$idx" eq "$c"@ + @eval $found = "internal"@ + @end@ + @end@ + /** Index $idx is $found */ + @if "$found" eq "external"@ + @eval $ext_index = 1@ + @end@ + @end@ + @end@ + +typedef struct ${i}_context_s { + netsnmp_index index; /** THIS MUST BE FIRST!!! */ + + /************************************************************* + * You can store data internally in this structure. + * + * TODO: You will probably have to fix a few types here... + */ + @if $ext_index != 0@ + /** TODO: add storage for external index(s)! */ + @end@ + @foreach $c column@ + /** $c.syntax = $c.type */ + @eval $have_type = 0@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_type = 1@ + @eval $o_len = "65535"@ + @if "$c.syntax" eq "DisplayString"@ + @eval $o_len = "255"@ + @end@ + @if "$c.syntax" eq "SnmpAdminString"@ + @eval $o_len = "255"@ + @end@ + unsigned char $c[$o_len]; + long ${c}_len; + @end@ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_type = 1@ + oid $c[MAX_OID_LEN]; + long ${c}_len; + @end@ + @if "$c.type" eq "ASN_UNSIGNED"@ + @eval $have_type = 1@ + unsigned long $c; + @end@ + @if "$c.type" eq "ASN_TIMETICKS"@ + @eval $have_type = 1@ + unsigned long $c; + @end@ + @if "$c.type" eq "ASN_IPADDRESS"@ + @eval $have_type = 1@ + unsigned long $c; + @end@ + @if "$c.type" eq "ASN_UINTEGER"@ + @eval $have_type = 1@ + unsigned long $c; + @end@ + @if "$c.type" eq "ASN_INTEGER"@ + @eval $have_type = 1@ + long $c; + @end@ + @if "$c.type" eq "ASN_COUNTER"@ + @eval $have_type = 1@ + unsigned long $c; + @end@ + @if $have_type == 0@ + /** TODO: Is this type correct? */ + long $c; + @end@ + + @end@ + + /* + * OR + * + * Keep a pointer to your data + */ + void * data; + + /* + *add anything else you want here + */ + +} ${i}_context; + +/************************************************************* + * function declarations + */ +void init_$i(void); +void initialize_table_$i(void); +const ${i}_context * ${i}_get_by_idx(netsnmp_index *); +const ${i}_context * ${i}_get_by_idx_rs(netsnmp_index *, + int row_status); +int ${i}_get_value(netsnmp_request_info *, netsnmp_index *, netsnmp_table_request_info *); + + +/************************************************************* + * oid declarations + */ +extern oid ${i}_oid[]; +extern size_t ${i}_oid_len; + +#define ${i}_TABLE_OID $i.commaoid + +/************************************************************* + * column number definitions for table $i + */ +@eval $minv = 0xffffffff@ +@eval $maxv = 0@ +@foreach $c column@ +#define COLUMN_$c.uc $c.subid +@if ! $c.noaccess@ +@eval $minv = min($minv, $c.subid)@ +@eval $maxv = max($maxv, $c.subid)@ +@end@ +@if "$c.syntax" eq "RowStatus"@ + @eval $rs_name = "$c"@ +@end@ +@if "$c.syntax" eq "StorageType"@ + @eval $st_name = "$c"@ +@end@ +@end@ +#define ${i}_COL_MIN $minv +#define ${i}_COL_MAX $maxv + +/* comment out the following line if you don't want a custom sort */ +#define ${i}_CUSTOM_SORT + +@if "$rs_name" ne ""@ +/* uncommend the following line if you allow modifications to an + * active row */ +/** define ${i}_CAN_MODIFY_ACTIVE_ROW */ + +@end@ +@if $i.settable@ +int ${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr ); + +void ${i}_set_reserve1( netsnmp_request_group * ); +void ${i}_set_reserve2( netsnmp_request_group * ); +void ${i}_set_action( netsnmp_request_group * ); +void ${i}_set_commit( netsnmp_request_group * ); +void ${i}_set_free( netsnmp_request_group * ); +void ${i}_set_undo( netsnmp_request_group * ); + +${i}_context * ${i}_duplicate_row( ${i}_context* ); +netsnmp_index * ${i}_delete_row( ${i}_context* ); + +@if "$rs_name" ne ""@ +int ${i}_can_activate(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg); +int ${i}_can_deactivate(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg); +@end@ +int ${i}_can_delete(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg); + + +@if $i.creatable@ +${i}_context * ${i}_create_row( netsnmp_index* ); +@end@ +@end@ + +#ifdef ${i}_CUSTOM_SORT +${i}_context * ${i}_get( const char *name, int len ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /** $i.uc_H */ +@end@ +###################################################################### +## Do the .c file +###################################################################### +@foreach $i table@ +@open ${i}.c@ +@eval $hack = "Id"@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.array-user.conf 15997 2007-03-25 22:28:35Z dts12 $ + * + * $$hack:$ + * + * + * For help understanding NET-SNMP in general, please check the + * documentation and FAQ at: + * + * http://www.net-snmp.org/ + * + * + * For help understanding this code, the agent and how it processes + * requests, please check the following references. + * + * http://www.net-snmp.org/tutorial-5/ + * + * + * You can also join the #net-snmp channel on irc.freenode.net + * and ask for help there. + * + * + * And if all else fails, send a detailed message to the developers + * describing the problem you are having to: + * + * net-snmp-coders@lists.sourceforge.net + * + * + * Yes, there is lots of code here that you might not use. But it is much + * easier to remove code than to add it! + */ +#include +#include +#include + +#include + +#include "${i}.h" + +static netsnmp_handler_registration *my_handler = NULL; +static netsnmp_table_array_callbacks cb; + +oid ${i}_oid[] = { ${i}_TABLE_OID }; +size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + + +#ifdef ${i}_CUSTOM_SORT +/************************************************************ + * keep binary tree to find context by name + */ +static int ${i}_cmp( const void *lhs, const void *rhs ); + +/************************************************************ + * compare two context pointers here. Return -1 if lhs < rhs, + * 0 if lhs == rhs, and 1 if lhs > rhs. + */ +static int +${i}_cmp( const void *lhs, const void *rhs ) +{ + ${i}_context *context_l = + (${i}_context *)lhs; + ${i}_context *context_r = + (${i}_context *)rhs; + + /* + * check primary key, then secondary. Add your own code if + * there are more than 2 keys + */ + int rc; + + /* + * TODO: implement compare. Remove this ifdef code and + * add your own code here. + */ +#ifdef TABLE_CONTAINER_TODO + snmp_log(LOG_ERR, + "${i}_compare not implemented! Container order undefined\n" ); + return 0; +#endif + + /* + * EXAMPLE (assuming you want to sort on a name): + * + * rc = strcmp( context_l->xxName, context_r->xxName ); + * + * if(rc) + * return rc; + * + * TODO: fix secondary keys (or delete if there are none) + * + * if(context_l->yy < context_r->yy) + * return -1; + * + * return (context_l->yy == context_r->yy) ? 0 : 1; + */ +} + +/************************************************************ + * search tree + */ +/** TODO: set additional indexes as parameters */ +${i}_context * +${i}_get( const char *name, int len ) +{ + ${i}_context tmp; + + /** we should have a custom container */ + netsnmp_assert(cb.container->next != NULL); + + /* + * TODO: implement compare. Remove this ifdef code and + * add your own code here. + */ +#ifdef TABLE_CONTAINER_TODO + snmp_log(LOG_ERR, "${i}_get not implemented!\n" ); + return NULL; +#endif + + /* + * EXAMPLE: + * + * if(len > sizeof(tmp.xxName)) + * return NULL; + * + * strncpy( tmp.xxName, name, sizeof(tmp.xxName) ); + * tmp.xxName_len = len; + * + * return CONTAINER_FIND(cb.container->next, &tmp); + */ +} +#endif + + +/************************************************************ + * Initializes the $i module + */ +void +init_$i(void) +{ + initialize_table_$i(); + + /* + * TODO: perform any startup stuff here, such as + * populating the table with initial data. + * + * ${i}_context * new_row = create_row(index); + * CONTAINER_INSERT(cb.container,new_row); + */ +} + +@if $i.settable@ +/************************************************************ + * the *_row_copy routine + */ +static int ${i}_row_copy(${i}_context * dst, + ${i}_context * src) +{ + if(!dst||!src) + return 1; + + /* + * copy index, if provided + */ + if(dst->index.oids) + free(dst->index.oids); + if(snmp_clone_mem( (void*)&dst->index.oids, src->index.oids, + src->index.len * sizeof(oid) )) { + dst->index.oids = NULL; + return 1; + } + dst->index.len = src->index.len; + + + /* + * copy components into the context structure + */ + @if $ext_index != 0@ + /** TODO: add code for external index(s)! */ + @end@ + @foreach $c column@ + @eval $have_type = 0@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_type = 1@ + memcpy( dst->$c, src->$c, src->${c}_len ); + dst->${c}_len = src->${c}_len; + @end@ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_type = 1@ + memcpy( dst->$c, src->$c, src->${c}_len ); + dst->${c}_len = src->${c}_len; + @end@ + @if $have_type == 0@ + dst->$c = src->$c; + @end@ + + @end@ + return 0; +} + +/** + * the *_extract_index routine + * + * This routine is called when a set request is received for an index + * that was not found in the table container. Here, we parse the oid + * in the the individual index components and copy those indexes to the + * context. Then we make sure the indexes for the new row are valid. + */ +int +${i}_extract_index( ${i}_context * ctx, netsnmp_index * hdr ) +{ + /* + * temporary local storage for extracting oid index + * + * extract index uses varbinds (netsnmp_variable_list) to parse + * the index OID into the individual components for each index part. + */ + @if $ext_index != 0@ + /** TODO: add storage for external index(s)! */ + @end@ + @eval $first_idx = ""@ + @foreach $idx index@ + @if "$first_idx" eq ""@ + @eval $first_idx = $idx@ + @end@ + netsnmp_variable_list var_$idx; + @end@ + int err; + + /* + * copy index, if provided + */ + if(hdr) { + netsnmp_assert(ctx->index.oids == NULL); + if((hdr->len > MAX_OID_LEN) || + snmp_clone_mem( (void*)&ctx->index.oids, hdr->oids, + hdr->len * sizeof(oid) )) { + return -1; + } + ctx->index.len = hdr->len; + } + + /* + * initialize variable that will hold each component of the index. + * If there are multiple indexes for the table, the variable_lists + * need to be linked together, in order. + */ + @if $ext_index != 0@ + /** TODO: add code for external index(s)! */ + @end@ + @foreach $idx index@ + memset( &var_$idx, 0x00, sizeof(var_$idx) ); + var_${idx}.type = $idx.type; /* type hint for parse_oid_indexes */ + /** TODO: link this index to the next, or NULL for the last one */ +#ifdef TABLE_CONTAINER_TODO + snmp_log(LOG_ERR, "${i}_extract_index index list not implemented!\n" ); + return 0; +#else + var_${idx}.next_variable = &var_XX; +#endif + + @end@ + + /* + * parse the oid into the individual index components + */ + err = parse_oid_indexes( hdr->oids, hdr->len, &var_$first_idx ); + if (err == SNMP_ERR_NOERROR) { + /* + * copy index components into the context structure + */ + @foreach $idx index@ + @eval $found = "external"@ + @foreach $c column@ + @if "$idx" eq "$c"@ + @eval $found = "internal"@ + @end@ + @end@ + @if "$found" eq "external"@ + /** skipping external index $idx */ + @end@ + @if "$found" eq "internal"@ + @eval $have_type = 0@ + @if "$idx.type" eq "ASN_OCTET_STR"@ + @eval $have_type = 1@ + if(var_${idx}.val_len > sizeof(ctx->$idx)) + err = -1; + else + memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len ); + ctx->${idx}_len = var_${idx}.val_len; + @end@ + @if "$idx.type" eq "ASN_OBJECT_ID"@ + @eval $have_type = 1@ + memcpy( ctx->$idx, var_${idx}.val.string, var_${idx}.val_len ); + ctx->${idx}_len = var_${idx}.val_len; + @end@ + @if $have_type == 0@ + ctx->$idx = *var_${idx}.val.integer; + @end@ + @end@ + + @end@ + + @foreach $c index@ + /* + * TODO: check index for valid values. For EXAMPLE: + * + @eval $have_check = 0@ + @if "$c.type" eq "ASN_IPADDRESS"@ + @eval $have_check = 1@ + * if ( XXX_check_ip( *var_${c}.val.integer ) ) { + @end@ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_check = 1@ + * if ( XXX_check_oid( var_${c}.val.objid, var_${c}.val_len / + sizeof(oid) ) ) { + @end@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_check = 1@ + * if ( XXX_check_value( var_${c}.val.string, XXX ) ) { + @end@ + @if $have_check != 1@ + * if ( *var_${c}.val.integer != XXX ) { + @end@ + * err = -1; + * } + */ + @end@ + } + + /* + * parsing may have allocated memory. free it. + */ + snmp_reset_var_buffers( &var_$first_idx ); + + return err; +} + +@if "$rs_name" ne ""@ +/************************************************************ + * the *_can_activate routine is called + * when a row is changed to determine if all the values + * set are consistent with the row's rules for a row status + * of ACTIVE. + * + * return 1 if the row could be ACTIVE + * return 0 if the row is not ready for the ACTIVE state + */ +int ${i}_can_activate(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg) +{ + /* + * TODO: check for activation requirements here + */ + + + /* + * be optimistic. + */ + return 1; +} + +/************************************************************ + * the *_can_deactivate routine is called when a row that is + * currently ACTIVE is set to a state other than ACTIVE. If + * there are conditions in which a row should not be allowed + * to transition out of the ACTIVE state (such as the row being + * referred to by another row or table), check for them here. + * + * return 1 if the row can be set to a non-ACTIVE state + * return 0 if the row must remain in the ACTIVE state + */ +int ${i}_can_deactivate(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg) +{ + /* + * TODO: check for deactivation requirements here + */ + return 1; +} + +@end@ +/************************************************************ + * the *_can_delete routine is called to determine if a row + * can be deleted. + * + * return 1 if the row can be deleted + * return 0 if the row cannot be deleted + */ +int ${i}_can_delete(${i}_context *undo_ctx, + ${i}_context *row_ctx, + netsnmp_request_group * rg) +{ +@if "$rs_name" ne ""@ + /* + * probably shouldn't delete a row that we can't + * deactivate. + */ + if(${i}_can_deactivate(undo_ctx,row_ctx,rg) != 1) + return 0; +@end@ + + /* + * TODO: check for other deletion requirements here + */ + return 1; +} + +@if $i.creatable@ +/************************************************************ + * the *_create_row routine is called by the table handler + * to create a new row for a given index. If you need more + * information (such as column values) to make a decision + * on creating rows, you must create an initial row here + * (to hold the column values), and you can examine the + * situation in more detail in the *_set_reserve1 or later + * states of set processing. Simple check for a NULL undo_ctx + * in those states and do detailed creation checking there. + * + * returns a newly allocated ${i}_context + * structure if the specified indexes are not illegal + * returns NULL for errors or illegal index values. + */ +${i}_context * +${i}_create_row( netsnmp_index* hdr) +{ + ${i}_context * ctx = + SNMP_MALLOC_TYPEDEF(${i}_context); + if(!ctx) + return NULL; + + /* + * TODO: check indexes, if necessary. + */ + if(${i}_extract_index( ctx, hdr )) { + if (NULL != ctx->index.oids) + free(ctx->index.oids); + free(ctx); + return NULL; + } + + /* netsnmp_mutex_init(ctx->lock); + netsnmp_mutex_lock(ctx->lock); */ + + /* + * TODO: initialize any default values here. This is also + * first place you really should allocate any memory for + * yourself to use. If you allocated memory earlier, + * make sure you free it for earlier error cases! + */ + /** + @foreach $c column@ + @if $c.settable@ + ctx->$c = 0; + @end@ + @end@ + */ + + return ctx; +} +@end@ + +/************************************************************ + * the *_duplicate row routine + */ +${i}_context * +${i}_duplicate_row( ${i}_context * row_ctx) +{ + ${i}_context * dup; + + if(!row_ctx) + return NULL; + + dup = SNMP_MALLOC_TYPEDEF(${i}_context); + if(!dup) + return NULL; + + if(${i}_row_copy(dup,row_ctx)) { + free(dup); + dup = NULL; + } + + return dup; +} + +/************************************************************ + * the *_delete_row method is called to delete a row. + */ +netsnmp_index * ${i}_delete_row( ${i}_context * ctx ) +{ + /* netsnmp_mutex_destroy(ctx->lock); */ + + if(ctx->index.oids) + free(ctx->index.oids); + + /* + * TODO: release any memory you allocated here... + */ + + /* + * release header + */ + free( ctx ); + + return NULL; +} + + +/************************************************************ + * RESERVE is used to check the syntax of all the variables + * provided, that the values being set are sensible and consistent, + * and to allocate any resources required for performing the SET. + * After this stage, the expectation is that the set ought to + * succeed, though this is not guaranteed. (In fact, with the UCD + * agent, this is done in two passes - RESERVE1, and + * RESERVE2, to allow for dependancies between variables). + * + * BEFORE calling this routine, the agent will call duplicate_row + * to create a copy of the row (unless this is a new row; i.e. + * row_created == 1). + * + * next state -> SET_RESERVE2 || SET_FREE + */ +void ${i}_set_reserve1( netsnmp_request_group *rg ) +{ + ${i}_context *row_ctx = + (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = + (${i}_context *)rg->undo_info; + netsnmp_variable_list *var; + netsnmp_request_group_item *current; + int rc; + + @if "$st_name" ne ""@ + /* + * Block all attempts to modify a readOnly row + */ + if( row_ctx && (row_ctx->$st_name == SNMP_STORAGE_READONLY) ) { + netsnmp_set_mode_request_error(MODE_SET_BEGIN, rg->list->ri, + SNMP_ERR_NOTWRITABLE); + return; + } + @end@ + + /* + * TODO: loop through columns, check syntax and lengths. For + * columns which have no dependencies, you could also move + * the value/range checking here to attempt to catch error + * cases as early as possible. + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + rc = SNMP_ERR_NOERROR; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + @if $c.needlength@ + /* or possibly 'netsnmp_check_vb_type_and_size' */ + rc = netsnmp_check_vb_type_and_max_size(var, $c.type, + sizeof(row_ctx->$c)); + @else@ + /* or possibly 'netsnmp_check_vb_int_range' */ + rc = netsnmp_check_vb_int( var ); + @end@ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + rc = SNMP_ERR_GENERR; + snmp_log(LOG_ERR, "unknown column in " + "${i}_set_reserve1\n"); + } + + if (rc) + netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc ); + rg->status = SNMP_MAX( rg->status, current->ri->status ); + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ +} + +void ${i}_set_reserve2( netsnmp_request_group *rg ) +{ + ${i}_context *row_ctx = (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = (${i}_context *)rg->undo_info; + netsnmp_request_group_item *current; + netsnmp_variable_list *var; + int rc; + + rg->rg_void = rg->list->ri; + + /* + * TODO: loop through columns, check for valid + * values and any range constraints. + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + rc = SNMP_ERR_NOERROR; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + @eval $have_check = 0@ + @if "$c" eq "$st_name"@ + @eval $have_check = 1@ + rc = netsnmp_check_vb_storagetype(current->ri->requestvb, + undo_ctx ? + undo_ctx->$c:0); + @end@ + @if "$c" eq "$rs_name"@ + @eval $have_check = 1@ + rc = netsnmp_check_vb_rowstatus(current->ri->requestvb, + undo_ctx ? + undo_ctx->$c:0); + rg->rg_void = current->ri; + @end@ + @if "$c.syntax" eq "TruthValue"@ + @eval $have_check = 1@ + rc = netsnmp_check_vb_truthvalue(current->ri->requestvb); + @end@ + @if $have_check == 0@ + /* + * TODO: routine to check valid values + * + * EXAMPLE: + * + @if "$c.type" eq "ASN_IPADDRESS"@ + @eval $have_check = 1@ + * if ( XXX_check_ip( *var->val.integer ) ) { + @end@ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_check = 1@ + * if ( XXX_check_oid( var ) ) { + @end@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_check = 1@ + * if ( XXX_check_value( var->val.string, XXX ) ) { + @end@ + @if $have_check != 1@ + * if ( *var->val.integer != XXX ) { + @end@ + * rc = SNMP_ERR_INCONSISTENTVALUE; + * rc = SNMP_ERR_BADVALUE; + * } + */ + @end@ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + netsnmp_assert(0); /** why wasn't this caught in reserve1? */ + } + + if (rc) + netsnmp_set_mode_request_error(MODE_SET_BEGIN, current->ri, rc); + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ +} + +/************************************************************ + * Assuming that the RESERVE phases were successful, the next + * stage is indicated by the action value ACTION. This is used + * to actually implement the set operation. However, this must + * either be done into temporary (persistent) storage, or the + * previous value stored similarly, in case any of the subsequent + * ACTION calls fail. + * + * In your case, changes should be made to row_ctx. A copy of + * the original row is in undo_ctx. + */ +void ${i}_set_action( netsnmp_request_group *rg ) +{ + netsnmp_variable_list *var; + ${i}_context *row_ctx = (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = (${i}_context *)rg->undo_info; + netsnmp_request_group_item *current; + + @if "$rs_name" ne ""@ + int row_err = 0; + @end@ + + /* + * TODO: loop through columns, copy varbind values + * to context structure for the row. + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + @eval $have_type = 0@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_type = 1@ + memcpy(row_ctx->$c,var->val.string,var->val_len); + row_ctx->${c}_len = var->val_len; + @end@ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_type = 1@ + memcpy(row_ctx->$c,var->val.objid,var->val_len); + row_ctx->${c}_len = var->val_len; + @end@ + @if $have_type == 0@ + row_ctx->$c = *var->val.integer; + @end@ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + netsnmp_assert(0); /** why wasn't this caught in reserve1? */ + } + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ + @if "$rs_name" ne ""@ +#ifndef ${i}_CAN_MODIFY_ACTIVE_ROW + if( undo_ctx && RS_IS_ACTIVE(undo_ctx->$rs_name) && + row_ctx && RS_IS_ACTIVE(row_ctx->$rs_name) ) { + row_err = 1; + } +#endif + + /* + * check activation/deactivation + */ + row_err = netsnmp_table_array_check_row_status(&cb, rg, + row_ctx ? &row_ctx->$rs_name : NULL, + undo_ctx ? &undo_ctx->$rs_name : NULL); + if(row_err) { + netsnmp_set_mode_request_error(MODE_SET_BEGIN, + (netsnmp_request_info*)rg->rg_void, + row_err); + return; + } + + @end@ + /* + * TODO: if you have dependencies on other tables, this would be + * a good place to check those, too. + */ +} + +/************************************************************ + * Only once the ACTION phase has completed successfully, can + * the final COMMIT phase be run. This is used to complete any + * writes that were done into temporary storage, and then release + * any allocated resources. Note that all the code in this phase + * should be "safe" code that cannot possibly fail (cue + * hysterical laughter). The whole intent of the ACTION/COMMIT + * division is that all of the fallible code should be done in + * the ACTION phase, so that it can be backed out if necessary. + * + * BEFORE calling this routine, the agent will update the + * container (inserting a row if row_created == 1, or removing + * the row if row_deleted == 1). + * + * AFTER calling this routine, the agent will delete the + * undo_info. + */ +void ${i}_set_commit( netsnmp_request_group *rg ) +{ + netsnmp_variable_list *var; + ${i}_context *row_ctx = (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = (${i}_context *)rg->undo_info; + netsnmp_request_group_item *current; + + /* + * loop through columns + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + netsnmp_assert(0); /** why wasn't this caught in reserve1? */ + } + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ +} + +/************************************************************ + * If either of the RESERVE calls fail, the write routines + * are called again with the FREE action, to release any resources + * that have been allocated. The agent will then return a failure + * response to the requesting application. + * + * AFTER calling this routine, the agent will delete undo_info. + */ +void ${i}_set_free( netsnmp_request_group *rg ) +{ + netsnmp_variable_list *var; + ${i}_context *row_ctx = (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = (${i}_context *)rg->undo_info; + netsnmp_request_group_item *current; + + /* + * loop through columns + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + /** should have been logged in reserve1 */ + } + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ +} + +/************************************************************ + * If the ACTION phase does fail (for example due to an apparently + * valid, but unacceptable value, or an unforeseen problem), then + * the list of write routines are called again, with the UNDO + * action. This requires the routine to reset the value that was + * changed to its previous value (assuming it was actually changed), + * and then to release any resources that had been allocated. As + * with the FREE phase, the agent will then return an indication + * of the error to the requesting application. + * + * BEFORE calling this routine, the agent will update the container + * (remove any newly inserted row, re-insert any removed row). + * + * AFTER calling this routing, the agent will call row_copy + * to restore the data in existing_row from the date in undo_info. + * Then undo_info will be deleted (or existing row, if row_created + * == 1). + */ +void ${i}_set_undo( netsnmp_request_group *rg ) +{ + netsnmp_variable_list *var; + ${i}_context *row_ctx = (${i}_context *)rg->existing_row; + ${i}_context *undo_ctx = (${i}_context *)rg->undo_info; + netsnmp_request_group_item *current; + + /* + * loop through columns + */ + for( current = rg->list; current; current = current->next ) { + + var = current->ri->requestvb; + + switch(current->tri->colnum) { + + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + netsnmp_assert(0); /** why wasn't this caught in reserve1? */ + } + } + + /* + * done with all the columns. Could check row related + * requirements here. + */ +} + +@end@ + + +/************************************************************ + * + * Initialize the $i table by defining its contents and how it's structured + */ +void +initialize_table_$i(void) +{ + netsnmp_table_registration_info *table_info; + + if(my_handler) { + snmp_log(LOG_ERR, "initialize_table_${i}_handler called again\n"); + return; + } + + memset(&cb, 0x00, sizeof(cb)); + + /** create the table structure itself */ + table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); + + my_handler = netsnmp_create_handler_registration("$i", + netsnmp_table_array_helper_handler, + ${i}_oid, + ${i}_oid_len, +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + if (!my_handler || !table_info) { + snmp_log(LOG_ERR, "malloc failed in " + "initialize_table_${i}_handler\n"); + return; /** mallocs failed */ + } + + /*************************************************** + * Setting up the table's definition + */ + /* + * TODO: add any external indexes here. + */ + @if $ext_index != 0@ + /** TODO: add code for external index(s)! */ + @end@ + + /* + * internal indexes + */ + @foreach $idx index@ + /** index: $idx */ + netsnmp_table_helper_add_index(table_info, $idx.type); + @end@ + + table_info->min_column = ${i}_COL_MIN; + table_info->max_column = ${i}_COL_MAX; + + /*************************************************** + * registering the table with the master agent + */ + cb.get_value = ${i}_get_value; + cb.container = netsnmp_container_find("${i}_primary:" + "${i}:" + "table_container"); +#ifdef ${i}_CUSTOM_SORT + netsnmp_container_add_index(cb.container, + netsnmp_container_find("${i}_custom:" + "${i}:" + "table_container")); + cb.container->next->compare = ${i}_cmp; +#endif +@if $i.settable@ + cb.can_set = 1; +@if $i.creatable@ + cb.create_row = (UserRowMethod*)${i}_create_row; +@end@ + cb.duplicate_row = (UserRowMethod*)${i}_duplicate_row; + cb.delete_row = (UserRowMethod*)${i}_delete_row; + cb.row_copy = (Netsnmp_User_Row_Operation *)${i}_row_copy; + +@if "$rs_name" ne ""@ + cb.can_activate = (Netsnmp_User_Row_Action *)${i}_can_activate; + cb.can_deactivate = (Netsnmp_User_Row_Action *)${i}_can_deactivate; +@end@ + cb.can_delete = (Netsnmp_User_Row_Action *)${i}_can_delete; + + cb.set_reserve1 = ${i}_set_reserve1; + cb.set_reserve2 = ${i}_set_reserve2; + cb.set_action = ${i}_set_action; + cb.set_commit = ${i}_set_commit; + cb.set_free = ${i}_set_free; + cb.set_undo = ${i}_set_undo; +@end@ + DEBUGMSGTL(("initialize_table_$i", + "Registering table $i " + "as a table array\n")); + netsnmp_table_container_register(my_handler, table_info, &cb, + cb.container, 1); +} + +/************************************************************ + * ${i}_get_value + * + * This routine is called for get requests to copy the data + * from the context to the varbind for the request. If the + * context has been properly maintained, you don't need to + * change in code in this fuction. + */ +int ${i}_get_value( + netsnmp_request_info *request, + netsnmp_index *item, + netsnmp_table_request_info *table_info ) +{ + netsnmp_variable_list *var = request->requestvb; + ${i}_context *context = (${i}_context *)item; + + switch(table_info->colnum) { + + @foreach $c column@ + @if $c.readable@ + @eval $have_type = 0@ + case COLUMN_$c.uc: + /** $c.syntax = $c.type */ + @if "$c.type" eq "ASN_OBJECT_ID"@ + @eval $have_type = 1@ + snmp_set_var_typed_value(var, $c.type, + (char*)&context->$c, + context->${c}_len ); + @end@ + @if "$c.type" eq "ASN_OCTET_STR"@ + @eval $have_type = 1@ + snmp_set_var_typed_value(var, $c.type, + (char*)&context->$c, + context->${c}_len ); + @end@ + @if $have_type == 0@ + snmp_set_var_typed_value(var, $c.type, + (char*)&context->$c, + sizeof(context->$c) ); + @end@ + break; + + @end@ + @end@ + default: /** We shouldn't get here */ + snmp_log(LOG_ERR, "unknown column in " + "${i}_get_value\n"); + return SNMP_ERR_GENERR; + } + return SNMP_ERR_NOERROR; +} + +/************************************************************ + * ${i}_get_by_idx + */ +const ${i}_context * +${i}_get_by_idx(netsnmp_index * hdr) +{ + return (const ${i}_context *) + CONTAINER_FIND(cb.container, hdr ); +} + + +@end@ diff --git a/local/mib2c.check_values.conf b/local/mib2c.check_values.conf new file mode 100644 index 0000000..f9d8851 --- /dev/null +++ b/local/mib2c.check_values.conf @@ -0,0 +1,154 @@ +@run mib2c.check_values_local.conf@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}_checkfns.h@ +/* + * Note: this file originally auto-generated by mib2c using + * : mib2c.iterate.conf,v 5.6 2003/02/20 00:52:07 hardaker Exp $ + */ + +/*********************************************************************** + * This file is auto-generated and SHOULD NOT BE EDITED by hand. + * Modify the ${name}_checkfns_local.[ch] files insead. + * (so that you can regenerate this one as mib2c improvements are made) + ***********************************************************************/ +#ifndef $name.uc_CHECKFNS_H +#define $name.uc_CHECKFNS_H + +/** make sure we load the functions that you can modify */ +config_require(${name}_checkfns_local) + +@foreach $t table@ +/* these functions are designed to check incoming values for +columns in the $t table for legality with respect to +datatype and value. + */ + + @foreach $i column@ + @if $i.access =~ /(Write|Create)/@ + int check_${i}(int type, $i.decl *val, size_t val_len, $i.decl *old_val, size_t old_val_len); + @end@ + @end@ +@end@ + +#endif /* $name.uc_CHECKFNS_H */ + +###################################################################### +## Do the .c file +###################################################################### +@open ${name}_checkfns.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.check_values.conf 9254 2004-01-12 00:43:46Z rstory $ + */ + +/******************************************************************** + * NOTE NOTE NOTE + * This file is auto-generated and SHOULD NOT BE EDITED by hand. + * Modify the ${name}_checkfns_local.[ch] files insead so that you + * can regenerate this one as mib2c improvements are made. + ********************************************************************/ + +/* standard headers */ +#include +#include +#include "${name}_checkfns.h" +#include "${name}_checkfns_local.h" +#include "${name}_enums.h" +@run mib2c.column_enums.conf@ + +@foreach $t table@ + @foreach $i column@ + @if $i.access =~ /(Write|Create)/@ +/** Decides if an incoming value for the $i mib node is legal. + * @param type The incoming data type. + * @param val The value to be checked. + * @param val_len The length of data stored in val (in bytes). + * @return 0 if the incoming value is legal, an SNMP error code otherwise. + */ + int + check_${i}(int type, $i.decl *val, size_t val_len, + $i.decl *old_val, size_t old_val_len) { + + int ret; + + /** Check to see that we were called legally */ + if (!val) + return SNMP_ERR_GENERR; + + /** Check the incoming type for correctness */ + if (type != $i.type) + return SNMP_ERR_WRONGTYPE; + + @if $i.type =~ /int/i@ + @eval $x = 0@ + @foreach $l, $v enum@ + @if $x == 0@ + /** Check the enums. Legal values will continue, others return error. */ + switch (*val) { + @eval $x = 1@ + @end@ + case $i.uc_$l.uc: + @end@ + @if $x == 1@ + break; + + /** not a legal enum value. return an error */ + default: + return SNMP_ERR_INCONSISTENTVALUE; + } + @end@ + ret = SNMP_ERR_NOERROR; + @eval $x = 0@ + @foreach $min $max range $i@ + @if $x == 0@ + /** Check the ranges of the passed value for legality */ + @eval $x = 1@ + if ( + @else@ + || + @end@ + !(*val >= $min && *val <= $max) + @end@ + @if $x != 0@ + ) { + return SNMP_ERR_WRONGVALUE; + } + @end@ + @end@ + @if $i.type =~ /str/i@ + @eval $x = 0@ + @foreach $min $max range $i@ + @if $x == 0@ + /** Check the ranges of the passed value for legality */ + @eval $x = 1@ + if ( + @else@ + && + @end@ + !(val_len >= $min && val_len <= $max) + @end@ + @if $x == 1@ + ) { + return SNMP_ERR_WRONGVALUE; + } + @end@ + @end@ + + @if "$i.syntax" eq "RowStatus"@ + if (ret = check_rowstatus_transition((old_val) ? *old_val : RS_NONEXISTENT, *val)) + return ret; + @end@ + @if "$i.syntax" eq "StorageType"@ + if (ret = check_storage_transition((old_val) ? *old_val : SNMP_STORAGE_NONE, *val)) + return ret; + @end@ + + /** looks ok, call the local version of the same function. */ + return check_${i}_local(type, val, val_len, old_val, old_val_len); + } + @end@ + @end@ +@end@ diff --git a/local/mib2c.check_values_local.conf b/local/mib2c.check_values_local.conf new file mode 100644 index 0000000..25e00c9 --- /dev/null +++ b/local/mib2c.check_values_local.conf @@ -0,0 +1,72 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}_checkfns_local.h@ +/* + * Note: this file originally auto-generated by mib2c using + * : $Id: mib2c.check_values_local.conf 10232 2004-05-04 23:35:32Z hardaker $ + * + */ +#ifndef $name.uc_CHECKFNS_H +#define $name.uc_CHECKFNS_H + +@foreach $t table@ +/* these functions are designed to check incoming values for +columns in the $t table for legality with respect to +datatype and value according to local conventions. You should modify +them as appropriate. They will be called from parent check_value +functions that are auto-generated using mib2c and the parent functions +should NOT be modified. + */ + + @foreach $i column@ + @if $i.access =~ /(Write|Create)/@ + int check_${i}_local(int type, $i.decl *val, size_t val_len, $i.decl *old_val, size_t old_val_len); + @end@ + @end@ +@end@ + +#endif /* $name.uc_CHECKFNS_H */ + +###################################################################### +## Do the .c file +###################################################################### +@open ${name}_checkfns_local.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.check_values_local.conf 10232 2004-05-04 23:35:32Z hardaker $ + */ + +/* standard headers */ +#include +#include +#include "${name}_checkfns.h" +#include "${name}_enums.h" +@run mib2c.column_enums.conf@ + +@foreach $t table@ + @foreach $i column@ + @if $i.access =~ /(Write|Create)/@ +/** Decides if an incoming value for the $i mib node is legal, from a local implementation specific viewpoint. + * @param type The incoming data type. + * @param val The value to be checked. + * @param val_len The length of data stored in val (in bytes). + * @return 0 if the incoming value is legal, an SNMP error code otherwise. + */ + int + check_${i}_local(int type, $i.decl *val, size_t val_len, $i.decl *old_val, size_t old_val_len) { + + /** XXX: you may want to check aspects of the new value that + were not covered by the automatic checks by the parent function. */ + + /** XXX: you make want to check that the requested change from + the old value to the new value is legal (ie, the transistion + from one value to another is legal */ + + /** if everything looks ok, return SNMP_ERR_NOERROR */ + return SNMP_ERR_NOERROR; + } + @end@ + @end@ +@end@ diff --git a/local/mib2c.column_defines.conf b/local/mib2c.column_defines.conf new file mode 100644 index 0000000..a4d2e6d --- /dev/null +++ b/local/mib2c.column_defines.conf @@ -0,0 +1,15 @@ +@open ${name}_columns.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.column_defines.conf 7011 2002-05-08 05:42:47Z hardaker $ + */ +#ifndef $name.uc_COLUMNS_H +#define $name.uc_COLUMNS_H +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ +@end@ +#endif /* $name.uc_COLUMNS_H */ diff --git a/local/mib2c.column_enums.conf b/local/mib2c.column_enums.conf new file mode 100644 index 0000000..f18230d --- /dev/null +++ b/local/mib2c.column_enums.conf @@ -0,0 +1,34 @@ +@open ${name}_enums.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.column_enums.conf 12909 2005-09-29 22:16:22Z hardaker $ + */ +#ifndef $name.uc_ENUMS_H +#define $name.uc_ENUMS_H +@foreach $i table@ + @foreach $c column@ + @eval $x = 0@ + @foreach $e $v enum@ + @if $x == 0@ + +/* enums for column $c */ + @eval $x = 1@ + @end@ + #define $c.uc_$e.uc $v + @end@ + @end@ +@end@ + +@foreach $s scalar@ + @eval $x = 0@ + @foreach $e $v enum@ + @if $x == 0@ + +/* enums for scalar $s */ + @eval $x = 1@ + @end@ +#define $s.uc_$e.uc $v + @end@ +@end@ + +#endif /* $name.uc_ENUMS_H */ diff --git a/local/mib2c.column_storage.conf b/local/mib2c.column_storage.conf new file mode 100644 index 0000000..de4249f --- /dev/null +++ b/local/mib2c.column_storage.conf @@ -0,0 +1,23 @@ +############################################################# -*- c -*- +## top level mfd conf file +## $Id: mib2c.column_storage.conf 11111 2004-09-21 23:48:45Z rstory $ +######################################################################## +@ open ${name}_storage.h@ +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 11111 $ */ +@end@ +######################################################################## +## +## +## +@foreach $table table@ +@ include m2c_setup_table.m2i@ +@ eval $m2c_data_context = "generated"@ +@ include generic-table-indexes.m2i@ +@ include generic-data-context.m2i@ +@end@ # table +## +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 11111 $ */ +@end@ diff --git a/local/mib2c.conf b/local/mib2c.conf new file mode 100644 index 0000000..329e71e --- /dev/null +++ b/local/mib2c.conf @@ -0,0 +1,284 @@ +@open -@ +mib2c has multiple configuration files depending on the type of +code you need to write. You must pick one depending on your need. + +You requested mib2c to be run on the following part of the MIB tree: + OID: $name + numeric translation: $name.objectID +@eval $num = count_scalars@ + number of scalars within: $num +@eval $num = count_tables@ + number of tables within: $num +@eval $num = count_notifications@ + number of notifications within: $num + +First, do you want to generate code that is compatible with the +ucd-snmp 4.X line of code, or code for the newer Net-SNMP 5.X code +base (which provides a much greater choice of APIs to pick from): + + 1) ucd-snmp style code + 2) Net-SNMP style code + +@prompt $ans Select your choice : @ +@if $ans == 1@ +********************************************************************** + GENERATING CODE FOR THE 4.X LINE OF CODE (THE OLDER API) +********************************************************************** + + using the mib2c.old-api.conf configuration file to generate your code. + @run mib2c.old-api.conf@ + +@elsif $ans != 2@ +Invalid answer. +@else@ +@if count_scalars() > 0@ + +********************************************************************** + GENERATING CODE FOR SCALAR OBJECTS: +********************************************************************** + + It looks like you have some scalars in the mib you requested, so I + will now generate code for them if you wish. You have two choices + for scalar API styles currently. Pick between them, or choose not + to generate any code for the scalars: + + 1) If you're writing code for some generic scalars + (by hand use: "mib2c -c mib2c.scalar.conf $name") + + 2) If you want to magically "tie" integer variables to integer + scalars + (by hand use: "mib2c -c mib2c.int_watch.conf $name") + + 3) Don't generate any code for the scalars + + @prompt $ans Select your choice: @ + @if $ans == 1@ + using the mib2c.scalar.conf configuration file to generate your code. + @run mib2c.scalar.conf@ + @elsif $ans == 2@ + using the mib2c.int_watch.conf configuration file to generate your code. + @run mib2c.int_watch.conf@ + @elsif $ans != 3@ + WARNING: Unknown response. Skipping code generation for scalars. + @end@ +@end@ # scalars + +@if count_tables() > 0@ +********************************************************************** + GENERATING CODE FOR TABLES: +********************************************************************** + + Your tables will likely either fall into one of two categories: + + 1) tables where the list of rows is external to the agent. + This is suited to MIBs which monitor or manipulate external + data (perhaps extracted from the operating system kernel + or other system interfaces), and where rows are typically + created or destroyed independently of the SNMP agent. + + 2) tables where the list of rows is held by the agent itself. + This is particularly suited to tables that are primarily + manipulated via SNMP, or where the rows of the table are + relatively static. + + 3) Do not generate code for the tables. + + @prompt $ans Select the option that best fits you: @ + @if $ans != 3@ + @if $ans == 1@ + + This style of table tends to use the iterator helper to instrument + the external data, so it can be represented by an SNMP table. + The main characteristic of this helper is the use of a pair + of "iteration hook" routines to loop through the rows in turn + (in the most natural order for the underlying data). + There are a couple of different template configurations that + can be used as a framework for this: + + 1) One based around a single handler, that includes code to handle + both GET and SET requests, as well as row creation and deletion. + This template defines a suitable data structure, and implements + the table as an internally-held linked list, but both of these + are mainly for illustration, and could reasonably be replaced by + code more appropriate for the table being implemented. + The same template can be generated using + mib2c -c mib2c.iterate.conf $name + + 2) An alternative framework, designed as an API wrapper on top of + the basic iterator helper, that seeks to separate the standard + processing of the syntax of a MIB table (which can be generated + automaticall), from the semantics of a given table (which cannot). + It generates a number of separate code files, but typically + only one or two of these will need to be edited. These contain + separate 'get_column()' and 'set_column()' functions for each + column in the table, plus some other routines for manipulating + rows (plus the standard iterator hook routines). + The same templates can be generated using + mib2c -c mib2c.iterate_access.conf $name + (See the agent/mibgroup/example/netSnmpHostsTable.c file for example) + + 3) An API layer (not based on the iterator helper) that attempts + to reduce the amount of SNMP specific knowledge required to + implement a module. It provides more APIs than 2, which are + (hopefully) smaller and more specific, with less SNMP terminology. + This API is also known as "MIBs for Dummies". Numerous tables + in the Net-SNMP agent have been re-written to use this API. + The same templates can be generated using + mib2c -c mib2c.mfd.conf $name + (See the agent/mibgroup/if-mib/ifTable/ifTable*.c files for examples) + + 4) Do not generate code for the tables. + + If you are unsure which option to pick, choices 2) or 3) are perhaps + more suited for those less familiar with the concepts behind the SNMP + protocol operations, while choice 1) gives more control over exactly + what is done. + + @prompt $ans Select the API style you wish to use: @ + @if $ans != 5@ + @if $ans == 1@ + using the mib2c.iterate.conf configuration file to generate your code. + @run mib2c.iterate.conf@ + @elsif $ans == 2@ + using the mib2c.iterate_access.conf configuration file to + generate your code. + @run mib2c.iterate_access.conf@ + @elsif $ans == 3@ + using the mib2c.mfd.conf configuration file to + generate your code. + @run mib2c.mfd.conf@ + @else@ + WARNING: Unknown response. Skipping code generation for tables. + @end@ + @end@ + @else@ + @if $ans == 2@ + This style of table holds a list of the table rows internally + within the agent itself. Typically this will tend to include + the column values for each particular row, and that is the + model used by the generated template code. But it should usually + be possible to read in some or all of the column values from an + external source, should this be necessary for a particular MIB table. + There are a number of different template configurations that + can be used as a framework for this: + + + 1) dataset storage: The data for the table is stored completely + within the agent, and the user-visible code does not need to + be concerned with the internal representation of an individual + row. This is most suited to MIB tables that are purely internal + to the agent, rather than modelling external data, or using + existing data structures. + The same template can be generated using + mib2c -c mib2c.create-dataset.conf $name + + 2) row-data storage: The data for the table is held by the agent, + but using an arbitrary (user-provided) data structure for the + representation of an individual row. This is suited for MIB + tables where there is a natural existing data structure, + or where the contents of the table may need to be interpreted + for some additional purpose, other than simply implementing + the table for SNMP requests. + The same template can be generated using + mib2c -c mib2c.table_data.conf $name + + 3) container storage: This is very similar to the previous row-data + mechanism, but uses a different (and slightly more efficient) + internal representation. The main practical effect is to + introduce a slight constraint on the form of the per-row data + structure. + The same template can be generated using + mib2c -c mib2c.container.conf $name + + All three of these templates generate a single code file, and + use a "single handler" format for the driving code. + + 4) sorted array: The data for the table is stored in a sorted + array. + (manually mib2c -c mib2c.array-user.conf ${name}) + + 5) Net-SNMP container: (Also known as "MIBs for Dummies", or MFD.) + The data for the table is stored via a + generic interface. Various types of containers may be + selected, including linked lists or binary arrays. + (manually mib2c -c mib2c.mfd.conf ${name}) + + 6) Do not generate code for the tables. + + All APIs are fully functional with little-to-no required code + to make the table operational on your end once the template + code is produced. The MFD and dataset APIs are a bit better + documented, but the sorted array is probably better tested + as it was used heavily in the net-policy sourceforge project. + The MFD API is the successor to the array-user API, and several + tables in the Net-SNMP agent have been re-written to use it. + The dataset API is used inside the snmptrapd application for + logging incoming traps. + + @prompt $ans Select the API style you wish to use: @ + @if $ans != 6@ + @if $ans == 1@ + using the mib2c.create-dataset.conf configuration file + to generate your code. + @run mib2c.create-dataset.conf@ + @elsif $ans == 2@ + using the mib2c.table_data.conf configuration file to + generate your code. + @run mib2c.table_data.conf@ + @elsif $ans == 3@ + using the mib2c.container.conf configuration file to + generate your code. + @run mib2c.container.conf@ + @elsif $ans == 4@ + using the mib2c.array-user.conf configuration file to + generate your code. + @run mib2c.array-user.conf@ + @elsif $ans == 5@ + using the mib2c.mfd.conf configuration file to generate your code. + @run mib2c.mfd.conf@ + @else@ + WARNING: Unknown response. Skipping code generation for tables. + @end@ + @else@ + WARNING: Unknown response. Skipping code generation for tables. + @end@ + @end@ + @end@ + @end@ # != 3 +@end@ # tables + +@if count_notifications() > 0@ +********************************************************************** + GENERATING CODE FOR NOTIFICATIONS: +********************************************************************** + +Would you like to generate code for sending notifications from within +the agent? + + @prompt $ans "y" or "n": @ + @if ("$ans" eq "y") or ("$ans" eq "yes")@ + using mib2c.notify.conf to generate code for sending notifications + @run mib2c.notify.conf@ + @end@ + +# GENERATING HEADER FILE DEFINITIONS +# +# To generate just a header with a define for each column number in +# your table: +# +# mib2c -c mib2c.column_defines.conf ${name} +# +# To generate just a header with a define for each enum for any +# column containing enums: +# +# mib2c -c mib2c.column_enums.conf ${name} + +@end@ # notifications +@end@ # new style code + +********************************************************************** +* NOTE WELL: The code generated by mib2c is only a template. *YOU* * +* must fill in the code before it'll work most of the time. In many * +* cases, spots that MUST be edited within the files are marked with * +* /* XXX */ or /* TODO */ comments. * +********************************************************************** diff --git a/local/mib2c.container.conf b/local/mib2c.container.conf new file mode 100644 index 0000000..eb4e4bc --- /dev/null +++ b/local/mib2c.container.conf @@ -0,0 +1,569 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.container.conf 15999 2007-03-25 22:32:02Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ +@end@ +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.container.conf 15999 2007-03-25 22:32:02Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/** Initializes the $name module */ +void +init_$name(void) +{ + /* here we initialize all the tables we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} + +@foreach $i table@ + # Determine the first/last column names + @eval $first_column = "-"@ + @eval $last_column = "-"@ + @foreach $c column@ + @if $c.readable@ + @if "$first_column" eq "-"@ + @eval $first_column = $c@ + @end@ + @eval $last_column = $c@ + @end@ + @end@ + +/** Initialize the $i table by defining its contents and how it's structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + netsnmp_handler_registration *reg; + netsnmp_container *container; + netsnmp_table_registration_info *table_info; + + reg = netsnmp_create_handler_registration( + "$i", ${i}_handler, + ${i}_oid, ${i}_oid_len, +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + container = netsnmp_container_find( "table_container" ); + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + netsnmp_table_helper_add_indexes(table_info, + @foreach $idx index@ + $idx.type, /* index: $idx */ + @end@ + 0); + table_info->min_column = COLUMN_$first_column.uc; + table_info->max_column = COLUMN_$last_column.uc; + + netsnmp_container_table_register( reg, table_info, container, 0 ); + + /* Initialise the contents of the table here */ +} + + /* Typical data structure for a row entry */ +struct ${i}_entry { + netsnmp_index oid_index; + + /* Index values */ + @foreach $idx index@ + @if $idx.needlength@ + $idx.decl $idx[NNN]; + size_t ${idx}_len; + @else@ + $idx.decl $idx; + @end@ + @end@ + + /* Column values */ + @foreach $c column@ + @if $c.readable@ + @if $c.needlength@ + $c.decl $c[NNN]; + size_t ${c}_len; + @else@ + $c.decl $c; + @end@ + @if $c.settable@ + @if !$c.rowstatus@ + @if $c.needlength@ + $c.decl old_$c[NNN]; + size_t old_${c}_len; + @else@ + $c.decl old_$c; + @end@ + @end@ + @end@ + @end@ + @end@ + + int valid; +}; + +/* create a new row in the table */ +struct ${i}_entry * +${i}_createEntry(netsnmp_container *container, + @foreach $idx index@ + @if $idx.needlength@ + , $idx.decl* $idx + , size_t ${idx}_len + @else@ + , $idx.decl $idx + @end@ + @end@ + ) { + struct ${i}_entry *entry; + + entry = SNMP_MALLOC_TYPEDEF(struct ${i}_entry); + if (!entry) + return NULL; + + @foreach $idx index@ + @if $idx.needlength@ + memcpy(entry->$idx, $idx, ${idx}_len); + entry->${idx}_len = ${idx}_len; + @else@ + entry->$idx = $idx; + @end@ + @end@ + entry->oid_index.len = XXX; + entry->oid_index.oids = YYY; + CONTAINER_INSERT( container, entry ); + return entry; +} + +/* remove a row from the table */ +void +${i}_removeEntry(netsnmp_container *container, + struct ${i}_entry *entry) { + + if (!entry) + return; /* Nothing to remove */ + CONTAINER_REMOVE( container, entry ); + if (entry) + SNMP_FREE( entry ); /* XXX - release any other internal resources */ +} + +/** handles requests for the $i table */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + + netsnmp_request_info *request; + netsnmp_table_request_info *table_info; + netsnmp_table_data *table_data; + netsnmp_container *container; + struct ${i}_entry *table_entry; + int ret; + + switch (reqinfo->mode) { + /* + * Read-support (also covers GetNext requests) + */ + case MODE_GET: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.readable@ + case COLUMN_$c.uc: + if ( !table_entry ) { + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHINSTANCE); + continue; + } + @if $c.needlength@ + snmp_set_var_typed_value( request->requestvb, $c.type, + (u_char*)table_entry->$c, + table_entry->${c}_len); + @else@ + snmp_set_var_typed_integer( request->requestvb, $c.type, + table_entry->$c); + @end@ + break; + @end@ + @end@ + default: + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHOBJECT); + break; + } + } + break; + +@if $i.settable@ + /* + * Write-support + */ + case MODE_SET_RESERVE1: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + @if $c.rowstatus@ + ret = netsnmp_check_vb_rowstatus(request->requestvb, + (table_entry ? RS_ACTIVE : RS_NONEXISTENT )); + @else@ + @if $c.needlength@ + /* or possiblc 'netsnmp_check_vb_type_and_size' */ + ret = netsnmp_check_vb_type_and_max_size( + request->requestvb, $c.type, sizeof(table_entry->$c)); + @else@ + /* or possibly 'netsnmp_check_vb_int_range' */ + ret = netsnmp_check_vb_int( request->requestvb ); + @end@ + @end@ + if ( ret != SNMP_ERR_NOERROR ) { + netsnmp_set_request_error( reqinfo, request, ret ); + return SNMP_ERR_NOERROR; + } + break; + @end@ + @end@ + default: + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_NOTWRITABLE ); + return SNMP_ERR_NOERROR; + } + } + break; + + case MODE_SET_RESERVE2: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + container = netsnmp_container_table_extract(request); + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + table_entry = ${i}_createEntry(container + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_entry) { + netsnmp_container_table_insert_row( request, table_entry ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( !table_entry ) { + table_entry = ${i}_createEntry(container + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_entry) { + netsnmp_container_table_insert_row( request, table_entry ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_FREE: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + container = netsnmp_container_table_extract(request); + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(container, table_entry ); + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(container, table_entry ); + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_ACTION: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + @if !$c.rowstatus@ + case COLUMN_$c.uc: + @if $c.needlength@ + memcpy( table_entry->old_$c, + table_entry->$c, + sizeof(table_entry->$c)); + table_entry->old_${c}_len = + table_entry->${c}_len; + memset( table_entry->$c, 0, + sizeof(table_entry->$c)); + memcpy( table_entry->$c, + request->requestvb->val.string, + request->requestvb->val_len); + table_entry->${c}_len = + request->requestvb->val_len; + @else@ + table_entry->old_$c = table_entry->$c; + table_entry->$c = *request->requestvb->val.integer; + @end@ + break; + @end@ + @end@ + @end@ + } + } +@if $i.rowstatus@ + /* Check the internal consistency of an active row */ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_ACTIVE: + case RS_CREATEANDGO: + if (/* XXX */) { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_INCONSISTENTVALUE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ + } + } +@end@ + break; + + case MODE_SET_UNDO: + for (request=requests; request; request=request->next) { + container = netsnmp_container_table_extract(request); + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: +@if $i.rowstatus@ + @if $c.rowstatus@ + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(container, table_entry ); + } + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@else@ + @if $c.creatable@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(container, table_row ); + } else { + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@end@ + break; + @end@ + @end@ + } + } + break; + + case MODE_SET_COMMIT: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + container = netsnmp_container_table_extract(request); + table_entry = (struct ${i}_entry *) + netsnmp_container_table_extract_context(request); + table_info = netsnmp_extract_table_info(request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + table_entry->valid = 1; + /* Fall-through */ + case RS_ACTIVE: + table_entry->$c = RS_ACTIVE; + break; + + case RS_CREATEANDWAIT: + table_entry->valid = 1; + /* Fall-through */ + case RS_NOTINSERVICE: + table_entry->$c = RS_NOTINSERVICE; + break; + + case RS_DESTROY: + ${i}_removeEntry(container, table_entry ); + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + table_entry->valid = 1; + } +@end@ + } + } +@end@ + break; +@end@ + } + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.create-dataset.conf b/local/mib2c.create-dataset.conf new file mode 100644 index 0000000..f47b9f0 --- /dev/null +++ b/local/mib2c.create-dataset.conf @@ -0,0 +1,112 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.create-dataset.conf 9375 2004-02-02 19:06:54Z rstory $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ +@end@ +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.create-dataset.conf 9375 2004-02-02 19:06:54Z rstory $ + */ + +#include +#include +#include +#include "${name}.h" + +@foreach $i table@ +/** Initialize the $i table by defining its contents and how it's structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + netsnmp_table_data_set *table_set; + + /* create the table structure itself */ + table_set = netsnmp_create_table_data_set("$i"); + + /* comment this out or delete if you don't support creation of new rows */ + table_set->allow_creation = 1; + + /*************************************************** + * Adding indexes + */ + DEBUGMSGTL(("initialize_table_$i", + "adding indexes to table $i\n")); + netsnmp_table_set_add_indexes(table_set, + @foreach $idx index@ + $idx.type, /* index: $idx */ + @end@ + 0); + + DEBUGMSGTL(("initialize_table_$i", + "adding column types to table $i\n")); + netsnmp_table_set_multi_add_default_row(table_set, + @foreach $c column@ + COLUMN_$c.uc, $c.type, $c.settable, + NULL, 0, + @end@ + 0); + + /* registering the table with the master agent */ + /* note: if you don't need a subhandler to deal with any aspects + of the request, change ${i}_handler to "NULL" */ + netsnmp_register_table_data_set(netsnmp_create_handler_registration("$i", ${i}_handler, + ${i}_oid, + ${i}_oid_len, + HANDLER_CAN_RWRITE), + table_set, NULL); +} +@end@ + +/** Initializes the $name module */ +void +init_$name(void) +{ + + /* here we initialize all the tables we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} +@foreach $i table@ + +/** handles requests for the $i table, if anything else needs to be done */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + /* perform anything here that you need to do. The requests have + already been processed by the master table_dataset handler, but + this gives you chance to act on the request in some other way + if need be. */ + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.emulation.conf b/local/mib2c.emulation.conf new file mode 100644 index 0000000..c879d0d --- /dev/null +++ b/local/mib2c.emulation.conf @@ -0,0 +1,246 @@ +############################################## -*- Mib2c -*- +## +## File : mib2c.emulation.conf +## Author : Robert Story +## Purpose: A mib2c conf file to generate snmpd.conf configuration to +## provide basic/simplistic emulation for a particular MIB. +## +## +## $Id: mib2c.emulation.conf 14860 2006-07-05 22:44:06Z rstory $ +###################################################################### +@open ${name}-emulation.conf@ +# +# $name.module MIB emulation +# Base OID: $name.objectID +# +# Requirements: Net-SNMP 5.2 or greater +# +# This file can be used as (part of) a Net-SNMP snmpd.conf +# configuration file to emulate (in a minimal fashion) the objects defined +# in the $name MIB. +# +# It is important to note that this file merely creates dummy values +# and variables and does not implement any of the functionality which +# the mib objects are actually supposed to implement! +# +# Also, it just defaults to 0, '' or 0.0 for initial values, so you'll need +# to tweak all the vaules. For any tables, you'll have set any indexes. +# +# The configuration tokens used in this file are documented in the +# snmpd.conf manual page, with the exception of the first line, which +# is documented in the snmp.conf and snmp_config manual pages. +# +# +# To use this file, you have several options: +# +# 1) add the contents to your existing snmpd.conf file +# 2) copy it to a new snmpd.conf, somewhere in SNMPCONFPATH +# 3) copy it to snmpd.conf.local, somewhere in SNMPCONFPATH +# +# The command 'net-snmp-config --snmpconfpath' will give your the +# SNMPCONFPATH (5.3.x and later). + + +# Here we tell the agent to load the MIB, so we can use names instead +# of OIDs. You may need to add other MIBs that this MIB depends on. +# Also, you might want to consider adding these to the global snmp.conf, +# so all users can reference them. +# +# See the Net-SNMP FAQ for more information on MIB loading. +# +[snmp] mibs +$name.module + +# +# $name Scalar variables +# + +@foreach $node scalar@ +@ print Scalar: $node@ +# $node.module::$node.parent.$node($node.subid) [$node.syntax = $node.type] +@ if "$node.status" eq "Deprecated"@ +# **** WARNING: deprecated object **** +@ end@ +@if $node.enums == 1@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $e $v enum@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ eval $m2c_evals = "$m2c_evals $e($v)"@ +@ if $node.hasdefval == 1@ +@ if (("$node.defval" eq "$e") || ("$node.defval" eq "$v"))@ +@ eval $m2c_evals = "${m2c_evals}*"@ +@ end@ +@ end@ +@ end@ +# Enum range: $node.enumrange. Values: $m2c_evals +@elsif $node.ranges == 1@ +@ eval $m2c_range_max = 0@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $a $b range $node@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ if $a == $b@ +@ eval $m2c_evals = "$m2c_evals $a"@ +@ else@ +@ eval $m2c_evals = "$m2c_evals $a - $b"@ +@ end@ +@ eval $m2c_range_max = max($m2c_range_max,$b)@ +@ end@ +# Ranges: $m2c_evals; +@end@ #ranges +@ if $node.hasdefval == 1@ +@ eval $m2c_emu_def = "$node.defval"@ +@ else@ +# (no default value) +@ if "$node.type" eq "ASN_OCTET_STR"@ +@ eval $m2c_emu_def = "''" @ +@ elsif "$node.type" eq "ASN_OBJECT_ID"@ +@ eval $m2c_emu_def = "0.0" @ +@ else@ +@ eval $m2c_emu_def = "0" @ +@ end@ +@ end@ +## uggh.. try to convert type into something 5.3.x override understands +@ eval $m2c_emu_type = lc($node.type)@ +@ perleval $vars{'m2c_emu_type'} =~ s/asn_//; 0;@ +@ if $node.settable@ +#override -rw ${node}.0 $m2c_emu_type $m2c_emu_def +@ else@ +#override ${node}.0 $m2c_emu_type $m2c_emu_def +@ end@ + +@end@ + + +##====================================================================== +# +# Note that in tables, all indices are shown first, then each +# readable column. This results in indices being given twice. +# +@foreach $node table@ +@ print Table: $node@ +# $node.module::$node.parent.$node($node.subid) +table $node +##============================================================ +@ eval $m2c_idx_def = ""@ +@ eval $m2c_add_def = ""@ +@ foreach $col index@ +# [$col] ($node.accessible) $col.syntax / $col.type / $m2c_decl ($col.decl) +@ if $col.enums == 1@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $e $v enum@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ eval $m2c_evals = "$m2c_evals $e($v)"@ +@ if $col.hasdefval == 1@ +@ if (("$col.defval" eq "$e") || ("$col.defval" eq "$v"))@ +@ eval $m2c_evals = "${m2c_evals}*"@ +@ end@ +@ end@ +@ end@ +# enum range: $col.enumrange. Values: $m2c_evals +@ elsif $col.ranges == 1@ +@ eval $m2c_range_max = 0@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $a $b range $col@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ if $a == $b@ +@ eval $m2c_evals = "$m2c_evals $a"@ +@ else@ +@ eval $m2c_evals = "$m2c_evals $a - $b"@ +@ end@ +@ eval $m2c_range_max = max($m2c_range_max,$b)@ +@ end@ +# ranges: $m2c_evals; +@ end@ #ranges +@ if $col.hasdefval == 1@ +@ eval $m2c_col_def = '$col.defval'@ +@ else@ +@ if "$col.type" eq "ASN_OCTET_STR"@ +@ eval $m2c_col_def = "''" @ +@ elsif "$col.type" eq "ASN_OBJECT_ID"@ +@ eval $m2c_col_def = "0.0" @ +@ else@ +@ eval $m2c_col_def = "0" @ +@ end@ +@ end@ +@ eval $m2c_add_def = "$m2c_add_def $m2c_col_def"@ +##@ if $node.accessible == 1@ +@ eval $m2c_idx_def = "$m2c_idx_def $m2c_col_def"@ +##@ end@ +@ end@ ## col +##=================================================== +@ foreach $col nonindex@ +# $col [$col.syntax = $col.type] +@ if "$col.status" eq "Deprecated"@ +# **** WARNING: deprecated object **** +@ end@ +@ if $col.enums == 1@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $e $v enum@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ eval $m2c_evals = "$m2c_evals $e($v)"@ +@ if $col.hasdefval == 1@ +@ if (("$col.defval" eq "$e") || ("$col.defval" eq "$v"))@ +@ eval $m2c_evals = "${m2c_evals}*"@ +@ end@ +@ end@ +@ end@ +# enum range: $col.enumrange. Values: $m2c_evals +@ elsif $col.ranges == 1@ +@ eval $m2c_range_max = 0@ +@ eval $m2c_evals = ""@ +@ eval $m2c_first = 1@ +@ foreach $a $b range $col@ +@ if $m2c_first == 1@ +@ eval $m2c_first = 0@ +@ else@ +@ eval $m2c_evals = "$m2c_evals,"@ +@ end@ +@ if $a == $b@ +@ eval $m2c_evals = "$m2c_evals $a"@ +@ else@ +@ eval $m2c_evals = "$m2c_evals $a - $b"@ +@ end@ +@ eval $m2c_range_max = max($m2c_range_max,$b)@ +@ end@ +# ranges: $m2c_evals; +@ end@ #ranges +@ if $col.hasdefval == 1@ +@ eval $m2c_col_def = '$col.defval'@ +@ else@ +@ if "$col.type" eq "ASN_OCTET_STR"@ +@ eval $m2c_col_def = "''" @ +@ elsif "$col.type" eq "ASN_OBJECT_ID"@ +@ eval $m2c_col_def = "0.0" @ +@ else@ +@ eval $m2c_col_def = "0" @ +@ end@ +@ end@ +@ eval $m2c_add_def = "$m2c_add_def $m2c_col_def"@ +@ end@ ## col +#add_row $node $m2c_idx_def $m2c_add_def + +@end@ ## table diff --git a/local/mib2c.genhtml.conf b/local/mib2c.genhtml.conf new file mode 100644 index 0000000..b0f6284 --- /dev/null +++ b/local/mib2c.genhtml.conf @@ -0,0 +1,370 @@ +## +## USAGE: +## mib2c -c mib2c.genhtml.conf STARTINGNODE +## +## Optional extra arguments: +## +## -S cssfile=file.css (specifies an alternate CSS style +## file to include in the output) +## +## +## try to strip leading white space from text +## +@define DO_FORMATED_TEXT@ +@startperl@ + my ($s) = ($vars{'x'} =~ /\n(\s+)/); + $vars{'x'} =~ s/^$s//gm; + 0; +@endperl@ +
+$x
+
+@enddefine@ +## +## print a description clause (include TC info and references +## +@define DO_DESCR@ + +@if "$i.perltype" ne "$i.syntax"@ +

+@eval $tmpsyn = "$i.syntax"@ +@perleval if (!defined($TCS{$vars{'tmpsyn'}})) { $TCS{$vars{'tmpsyn'}} = $vars{'i'}; }; 0;@ +Note: this object is based on the $i.syntax TEXTUAL-CONVENTION. +

+@end@ +@eval $x = "$i.description"@ +@calldefine DO_FORMATED_TEXT@ +##@startperl@ +## my ($s) = ($vars{'x'} =~ /\n(\s+)/); +## $vars{'x'} =~ s/^$s//gm; +## 0; +##@endperl@ +##
+##$x
+##
+@if "$i.reference" ne ""@ +@eval $x = "$i.reference"@ +

Also see Reference: +@calldefine DO_FORMATED_TEXT@ +

+@end@ + +@enddefine@ +## +## print information (a row) about a given node +## +@define NODE_INFO@ +@if ("$i.status" eq "Current")@ + +@else@ + +@end@ + +@eval $tmpi = "$i.parent"@ +@if "$doindexstuff" ne "" && "$tmpi.parent" ne "$t"@ +(external from $tmpi.parent) +@else@ +$i.subid +@end@ +
$i + + +## +## print the data type +## +@if ("$i.status" ne "Current")@ +DEPRECATED
+@end@ + $i.perltype +## +## print range information +## + @if "$i.ranges"@ + @if "$i.perltype" eq 'OCTETSTR' || "$i.perltype" eq 'OBJECTID'@ +
Legal Lengths: + @else@ +
Legal values: + @end@ + @eval $tmpdidit = 0@ + @foreach $st $end range $i@ + @if "$tmpdidit" == "1"@ + , + @end@ + @if "$st" eq "$end"@ + $st + @else@ + $st .. $end + @end@ + @eval $tmpdidit = 1@ + @end@ + @end@ +## +## check for TC vs non-TC cases +## + @if "$i.perltype" ne "$i.syntax"@ +
+ @eval $tmpsyn = "$i.syntax"@ + @perleval if (!defined($TCS{$vars{'tmpsyn'}})) { $TCS{$vars{'tmpsyn'}} = $vars{'i'}; }; 0;@ +
$i.syntax + @if $i.enums@ +
(ENUM list below) + @end@ + @else@ + @if $i.enums@ + + + @foreach $e $v enum@ + + @end@ +
ValueLabel/Meaning
$v$e
+ @end@ + @end@ + + $i.access + @if !"$dont_do_oids"@ + $i.objectID + @end@ + @calldefine DO_DESCR@ +@enddefine@ +@open ${name}.html@ + + MIB information for $name + + + +

INTRODUCTION

+
    +

    +This is a summary of information regarding objects below the $name +MIB object, which is defined within the $name.module MIB +document as $name.objectID. +

    +
+## +## Table of contents +## +

TABLE OF CONTENTS

+ +## +## Start of definitions +## +@foreach $Current stuff Current Deprecated@ + +@if "$Current" ne "Current"@ + @eval $namestring = "notcurrent"@ +
+

DEPRECATED OR OBSOLETE OR HISTORIC OBJECTS

+
+
+@else@ + @eval $namestring = "current"@ +@end@ + +

SCALAR OBJECTS

+
    + + +@foreach $i scalar@ + @if ("$Current" eq "Current" && "$i.status" eq "Current") || ("$Current" ne "Current" && "$i.status" ne "Current")@ + + @calldefine NODE_INFO@ + + @end@ +@end@ +
    NameTypeAccessOIDDescription
    +
+ +

TABLE OBJECTS

+@eval $dont_do_oids = 1@ +@foreach $t table@ +@if ("$Current" eq "Current" && "$t.status" eq "Current") || ("$Current" ne "Current" && "$t.status" ne "Current")@ +

Table $t

+
    + + + + + +@eval $i ="$t"@ +@calldefine DO_DESCR@ + + @eval $tmpx = $t@ + @perleval $vars{'tmpx'} =~ s/Table/Entry/; 0;@ +@eval $i = "$tmpx"@ + +@calldefine DO_DESCR@ + +
    Table Name$t
    In MIB$t.module
    Registered at OID$t.objectID
    Table Description
    Row Description
    + +

    $t Indexes:

    + + + +@foreach $i index@ + + @calldefine NODE_INFO@ + +@end@ +
    NameTypeAccessDescription
    + +

    Other $t Columns:

    + + +@foreach $i nonindex@ + + @calldefine NODE_INFO@ + +@end@ +
    NameTypeAccessDescription
    +
+@end@ +@end@ +@end@ + +
+
+
+
+

NOTIFICATIONS

+
+ + +
+
+
+

TEXTUAL CONVENTIONS

+
    +

    +These TEXTUAL-CONVENTIONS are used in other parts of the document +above. They are SNMP's way of defining a datatype that is used +repeatedly by other MIB objects. Any implementation implementing +objects that use one of these definitions must follow its DESCRIPTION +clause as well as the DESCRIPTION clause of the object itself. +

    +@startperl@ +mib2c_output(""); +mib2c_output("\n"); +map { + my $desc = $SNMP::MIB{$TCS{$_}}{'TCDescription'}; + my ($s) = ($desc =~ /\n(\s+)/); + $desc =~ s/^$s//gm; + mib2c_output("\n"); +} keys(%TCS); +mib2c_output("
    NameTypeDescription
    $_"); + mib2c_output($SNMP::MIB{$TCS{$_}}{'type'}); + my @enumkeys = keys(%{$SNMP::MIB{$TCS{$_}}{'enums'}}); + if ($#enumkeys > -1) { + mib2c_output(""); + mib2c_output(""); + foreach $k (sort { $SNMP::MIB{$TCS{$_}}{'enums'}{$a} <=> + $SNMP::MIB{$TCS{$_}}{'enums'}{$b} } @enumkeys) { + mib2c_output(""); + } + mib2c_output("
    ValueLabel/Meaning
    $SNMP::MIB{$TCS{$_}}{'enums'}{$k}$k
    "); + } + mib2c_output("
    $desc
    "); +0; +@endperl@ +
+ +
+

TREE VIEW

+@eval $mod = "$name.module"@ +

Tree view generated by running: snmptranslate -Tp $mod::$name

+
+@startperl@
+open(TREE,"snmptranslate -Tp $vars{mod}::$vars{name}|");
+while() {
+  s/(\+-- .*\s)(\w+)(\(\d+\))$/$1$2<\/a>$3/;
+  s/\+--(\w+)/+--$1<\/a>/;
+  s/Textual Convention: (\w+)/Textual Convention: $1<\/a>/;
+  mib2c_output($_);
+}
+close(TREE);
+return 0;
+@endperl@
+
diff --git a/local/mib2c.int_watch.conf b/local/mib2c.int_watch.conf new file mode 100644 index 0000000..5804a74 --- /dev/null +++ b/local/mib2c.int_watch.conf @@ -0,0 +1,107 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open -@ +*** Warning: only generating code for nodes of MIB type INTEGER +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); + +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.int_watch.conf 13957 2005-12-20 15:33:08Z tanders $ + */ + +#include +#include +#include +#include "${name}.h" + +/* + * The variables we want to tie the relevant OIDs to. + * The agent will handle all GET and (if applicable) SET requests + * to these variables automatically, changing the values as needed. + */ + +@foreach $i scalar@ + @if !$i.needlength@ +$i.decl $i = 0; /* XXX: set default value */ + @end@ +@end@ + +/* + * Our initialization routine, called automatically by the agent + * (Note that the function name must match init_FILENAME()) + */ +void +init_${name}(void) +{ + netsnmp_handler_registration *reg; + netsnmp_watcher_info *winfo; + + @foreach $i scalar@ + @if !$i.needlength@ + static oid ${i}_oid[] = { $i.commaoid }; + @end@ + @end@ + + /* + * a debugging statement. Run the agent with -D$name to see + * the output of this debugging statement. + */ + DEBUGMSGTL(("$name", "Initializing the $name module\n")); + + + /* + * Register scalar watchers for each of the MIB objects. + * The ASN type and RO/RW status are taken from the MIB definition, + * but can be adjusted if needed. + * + * In most circumstances, the scalar watcher will handle all + * of the necessary processing. But the NULL parameter in the + * netsnmp_create_handler_registration() call can be used to + * supply a user-provided handler if necessary. + * + * This approach can also be used to handle Counter64, string- + * and OID-based watched scalars (although variable-sized writeable + * objects will need some more specialised initialisation). + */ + @foreach $i scalar@ + @if !$i.needlength@ + DEBUGMSGTL(("$name", + "Initializing $i scalar integer. Default value = %d\n", + $i)); + reg = netsnmp_create_handler_registration( + "$i", NULL, + ${i}_oid, OID_LENGTH(${i}_oid), + @if $i.settable@ + HANDLER_CAN_RWRITE); + @else@ + HANDLER_CAN_RONLY); + @end@ + winfo = netsnmp_create_watcher_info( + &$i, sizeof($i.decl), + $i.type, WATCHER_FIXED_SIZE); + if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { + snmp_log( LOG_ERR, "Failed to register watched $i" ); + } + + @end@ + @end@ + + DEBUGMSGTL(("$name", + "Done initalizing $name module\n")); +} diff --git a/local/mib2c.iterate.conf b/local/mib2c.iterate.conf new file mode 100644 index 0000000..774ae22 --- /dev/null +++ b/local/mib2c.iterate.conf @@ -0,0 +1,668 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.iterate.conf 17821 2009-11-11 09:00:00Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; +Netsnmp_First_Data_Point ${i}_get_first_data_point; +Netsnmp_Next_Data_Point ${i}_get_next_data_point; +@if "$cache" ne "" @ +NetsnmpCacheLoad ${i}_load; +NetsnmpCacheFree ${i}_free; +#define $i.uc_TIMEOUT 60 +@end@ +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ +@end@ +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.iterate.conf 17821 2009-11-11 09:00:00Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/** Initializes the $name module */ +void +init_$name(void) +{ + /* here we initialize all the tables we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} + +@foreach $i table@ + # Determine the first/last column names + @eval $first_column = "-"@ + @eval $last_column = "-"@ + @foreach $c column@ + @if $c.readable@ + @if "$first_column" eq "-"@ + @eval $first_column = $c@ + @end@ + @eval $last_column = $c@ + @end@ + @end@ + +/** Initialize the $i table by defining its contents and how it's structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + netsnmp_handler_registration *reg; + netsnmp_iterator_info *iinfo; + netsnmp_table_registration_info *table_info; + + reg = netsnmp_create_handler_registration( + "$i", ${i}_handler, + ${i}_oid, ${i}_oid_len, +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + netsnmp_table_helper_add_indexes(table_info, + @foreach $idx index@ + $idx.type, /* index: $idx */ + @end@ + 0); + table_info->min_column = COLUMN_$first_column.uc; + table_info->max_column = COLUMN_$last_column.uc; + + iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); + iinfo->get_first_data_point = ${i}_get_first_data_point; + iinfo->get_next_data_point = ${i}_get_next_data_point; + iinfo->table_reginfo = table_info; + + netsnmp_register_table_iterator( reg, iinfo ); +@if "$cache" ne "" @ + netsnmp_inject_handler_before( reg, + netsnmp_get_cache_handler($i.uc_TIMEOUT, + ${i}_load, ${i}_free, + ${i}_oid, ${i}_oid_len), + TABLE_ITERATOR_NAME); +@end@ + + /* Initialise the contents of the table here */ +} + + /* Typical data structure for a row entry */ +struct ${i}_entry { + /* Index values */ + @foreach $idx index@ + @if $idx.needlength@ + $idx.decl $idx[NNN]; + size_t ${idx}_len; + @else@ + $idx.decl $idx; + @end@ + @end@ + + /* Column values */ + @foreach $c column@ + @if $c.readable@ + @if $c.needlength@ + $c.decl $c[NNN]; + size_t ${c}_len; + @else@ + $c.decl $c; + @end@ + @if $c.settable@ + @if !$c.rowstatus@ + @if $c.needlength@ + $c.decl old_$c[NNN]; + size_t old_${c}_len; + @else@ + $c.decl old_$c; + @end@ + @end@ + @end@ + @end@ + @end@ + + /* Illustrate using a simple linked list */ + int valid; + struct ${i}_entry *next; +}; + +struct ${i}_entry *${i}_head; + +/* create a new row in the (unsorted) table */ +struct ${i}_entry * +${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + $idx.decl* $idx, + size_t ${idx}_len, + @else@ + $idx.decl $idx, + @end@ + @end@ + ) { + struct ${i}_entry *entry; + + entry = SNMP_MALLOC_TYPEDEF(struct ${i}_entry); + if (!entry) + return NULL; + + @foreach $idx index@ + @if $idx.needlength@ + memcpy(entry->$idx, $idx, ${idx}_len); + entry->${idx}_len = ${idx}_len; + @else@ + entry->$idx = $idx; + @end@ + @end@ + entry->next = ${i}_head; + ${i}_head = entry; + return entry; +} + +/* remove a row from the table */ +void +${i}_removeEntry( struct ${i}_entry *entry ) { + struct ${i}_entry *ptr, *prev; + + if (!entry) + return; /* Nothing to remove */ + + for ( ptr = ${i}_head, prev = NULL; + ptr != NULL; + prev = ptr, ptr = ptr->next ) { + if ( ptr == entry ) + break; + } + if ( !ptr ) + return; /* Can't find it */ + + if ( prev == NULL ) + ${i}_head = ptr->next; + else + prev->next = ptr->next; + + SNMP_FREE( entry ); /* XXX - release any other internal resources */ +} + +@if "$cache" ne "" @ +/* Example cache handling - set up linked list from a suitable file */ +int +${i}_load( netsnmp_cache *cache, void *vmagic ) { + FILE *fp; + struct ${i}_entry *this; + char buf[STRMAX]; + + fp = fopen( "/data/for/${i}", "r" ); + if ( !fp ) { + return -1; + } + while ( fgets( buf, STRMAX, fp )) { + this = SNMP_MALLOC_TYPEDEF( struct ${i}_entry ); + /* Unpick 'buf' and populate 'this' */ + + this->next = ${i}_head; + ${i}_head = this; /* Iterate helper is fine with unordered lists! */ + } + fclose(fp); + return 0; /* OK */ +} + +void +${i}_free( netsnmp_cache *cache, void *vmagic ) { + struct ${i}_entry *this, *that; + + for ( this = ${i}_head; this; this=that ) { + that = this->next; + SNMP_FREE( this ); /* XXX - release any other internal resources */ + } + ${i}_head = NULL; +} +@end@ + +/* Example iterator hook routines - using 'get_next' to do most of the work */ +netsnmp_variable_list * +${i}_get_first_data_point(void **my_loop_context, + void **my_data_context, + netsnmp_variable_list *put_index_data, + netsnmp_iterator_info *mydata) +{ + *my_loop_context = ${i}_head; + return ${i}_get_next_data_point(my_loop_context, my_data_context, + put_index_data, mydata ); +} + +netsnmp_variable_list * +${i}_get_next_data_point(void **my_loop_context, + void **my_data_context, + netsnmp_variable_list *put_index_data, + netsnmp_iterator_info *mydata) +{ + struct ${i}_entry *entry = (struct ${i}_entry *)*my_loop_context; + netsnmp_variable_list *idx = put_index_data; + + if ( entry ) { + @foreach $idx index@ + @if $idx.needlength@ + snmp_set_var_value( idx, entry->${idx}, sizeof(entry->${idx}) ); + @else@ + snmp_set_var_typed_integer( idx, $idx.type, entry->${idx} ); + @end@ + idx = idx->next_variable; + @end@ + *my_data_context = (void *)entry; + *my_loop_context = (void *)entry->next; + return put_index_data; + } else { + return NULL; + } +} + + +/** handles requests for the $i table */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + + netsnmp_request_info *request; + netsnmp_table_request_info *table_info; + struct ${i}_entry *table_entry; + + switch (reqinfo->mode) { + /* + * Read-support (also covers GetNext requests) + */ + case MODE_GET: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.readable@ + case COLUMN_$c.uc: + if ( !table_entry ) { + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHINSTANCE); + continue; + } + @if $c.needlength@ + snmp_set_var_typed_value( request->requestvb, $c.type, + (u_char*)table_entry->$c, + table_entry->${c}_len); + @else@ + snmp_set_var_typed_integer( request->requestvb, $c.type, + table_entry->$c); + @end@ + break; + @end@ + @end@ + default: + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHOBJECT); + break; + } + } + break; + +@if $i.settable@ + /* + * Write-support + */ + case MODE_SET_RESERVE1: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + @if $c.rowstatus@ + ret = netsnmp_check_vb_rowstatus(request->requestvb, + (table_entry ? RS_ACTIVE : RS_NONEXISTENT )); + @else@ + @if $c.needlength@ + /* or possiblc 'netsnmp_check_vb_type_and_size' */ + ret = netsnmp_check_vb_type_and_max_size( + request->requestvb, $c.type, sizeof(table_entry->$c)); + @else@ + /* or possibly 'netsnmp_check_vb_int_range' */ + ret = netsnmp_check_vb_int( request->requestvb ); + @end@ + @end@ + if ( ret != SNMP_ERR_NOERROR ) { + netsnmp_set_request_error( reqinfo, request, ret ); + return SNMP_ERR_NOERROR; + } + break; + @end@ + @end@ + default: + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_NOTWRITABLE ); + return SNMP_ERR_NOERROR; + } + } + break; + + case MODE_SET_RESERVE2: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + table_row = ${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_row) { + netsnmp_insert_iterator_context( request, table_row ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( !table_row ) { + table_row = ${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_row) { + netsnmp_insert_iterator_context( request, table_row ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_FREE: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(table_data, table_row ); + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(table_data, table_row ); + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_ACTION: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + @if !$c.rowstatus@ + case COLUMN_$c.uc: + @if $c.needlength@ + memcpy( table_entry->old_$c, + table_entry->$c, + sizeof(table_entry->$c)); + table_entry->old_${c}_len = + table_entry->${c}_len; + memset( table_entry->$c, 0, + sizeof(table_entry->$c)); + memcpy( table_entry->$c, + request->requestvb->val.string, + request->requestvb->val_len); + table_entry->${c}_len = + request->requestvb->val_len; + @else@ + table_entry->old_$c = table_entry->$c; + table_entry->$c = *request->requestvb->val.integer; + @end@ + break; + @end@ + @end@ + @end@ + } + } +@if $i.rowstatus@ + /* Check the internal consistency of an active row */ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_ACTIVE: + case RS_CREATEANDGO: + if (/* XXX */) { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_INCONSISTENTVALUE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ + } + } +@end@ + break; + + case MODE_SET_UNDO: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: +@if $i.rowstatus@ + @if $c.rowstatus@ + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(table_data, table_row ); + } + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@else@ + @if $c.creatable@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(table_data, table_row ); + } else { + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@end@ + break; + @end@ + @end@ + } + } + break; + + case MODE_SET_COMMIT: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_extract_iterator_context(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + table_entry->valid = 1; + /* Fall-through */ + case RS_ACTIVE: + table_entry->$c = RS_ACTIVE; + break; + + case RS_CREATEANDWAIT: + table_entry->valid = 1; + /* Fall-through */ + case RS_NOTINSERVICE: + table_entry->$c = RS_NOTINSERVICE; + break; + + case RS_DESTROY: + ${i}_removeEntry(table_data, table_row ); + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + table_entry->valid = 1; + } +@end@ + } + } +@end@ + break; +@end@ + } + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.iterate_access.conf b/local/mib2c.iterate_access.conf new file mode 100644 index 0000000..a7e0f32 --- /dev/null +++ b/local/mib2c.iterate_access.conf @@ -0,0 +1,423 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.iterate_access.conf 17483 2009-04-09 08:54:46Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/** other required module components */ +config_require(${name}_access) +config_require(${name}_checkfns) + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; + +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ +#include "${name}_columns.h" +@run mib2c.column_defines.conf@ + +/* enum definions */ +#include "${name}_enums.h" +@run mib2c.column_enums.conf@ + +@end@ +#endif /** $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.iterate_access.conf 17483 2009-04-09 08:54:46Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" +#include "${name}_checkfns.h" +#include "${name}_access.h" + +static netsnmp_oid_stash_node *undoStorage = NULL; +static netsnmp_oid_stash_node *commitStorage = NULL; + +struct undoInfo { + void *ptr; + size_t len; +}; + +struct commitInfo { + void *data_context; + int have_committed; + int new_row; +}; + +void +${name}_free_undoInfo(void *vptr) { + struct undoInfo *ui = vptr; + if (!ui) + return; + SNMP_FREE(ui->ptr); + SNMP_FREE(ui); +} + +@foreach $i table@ +/** Initialize the $i table by defining its contents and how it's structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + netsnmp_table_registration_info *table_info; + netsnmp_handler_registration *my_handler; + netsnmp_iterator_info *iinfo; + + /** create the table registration information structures */ + table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); + iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); + + my_handler = netsnmp_create_handler_registration("$i", + ${i}_handler, + ${i}_oid, + OID_LENGTH(${i}_oid), +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + if (!my_handler || !table_info || !iinfo) { + snmp_log(LOG_ERR, "malloc failed in initialize_table_$i"); + return; /** Serious error. */ + } + + /*************************************************** + * Setting up the table's definition + */ + netsnmp_table_helper_add_indexes(table_info, + @foreach $idx index@ + $idx.type, /** index: $idx */ + @end@ + 0); + + /** Define the minimum and maximum accessible columns. This + optimizes retrival. */ + @eval $minv = 0xffffffff@ + @eval $maxv = 0@ + @foreach $c column@ + @if $c.access =~ /(Read|Create)/@ + @eval $minv = min($minv, $c.subid)@ + @eval $maxv = max($maxv, $c.subid)@ + @end@ + @end@ + table_info->min_column = $minv; + table_info->max_column = $maxv; + + /** iterator access routines */ + iinfo->get_first_data_point = ${i}_get_first_data_point; + iinfo->get_next_data_point = ${i}_get_next_data_point; + + /** you may wish to set these as well */ +#ifdef MAYBE_USE_THESE + iinfo->make_data_context = ${i}_context_convert_function; + iinfo->free_data_context = ${i}_data_free; + + /** pick *only* one of these if you use them */ + iinfo->free_loop_context = ${i}_loop_free; + iinfo->free_loop_context_at_end = ${i}_loop_free; +#endif + + /** tie the two structures together */ + iinfo->table_reginfo = table_info; + + /*************************************************** + * registering the table with the master agent + */ + DEBUGMSGTL(("initialize_table_$i", + "Registering table $i as a table iterator\n")); + netsnmp_register_table_iterator(my_handler, iinfo); +} +@end@ + +/** Initializes the $name module */ +void +init_$name(void) +{ + + /** here we initialize all the tables we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} +@foreach $i table@ + +/** handles requests for the $i table, if anything else needs to be done */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + + netsnmp_request_info *request; + netsnmp_table_request_info *table_info; + netsnmp_variable_list *var; + struct commitInfo *ci = NULL; + + void *data_context = NULL; + + oid *suffix; + size_t suffix_len; + + /** column and row index encoded portion */ + suffix = requests->requestvb->name + reginfo->rootoid_len + 1; + suffix_len = requests->requestvb->name_length - + (reginfo->rootoid_len + 1); + + for(request = requests; request; request = request->next) { + var = request->requestvb; + if (request->processed != 0) + continue; + + switch (reqinfo->mode) { + case MODE_GET: + data_context = netsnmp_extract_iterator_context(request); + if (data_context == NULL) { + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHINSTANCE); + continue; + } + break; + +@if $i.settable@ + case MODE_SET_RESERVE1: + data_context = netsnmp_extract_iterator_context(request); +@if !$i.creatable@ + if (data_context == NULL) { + netsnmp_set_request_error(reqinfo, request, + SNMP_ERR_NOCREATION); + continue; + } +@end@ + break; + + default: /* == the other SET modes */ + ci = netsnmp_oid_stash_get_data(commitStorage, + suffix+1, suffix_len-1); + break; +@end@ + } + + /** extracts the information about the table from the request */ + table_info = netsnmp_extract_table_info(request); + /** table_info->colnum contains the column number requested */ + /** table_info->indexes contains a linked list of snmp variable + bindings for the indexes of the table. Values in the list + have been set corresponding to the indexes of the + request */ + if (table_info == NULL) { + continue; + } + + switch(reqinfo->mode) { + case MODE_GET: + switch(table_info->colnum) { + @foreach $c column@ + @if $c.access =~ /(Read|Create)/@ + case COLUMN_$c.uc: + { + $c.decl *retval; + size_t retval_len = 0; + retval = get_$c(data_context, &retval_len); + if (retval) + snmp_set_var_typed_value(var, $c.type, + (const u_char *) retval, + retval_len); + } + break; + + @end@ + @end@ + default: + /** We shouldn't get here */ + snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unknown column\n"); + } + break; + +@if $i.settable@ + case MODE_SET_RESERVE1: + ci = netsnmp_oid_stash_get_data(commitStorage, + suffix+1, suffix_len-1); + + if (!ci) { + /** create the commit storage info */ + ci = SNMP_MALLOC_STRUCT(commitInfo); + if (!data_context) { + ci->data_context = ${i}_create_data_context(table_info->indexes, table_info->colnum); + ci->new_row = 1; + } else { + ci->data_context = data_context; + } + netsnmp_oid_stash_add_data(&commitStorage, + suffix+1, suffix_len-1, ci); + } + break; + + case MODE_SET_RESERVE2: + switch(table_info->colnum) { + @foreach $c column@ + @if $c.access =~ /(Write|Create)/@ + case COLUMN_$c.uc: + { + $c.decl *retval; + size_t retval_len = 0; + struct undoInfo *ui = NULL; + int ret; + + /** first, get the old value */ + retval = get_$c(ci->data_context, &retval_len); + if (retval) { + ui = SNMP_MALLOC_STRUCT(undoInfo); + ui->len = retval_len; + memdup((u_char **) &ui->ptr, + (u_char *) retval, + ui->len); + } + + /** check the new value, possibly against the + older value for a valid state transition */ + ret = check_$c(request->requestvb->type, + ($c.decl *) request->requestvb->val.string, + request->requestvb->val_len, + retval, retval_len); + if (ret != 0) { + netsnmp_set_request_error(reqinfo, request, + ret); + ${name}_free_undoInfo(ui); + } else if (ui) { + /** remember information for undo purposes later */ + netsnmp_oid_stash_add_data(&undoStorage, + suffix, + suffix_len, + ui); + } + + } + break; + @end@ + @end@ + default: + netsnmp_set_request_error(reqinfo, request, + SNMP_ERR_NOTWRITABLE); + break; + } + break; + + case MODE_SET_ACTION: + /** save a variable copy */ + switch(table_info->colnum) { + @foreach $c column@ + @if $c.access =~ /(Write|Create)/@ + case COLUMN_$c.uc: + { + int ret; + ret = set_$c(ci->data_context, + ($c.decl *) request->requestvb->val.string, + request->requestvb->val_len); + if (ret) { + netsnmp_set_request_error(reqinfo, request, + ret); + } + @if $c.syntax eq "RowStatus"@ + if (*request->requestvb->val.integer == + RS_DESTROY) { + ci->new_row = -1; + } + @end@ + } + break; + @end@ + @end@ + } + break; + + case MODE_SET_COMMIT: + if (!ci->have_committed) { + /** do this once per row only */ + ${i}_commit_row(&ci->data_context, ci->new_row); + ci->have_committed = 1; + } + break; + + case MODE_SET_UNDO: + /** save a variable copy */ + switch(table_info->colnum) { + @foreach $c column@ + @if $c.access =~ /(Write|Create)/@ + case COLUMN_$c.uc: + { + int retval; + struct undoInfo *ui; + ui = netsnmp_oid_stash_get_data(undoStorage, + suffix, + suffix_len); + retval = set_$c(ci->data_context, ui->ptr, + ui->len); + if (retval) { + netsnmp_set_request_error(reqinfo, request, + SNMP_ERR_UNDOFAILED); + } + } + break; + @end@ + @end@ + } + break; + + case MODE_SET_FREE: + break; +@end@ + + default: + snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unsupported mode\n"); + } + } + +@if $i.settable@ + /** clean up after all requset processing has ended */ + switch(reqinfo->mode) { + case MODE_SET_UNDO: + case MODE_SET_FREE: + case MODE_SET_COMMIT: + /** clear out the undo cache */ + netsnmp_oid_stash_free(&undoStorage, ${name}_free_undoInfo); + netsnmp_oid_stash_free(&commitStorage, netsnmp_oid_stash_no_free); + } +@end@ + + return SNMP_ERR_NOERROR; +} +@end@ +@run mib2c.check_values.conf@ +@run mib2c.access_functions.conf@ +@open -@ + +********************************************************************** +NOTE: The only files you MUST modify should be the following: + ${name}_access.c + ${name}_access.h + ${name}_checkfns_local.h + ${name}_checkfns_local.c +********************************************************************** + diff --git a/local/mib2c.mfd.conf b/local/mib2c.mfd.conf new file mode 100644 index 0000000..ba1dc26 --- /dev/null +++ b/local/mib2c.mfd.conf @@ -0,0 +1,32 @@ +############################################################# -*- c -*- +## top level mfd conf file +## $Id: mib2c.mfd.conf 15885 2007-02-26 11:30:36Z dts12 $ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** START code generated by $RCSfile$ $Revision: 15885 $ */ +@end@ +######################################################################## +## +@if "x$mfd_interactive_setup" == "x"@ +@ eval $mfd_interactive_setup = 1@ +@end@ +@if "x$m2c_report_progress" == "x"@ +@ eval $m2c_report_progress = 1@ +@end@ +## +@ifconf default-mfd-top.m2c@ +@ include default-mfd-top.m2c@ +@end@ +## +@if $name =~ /Table$/i@ +@else@ +@ print This module can only be used with tables, not branches or entire MIBs.@ +@ print Please specify and OID that is a table. (OID: $name)@ +@ quit@ +@end@ +## +@run mfd-top.m2c@ +######################################################################## +@if $m2c_mark_boundary == 1@ +/** END code generated by $RCSfile$ $Revision: 15885 $ */ +@end@ diff --git a/local/mib2c.notify.conf b/local/mib2c.notify.conf new file mode 100644 index 0000000..d93963c --- /dev/null +++ b/local/mib2c.notify.conf @@ -0,0 +1,84 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.notify.conf 10110 2004-04-15 12:29:19Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +@foreach $i notifications@ +int send_${i}_trap(void); +@end@ + +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.notify.conf 10110 2004-04-15 12:29:19Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +static oid snmptrap_oid[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0}; + +@foreach $i notifications@ +int +send_${i}_trap( void ) +{ + netsnmp_variable_list *var_list = NULL; + oid ${i}_oid[] = { $i.commaoid }; + @foreach $v varbinds@ + @if $v.isscalar@ + oid ${v}_oid[] = { $v.commaoid, 0 }; + @end@ + @if !$v.isscalar@ + oid ${v}_oid[] = { $v.commaoid, /* insert index here */ }; + @end@ + @end@ + + /* + * Set the snmpTrapOid.0 value + */ + snmp_varlist_add_variable(&var_list, + snmptrap_oid, OID_LENGTH(snmptrap_oid), + ASN_OBJECT_ID, + ${i}_oid, sizeof(${i}_oid)); + + @if count_varbinds($i) > 0@ + /* + * Add any objects from the trap definition + */ + @end@ + @foreach $v varbinds@ + snmp_varlist_add_variable(&var_list, + ${v}_oid, OID_LENGTH(${v}_oid), + $v.type, + /* Set an appropriate value for $v */ + NULL, 0); + @end@ + + /* + * Add any extra (optional) objects here + */ + + /* + * Send the trap to the list of configured destinations + * and clean up + */ + send_v2trap( var_list ); + snmp_free_varbind( var_list ); + + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.old-api.conf b/local/mib2c.old-api.conf new file mode 100644 index 0000000..4ee924d --- /dev/null +++ b/local/mib2c.old-api.conf @@ -0,0 +1,345 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.old-api.conf 17851 2009-11-30 16:46:06Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +FindVarMethod var_$name; +@foreach $i table@ +FindVarMethod var_${i}; +@end@ +@foreach $i scalar@ + @if $i.settable@ + WriteMethod write_${i}; + @end@ +@end@ +@foreach $i table@ + @foreach $c column@ + @if $c.settable@ + WriteMethod write_${c}; + @end@ + @end@ +@end@ + +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.old-api.conf 17851 2009-11-30 16:46:06Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/* + * ${name}_variables_oid: + * this is the top level oid that we want to register under. This + * is essentially a prefix, with the suffix appearing in the + * variable below. + */ + +oid ${name}_variables_oid[] = { $name.commaoid }; + +/* + * variable4 ${name}_variables: + * this variable defines function callbacks and type return information + * for the $name mib section + */ + +struct variable4 ${name}_variables[] = { +/* magic number , variable type , ro/rw , callback fn , L, oidsuffix */ +@eval $magic = 0@ +@eval $namelen = length("$name.commaoid")@ +@foreach $i scalar@ + @eval $magic = $magic + 1@ + @eval $suffix = substr("$i.commaoid", $namelen + 1)@ + @eval $suffixlen = $i.oidlength - $name.oidlength@ +#define $i.uc $magic + @if $i.settable@ +{$i.uc, $i.type, RWRITE, var_${name}, $suffixlen, { $suffix }}, + @end@ + @if !$i.settable@ +{$i.uc, $i.type, RONLY , var_${name}, $suffixlen, { $suffix }}, + @end@ +@end@ + +@foreach $i table@ + @eval $magic = 0@ + @eval $nlen2 = length("$i.commaoid")@ + @if $nlen2 > $namelen@ + @eval $suffix = substr("$i.commaoid", $namelen + 1)@ + @eval $ctmp = ","@ + @else@ + @eval $suffix = ""@ + @eval $ctmp = ""@ + @end@ + @eval $suffixlen = $i.oidlength - $name.oidlength + 2@ + @foreach $c column@ + @eval $magic = $magic + 1@ +#define $c.uc $magic + @if $c.settable@ +{$c.uc, $c.type, RWRITE, var_${i}, $suffixlen, { $suffix $ctmp 1, $c.subid }}, + @end@ + @if !$c.settable@ +{$c.uc, $c.type, RONLY, var_${i}, $suffixlen, { $suffix $ctmp 1, $c.subid }}, + @end@ + @end@ +@end@ +}; +/* (L = length of the oidsuffix) */ + + +/** Initializes the $name module */ +void +init_$name(void) +{ + + DEBUGMSGTL(("$name", "Initializing\n")); + + /* register ourselves with the agent to handle our mib tree */ + REGISTER_MIB("$name", ${name}_variables, variable4, + ${name}_variables_oid); + + /* place any other initialization junk you need here */ +} + +/* + * var_$name(): + * This function is called every time the agent gets a request for + * a scalar variable that might be found within your mib section + * registered above. It is up to you to do the right thing and + * return the correct value. + * You should also correct the value of "var_len" if necessary. + * + * Please see the documentation for more information about writing + * module extensions, and check out the examples in the examples + * and mibII directories. + */ +unsigned char * +var_$name(struct variable *vp, + oid *name, + size_t *length, + int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* variables we may use later */ + static long long_ret; + static u_long ulong_ret; + static unsigned char string[SPRINT_MAX_LEN]; + static oid objid[MAX_OID_LEN]; + static struct counter64 c64; + + if (header_generic(vp,name,length,exact,var_len,write_method) + == MATCH_FAILED ) + return NULL; + + /* + * this is where we do the value assignments for the mib results. + */ + switch(vp->magic) { +@foreach $i scalar@ + case $i.uc: + @if $i.settable@ + *write_method = write_${i}; + @end@ + VAR = VALUE; /* XXX */ + return (u_char*) &VAR; +@end@ + default: + ERROR_MSG(""); + } + return NULL; +} + + +@foreach $i table@ +/* + * var_$i(): + * Handle this table separately from the scalar value case. + * The workings of this are basically the same as for var_$name above. + */ +unsigned char * +var_$i(struct variable *vp, + oid *name, + size_t *length, + int exact, + size_t *var_len, + WriteMethod **write_method) +{ + /* variables we may use later */ + static long long_ret; + static u_long ulong_ret; + static unsigned char string[SPRINT_MAX_LEN]; + static oid objid[MAX_OID_LEN]; + static struct counter64 c64; + + /* + * This assumes that the table is a 'simple' table. + * See the implementation documentation for the meaning of this. + * You will need to provide the correct value for the TABLE_SIZE parameter + * + * If this table does not meet the requirements for a simple table, + * you will need to provide the replacement code yourself. + * Mib2c is not smart enough to write this for you. + * Again, see the implementation documentation for what is required. + */ + if (header_simple_table(vp,name,length,exact,var_len,write_method, TABLE_SIZE) + == MATCH_FAILED ) + return NULL; + + /* + * this is where we do the value assignments for the mib results. + */ + switch(vp->magic) { +@foreach $c column@ + case $c.uc: + @if $c.settable@ + *write_method = write_${c}; + @end@ + VAR = VALUE; /* XXX */ + return (u_char*) &VAR; +@end@ + default: + ERROR_MSG(""); + } + return NULL; +} +@end@ + +@foreach $i scalar@ +@if $i.settable@ + + +int +write_$i(int action, + u_char *var_val, + u_char var_val_type, + size_t var_val_len, + u_char *statP, + oid *name, + size_t name_len) +{ + $i.decl value; + int size; + + switch ( action ) { + case RESERVE1: + if (var_val_type != $i.type) { + fprintf(stderr, "write to $name not $i.type\n"); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len > sizeof($i.decl)) { + fprintf(stderr,"write to $name: bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + break; + + case RESERVE2: + size = var_val_len; + value = * ($i.decl *) var_val; + + break; + + case FREE: + /* Release any resources that have been allocated */ + break; + + case ACTION: + /* + * The variable has been stored in 'value' for you to use, + * and you have just been asked to do something with it. + * Note that anything done here must be reversable in the UNDO case + */ + break; + + case UNDO: + /* Back out any changes made in the ACTION case */ + break; + + case COMMIT: + /* + * Things are working well, so it's now safe to make the change + * permanently. Make sure that anything done here can't fail! + */ + break; + } + return SNMP_ERR_NOERROR; +} +@end@ +@end@ + +@foreach $i table@ +@foreach $c column@ +@if $c.settable@ +int +write_$c(int action, + u_char *var_val, + u_char var_val_type, + size_t var_val_len, + u_char *statP, + oid *name, + size_t name_len) +{ + $c.decl value; + int size; + + switch ( action ) { + case RESERVE1: + if (var_val_type != $c.type) { + fprintf(stderr, "write to $name not $c.type\n"); + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len > sizeof($c.decl)) { + fprintf(stderr,"write to $name: bad length\n"); + return SNMP_ERR_WRONGLENGTH; + } + break; + + case RESERVE2: + size = var_val_len; + value = * ($c.decl *) var_val; + + break; + + case FREE: + /* Release any resources that have been allocated */ + break; + + case ACTION: + /* + * The variable has been stored in 'value' for you to use, + * and you have just been asked to do something with it. + * Note that anything done here must be reversable in the UNDO case + */ + break; + + case UNDO: + /* Back out any changes made in the ACTION case */ + break; + + case COMMIT: + /* + * Things are working well, so it's now safe to make the change + * permanently. Make sure that anything done here can't fail! + */ + break; + } + return SNMP_ERR_NOERROR; +} +@end@ +@end@ +@end@ diff --git a/local/mib2c.perl.conf b/local/mib2c.perl.conf new file mode 100755 index 0000000..3c83a18 --- /dev/null +++ b/local/mib2c.perl.conf @@ -0,0 +1,314 @@ +## ######################################################################## +## +## Config for generating modules for use in the embedded perl environmentg +## +## Copyright Tripleplay Services Limited 2005 +## All rights reserved. +## +## Use is subject to license terms specified in the COPYING file +## distributed with the Net-SNMP package. +## +## ######################################################################## +## +## Gotchas. +## Any $ signs in the output will be snaffled and disappear. For this reason +## lines that need to output perl variables use a printf line instead +## +## Comments that are for the use of documenting this config file +## need to be double hashes +## +## Operation +## 1. Creates a file called output.tmp which contains the main data structures +## and a call to the agent startup function. +## 2. Creates a file called skel.tmp with skeleton accessor functions. +## This should be copied to functions.pl and edited to actually +## do the work required for each leaf. +## 3. Creates an output file with the OID name. This contains the bolierplate +## and the data structures +## This is the file to reference in the snmpd.conf file +## +## The user must fill in the functions.pl code as requried. This file is then +## included at run time at the top of the generated perl code +## (do 'functions.pl) +## +## The generated file needs the NetSNMP::agent::Support.pm module in the +## system. This module contains the run-time support for the agent. +## +## The oidtable is a hash of hashes with the top level key an OID +## There are two types of entry +## 1. Scalars have the full OID plus the .0 index string +## 2. Columnar data has the index fields set to 0. The NetSNMP::agent::Support +## code will use zeros to locate the table specific handlers. +## +## ######################################################################### + + +## ######################################################################### +## Define the 'macros' used later in this config file +## ######################################################################### +@define EMIT_INDEX_VARS@ + ## + ## Calculate the number of index identifiers and then + ## for each identifier work out the offset in the oid + ## + @eval $numindex=0@ + @eval $idxoffset = $c.oidlength@ + # The values of the oid elements for the indexes + @foreach $i index@ +## my $$idx_$i = getOidElement($$idx, $idxoffset); + @printf " my %sidx_$vars{'i'} = getOidElement(%soid, $vars{'idxoffset'});\n",$,$@ + @eval $idxoffset = $idxoffset + 1@ + @end@ +@enddefine@ + +@define EMIT_GETARGS@ + ## + ## Output the code the get the args for a function + ## + # The OID is passed as a NetSNMP::OID object + @printf " my (%soid) = shift;\n",$@ +@enddefine@ + +@define EMIT_LOAD_DATA@ + ## + ## Emit the code to load a data table + ## + # Load the $t table data + load_$t(); +@enddefine@ + +@define EMIT_INDEX_INFO@ +## +## Emit a list of indexes for a table as perl comments +## To be used when generating the comment fields for a handler +## +# In Table: $t +@foreach $i index@ +# Index: $i +@end@ +@enddefine@ + +@define EMIT_INDEX_WALKER@ +## +## Output a skeleton index walker and index checker +## for the table if it has not been done already +## +@if $needwalker@ +## Output skeleton index validator for table +# ------------------------------------------------------- +# Index validation for table $t +# Checks the supplied OID is in range +# Returns 1 if it is and 0 if out of range +@calldefine EMIT_INDEX_INFO@ +# ------------------------------------------------------- +sub check_$t { + @calldefine EMIT_GETARGS@ + + @calldefine EMIT_INDEX_VARS@ + + @calldefine EMIT_LOAD_DATA@ + + # Check the index is in range and valid + return 1; +} + +# ------------------------------------------------------- +# Index walker for table $t +# Given an OID for a table, returns the next OID in range, +# or if no more OIDs it returns 0. +@calldefine EMIT_INDEX_INFO@ +# ------------------------------------------------------- +sub next_$t { + @calldefine EMIT_GETARGS@ + + @calldefine EMIT_INDEX_VARS@ + + @calldefine EMIT_LOAD_DATA@ + + # Return the next OID if there is one + # or return 0 if no more OIDs in this table + return 0; +} +@eval $needwalker = 0@ ## Dont need this again for the current table +@end@ +@enddefine@ + +@define EMIT_TABLE_LOAD@ +# ------------------------------------------------------- +# Loader for table $t +# Edit this function to load the data needed for $t +# This function gets called for every request to columnar +# data in the $t table +# ------------------------------------------------------- +sub load_$t { + +} +@enddefine@ + +@eval $date=scalar localtime; @ + +## Open the output file and emit the perl startup bolierplate +@open output.tmp@ +#!/usr/bin/perl -w +# +# +# WARNING: DO NOT EDIT THIS FILE BY HAND. +# +# This file has been generated by mib2c using the mib2c.perl.conf file +# This is intended to be used by the net-snmp agent with embedded perl +# support. See perldoc NetSNMP::agent +# +# Created on $date +# +# To load this into a running agent with embedded perl support turned +# on, simply put the following line (without the leading # mark) your +# snmpd.conf file: +# +@printf "# perl do 'path/to/agent_%s.pl'\n",$oid@ +# +# You will need a copy of NetSNMP installed. This has been developed using +# NetSNMP version 5.2.2 +# + + + +##use strict; +use NetSNMP::agent::Support; +use NetSNMP::ASN (':all'); + +# Include the functions to handle the nodes +do 'functions.pl'; + +## Create the skeleton file ready for the skeleton handlers later on +@push@ +@open skel.tmp@ +# Skeleton accessor functions. +# DO NOT EDIT +# This file will be overwritten next time mib2c is run. +# Copy this file to functions.pl and then edit it. +@close skel.tmp@ +@pop@ + +## Generate the hash of hashes with the oids and handlers for the tables +# Hash for all OIDs +@printf "my %soidtable={\n", $@ +# Table objects +@foreach $t table@ + @print Processing table $t@ + @push@ + @append skel.tmp@ +## Output skeleton loader for this table + @calldefine EMIT_TABLE_LOAD@ + @close skel.tmp@ + @pop@ + ## + @eval $needwalker = 1@ ## Need the walker and checker once this table + @foreach $c nonindex@ + @if $c.accessible @ + ## + ## Generate the entry for the hash table + ## We first calculate the number of index items for this table + @eval $numindex = 0@ + @eval $idxelem = ""@ + @foreach $i index@ + @perleval $vars{'idxelem'} .= '.0'; 0; @ + @eval $numindex = $numindex+1@ + @end@ + "$c.objectID$idxelem"=>{func=>\&get_$c,type=>$c.type, check=>\&check_$t, nextoid=>\&next_$t, istable=>'1', next=>"", numindex=>$numindex}, + ## Output skeleton handlers for this column object + @push@ + @append skel.tmp@ +@calldefine EMIT_INDEX_WALKER@ +# ------------------------------------------------------- +# Handler for columnar object '$c' +# OID: $c.objectID +# Syntax: $c.type +# From: $c.module +@calldefine EMIT_INDEX_INFO@ +# ------------------------------------------------------- +sub get_$c { + @calldefine EMIT_GETARGS@ + + @calldefine EMIT_INDEX_VARS@ + + @calldefine EMIT_LOAD_DATA@ + + # Code here to read the required variable from the loaded table + # using whatever indexing you need. + # The index has already been checked and found to be valid + + ## Add further types as required. + @if $c.type eq "ASN_INTEGER"@ + return 32; + @end@ + @if $c.type eq "ASN_OCTET_STR"@ + return "STR"; + @end@ + @if $c.type eq "ASN_COUNTER64"@ + return 64; + @end@ +} + @close skel.tmp@ + @pop@ + @end@ + @end@ +@end@ +@print Processing scalars@ +## output the hash with the OIDs and handlers +## Scalars have a single index element +# Scalars +@foreach $s scalar@ + @if $s.accessible@ + '$s.objectID.0'=>{func=>\&get_$s,type=>$s.type,next=>"", numindex=>1}, + @end@ +@end@ +##End of the OID hash +}; + +## Emit code to register the top level oid with the agent +## The $oid variable comes from mib2c as the last non option arg +# Register the top oid with the agent +@printf "registerAgent(%sagent, '$oid', %soidtable);",$,$@ + +## Output skeleton handlers for the scalars +@push@ +@append skel.tmp@ +@foreach $s scalar@ + @if $s.accessible@ +# ------------------------------------------------------- +# Handler for scalar object $s +# OID: $s.objectID +# Syntax: $s.type +# From: $s.module +# ------------------------------------------------------- +sub get_$s { + + # Add code here to read the value required and return it + + ## Add further types as required. + @if $s.type eq "ASN_INTEGER"@ + return 32; + @end@ + @if $s.type eq "ASN_OCTET_STR"@ + return "STR"; + @end@ + @if $s.type eq "ASN_COUNTER64"@ + return 64; + @end@ +} + @end@ +@end@ +@close skel.tmp@ +@pop@ + +@close output.tmp@ +## +## Now create the code file from the outputfile +## +@startperl@ +my $oidname = $vars{'oid'}; +my $out = "agent_" . $oidname .".pl"; +system("cat output.tmp > $out"); +@endperl@ +@print Output code generated.@ + diff --git a/local/mib2c.row.conf b/local/mib2c.row.conf new file mode 100755 index 0000000..4b81145 --- /dev/null +++ b/local/mib2c.row.conf @@ -0,0 +1,282 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.row.conf 15201 2006-09-14 09:53:44Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; +netsnmp_variable_list *${i}_buildIndexList(struct ${i}_entry *row); +struct ${i}_entry * +${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + , $idx.decl* $idx + , size_t ${idx}_len + @else@ + , $idx.decl $idx + @end@ + @end@ + ); +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ + + +/* Typical data structure for a row entry */ +struct ${i}_entry { + netsnmp_index oid_index; + + /* Index values */ + @foreach $idx index@ + @if $idx.needlength@ + $idx.decl $idx[NNN]; + size_t ${idx}_len; + @else@ + $idx.decl $idx; + @end@ + @end@ + + /* Column values */ + @foreach $c column@ + @if $c.readable@ + @if $c.needlength@ + $c.decl $c[NNN]; + size_t ${c}_len; + @else@ + $c.decl $c; + @end@ + @if $c.settable@ + @if !$c.rowstatus@ + @if $c.needlength@ + $c.decl old_$c[NNN]; + size_t old_${c}_len; + @else@ + $c.decl old_$c; + @end@ + @end@ + @end@ + @end@ + @end@ + + int valid; +}; + +@end@ +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.row.conf 15201 2006-09-14 09:53:44Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/** Initializes the $name module */ +void +init_$name(void) +{ + /* here we initialize all the table rows we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} + +@foreach $i table@ + @eval $first_column = "-"@ + @eval $last_column = "-"@ + @foreach $c column@ + @if $c.readable@ + @if "$first_column" eq "-"@ + @eval $first_column = $c@ + @end@ + @eval $last_column = $c@ + @end@ + @end@ + +/** Initialize an entry in the $i table, including how the table is structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + netsnmp_handler_registration *reg; + struct ${i}_entry *row; + netsnmp_variable_list *idxs; + netsnmp_table_registration_info *table_info; + + reg = netsnmp_create_handler_registration( + "$i", ${i}_handler, + ${i}_oid, ${i}_oid_len, +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + netsnmp_table_helper_add_indexes(table_info, + @foreach $idx index@ + $idx.type, /* index: $idx */ + @end@ + 0); + table_info->min_column = COLUMN_$first_column.uc; + table_info->max_column = COLUMN_$last_column.uc; + + /* + * Create the row to be registered + */ + row = ${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + ,/* $idx value */ , /* $idx length */ + @else@ + ,/* $idx value */ + @end@ + @end@ + ); + /* + * XXX: Set any other readable column values here + */ + idxs = ${i}_buildIndexList(row); + netsnmp_table_row_register( reg, table_info, row, idxs ); + + /* Repeat for any other rows to be registered */ +} + +/* create a new row in the table */ +struct ${i}_entry * +${i}_createEntry( + @foreach $idx index@ + @if $idx.needlength@ + , $idx.decl* $idx + , size_t ${idx}_len + @else@ + , $idx.decl $idx + @end@ + @end@ + ) { + struct ${i}_entry *entry; + + entry = SNMP_MALLOC_TYPEDEF(struct ${i}_entry); + if (!entry) + return NULL; + + @foreach $idx index@ + @if $idx.needlength@ + memcpy(entry->$idx, $idx, ${idx}_len); + entry->${idx}_len = ${idx}_len; + @else@ + entry->$idx = $idx; + @end@ + @end@ + + return entry; +} + +netsnmp_variable_list * +${i}_buildIndexList(struct ${i}_entry *row) +{ + netsnmp_variable_list *v1 = NULL, *v2; + + if (!row) + return NULL; + + @eval $first=1@ + @foreach $idx index@ + @if $first==1@ + v1 = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); + v2 = v1; + @else@ + v2->next_variable = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); + v2 = v2->next_variable; + @end@ + @if $idx.needlength@ + snmp_set_var_typed_value( v2, $idx.type, (u_char*)row->$idx, + row->${idx}_len); + @else@ + snmp_set_var_typed_integer( v2, $idx.type, (u_char*)row->$idx); + @end@ + @eval $first=0@ + @end@ + + return v1; +} + +/** handles requests for a row of the $i table */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + + netsnmp_request_info *request; + netsnmp_table_request_info *table_info; + netsnmp_table_data *table_data; + struct ${i}_entry *table_entry; + int ret; + + switch (reqinfo->mode) { + /* + * Read-support (also covers GetNext requests) + */ + case MODE_GET: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_table_row_extract(request); + + switch (request->requestvb->name[$i.oidlength+1]) { + @foreach $c column@ + @if $c.readable@ + case COLUMN_$c.uc: + @if $c.needlength@ + snmp_set_var_typed_value( request->requestvb, $c.type, + (u_char*)table_entry->$c, + table_entry->${c}_len); + @else@ + snmp_set_var_typed_integer( request->requestvb, $c.type, + table_entry->$c); + @end@ + break; + @end@ + @end@ + default: + /* An unsupported/unreadable column (if applicable) */ + snmp_set_var_typed_value( request->requestvb, SNMP_NOSUCHOBJECT, + NULL, 0 ); + } + } + break; + +@if $i.settable@ + /* + * Write-support - TODO + */ +@end@ + break; +@end@ + } + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.scalar.conf b/local/mib2c.scalar.conf new file mode 100644 index 0000000..dda308c --- /dev/null +++ b/local/mib2c.scalar.conf @@ -0,0 +1,142 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i scalar@ +Netsnmp_Node_Handler handle_${i}; +@end@ + +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.scalar.conf 11805 2005-01-07 09:37:18Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/** Initializes the $name module */ +void +init_$name(void) +{ + @foreach $i scalar@ + static oid ${i}_oid[] = { $i.commaoid }; + @end@ + + DEBUGMSGTL(("$name", "Initializing\n")); + + @foreach $i scalar@ + netsnmp_register_scalar( + netsnmp_create_handler_registration("$i", handle_$i, + ${i}_oid, OID_LENGTH(${i}_oid), + @if !$i.settable@ + HANDLER_CAN_RONLY + @end@ + @if $i.settable@ + HANDLER_CAN_RWRITE + @end@ + )); + @end@ +} + +@foreach $i scalar@ +int +handle_$i(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + @if $i.settable@ + int ret; + @end@ + /* We are never called for a GETNEXT if it's registered as a + "instance", as it's "magically" handled for us. */ + + /* a instance handler also only hands us one request at a time, so + we don't need to loop over a list of requests; we'll only get one. */ + + switch(reqinfo->mode) { + + case MODE_GET: + snmp_set_var_typed_value(requests->requestvb, $i.type, + (u_char *) /* XXX: a pointer to the scalar's data */, + /* XXX: the length of the data in bytes */); + break; + + @if $i.settable@ + /* + * SET REQUEST + * + * multiple states in the transaction. See: + * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg + */ + case MODE_SET_RESERVE1: + /* or you could use netsnmp_check_vb_type_and_size instead */ + ret = netsnmp_check_vb_type(requests->requestvb, $i.type); + if ( ret != SNMP_ERR_NOERROR ) { + netsnmp_set_request_error(reqinfo, requests, ret ); + } + break; + + case MODE_SET_RESERVE2: + /* XXX malloc "undo" storage buffer */ + if (/* XXX if malloc, or whatever, failed: */) { + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); + } + break; + + case MODE_SET_FREE: + /* XXX: free resources allocated in RESERVE1 and/or + RESERVE2. Something failed somewhere, and the states + below won't be called. */ + break; + + case MODE_SET_ACTION: + /* XXX: perform the value change here */ + if (/* XXX: error? */) { + netsnmp_set_request_error(reqinfo, requests, /* some error */); + } + break; + + case MODE_SET_COMMIT: + /* XXX: delete temporary storage */ + if (/* XXX: error? */) { + /* try _really_really_ hard to never get to this point */ + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED); + } + break; + + case MODE_SET_UNDO: + /* XXX: UNDO and return to previous value for the object */ + if (/* XXX: error? */) { + /* try _really_really_ hard to never get to this point */ + netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED); + } + break; + @end@ + + default: + /* we should never get here, so this is a really bad error */ + snmp_log(LOG_ERR, "unknown mode (%d) in handle_${i}\n", reqinfo->mode ); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/mib2c.table_data.conf b/local/mib2c.table_data.conf new file mode 100644 index 0000000..5362ee9 --- /dev/null +++ b/local/mib2c.table_data.conf @@ -0,0 +1,647 @@ +## -*- c -*- +###################################################################### +## Do the .h file +###################################################################### +@open ${name}.h@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.table_data.conf 18469 2010-04-07 14:05:38Z dts12 $ + */ +#ifndef $name.uc_H +#define $name.uc_H + +/* function declarations */ +void init_$name(void); +@foreach $i table@ +void initialize_table_$i(void); +Netsnmp_Node_Handler ${i}_handler; +@if "$cache" ne "" @ +NetsnmpCacheLoad ${i}_load; +NetsnmpCacheFree ${i}_free; +#define $i.uc_TIMEOUT 60 +@end@ +@end@ +@foreach $i table@ + +/* column number definitions for table $i */ + @foreach $c column@ + #define COLUMN_$c.uc $c.subid + @end@ +@end@ +#endif /* $name.uc_H */ +###################################################################### +## Do the .c file +###################################################################### +@open ${name}.c@ +/* + * Note: this file originally auto-generated by mib2c using + * $Id: mib2c.table_data.conf 18469 2010-04-07 14:05:38Z dts12 $ + */ + +#include +#include +#include +#include "${name}.h" + +/** Initializes the $name module */ +void +init_$name(void) +{ + /* here we initialize all the tables we're planning on supporting */ + @foreach $i table@ + initialize_table_$i(); + @end@ +} + +@foreach $i table@ + ## Determine the first/last column names + @eval $first_column = "-"@ + @eval $last_column = "-"@ + @foreach $c column@ + @if $c.readable@ + @if "$first_column" eq "-"@ + @eval $first_column = $c@ + @end@ + @eval $last_column = $c@ + @end@ + @end@ + +/** Initialize the $i table by defining its contents and how it's structured */ +void +initialize_table_$i(void) +{ + static oid ${i}_oid[] = {$i.commaoid}; + size_t ${i}_oid_len = OID_LENGTH(${i}_oid); + netsnmp_handler_registration *reg; + netsnmp_tdata *table_data; + netsnmp_table_registration_info *table_info; +@if "$cache" ne "" @ + netsnmp_cache *cache; +@end@ + + reg = netsnmp_create_handler_registration( + "$i", ${i}_handler, + ${i}_oid, ${i}_oid_len, +@if $i.settable@ + HANDLER_CAN_RWRITE +@else@ + HANDLER_CAN_RONLY +@end@ + ); + + table_data = netsnmp_tdata_create_table( "$i", 0 ); + table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); + netsnmp_table_helper_add_indexes(table_info, + @foreach $idx index@ + $idx.type, /* index: $idx */ + @end@ + 0); + + table_info->min_column = COLUMN_$first_column.uc; + table_info->max_column = COLUMN_$last_column.uc; + + netsnmp_tdata_register( reg, table_data, table_info ); +@if "$cache" ne "" @ + cache = netsnmp_cache_create($i.uc_TIMEOUT, + ${i}_load, ${i}_free, + ${i}_oid, ${i}_oid_len); + cache->magic = (void *)table_data; + netsnmp_inject_handler_before( reg, netsnmp_cache_handler_GET(cache), TABLE_TDATA_NAME); +@end@ + + /* Initialise the contents of the table here */ +} + + /* Typical data structure for a row entry */ +struct ${i}_entry { + /* Index values */ + @foreach $idx index@ + @if $idx.needlength@ + $idx.decl $idx[NNN]; + size_t ${idx}_len; + @else@ + $idx.decl $idx; + @end@ + @end@ + + /* Column values */ + @foreach $c column@ + @if $c.readable@ + @if $c.needlength@ + $c.decl $c[NNN]; + size_t ${c}_len; + @else@ + $c.decl $c; + @end@ + @if $c.settable@ + @if !$c.rowstatus@ + @if $c.needlength@ + $c.decl old_$c[NNN]; + size_t old_${c}_len; + @else@ + $c.decl old_$c; + @end@ + @end@ + @end@ + @end@ + @end@ + + int valid; +}; + +/* create a new row in the table */ +netsnmp_tdata_row * +${i}_createEntry(netsnmp_tdata *table_data + @foreach $idx index@ + @if $idx.needlength@ + , $idx.decl* $idx + , size_t ${idx}_len + @else@ + , $idx.decl $idx + @end@ + @end@ + ) { + struct ${i}_entry *entry; + netsnmp_tdata_row *row; + + entry = SNMP_MALLOC_TYPEDEF(struct ${i}_entry); + if (!entry) + return NULL; + + row = netsnmp_tdata_create_row(); + if (!row) { + SNMP_FREE(entry); + return NULL; + } + row->data = entry; + @foreach $idx index@ + @if $idx.needlength@ + memcpy(entry->$idx, $idx, ${idx}_len); + entry->${idx}_len = ${idx}_len; + netsnmp_tdata_row_add_index( row, $idx.type, + entry->$idx, ${idx}_len); + @else@ + entry->$idx = $idx; + netsnmp_tdata_row_add_index( row, $idx.type, + &(entry->$idx), + sizeof(entry->$idx)); + @end@ + @end@ + netsnmp_tdata_add_row( table_data, row ); + return row; +} + +/* remove a row from the table */ +void +${i}_removeEntry(netsnmp_tdata *table_data, + netsnmp_tdata_row *row) { + struct ${i}_entry *entry; + + if (!row) + return; /* Nothing to remove */ + entry = (struct ${i}_entry *) + netsnmp_tdata_remove_and_delete_row( table_data, row ); + if (entry) + SNMP_FREE( entry ); /* XXX - release any other internal resources */ +} + +@if "$cache" ne "" @ +/* Example cache handling - set up table_data list from a suitable file */ +int +${i}_load( netsnmp_cache *cache, void *vmagic ) { + netsnmp_tdata *table = (netsnmp_tdata *)vmagic; + netsnmp_tdata_row *row; + FILE *fp; + char buf[STRMAX]; + @if $idx.needlength@ + $idx.decl* $idx; + size_t ${idx}_len; + @else@ + $idx.decl $idx; + @end@ + + fp = fopen( "/data/for/${i}", "r" ); + if ( !fp ) { + return -1; + } + while ( fgets( buf, STRMAX, fp )) { + /* Unpick 'buf' to extract the index values... */ + this = ${i}_createEntry(table + @foreach $idx index@ + @if $idx.needlength@ + , $idx + , ${idx}_len + @else@ + , $idx + @end@ + @end@ + ); + /* ... and then populate 'this' with the column values */ + } + fclose(fp); + return 0; /* OK */ +} + +void +${i}_free( netsnmp_cache *cache, void *vmagic ) { + netsnmp_tdata *table = (netsnmp_tdata *)vmagic; + netsnmp_tdata_row *this; + + while ((this = netsnmp_tdata_get_first_row(table))) { + netsnmp_tdata_remove_and_delete_row(table, this); + } +} +@end@ + +/** handles requests for the $i table */ +int +${i}_handler( + netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) { + + netsnmp_request_info *request; + netsnmp_table_request_info *table_info; + netsnmp_tdata *table_data; + netsnmp_tdata_row *table_row; + struct ${i}_entry *table_entry; + int ret; + + switch (reqinfo->mode) { + /* + * Read-support (also covers GetNext requests) + */ + case MODE_GET: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.readable@ + case COLUMN_$c.uc: + if ( !table_entry ) { + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHINSTANCE); + continue; + } + @if $c.needlength@ + snmp_set_var_typed_value( request->requestvb, $c.type, + (u_char*)table_entry->$c, + table_entry->${c}_len); + @else@ + snmp_set_var_typed_integer( request->requestvb, $c.type, + table_entry->$c); + @end@ + break; + @end@ + @end@ + default: + netsnmp_set_request_error(reqinfo, request, + SNMP_NOSUCHOBJECT); + break; + } + } + break; + +@if $i.settable@ + /* + * Write-support + */ + case MODE_SET_RESERVE1: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: + @if $c.rowstatus@ + ret = netsnmp_check_vb_rowstatus(request->requestvb, + (table_entry ? RS_ACTIVE : RS_NONEXISTENT )); + @else@ + @if $c.needlength@ + /* or possiblc 'netsnmp_check_vb_type_and_size' */ + ret = netsnmp_check_vb_type_and_max_size( + request->requestvb, $c.type, sizeof(table_entry->$c)); + @else@ + /* or possibly 'netsnmp_check_vb_int_range' */ + ret = netsnmp_check_vb_int( request->requestvb ); + @end@ + @end@ + if ( ret != SNMP_ERR_NOERROR ) { + netsnmp_set_request_error( reqinfo, request, ret ); + return SNMP_ERR_NOERROR; + } + break; + @end@ + @end@ + default: + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_NOTWRITABLE ); + return SNMP_ERR_NOERROR; + } + } + break; + + case MODE_SET_RESERVE2: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_row = netsnmp_tdata_extract_row( request); + table_data = netsnmp_tdata_extract_table(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + table_row = ${i}_createEntry(table_data + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_row) { + netsnmp_insert_tdata_row( request, table_row ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( !table_row ) { + table_row = ${i}_createEntry(table_data + @foreach $idx index@ + @if $idx.needlength@ + , table_info->indexes->val.string + , table_info->indexes->val_len + @else@ + , *table_info->indexes->val.integer + @end@ + @end@ + ); + if (table_row) { + netsnmp_insert_tdata_row( request, table_row ); + } else { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_RESOURCEUNAVAILABLE ); + return SNMP_ERR_NOERROR; + } + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_FREE: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_row = netsnmp_tdata_extract_row( request); + table_data = netsnmp_tdata_extract_table(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(table_data, table_row ); + } + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(table_data, table_row ); + } + break; +@end@ + } + } +@end@ + break; + + case MODE_SET_ACTION: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + @if !$c.rowstatus@ + case COLUMN_$c.uc: + @if $c.needlength@ + memcpy( table_entry->old_$c, + table_entry->$c, + sizeof(table_entry->$c)); + table_entry->old_${c}_len = + table_entry->${c}_len; + memset( table_entry->$c, 0, + sizeof(table_entry->$c)); + memcpy( table_entry->$c, + request->requestvb->val.string, + request->requestvb->val_len); + table_entry->${c}_len = + request->requestvb->val_len; + @else@ + table_entry->old_$c = table_entry->$c; + table_entry->$c = *request->requestvb->val.integer; + @end@ + break; + @end@ + @end@ + @end@ + } + } +@if $i.rowstatus@ + /* Check the internal consistency of an active row */ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_ACTIVE: + case RS_CREATEANDGO: + if (/* XXX */) { + netsnmp_set_request_error( reqinfo, request, + SNMP_ERR_INCONSISTENTVALUE ); + return SNMP_ERR_NOERROR; + } + } + @end@ + @end@ + } + } +@end@ + break; + + case MODE_SET_UNDO: + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); + table_row = netsnmp_tdata_extract_row( request); + table_data = netsnmp_tdata_extract_table(request); + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { + @foreach $c column@ + @if $c.settable@ + case COLUMN_$c.uc: +@if $i.rowstatus@ + @if $c.rowstatus@ + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + case RS_CREATEANDWAIT: + if (table_entry && !table_entry->valid) { + ${i}_removeEntry(table_data, table_row ); + } + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@else@ + @if $c.creatable@ + if ( table_entry && !table_entry->valid ) { + ${i}_removeEntry(table_data, table_row ); + } else { + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + } + @else@ + @if $c.needlength@ + memcpy( table_entry->$c, + table_entry->old_$c, + sizeof(table_entry->$c)); + memset( table_entry->old_$c, 0, + sizeof(table_entry->$c)); + table_entry->${c}_len = + table_entry->old_${c}_len; + @else@ + table_entry->$c = table_entry->old_$c; + table_entry->old_$c = 0; + @end@ + @end@ +@end@ + break; + @end@ + @end@ + } + } + break; + + case MODE_SET_COMMIT: +@if $i.creatable@ + for (request=requests; request; request=request->next) { + table_entry = (struct ${i}_entry *) + netsnmp_tdata_extract_entry(request); +@if $i.rowstatus@ + table_row = netsnmp_tdata_extract_row( request); + table_data = netsnmp_tdata_extract_table(request); +@end@ + table_info = netsnmp_extract_table_info( request); + + switch (table_info->colnum) { +@if $i.rowstatus@ + @foreach $c column@ + @if $c.rowstatus@ + case COLUMN_$c.uc: + switch (*request->requestvb->val.integer) { + case RS_CREATEANDGO: + table_entry->valid = 1; + /* Fall-through */ + case RS_ACTIVE: + table_entry->$c = RS_ACTIVE; + break; + + case RS_CREATEANDWAIT: + table_entry->valid = 1; + /* Fall-through */ + case RS_NOTINSERVICE: + table_entry->$c = RS_NOTINSERVICE; + break; + + case RS_DESTROY: + ${i}_removeEntry(table_data, table_row ); + } + @end@ + @end@ +@else@ + @foreach $c column@ + @if $c.creatable@ + case COLUMN_$c.uc: + @end@ + @end@ + if ( table_entry && !table_entry->valid ) { + table_entry->valid = 1; + } +@end@ + } + } +@end@ + break; +@end@ + } + return SNMP_ERR_NOERROR; +} +@end@ diff --git a/local/pass_persisttest b/local/pass_persisttest new file mode 100644 index 0000000..9fd1deb --- /dev/null +++ b/local/pass_persisttest @@ -0,0 +1,77 @@ +#!/usr/bin/perl + +# Persistant perl script to respond to pass-through smnp requests + +# put the following in your snmpd.conf file to call this script: +# +# pass_persist .1.3.6.1.4.1.2021.255 /path/to/pass_persisttest + +# Forces a buffer flush after every print +$|=1; + +use strict; + +my $counter = 0; +my $place = ".1.3.6.1.4.1.2021.255"; + +while (<>){ + if (m!^PING!){ + print "PONG\n"; + next; + } + + my $cmd = $_; + my $req = <>; + my $ret; + chomp($cmd); + chomp($req); + + if ( $cmd eq "getnext" ) { + if ($req eq $place) { + $ret = "$place.1"; + } elsif ($req eq "$place.1") { + $ret = "$place.2.1"; + } elsif ($req eq "$place.2.1") { + $ret = "$place.2.2"; + } elsif ($req eq "$place.2.2") { + $ret = "$place.3"; + } elsif ($req eq "$place.3") { + $ret = "$place.4"; + } elsif ($req eq "$place.4") { + $ret = "$place.5"; + } elsif ($req eq "$place.5") { + $ret = "$place.6"; + } else { + print "NONE\n"; + next; + } + } else { + if ($req eq $place) { + print "NONE\n"; + next; + } else { + $ret = $req; + } + } + + print "$ret\n"; + + if ($ret eq "$place.1") { + print "string\nlife the universe and everything\n"; + } elsif ($ret eq "$place.2.1") { + print "integer\n423\n"; + } elsif ($ret eq "$place.2.2") { + print "objectid\n.1.3.6.1.4.42.42.42\n"; + } elsif ($ret eq "$place.3") { + print "timeticks\n363136200\n"; + } elsif ($ret eq "$place.4") { + print "ipaddress\n127.0.0.1\n"; + } elsif ($ret eq "$place.5") { + $counter++; + print "counter\n$counter\n"; + } elsif ($ret eq "$place.6") { + print "gauge\n42\n"; + } else { + print "string\nack... $ret $req\n"; + } +} diff --git a/local/passtest b/local/passtest new file mode 100755 index 0000000..9ff65cf --- /dev/null +++ b/local/passtest @@ -0,0 +1,41 @@ +#!/bin/sh -f + +PATH=$path:/bin:/usr/bin:/usr/ucb + +PLACE=".1.3.6.1.4.1.2021.255" +REQ="$2" + +if [ "$1" = "-s" ]; then + echo $* >> /tmp/passtest.log + exit 0 +fi + +if [ "$1" = "-n" ]; then + case "$REQ" in + $PLACE) RET=$PLACE.1 ;; + $PLACE.1) RET=$PLACE.2.1 ;; + $PLACE.2.1) RET=$PLACE.2.2 ;; + $PLACE.2.2) RET=$PLACE.3 ;; + $PLACE.3) RET=$PLACE.4 ;; + $PLACE.4) RET=$PLACE.5 ;; + $PLACE.5) RET=$PLACE.6 ;; + *) exit 0 ;; + esac +else + case "$REQ" in + $PLACE) exit 0 ;; + *) RET=$REQ ;; + esac +fi + +echo "$RET" +case "$RET" in + $PLACE.1) echo "string"; echo "life the universe and everything"; exit 0 ;; + $PLACE.2.1) echo "integer"; echo "42"; exit 0 ;; + $PLACE.2.2) echo "objectid"; echo ".1.3.6.1.4.42.42.42"; exit 0 ;; + $PLACE.3) echo "timeticks"; echo "363136200"; exit 0 ;; + $PLACE.4) echo "ipaddress"; echo "127.0.0.1" ;; + $PLACE.5) echo "counter"; echo "42"; exit 0 ;; + $PLACE.6) echo "gauge"; echo "42"; exit 0 ;; + *) echo "string"; echo "ack... $RET $REQ"; exit 0 ;; +esac diff --git a/local/passtest.pl b/local/passtest.pl new file mode 100755 index 0000000..049cf45 --- /dev/null +++ b/local/passtest.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl +$place = ".1.3.6.1.4.1.8072.2.255"; # NET-SNMP-PASS-MIB::netSnmpPassExamples +$req = $ARGV[1]; # Requested OID + +# +# Process SET requests by simply logging the assigned value +# Note that such "assignments" are not persistent, +# nor is the syntax or requested value validated +# +if ($ARGV[0] eq "-s") { + open LOG,">>/tmp/passtest.log"; + print LOG "@ARGV\n"; + close LOG; + exit 0; +} + +# +# GETNEXT requests - determine next valid instance +# +if ($ARGV[0] eq "-n") { + if (($req eq "$place") || + ($req eq "$place.0") || + ($req =~ m/$place\.0\..*/) || + ($req eq "$place.1")) { $ret = "$place.1.0";} # netSnmpPassString.0 + elsif (($req =~ m/$place\.1\..*/) || + ($req eq "$place.2") || + ($req eq "$place.2.0") || + ($req =~ m/$place\.2\.0\..*/) || + ($req eq "$place.2.1") || + ($req eq "$place.2.1.0") || + ($req =~ m/$place\.2\.1\.0\..*/) || + ($req eq "$place.2.1.1") || + ($req =~ m/$place\.2\.1\.1\..*/) || + ($req eq "$place.2.1.2") || + ($req eq "$place.2.1.2.0")) { $ret = "$place.2.1.2.1";} # netSnmpPassInteger.1 + elsif (($req =~ m/$place\.2\.1\.2\..*/) || + ($req eq "$place.2.1.3") || + ($req eq "$place.2.1.3.0")) { $ret = "$place.2.1.3.1";} # netSnmpPassOID.1 + elsif (($req =~ m/$place\.2\..*/) || + ($req eq "$place.3")) { $ret = "$place.3.0";} # netSnmpPassTimeTicks.0 + elsif (($req =~ m/$place\.3\..*/) || + ($req eq "$place.4")) { $ret = "$place.4.0";} # netSnmpPassIpAddress.0 + elsif (($req =~ m/$place\.4\..*/) || + ($req eq "$place.5")) { $ret = "$place.5.0";} # netSnmpPassCounter.0 + elsif (($req =~ m/$place\.5\..*/) || + ($req eq "$place.6")) { $ret = "$place.6.0";} # netSnmpPassGauge.0 + else {exit 0;} +} +else { +# +# GET requests - check for valid instance +# + if ( ($req eq "$place.1.0") || + ($req eq "$place.2.1.2.1") || + ($req eq "$place.2.1.3.1") || + ($req eq "$place.3.0") || + ($req eq "$place.3.0") || + ($req eq "$place.3.0") || + ($req eq "$place.3.0")) { $ret = $req; } + else { exit 0;} +} + +# +# "Process" GET* requests - return hard-coded value +# +print "$ret\n"; + if ($ret eq "$place.1.0") { print "string\nLife, the Universe, and Everything\n"; exit 0;} +elsif ($ret eq "$place.2.1.2.1") { print "integer\n42\n"; exit 0;} +elsif ($ret eq "$place.2.1.3.1") { print "objectid\n.1.3.6.1.4.42.42.42\n"; exit 0;} +elsif ($ret eq "$place.3.0") { print "timeticks\n363136200\n"; exit 0;} +elsif ($ret eq "$place.4.0") { print "ipaddress\n127.0.0.1\n"; exit 0;} +elsif ($ret eq "$place.5.0") { print "counter\n42\n"; exit 0;} +elsif ($ret eq "$place.6.0") { print "gauge\n42\n"; exit 0;} +else { print "string\nack... $ret $req\n"; exit 0;} # Should not happen diff --git a/local/snmp-ucd.sh b/local/snmp-ucd.sh new file mode 100755 index 0000000..7d16b74 --- /dev/null +++ b/local/snmp-ucd.sh @@ -0,0 +1,187 @@ +#!/bin/sh +# +# snmpd-ucd.sh +# +# Start UCD SNMP daemon and trap catcher. Backup the log file *first* +# since currently the daemon truncates and overwrites any pre-existing file. +# +# killproc() and pidofproc() lifted from Linux's /etc/init.d/functions. +# +# NOTE: Solaris users must uncomment the proper PSARGS definition below. XXX +# + +USAGE="Usage: `basename $0` start|stop|restart" + + + +#------------------------------------ -o- +# Globals. +# +DAEMONLOG=/var/log/snmpd.log + TRAPLOG=/var/log/snmptrapd.log + LOGDIR=/var/log/SNMPDLOGS + +D=".`date '+%h%d_%H%M' | sed 's/\([a-z]\)0/\1/' | tr 'A-Z' 'a-z'`" + +PSARGS=auwwx +#PSARGS=-ef # Solaris. + +DEBUGFLAG= # -D # Toggles use of debugging + + + + +#------------------------------------ -o- +# Function definitions. +# +killproc() { # [signal] + base= + killlevel="-9" + notset=1 + pid= + + + # + # Parse. + # + [ $# = 0 ] && { + echo "`basename $0`: Wrong arguments to killproc()." 1>&2 + return 1 + } + base="`basename $1`" + [ -n "$2" ] && { + killlevel=$2 + notset=0 + } + + + # + # Kill process. + # + pid=`pidofproc $base 2>/dev/null` + [ -z "$pid" ] && { + pid=`ps $PSARGS | egrep $base | egrep -v egrep | egrep -v $0 | awk '{ print $2 }'`; + } + [ -z "$pid" ] && { + echo "`basename $0`: killproc: Could not find process ID." + } + + [ -n "$pid" ] && { + echo -n "$base " + + # + # Kill with -TERM then -KILL by default. Use given + # instead if one was passed in. + # + [ "$notset" = 1 ] && { + kill -TERM $pid + sleep 1 + + [ -n "`ps $PSARGS | + awk '{print $2}' | grep $pid`" ] && { + sleep 3 + kill -KILL $pid + } + + true + } || { + kill $killlevel $pid + } + } + + rm -f /var/run/$base.pid + +} # end killproc() + + +pidofproc() { # + pid= + + [ $# = 0 ] && { + echo "`basename $0`: Wrong argument to pidofproc()." 1>&2 + return 1 + } + + # + # Try looking for a /var/run file. + # + [ -f /var/run/$1.pid ] && { + pid=`head -1 /var/run/$1.pid` + + [ -n "$pid" ] && { + echo $pid + return 0 + } + } + + # + # Try pidof. (Linux offering.) + # + pid=`pidof $1` + [ -n "$pid" ] && { + echo $pid + return 0 + } + + # + # Try ps. + # + ps $PSARGS | awk ' BEGIN { prog=ARGV[1]; ARGC=1 } + { if ((prog == $11) || + (("(" prog ")") == $11) || + ((prog ":") == $11)) + { + print $2 + } + }' $1 +} # end pidofproc() + + + +#------------------------------------ -o- +# Action. +# +case "$1" in + start) + echo "Starting SNMP. " + + cp $DAEMONLOG ${DAEMONLOG}$D + cp $TRAPLOG ${TRAPLOG}$D + cat /dev/null >$TRAPLOG + + [ ! -e $LOGDIR ] && mkdir $LOGDIR + mv ${DAEMONLOG}$D ${TRAPLOG}$D $LOGDIR + gzip -r $LOGDIR 2>/dev/null & + + snmpd -a -d -V $DEBUGFLAG + snmptrapd -Lf "$TRAPLOG" + + echo + ;; + + stop) + echo -n "Shutting down SNMP: " + + killproc snmpd + killproc snmptrapd + + echo + ;; + + restart) + $0 stop + $0 start + ;; + + *) + echo $USAGE 1>&2 + exit 1 +esac + + + +#------------------------------------ -o- +# +exit 0 + + diff --git a/local/snmpcheck.def b/local/snmpcheck.def new file mode 100755 index 0000000..84997ef --- /dev/null +++ b/local/snmpcheck.def @@ -0,0 +1,1224 @@ +#!/usr/local/bin/perl -w + +use strict 'refs'; +require Net::Ping; +require Term::ReadKey; + +#defaults +$mibident=".ERRORNAME"; +$miberrflag=".ERRORFLAG"; +$miberrmsg=".ERRORMSG"; +$mibfix=".ERRORFIX"; +$mibheadall=".EXTENSIBLEDOTMIB"; +$mibclearcache="$mibheadall.VERSIONMIBNUM.VERCLEARCACHE"; +$mibrestartagent="$mibheadall.VERSIONMIBNUM.VERRESTARTAGENT"; +$mibupdateconfig="$mibheadall.VERSIONMIBNUM.VERUPDATECONFIG"; +%miblist=( '.PROCMIBNUM.1' => 'processes', + '.SHELLMIBNUM.1' => 'scripts', + '.MEMMIBNUM' => 'swap space', + '.DISKMIBNUM.1' => 'disks', + '.LOADAVEMIBNUM.1' => 'load-average', + '.ERRORMIBNUM' => 'snmp-agent-errors'); +@fixitlist=('.PROCMIBNUM.1','.SHELLMIBNUM.1'); +%mibchecklist = ('.PROCMIBNUM.1' => 1, + '.SHELLMIBNUM.1' => 1, + '.MEMMIBNUM' => 1, + '.DISKMIBNUM.1' => 1, + '.LOADAVEMIBNUM.1' => 1, + '.ERRORMIBNUM' => 1); +$errlog="/net/tyfon/1/OV/log/ece-log"; +$default_get_args = "-v 1 %s private"; +$default_set_args = "-v 1 %s private"; +$andlog=0; +$snmppath="BINDIR"; +$eraseline=" \r"; +$fixit=0; # this should be 0 not -1, but is necissary till getc(STDIN) works +$rescanWhen = 300; +$display = $ENV{'DISPLAY'}; +$hidden = 0; +$pinghost = 0; +$loglevel = 1; +$logwindowatstart = 0; +$numloglevels = 5; +$dontstart = 0; +$raiseonnew = 1; + +# +# Mib Package: Each mib has a mib number attached and can check/fix itself; +# + +package Mib; + +# @ISA = qw( Host ); + +sub new { + my $tmp = shift; + my $self = {}; + $self->{'HostId'} = shift; + $self->{'Host'} = $self->{'HostId'}->{'Name'}; + $_ = shift; + $self->{'Mib'} = $_; + print "test: $_\n"; + ($self->{'MibSuffix'}) = /(\.[0-9]+)$/; + if (!defined($mibchecklist{$self->{'MibSuffix'}})) { + ($self->{'MibSuffix'}) = /(\.[0-9]+\.1)$/; + } + print "suff: $self->{'MibSuffix'}\n"; + $self->{'MibDesc'} = shift; + $self->{'Frame'} = shift; + bless $self; +} + +sub getmibnum { + my $self = shift; + return ($self->{'Mib'}); +} + +sub snmp_walk { + my $self = shift; + $self->{'Frame'}->toplevel->Busy() if ($::display); + my $mib = shift; + my $cmd = "$::snmppath/snmpwalk " . sprintf($::default_get_args, $self->{'Host'}) . " $mib|"; + ::addToLog("running: $cmd",5); + open(OUT,"$cmd"); + my $outcount = 0; + my @result = []; + while () { + $result[$outcount] = $_; + chop; + ::addToLog("snmpwalk: $_",5); + if ($::display) { + $self->{'Frame'}->toplevel->update; + } + $outcount++; + } + close(OUT); + for($i=0; $i <= $#result; $i++) { + $result[$i] =~ s/ Hex:.*$//g; + $result[$i] =~ s/\"//g; + } + $self->{'Frame'}->toplevel->Unbusy() if ($::display); + if ($result[0] =~ /No Response/) { + $self->{'HostId'}->hostdown; + splice(@result,0); + } + return @result; +} + +sub check { + my $self = shift; + my $tmp = []; + if ($::mibchecklist{$self->{'MibSuffix'}} != 1) { + return @{$tmp}; + } + if (! $::display) { + printf "%sChecking %s: %s\r", $::eraseline,$self->{'Host'}, + $self->{'MibDesc'}; + } + my @walkout = $self->snmp_walk("$self->{'Mib'}$::miberrflag"); + while ($#walkout > -1) { + $_ = shift @walkout; + ($result) = /= ([0-9]+)/; + if (defined($result) && $result > 0) + { + ($mibloc) = /\.([0-9]+) /; + push(@{$tmp},FixProblem::new("",$self->{'HostId'}, $self->{'Mib'}, + $self->{'MibDesc'}, + $mibloc,$self->{'Frame'})); + if (! $::display) { + printf("%s%-8.8s %-12.12s %2d -- %-37.37s",$::eraseline, + $self->{'Host'},$tmp->[0]->{'ErrName'}, + $result,$tmp->[0]->{'ErrMsg'}); + if ($tmp->[0]->canfix() && $::fixit == 0) { + printf(" / Fix? "); + $ans = Term::ReadKey::ReadKey(0); + if ("$ans" eq "y" || "$ans" eq "Y") { + printf("\b\b\b\b\b\b\b\b"); + $tmp->[0]->fix($mibloc); # fix now if curses + } else { + print $ans; + printf("\nChecking %s: %s\r",$self->{'Host'}, + $self->{'MibDesc'}); + } + } elsif ($::fixit > 0) { + $tmp->[0]->fix($mibloc); # fix now if curses + } + shift @{$tmp}; + } + } + } + return(@{$tmp}); +} + +# +# Problem Package: A problem comes into existence when found. It may +# or may not know how to fix itself (Problem/FixProblem). +# + +package Problem; + +@ISA = qw( Mib ); + +sub snmp_get { + my $self = shift; + $self->{'Frame'}->toplevel->Busy() if ($::display); + my $mib = shift; + my $args = sprintf($::default_get_args, $self->{'Host'}); + $_ = `$::snmppath/snmpget $args $mib`; + my ($result) = /= (.*)$/; + if (!defined($result) || $result =~ /No Response/) { + $self->{'HostId'}->hostdown; + $result = ""; + } + $result =~ s/\"//g; + $result =~ s/ Hex:.*$//g; + ::addToLog("snmpget: $_",5); + $self->{'Frame'}->toplevel->Unbusy() if ($::display); + return $result; +} + +sub snmp_set { + my $self = shift; + $self->{'Frame'}->toplevel->Busy() if ($::display); + my $mib = shift; + my $args = sprint($::default_set_args, $self->{'Host'}); + $_ = `$::snmppath/snmpset $args $mib`; + my ($result) = /= (.*)$/; + $result = "" if (!defined($result)); + $result =~ s/\"//g; + ::addToLog("snmpset: $_",5); + $self->{'Frame'}->toplevel->Unbusy() if ($::display); + return $result; +} + +sub new{ + my $tmp = shift; + my $hostId = shift; + my $mib = shift; + my $mibname = shift; + my $self = new Mib ($hostId,$mib,$mibname); + $self->{'MibLocation'} = shift; + $tmp = shift; + if ($::display) { + $self->{'Frame'} = $tmp->Frame(); + } + bless $self; + $self->{'ErrName'} = + $self->snmp_get("$self->{'Mib'}$::mibident.$self->{'MibLocation'}"); + $self->{'ErrMsg'} = + $self->snmp_get("$self->{'Mib'}$::miberrmsg.$self->{'MibLocation'}"); + if (exists $self->{'HostId'}->{'Down'}) { + return $self; + } + if ($::display) { + $self->{'Frame'}->pack(); + $self->{'Desc'} = + $self->{'Frame'}->Button(-text => sprintf("%-12.12s %-42.42s", + $self->{'ErrName'}, + $self->{'ErrMsg'}), + -font => "6x13", + -highlightcolor => "#ffffff", + -borderwidth => 0, + -relief => "flat", + -bd => 0, -padx => 0, -pady => 0, + -activeforeground => 'red', + -activebackground => '#C9C9C9', + -background => '#E0C9C9', + -command => [\&selectme,$self]); + $self->{'Desc'}->pack(-fill => "x",-expand => 1,-side=>"left"); # + if ($::raiseonnew) { + $tmp->toplevel->deiconify(); + $tmp->toplevel->raise(); + } + ::addToLog("problem found: $self->{'Host'}\t$self->{'ErrName'}\t$self->{'ErrMsg'}",2); + } + bless $self; + return $self; +} + +sub haveseen { + my $self = shift; + $self->{'Desc'}->configure(-background => '#C9C9C9'); +} + +sub selectme { + my $self = shift; + if ($main::hidden) { + main::makeappear(); + return; + } + if (exists $self->{'Selected'}) { + main::deselectitem($self); + delete $self->{'Selected'}; + } else { + main::selectitem($self); + $self->{'Desc'}->configure(-foreground => "red"); + $self->{'Selected'} = 1; + } + $self->haveseen(); +} + +sub deselectme { + my $self = shift; + $self->{'Desc'}->configure(-foreground => "black"); + delete $self->{'Selected'}; +} + +sub check { + my $self = shift; + if ($::display) { + main::setstatus("Checking $self->{'Host'} -- $self->{'ErrName'}"); + } + else { + printf("Checking \b\b\b\b\b\b\b\b\b"); + } + $result = $self->snmp_get("$self->{'Mib'}$::miberrflag.$self->{'MibLocation'}"); + if (exists $self->{'HostId'}->{'Down'}) { + return 0; + } + if ($result == 0) { + $self->deleteme(); + } + main::setstatus("idle"); + return $result; +} + +sub fix { +# Don't fix and/or unable to + my $self = shift; + main::setmsg("Don't know how to fix $self->{'ErrName'}"); +} + +sub rsh { + my $self = shift; + if ($::display) { + system "xterm -e rsh $self->{'HostId'}->{'Name'} -l root &"; + } +} + +sub deleteme { + my $self = shift; + my $host = $self->{'HostId'}; + $host->deleteProb($self); +} + +sub deleteself { + my $self = shift; + if ($::display) { + if ($self->{'Selected'}) { + main::deselectitem($self); + } + $self->{'Desc'}->destroy(); + $self->{'Frame'}->destroy(); + } +} + +sub canfix { + return 0; +} + +package FixProblem; + +@ISA = qw( Problem ); + +sub new { + my $tmp = shift; + my $hostId = shift; + my $mib = shift; + my $mibdesc = shift; + my $mibloc = shift; + my $frame = shift; + my $self = new Problem ($hostId,$mib,$mibdesc,$mibloc,$frame); + $_ = $mib; + ($mymib) = /(\.[0-9]+)$/; + if (grep(/$mymib/,@::fixitlist) && ($::fixit >= 0)) { + bless $self; # Make it a FixProblem if fixable + } + return $self; # else just return a Problem +} + +sub canfix { + return 1; +} + +sub fix { + my $self = shift; + my $mibloc = shift; + if ($::display) { + main::setstatus(sprintf("Fixing %s: %s", + $self->{'Host'}, $self->{'ErrName'})); + } + else { + printf(" / Fixing...\b\b\b\b\b\b\b\b\b"); + } + $self->snmp_set("$self->{'Mib'}$::mibfix.$self->{'MibLocation'} integer 1"); + $self->snmp_set("$::mibclearcache integer 1"); + if (exists $self->{'HostId'}->{'Down'}) { + return; + } + if ($::display) { + main::setstatus("Sleeping"); + } + else { + printf("Sleeping \b\b\b\b\b\b\b\b\b"); + } + sleep(2); + if ($::display) { + main::setstatus("Checking"); + } + else { + printf("Checking\b\b\b\b\b\b\b\b"); + } + if ($self->check() != 0) { + if (! $::display) { + printf("*failed* \n"); + } else { + main::setmsg("Failed to fix $self->{'ErrName'} on $self->{'Host'}"); + } + } + else { + if ($::display) { +# $self->{'HostId'}->deleteProb($self); + main::setmsg("Fixed $self->{'ErrName'} on $self->{'Host'}"); + } + else { + printf("Fixed \n"); + } + } + main::setstatus("Idle"); +} + +# +# Host Package: Each object is a host which can check itself and display +# the results +# +package Host; + +sub mibsort { + $_ = $a; + ($av) = /\.([0-9]+)/; + $_ = $b; + ($bv) = /\.([0-9]+)/; + return $av <=> $bv; +} + +sub new { + my $self = {}; + my $tmp = shift; + $self->{'Name'} = shift; + $self->{'Host'} = $self->{'Name'}; + $self->{'Mibs'} = []; + $self->{'Problems'} = []; + bless $self; + if ($::display) { + $self->{'MainFrame'} = $::HostFrame->Frame(); + if (!$::hidden) { + $self->{'MainFrame'}->configure(-relief =>"sunken",-borderwidth=>2); + } + $self->{'ProbFrame'} = $self->{'MainFrame'}->Frame(); + $self->{'hostlabel'} = + $self->{'MainFrame'}->Button(-text => sprintf("%-9.9s", + $self->{'Name'}), + -bd => 0, -padx => 0, -pady => 0, + -command =>[\&selectme,$self], + -activeforeground => 'red', + -activebackground => '#C9C9C9', + -width => 9, + -anchor => "w", + -relief => "flat"); + $self->{'hostlabel'}->pack(-side=>"left",-ipadx=>1, + -padx=> 1,-pady =>1); + $self->{'ProbFrame'}->pack(-side=>"left",-ipadx=>1, + -padx=> 1,-pady =>1); + $self->{'MainFrame'}->pack( #-padx => 2,-pady =>2, + -fill => "x", -expand => 1); + } + foreach $mibx ( sort mibsort keys(%::miblist) ) { + push(@{$self->{'Mibs'}}, + new Mib ($self,"$::mibheadall$mibx",$::miblist{$mibx}, + $self->{'ProbFrame'})); + } + return $self; +} + +sub rsh { + my $self = shift; + if ($::display) { + system "xterm -e rsh $self->{'Name'} -l root &"; + } +} + +sub selectme { + my $self = shift; + if ($main::hidden) { + main::makeappear(); + return; + } + if (exists $self->{'Selected'}) { + main::deselectitem($self); + delete $self->{'Selected'}; + } else { + main::selectitem($self); + $self->{'hostlabel'}->configure(-foreground => "red"); + $self->{'Selected'} = 1; + } +} + +sub deselectme { + my $self = shift; + $self->{'hostlabel'}->configure(-foreground => "black"); + delete $self->{'Selected'}; +} + +sub fix { + my $self = shift; + if (! exists $self->{'Down'}) { + foreach $i (@{$self->{'Problems'}}) { + if ($i->canfix() && ref($i) ne Host) { + $i->fix(); + } + } + } +} + +sub seenall { + my $self = shift; + foreach $i (@{$self->{'Problems'}}) { + if (ref($i) ne Host) { + $i->haveseen(); + } + } +} + +sub canfix { + return 1; +} + +sub hostdown { + my $self = shift; + $self->deleteProbs(); + push(@{$self->{'Problems'}},$self); + $self->{'Down'} = 1; + if ($::display) { + if (!exists $self->{'hostlabel'}) { + $self->{'hostlabel'} = + $self->{'MainFrame'}->Button(-text => sprintf("%-9.9s", + $self->{'Name'}), + -bd => 0, -padx => 0, -pady => 0, + -command =>[\&selectme,$self], + -activeforeground => 'red', + -activebackground => '#C9C9C9', + -width => 9, + -anchor => "w", + -relief => "flat"); + } + ::addToLog("$self->{'Name'} is down",2); + $self->{'hostlabel'}->configure(-text => + sprintf("%-9.9s down",$self->{'Name'}), + -width => 14); + } +} + +sub check { + my $self = shift; + $self->{'noDelete'} = 1; + $self->deleteProbs(); + delete $self->{'noDelete'}; + if ($::display) { + $self->{'hostlabel'}->configure(-text => $self->{'Name'},-width=>9); + } + delete $self->{'Down'}; + main::setstatus("pinging $self->{'Name'}"); + if (!($::pinghost) || Net::Ping::pingecho($self->{'Name'},2)) { + foreach $i (@{$self->{'Mibs'}}) { + if (ref($i) ne Mib) { + print "$i is a ref($i) not a Mib\n"; + } else { + main::setstatus("Checking $self->{'Name'}: " . $i->{'MibDesc'}); + push(@{$self->{'Problems'}},$i->check()); + } + if (exists $self->{'Down'}) { + last; + } + } + } else { + $self->hostdown(); + } + main::setstatus("Idle"); + if ($#{$self->{'Problems'}} == -1) { + $self->deleteme(); + } +} + +sub deleteme { + my $self = shift; + if ($self->{'Selected'}) { + main::deselectitem($self); + } + $self->deleteProbs(); + if ($::display) { + $self->{'hostlabel'}->destroy(); + $self->{'ProbFrame'}->destroy(); + my $top = $self->{'MainFrame'}->toplevel; + $self->{'MainFrame'}->destroy(); + $top->update; + } + main::deletehost($self->{'Name'}); +} + +sub deleteProbs { + my $self = shift; + foreach $i (@{$self->{'Problems'}}) { + if (ref($i) eq Host) { + delete $self->{'Problems'}; + return; + } + if (ref($i) ne Problem && ref($i) ne FixProblem) { + print "i: $i is a ", ref($i), "\n"; + next; + } + $self->deleteProb($i); + } +} + +sub deleteProb { + my $self = shift; + my $child = shift; + for ($k = 0; $k <= $#{$self->{'Problems'}}; $k++) { + if (ref($self->{'Problems'}->[$k]) eq Problem || + ref($self->{'Problems'}->[$k]) eq FixProblem ) { + if ($self->{'Problems'}->[$k]->{'Mib'} eq $child->{'Mib'} && + $self->{'Problems'}->[$k]->{'MibLocation'} eq + $child->{'MibLocation'}) { + splice(@{$self->{'Problems'}},$k,1); + $child->deleteself(); + if ($#{$self->{'Problems'}} == -1 && + !exists $self->{'noDelete'}) { + $self->deleteme(); + } + last; + } + } else { + print " not: ",$self->{'Problems'}->[$k],"/", + ref($self->{'Problems'}->[$k]),"\n"; + } + } +} + +package main; + +# +# Read arguments +# + +if ($#ARGV != -1) { + while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) { + $_ = shift; + $andlog = 1 if (/^-a/); + $dontstart = 1 if (/^-d/); + $fixit = -1 if (/^-n/); + $fixit = 1 if (/^-y/); + $display = 0 if (/^-x/); + $pinghost = 1 if (/^-p/); + $hidden = 1 if (/^-H/); + $loglevel = shift if (/^-V/); + $logwindowatstart = 1 if (/^-L/); + &display_help() if (/^-h/); + &setmibchecklist(@fixitlist) if (/^-f/); + } +} + +# +# If necessary check the ece-log file for problems +# + +if (($andlog || $#ARGV == -1) && !$dontstart) { + open(LOG,$errlog); + while () { + @fields = split; + @tmp = grep(/$fields[0]/,@ARGV); + if ($#tmp == -1) { # && $fields[1] ne "down") { + $ARGV[$#ARGV + 1] = $fields[0]; + } + } + close(LOG); +} + +# +# Check all the found hosts +# + +if ($display) { + use Tk; +# $tk_strictMotif = 1; + $top = MainWindow->new(); + $top->bind('all',"",[\&quit]); + $top->bind('all',"",[\&makehidden]); + $top->bind('all',"",[\&seenall]); + $top->bind('all',"",[\&fixall]); + $top->option('add','*highlightThickness','0'); #wish this worked +# $top->option('add','*highlightbackground','#C9C9C9'); + $top->option('add','*background','#C9C9C9'); + $top->option('add','*font','6x13'); + $HostFrame = $top->Frame(); + $MenuFrame = $top->Frame(-relief => "raised",-borderwidth => 2); + $MenuFrame->pack(-fill => "x",-expand => 1); + $statusBar = $top->Frame(-relief => "raised",-borderwidth => 2); + $status = $statusBar->Label(-text => "initializing",-anchor =>"e"); + $statusl = $statusBar->Label(-text => "Status: ", -anchor => "w"); + $msgBar = $top->Frame(-relief => "raised",-borderwidth => 2); + $msg = $msgBar->Label(-text => "",-anchor =>"e"); + $msgl = $msgBar->Label(-text => "Note: ", -anchor => "w"); + + $botFrame = $top->Frame(); + $butFrame = $top->Frame(); + $entryhost = ""; + $NewHost = $botFrame->Entry(-textvariable => \$entryhost,-width=>20, + -relief => "sunken"); + $NewHost->bind("",sub {newHost("$entryhost"); + $NewHost->delete(0,length($entryhost));}); + $BotLabel = $botFrame->Label(-text => "Check New Host: ", + -anchor => "w"); + $CmdsMenuBut = $MenuFrame->Menubutton(-text => "Cmds"); + $CmdsMenu = $CmdsMenuBut->Menu(-tearoff => 1); + $CmdsMenuBut->configure(-menu => $CmdsMenu); + $CmdsMenuBut->pack(-side => "left"); + $CmdsMenuBut->command(-label => "Check Hosts", -command => [\&rescanhosts]); + $CmdsMenuBut->command(-label => "Check Log", -command => [\&scanlog]); + $CmdsMenuBut->command(-label => "Fix All", -command => [\&fixall], + -accelerator => "Ctrl-f"); + $CmdsMenuBut->command(-label => "Seen All", -command => [\&seenall], + -accelerator => "Ctrl-s"); + $CmdsMenuBut->separator(); + $CmdsMenuBut->command(-label => "Hide", -command => [\&makehidden], + -accelerator => "Ctrl-h"); + $CmdsMenuBut->command(-label => "Quit", -command => [\&quit], + -accelerator => "Ctrl-q"); + $PrefsMenuBut = $MenuFrame->Menubutton(-text => "Prefs"); + $PrefsMenu = $PrefsMenuBut->Menu(-tearoff => 1); + $PrefsMenuBut->configure(-menu => $PrefsMenu); + $PrefsMenuBut->pack(-side => "left"); + $PrefsMenuBut->cascade(-label => "Rescan"); + $RescanPrefsBut = $PrefsMenu->Menu(); + $PrefsMenuBut->entryconfigure("Rescan",-menu => $RescanPrefsBut); + $AutoRescan = 1; + if ($AutoRescan) { + $afterId = Tk::after($rescanWhen*1000,[\&autorescan]); + } + $RescanPrefsBut->checkbutton(-label =>"Auto Rescan", + -variable =>\$AutoRescan, + -command => sub {if ($AutoRescan) { + $afterId = + Tk::after($rescanWhen*1000,[\&autorescan]) + } else { + Tk::after("cancel",$afterId); + }}); + $AutoCheckLog = 1; + $RescanPrefsBut->checkbutton(-label =>"Checks Log", + -variable =>\$AutoCheckLog); + $AutoCheckHosts = 0; + $RescanPrefsBut->checkbutton(-label =>"Checks Hosts", + -variable =>\$AutoCheckHosts); + $RescanWhenHidden = 1; + $RescanPrefsBut->checkbutton(-label =>"Only When Hidden", + -variable =>\$RescanWhenHidden); + + $RescanPrefsBut->checkbutton(-label =>"Pop forward with new", + -variable =>\$raiseonnew); + + $PrefsMenuBut->cascade(-label => "Log Verbosity"); + $LogVerbBut = $PrefsMenu->Menu(); + $PrefsMenuBut->entryconfigure("Log Verbosity", + -menu => $LogVerbBut); + for ($i=1; $i <= $numloglevels; $i++) { + $LogVerbBut->radiobutton(-label => "$i", -variable => \$loglevel, + -value => $i); + } + + $PrefsMenuBut->cascade(-label => "Check For"); + $CheckForBut = $PrefsMenu->Menu(); + $PrefsMenuBut->entryconfigure("Check For", + -menu => $CheckForBut); + $CheckForBut->command(-label => "Fixable Problems", + -command => [\&setmibchecklist,@fixitlist]); + $CheckForBut->command(-label => "Everything", + -command => [\&setmibchecklist,keys(%miblist)]); + $CheckForBut->separator(); + foreach $i ( sort mibsort keys(%::mibchecklist) ) { + $CheckForBut->checkbutton(-label => $miblist{$i}, + -variable => \$mibchecklist{$i}); + } + + $PrefsMenuBut->checkbutton(-label => "Ping Host First", + -variable => \$pinghost); + + # Agent control + + $agentMenuBut = $MenuFrame->Menubutton(-text => "Agent-Control"); + $agentMenu = $agentMenuBut->Menu(-tearoff => 1); + $agentMenuBut->configure(-menu => $agentMenu); + $agentMenuBut->pack(-side => "left"); + $agentMenuBut->command(-label => "Re-read Configuration", + -command => [sub {if ($selected) { $top->Busy(); + my $args = sprint($::default_get_args, $selected->{'Host'}); +$_ = `$::snmppath/snmpset $args $mibupdateconfig i 1`; $top->Unbusy();}}]); + $agentMenuBut->command(-label => "Clear Exec Cache", + -command => [sub {if ($selected) { $top->Busy(); + my $args = sprint($::default_get_args, $selected->{'Host'}); +$_ = `$::snmppath/snmpset $args $mibclearcache i 1`; $top->Unbusy();}}]); + $agentMenuBut->separator(); + $agentMenuBut->command(-label => "Re-start Agent", + -command => [sub {if ($selected) { $top->Busy(); + my $args = sprint($::default_get_args, $selected->{'Host'}); +$_ = `$::snmppath/snmpset $args $mibrestartagent i 1`; $top->Unbusy();} }]); + + # set up remote commands + + $remoteMenuBut = $MenuFrame->Menubutton(-text => "Remote-Info"); + $remoteMenu = $remoteMenuBut->Menu(-tearoff => 1); + $remoteMenuBut->configure(-menu => $remoteMenu); + $remoteMenuBut->pack(-side => "left"); + $remoteMenuBut->command(-label => "Load-Av", -command => [\&remote_load]); + $remoteMenuBut->separator(); + $remoteMenuBut->command(-label => "top", -command => [\&remote_cmd,"top"]); + $remoteMenuBut->command(-label => "mailq", -command => [\&remote_cmd,"mailq"]); + $remoteMenuBut->command(-label => "ps", -command => [\&remote_cmd,"ps"]); + $remoteMenuBut->command(-label => "conf", -command => [\&remote_cmd,"conf"]); + + # set up log file menu + $logFileMenuBut = $MenuFrame->Menubutton(-text => "Log"); + $logFileMenu = $logFileMenuBut->Menu(-tearoff => 1); + $logFileMenuBut->configure(-menu => $logFileMenu); + $logFileMenuBut->pack(-side => "left"); + $logFileMenuBut->command(-label => "show log", -command => [\&displayLog]); + $logFileMenuBut->command(-label => "clear log", -command => [\&clearLog]); + $logFileMenuBut->separator(); + $logFileMenuBut->command(-label => "show Tyfon's log", -command => [\&displayTyfon]); + + + # set up status bar + + $statusl->pack(-fill => "x", -expand => 1, -side =>"left"); + $status->pack(-fill => "x", -expand => 1, -side =>"left"); + $msgl->pack(-fill => "x", -expand => 1, -side => "left"); + $msg->pack(-fill => "x", -expand => 1, -side => "left"); + $statusBar->pack(-fill => "x", -expand => 1); + $msgBar->pack(-fill => "x", -expand => 1); + $HostFrame->pack(-fill => "x",-expand => 1); + $butFrame->pack(-fill => "x",-expand => 1); + $botFrame->pack(-fill => "x",-expand => 1); + $FixBut = $butFrame->Button(-text => "Fix",-command=>[sub{print "hi\n"}], + -state => "disabled"); + $FixBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2, + -ipady => 2); + $RshBut = $butFrame->Button(-text => "Rsh",-command=>[sub{print "hi\n"}], + -state => "disabled"); + $RshBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2, + -ipady => 2); + $DelBut = $butFrame->Button(-text => "Del", + -state => "disabled"); + $DelBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2, + -ipady => 2); + $ChkBut = $butFrame->Button(-text => "Chk", + -state => "disabled"); + $ChkBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2, + -ipady => 2); + $BotLabel->pack(-fill => "x",-expand => 1,-side=>"left"); + $NewHost->pack(-side=>"left"); + &makehidden() if ($hidden); + $top->update(); + + # generate log window, but tell it not to create display + $logwindow = MainWindow->new; + $logwindow->option('add','*highlightThickness','0'); #wish this worked +# $logwindow->option('add','*highlightbackground','#C9C9C9'); + $logwindow->option('add','*background','#C9C9C9'); + $logwindow->option('add','*font','6x13'); + + $logbuttons = $logwindow->Frame; + $logbuttons->pack(-side => 'bottom', -expand => 1, -fill => 'x'); + $logclose = $logbuttons->Button(-text => 'Close', + -command => ['withdraw',$logwindow]); + $logclose->pack(-side => 'left', -expand => 1); + + $logtext = $logwindow->Text(-height => 40, -setgrid => 1); + $logtext->pack(-side => 'left', -fill => 'both', -expand => 1); + $logscroll = $logwindow->Scrollbar(-command => ['yview',$logtext]); + $logscroll->pack(-side => 'right', -fill => 'y'); + $logtext->configure(-yscrollcommand => ['set', $logscroll]); + $logwindow->title("snmpcheck Action Log file"); + $logwindow->iconname("snmpcheck-log"); + $logtext->delete('1.0','end'); + $logclear = $logbuttons->Button(-text => 'Clear Log', + -command => [\&deleteLog]); + $logclear->pack(-side => 'right', -expand => 1); + if (! $logwindowatstart) { + $logwindow->withdraw; + } + + $status->configure(-text => "Idle"); + $selected = 0; + # fill table with hosts + if (!$dontstart) { + loadAllHosts(@ARGV); + } + MainLoop; +} +else { + select(STDOUT); + $| = 1; + if ($::fixit == 0) { + Term::ReadKey::ReadMode(3); + } + loadAllHosts(@ARGV); + printf("$eraseline"); +} + +sub loadAllHosts { + my @hostlist = @_; + foreach $host ( @hostlist ) { + newHost($host); + } +} + +sub newHost { + my $name = shift; + if (!exists $chost{"$name"}) { + $chost{"$name"} = new Host ($name); + if ($::display) { $top->update(); } + $chost{"$name"}->check; + } else { + setmsg("$name all ready exists"); + } +} + +sub deletehost { + my $name = shift; + delete $chost{"$name"}; +} + +sub setstatus { + my $arg = shift; + if ($display) { + $status->configure(-text => $arg); + $top->update(); + addToLog($arg,4); + } +} + +sub setmsg { + my $arg = shift; + if ($display) { + $msg->configure(-text => $arg); + $top->update(); + addToLog($arg); + } +} + +sub addToLog { + if ($display) { + my $logmsg = shift; + my $logaddlevel = shift; + if (! defined($logaddlevel)) { + $logaddlevel = 1; + } + if ($logaddlevel <= $loglevel) { + $logtext->insert('end'," " x ($logaddlevel-1) . "$logmsg\n"); + } + } +} + +sub displayTyfon { + remote_cmd_generic("cat /net/tyfon/1/OV/log/ece-log","Tyfon -- ece-log"); +} + +sub displayLog { + $logwindow->deiconify; + $logwindow->raise; +} + +sub deleteLog { + $logtext->delete('1.0','end'); +} + +sub deselectitem { + $obj = shift; + $obj->deselectme(); + $FixBut->configure(-state => "disabled"); + $RshBut->configure(-state => "disabled"); + $DelBut->configure(-state => "disabled"); + $ChkBut->configure(-state => "disabled"); + $selected = 0; +} + +sub selectitem { + if ($selected) { + $selected->deselectme(); + } + $selected = shift; + if (ref($selected) ne Host || !(exists $selected->{'Down'})) { + $RshBut->configure(-state => "normal", -command => ['rsh',$selected]); + } else { + $RshBut->configure(-state => "disabled"); + } + $DelBut->configure(-state => "normal", -command => ['deleteme',$selected]); + $ChkBut->configure(-state => "normal", -command => ['check',$selected]); + if ($selected->canfix() && !(exists $selected->{'Down'})) { + $FixBut->configure(-state => "normal", + -command => ['fix',$selected]); + } else { + $FixBut->configure(-state => "disabled"); + } + if ($hidden == 1) { + makeappear(); + } +} + +sub makehidden { + $MenuFrame->pack("forget"); + $statusBar->pack("forget"); + $msgBar->pack("forget"); + $butFrame->pack("forget"); + $botFrame->pack("forget"); + flatten(); + $hidden=1; +} + +sub makeappear { + $HostFrame->pack("forget"); + $MenuFrame->pack(-expand => 1, -fill => "x"); + $statusBar->pack(-expand => 1, -fill => "x"); + $msgBar->pack(-expand => 1, -fill => "x"); + $HostFrame->pack(-expand => 1, -fill => "x"); + $butFrame->pack(-expand => 1, -fill => "x"); + $botFrame->pack(-expand => 1, -fill => "x"); + reliefen(); + $hidden=0; +} + +sub quit { + $top->destroy(); + exit(); +} + +sub scanlog { + my (@fields, @tmp); + open(LOG,$::errlog); + while () { + @fields = split; + @tmp = grep(/$fields[0]/,@ARGV); + if ($#tmp == -1 && !exists $::chost->{$fields[0]}) { + newHost($fields[0]); + } + } + close(LOG); +} + +sub rescanhosts { + foreach $i (keys(%chost)) { + $chost{$i}->check(); + } +} + +sub autorescan { + $afterId = Tk::after($rescanWhen*1000,[\&autorescan]); + if ($RescanWhenHidden && !$hidden) {return;} + if ($AutoCheckHosts) { + rescanhosts(); + } + if ($AutoCheckLog) { + scanlog(); + } +} + +sub flatten { + foreach $i (keys(%chost)) { + $chost{$i}->{'MainFrame'}->configure(-relief => "flat",-borderwidth=>0); + } +} + +sub reliefen { + foreach $i (keys(%chost)) { + $chost{$i}->{'MainFrame'}->configure(-relief =>"sunken",-borderwidth=>2); + } +} + +sub fixall { + foreach $i (keys(%chost)) { + $chost{$i}->fix(); + } +} + +sub seenall { + foreach $i (keys(%chost)) { + $chost{$i}->seenall(); + } +} + +sub remote_cmd { + my $type = shift; + if ($selected) { + remote_cmd_generic("$::snmppath/rsnmp -p $type $selected->{'Host'}", + "$selected->{'Host'} -- $type",1); + } else { + setmsg("Error: Nothing selected"); + } +} + +sub remote_load { + if ($selected) { + remote_cmd_generic("$::snmppath/snmpwalk " . sprintf($::default_get_args,$selected->{'Host'}) . " .EXTENSIBLEDOTMIB.LOADAVEMIBNUM.LOADAVE", + "$selected->{'Host'} -- LoadAve"); + } else { + setmsg("Error: Nothing selected"); + } +} + +sub remote_cmd_generic { + my $cmd = shift; + my $title = shift; + my $insert = shift; + addToLog("running: $cmd ... "); + my $newwin = MainWindow->new; + $newwin->Busy(); + + $newwin->option('add','*highlightThickness','0'); #wish this worked +# $newwin->option('add','*highlightbackground','#C9C9C9'); + $newwin->option('add','*background','#C9C9C9'); + $newwin->option('add','*font','6x13'); + + my $buttons = $newwin->Frame; + $buttons->pack(-side => 'bottom', -expand => 1, -fill => 'x'); + my $entries = $newwin->Frame; + $entries->pack(-side => 'bottom', -expand => 1, -fill => 'x'); + + my $text = $newwin->Text(-height => 40, -setgrid => 1); + $text->pack(-side => 'left', -fill => 'both', -expand => 1); + my $scroll = $newwin->Scrollbar(-command => ['yview',$text]); + $scroll->pack(-side => 'left', -fill => 'y'); + $text->configure(-yscrollcommand => ['set', $scroll]); + + my $close = $buttons->Button(-text => 'Close', + -command => ['destroy',$newwin]); + $close->pack(-side => 'left', -expand => 1); + my $rerun = $buttons->Button(-text => 'Re-Run', + -command=>[\&fill_text,'',$text, + \$cmd,$insert]); + $rerun->pack(-side => 'left', -expand => 1); + + my $cmdlabel = $entries->Label(-text => "Command: "); + my $cmdtexte = $entries->Entry(-textvariable => \$cmd, + -relief => "sunken"); + $cmdtexte->bind('' => [\&fill_text,$text, \$cmd,$insert]); + $cmdlabel->pack(-side => 'left'); + $cmdtexte->pack(-side => 'left'); + + my $searchtext = ''; + my $searchlabel = $entries->Label(-text => "Search for: "); + my $searchtexte = $entries->Entry(-textvariable => \$searchtext, + -relief => "sunken"); + + $searchtexte->pack(-side => 'right'); + $searchlabel->pack(-side => 'right'); + $searchtexte->bind('' => [sub { $text->tag('remove','search','0.0','end'); + my($current, $length) = ('1.0', 0); + while (1) { + $current = $text->search(-count => \$length, $searchtext, $current, 'end'); + last if not $current; + $text->tag('add', 'search', $current, "$current + $length char"); + $current = $text->index("$current + $length char"); + $text->tag('configure','search', + -background => + 'lightBlue');}}]); + + if (defined($title)) { + $newwin->title($title); + $newwin->iconname($title); + } + fill_text('',$text,\$cmd,$insert); +} + +sub fill_text { + my $dump = shift; + my $textw = shift; + my $cmd = shift; + my $insert = shift; + $textw->delete('1.0','end'); + if (defined($insert) && $insert) { + $textw->insert('end',"running: $$cmd\n\n"); + } + $textw->toplevel->update(); + $textw->toplevel->Busy(); + open(OUT,"$$cmd|"); + while () { + $textw->insert('end',$_); + $textw->toplevel->update(); + $textw->toplevel->Busy(); + } + close(OUT); + if (defined ($insert) && $insert) { + $textw->insert('end',"\ndone.\n"); + } + $textw->toplevel->Unbusy(); + $textw->Unbusy(); + addToLog("done: $$cmd"); +} + +sub display_help { + print " +Usage: snmpcheck [-x] [-n|y] [-h] [-H] [-V NUM] [-L] [-f] [[-a] HOSTS] + + -h\tDisplay this message. + -a\tcheck error log file AND hosts specified on command line. + -p\tDon't try and ping-echo the host first + -f\tOnly check for things I can fix + HOSTS\tcheck these hosts for problems. + +X Options: + -x\tforces ascii base if \$DISPLAY set (instead of tk). + -H\tstart in hidden mode. (hides user interface) + -V NUM\tsets the initial verbosity level of the command log (def: 1) + -L\tShow the log window at startup + -d\tDon't start by checking anything. Just bring up the interface. + +Ascii Options: + -n\tDon't ever try and fix the problems found. Just list. + -y\tAlways fix problems found. + +"; + exit(0); + +} + +sub option_get { + my $resource = shift; + return $top->option('get',$resource); +} + +sub option_set { + my $resource = shift; + my $value = shift; + $top->option('add',"*$resource",$value); +} + +sub option_save { + +} + +sub mibsort { + $_ = $a; + ($av) = /\.([0-9]+)/; + $_ = $b; + ($bv) = /\.([0-9]+)/; + return $av <=> $bv; +} + +sub setmibchecklist { + my $i; + foreach $i (keys(%mibchecklist)) { + $mibchecklist{$i} = 0; + } + foreach $i (@_) { + $mibchecklist{$i} = 1; + } +} diff --git a/local/snmpconf b/local/snmpconf new file mode 100755 index 0000000..37a5136 --- /dev/null +++ b/local/snmpconf @@ -0,0 +1,933 @@ +#!/usr/bin/perl -w + +# +# A simple configuration file builder based on questions listed in +# its own configuration file. It would certainly be easy to use this +# for other (non-snmp) programs as well. +# + +use Getopt::Std; +use Term::ReadLine; +use IO::File; +use Data::Dumper; +use File::Copy; +if ($^O eq 'MSWin32') { + eval 'require Win32::Registry;'; + if ($@) { + print "\nWarning: Perl module Win32::Registry is not installed. This module is\n"; + print " required to read the SNMPSHAREPATH and SNMPCONFPATH values from \n"; + print " the registry. To use snmpconf without the module you need to\n"; + print " define SNMPSHAREPATH and SNMPCONFPATH as environment variables\n"; + print " or use the -c and -I command line options.\n"; + } +} + +# globals +%tokenitems=qw(line 1 info 1 comment 1); +%arrayitems=qw(question 1 validanswer 1); + +# default folder for snmpconf-data +if (defined(&my_getenv("SNMPSHAREPATH"))) { + $opts{'c'} = &my_getenv("SNMPSHAREPATH") . "/snmpconf-data"; +} +else { + $opts{'c'} = "/usr/local/share/snmp/snmpconf-data"; +} + +# default config file path +if (defined(&my_getenv("SNMPCONFPATH"))) { + $confpath = &my_getenv("SNMPCONFPATH"); +} +else { + $confpath = "/usr/local/share/snmp"; +} + +# home environment variable +if (defined(&my_getenv("HOME"))) { + $home = &my_getenv("HOME") . "/.snmp"; +} +else { + $home = "(HOME dir - n/a)"; +} + +# read the argument string +getopts("qadhfc:piI:r:R:g:G", \%opts); + +# display help +if ($opts{'h'}) { + print "$0 [options] [FILETOCREATE...]\n"; + print "options:\n"; + print " -f overwrite existing files without prompting\n"; + print " -i install created files into $confpath.\n"; + print " -p install created files into $home.\n"; + print " -I DIR install created files into DIR.\n"; + print " -a Don't ask any questions, just read in current\n"; + print " current .conf files and comment them\n"; + print " -r all|none Read in all or none of the .conf files found.\n"; + print " -R file,... Read in a particular list of .conf files.\n"; + print " -g GROUP Ask a series of GROUPed questions.\n"; + print " -G List known GROUPs.\n"; + print " -c conf_dir use alternate configuration directory.\n"; + print " -q run more quietly with less advice.\n"; + print " -d turn on debugging output.\n"; + print " -D turn on debugging dumper output.\n"; + exit; +} + +# setup terminal interface. +$ENV{'PERL_RL'}='o=0' if (!exists($ENV{'PERL_RL'})); +$term = new Term::ReadLine 'snmpconf'; + +# read in configuration file set +read_config_files($opts{'c'}, \%filetypes); +debug(my_Dumper(\%filetypes)); + +if ($opts{'G'}) { + Print("\nKnown GROUPs of tokens:\n\n"); + foreach my $group (keys(%groups)) { + print " $group\n"; + } + Print("\n"); + exit; +} + +# +# Expand the search path in case it contains multiple directories +# separated by : (Unix) or ; (Win32) +# +my $ENV_SEPARATOR = ':'; +if ($^O eq 'MSWin32') { + $ENV_SEPARATOR = ';'; +} +my @searchpath = split(/$ENV_SEPARATOR/, $confpath); +push @searchpath, "/usr/local/etc/snmp"; +push @searchpath, "."; +push @searchpath, "$home"; + +# Remove trailing /'s or \'s +for (my $i=0; $i <= $#searchpath; $i++) { + $searchpath[$i] =~ /(.*?)([\/\\])*$/; + $searchpath[$i] = $1; +} + +# Determine persistent directory. Order of preference: +# +# file in SNMP_PERSISTENT_FILE environment variable +# directory defined by persistentDir snmp.conf variable +# directory in SNMP_PERSISTENT_DIR environment variable +# default PERSISTENT_DIRECTORY directory +my $persistentDir = ""; +my $persistentFile = ""; + +# SNMP_PERSISTENT_FILE environment variable +if (defined(&my_getenv("SNMP_PERSISTENT_FILE"))) { + $persistentFile = &my_getenv("SNMP_PERSISTENT_FILE"); + debug ("persistent file: SNMP_PERSISTENT_FILE environment variable set\n"); +} + +# snmp.conf persistentDir +if (!($persistentDir) && !($persistentFile)) { + foreach my $i (@searchpath) { + debug ("Searching file $i/snmp.conf for persistentDir\n"); + my $temp = get_persistentDir("$i/snmp.conf"); + if ($temp) { + debug("persistent directory: set to $temp in $i/snmp.conf\n"); + $persistentDir = $temp; + last; + } + } +} + +# SNMP_PERSISTENT_DIR environment variable +if (!($persistentDir) && !($persistentFile)) { + if (&my_getenv("SNMP_PERSISTENT_DIR")) { + $persistentDir = &my_getenv("SNMP_PERSISTENT_DIR"); + debug ("persistent directory: SNMP_PERSISTENT_DIR environment variable set\n"); + } +} + +# PERSISTENT_DIRECTORY default variable +if (!($persistentDir) && !($persistentFile)) { + $persistentDir = "/var/net-snmp"; + debug ("persistent directory: Using default value\n"); +} + +# Rebuild search path without persistent folder +# Note: persistent file handled in Find existing +# files to possibly read in section +if ($persistentDir) { + # Remove trailing /'s or \'s + $persistentDir =~ /(.*?)([\/\\])*$/; + $persistentDir = $1; + debug ("persistent directory: $persistentDir\n"); + + my @searchpath_old = @searchpath; + @searchpath = (); + foreach my $path_temp (@searchpath_old) { + if ($path_temp eq $persistentDir) { + debug("skipping persistent directory $path_temp\n"); + next; + } + push @searchpath, $path_temp; + } +} + +# Reset $confpath to the first path +$confpath = $searchpath[0]; + +# +# Find existing files to possibly read in. +# +push @searchpath, $opts{I} if ($opts{I}); +foreach my $i (@searchpath) { + debug("searching $i\n"); + foreach my $ft (keys(%filetypes)) { + if ("$i/$ft" eq $persistentFile) { + debug("skipping persistent file $i/$ft\n"); + next; + } + debug("searching for $i/$ft\n"); + $knownfiles{"$i/$ft"} = $ft if (-f "$i/$ft"); + my $localft = $ft; + $localft =~ s/.conf/.local.conf/; + $knownfiles{"$i/$localft"} = $ft if (-f "$i/$localft"); + } +} + +# +# Ask the user if they want them to be read in and read them +# +if (keys(%knownfiles)) { + my @files; + if (defined($opts{'r'})) { + if ($opts{'r'} eq "all" || $opts{'r'} eq "a") { + @files = keys(%knownfiles); + } elsif ($opts{'r'} ne "none" && $opts{'r'} ne "n") { + print "unknown argument to -r: $opts{'r'}\n"; + exit(1); + } + } elsif(defined($opts{'R'})) { + @files = split(/\s*,\s*/,$opts{'R'}); + foreach my $i (@files) { + my $x = $i; + $x =~ s/.*\/([^\/]+)$/$1/; + $knownfiles{$i} = $x; + } + Print("reading: ", join(",",@files),"\n"); + } else { + @files = display_menu(-head => "The following installed configuration files were found:\n", + -tail => "Would you like me to read them in? Their content will be merged with the\noutput files created by this session.\n\nValid answer examples: \"all\", \"none\",\"3\",\"1,2,5\"\n", + -multiple => 1, + -question => 'Read in which', + -defaultvalue => 'all', + sort keys(%knownfiles)); + } + foreach my $i (@files) { + debug("reading $i\n"); + read_config($i, $knownfiles{$i}); + } +} + +if ($opts{'g'}) { + my @groups = split(/,:\s/,$opts{'g'}); + foreach my $group (@groups) { + do_group($group); + } +} elsif ($#ARGV >= 0) { + # + # loop through requested files. + # + foreach my $i (@ARGV) { + if (!defined($filetypes{$i})) { + warn "invalid file: $i\n"; + } else { + if ($opts{'a'}) { + $didfile{$i} = 1; + } else { + build_file($term, $i, $filetypes{$i}); + } + } + } +} else { + # + # ask user to select file type to operate on. + # + while(1) { + my $line = display_menu(-head => "I can create the following types of configuration files for you.\nSelect the file type you wish to create:\n(you can create more than one as you run this program)\n", + -question => 'Select File', + -otheranswers => ['quit'], + -mapanswers => { 'q' => 'quit' }, + keys(%filetypes)); + last if ($line eq "quit"); + debug("file selected: $line\n"); + build_file($term, $line, $filetypes{$line}); + } +} + +# +# Write out the results to the output files. +# +output_files(\%filetypes, $term); + + +# +# Display the files that have been created for the user. +# +Print("\n\nThe following files were created:\n\n"); +@didfiles = keys(%didfile); +foreach my $i (@didfiles) { + if ($didfile{$i} ne "1") { + if ($opts{'i'} || $opts{'I'}) { + $opts{'I'} = "$confpath" if (!$opts{'I'}); + + if (! (-d "$opts{'I'}") && ! (mkdir ("$opts{'I'}", 0755))) { + print "\nCould not create $opts{'I'} directory: $!\n"; + print ("File $didfile{$i} left in current directory\n"); + } + else { + move ("$opts{'I'}/$i", "$opts{'I'}/$i.bak") if (-f "$opts{'I'}/$i"); + if (move ("$didfile{$i}", "$opts{'I'}")) { + print(" $didfile{$i} installed in $opts{'I'}\n"); + } + else { + print "\nCould not move file $didfile{$i} to $opts{'I'}/$i: $!\n"; + print ("File $didfile{$i} left in current directory\n"); + } + } + } elsif ($opts{'p'}) { + if (! (-d "$home") && ! (mkdir ("$home", 0755))) { + print "\nCould not create $home directory: $!\n"; + print ("File $didfile{$i} left in current directory\n"); + } + else { + move ("$home/$i", "$home/$i.bak") if (-f "$home/$i"); + if (move ("$didfile{$i}", "$home")) { + print(" $didfile{$i} installed in $home\n"); + } + else { + print "\nCould not move file $didfile{$i} to $home: $!\n"; + print ("File $didfile{$i} left in current directory\n"); + } + } + } else { + Print(" $didfile{$i} ", + ($i ne $didfile{$i})?"[ from $i specifications]":" ","\n"); + if ($opts{'d'}) { + open(I,$didfile{$i}); + debug(" " . join(" ",) . "\n"); + close(I); + } + } + } +} + +if (!$opts{'p'} && !$opts{'i'} && !$opts{'I'}) { + Print("\nThese files should be moved to $confpath if you +want them used by everyone on the system. In the future, if you add +the -i option to the command line I'll copy them there automatically for you. + +Or, if you want them for your personal use only, copy them to +$home . In the future, if you add the -p option to the +command line I'll copy them there automatically for you. + +"); +} + +########################################################################### +# Functions +########################################################################### + +sub Print { + print @_ if (!$opts{'q'}); +} +# +# handle a group of questions +# +sub get_yn_maybe { + my $question = shift; + my $ans = "y"; + if ($question ne "") { + $ans = get_answer($term, $question, + valid_answers(qw(yes y no n)), 'y'); + } + return ($ans =~ /^y/)?1:0; +} + +sub do_group { + my $group = shift; + die "no such group $group\n" if (!$groups{$group}); + foreach my $token (@{$groups{$group}}) { + if ($token->[0] eq "message") { + Print ("$token->[1] $token->[2]\n"); + } elsif ($token->[0] eq "subgroup") { + do_group($token->[1]) if (get_yn_maybe($token->[2])); + } elsif (defined($tokenmap{$token->[1]})) { + if (get_yn_maybe($token->[2])) { + do { + do_line($token->[1], $tokenmap{$token->[1]}); + } until ($token->[0] ne "multiple" || + get_answer($term, "Do another $token->[1] line?", + valid_answers(qw(yes y no n)), 'y') + =~ /n/); + } + } elsif (defined($filetypes{$token->[1]})) { + $didfile{$token->[1]} = 1; + } else { + die "invalid member $token->[1] of group $group\n"; + } + } +} + +# +# build a particular type of file by operating on sections +# +sub build_file { + my ($term, $filename, $fileconf) = @_; + $didfile{$filename} = 1; + my (@lines); + while(1) { + my $line = display_menu(-head => "The configuration information which can be put into $filename is divided\ninto sections. Select a configuration section for $filename\nthat you wish to create:\n", + -otheranswers => ['finished'], + -mapanswers => { 'f' => 'finished' }, + -question => "Select section", + -numeric => 1, + map { $_->{'title'}[0] } @$fileconf); + + return @lines if ($line eq "finished"); + do_section($fileconf->[$line-1]); + } +} + +# +# configure a particular section by operating on token types +# +sub do_section { + my $confsect = shift; + my @lines; + while(1) { + Print ("\nSection: $confsect->{'title'}[0]\n"); + Print ("Description:\n"); + Print (" ", join("\n ",@{$confsect->{'description'}}),"\n"); + my $line = + display_menu(-head => "Select from:\n", + -otheranswers => ['finished','list'], + -mapanswers => { 'f' => 'finished', + 'l' => 'list' }, + -question => 'Select section', + -descriptions => [map { $confsect->{$_}{info}[0] } + @{$confsect->{'thetokens'}}], + @{$confsect->{'thetokens'}}); + return @lines if ($line eq "finished"); + if ($line eq "list") { + print "Lines defined for section \"$confsect->{title}[0]\" so far:\n"; + foreach my $i (@{$confsect->{'thetokens'}}) { + if ($#{$confsect->{$i}{'results'}} >= 0) { + print " ",join("\n ",@{$confsect->{$i}{'results'}}),"\n"; + } + } + next; + } + do_line($line, $confsect->{$line}); + } + return; +} + +# +# Ask all the questions related to a particular line type +# +sub do_line { + my $token = shift; + my $confline = shift; + my (@answers, $counter, $i); +# debug(my_Dumper($confline)); + Print ("\nConfiguring: $token\n"); + Print ("Description:\n ",join("\n ",@{$confline->{'info'}}),"\n\n"); + for($i=0; $i <= $#{$confline->{'question'}}; $i++) { + if (defined($confline->{'question'}[$i]) && + $confline->{'question'}[$i] ne "") { + my $q = $confline->{'question'}[$i]; + $q =~ s/\$(\d+)/$answers[$1]/g; + debug("after: $term, $q, ",$confline->{'validanswer'}[$i],"\n"); + $answers[$i] = get_answer($term, $q, + $confline->{'validanswer'}[$i]); + $answers[$i] =~ s/\"/\\\"/g; + $answers[$i] = '"' . $answers[$i] . '"' if ($answers[$i] =~ /\s/); + } + } + if ($#{$confline->{'line'}} == -1) { + my ($i,$line); + for($i=0; $i <= $#{$confline->{'question'}}; $i++) { + next if (!defined($confline->{'question'}[$i]) || + $confline->{'question'}[$i] eq ""); + $line .= " \$" . $i; + } + push @{$confline->{'line'}}, $line; + } + + foreach my $line (@{$confline->{'line'}}) { + my $finished = $line; + debug("preline: $finished\n"); + debug("answers: ",my_Dumper(\@answers)); + $finished =~ s/\$(\d+)/$answers[$1]/g; + if ($line =~ s/^eval\s+//) { + debug("eval: $finished\n"); + $finished = eval $finished; + debug("eval results: $finished\n"); + } + $finished = $token . " " . $finished; + Print ("\nFinished Output: $finished\n"); + push @{$confline->{'results'}},$finished; + } +} + +# +# read all sets of config files in the various subdirectories. +# +sub read_config_files { + my $readdir = shift; + my $filetypes = shift; + opendir(DH, $readdir) || die "no such directory $readdir, did you run make install?\n"; + my $dir; + my $configfilename="snmpconf-config"; + + while(defined($dir = readdir(DH))) { + next if ($dir =~ /^\./); + next if ($dir =~ /CVS/); + debug("dir entry: $dir\n"); + if (-d "$readdir/$dir" && -f "$readdir/$dir/$configfilename") { + + my $conffile; + + # read the top level configuration inforamation about the direcotry. + open(I, "$readdir/$dir/$configfilename"); + while() { + $conffile = $1 if (/forconffile: (.*)/); + } + close(I); + + # no README informatino. + if ($conffile eq "") { + print STDERR "Warning: No 'forconffile' information in $readdir/$dir/$configfilename\n"; + next; + } + + # read all the daat in the directory + $filetypes->{$conffile} = read_config_items("$readdir/$dir", $conffile); + } else { + # no README informatino. + print STDERR "Warning: No $configfilename file found in $readdir/$dir\n"; + } + } + closedir DH; +} + +# +# read each configuration file in a directory +# +sub read_config_items { + my $itemdir = shift; + my $type = shift; + opendir(ITEMS, $itemdir); + my $file; + my @results; + while(defined($file = readdir(ITEMS))) { + next if ($file =~ /~$/); + next if ($file =~ /^snmpconf-config$/); + if (-f "$itemdir/$file") { + my $res = read_config_item("$itemdir/$file", $type); + if (scalar(keys(%$res)) > 0) { + push @results, $res; + } + } + } + closedir(ITEMS); + return \@results; +} + +# +# mark a list of tokens as a special "group" +# +sub read_config_group { + my ($fh, $group, $type) = @_; + my $line; + debug("handling group $group\n"); + push (@{$groups{$group}},['filetype', $type]); + while($line = <$fh>) { + chomp($line); + next if ($line =~ /^\s*$/); + next if ($line =~ /^\#/); + return $line if ($line !~ /^(single|multiple|message|filetype|subgroup)/); + my ($type, $token, $rest) = ($line =~ /^(\w+)\s+([^\s]+)\s*(.*)/); + debug ("reading group $group : $type -> $token -> $rest\n"); + push (@{$groups{$group}}, [$type, $token, $rest]); + } + return; +} + + +# +# Parse one file +# +sub read_config_item { + my $itemfile = shift; + my $itemcount; + my $type = shift; + my $fh = new IO::File($itemfile); + return if (!defined($fh)); + my (%results, $curtoken); + debug("tokenitems: ", my_Dumper(\%tokenitems)); + topwhile: + while($line = <$fh>) { + next if ($line =~ /^\s*\#/); + my ($token, $rest) = ($line =~ /^(\w+)\s+(.*)/); + next if (!defined($token) || !defined($rest)); + while ($token eq 'group') { + # handle special group list + my $next = read_config_group($fh, $rest,$type); + if ($next) { + ($token, $rest) = ($next =~ /^(\w+)\s+(.*)/); + } else { + next topwhile; + } + } + debug("token: $token => $rest\n"); + if ($token eq 'steal') { + foreach my $stealfrom (keys(%{$results{$rest}})) { + if (!defined($results{$curtoken}{$stealfrom})) { + @{$results{$curtoken}{$stealfrom}} = + @{$results{$rest}{$stealfrom}}; + } + } + } elsif (defined($tokenitems{$token})) { + if (!defined($curtoken)) { + die "error in configuration file $itemfile, no token set\n"; + } + $rest =~ s/^\#//; + push @{$results{$curtoken}{$token}},$rest; + } elsif (defined($arrayitems{$token})) { + if (!defined($curtoken)) { + die "error in configuration file $itemfile, no token set\n"; + } + my ($num, $newrest) = ($rest =~ /^(\d+)\s+(.*)/); + if (!defined($num) || !defined($newrest)) { + warn "invalid config line: $line\n"; + } else { + $results{$curtoken}{$token}[$num] = $newrest; + } + } elsif ($token =~ /^token\s*$/) { + $rest = lc($rest); + $curtoken = $rest; + if (! exists $results{$curtoken}{'defined'}) { + push @{$results{'thetokens'}}, $curtoken; + $results{$curtoken}{'defined'} = 1; + } + $tokenmap{$curtoken} = $results{$curtoken}; + debug("current token set to $token\n"); + } else { + push @{$results{$token}},$rest; + } + } + return \%results; +} + +sub debug { + print @_ if ($opts{'d'}); +} + +sub output_files { + my $filetypes = shift; + my $term = shift; + foreach my $ft (keys(%$filetypes)) { + next if (!$didfile{$ft}); + my $outputf = $ft; + if (-f $outputf && !$opts{'f'}) { + print "\nError: An $outputf file already exists in this directory.\n\n"; + my $ans = get_answer($term,"'overwrite', 'skip', 'rename' or 'append'? ",valid_answers(qw(o overwrite r rename s skip a append))); + next if ($ans =~ /^(s|skip)$/i); + if ($ans =~ /^(a|append)/) { + $outputf = ">$outputf"; + } elsif ($ans =~ /^(r|rename)$/i) { + # default to rename for error conditions + $outputf = $term->readline("Save to what new file name instead (or 'skip')? "); + } + } + $didfile{$ft} = $outputf; + open(O,">$outputf") || warn "couldn't write to $outputf\n"; + print O "#" x 75,"\n"; + print O "#\n# $ft\n"; + print O "#\n# - created by the snmpconf configuration program\n#\n"; + foreach my $sect (@{$filetypes->{$ft}}) { + my $secthelp = 0; + foreach my $token (@{$sect->{'thetokens'}}) { + if ($#{$sect->{$token}{'results'}} >= 0) { + if ($secthelp++ == 0) { + print O "#" x 75,"\n# SECTION: ", + join("\n# ", @{$sect->{title}}), "\n#\n"; + print O "# ", join("\n# ",@{$sect->{description}}), + "\n"; + } + print O "\n# $token: ", + join("\n# ",@{$sect->{$token}{info}}), "\n\n"; + foreach my $result (@{$sect->{$token}{'results'}}) { + print O "$result\n"; + } + } + } + print O "\n\n\n"; + } + if ($#{$unknown{$ft}} > -1) { + print O "#\n# Unknown directives read in from other files by snmpconf\n#\n"; + foreach my $unknown (@{$unknown{$ft}}) { + print O $unknown,"\n"; + } + } + close(O); + } +} + +sub get_answer { + my ($term, $question, $regexp, $defaultval) = @_; + $question .= " (default = $defaultval)" if (defined($defaultval) && $defaultval ne ""); + $question .= ": "; + my $ans = $term->readline($question); + return $defaultval if ($ans eq "" && defined($defaultval) && + $defaultval ne ""); + while (!(!defined($regexp) || + $regexp eq "" || + $ans =~ /$regexp/)) { + print "invalid answer! It must match this regular expression: $regexp\n"; + $ans = $term->readline($question); + } + return $defaultval if ($ans eq "" && defined($defaultval) && + $defaultval ne ""); + return $ans; +} + +sub valid_answers { + my @list; + foreach $i (@_) { + push @list, $i if ($i); + } + return "^(" . join("|",@list) . ")\$"; +} + +sub read_config { + my $file = shift; + my $filetype = shift; + return if (!defined($filetypes{$filetype})); + if (! -f $file) { + warn "$file does not exist\n"; + return; + } + open(I,$file); + while() { + next if (/^\s*\#/); + next if (/^\s*$/); + chomp; + my ($token, $rest) = /^\s*(\w+)\s+(.*)/; + $token = lc($token); + next if (defined($alllines{$_})); # drop duplicate lines + if (defined($tokenmap{$token})) { + push @{$tokenmap{$token}{'results'}},$_; + } else { + push @{$unknown{$filetype}},$_; + } + $alllines{$_}++; + } + close(I); +} + +sub display_menu { + my %config; + + while ($#_ > -1 && $_[0] =~ /^-/) { + my $key = shift; + $config{$key} = shift; + } + + my $count=1; + print "\n" if (!defined($config{'-dense'})); + if ($config{'-head'}) { + print $config{'-head'}; + print "\n" if (!defined($config{'-dense'})); + } + my @answers = @_; + my @list; + if (defined($config{'-descriptions'}) && + ref($config{'-descriptions'}) eq "ARRAY") { + @list = @{$config{'-descriptions'}} + } else { + @list = @_; + } + foreach my $i (@list) { + printf " %2d: $i\n", $count++ if ($i); + } + print "\n" if (!defined($config{'-dense'})); + if (defined($config{'-otheranswers'})) { + if (ref($config{'-otheranswers'}) eq 'ARRAY') { + print "Other options: ", join(", ", + @{$config{'-otheranswers'}}), "\n"; + push @answers, @{$config{'-otheranswers'}}; + push @answers, keys(%{$config{'-mapanswers'}}); + } else { + my $maxlen = 0; + push @answers,keys(%{$config{'-otheranswers'}}); + foreach my $i (keys(%{$config{'-otheranswers'}})) { + $maxlen = length($i) if (length($i) > $maxlen); + } + foreach my $i (keys(%{$config{'-otheranswers'}})) { + printf(" %-" . $maxlen . "s: %s\n", $i, + $config{'-otheranswers'}{$i}); + } + } + print "\n" if (!defined($config{'-dense'})); + } + if ($config{'-tail'}) { + print $config{'-tail'}; + print "\n" if (!defined($config{'-dense'})); + } + + if (defined($config{'-question'})) { + while(1) { + my $numexpr; + if ($config{'-multiple'}) { + $numexpr = '[\d\s,]+|all|a|none|n'; + } else { + $numexpr = '\d+'; + } + push @answers,"" if ($config{'-defaultvalue'}); + $ans = get_answer($term, $config{'-question'}, + valid_answers($numexpr,@answers), + $config{'-defaultvalue'}); + if ($config{'-mapanswers'}{$ans}) { + $ans = $config{'-mapanswers'}{$ans}; + } + + if ($ans =~ /^$numexpr$/) { + if ($config{'-multiple'}) { + my @list = split(/\s*,\s*/,$ans); + my @ret; + $count = 0; + foreach my $i (@_) { + $count++; + if ($ans eq "all" || $ans eq "a" + || grep(/^$count$/,@list)) { + push @ret, $i; + } + } + return @ret; + } else { + if ($ans <= 0 || $ans > $#_+1) { + warn "invalid selection: $ans [must be 1-" . + ($#_+1) . "]\n"; + } else { + return $ans if ($config{'-numeric'}); + $count = 0; + foreach my $i (@_) { + $count++; + if ($ans eq $count) { + return $i; + } + } + } + } + } else { + return $ans; + } + } + } +} + +sub my_Dumper { + if ($opts{'D'}) { + return Dumper(@_); + } else { + return "\n"; + } +} + +sub get_persistentDir { + my $file = shift; + my $result = 0; + if (! -f $file) { + return 0; + } + open(I,$file); + while() { + next if (/^\s*\#/); + next if (/^\s*$/); + chomp; + my ($token, $rest) = /^\s*(\w+)\s+(.*)/; + if (lc($token) eq "persistentdir") { + $result = $rest; + } + next; + } + close(I); + return $result; +} + +# Usage: &win32_reg_read("key", "value") +# Example: &win32_reg_read("SOFTWARE\\Net-SNMP","SNMPSHAREPATH"); +# Returns: Value if found in HKCU or HCLM. Otherwise an empty string. +sub win32_reg_read { + my $sub_key = shift; + my $value = shift; + + require Win32::Registry; + + my ($hkey, %key_values, $temp, $no_warn); + + # Try HKCU first + $no_warn = $HKEY_CURRENT_USER; + if ($HKEY_CURRENT_USER->Open($sub_key, $hkey)) + { + $hkey->GetValues(\%key_values); + foreach $temp (sort keys %key_values) { + if ($temp eq $value) { + return $key_values{$temp}[2]; + } + } + $hkey->Close(); + } + + # Try HKLM second + $no_warn = $HKEY_LOCAL_MACHINE; + if ($HKEY_LOCAL_MACHINE->Open($sub_key, $hkey)) + { + $hkey->GetValues(\%key_values); + foreach $temp (sort keys %key_values) { + if ($temp eq $value) { + return $key_values{$temp}[2]; + } + } + $hkey->Close(); + } + return ""; +} + +# Usage: &my_getenv("key") +# Example: &my_getenv("SNMPSHAREPATH"); +# Returns: Unix: Environment variable value (undef if not defined) +# Win32: HKCU\Software\Net-SNMP\(key) or +# Win32: HKLM\Software\Net-SNMP\(key) or +# Win32: Environment variable value (undef if not defined) +sub my_getenv { + my $key = shift; + + # Unix + if ($^O ne 'MSWin32') { + return $ENV{$key}; + } + # Windows + else { + my $temp = &win32_reg_read("SOFTWARE\\Net-SNMP","$key"); + if ($temp ne "") { + return $temp; + } + else { + return $ENV{$key}; + } + } +} + diff --git a/local/snmpconf.dir/snmp-data/authopts b/local/snmpconf.dir/snmp-data/authopts new file mode 100644 index 0000000..12cd8e5 --- /dev/null +++ b/local/snmpconf.dir/snmp-data/authopts @@ -0,0 +1,77 @@ +title Default Authentication Options +description This section defines the default authentication +description information. Setting these up properly in your +description ~/.snmp/snmp.conf file will greatly reduce the amount of +description command line arguments you need to type (especially for snmpv3). + +token defaultPort +info The default port number to use +info This token specifies the default port number you want packets to +info be sent to and received from. +info override: with -p on the command line. +info arguments: portnum +question 1 Enter the default port number to use + +token defVersion +info The default snmp version number to use. +info override: with -v on the command line. +info arguments: 1|2c|3 +question 1 Enter the default snmp version number to use (1|2c|3) +validanswer 1 ^(1|2c|3)$ + +token defCommunity +info The default snmpv1 and snmpv2c community name to use when needed. +info If this is specified, you don't need to include the community +info name as an argument to the snmp applications. +info override: with -c on the command line. +info arguments: communityname +question 1 Enter the default community name to use + +token defSecurityName +info The default snmpv3 security name to use when using snmpv3 +info override: with -u on the command line. +info arguments: securityname +question 1 Enter the default security name to use + +token defContext +info The default snmpv3 context name to use +info override: with -n on the command line. +info arguments: contextname +question 1 Enter the default context name to use + +token defSecurityLevel +info The default snmpv3 security level to use +info override: with -l on the command line. +info arguments: noAuthNoPriv|authNoPriv|authPriv +question 1 Enter the default privacy pass phrase to use +validanswer 1 ^(noAuthNoPriv|authNoPriv|authPriv|nanp|anp|ap)$ + +token defAuthType +info The default snmpv3 authentication type name to use +info override: with -a on the command line. +info arguments: authtype +question 1 Enter the default authentication type to use (MD5|SHA) +validanswer 1 ^(MD5|SHA)$ + +token defAuthPassphrase +info The default snmpv3 authentication pass phrase to use +info Note: It must be at least 8 characters long. +info override: with -A on the command line. +info arguments: passphrase +question 1 Enter the default authentication pass phrase to use + +token defPrivType +info The default snmpv3 privacy (encryption) type name to use +info override: with -x on the command line. +info arguments: privtype +question 1 Enter the default privacy type to use (DES|AES) +validanswer 1 ^(DES|AES)$ + +token defPrivPassphrase +info The default snmpv3 privacy pass phrase to use +info Note: It must be at least 8 characters long. +info override: with -X on the command line. +info arguments: passphrase +question 1 Enter the default privacy pass phrase to use + + diff --git a/local/snmpconf.dir/snmp-data/debugging b/local/snmpconf.dir/snmp-data/debugging new file mode 100644 index 0000000..90a271f --- /dev/null +++ b/local/snmpconf.dir/snmp-data/debugging @@ -0,0 +1,39 @@ +title Debugging output options +description This section allows debugging output of various kinds to +description be turned on or off. + +token doDebugging +info Turns debugging output on or off (0|1) +info arguments: (0|1) +question 1 Turn debugging on (0|1) +validanswer 1 ^(0|1)$ + +token debugTokens +info Debugging tokens specify which lines of debugging +info output you'd actually like to see. Each section of code is most +info likely instrumented with a particular "tag". So, to see that tag you +info would specify it here. Specifying a tag will match against all +info tags that begin with that prefix, so the tag "test" will match +info "test_function" and "test_something" and... +info There are a few special tokens as well: +info - ALL: turns on all the tokens (which generates lots of output) +info - trace: prints 'trace' lines showing source code files and +info - line numbers as they're traversed. +info - dump: Nicely breaks down packets as they're parsed or sent out. +info command line equivelent: -Dtoken[,token...] +info arguments: token[,token...] +question 1 Enter the tokens (comma seperated) you wish to see output for + +token dumpPacket +info Print packets as they are received or sent +info arguments: (1|yes|true|0|no|false) +info command line equivelent: -d +validanswer 1 ^(1|yes|true|0|no|false)$ +question 1 Print packets as they are received or sent + + +token noTokenWarnings +info Silence warnings about unknown tokens in configuration files +question 1 Silence warnings about unknown tokens in configuration files +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ diff --git a/local/snmpconf.dir/snmp-data/mibs b/local/snmpconf.dir/snmp-data/mibs new file mode 100644 index 0000000..c3cfd74 --- /dev/null +++ b/local/snmpconf.dir/snmp-data/mibs @@ -0,0 +1,56 @@ +title Textual mib parsing +description This section controls the textual mib parser. Textual +description mibs are parsed in order to convert OIDs, enumerated +description lists, and ... to and from textual representations +description and numerical representations. + +token mibdirs +info Specifies directories to be searched for mibs. +info Adding a '+' sign to the front of the argument appends the new +info directory to the list of directories already being searched. +info arguments: [+]directory[:directory...] +question 1 Enter the list of directories to search through for mibs + +token mibs +info Specifies a list of mibs to be searched for and loaded. +info Adding a '+' sign to the front of the argument appends the new +info mib name to the list of mibs already being searched for. +info arguments: [+]mibname[:mibname...] +question 1 Enter the list of mibs to read + +token mibfile +info Loads a particular mib file from a particualar path +info arguments: /path/to/mibfile +question 1 Enter the mib file name to read + +token showMibErrors +info Should errors in mibs be displayed when the mibs are loaded +question 1 Should errors in mibs be displayed when the mibs are loaded +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ + +token mibWarningLevel +info Should warnings about mibs be displayed when the mibs are loaded +question 1 Should warnings about mibs be displayed when the mibs are loaded +info arguments: 1|2 +validanswer 1 ^(1|2)$ + +token strictCommentTerm +info Be strict about about mib comment termination. +info Strictly follow comment rules about parsing mibs. +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ +question 1 Be strict about about mib comment termination + +token mibAllowUnderline +info Should underlines be allowed in mib symbols (illegal) +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ +question 1 Should underlines be allowed in mib symbols + +token mibReplaceWithLatest +info Force replacement of older mibs with known updated ones +question 1 Force replacement of older mibs with known updated ones +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ + diff --git a/local/snmpconf.dir/snmp-data/output b/local/snmpconf.dir/snmp-data/output new file mode 100644 index 0000000..ae3c561 --- /dev/null +++ b/local/snmpconf.dir/snmp-data/output @@ -0,0 +1,79 @@ +title Output style options +description This section allows you to control how the output of the +description various commands will be formated + +token logTimestamp +info Should timestamps be shown on the output +info arguments: (1|yes|true|0|no|false) +question 1 Should timestamps be shown on the output +validanswer 1 ^(1|yes|true|0|no|false)$ + +token printNumericEnums +info Print enums numericly or textually +info command line equivelent: -Oe +question 1 Print enums numericly +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ + +token printNumericOids +info Print OIDs numericly or textually +info command line equivelent: -On +question 1 Print enums numericly +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ + +token dontBreakdownOids +info When OIDs contain a index to a table, they are broken +info into the displayable pieces and shown to you. +info For example the oid vacmSecurityModel.0.3.119.101.115 +info is nicely broken down by +info default and the string hidden in the oid is shown +info to you as vacmSecurityModel.0."wes". This token and the -Ob +info option diables this feature and displays it as +info vacmSecurityModel.0.3.119.101.115 again. +info command line equivelent: -Ob +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ +question 1 Disable the breaking-down of OIDs? + +token escapeQuotes +info Should the quotation marks in broken down oids be escaped +info If you want to cut and paste oids that have been broken down +info into indexes and strings, this will put a backslash in front of them +info so your shell will pass them rather than interpret them. +info arguments: (1|yes|true|0|no|false) +question 1 Should the quotation marks in broken down oids be escaped +validanswer 1 ^(1|yes|true|0|no|false)$ + +token quickPrinting +info Make the output simple for quick parsing +info This option removes the equal sign and value identifies leaving +info just the oid and the value on the output for easier parsing in scripts +info command line equivelent: -Oq +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ +question 1 Make the output simple for quick parsing + +token numericTimeticks +info Print timeticks as a number and not a time-string +info command line equivelent: +info arguments: (1|yes|true|0|no|false) +question 1 Print timeticks as a number and not a time-string +validanswer 1 ^(1|yes|true|0|no|false)$ + +token suffixPrinting +info Shorten OIDs printed to the screen +info possible values: +info - 0: UCD-style. OIDs are displayed like: +info - system.sysUpTime.0 +info - 1: deletes all by the last symbolic part of the OID: +info - system.sysUpTime.0 becomes sysUpTime.0 +info - 2: is a variant of this, adding the name of the MIB +info - that defined this object: +info - system.sysUpTime.0 becomes SNMPv2-MIB::sysUpTime.0 +info - (This is the default with net-snmp v5) +info command line equivelent: 0 = -Ou, 1 = -Os, 2 = -OS +info arguments: (1|2) +question 1 Shorten OIDs (0|1|2) +validanswer 1 ^(0|1|2)$ + diff --git a/local/snmpconf.dir/snmp-data/snmpconf-config b/local/snmpconf.dir/snmp-data/snmpconf-config new file mode 100644 index 0000000..9be7d10 --- /dev/null +++ b/local/snmpconf.dir/snmp-data/snmpconf-config @@ -0,0 +1 @@ +forconffile: snmp.conf diff --git a/local/snmpconf.dir/snmpd-data/acl b/local/snmpconf.dir/snmpd-data/acl new file mode 100644 index 0000000..14f44a8 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/acl @@ -0,0 +1,36 @@ +title Access Control Setup +description This section defines who is allowed to talk to your running +description snmp agent. + +token rwuser +info a SNMPv3 read-write user +info arguments: user [noauth|auth|priv] [restriction_oid] +question 1 The SNMPv3 user that should have read-write access +question 2 The minimum security level required for that user [noauth|auth|priv, default = auth] +validanswer 2 (noauth|auth|priv|) +question 3 The OID that this community should be restricted to [if appropriate] + +token rouser +info a SNMPv3 read-only user +info arguments: user [noauth|auth|priv] [restriction_oid] +steal rwuser +question 1 Enter the SNMPv3 user that should have read-only access to the system + +token rocommunity +info a SNMPv1/SNMPv2c read-only access community name +info arguments: community [default|hostname|network/bits] [oid] +question 1 The community name to add read-only access for +question 2 The hostname or network address to accept this community name from [RETURN for all] +question 3 The OID that this community should be restricted to [RETURN for no-restriction] + +token rwcommunity +info a SNMPv1/SNMPv2c read-write access community name +info arguments: community [default|hostname|network/bits] [oid] +steal rocommunity +question 1 Enter the community name to add read-write access for + +group access_control +multiple rwuser Do you want to allow SNMPv3 read-write user based access +multiple rouser Do you want to allow SNMPv3 read-only user based access +multiple rwcommunity Do you want to allow SNMPv1/v2c read-write community access +multiple rocommunity Do you want to allow SNMPv1/v2c read-only community access diff --git a/local/snmpconf.dir/snmpd-data/basic_setup b/local/snmpconf.dir/snmpd-data/basic_setup new file mode 100644 index 0000000..28721e1 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/basic_setup @@ -0,0 +1,17 @@ +group basic_setup +message ************************************************ +message *** Beginning basic system information setup *** +message ************************************************ +subgroup system_setup Do you want to configure the information returned in the system MIB group (contact info, etc)? +message ************************************** +message *** BEGINNING ACCESS CONTROL SETUP *** +message ************************************** +subgroup access_control Do you want to configure the agent's access control? +message **************************************** +message *** Beginning trap destination setup *** +message **************************************** +subgroup trapsinks Do you want to configure where and if the agent will send traps? +message **************************************** +message *** Beginning monitoring setup *** +message **************************************** +subgroup monitoring_services Do you want to configure the agent's ability to monitor various aspects of your system? diff --git a/local/snmpconf.dir/snmpd-data/extending b/local/snmpconf.dir/snmpd-data/extending new file mode 100644 index 0000000..039b103 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/extending @@ -0,0 +1,68 @@ +title Extending the Agent +description You can extend the snmp agent to have it return information +description that you yourself define. + +token exec +info run a simple command using exec() +info arguments: [oid] name /path/to/executable arguments +question 1 The OID where the results table should be display [default=extTable] +question 2 The "name" to associate with this command when displaying the results. +question 3 The path to the program to be run. +question 4 The arguments to pass to $3 + +token pass +info Run a command that intepretes the request for an entire tree. +info The pass program defined here will get called for all +info requests below a certain point in the mib tree. It is then +info responsible for returning the right data beyond that point. +info # +info arguments: miboid program +info # +info example: pass .1.3.6.1.4.1.2021.255 /path/to/local/passtest +info # +info See the snmpd.conf manual page for further information. +info # +info Consider using "pass_persist" for a performance increase. +question 1 The OID where the script should take control of +question 2 The path to the program that should be called + +token pass_persist +info Run a persistant process that intepretes the request for an entire tree. +info The pass program defined here will get called for all +info requests below a certain point in the mib tree. It is then +info responsible for returning the right data beyond that point. +info The pass_persist scripts must be able to stay running and accept input +info from stdin. +info # +info arguments: miboid program +info # +info example: pass_persist .1.3.6.1.4.1.2021.255 /path/to/local/pass_persisttest +info # +info See the snmpd.conf manual page for further information. +steal pass + +token proxy +info Proxy requests to an external agent running somewhere else +info This passes all requests for a certain point of the mib tree to +info an external agent using snmp requests and then returning the +info results to the caller that spoke to our agent. +info arguments: [snmpcmd args] host oid [remoteoid] +question 1 Enter the "snmpcmd" arguments that specify how to talk to the remote host +question 2 The host you want to pass the requests to +qusetion 3 The oid that we should pass beyond +question 4 The oid of the remote site that we should talk to if different from $3 + +token sh +info run a simple command using system() +info arguments: [oid] name command arguments +info similar to exec, but implemented using system() instead of exec() +info # +info For security reasons, exec should be preferred. +steal exec + +token dlmod +info dynamically extend the agent using a shared-object +info arguments: module-name module-path +question 1 Enter the name of the module +question 2 Enter the path to the $1 module + diff --git a/local/snmpconf.dir/snmpd-data/monitor b/local/snmpconf.dir/snmpd-data/monitor new file mode 100644 index 0000000..9458793 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/monitor @@ -0,0 +1,72 @@ +title Monitor Various Aspects of the Running Host +description The following check up on various aspects of a host. + +token proc +info Check for processes that should be running. +info # proc NAME [MAX=0] [MIN=0] +info # +info # NAME: the name of the process to check for. It must match +info # exactly (ie, http will not find httpd processes). +info # MAX: the maximum number allowed to be running. Defaults to 0. +info # MIN: the minimum number to be running. Defaults to 0. +info # +info The results are reported in the prTable section of the UCD-SNMP-MIB tree +info Special Case: When the min and max numbers are both 0, it assumes +info you want a max of infinity and a min of 1. +question 1 Name of the process you want to check on +question 2 Maximum number of processes named '$1' that should be running [default = 0] +question 3 Minimum number of processes named '$1' that should be running [default = 0] + +token disk +info Check for disk space usage of a partition. +info The agent can check the amount of available disk space, and make +info sure it is above a set limit. +info +info # disk PATH [MIN=100000] +info # +info # PATH: mount path to the disk in question. +info # MIN: Disks with space below this value will have the Mib's errorFlag set. +info # Can be a raw integer value (units of kB) or a percentage followed by the % +info # symbol. Default value = 100000. +info # +info The results are reported in the dskTable section of the UCD-SNMP-MIB tree +question 1 Enter the mount point for the disk partion to be checked on +question 2 Enter the minimum amount of space that should be available on $1 + +token load +info Check for unreasonable load average values. +info Watch the load average levels on the machine. +info +info # load [1MAX=12.0] [5MAX=12.0] [15MAX=12.0] +info # +info # 1MAX: If the 1 minute load average is above this limit at query +info # time, the errorFlag will be set. +info # 5MAX: Similar, but for 5 min average. +info # 15MAX: Similar, but for 15 min average. +info # +info The results are reported in the laTable section of the UCD-SNMP-MIB tree +question 1 Enter the maximum allowable value for the 1 minute load average +question 2 Enter the maximum allowable value for the 5 minute load average +question 3 Enter the maximum allowable value for the 15 minute load average +validanswer 1 ^[\d\.]+$ +validanswer 2 ^([\d\.]+|)$ +validanswer 3 ^([\d\.]+|)$ + +token file +info Check on the size of a file. +info Display a files size statistics. +info If it grows to be too large, report an error about it. +info +info # file /path/to/file [maxsize_in_kilobytes] +info # +info # if maxsize is not specified, assume only size reporting is needed. +info # +info The results are reported in the fileTable section of the UCD-SNMP-MIB tree +question 1 Enter the path to the file you wish to monitor +question 2 Enter the maximum size (in kilobytes) allowable for $1 + +group monitoring_services +multiple proc Do you want to configure the agents ability to monitor processes? +multiple disk Do you want to configure the agents ability to monitor disk space? +multiple load Do you want to configure the agents ability to monitor load average? +multiple file Do you want to configure the agents ability to monitor file sizes? diff --git a/local/snmpconf.dir/snmpd-data/operation b/local/snmpconf.dir/snmpd-data/operation new file mode 100644 index 0000000..8a286e5 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/operation @@ -0,0 +1,32 @@ +title Agent Operating Mode +description This section defines how the agent will operate when it +description is running. + +token master +info Should the agent operate as a master agent or not. +info Currently, the only supported master agent type for this token +info is "agentx". +info # +info arguments: (on|yes|agentx|all|off|no) +question 1 Should the agent run as a AgentX master agent? +validanswer 1 ^(on|yes|agentx|all|off|no)$ + +token agentuser +info The system user that the agent runs as. +info arguments: name|#uid +question 1 Enter the name of the user that you want the agent to run as + +token agentgroup +info The system group that the agent runs as. +info arguments: group|#GID +question 1 Enter the name of the group that you want the agent to run as + +token agentaddress +info The IP address and port number that the agent will listen on. +info By default the agent listens to any and all traffic from any +info interface on the default SNMP port (161). This allows you to +info specify which address, interface, transport type and port(s) that you +info want the agent to listen on. Multiple definitions of this token +info are concatenated together (using ':'s). +info arguments: [transport:]port[@interface/address],... +question 1 Enter the port numbers, etc that you want the agent to listen to diff --git a/local/snmpconf.dir/snmpd-data/snmpconf-config b/local/snmpconf.dir/snmpd-data/snmpconf-config new file mode 100644 index 0000000..49d06bb --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/snmpconf-config @@ -0,0 +1 @@ +forconffile: snmpd.conf diff --git a/local/snmpconf.dir/snmpd-data/system b/local/snmpconf.dir/snmpd-data/system new file mode 100644 index 0000000..4cd09b9 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/system @@ -0,0 +1,43 @@ +title System Information Setup +description This section defines some of the information reported in +description the "system" mib group in the mibII tree. + +token syslocation +info The [typically physical] location of the system. +info Note that setting this value here means that when trying to +info perform an snmp SET operation to the sysLocation.0 variable will make +info the agent return the "notWritable" error code. IE, including +info this token in the snmpd.conf file will disable write access to +info the variable. +info arguments: location_string +question 1 The location of the system + +token syscontact +info The contact information for the administrator +info Note that setting this value here means that when trying to +info perform an snmp SET operation to the sysContact.0 variable will make +info the agent return the "notWritable" error code. IE, including +info this token in the snmpd.conf file will disable write access to +info the variable. +info arguments: contact_string +question 1 The contact information + +token sysservices +info The proper value for the sysServices object. +info arguments: sysservices_number +question 1 does this host offer physical services (eg, like a repeater) [answer 0 or 1] +question 2 does this host offer datalink/subnetwork services (eg, like a bridge) +question 3 does this host offer internet services (eg, supports IP) +question 4 does this host offer end-to-end services (eg, supports TCP) +question 7 does this host offer application services (eg, supports SMTP) +validanswer 1 ^(0|1)$ +validanswer 2 ^(0|1)$ +validanswer 3 ^(0|1)$ +validanswer 4 ^(0|1)$ +validanswer 7 ^(0|1)$ +line eval $1*1 + $2*2 + $3*4 + $4*8 + $7*64 + +group system_setup +single syslocation +single syscontact +single sysservices Do you want to properly set the value of the sysServices.0 OID (if you don't know, just say no)? diff --git a/local/snmpconf.dir/snmpd-data/trapsinks b/local/snmpconf.dir/snmpd-data/trapsinks new file mode 100644 index 0000000..cc29b66 --- /dev/null +++ b/local/snmpconf.dir/snmpd-data/trapsinks @@ -0,0 +1,46 @@ +title Trap Destinations +description Here we define who the agent will send traps to. + +token trapsink +info A SNMPv1 trap receiver +info arguments: host [community] [portnum] +question 1 A host name that should receive the trap +question 2 The community to be used in the trap sent [optional] +question 3 The port number the trap should be sent to [optional] +validanswer 3 ^(\d+|)$ + +token trap2sink +info A SNMPv2c trap receiver +info arguments: host [community] [portnum] +steal trapsink + +token informsink +info A SNMPv2c inform (acknowledged trap) receiver +info arguments: host [community] [portnum] +steal trapsink + +token trapsess +info A generic trap receiver defined using snmpcmd style arguments. +info Read the snmpcmd manual page for further information. +info arguments: [snmpcmdargs] host +question 1 Specify the command line snmpcmd style options for this host +question 2 Specify the host name + +token trapcommunity +info Default trap sink community to use +info arguments: community-string +question 1 The default community name to use when sending traps + + +token authtrapenable +info Should we send traps when authentication failures occur +info arguments: 1 | 2 (1 = yes, 2 = no) +question 1 Should traps be sent when authentication failures occur? (1=yes, 2=no) +validanswer 1 ^(1|2)$ + +group trapsinks +single authtrapenable Do you want the agent to send snmp traps on snmp authentication failures? +single trapcommunity +multiple informsink Do you want the agent to send snmpv2c informs to a trap receiver +multiple trap2sink Do you want the agent to send snmpv2c traps to a trap receiver +multiple trapsink Do you want the agent to send snmpv1 traps to a trap receiver diff --git a/local/snmpconf.dir/snmptrapd-data/authentication b/local/snmpconf.dir/snmptrapd-data/authentication new file mode 100644 index 0000000..6591b2d --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/authentication @@ -0,0 +1,8 @@ +title Authentication options +description Authentication options + +token ignoreAuthFailure +info Ignore authentication failure traps +info arguments: (1|yes|true|0|no|false) +question 1 Ignore authentication failure traps +validanswer 1 ^(1|yes|true|0|no|false) diff --git a/local/snmpconf.dir/snmptrapd-data/formatting b/local/snmpconf.dir/snmptrapd-data/formatting new file mode 100644 index 0000000..5b824b2 --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/formatting @@ -0,0 +1,15 @@ +title Output formatting for traps received. +description Output from snmptrapd is formatted according to the +description rules defined by the formatting configuration directives. + +token format1 +info How SNMPv1 traps are formatted. +info See the snmptrapd.conf manual page for format string details. +info arguments: formatstring +question 1 The format specification string for SNMPv1 traps + +token format2 +info How SNMPv2 and SNMPv3 traps are formatted. +info See the snmptrapd.conf manual page for format string details. +info arguments: formatstring +question 1 The format specification string for SNMPv2 and SNMPv3 traps. diff --git a/local/snmpconf.dir/snmptrapd-data/logging b/local/snmpconf.dir/snmptrapd-data/logging new file mode 100644 index 0000000..81abe37 --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/logging @@ -0,0 +1,26 @@ +title Logging options +description Logging options + +token doNotLogTraps +info Prevent traps from being logged +info Useful when you only want to use traphandles +info arguments: (1|yes|true|0|no|false) +question 1 Should traps be logged +validanswer 1 ^(1|yes|true|0|no|false) + +token logOption +info Set options controlling where to log to +info See -L options in the snmptrapd.conf man page +question 1 Logging options + +token outputOption +info Toggle options controlling output display +info See -O options in the snmptrapd.conf man page +question 1 Logging options + +token printEventNumbers +info Print event numbers (rising/falling alarm, etc.) +info arguments: (1|yes|true|0|no|false) +question 1 Print event numbers +validanswer 1 ^(1|yes|true|0|no|false) + diff --git a/local/snmpconf.dir/snmptrapd-data/runtime b/local/snmpconf.dir/snmptrapd-data/runtime new file mode 100644 index 0000000..5a342c2 --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/runtime @@ -0,0 +1,13 @@ +title Runtime options +description Runtime options + +token doNotFork +info Do not fork from the shell +question 1 Do not fork from the shell +info arguments: (1|yes|true|0|no|false) +validanswer 1 ^(1|yes|true|0|no|false)$ + +token pidFile +info Store Process ID in file +info arguments: PID file +question 1 PID file diff --git a/local/snmpconf.dir/snmptrapd-data/snmpconf-config b/local/snmpconf.dir/snmptrapd-data/snmpconf-config new file mode 100644 index 0000000..6f1e4f7 --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/snmpconf-config @@ -0,0 +1 @@ +forconffile: snmptrapd.conf diff --git a/local/snmpconf.dir/snmptrapd-data/traphandle b/local/snmpconf.dir/snmptrapd-data/traphandle new file mode 100644 index 0000000..384364e --- /dev/null +++ b/local/snmpconf.dir/snmptrapd-data/traphandle @@ -0,0 +1,17 @@ +title Trap Handlers +description Here we define what programs are run when a trap is +description received by the trap receiver. + +token traphandle +info When traps are received, a program can be run. +info When traps are received, the list of configured trap +info handles is consulted and any configured program is run. +info If no handler is found, any handler with "default" as the +info traphandle type is run instead. The information contained +info in trap is passed to the program via standard input (see +info the snmptrapd.conf manual page for details). +info # +info arguments: oid|"default" program args +question 1 The oid of the trap you want to handle. +question 2 The program you want to run If the program is a script, specify the script program first (ie /bin/sh /path/to/script). +question 3 Arguments that you want passed to the program diff --git a/local/snmpdump.pl b/local/snmpdump.pl new file mode 100755 index 0000000..0220beb --- /dev/null +++ b/local/snmpdump.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl +# +# Reformat 'snmpcmd -d' style raw dump output +# into something a little easier to understand. +# + + +sub parse_dump { + # + # Basic formatting technique: + # Display the contents of each nested SEQUENCE + # indented from the enclosing level. + # Individual data fields are all on one line + # + my @data = @_; + my $indent = shift( @data ); + my $datalen = shift( @data ); + + while ( $datalen > 0 ) { + my ($tag, $tlen, $tmp); + my ($tag1, $tag2 ); + $tag = shift( @data ); + $tmp = shift( @data ); + $tlen = hex($tmp); + # + # Handle 2-octet lengths + if ( $tlen >= 128 ) { + $tlen -= 128; + $tmp = shift( @data ); + $tlen += hex($tmp); + } + $datalen -= ($tlen + 2 ); + + $tag1 = substr($tag, 0, 1); + $tag2 = substr($tag, 1, 1); + + # + # Sequence-based tags - display and indent + # + if ( $tag1 eq 3 ) { + print " "x$indent, "$tag $tmp\n"; + parse_dump( $indent+3, $tlen, @data ); + } + elsif ( $tag1 eq "A" ) { + print " "x$indent, "$tag $tmp\n"; + parse_dump( $indent+3, $tlen, @data ); + } + + # + # Leaf-data tags - just display + # + else { + $val = ""; + while ( $tlen > 0 ) { + $val .= " "; + $val .= shift( @data ); + $tlen--; + } + if ( $tag1 eq "0" ) { # leaf data + print " "x$indent, "$tag $tmp$val\n"; + } + elsif ( $tag1 eq "8" ) { # exceptions + print " "x$indent, "$tag $tmp$val\n"; + } + else { # unknown + print " "x$indent, "$tag $tmp$val\n"; + } + } + } +} + +$inpacket=0; +$rawdump=""; + +while (<>) { + if ( $inpacket ) { + # + # Strip off the extraneous junk, and join + # the raw dump output into a single line + # + if ( /^[0-9]*: / ) { + chomp; + s/^[0-9]*: //; + s/ .*$//; + s/ / /g; + $rawdump = "$rawdump $_"; + } else { + # + # Once this line is complete, display the + # dump in a vaguely sensible layout + # + @rawdata = split( " ", $rawdump ); + parse_dump( 3, $#rawdata, @rawdata ); + $inpacket=0; + $rawdump=""; + } + } else { + # + # Pass everything else through untouched + # + print; + if ( /^Sending / || /^Received / ) { + $inpacket=1; + $rawdump=""; + } + } +} diff --git a/local/tkmib b/local/tkmib new file mode 100755 index 0000000..aea22f3 --- /dev/null +++ b/local/tkmib @@ -0,0 +1,994 @@ +#!/usr/bin/perl +#!/usr/bin/perl -w + +require 5; + +# attempt to determine if they have the proper modules installed. + +# SNMP +my $havesnmp = eval {require SNMP;}; + +# the Tk packages + +my $havetk = eval {require Tk; + require Tk::Table; + require Tk::HList; + require Tk::FileSelect; + require Tk::Dialog;}; +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/ . The perl module is contained in +the perl/SNMP directory. See the INSTALL file there for +instructions. +"; +} + +if (!$havetk) { + print " +ERROR: You don't have the Tk module installed. You should be able to +install this by running (as root): + + perl -MCPAN -e 'install Tk' +"; +} + +if (!$havetk || !$havesnmp) { + print "\n"; + exit; +} + +if ($havetk) { + # Tk doesn't seem to like require so we force use here. + eval {import Tk; + import Tk::Table; + import Tk::HList; + import Tk::FileSelect; + import Tk::Dialog; + import SNMP;}; +} + +use Getopt::Std; +use Data::Dumper; + +$host = 'localhost'; +$OID = '.1.3.6.1'; +$opts{'f'} = $ENV{'HOME'} . "/.snmp/tkmibrc"; + +getopts("hp:v:a:A:x:X:n:u:l:r:t:o:c:Cf:", \%opts); + +# default session options +print "setting opts\n"; +%session_opts = ( + 'Community' => "public", + 'RemotePort' => 161, + 'Timeout' => 5000000, + 'Retries' => 5, + 'Version' => 1, + 'AuthProto' => 'MD5', + 'PrivProto' => 'DES', + 'AuthPass' => '', + 'PrivPass' => '', + 'Context' => '', + 'SecName' => 'initial', + 'SecLevel' => 'authNoPriv', + ); + +sub usage { + print " +tkmib [-C] [-o OID] [SNMPCMD arguments] [host] + -f CONFIG_FILE load CONFIG_FILE after starting up. (default: ~/.snmp/tkmibrc) + (use -f /dev/null to not read one). + + See the snmpcmd manual page for related SNMPCMD arguments. (Not all + options are currently supported.) +"; + exit(); +} + +usage() if ($opts{'h'}); + +# initialize defaults, may be overridden by config file below +@displayInfo=qw(type access status units hint moduleID enums indexes); +@saveoptions = ('displayoidas', 'writecolor', 'graphtime', 'graphdelta'); +$displayoidas='full'; +$writecolor = "blue"; +$graphtime=5; +$graphdelta=1; +foreach $i (@displayInfo) { + $displayInfoStates{$i} = 1; +} + + +# source config file +do $opts{'f'} if ($opts{'f'} && -f $opts{'f'}); + +$session_opts{'UseLongNames'} => 1; +$session_opts{'RemotePort'} = $opts{'p'} if ($opts{'p'}); +$session_opts{'Community'} = $opts{'c'} if ($opts{'c'}); +$session_opts{'Version'} = $opts{'v'} if ($opts{'v'}); +$session_opts{'AuthProto'} = $opts{'a'} if ($opts{'a'}); +$session_opts{'AuthPass'} = $opts{'A'} if ($opts{'A'}); +$session_opts{'PrivProto'} = $opts{'x'} if ($opts{'x'}); +$session_opts{'PrivPass'} = $opts{'X'} if ($opts{'X'}); +$session_opts{'Context'} = $opts{'n'} if ($opts{'n'}); +$session_opts{'SecName'} = $opts{'u'} if ($opts{'u'}); +$session_opts{'SecLevel'} = $opts{'l'} if ($opts{'l'}); +$session_opts{'Retries'} = $opts{'r'} if ($opts{'r'}); +$session_opts{'Timeout'} = $opts{'t'} if ($opts{'t'}); + +$host = shift if ($#ARGV > -1); +$session_opts{'Community'} = shift if ($#ARGV > -1); + +@graphcolors=qw(blue red green yellow purple); + +# initialize SNMP module +$SNMP::save_descriptions=1; +$SNMP::use_long_names=1; +$SNMP::use_enums=1; +$SNMP::verbose = 1; +my $tmpbd = 1; + +$top = MainWindow->new(); +$top->title("tkmib"); + +#Menus +$MenuFrame = $top->Frame(-relief => "raised",-borderwidth => 2); +$MenuFrame->pack(-fill => "x",-expand => 1); +$FileMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "File", + -menuitems => + [ +# [Button => "Save Output", -command => [\&saveOutput]], + [Button => "Quit", -command => [\&exit]] + ]); +$FileMenuBut->pack(-side => 'left'); + +$MibMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "Mib", + -menuitems => + [[Button => "Find a mib node", + -command => sub { my $var; + entryBox("Find a Mib Node", + "Enter a mib node name to search for:", + \$var, \&findANode );}], + [Button => "Load a New Mib File", -command => [\&loadNewMibFile]], + [Button => "Load a New Mib Module", + -command => sub { my $var; + entryBox("Load a Module", + "Enter a SNMP MIB module name to load:", + \$var, \&loadIt);}] + ]); +$MibMenuBut->pack(-side => 'left'); + +$OptMenuBut = $MenuFrame->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -text => "Options", + -menuitems => + [[Cascade => "~Display", -menuitems => + [ + [Cascade => "~MIB Information"], + [Cascade => "~OID Display", -menuitems => + [ + [Radiobutton => 'full', -variable => \$displayoidas], + [Radiobutton => 'numeric', -variable => \$displayoidas], + [Radiobutton => 'short', -variable => \$displayoidas], + [Radiobutton => 'module', -variable => \$displayoidas] + ] + ], + [Button => "Writable Color", + -command => [\&entryBox,"Writable Color", + "Color for writable objects:", + \$writecolor]] + ]], + [Cascade => "Use SNMP Version", -menuitems => + [ + [Radiobutton => '1', -variable => \$session_opts{'Version'}], + [Radiobutton => '2c', -variable => \$session_opts{'Version'}], + [Radiobutton => '3', -variable => \$session_opts{'Version'}] + ] + ], # ends version number specification + [Cascade => "SNMPv1/2c options", -menuitems => + [ + [Button => "Community Name", + -command => [\&entryBox,"Community Name", "Community name to use:", + \$session_opts{'Community'}]] + ] + ], + [Cascade => "SNMP3 options", -menuitems => + [ + [Button => "Security Name", + -command => [\&entryBox,"Security Name", "Security Name to use:", + \$session_opts{'SecName'}]], + [Cascade => "Security Level", -menuitems => + [ + [Radiobutton => 'noAuthNoPriv', + -variable => \$session_opts{'SecLevel'}], + [Radiobutton => 'authNoPriv', + -variable => \$session_opts{'SecLevel'}], + [Radiobutton => 'authPriv', + -variable => \$session_opts{'SecLevel'}] + ] + ], + [Button => "Authentication Passphrase", + -command => [\&entryBox,"Authentication Passphrase", + "Authentication Passphrase to use:", + \$session_opts{'AuthPass'}]], + [Cascade => "Authentication Type", -menuitems => + [ + [Radiobutton => 'MD5', + -variable => \$session_opts{'AuthProto'}], + [Radiobutton => 'SHA', + -variable => \$session_opts{'AuthProto'}], + ] + ], + [Button => "Privacy Passphrase", + -command => [\&entryBox,"Privacy Passphrase", + "Privacy Passphrase to use:", + \$session_opts{'PrivPass'}]], + [Cascade => "Privacy Type", -menuitems => + [ + [Radiobutton => 'DES', + -variable => \$session_opts{'PrivProto'}], + ] + ], + ] + ], + [Button => "Time between graph polls", + -command => sub { entryBox("graph polls", "Time between graph polls:", + \$graphtime);}], + [Button => "Port number", + -command => sub { entryBox("Port Number", "SNMP Port number to use:", + \$session_opts{'RemotePort'});}], + [Button => "TimeOut", + -command => sub { entryBox("Time Out", "Timeout for SNMP requests:", + \$session_opts{'Timeout'});}], + [Button => "Retries", + -command => sub { entryBox("Retries", + "Number of Times to Retransmit Requests:", + \$session_opts{'Retries'});}], + [Button => "Save Options", + -command => \&save_options] + ])->pack(-side => 'left'); + +$tmp = $OptMenuBut->cget(-menu); +$OptMenuWidgets = $tmp->entrycget("Display", -menu); +$OptMenuWidgets = $OptMenuWidgets->entrycget("MIB Information", -menu); + +$hlist=$top->Scrolled(qw(HList -itemtype imagetext -browsecmd main::showInfo + -command main::showChildren -width 80 -height 15)); +$hlist->pack(-side => 'top', -expand => 1, -fill => 'both'); +my $sFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd); +$sFrame->pack(-side => 'top', -fill => 'x'); +$sFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => 'OID: ', -relief => 'raised', -borderwidth => $tmpbd) + ->pack(-side => 'left'); +$mibOID = $sFrame->Entry(-textvariable => \$OID, -relief => 'flat', -width => 40); +$mibOID->pack(-side => 'left'); +$mibTextOID = $sFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => ''); +$mibTextOID->pack(-side => 'right'); + +$dispFrame=$top->Frame(-relief => 'raised', -borderwidth => $tmpbd); +$dispFrame->pack(-side => 'top', -fill =>'x'); +for($i=0;$i<= $#displayInfo;$i++) { + createRow($i) if ($displayInfoStates{$displayInfo[$i]}); + optionalWidget($i,$OptMenuWidgets, \$displayInfoStates{$displayInfo[$i]}); +} + +$descrFrame=$top->Frame(-relief => 'raised', -borderwidth => $tmpbd); +$descrFrame->pack(-side => 'top', -fill =>'x'); +$descrFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => 'Description:', -anchor => 'w')->pack(-side => 'top', + -fill => 'x'); +$descr = $descrFrame->Scrolled(qw(Text -width 80 -height 4)); +$descr->pack(-side => 'top', -fill => 'x'); + +$bFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd); +$bFrame->pack(-side => 'top', -fill => 'x'); +$hostEntry = $bFrame->Entry(-textvariable => \$host, -width => 12); +$hostEntry->pack(-side => 'left'); +$bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'graph', -command => \&snmpgraph)->pack(-side => 'right'); +$tablebutton = $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'table', -command => \&snmptable); +$tablebutton->pack(-side => 'right'); +$bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'walk', -command => \&snmpwalk)->pack(-side => 'right'); +$bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'getnext', -command => \&snmpgetnext)->pack(-side => 'right'); +$bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'get', -command => \&snmpget)->pack(-side => 'right'); +$bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'set', -command => [\&snmpsetbegin, 'OID'])->pack(-side => 'right'); +$stopBut = $bFrame->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'stop', -command => sub { stop(1) }, + -state => 'disabled'); +$stopBut->pack(-side => 'right'); +$oFrame = $top->Frame(-borderwidth => $tmpbd, -relief => 'raised'); +$oFrame->pack(-side => 'top', -fill => 'both'); +$output = $oFrame->Scrolled(qw(Text -width 80 -height 14)); +$output->pack(-side => 'top', -fill => 'both', -expand => 1); + +$tmpFrame = $top->Frame(-relief => 'raised', -borderwidth => $tmpbd); +$tmpFrame->pack(-side => 'top', -fill => 'x'); +$tmpFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -text => "Status: ", -anchor => 'w') +# -relief => 'raised', -borderwidth => $tmpbd) + ->pack(-side => 'left'); +$status = $tmpFrame->Label(-pady => $tmpbd, -padx => $tmpbd, -anchor => 'w'); +$status->pack(-side => 'left', -fill => 'x'); + +# initialize the browser +foreach $i (qw(.1 .1.3 .1.3.6 .1.3.6.1)) { + addMibOID($i); +} +showChildren("$OID"); +if (defined($opts{'o'})) { + findANode($opts{'o'}); +} + +MainLoop(); + +sub insertresult { + my $oid = shift; + my $val = shift; + $oid = $OID if ($oid eq "OID"); + $output->insert('end', $oid, "oid:$oid"); + $output->tagBind("oid:$oid", '<1>', [sub{shift; + my $oid = shift; + findANode($oid); + my $tag = SNMP::translateObj($oid); + showInfo($tag);},$oid]); + $output->insert('end', " = "); + my $mib = $SNMP::MIB{format_oid("$oid",'numeric')}; + $output->insert('end', $val, "value:$oid"); + if ($mib->{'access'} =~ /(Write|Create)/) { + $output->tagConfigure("value:$oid", -foreground => $writecolor); + $output->tagBind("value:$oid", '<1>', [sub{shift; + my $oid = shift; + my $value = shift; + snmpsetmaybebegin($oid, $value); + findANode($oid); + my $tag = SNMP::translateObj($oid); + showInfo($tag);},format_oid($oid,'full'), $val]); + } + $output->insert('end', "\n"); +} + +sub insertvar { + my $var = shift; + my $name = get_oid($var); + + insertresult($name,"$var->[$SNMP::Varbind::val_f]"); +} + +sub snmpsetup { + my $oid = $OID; + my $tag = SNMP::translateObj($oid); + my $sess = new SNMP::Session(DestHost => $host, %session_opts); + my $var = new SNMP::Varbind([$oid]); + if (!defined($var)) { + print "ack: $@ $SNMP::ErrorStr $!\n"; + } + stop(0); + initText(); + $oid = "." . $oid if ($oid !~ /^\./); + return ($oid, $sess, $var); +} + +sub initText { + if (ref($output) eq "Tk::Frame" && defined($$output{'_#text'})) { + $output->delete('0.0','end'); + } else { + $output->destroy(); + $output = $oFrame->Scrolled(qw(Text -width 80 -height 14)); + $output->pack(-side => 'top', -fill => 'both', -expand => 1); + } +} + +sub initTable { + $output->destroy(); + $oFrame->packPropagate(0); + $output = $oFrame->Table(-columns => shift, -width => 80, -height => 14, + -fixedrows => 2, -fixedcolumns => 1); + $output->pack(-side => 'top', -fill => 'both', -expand => 1); +} + +sub initCanvas { + $output->destroy(); + $oFrame->packPropagate(0); + $output = $oFrame->Scrolled(qw(Canvas -width 80c -height 14c)); + $output->pack(-side => 'top', -fill => 'both', -expand => 1); +} + +sub snmpget { + (my $oid, my $sess, my $var) = snmpsetup(); + $status->configure(-text => "getting: $host $community $oid"); + $top->update(); + my $val = $sess->get($var); + if ($sess->{ErrorStr}) { + $status->configure(-text => $sess->{ErrorStr}); + } else { + insertvar($var); + $status->configure(-text => ""); + } +} + +sub snmpsetbegin { + my $startoid = shift; + my $startval = shift; + my $setwin = MainWindow->new(); + $setwin->title("SNMP set"); + my $varswin = $setwin->Frame(-relief => "raised",-borderwidth => $tmpbd); + my $vars = new SNMP::VarList; + $varswin->pack(-side => 'top'); + my $buttons = $setwin->Frame(-relief => "raised")->pack(-side => 'top', -fill => "x",-expand => 1); + $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Add a varbind', -command => [\&snmpsetbegin_addvar, $vars, $varswin, 'OID'])->pack(-side => 'left', -fill => "x",-expand => 1); + $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'perform set', -command => [\&snmpsetbegin_ok, $vars, $setwin, $varswin])->pack(-side => 'left'); + $buttons->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Cancel', -command => [sub { my $widget = shift; $varswin = shift; if ($setmain == $varswin) { $setmain = undef; } $widget->destroy();}, $setwin, $varswin])->pack(-side => 'right'); + if ($startoid ne "") { + snmpsetbegin_addvar($vars, $varswin, $startoid, $startval); + } + if (!$setmain) { + $setmain = $varswin; + $setvars = $vars; + } +} + +sub make_enum_button { + my $win = shift; + my $var = shift; + my @objs; + foreach my $i (@_) { + push @objs,[Radiobutton => $i, -variable => $var]; + } + return $win->Menubutton(-pady => $tmpbd, -padx => $tmpbd, -textvariable => $var, + -relief => raised, + -menuitems => \@objs); +} + +sub snmpsetmaybebegin { + my ($oid, $val) = @_; + if ($setmain) { + snmpsetbegin_addvar($setvars, $setmain, $oid, $val); + } else { + snmpsetbegin($oid, $val); + } +} + + +sub snmpsetbegin_addvar { + my ($vars, $place, $oid, $val) = @_; + $oid = $OID if ($oid eq "OID"); + my $mib = $SNMP::MIB{format_oid("$oid",'numeric')}; + my $var = new SNMP::Varbind([$oid, '', $val, $mib->{'type'} || 'INTEGER']); + push @$vars,$var; + my $frame = $place->Frame(); + $frame->Entry(-textvariable => \$var->[0], -width => 20)->pack(-side => 'left'); + make_enum_button($frame, \$var->[3], qw(OBJECTID OCTETSTR INTEGER NETADDR IPADDR COUNTER COUNTER64 GAUGE UINTEGER TICKS OPAQUE NULL))->pack(-side => 'left'); + if (ref($mib->{'enums'}) eq HASH && scalar(keys(%{$mib->{'enums'}})) > 0) { + make_enum_button($frame, \$var->[2], keys(%{$mib->{'enums'}}))->pack(-side => 'left'); + } else { + $frame->Entry(-textvariable => \$var->[2])->pack(-side => 'left'); + } + $frame->pack(-expand => 1, -fill => 'x'); +} + +sub snmpsetbegin_ok { + my ($vars, $win, $frame) = @_; + snmpset($vars); + $setmain = undef if ($setmain == $frame); + $win->destroy(); +} + +sub snmpset { + my $vars = shift; + (my $oid, my $sess, my $var) = snmpsetup(); + $status->configure(-text => "setting: $host -> " . Dumper($vars) . "\n"); + $top->update(); + my $val = $sess->set($vars); + if ($sess->{ErrorStr}) { + $output->insert('end', "Set failed.\nReason: $sess->{ErrorStr}"); + $status->configure(-text => $sess->{ErrorStr}); + } else { + foreach my $i (@$vars) { + insertvar($i); + } + $status->configure(-text => ""); + } +} + +sub snmpgetnext { + (my $oid, my $sess, my $var) = snmpsetup(); + $status->configure(-text => "get next: $host $community $oid"); + $top->update(); + my $val = $sess->getnext($var); + if ($sess->{ErrorStr}) { + $status->configure(-text => $sess->{ErrorStr}); + } else { + insertvar($var); + $status->configure(-text => ""); + } +} + +sub snmpwalk { + (my $oid, my $sess, my $var) = snmpsetup(); + $status->configure(-text => "walking: $host $community $oid"); + $top->update(); + while (!$sess->{ErrorStr} && !$stopit) { + my $val = $sess->getnext($var); + last if (!defined($var->tag) || + $sess->{ErrorStr} || + $val eq "ENDOFMIBVIEW" || + !is_in_subtree($oid, $var->tag . "." . $var->iid)); + insertvar($var); + $top->update(); + } + if ($sess->{ErrorStr}) { + $status->configure(-text => $sess->{ErrorStr}); + $output->insert('end',"$sess->{ErrorStr} ($sess->{ErrorNum})\n"); + } else { + $status->configure(-text => ""); + } + stop(1); +} + +sub snmptable { + (my $oid, my $sess, my $var) = snmpsetup(); + $status->configure(-text => "collecting data: $host $community $oid"); + $top->update(); + my (%tb, @tags, @index, %tboids); + while (!$sess->{ErrorStr} && !$stopit) { + my $val = $sess->getnext($var); + last if (!defined($var->tag) || + $sess->{ErrorStr} || + $val eq "ENDOFMIBVIEW" || + !is_in_subtree($oid, $var->tag . "." . $var->iid)); + $newoid = "$var->[$SNMP::Varbind::tag_f].$var->[$SNMP::Varbind::iid_f]"; + insertvar($var); + $top->update(); + $newoid =~ /([^\.]+)\.([0-9\.]+)$/; + if (!grep(/$1/,@tags)) { + push @tags,$1; + } + if (!grep(/$2/,@index)) { + push @index,$2; + } + $tb{$2}{$1} = $var->val; +# $tboids{$2}{$1} = $var->tag; + $tboids{$2}{$1} = $newoid; + } + initTable($#tags+1); + for(my $k=0;$k <= $#tags;$k++) { + $output->put(1,$k+2,$tags[$k]); + } + $output->put(1,1,"Index"); + for(my $i=0;$i <= $#index;$i++) { + $output->put($i+2,1,$index[$i]); + } + for(my $i=0;$i <= $#index; $i++) { + for(my $k=0;$k <= $#tags;$k++) { + my $mib = $SNMP::MIB{format_oid("$tboids{$index[$i]}{$tags[$k]}",'numeric')}; + if ($mib->{'access'} =~ /(Write|Create)/) { + $output->put($i+2,$k+2,$output->Button(-fg => $writecolor, -pady => $tmpbd, -padx => $tmpbd, -text => $tb{$index[$i]}{$tags[$k]}, -command => [\&snmpsetmaybebegin, $tboids{$index[$i]}{$tags[$k]}, $tb{$index[$i]}{$tags[$k]}], -padx => 0, -pady => 0)); + } else { + $output->put($i+2,$k+2,$tb{$index[$i]}{$tags[$k]}); + } + } + } + $status->configure(-text => ""); + stop(1); +} + +sub snmpgraph { + ($graphoid, $graphsess, my $graphvar) = snmpsetup(); + $top->update(); + %graphtb = (); + @graphvars = (); + initCanvas(); + $gcount=0; + $max=-1; + $min=2**32-1; + updateGraph(); + $output->repeat($graphtime*1000, \&updateGraph); +} + +sub updateGraph() { + $status->configure(-text => "collecting data: $host $community $graphoid"); + my $oid = $graphoid; + my $tag = SNMP::translateObj($graphoid,0); + my $var = new SNMP::Varbind([$oid]); + $graphsess->{ErrorStr} = ""; + while (!$graphsess->{ErrorStr} && !$stopit) { + my $val = $graphsess->getnext($var); + if ($#graphvars == -1 && SNMP::translateObj($var->tag) !~ /^$oid/) { + # if an exact oid, do a get instead. + $var = new SNMP::Varbind([$oid]); + $val = $graphsess->get($var); + } + if ($graphsess->{ErrorStr} || + !defined($var->tag) || + SNMP::translateObj($var->tag) !~ /^$oid/) { + last; + } + my $newoid = SNMP::translateObj("$var->[$SNMP::Varbind::tag_f].$var->[$SNMP::Varbind::iid_f]"); + $top->update(); + $newoid =~ /$oid\.([0-9\.]+)$/; + if (defined($1)) { + if (!grep(/$1/,@graphvars)) { + push @graphvars,$1; + } + if ($graphdelta) { + if ($gcount > 0) { + $graphtb{$1}[$gcount-1] = $var->val - $prev{$1}; + } + $prev{$1} = $var->val; + } else { + $graphtb{$1}[$gcount] = $var->val; + } + $max = $graphtb{$1}[$#{$graphtb{$1}}] + if ($#{$graphtb{$1}} >= 0 && + $graphtb{$1}[$#{$graphtb{$1}}] > $max); + $min = $graphtb{$1}[$#{$graphtb{$1}}] + if ($#{$graphtb{$1}} >= 0 && + $graphtb{$1}[$#{$graphtb{$1}}] < $min); + } + } + if ($gcount > 1) { + $output->delete('all'); + my $canvas = $$output{'SubWidget'}{'canvas'}; + my $h=$canvas->cget(-height); + foreach $i (@graphvars) { + my @a = (); + for(my $j=0; $j <= $#{$graphtb{$i}}; $j++) { + $a[$j*2] = $j; + $a[$j*2+1] = $h-(($h-3)*($graphtb{$i}[$j]-$min))/($max-$min)-3; + } + $output->createLine(@a, -fill => $graphcolors[$i%$#graphcolors]); + } + $output->create('text',5, $h-3, -text => "$max"); + $output->create('text',5, 3, -text => "$min"); + } + $gcount++; + $status->configure(-text => "sleeping for $graphtime seconds"); +} + +sub addMibOID { + my $i = shift; + $i = ".$i" if ($i !~ /^\./); + my $name = SNMP::translateObj($i,1); + if (defined($name)) { + $name =~ s/.*\.([^.]+)$/$1/; + } else { + return; + } + $i =~ s/^\.//; + $hlist->add($i, -text => $name); +} + +sub showInfo { + my $full = shift; + $full = ".$full" if ($full !~ /^\./); + my $oid = $full; + my $tag = $oid; + + if ($tag =~ /^[.0-9]+$/) { + # strip off index in case there is one + $tag = SNMP::translateObj("$oid"); + $tag = ".iso.org.dod.internet.private.$tag" if $tag =~ /^enterprises/; + } else { + $full = SNMP::translateObj("$oid"); + } + + $tag =~ s/[.0-9]+$//; + $oid = SNMP::translateObj($tag); + + if (!defined($last) || "$last" ne $oid) { + updateInfo($oid); + } + $OID = $full; + $mibOID->configure(-textvariable => \$OID); + $mibOID->update(); + $last = $oid; +} + +sub showAllChildren { + my $id = shift; + $id =~ s/^\.//; + my @pieces = split(/\./,$id); + my ($i, $lastvalid); + for($i = 0; $i <= $#pieces; $i++) { + my $a = join(".", @pieces[0..$i]); + if ($hlist->infoExists($a) && !($hlist->infoChildren($a))) { + showChildren(join(".", $a)); + } + if ($hlist->infoExists($a)) { + $lastvalid = $a; + } else { + last; + } + } + $hlist->see($lastvalid); + $hlist->selectionClear($hlist->selectionGet); + $hlist->selectionSet($lastvalid); +} + +sub showChildren { + $OID = shift; + $OID =~ s/^\.//; + my $oid = $OID; + $mibOID->configure(-textvariable => \$OID); + if ($hlist->infoChildren($oid)) { + my @a = $hlist->infoChildren($oid); + my $i; + foreach $i (@a) { + $hlist->deleteEntry($i); + } + } else { + $oid = ".$oid"; + my $mib = $SNMP::MIB{format_oid($oid,'full')}; + if (defined($mib)) { + my $children = $$mib{'children'}; + if (ref($children) eq "ARRAY") { + foreach $i (sort {$$a{'subID'} <=> $$b{'subID'}} @{$children}) { + addMibOID($$i{'objectID'}); + } + } else { + $status->configure(-text => SNMP::translateObj($oid,1) . + " has no children"); + return; + } + } + } + $status->configure(-text => ""); +} + +sub updateInfo { + $OID = shift; + my $oid = $OID; + my $mib = $SNMP::MIB{format_oid("$oid",'numeric')}; + if (!defined($mib->{'description'}) || $mib->{'description'} eq "") { + $oid =~ s/[.0-9]+$//; + $mib = $SNMP::MIB{format_oid("$oid",'numeric')}; + } + if (defined($mib)) { + if ($mib->{'label'} =~ /Table$/) { + $tablebutton->configure(-state => 'normal'); + } else { + $tablebutton->configure(-state => 'disabled'); + } + $mibOID->configure(-text => $mib->{'objectID'}); + $mibTextOID->configure(-text => + SNMP::translateObj($mib->{'objectID'},1)); + $descr->delete('0.0','end'); + if (defined($mib->{'description'}) && + $mib->{'description'} ne "") { + my $desc = $mib->{'description'}; + $desc =~ s/\n[ \t]+/\n/g; + $desc =~ s/^\n//; + $descr->insert('end',$desc); + } + for($i=0; $i<= $#displayInfo;$i++) { + $dpyInfo[$i] = $mib->{$displayInfo[$i]}; + if (ref($dpyInfo[$i]) eq HASH) { + my %hash = %{$dpyInfo[$i]}; + $dpyInfo[$i] = ""; + foreach $j (sort { $hash{$a} <=> $hash{$b} } keys(%hash)) { + $dpyInfo[$i] .= "$j = $hash{$j},"; + } + } elsif (ref($dpyInfo[$i]) eq ARRAY) { + $dpyInfo[$i] = join(", ", @{$dpyInfo[$i]}); + } + } + } +} + +sub optionalWidget { + my $num = shift; + my $menu = shift; + my $var = shift; + $menu->checkbutton(-label => $displayInfo[$num], + -variable => $var, + -command => [\&toggleWidgetShown, $num, $var]); +} + +sub createRow { + my $i = shift; + if (!$displayLabels[$i]) { + $displayLabels[$i] = $dispFrame->Label(-pady => $tmpbd, -padx => $tmpbd, + -text => $displayInfo[$i], + -anchor => 'w', + -borderwidth => $tmpbd); + } + if (!$displayEntries[$i]) { + $displayEntries[$i] = $dispFrame->Entry(-textvariable => \$dpyInfo[$i], + -width => 40, -relief => 'flat', + -borderwidth => $tmpbd); + } + $displayLabels[$i]->grid(-ipady => $tmpbd, -ipadx => $tmpbd, + -column => ($i%2)*2, -row => int($i/2), + -sticky => 'w'); + $dpyInfo[$i] = "" if (!defined($dpyInfo[$i])); + $displayEntries[$i]->grid(-ipady => $tmpbd, -ipadx => $tmpbd, -column => ($i%2)*2 + 1, -row => int($i/2), -sticky => 'w'); +} + +sub toggleWidgetShown { + my ($num, $var) = @_; + if ($$var) { + createRow($num); + } else { + $displayLabels[$num]->gridForget(); + $displayEntries[$num]->gridForget() + } +# my @widgets = $dispFrame->gridSlaves(-row => $num); +} + +sub loadNewMibFile { + my $sel = $top->FileSelect(); + my $file = $sel->Show(); + if (defined($file)) { + SNMP::addMibFiles($file); + showChildren("1.3.6.1"); + showChildren("1.3.6.1"); + } +} + +sub loadNewMibModule { + my $tmptop = MainWindow->new(); + my $var = ""; + $tmptop->Label(-pady => $tmpbd, -padx => $tmpbd, -text => "Enter a SNMP MIB module name") + ->pack(-side => 'top'); + my $e = $tmptop->Entry(-textvariable => \$var); + $e->pack(-side => 'top'); + $e->bind('',[\&loadIt,\$var,$tmptop]); + my $f = $tmptop->Frame(); + $f->pack(-side => 'top'); + $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Ok', -command => [\&loadIt,"",\$var,$tmptop]) + ->pack(-side => 'left'); + $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Cancel', -command => [sub { my $wid = shift; + $wid->destroy(); }, + $tmptop]) + ->pack(-side => 'left'); +} + +sub loadIt { + my $var = shift; + if ($var ne "") { + my $ret = SNMP::loadModules($var); + if ($ret) { + showChildren("1.3.6.1"); + showChildren("1.3.6.1"); + return 1; + } else { + $status->configure(-text => "Failed reading module $var"); + return 0; + } + } + return 0; +} + +sub stop { + $stopit = shift; + if ($stopit) { + $stopBut->configure(-state => 'disabled'); + } else { + $stopBut->configure(-state => 'normal'); + } +} + +sub entryBox { + my $title = shift; + my $text = shift; + my $var = shift; + my $callback = shift; + my $top = MainWindow->new(); + my $newvar = $$var if defined($var); + $top->title($title); + my $f = $top->Frame(); + $f->pack(-side => 'top'); + $f->Label(-pady => $tmpbd, -padx => $tmpbd, + -text => $text)->pack(-side => 'left'); + my $e = $f->Entry(-textvariable => \$newvar); + $e->pack(-side => 'left'); + $f = $top->Frame(); + $f->pack(-side => 'bottom'); + my $b = $f->Button(-pady => $tmpbd, -padx => $tmpbd, -text => 'Ok', + -command => [sub { my $w = shift; + my $v1 = shift; + my $v2 = shift; + my $call = shift; + my $ret = 1; + $$v1 = $$v2 if defined($v1); + $ret = $call->($$v2) + if defined($call); + $w->destroy() if ($ret);}, $top, $var, + \$newvar, $callback]); + $b->pack(-side => 'left'); + $e->bind('',[$b,'invoke']); + $b = $f->Button(-pady => $tmpbd, -padx => $tmpbd, + -text => 'Cancel', -command => [sub { my $w = shift; + $w->destroy();}, $top + ]); + $b->pack(-side => 'right'); + $e->bind('',[$b,'invoke']); + +} + +sub findANode { + my $val = shift; + my $tag = SNMP::translateObj($val); + if ($tag) { + showAllChildren($tag); + return 1; + } else { + $top->Dialog(-text => "$val not found")->Show(); + return 0; + } +} + +sub test_version { + my ($gt, $major, $minor, $sub) = @_; + $SNMP::VERSION =~ /(\d)\.(\d).(\d)/; + if ($gt) { + if ($1 > $major || ($1 == $major && $2 > $minor) || + ($1 == $major && $2 == $minor && $3 >= $sub)) { + return 1; + } + } else { + if ($1 < $major || ($1 == $major && $2 < $minor) || ($1 == $major && $2 == $minor && $3 < $sub)) { + return 1; + } + } + return 0; +} + +sub save_options { + my $umask = umask(); + umask 0077; # make sure its not readable by the world by default. + if (!open(O,">$opts{'f'}")) { + warn "can't save to $opts{'f'}\n"; + umask $umask; + return; + } + umask $umask; + print O Data::Dumper->Dump([\%session_opts], [qw(*session_opts)]); + print O Data::Dumper->Dump([\%displayInfoStates], [qw(*displayInfoStates)]); + foreach my $var (@saveoptions) { + print O Data::Dumper->Dump([$$var], [$var]); + } + close(O); + $status->configure(-text => "saved options to $opts{'f'}"); +} + +# returns 1 if $oid2 is below $oid1 in the hierarchy +sub is_in_subtree { + my ($oid1, $oid2) = @_; + # get pure numeric + $oid1 = SNMP::translateObj($oid1) if ($oid1 !~ /^[\d\.]*$/); + $oid2 = SNMP::translateObj($oid2) if ($oid2 !~ /^[\d\.]*$/); + + # has more on it or is exactly the same + return 1 if ($oid2 =~ /^$oid1\./ || $oid2 =~ /^$oid1$/); + return 0; +} + +sub format_oid { + my ($oid, $type) = @_; + $oid =~ s/\.$//; + $type = $displayoidas if ($type eq ""); + + if ($type eq 'numeric') { + return SNMP::translateObj($oid) if ($oid !~ /^[\d\.]*$/); + return $oid; + } elsif ($type eq 'full') { + return SNMP::translateObj($oid, 1) if ($oid =~ /^[\d\.]*$/); + return SNMP::translateObj(SNMP::translateObj($oid), 1) if ($oid !~ /^\./); + return $oid; + } elsif ($type eq 'short' || $type eq 'module') { + $oid = SNMP::translateObj($oid) if ($oid =~ /^[\d\.]*$/); + $oid =~ s/.*\.([a-zA-Z]\w+)\.(.*)/$1.$2/; + if ($type eq 'module') { + $oid = $SNMP::MIB{format_oid($oid,'numeric')}->{'moduleID'} . "::" . $oid; + } + return $oid; + } elsif ($type eq 'module') { + $oid = SNMP::translateObj($oid) if ($oid =~ /^[\d\.]*$/); + $oid =~ s/.*\.([a-zA-Z]\w+)\.(.*)/$1.$2/; + return $oid; + } else { + warn 'unknown oid translation type: $type'; + return $oid; + } +} + +sub get_oid { + my ($var, $type) = @_; + return format_oid($var->tag . "." . $var->iid, $type); +} diff --git a/local/traptoemail b/local/traptoemail new file mode 100755 index 0000000..e738ba7 --- /dev/null +++ b/local/traptoemail @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +# This is a snmptrapd handler script to convert snmp traps into email +# messages. + +# Usage: +# Put a line like the following in your snmptrapd.conf file: +# traphandle TRAPOID|default /usr/local/bin/traptoemail [-f FROM] [-s SMTPSERVER]b ADDRESSES +# FROM defaults to "root" +# SMTPSERVER defaults to "localhost" + +use Net::SMTP; +use Getopt::Std; +use POSIX qw(strftime); + +$opts{'s'} = "localhost"; +$opts{'f'} = 'root@' . `hostname`; +chomp($opts{'f'}); +getopts("hs:f:", \%opts); + +if ($opts{'h'}) { + print " +traptoemail [-s smtpserver] [-f fromaddress] toaddress [...] + + traptoemail shouldn't be called interatively by a user. It is + designed to be called as an snmptrapd extension via a \"traphandle\" + directive in the snmptrapd.conf file. See the snmptrapd.conf file for + details. + + Options: + -s smtpserver Sets the smtpserver for where to send the mail through. + -f fromaddress Sets the email address to be used on the From: line. + toaddress Where you want the email sent to. + +"; + exit; +} + +die "no recepients to send mail to" if ($#ARGV < 0); + +# process the trap: +$hostname = ; +chomp($hostname); +$ipaddress = ; +chomp($ipaddress); + +$maxlen = 0; +while() { + ($oid, $value) = /([^\s]+)\s+(.*)/; + push @oids, $oid; + push @values, $value; + $maxlen = (length($oid) > $maxlen) ? length($oid) : $maxlen; +} +$maxlen = 60 if ($maxlen > 60); +$formatstr = "%" . $maxlen . "s %s\n"; + +die "illegal trap" if ($#oids < 1); + +# send the message +$message = Net::SMTP->new($opts{'s'}) || die "can't talk to server $opts{'s'}\n"; +$message->mail($opts{'f'}); +$message->to(@ARGV) || die "failed to send to the recepients ",join(",",@ARGV),": $!"; +$message->data(); +$message->datasend("To: " . join(", ",@ARGV) . "\n"); +$message->datasend("From: $opts{f}\n"); +$message->datasend("Date: ".strftime("%a, %e %b %Y %X %z", localtime())."\n"); +$message->datasend("Subject: trap received from $hostname: $values[1]\n"); +$message->datasend("\n"); +$message->datasend("Host: $hostname ($ipaddress)\n"); +for($i = 0; $i <= $#oids; $i++) { + $message->datasend(sprintf($formatstr, $oids[$i], $values[$i])); +} +$message->dataend(); +$message->quit; -- cgit v1.2.3