diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2015-09-22 22:01:05 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@nxc.no> | 2015-09-23 18:24:42 +0200 |
commit | a1a667a8341c84ea05572d3997b791d29d0dc440 (patch) | |
tree | 888828e458e7b0d04a7948fb6a88c758a2ee5987 | |
download | netsnmp-sendmail-a1a667a8341c84ea05572d3997b791d29d0dc440.tar.gz netsnmp-sendmail-a1a667a8341c84ea05572d3997b791d29d0dc440.tar.bz2 |
Initial commit
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | MANIFEST | 5 | ||||
-rw-r--r-- | Makefile.PL | 43 | ||||
-rw-r--r-- | NetSNMP/Sendmail.pm | 484 | ||||
-rw-r--r-- | SENDMAIL-STATS.txt | 226 | ||||
-rwxr-xr-x | install-mib.pl | 69 |
6 files changed, 833 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5871f3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.tar.gz +MYMETA.yml +Makefile +/blib +/pm_to_blib diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..14750a5 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,5 @@ +Makefile.PL +MANIFEST This list of files +NetSNMP/Sendmail.pm +SENDMAIL-STATS.txt +install-mib.pl
\ No newline at end of file diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..195b8c6 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,43 @@ +# SNMP Sendmail Statistics Module -*- perl -*- +# Copyright (C) 2015 Sergey Poznyakoff <gray@gnu.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +use ExtUtils::MakeMaker; + +WriteMakefile( + 'NAME' => 'NetSNMP::Sendmail', + 'AUTHOR' => 'Sergey Poznyakoff <gray@gnu.org>', + 'ABSTRACT' => 'NetSNMP module for Sendmail statistics', + 'LICENSE' => 'gpl_v3', + 'FIRST_MAKEFILE' => 'Makefile', + 'VERSION_FROM' => 'NetSNMP/Sendmail.pm', + 'PM' => { + 'NetSNMP/Sendmail.pm' => '$(INST_LIBDIR)/Sendmail.pm' + }, + 'PREREQ_PM' => { 'NetSNMP::OID', 'NetSNMP::agent', 'NetSNMP::ASN' }, +); + +sub MY::postamble { + return <<'_MAKE_'; +INSTALLSITEMIB = $(SITEPREFIX)/share/snmp/mibs +DESTINSTALLSITEMIB = $(DESTDIR)$(INSTALLSITEMIB) + +install:: install-mib + +install-mib: + $(PERLRUN) install-mib.pl SENDMAIL-STATS.txt $(DESTINSTALLSITEMIB) +_MAKE_ +} + diff --git a/NetSNMP/Sendmail.pm b/NetSNMP/Sendmail.pm new file mode 100644 index 0000000..cf1e3ca --- /dev/null +++ b/NetSNMP/Sendmail.pm @@ -0,0 +1,484 @@ +# SNMP Sendmail Statistics Module -*- perl -*- +# Copyright (C) 2015 Sergey Poznyakoff <gray@gnu.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +package NetSNMP::Sendmail; + +use strict; +use feature 'state'; +use NetSNMP::OID (':all'); +use NetSNMP::agent (':all'); +use NetSNMP::ASN (':all'); +use Carp; + +use Data::Dumper; + +require Exporter; +our @ISA = qw(Exporter); + +our $VERSION = "0.90"; + +our @EXPORT_OK = qw(&Configure); + +my $mailq_bin = 'mailq'; +my $mailstats_bin = 'mailstats'; + +my %ttl = ( + mailq => 10, + mailstats => 10 +); + +my %config = ( + mailq_ttl => \$ttl{mailq}, + mailstats_ttl => \$ttl{mailstats}, + mailq => \$mailq_bin, + mailstats => \$mailstats_bin, + bindir => sub { + $mailq_bin = "$_[1]/$mailq_bin" if $mailq_bin !~ m#^/#; + $mailstats_bin = "$_[1]/$mailstats_bin" if $mailstats_bin !~ m#^/#; + } +); + +sub Configure { +# print Dumper ( \@_ ); + local %_ = @_; + while (my ($k,$v) = each %_) { + if (exists($config{$k})) { + if (ref($config{$k}) eq 'CODE') { + &{$config{$k}}($k, $v); + } else { + ${$config{$k}} = $v; + } + } else { + confess "unknown keyword: $k"; + } + } +} + +sub import { + my $pkg = shift; # package + my @syms = (); # symbols to import + my @config = (); # configuration + my $dest = \@syms; # symbols first + for (@_) { + if ($_ eq ':config') { + $dest = \@config; + next; + } + push @$dest, $_; + } + local $Exporter::ExportLevel = 1; + $pkg->SUPER::import(@syms); + Configure(@config) if @config; +} + +use constant OID_BASE => '.1.3.6.1.4.1.9163.100'; +use constant SUBOID_QUEUE_TOTAL => '1'; +use constant SUBOID_STAT_MAILERTAB => '2'; +use constant SUBOID_STAT_TOTALTAB => '3'; +use constant SUBOID_STAT_CONNTAB => '4'; + +use constant OID_STAT_MAILERTAB => OID_BASE . '.' . SUBOID_STAT_MAILERTAB; +use constant OID_STAT_MAILERENTRY => OID_STAT_MAILERTAB . '.1'; +use constant OID_STAT_TOTALTAB => OID_BASE . '.' . SUBOID_STAT_TOTALTAB; +use constant OID_STAT_CONNTAB => OID_BASE . '.' . SUBOID_STAT_CONNTAB; + +my $oid_base = new NetSNMP::OID(OID_BASE); + +sub debug { + # nothing +} + +my %timestamp; + +sub queue_totals { + state $n; + + if ($ttl{mailq}) { + my $now = time(); + return $n if $now - $timestamp{mailq} < $ttl{mailq}; + $timestamp{mailq} = $now; + } + open(my $fd, '-|', $mailq_bin) + or die "can't run $mailq_bin: $!"; + $n = shift [map { /Total requests:\s+(\d+)\s*$/ ? $1 : () } <$fd>]; + close($fd); + return $n; +} + +sub mailer_stats { + state $timestamp; + state %mstats; + + my $now = time(); + return %mstats if $now - $timestamp{mailstats} < $ttl{mailstats}; + $timestamp{mailstats} = $now; + + debug("calling $mailstats_bin"); + open(my $fd, '-|', "$mailstats_bin -P") + or die "can't run $mailstats_bin: $!"; + my $line = 0; + + while (<$fd>) { + ++$line; + + next if $line == 1; + + s/^\s+//; +# msgsfr bytes_from msgsto bytes_to msgsrej msgsdis msgsqur Mailer + my @a = split /\s+/; + if ($a[0] eq 'T') { + $mstats{totals} = [ @a[1..7] ]; + } elsif ($a[0] eq 'C') { + $mstats{conn} = [ @a[1..3] ]; + } else { + push @{$mstats{mailertab}}, $a[8] + unless exists $mstats{mailer}{$a[8]}; + $mstats{mailer}{$a[8]} = [ @a[1..7] ]; + } + } + close($fd); + return %mstats; +} + +sub get_queue_totals { + my $request = shift; + my $mode = shift; + + if ($#_ == 0 and $_[0] == 0) { + if ($mode == MODE_GETNEXT) { + get_mailertab($request, MODE_GETNEXT); + } elsif ($mode == MODE_GET) { + $request->setValue(ASN_COUNTER64, queue_totals()); + } + } +} + +sub get_mailertab { + my $request = shift; + my $mode = shift; + + debug("get_mailertab($mode," . join('.', @_) . ")"); + + my @idx = @_; + if ($#idx == -1) { + @idx = (1, 2, -1); + } + + my $x = shift @idx; + return unless $x == 1; + return unless $#idx == 1; + + my %mstats = mailer_stats(); + + if ($idx[1] <= $#{$mstats{mailertab}}) { + if ($mode == MODE_GETNEXT) { + ++$idx[1]; + if ($idx[1] > $#{$mstats{mailertab}}) { + $idx[1] = 0; + ++$idx[0]; + return get_totaltab($request, MODE_GETNEXT) + unless $idx[0]-3 <= $#{$mstats{mailer}{$mstats{mailertab}->[$idx[1]]}}; + } + my $oid = OID_STAT_MAILERENTRY . '.' . $idx[0] . '.' . $idx[1]; + $request->setOID($oid); + debug("NEXT OID $oid"); + $mode = MODE_GET; + } + ++$idx[0] if $idx[0] == 1; + if ($mode == MODE_GET) { + my $mailer = $mstats{mailertab}->[$idx[1]]; + if ($idx[0] == 2) { + $request->setValue(ASN_OCTET_STR, $mailer); + } else { + $request->setValue(ASN_COUNTER64, + $mstats{mailer}{$mailer}[$idx[0] - 3]); + } + } + } +} + +sub get_totaltab { + my $request = shift; + my $mode = shift; + + debug("get_totaltab($mode," . join('.', @_) . ")"); + + if ($#_ == -1) { + @_ = ( 0, 0 ); + } + + my $idx = shift @_; + return unless $#_ == 0 and $_[0] == 0; + + my %mstats = mailer_stats(); + if ($idx-1 <= $#{$mstats{totals}}) { + if ($mode == MODE_GETNEXT) { + ++$idx; + my $oid = OID_STAT_TOTALTAB . '.' . $idx . '.0'; + if ($idx-1 <= $#{$mstats{totals}}) { + $request->setOID($oid); + debug("NEXT OID $oid"); + $mode = MODE_GET; + } else { + return get_conntab($request, MODE_GETNEXT); + } + } + $request->setValue(ASN_COUNTER64, $mstats{totals}->[$idx-1]) + if $mode == MODE_GET and $idx > 0; + } +} + +sub get_conntab { + my $request = shift; + my $mode = shift; + + debug("get_conntab($mode," . join('.', @_) . ")"); + + if ($#_ == -1) { + @_ = ( 0, 0 ); + } + + my $idx = shift @_; + return unless $#_ == 0 and $_[0] == 0; + + my %mstats = mailer_stats(); + if ($idx-1 <= $#{$mstats{conn}}) { + if ($mode == MODE_GETNEXT) { + ++$idx; + my $oid = OID_STAT_CONNTAB . '.' . $idx . '.0'; + if ($idx-1 <= $#{$mstats{conn}}) { + $request->setOID($oid); + debug("NEXT OID $oid"); + $mode = MODE_GET; + } + } + $request->setValue(ASN_COUNTER64, $mstats{conn}->[$idx-1]) + if $mode == MODE_GET and $idx > 0; + } +} + +my %oidhandler = ( + (+SUBOID_QUEUE_TOTAL) => \&get_queue_totals, + (+SUBOID_STAT_MAILERTAB) => \&get_mailertab, + (+SUBOID_STAT_TOTALTAB) => \&get_totaltab, + (+SUBOID_STAT_CONNTAB) => \&get_conntab +); + + +sub mailstats_handler { + my ($handler, $registration_info, $request_info, $requests) = @_; + + for (my $request = $requests; $request; $request = $request->next()) { + my $oid = $request->getOID(); + debug("OID $oid"); + $oid =~ s/$oid_base//; + $oid =~ s/^\.//; + my $mode = $request_info->getMode(); + my $fun; + my @subid = split /\./, $oid; + if ($#subid == -1) { + debug("RESTART"); + if ($mode == MODE_GETNEXT) { + $request->setOID($oid_base . '.' . SUBOID_QUEUE_TOTAL . '.0'); + push @subid, 0; + $fun = $oidhandler{+SUBOID_QUEUE_TOTAL}; + $mode = MODE_GET; + } + } else { + $fun = $oidhandler{shift @subid}; + } + + &{$fun}($request, $mode, @subid) if defined $fun; + } +} + +my $agent = new NetSNMP::agent('Name' => 'sendmail'); +$agent->register("sendmail", $oid_base, \&mailstats_handler); + +__END__ + +=head1 NAME + +NetSNMP::Sendmail - NetSNMP plugin for Sendmail statistics + +=head1 SYNOPSIS + +B<perl use NetSNMP::Sendmail qw (:config bindir /usr/bin/sm.bin);> + +=head1 DESCRIPTION + +A perl plugin for B<net-snmp> that provides access to Sendmail +statistics information obtained by B<mailq> and B<mailstats>. + +In most cases adding + + perl use NetSNMP::Sendmail; + +to B<snmpd.conf>(5) is enough to get the plugin working. You may +however need to tune it. For example, Debian-based distributions +override default Sendmail binaries with homemade scripts that have +somewhat different output format, which can confuse this module. The +binaries are then located in the F</usr/lib/sm.bin> directory. To have +the plugin use the right binaries, load it as follows: + + perl use NetSNMP::Sendmail qw(:config bindir /usr/lib/sm.bin); + +Another way to do so would be to export the B<Configure> method and +call it right after requiring the module: + + perl use NetSNMP::Sendmail qw(Configure); + perl NetSNMP::Sendmail::Configure(bindir => '/usr/lib/sm.bin'); + +In general, configuration options and corresponding values are either +passed as a hash to the B<Configure> function, or passed with the +B<use> statement following the B<:config> marker. The following +options are defined: + +=over 4 + +=item B<mailq_ttl> + +Time in seconds during which the result of the recent invocation of +B<mailq>(1) is cached. Default is 10. + +=item B<mailstats_ttl> + +Time in seconds during which the result of the recent invocation of +B<mailstats>(8) is cached. Default is 10. + +=item B<mailq> + +Name of the B<mailq> binary. Default is B<mailq>. + +=item B<mailstats> + +Name of the B<mailstats> binary. Default is B<mailstats>. + +=item B<bindir> + +Directory where to look for B<mailq> and B<mailstats>. It is unset by +default, which means that both binaries will be looked up using the +B<PATH> environment variable, unless they are set to absolute pathname +using B<mailq> and B<mailstats> keywords. + +=back + +=head2 OIDS + +The MIB is defined in file SENDMAIL-STATS.txt, which is distributed along +with this module. The following OIDs are defined: + +=over 4 + +=item B<queueTotal.0> + +Total number of messages in the queue. + +=item B<mailerTable> + +This OID provides a conceptual table of mailers with the corresponding +statistics. Each row has the following elements (I<N> stands for the +row index): + +=over 4 + +=item B<mailerName.>I<N> + +Name of the mailer, as set in its definition in F<sendmail.cf>. + +=item B<mailerMessagesFrom.>I<N> + +Number of outgoing messages sent using this mailer. + +=item B<mailerKBytesFrom.>I<N> + +Number of kilobytes in outgoing messages sent using this mailer. + +=item B<mailerMessagesTo.>I<N> + +Number of messages received using this mailer. + +=item B<mailerKBytesTo.>I<N> + +Number of kilobytes in messages received using this mailer. + +=item B<mailerMessagesRejected.>I<N> + +Number of messages rejected by this mailer. + +=item B<mailerMessagesDiscarded.>I<N> + +Number of messages discarded by this mailer. + +=item B<mailerMessagesQuarantined.>I<N> + +Number of messages put in quarantine by this mailer. + +=back + + +=item B<totalMessagesFrom.0> + +Total number of outgoing messages. + +=item B<totalKBytesFrom.0> + +Total number of outgoing kilobytes. + +=item B<totalMessagesTo.0> + +Total number of incoming messages. + +=item B<totalKBytesTo.0> + +Total number of incoming kilobytes. + +=item B<totalMessagesRejected.0> + +Total number of rejected messages. + +=item B<totalMessagesDiscarded.0> + +Total number of discarded messages. + +=item B<totalMessagesQuarantined.0> + +Total number of messages put in quarantine. + +=item B<connectionMessagesFrom.0> + +Number of messages sent over TCP connections. + +=item B<connectionMessagesTo.0> + +Number of messages received over TCP connections. + +=item B<connectionMessagesRejected.0> + +Number of messages that arrived over TCP connections and were rejected. + +=back + +=head1 SEE ALSO + +B<snmpd.conf>(5), B<snmpd>(8), B<mailq>(1), B<mailstats>(8). + +=head1 AUTHOR + +Sergey Poznyakoff <gray@gnu.org>. + +=cut + diff --git a/SENDMAIL-STATS.txt b/SENDMAIL-STATS.txt new file mode 100644 index 0000000..8fdb1c2 --- /dev/null +++ b/SENDMAIL-STATS.txt @@ -0,0 +1,226 @@ +SENDMAIL-STATS DEFINITIONS ::= BEGIN + +-- ************************************************************* +-- +-- Sendmail statistics MIB +-- +-- ************************************************************* + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, enterprises, Counter64 + FROM SNMPv2-SMI + OBJECT-GROUP, MODULE-COMPLIANCE + FROM SNMPv2-CONF; + +sendmail OBJECT IDENTIFIER ::= { enterprises 9163 100 } + +sendmailMIB MODULE-IDENTITY + LAST-UPDATED "201411280837Z" + ORGANIZATION "Gray Software" + CONTACT-INFO "Sergey Poznyakoff <gray@gnu.org>" + DESCRIPTION + "This MIB module defines objects for Sendmail statistics." + REVISION "201411280837Z" + DESCRIPTION + "First revision." + ::= { sendmail 0 } + +queueTotal OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages in queue." + ::= { sendmail 1 } + +mailerTable OBJECT-TYPE + SYNTAX SEQUENCE OF MailerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Mailer statistics table." + ::= { sendmail 2 } + +mailerEntry OBJECT-TYPE + SYNTAX MailerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry (conceptual row) describing a mailer." + INDEX { mailerIndex } + ::= { mailerTable 1 } + +MailerEntry ::= SEQUENCE { + mailerIndex Integer32, + mailerName mailerNameString, + mailerMessagesFrom Counter64, + mailerKBytesFrom Counter64, + mailerMessagesTo Counter64, + mailerKBytesTo Counter64, + mailerMessagesRejected Counter64, + mailerMessagesDiscarded Counter64, + mailerMessagesQuarantined Counter64, +} + +mailerIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A number uniquely identifying each mailer." + ::= { mailerEntry 1 } + +mailerNameString TEXTUAL-CONVENTION + SYNTAX OCTET STRING (SIZE (0..128)) + DISPLAY-HINT "128t" + STATUS current + +mailerName OBJECT-TYPE + SYNTAX mailerNameString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the mailer." + ::= { mailerEntry 2 } + +mailerMessagesFrom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages sent from the mailer." + ::= { mailerEntry 3 } + +mailerKBytesFrom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of kilobytes sent from the mailer." + ::= { mailerEntry 4 } + +mailerMessagesTo OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages sent to the mailer." + ::= { mailerEntry 5 } + +mailerKBytesTo OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of kilobytes sent to the mailer." + ::= { mailerEntry 6 } + +mailerMessagesRejected OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages rejected by this mailer." + ::= { mailerEntry 7 } + +mailerMessagesDiscarded OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages discarded by the mailer." + ::= { mailerEntry 8 } + +mailerMessagesQuarantined OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of messages quarantined by the mailer." + ::= { mailerEntry 9 } + +totals OBJECT IDENTIFIER ::= { sendmail 3 } + +totalMessagesFrom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages received." + ::= { totals 1 } + +totalKBytesFrom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of kilobytes received." + ::= { totals 2 } + +totalMessagesTo OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages sent." + ::= { totals 3 } + +totalKBytesTo OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of kilobytes sent." + ::= { totals 4 } + +totalMessagesRejected OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages rejected." + ::= { totals 5 } + +totalMessagesDiscarded OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages discarded." + ::= { totals 6 } + +totalMessagesQuarantined OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages quarantined." + ::= { totals 7 } + +connection OBJECT IDENTIFIER ::= { sendmail 4 } + + +connectionMessagesFrom OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages received over TCP." + ::= { connection 1 } + +connectionMessagesTo OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages sent over TCP." + ::= { connection 3 } + +connectionMessagesRejected OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Total number of messages rejected over TCP." + ::= { connection 5 } + diff --git a/install-mib.pl b/install-mib.pl new file mode 100755 index 0000000..56461a8 --- /dev/null +++ b/install-mib.pl @@ -0,0 +1,69 @@ +#! /usr/bin/env perl +# +use strict; +use File::Basename; +use File::Copy; +use autodie; + +# install-mib FILE DIR + +die "bad number of arguments" unless $#ARGV == 1; + +my ($file, $destdir) = @ARGV; + +my $mibname; + +open(my $fd, '<', $file); +while (<$fd>) { + s/^\s+//; + if (/([\S]+)\s+DEFINITIONS\s+::=\s+BEGIN\s*$/) { + $mibname = $1; + last; + } +} +close($fd); + +die "no MIB definition in $file" unless defined $mibname; + +mkdir($destdir) unless -e $destdir; + +copy($file, $destdir); + +my $index = "$destdir/.index"; +my $tmpname = $index . $$; +open(my $ofd, '>', $tmpname); + +my $modified; + +$file = basename($file); + +if (-e $index) { + open($fd, '+<', $index); + while (<$fd>) { + if (defined($mibname) and /^${mibname}\s+/) { + chomp; + my @a = split /\s+/; + unless ($#a == 1 and $a[1] eq $file) { + print $ofd "$mibname $file\n"; + $modified = 1; + } + $mibname = undef; + } else { + print $ofd $_; + } + } + close($fd); +} + +if (defined($mibname)) { + print $ofd "$mibname $file\n"; + $modified = 1; +} +close $ofd; + +if ($modified) { + unlink $index if -e $index; + rename $tmpname, $index; +} else { + unlink $tmpname; +} |