diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-09-26 20:28:52 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-09-26 20:28:52 +0300 |
commit | c62da081f3dca12030a32fc10eb240c45d08f8f3 (patch) | |
tree | c30ce230e8806a8cebc0fe245ddbe39065ca7e9c | |
parent | 40468ec97480e350dc47e6db44b87ccce35ac67b (diff) | |
download | netsnmp-sendmail-c62da081f3dca12030a32fc10eb240c45d08f8f3.tar.gz netsnmp-sendmail-c62da081f3dca12030a32fc10eb240c45d08f8f3.tar.bz2 |
Rewrite using mib2c
* .gitignore: Update.
* MANIFEST: Update.
* Makefile.PL: Build Sendmail.pm
* NetSNMP/Sendmail.pm: Remove.
* Sendmail.mib2c: New file.
* sendmail.pl: New file.
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | MANIFEST | 8 | ||||
-rw-r--r-- | Makefile.PL | 15 | ||||
-rw-r--r-- | NetSNMP/Sendmail.pm | 546 | ||||
-rw-r--r-- | Sendmail.mib2c | 125 | ||||
-rw-r--r-- | sendmail.pl | 239 |
6 files changed, 386 insertions, 552 deletions
@@ -4,3 +4,8 @@ MYMETA.yml Makefile /blib /pm_to_blib +.emacs* +META.json +META.yml +MYMETA.json +Sendmail.pm @@ -1,5 +1,9 @@ Makefile.PL MANIFEST This list of files -NetSNMP/Sendmail.pm +Sendmail.pm SENDMAIL-STATS.txt -install-mib.pl
\ No newline at end of file +install-mib.pl +Sendmail.mib2c +sendmail.pl +META.yml Module YAML meta-data (added by MakeMaker) +META.json Module JSON meta-data (added by MakeMaker) diff --git a/Makefile.PL b/Makefile.PL index 3a5e151..1cc23a6 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -22,24 +22,31 @@ WriteMakefile( 'ABSTRACT' => 'NetSNMP module for Sendmail statistics', 'LICENSE' => 'gpl_v3', 'FIRST_MAKEFILE' => 'Makefile', - 'VERSION_FROM' => 'NetSNMP/Sendmail.pm', + 'VERSION_FROM' => 'sendmail.pl', 'PM' => { - 'NetSNMP/Sendmail.pm' => '$(INST_LIBDIR)/Sendmail.pm' + 'Sendmail.pm' => '$(INST_LIBDIR)/Sendmail.pm' }, 'PREREQ_PM' => { 'NetSNMP::OID' => 0, 'NetSNMP::agent' => 0, - 'NetSNMP::ASN' => 0 }, + 'NetSNMP::ASN' => 0 } ); sub MY::postamble { return <<'_MAKE_'; +NET_SNMP_MIBDIRS = `net-snmp-config --mibdirs` + +Sendmail.pm: Sendmail.mib2c sendmail.pl SENDMAIL-STATS.txt + MIBDIRS=.:${NET_SNMP_MIBDIRS} \ + MIBS="+SENDMAIL-STATS" \ + mib2c -c Sendmail.mib2c -f Sendmail.pm -S prologue=sendmail.pl SENDMAIL-STATS::sendmail + INSTALLSITEMIB = $(SITEPREFIX)/share/snmp/mibs DESTINSTALLSITEMIB = $(DESTDIR)$(INSTALLSITEMIB) install:: install-mib install-mib: - $(PERLRUN) install-mib.pl SENDMAIL-STATS.txt $(DESTINSTALLSITEMIB) + $(PERLRUN) install-mib.pl SENDMAIL-STATS.txt $(DESTINSTALLSITEMIB) _MAKE_ } diff --git a/NetSNMP/Sendmail.pm b/NetSNMP/Sendmail.pm deleted file mode 100644 index 28691ce..0000000 --- a/NetSNMP/Sendmail.pm +++ /dev/null @@ -1,546 +0,0 @@ -# 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; -require 5.10.0; -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 => '1'; -use constant SUBOID_STAT_MAILERTAB => '2'; -use constant SUBOID_STAT_TOTALTAB => '3'; -use constant SUBOID_STAT_CONNTAB => '4'; - -use constant OID_STAT_QUEUETOTALS => OID_BASE . '.' . SUBOID_QUEUE . '.1'; -use constant OID_STAT_QUEUETAB => OID_BASE . '.' . SUBOID_QUEUE . '.2'; -use constant OID_STAT_QUEUEENTRY => OID_STAT_QUEUETAB . '.1'; -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 -# print STDERR @_; -# print STDERR "\n"; -} - -my %timestamp; - -sub queue_stats { - state %tmp; - - if ($ttl{mailq}) { - my $now = time(); - return %tmp if $now - $timestamp{mailq} < $ttl{mailq}; - $timestamp{mailq} = $now; - %tmp = (); - } - open(my $fd, '-|', $mailq_bin) - or die "can't run $mailq_bin: $!"; - while (<$fd>) { - chomp; - if (/^(^\S+) is empty/) { - push @{$tmp{q}}, [ $1, 0 ]; - } elsif (/^\s*(\S+) \((\d+) requests\)/) { - push @{$tmp{q}}, [ $1, $2 ]; - } elsif (/Total requests:\s+(\d+)\s*$/) { - $tmp{total} = $1 - } - } - close($fd); - return %tmp; -} - -sub mailer_stats { - state $timestamp; - state %mstats; - - my $now = time(); - return %mstats if $now - $timestamp{mailstats} < $ttl{mailstats}; - $timestamp{mailstats} = $now; - %mstats = (); - - 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 { - my $request = shift; - my $mode = shift; - - debug("get_queue: enter: @_\n"); - my $prim = shift; - if ($prim == 1) { - if ($_[0] == 0) { - if ($mode == MODE_GETNEXT) { - get_queuetab($request, MODE_GETNEXT); - } elsif ($mode == MODE_GET) { - my %s = queue_stats(); - if (exists($s{total})) { - $request->setValue(ASN_COUNTER64, $s{total}); - } - } - } - } elsif ($prim == 2) { - get_queuetab($request, $mode, @_); - } - debug("get_queue: exit\n"); -} - -sub get_queuetab { - my $request = shift; - my $mode = shift; - - debug("get_queuetab($mode," . join('.', @_) . ")"); - - my @idx = @_; - if ($#idx == -1) { - @idx = (1, 1, -1); - } - return unless shift(@idx) == 1; - return unless $#idx == 1; - - my %qstats = queue_stats(); - if ($idx[1] <= $#{$qstats{q}}) { - if ($mode == MODE_GETNEXT) { - ++$idx[1]; - if ($idx[1] > $#{$qstats{q}}) { - $idx[1] = 0; - ++$idx[0]; - return get_mailertab($request, MODE_GETNEXT) - unless $idx[0]-2 <= $#{$qstats{q}[$idx[1]]}; - } - ++$idx[0] if $idx[0] == 1; - my $oid = OID_STAT_QUEUEENTRY . '.' . $idx[0] . '.' . $idx[1]; - $request->setOID($oid); - debug("NEXT OID $oid"); - $mode = MODE_GET; - } - if ($mode == MODE_GET) { - my $type = ($idx[0] == 2) ? ASN_OCTET_STR : ASN_COUNTER64; - $request->setValue($type, $qstats{q}[$idx[1]][$idx[0]-2]); - } - } -} - -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]; - ++$idx[0] if $idx[0] == 1; - 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; - } - 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) => \&get_queue, - (+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_STAT_QUEUETOTALS . '.0'); - push @subid, SUBOID_QUEUE, 0; - $fun = $oidhandler{+SUBOID_QUEUE}; - $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.mib2c b/Sendmail.mib2c new file mode 100644 index 0000000..bbf0269 --- /dev/null +++ b/Sendmail.mib2c @@ -0,0 +1,125 @@ +## SNMP Sendmail Statistics Module +## 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/>. +@startperl@ + +$vars{'sendmail_translate'} = sub { + my $name = shift; + if ($name eq 'queueTotal') { + $vars{'fn_table'} = 0; + $vars{'fn_get'} = "get_$name"; + } elsif ($name =~ /^((queue)|(total)|(connection))/) { + $vars{'fn_table'} = 1; + $vars{'fn_get'} = "$1_table_get"; + } else { + $vars{'fn_table'} = 0; + $vars{'fn_get'} = "get_$name"; + } + return 0; +}; + +$vars{agentname} = $vars{name}; +$vars{agentname} =~ s/\.pm//; +$vars{tempfile} = "$vars{agentname}.tmp"; + + +0; +@endperl@ +@open ${tempfile}@ +# Hash for all OIDs +@printf "my %soidtable={\n", $@ +@foreach $t table@ + @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@ + @eval $idxoffset = $c.oidlength@ + "$c.objectID$idxelem" => { + func => sub { get_$t('$c', $c.oidlength, @_) }, + type => $c.type, + check => sub { check_$t($c.oidlength, @_) }, + nextoid => sub { next_$t($c.oidlength, @_) }, + istable => '1', + next => "", + numindex => $numindex + }, + @end@ + @end@ +@end@ +## output the hash with the OIDs and handlers +## Scalars have a single index element +# Scalars +@foreach $s scalar@ + @if $s.accessible@ + @startperl@ + &{$vars{'sendmail_translate'}}($vars{s}); + @endperl@ + '$s.objectID.0' => { + @if $fn_table@ + func => sub { $fn_get('$s', @_) }, + @else@ + func => \&$fn_get, + @end@ + istable => 0, + 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 +my $@agent = new NetSNMP::agent('Name' => '$agentname'); +@printf "registerAgent(%sagent, '$oid', %soidtable);",$,$@ + +@close ${tempfile}@ +@startperl@ +use File::Copy; +use autodie; + +print "creating $vars{name}\n"; + +open(FILE, '>', $vars{name}); + +print FILE "# THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT.\n"; + +copy($vars{prologue}, \*FILE) if defined $vars{prologue}; +copy($vars{tempfile}, \*FILE); +copy($vars{epilogue}, \*FILE) if defined $vars{epilogue}; + +# Use concatenation to prevent Emacs from handling this as local variables +# block +print FILE "# Local " . "variables:\n"; +print FILE "# buffer" . "-read-only: t\n"; +print FILE "# End:\n"; +print FILE "# vi: set ro:\n"; + +close FILE; +unlink $vars{tempfile}; +0; +@endperl@ + diff --git a/sendmail.pl b/sendmail.pl new file mode 100644 index 0000000..8cc6c65 --- /dev/null +++ b/sendmail.pl @@ -0,0 +1,239 @@ +# SNMP Sendmail Statistics Module +# 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; +require 5.10.0; +use strict; +use feature 'state'; +use NetSNMP::agent::Support; +use NetSNMP::agent (':all'); +use NetSNMP::ASN (':all'); +use Carp; + +use Data::Dumper; + +require Exporter; +our @ISA = qw(Exporter); + +our $VERSION = "0.91"; + +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 debug { +} + +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; +} + +my %timestamp; + +sub queue_stats { + state %tmp; + + if ($ttl{mailq}) { + my $now = time(); + return %tmp if $now - $timestamp{mailq} < $ttl{mailq}; + $timestamp{mailq} = $now; + %tmp = (); + } + open(my $fd, '-|', $mailq_bin) + or die "can't run $mailq_bin: $!"; + while (<$fd>) { + chomp; + if (/^(^\S+) is empty/) { + push @{$tmp{q}}, { queueName => $1, queueMessages => 0 }; + } elsif (/^\s*(\S+) \((\d+) requests\)/) { + push @{$tmp{q}}, { queueName => $1, queueMessages => $2 }; + } elsif (/Total requests:\s+(\d+)\s*$/) { + $tmp{total} = $1 + } + } + close($fd); + return %tmp; +} + +sub mailer_stats { + state $timestamp; + state %mstats; + + my $now = time(); + return %mstats if $now - $timestamp{mailstats} < $ttl{mailstats}; + $timestamp{mailstats} = $now; + %mstats = (); + + 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}}{('totalMessagesFrom', + 'totalKBytesFrom', + 'totalMessagesTo', + 'totalKBytesTo', + 'totalMessagesRejected', + 'totalMessagesDiscarded', + 'totalMessagesQuarantined')} = @a[1..7]; + } elsif ($a[0] eq 'C') { + @{$mstats{conn}}{('connectionMessagesFrom', + 'connectionMessagesTo', + 'connectionMessagesRejected')} = @a[1..3]; + } else { + my %h; + @h{('mailerMessagesFrom', + 'mailerKBytesFrom', + 'mailerMessagesTo', + 'mailerKBytesTo', + 'mailerMessagesRejected', + 'mailerMessagesDiscarded', + 'mailerMessagesQuarantined', + 'mailerName')} = @a[1..8]; + push @{$mstats{mailer}}, \%h; + } + } + close($fd); + return %mstats; +} + +# ############# + +sub get_queueTotal { + my %qstats = queue_stats(); + return $qstats{total}; +} + +sub get_queueTable { + my ($name, $off, $oid) = @_; + my $idx = getOidElement($oid, $off); + my %qstats = queue_stats(); + return $qstats{q}->[$idx-1]{$name}; +} + +sub check_queueTable { + my ($off, $oid) = @_; + my $idx = getOidElement($oid, $off); + my %qstats = queue_stats(); + return $idx-1 <= $#{$qstats{q}}; +} + +sub next_queueTable { + my ($len, $oid) = @_; + + my $idx = getOidElement($oid, $len); + my %qstats = queue_stats(); + ++$idx; + if ($idx-1 <= $#{$qstats{q}}) { + return setOidElement($oid, $len, $idx); + } + return 0; +} + +sub get_mailerTable { + my ($name, $off, $oid) = @_; + my $idx = getOidElement($oid, $off); + my %mstats = mailer_stats(); + return $mstats{mailer}->[$idx-1]{$name}; +} + +sub check_mailerTable { + my ($off, $oid) = @_; + my $idx = getOidElement($oid, $off); + my %mstats = mailer_stats(); + return $idx-1 <= $#{$mstats{mailer}}; +} + +sub next_mailerTable { + my ($len, $oid) = @_; + + my $idx = getOidElement($oid, $len); + my %mstats = mailer_stats(); + + ++$idx; + if ($idx-1 <= $#{$mstats{mailer}}) { + return setOidElement($oid, $len, $idx); + } + return 0; +} + +sub total_table_get { + my $name = shift; + my %mstats = mailer_stats(); + return $mstats{totals}->{$name}; +} + +sub connection_table_get { + my $name = shift; + my %mstats = mailer_stats(); + return $mstats{conn}->{$name}; +} + |