aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2015-09-26 20:28:52 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2015-09-26 20:28:52 +0300
commitc62da081f3dca12030a32fc10eb240c45d08f8f3 (patch)
treec30ce230e8806a8cebc0fe245ddbe39065ca7e9c
parent40468ec97480e350dc47e6db44b87ccce35ac67b (diff)
downloadnetsnmp-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--.gitignore5
-rw-r--r--MANIFEST8
-rw-r--r--Makefile.PL15
-rw-r--r--NetSNMP/Sendmail.pm546
-rw-r--r--Sendmail.mib2c125
-rw-r--r--sendmail.pl239
6 files changed, 386 insertions, 552 deletions
diff --git a/.gitignore b/.gitignore
index 5871f3d..a8c39db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,8 @@ MYMETA.yml
Makefile
/blib
/pm_to_blib
+.emacs*
+META.json
+META.yml
+MYMETA.json
+Sendmail.pm
diff --git a/MANIFEST b/MANIFEST
index 14750a5..81fd335 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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};
+}
+

Return to:

Send suggestions and report system problems to the System administrator.