summaryrefslogtreecommitdiff
path: root/local
diff options
context:
space:
mode:
authorHideki Yamane <henrich@debian.org>2013-04-11 10:21:22 +0900
committerHideki Yamane <henrich@debian.org>2013-04-11 10:21:22 +0900
commite30beeedd5cbe6f72008c32122b3b8b617fd5ab2 (patch)
tree8bd5c28fc77a5a80d65cf70e2fd330b8af448c73 /local
parent2ebfa94e6e1fe2b88bb061d26f20fef9c0b78536 (diff)
downloadpkg-net-snmp-e30beeedd5cbe6f72008c32122b3b8b617fd5ab2.tar.gz
Imported Upstream version 5.4.3~dfsgupstream/5.4.3_dfsg
Diffstat (limited to 'local')
-rwxr-xr-xlocal/FAQ2HTML113
-rw-r--r--local/Makefile.in156
-rw-r--r--local/README.mib2c224
-rwxr-xr-xlocal/Version-Munge.pl195
-rwxr-xr-xlocal/convertcode132
-rwxr-xr-xlocal/fixproc694
-rwxr-xr-xlocal/html-add-header-footer.pl212
-rwxr-xr-xlocal/html-textfile-fix.pl60
-rwxr-xr-xlocal/ipf-mod.pl227
-rwxr-xr-xlocal/mib2c1252
-rw-r--r--local/mib2c-conf.d/default-mfd-top.m2c141
-rw-r--r--local/mib2c-conf.d/details-enums.m2i80
-rw-r--r--local/mib2c-conf.d/details-node.m2i102
-rw-r--r--local/mib2c-conf.d/details-table.m2i25
-rw-r--r--local/mib2c-conf.d/generic-ctx-copy.m2i33
-rw-r--r--local/mib2c-conf.d/generic-ctx-get.m2i106
-rw-r--r--local/mib2c-conf.d/generic-ctx-set.m2i29
-rw-r--r--local/mib2c-conf.d/generic-data-allocate.m2i62
-rw-r--r--local/mib2c-conf.d/generic-data-context.m2i51
-rw-r--r--local/mib2c-conf.d/generic-get-char.m2i49
-rw-r--r--local/mib2c-conf.d/generic-get-decl-bot.m2i22
-rw-r--r--local/mib2c-conf.d/generic-get-decl.m2i43
-rw-r--r--local/mib2c-conf.d/generic-get-long.m2i14
-rw-r--r--local/mib2c-conf.d/generic-get-oid.m2i18
-rw-r--r--local/mib2c-conf.d/generic-header-bottom.m2i21
-rw-r--r--local/mib2c-conf.d/generic-header-top.m2i22
-rw-r--r--local/mib2c-conf.d/generic-source-includes.m2i23
-rw-r--r--local/mib2c-conf.d/generic-table-constants.m2c44
-rw-r--r--local/mib2c-conf.d/generic-table-enums.m2c63
-rw-r--r--local/mib2c-conf.d/generic-table-indexes-from-oid.m2i70
-rw-r--r--local/mib2c-conf.d/generic-table-indexes-set.m2i123
-rw-r--r--local/mib2c-conf.d/generic-table-indexes-to-oid.m2i53
-rw-r--r--local/mib2c-conf.d/generic-table-indexes-varbind-setup.m2i51
-rw-r--r--local/mib2c-conf.d/generic-table-indexes.m2i67
-rw-r--r--local/mib2c-conf.d/generic-table-oids.m2c113
-rw-r--r--local/mib2c-conf.d/generic-value-map-func.m2i104
-rw-r--r--local/mib2c-conf.d/generic-value-map-reverse.m2i49
-rw-r--r--local/mib2c-conf.d/generic-value-map.m2i46
-rw-r--r--local/mib2c-conf.d/m2c-internal-warning.m2i21
-rw-r--r--local/mib2c-conf.d/m2c_setup_enum.m2i24
-rw-r--r--local/mib2c-conf.d/m2c_setup_node.m2i260
-rw-r--r--local/mib2c-conf.d/m2c_setup_table.m2i48
-rw-r--r--local/mib2c-conf.d/m2c_table_save_defaults.m2i117
-rw-r--r--local/mib2c-conf.d/mfd-access-container-cached-defines.m2i576
-rw-r--r--local/mib2c-conf.d/mfd-access-unsorted-external-defines.m2i1198
-rw-r--r--local/mib2c-conf.d/mfd-data-access.m2c331
-rw-r--r--local/mib2c-conf.d/mfd-data-get.m2c168
-rw-r--r--local/mib2c-conf.d/mfd-data-set.m2c142
-rw-r--r--local/mib2c-conf.d/mfd-doxygen.m2c60
-rw-r--r--local/mib2c-conf.d/mfd-interactive-setup.m2c332
-rw-r--r--local/mib2c-conf.d/mfd-interface.m2c1716
-rw-r--r--local/mib2c-conf.d/mfd-makefile.m2m139
-rw-r--r--local/mib2c-conf.d/mfd-persistence.m2i478
-rw-r--r--local/mib2c-conf.d/mfd-readme.m2c846
-rw-r--r--local/mib2c-conf.d/mfd-top.m2c605
-rw-r--r--local/mib2c-conf.d/node-get.m2i107
-rw-r--r--local/mib2c-conf.d/node-set.m2i236
-rw-r--r--local/mib2c-conf.d/node-storage.m2i21
-rw-r--r--local/mib2c-conf.d/node-validate.m2i71
-rw-r--r--local/mib2c-conf.d/node-varbind-validate.m2i54
-rw-r--r--local/mib2c-conf.d/parent-dependencies.m2i63
-rw-r--r--local/mib2c-conf.d/parent-set.m2i417
-rw-r--r--local/mib2c-conf.d/subagent.m2c183
-rw-r--r--local/mib2c-conf.d/syntax-COUNTER64-get.m2i35
-rw-r--r--local/mib2c-conf.d/syntax-DateAndTime-get.m2d9
-rw-r--r--local/mib2c-conf.d/syntax-DateAndTime-get.m2i54
-rw-r--r--local/mib2c-conf.d/syntax-DateAndTime-readme.m2i4
-rw-r--r--local/mib2c-conf.d/syntax-InetAddress-get.m2i100
-rw-r--r--local/mib2c-conf.d/syntax-InetAddress-set.m2i22
-rw-r--r--local/mib2c-conf.d/syntax-InetAddressType-get.m2i25
-rw-r--r--local/mib2c-conf.d/syntax-InetAddressType-set.m2i25
-rw-r--r--local/mib2c-conf.d/syntax-RowStatus-dependencies.m2i113
-rw-r--r--local/mib2c-conf.d/syntax-RowStatus-get.m2i65
-rw-r--r--local/mib2c-conf.d/syntax-RowStatus-varbind-validate.m2i16
-rw-r--r--local/mib2c-conf.d/syntax-StorageType-dependencies.m2i19
-rw-r--r--local/mib2c-conf.d/syntax-TestAndIncr-get.m2i22
-rwxr-xr-xlocal/mib2c-update358
-rw-r--r--local/mib2c.access_functions.conf183
-rw-r--r--local/mib2c.array-user.conf1305
-rw-r--r--local/mib2c.check_values.conf154
-rw-r--r--local/mib2c.check_values_local.conf72
-rw-r--r--local/mib2c.column_defines.conf15
-rw-r--r--local/mib2c.column_enums.conf34
-rw-r--r--local/mib2c.column_storage.conf23
-rw-r--r--local/mib2c.conf284
-rw-r--r--local/mib2c.container.conf569
-rw-r--r--local/mib2c.create-dataset.conf112
-rw-r--r--local/mib2c.emulation.conf246
-rw-r--r--local/mib2c.genhtml.conf370
-rw-r--r--local/mib2c.int_watch.conf107
-rw-r--r--local/mib2c.iterate.conf668
-rw-r--r--local/mib2c.iterate_access.conf423
-rw-r--r--local/mib2c.mfd.conf32
-rw-r--r--local/mib2c.notify.conf84
-rw-r--r--local/mib2c.old-api.conf345
-rwxr-xr-xlocal/mib2c.perl.conf314
-rwxr-xr-xlocal/mib2c.row.conf282
-rw-r--r--local/mib2c.scalar.conf142
-rw-r--r--local/mib2c.table_data.conf647
-rw-r--r--local/pass_persisttest77
-rwxr-xr-xlocal/passtest41
-rwxr-xr-xlocal/passtest.pl74
-rwxr-xr-xlocal/snmp-ucd.sh187
-rwxr-xr-xlocal/snmpcheck.def1224
-rwxr-xr-xlocal/snmpconf933
-rw-r--r--local/snmpconf.dir/snmp-data/authopts77
-rw-r--r--local/snmpconf.dir/snmp-data/debugging39
-rw-r--r--local/snmpconf.dir/snmp-data/mibs56
-rw-r--r--local/snmpconf.dir/snmp-data/output79
-rw-r--r--local/snmpconf.dir/snmp-data/snmpconf-config1
-rw-r--r--local/snmpconf.dir/snmpd-data/acl36
-rw-r--r--local/snmpconf.dir/snmpd-data/basic_setup17
-rw-r--r--local/snmpconf.dir/snmpd-data/extending68
-rw-r--r--local/snmpconf.dir/snmpd-data/monitor72
-rw-r--r--local/snmpconf.dir/snmpd-data/operation32
-rw-r--r--local/snmpconf.dir/snmpd-data/snmpconf-config1
-rw-r--r--local/snmpconf.dir/snmpd-data/system43
-rw-r--r--local/snmpconf.dir/snmpd-data/trapsinks46
-rw-r--r--local/snmpconf.dir/snmptrapd-data/authentication8
-rw-r--r--local/snmpconf.dir/snmptrapd-data/formatting15
-rw-r--r--local/snmpconf.dir/snmptrapd-data/logging26
-rw-r--r--local/snmpconf.dir/snmptrapd-data/runtime13
-rw-r--r--local/snmpconf.dir/snmptrapd-data/snmpconf-config1
-rw-r--r--local/snmpconf.dir/snmptrapd-data/traphandle17
-rwxr-xr-xlocal/snmpdump.pl107
-rwxr-xr-xlocal/tkmib994
-rwxr-xr-xlocal/traptoemail74
127 files changed, 24738 insertions, 0 deletions
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 '<p class="SectionTitle">
+FAQ
+</p>
+FAQ Maintainer: Dave Shield<br/>
+Email: <a href="mailto:net-snmp-coders@lists.sourceforge.net">net-snmp-coders@list.sourceforge.net</a><br/>
+';
+print O "Version: $version<br/>\n";
+print O '<hr/>
+<h2>Table of Contents</h2>
+';
+
+# 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/&/&amp;/g; }
+ if ( /</ ) { $_ =~ s/</&lt;/g; }
+ if ( />/ ) { $_ =~ s/>/&gt;/g; }
+ if (/^[ A-Z]+$/) {
+ # Section header (eg: GENERAL)
+ print O "</ul><b>$_</b><ul>\n";
+ } else {
+ # Question / answer - create link to it
+ if ($faqfile[$current_line+1] =~ /^ */) {
+
+ # Continuation of the question.
+ $current_line++;
+ my $part2 = $faqfile[$current_line];
+
+ # Remove white space at start of line
+ $part2 =~ s/^ *//;
+
+ print O "<li> <a href=\"#$x\">$_ $part2</a></li>\n";
+ }
+ else {
+ print O "<li> <a href=\"#$x\">$_</a></li>\n";
+ }
+ }
+ $current_line++;
+}
+
+print O "</ul><hr/><pre>\n";
+
+# Print contents with targets defined
+while($current_line <= $#faqfile) {
+ $_ = $faqfile[$current_line];
+ $current_line++;
+
+ chomp();
+
+ $y = $_;
+
+ if (defined($xlate{$y})) {
+ print O "<a name=\"$xlate{$y}\"></a>\n";
+ }
+ if ( /&/ ) { $_ =~ s/&/&amp;/g; }
+ if ( /</ ) { $_ =~ s/</&lt;/g; }
+ if ( />/ ) { $_ =~ s/>/&gt;/g; }
+ print O "$_\n";
+}
+
+print O '
+</pre>
+';
+
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 <wjhardaker@ucdavis.edu>
+Ken McNamara <conmara@tcon.net>
+Joe Marzot <gmarzot@nortelnetworks.com>
+
+ ...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 (<I>) {
+ 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 <net-snmp\/net-snmp-config.h>/;
+s/include "asn1.h"/include <net-snmp\/asn1.h>/;
+s/include "callback.h"/include <net-snmp\/callback.h>/;
+s/include "data_list.h"/include <net-snmp\/data_list.h>/;
+s/include "default_store.h"/include <net-snmp\/default_store.h>/;
+s/include "getopt.h"/include <net-snmp\/getopt.h>/;
+s/include "int64.h"/include <net-snmp\/int64.h>/;
+s/include "keytools.h"/include <net-snmp\/keytools.h>/;
+s/include "lcd_time.h"/include <net-snmp\/lcd_time.h>/;
+s/include "libsnmp.h"/include <net-snmp\/libsnmp.h>/;
+s/include "md5.h"/include <net-snmp\/md5.h>/;
+s/include "mib.h"/include <net-snmp\/mib.h>/;
+s/include "mt_support.h"/include <net-snmp\/mt_support.h>/;
+s/include "net-snmp-config.h"/include <net-snmp\/net-snmp-config.h>/;
+s/include "net-snmp-includes.h"/include <net-snmp\/net-snmp-includes.h>/;
+s/include "oid_array.h"/include <net-snmp\/oid_array.h>/;
+s/include "oid_stash.h"/include <net-snmp\/oid_stash.h>/;
+s/include "parse.h"/include <net-snmp\/parse.h>/;
+s/include "read_config.h"/include <net-snmp\/read_config.h>/;
+s/include "scapi.h"/include <net-snmp\/scapi.h>/;
+s/include "snmpAAL5PVCDomain.h"/include <net-snmp\/snmpAAL5PVCDomain.h>/;
+s/include "snmp_alarm.h"/include <net-snmp\/snmp_alarm.h>/;
+s/include "snmp_api.h"/include <net-snmp\/snmp_api.h>/;
+s/include "snmpCallbackDomain.h"/include <net-snmp\/snmpCallbackDomain.h>/;
+s/include "snmp_client.h"/include <net-snmp\/snmp_client.h>/;
+s/include "snmp_debug.h"/include <net-snmp\/snmp_debug.h>/;
+s/include "snmp_enum.h"/include <net-snmp\/snmp_enum.h>/;
+s/include "snmp.h"/include <net-snmp\/snmp.h>/;
+s/include "snmp_impl.h"/include <net-snmp\/snmp_impl.h>/;
+s/include "snmpIPXDomain.h"/include <net-snmp\/snmpIPXDomain.h>/;
+s/include "snmpksm.h"/include <net-snmp\/snmpksm.h>/;
+s/include "snmp_locking.h"/include <net-snmp\/snmp_locking.h>/;
+s/include "snmp_logging.h"/include <net-snmp\/snmp_logging.h>/;
+s/include "snmp_parse_args.h"/include <net-snmp\/snmp_parse_args.h>/;
+s/include "snmp_secmod.h"/include <net-snmp\/snmp_secmod.h>/;
+s/include "snmp-tc.h"/include <net-snmp\/snmp-tc.h>/;
+s/include "snmpTCPDomain.h"/include <net-snmp\/snmpTCPDomain.h>/;
+s/include "snmpTCPIPv6Domain.h"/include <net-snmp\/snmpTCPIPv6Domain.h>/;
+s/include "snmp_transport.h"/include <net-snmp\/snmp_transport.h>/;
+s/include "snmpUDPDomain.h"/include <net-snmp\/snmpUDPDomain.h>/;
+s/include "snmpUDPIPv6Domain.h"/include <net-snmp\/snmpUDPIPv6Domain.h>/;
+s/include "snmpUnixDomain.h"/include <net-snmp\/snmpUnixDomain.h>/;
+s/include "snmpusm.h"/include <net-snmp\/snmpusm.h>/;
+s/include "snmpusm_init.h"/include <net-snmp\/snmpusm_init.h>/;
+s/include "snmpv3.h"/include <net-snmp\/snmpv3.h>/;
+s/include "system.h"/include <net-snmp\/system.h>/;
+s/include "tools.h"/include <net-snmp\/tools.h>/;
+s/include "transform_oids.h"/include <net-snmp\/transform_oids.h>/;
+s/include "vacm.h"/include <net-snmp\/vacm.h>/;
+s/include <asn1.h>/include <net-snmp\/asn1.h>/;
+s/include <callback.h>/include <net-snmp\/callback.h>/;
+s/include <data_list.h>/include <net-snmp\/data_list.h>/;
+s/include <default_store.h>/include <net-snmp\/default_store.h>/;
+s/include <getopt.h>/include <net-snmp\/getopt.h>/;
+s/include <int64.h>/include <net-snmp\/int64.h>/;
+s/include <keytools.h>/include <net-snmp\/keytools.h>/;
+s/include <lcd_time.h>/include <net-snmp\/lcd_time.h>/;
+s/include <libsnmp.h>/include <net-snmp\/libsnmp.h>/;
+s/include <md5.h>/include <net-snmp\/md5.h>/;
+s/include <mib.h>/include <net-snmp\/mib.h>/;
+s/include <mt_support.h>/include <net-snmp\/mt_support.h>/;
+s/include <net-snmp-config.h>/include <net-snmp\/net-snmp-config.h>/;
+s/include <net-snmp-includes.h>/include <net-snmp\/net-snmp-includes.h>/;
+s/include <oid_array.h>/include <net-snmp\/oid_array.h>/;
+s/include <oid_stash.h>/include <net-snmp\/oid_stash.h>/;
+s/include <parse.h>/include <net-snmp\/parse.h>/;
+s/include <read_config.h>/include <net-snmp\/read_config.h>/;
+s/include <scapi.h>/include <net-snmp\/scapi.h>/;
+s/include <snmpAAL5PVCDomain.h>/include <net-snmp\/snmpAAL5PVCDomain.h>/;
+s/include <snmp_alarm.h>/include <net-snmp\/snmp_alarm.h>/;
+s/include <snmp_api.h>/include <net-snmp\/snmp_api.h>/;
+s/include <snmpCallbackDomain.h>/include <net-snmp\/snmpCallbackDomain.h>/;
+s/include <snmp_client.h>/include <net-snmp\/snmp_client.h>/;
+s/include <snmp_debug.h>/include <net-snmp\/snmp_debug.h>/;
+s/include <snmp_enum.h>/include <net-snmp\/snmp_enum.h>/;
+s/include <snmp.h>/include <net-snmp\/snmp.h>/;
+s/include <snmp_impl.h>/include <net-snmp\/snmp_impl.h>/;
+s/include <snmpIPXDomain.h>/include <net-snmp\/snmpIPXDomain.h>/;
+s/include <snmpksm.h>/include <net-snmp\/snmpksm.h>/;
+s/include <snmp_locking.h>/include <net-snmp\/snmp_locking.h>/;
+s/include <snmp_logging.h>/include <net-snmp\/snmp_logging.h>/;
+s/include <snmp_parse_args.h>/include <net-snmp\/snmp_parse_args.h>/;
+s/include <snmp_secmod.h>/include <net-snmp\/snmp_secmod.h>/;
+s/include <snmp-tc.h>/include <net-snmp\/snmp-tc.h>/;
+s/include <snmpTCPDomain.h>/include <net-snmp\/snmpTCPDomain.h>/;
+s/include <snmpTCPIPv6Domain.h>/include <net-snmp\/snmpTCPIPv6Domain.h>/;
+s/include <snmp_transport.h>/include <net-snmp\/snmp_transport.h>/;
+s/include <snmpUDPDomain.h>/include <net-snmp\/snmpUDPDomain.h>/;
+s/include <snmpUDPIPv6Domain.h>/include <net-snmp\/snmpUDPIPv6Domain.h>/;
+s/include <snmpUnixDomain.h>/include <net-snmp\/snmpUnixDomain.h>/;
+s/include <snmpusm.h>/include <net-snmp\/snmpusm.h>/;
+s/include <snmpusm_init.h>/include <net-snmp\/snmpusm_init.h>/;
+s/include <snmpv3.h>/include <net-snmp\/snmpv3.h>/;
+s/include <system.h>/include <net-snmp\/system.h>/;
+s/include <tools.h>/include <net-snmp\/tools.h>/;
+s/include <transform_oids.h>/include <net-snmp\/transform_oids.h>/;
+s/include <vacm.h>/include <net-snmp\/vacm.h>/;
+s/\"agent_read_config.h\"/<net-snmp\/agent\/agent_read_config.h>/;
+s/\"agent_registry.h\"/<net-snmp\/agent\/agent_registry.h>/;
+s/\"agent_index.h\"/<net-snmp\/agent\/agent_index.h>/;
+s/\"agent_trap.h\"/<net-snmp\/agent\/agent_trap.h>/;
+s/\"auto_nlist.h\"/<net-snmp\/agent\/auto_nlist.h>/;
+s/\"ds_agent.h\"/<net-snmp\/agent\/ds_agent.h>/;
+s/\"snmp_agent.h\"/<net-snmp\/agent\/snmp_agent.h>/;
+s/\"snmp_vars.h\"/<net-snmp\/agent\/snmp_vars.h>/;
+s/\"var_struct.h\"/<net-snmp\/agent\/var_struct.h>/;
+s/\"agent_handler.h\"/<net-snmp\/agent\/agent_handler.h>/;
+s/\"ucd-snmp-agent-includes.h\"/<net-snmp\/agent\/net-snmp-agent-includes.h>/;
+s/\"agent_handler.h\"/<net-snmp\/agent\/agent_handler.h>/;
+s/\"agent_callbacks.h\"/<net-snmp\/agent\/agent_callbacks.h>/;
+s/\"mib_modules.h\"/<net-snmp\/agent\/mib_modules.h>/;
+s/<agent_read_config.h>/<net-snmp\/agent\/agent_read_config.h>/;
+s/<agent_registry.h>/<net-snmp\/agent\/agent_registry.h>/;
+s/<agent_index.h>/<net-snmp\/agent\/agent_index.h>/;
+s/<agent_trap.h>/<net-snmp\/agent\/agent_trap.h>/;
+s/<auto_nlist.h>/<net-snmp\/agent\/auto_nlist.h>/;
+s/<ds_agent.h>/<net-snmp\/agent\/ds_agent.h>/;
+s/<snmp_agent.h>/<net-snmp\/agent\/snmp_agent.h>/;
+s/<snmp_vars.h>/<net-snmp\/agent\/snmp_vars.h>/;
+s/<var_struct.h>/<net-snmp\/agent\/var_struct.h>/;
+s/<agent_handler.h>/<net-snmp\/agent\/agent_handler.h>/;
+s/<ucd-snmp-agent-includes.h>/<net-snmp\/agent\/net-snmp-agent-includes.h>/;
+s/<agent_handler.h>/<net-snmp\/agent\/agent_handler.h>/;
+s/<agent_callbacks.h>/<net-snmp\/agent\/agent_callbacks.h>/;
+s/<mib_modules.h>/<net-snmp\/agent\/mib_modules.h>/;
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 = <COMMAND>;
+ 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 (<COMMAND>)
+ {
+ # 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 (<COMMAND>)
+ {
+ # 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 (<COMMAND>)
+ { # 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 (<DB>)
+ {
+ 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 [<options>] file1 file2 file3 ...
+Options:
+ --section= Menu section
+ --tidy Run tidy on input file before processing (turns on --body)
+ --body Remove everything before <body> 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 (<STDIN>) {
+ 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 (<I>) {
+ 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 <body lines
+ for (my $i = 0; $i <= $#old_file; $i++) {
+ if ($old_file[$i] =~ /<body/) {
+ $body_count++;
+ next;
+ }
+ }
+
+ # Remove anything before and including <body
+ while ($body_count > 0) {
+ while (! ($old_file[0] =~ /<body/)) {
+ splice (@old_file, 0, 1);
+ }
+ splice (@old_file, 0, 1); # <body line
+ $body_count--;
+ }
+ }
+
+ # Start to build new file in memory with header
+ push (@new_file, "<!--#set var=\"section\" value=\"$section\" -->\n");
+ push (@new_file, '<!--#include virtual="/page-top.html" -->' . "\n");
+ push (@new_file, '<!-- CONTENT START -->' . "\n");
+
+ # Add in old file, skipping existing header and footer and stopping at <body/>
+ 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] =~ /<!--#set var="section" value=/) { next; }
+ elsif ($old_file[$i] =~ /<!--#include virtual="\/page-top.html" -->/) { next; }
+ elsif ($old_file[$i] =~ /<!-- CONTENT START -->/) { next; }
+ elsif ($old_file[$i] =~ /<!-- CONTENT END -->/) { next; }
+ elsif ($old_file[$i] =~ /<!--#include virtual="\/page-bottom.html" -->/) { next; }
+
+ push (@new_file, $old_file[$i] . "\n");
+ }
+
+ # Finish to building new file in memory with footer
+ push (@new_file, '<!-- CONTENT END -->' . "\n");
+ push (@new_file, '<!--#include virtual="/page-bottom.html" -->' . "\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 = <FILEIN>) {
+ $line =~ s/&(?!lt|gt|quot|amp)/\&amp;/g;
+ $line =~ s/</\&lt;/g;
+ $line =~ s/>/\&gt;/g;
+ $line =~ s/\"/\&quot;/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 <ts@polynet.lviv.ua>
+## 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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+/* 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 <net-snmp/agent/table_container.h>
+#include <net-snmp/library/container.h>
+
+#include "${name}_interface.h"
+
+#include <ctype.h>
+
+@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 <net-snmp/library/asn1.h>
+
+/* 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 <net-snmp/agent/mib_modules.h>
+
+@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.
+ * <b>DO NOT</b> 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 <signal.h>
+
+static int keep_running;
+
+static RETSIGTYPE
+stop_server(int a) {
+ keep_running = 0;
+}
+
+static void usage(void) {
+ printf("usage: $name [-D<tokens>] [-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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/library/container.h>
+#include <net-snmp/agent/table_array.h>
+
+ @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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include <net-snmp/library/snmp_assert.h>
+
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <rstory@freesnmp.com>
+## 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@
+<pre>
+$x
+</pre>
+@enddefine@
+##
+## print a description clause (include TC info and references
+##
+@define DO_DESCR@
+<td>
+@if "$i.perltype" ne "$i.syntax"@
+<p>
+@eval $tmpsyn = "$i.syntax"@
+@perleval if (!defined($TCS{$vars{'tmpsyn'}})) { $TCS{$vars{'tmpsyn'}} = $vars{'i'}; }; 0;@
+Note: this object is based on the <a href="#$i.syntax"> $i.syntax TEXTUAL-CONVENTION</a>.
+</p>
+@end@
+@eval $x = "$i.description"@
+@calldefine DO_FORMATED_TEXT@
+##@startperl@
+## my ($s) = ($vars{'x'} =~ /\n(\s+)/);
+## $vars{'x'} =~ s/^$s//gm;
+## 0;
+##@endperl@
+##<pre>
+##$x
+##</pre>
+@if "$i.reference" ne ""@
+@eval $x = "$i.reference"@
+<p><i>Also see Reference:
+@calldefine DO_FORMATED_TEXT@
+</i></p>
+@end@
+</td>
+@enddefine@
+##
+## print information (a row) about a given node
+##
+@define NODE_INFO@
+@if ("$i.status" eq "Current")@
+ <td>
+@else@
+ <td class="deprecated">
+@end@
+<a name="$i" />
+@eval $tmpi = "$i.parent"@
+@if "$doindexstuff" ne "" && "$tmpi.parent" ne "$t"@
+(external from $tmpi.parent)
+@else@
+$i.subid
+@end@
+<br /><b>$i</b>
+
+</td><td>
+##
+## print the data type
+##
+@if ("$i.status" ne "Current")@
+<font color="red">DEPRECATED</font><br />
+@end@
+ $i.perltype
+##
+## print range information
+##
+ @if "$i.ranges"@
+ @if "$i.perltype" eq 'OCTETSTR' || "$i.perltype" eq 'OBJECTID'@
+ <br />Legal Lengths:
+ @else@
+ <br />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"@
+ <br>
+ @eval $tmpsyn = "$i.syntax"@
+ @perleval if (!defined($TCS{$vars{'tmpsyn'}})) { $TCS{$vars{'tmpsyn'}} = $vars{'i'}; }; 0;@
+ <a href="#$i.syntax">$i.syntax</a>
+ @if $i.enums@
+ <br>(ENUM list below)
+ @end@
+ @else@
+ @if $i.enums@
+ <table class="enum">
+ <tr><th>Value</th><th>Label/Meaning</th></tr>
+ @foreach $e $v enum@
+ <tr><td>$v</td><td>$e</td></tr>
+ @end@
+ </table>
+ @end@
+ @end@
+
+ </td><td>$i.access</td>
+ @if !"$dont_do_oids"@
+ <td>$i.objectID</td>
+ @end@
+ @calldefine DO_DESCR@
+@enddefine@
+@open ${name}.html@
+<head>
+ <title>MIB information for $name</title>
+<style type="text/css">
+@if "$cssfile" ne ""@
+@startperl@
+open(CSS,$vars{'cssfile'});
+while(<CSS>) {
+ mib2c_output($_);
+}
+close(CSS);
+0;
+@endperl@
+@else@
+<!--
+h2{background:#bbeebb}
+h3{background:#ccccee}
+table {
+ border: 1px;
+ background: #dddddd;
+ style: outset;
+}
+th {
+ border: 1px;
+ border: solid;
+ border-style: outset;
+ background: #bbbbbb;
+}
+td {
+ border: 1px;
+ border: solid;
+ border-style: inset;
+}
+table.enums {
+ background: #cccccc;
+}
+table.deprecated {
+ background: #ffdddd;
+}
+td.deprecated {
+ background: #ffdddd;
+}
+.label {
+ border-style: outset;
+ background: #bbbbbb;
+}
+-->
+@end@
+</style>
+</head>
+<body bgcolor="#ffffff">
+<h2>INTRODUCTION</h2>
+<ul>
+<p>
+This is a summary of information regarding objects below the <b>$name</b>
+MIB object, which is defined within the <b>$name.module</b> MIB
+document as <b>$name.objectID</b>.
+</p>
+</ul>
+##
+## Table of contents
+##
+<h2>TABLE OF CONTENTS</h2>
+<ul>
+@foreach $Current stuff Current Deprecated@
+<h3><a href="#objects_$Current">$Current Objects</a></h3>
+<ul>
+@if "$Current" eq "Current"@
+<li><a href="#scalar_current">Scalars</a></li>
+@else@
+<li><a href="#scalar_notcurrent">Deprecated Scalars</a></li>
+@end@
+@foreach $t table@
+@if ("$Current" eq "Current" && "$t.status" eq "Current") || ("$Current" ne "Current" && "$t.status" ne "Current")@
+ <li><a href="#$t">$t</a></li>
+@end@
+@end@
+</ul>
+@end@
+<h3><a href="#notifications">Notifications</a></h3>
+<h3><a href="#textconventions">Textual Conventions</a></h3>
+<h3><a href="#treeview">Tree-based view</a></h3>
+</ul>
+##
+## Start of definitions
+##
+@foreach $Current stuff Current Deprecated@
+<a name="objects_$Current" />
+@if "$Current" ne "Current"@
+ @eval $namestring = "notcurrent"@
+ <hr />
+ <h1><font color="red">DEPRECATED OR OBSOLETE OR HISTORIC OBJECTS</font></h1>
+ <br>
+ <table class="deprecated"><tr><td>
+@else@
+ @eval $namestring = "current"@
+@end@
+<a name="scalar_$namestring" />
+<h2>SCALAR OBJECTS</h2>
+<ul>
+<table>
+<tr><th>Name</th><th>Type</th><th>Access</th><th>OID</th><th>Description</th></tr>
+@foreach $i scalar@
+ @if ("$Current" eq "Current" && "$i.status" eq "Current") || ("$Current" ne "Current" && "$i.status" ne "Current")@
+ <tr>
+ @calldefine NODE_INFO@
+ </tr>
+ @end@
+@end@
+</table>
+</ul>
+
+<h2>TABLE OBJECTS</h2>
+@eval $dont_do_oids = 1@
+@foreach $t table@
+@if ("$Current" eq "Current" && "$t.status" eq "Current") || ("$Current" ne "Current" && "$t.status" ne "Current")@
+<a name="$t" /><h3>Table $t</h3>
+<ul>
+ <table>
+ <tr><td class="label">Table Name</td><td>$t</td></tr>
+ <tr><td class="label">In MIB</td><td>$t.module</td></tr>
+ <tr><td class="label">Registered at OID</td><td>$t.objectID</td></tr>
+ <tr><td class="label">Table Description</td>
+@eval $i ="$t"@
+@calldefine DO_DESCR@
+</tr>
+ @eval $tmpx = $t@
+ @perleval $vars{'tmpx'} =~ s/Table/Entry/; 0;@
+@eval $i = "$tmpx"@
+<tr><td class="label"><a name="$tmpx" />Row Description</td>
+@calldefine DO_DESCR@
+</tr>
+ </table>
+
+ <h4>$t Indexes:</h4>
+
+<table>
+<tr class="label"><th>Name</th><th>Type</th><th>Access</th><th>Description</th></tr>
+@foreach $i index@
+ <tr>
+ @calldefine NODE_INFO@
+ </tr>
+@end@
+</table>
+
+ <h4>Other $t Columns:</h4>
+<table>
+<tr class="label"><th>Name</th><th>Type</th><th>Access</th><th>Description</th></tr>
+@foreach $i nonindex@
+ <tr>
+ @calldefine NODE_INFO@
+ </tr>
+@end@
+</table>
+</ul>
+@end@
+@end@
+@end@
+
+<br>
+ </table>
+<hr />
+<a name="notifications" />
+<h2>NOTIFICATIONS</h2>
+<ul>
+<p>
+@foreach $i notifications@
+<a name="$i" /><h3>Notification: $i</h3>
+
+ <table>
+ <tr><td class="label">Notification Name</td><td>$i</td></tr>
+ <tr><td class="label">In MIB</td><td>$i.module</td></tr>
+ <tr><td class="label">Registered at OID</td><td>$i.objectID</td></tr>
+ <tr><td class="label">Notification Description</td>
+@calldefine DO_DESCR@
+ </tr>
+ <tr> <td class="label">Mandatory<br />Objects</td><td>
+ <table>
+ @foreach $v varbinds@
+ <tr><td><a href="#$v">$v</a></td></tr>
+ @end@
+ </table></td></tr>
+ </table>
+@end@
+</ul>
+
+
+<br>
+<hr />
+<a name="textconventions" />
+<h2>TEXTUAL CONVENTIONS</h2>
+<ul>
+<p>
+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.
+</p>
+@startperl@
+mib2c_output("<table>");
+mib2c_output("<tr class=\"label\"><th>Name</th><th>Type</th><th>Description</th></tr>\n");
+map {
+ my $desc = $SNMP::MIB{$TCS{$_}}{'TCDescription'};
+ my ($s) = ($desc =~ /\n(\s+)/);
+ $desc =~ s/^$s//gm;
+ mib2c_output("<tr><td><a name=\"$_\">$_</td><td>");
+ mib2c_output($SNMP::MIB{$TCS{$_}}{'type'});
+ my @enumkeys = keys(%{$SNMP::MIB{$TCS{$_}}{'enums'}});
+ if ($#enumkeys > -1) {
+ mib2c_output("<table class=\"enums\">");
+ mib2c_output("<tr><th>Value</th><th>Label/Meaning</th></tr>");
+ foreach $k (sort { $SNMP::MIB{$TCS{$_}}{'enums'}{$a} <=>
+ $SNMP::MIB{$TCS{$_}}{'enums'}{$b} } @enumkeys) {
+ mib2c_output("<tr><td>$SNMP::MIB{$TCS{$_}}{'enums'}{$k}</td><td>$k</td></tr>");
+ }
+ mib2c_output("</table>");
+ }
+ mib2c_output("</td><td><pre>$desc</pre></td></tr>\n");
+} keys(%TCS);
+mib2c_output("</table>");
+0;
+@endperl@
+</ul>
+
+<a name="treeview" />
+<h2>TREE VIEW</h2>
+@eval $mod = "$name.module"@
+<p>Tree view generated by running: <b>snmptranslate -Tp $mod::$name</b></p>
+<pre>
+@startperl@
+open(TREE,"snmptranslate -Tp $vars{mod}::$vars{name}|");
+while(<TREE>) {
+ s/(\+-- .*\s)(\w+)(\(\d+\))$/$1<a href="#$2">$2<\/a>$3/;
+ s/\+--(\w+)/+--<a href="#$1">$1<\/a>/;
+ s/Textual Convention: (\w+)/Textual Convention: <a href="#$1">$1<\/a>/;
+ mib2c_output($_);
+}
+close(TREE);
+return 0;
+@endperl@
+</pre>
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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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 <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#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() { # <program> [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() { # <program>
+ 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 (<OUT>) {
+ $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 (<LOG>) {
+ @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',"<Control-q>",[\&quit]);
+ $top->bind('all',"<Control-h>",[\&makehidden]);
+ $top->bind('all',"<Control-s>",[\&seenall]);
+ $top->bind('all',"<Control-f>",[\&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("<Return>",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 (<LOG>) {
+ @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('<Return>' => [\&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('<Return>' => [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 (<OUT>) {
+ $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(" ",<I>) . "\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(<I>) {
+ $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(<I>) {
+ 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(<I>) {
+ 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('<Return>',[\&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('<Return>',[$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('<Escape>',[$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 = <STDIN>;
+chomp($hostname);
+$ipaddress = <STDIN>;
+chomp($ipaddress);
+
+$maxlen = 0;
+while(<STDIN>) {
+ ($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;