system: Linux mars.sprixweb.com 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
Direktori : /usr/bin/ |
|
Current File : //usr/bin/amavisd-agent |
#!/usr/bin/perl -T
#------------------------------------------------------------------------------
# This is amavisd-agent, a demo program to display
# SNMP-like counters updated by amavisd-new.
#
# Author: Mark Martinec <Mark.Martinec@ijs.si>
#
# Copyright (c) 2004-2014, Mark Martinec
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of the Jozef Stefan Institute.
# (the above license is the 2-clause BSD license, also known as
# a "Simplified BSD License", and pertains to this program only)
#
# Patches and problem reports are welcome.
# The latest version of this program is available at:
# http://www.ijs.si/software/amavisd/
#------------------------------------------------------------------------------
use strict;
use re 'taint';
use warnings;
no warnings 'uninitialized';
use Errno qw(ENOENT);
use Time::HiRes ();
use BerkeleyDB;
my($dbfile) = 'snmp.db';
my($db_home) = # DB databases directory
defined $ENV{'AMAVISD_DB_HOME'} ? $ENV{'AMAVISD_DB_HOME'} : '/var/spool/amavisd/db';
my($wakeuptime) = 10; # -w, sleep time in seconds, may be fractional
my($repeatcount); # -c, repeat count (when defined)
use vars qw($VERSION); $VERSION = 2.701;
use vars qw(%values %virus_by_name);
use vars qw(%virus_by_os %spam_by_os %ham_by_os);
use vars qw(%history $avg_int $uptime);
$avg_int = 5*60; # 5 minute interval
sub p1($$@) {
my($k,$avg,@tot_k) = @_;
printf("%-35s %6d %6.0f/h", $k, $values{$k}, $avg*3600);
for my $tot_k (@tot_k) {
if ($values{$tot_k} <= 0) {
printf(" --- %%")
} else {
printf(" %7.1f %%", 100*$values{$k}/$values{$tot_k})
}
print " ($tot_k)";
}
print "\n";
}
sub p1_size($$@) {
my($k,$avg,@tot_k) = @_;
my($scale) = 1024*1024;
printf("%-35s %6.0fMB %4.0fMB/h", $k, $values{$k}/$scale, $avg*3600/$scale);
for my $tot_k (@tot_k) {
if ($values{$tot_k} <= 0) {
printf(" --- %%")
} else {
printf(" %5.1f %%", 100*$values{$k}/$values{$tot_k})
}
print " ($tot_k)";
}
print "\n";
}
sub p1_time($$$$) {
my($k,$dv,$dcnt,$tot_k) = @_;
printf("%-35s %6.0f s %8s s/msg (%s)\n",
$k, $values{$k}/1000,
$dcnt < 1 ? "---" : sprintf("%7.3f",$dv/1000/$dcnt),
$tot_k);
}
sub p2($$$$) {
my($k,$avg,$tot_k,$href) = @_;
if ($values{$tot_k} > 0) {
printf("%-35s %6d %6.0f/h %6.1f %% (%s)\n",
$k, $href->{$k}, $avg*3600, 100*$href->{$k}/$values{$tot_k}, $tot_k);
}
}
sub enqueue($$$$$) {
my($name,$now,$val,$msgcnt,$hold_time) = @_;
if (ref $history{$name} ne 'ARRAY') { $history{$name} = [] }
my($oldest_useful);
for my $j (0..$#{$history{$name}}) {
if ($history{$name}->[$j][0] + $hold_time >= $now)
{ $oldest_useful = $j; last }
}
if (defined $oldest_useful) {
@{$history{$name}} =
@{$history{$name}}[$oldest_useful..$#{$history{$name}}];
}
push(@{$history{$name}}, [$now,$val,$msgcnt]);
my($average,$dv,$dt,$dcnt); my($n) = scalar(@{$history{$name}});
my($oldest) = $history{$name}->[0];
my($latest) = $history{$name}->[$n-1];
$dt = $latest->[0] - $oldest->[0];
$dv = $latest->[1] - $oldest->[1];
$dcnt = $latest->[2] - $oldest->[2];
if ($n < 2 || $dt < $hold_time/2) {
$dt = $uptime; $dv = $val; $dcnt = $msgcnt; # average since the start time
}
if ($dt > 0) { $average = $dv/$dt }
($average, $dv, $dt, $dcnt, $n);
}
sub fmt_ticks($) {
my($t) = @_;
my($hh)= $t % 100; $t = int($t/100);
my($s) = $t % 60; $t = int($t/60);
my($m) = $t % 60; $t = int($t/60);
my($h) = $t % 24; $t = int($t/24);
my($d) = $t;
sprintf("%d days, %d:%02d:%02d.%02d", $d,$h,$m,$s,$hh);
};
# main program starts here
my($normal_termination) = 0;
$SIG{INT} = sub { die "\n" }; # do the END code block
while (@ARGV) {
my($opt) = shift @ARGV;
my($val) = shift @ARGV;
if ($opt eq '-w' && $val =~ /^\+?\d+(?:\.\d*)?\z/) { $wakeuptime = $val }
elsif ($opt eq '-c' && $val =~ /^[+-]?\d+\z/) { $repeatcount = $val }
else
{ die "Usage: $0 [-c <count>] [-w <wait-interval>]\n" }
}
my($stat,$key,$val);
my($env,$db,$old_db_inode,@dbstat,$cursor);
for (;;) {
last if defined $repeatcount && $repeatcount <= 0;
@dbstat = stat("$db_home/$dbfile");
my($errn) = @dbstat ? 0 : 0+$!;
$errn==0 || $errn==ENOENT or die "stat $db_home/$dbfile: $!";
if (defined $db && $old_db_inode != $dbstat[1]) {
$db->db_close==0 or die "BDB db_close error: $BerkeleyDB::Error $!";
undef $db;
printf STDERR ("Reopening snmp database %s/%s\n", $db_home,$dbfile);
}
if (!defined $db && $errn==0) {
$old_db_inode = $dbstat[1];
$env = BerkeleyDB::Env->new(
-Home => $db_home, -Flags => DB_INIT_CDB | DB_INIT_MPOOL,
-ErrFile => \*STDOUT, -Verbose => 1);
defined $env or die "BDB no env: $BerkeleyDB::Error $!";
$db = BerkeleyDB::Hash->new(-Filename => $dbfile, -Env => $env);
defined $db or die "BDB no dbS 1: $BerkeleyDB::Error $!";
}
$| = 0;
%values = (); %virus_by_name = ();
%virus_by_os = (); %spam_by_os = (); %ham_by_os = ();
my($now); my($eval_stat,$interrupt); $interrupt = '';
if (!defined $db) {
printf STDERR ("No snmp database %s/%s; waiting...\n", $db_home,$dbfile);
} else {
$repeatcount-- if defined $repeatcount && $repeatcount > 0;
print "\n\n";
my($h1) = sub { $interrupt = $_[0] };
local(@SIG{qw(INT HUP TERM TSTP QUIT ALRM USR1 USR2)}) = ($h1) x 8;
eval {
$cursor = $db->db_cursor; # obtain read lock
defined $cursor or die "db_cursor error: $BerkeleyDB::Error";
$now = Time::HiRes::time;
while ( ($stat=$cursor->c_get($key,$val,DB_NEXT)) == 0 ) {
if ($key =~ /^(virus\.byname\..*)\z/s) { $virus_by_name{$1} = $val }
elsif ($key =~ /^(virus\.byOS\..*)\z/s) { $virus_by_os{$1} = $val }
elsif ($key =~ /^(ham\.byOS\..*)\z/s) { $ham_by_os{$1} = $val }
elsif ($key =~ /^(?:spam|spammy)\.byOS\.(.*)\z/s)
{ $spam_by_os{"spam.byOS.$1"} = $val }
else { $values{$key} = $val }
}
$stat==DB_NOTFOUND or die "c_get: $BerkeleyDB::Error $!";
$cursor->c_close==0 or die "c_close error: $BerkeleyDB::Error";
$cursor = undef;
};
$eval_stat = $@;
if (defined $db) {
$cursor->c_close if defined $cursor; # unlock, ignoring status
$cursor = undef;
}
}
if ($interrupt ne '') { kill($interrupt,$$) } # resignal
elsif ($eval_stat ne '') { chomp($eval_stat); die "BDB $eval_stat\n" }
for my $k (sort keys %values) {
if ($values{$k} =~ /^(?:C32|C64) (.*)\z/) {
$values{$k} = $1;
} elsif ($k eq 'sysUpTime' && $values{$k} =~ /^INT (.*)\z/) {
$uptime = $now - $1; my($ticks) = int($uptime*100);
printf("%-15s %s %s (%s)\n",
$k,'TimeTicks', $ticks, fmt_ticks($ticks));
delete($values{$k});
} elsif ($values{$k} =~ /^(?:INT|TIM) (.*)\z/) {
$values{$k} = $1;
} else {
printf("%-15s %s\n", $k,$values{$k});
delete($values{$k});
}
}
my($msgcnt) = $values{'InMsgs'};
for (sort keys %values) {
my($avg,$dv,$dt,$dcnt,$n) =
enqueue($_, $now, $values{$_}, $msgcnt, $avg_int);
if (/^OpsDecTyp/) {} # later
elsif (/^CacheHitsVirusMsgs$/) { p1($_,$avg,'ContentVirusMsgs') }
elsif (/^CacheHitsBannedMsgs$/) { p1($_,$avg,'ContentBannedMsgs') }
elsif (/^CacheHitsSpamMsgs$/) { p1($_,$avg,'ContentSpamMsgs') }
elsif (/^Cache/) { p1($_,$avg,'CacheAttempts') }
# elsif (/^Content(.*?)Msgs/) { p1($_,$avg,'Content'.$1.'Msgs') }
elsif (/^Content(.*?)Msgs(.*)\z/) { p1($_,$avg,'InMsgs'.$2) }
elsif (/^Content/) { p1($_,$avg,'InMsgs') }
elsif (/^OpsSql/) { p1($_,$avg,'InMsgsRecips') }
elsif (/^InMsgsSize/) { p1_size($_,$avg,'InMsgsSize') }
elsif (/^InMsgsRecipsLocal\z/) { p1($_,$avg,'InMsgsRecips') }
elsif (/^InMsgsRecips(.*)\z/) { p1($_,$avg,'InMsgs'.$1) }
elsif (/^InMsgsBounce./) { p1($_,$avg,'InMsgsBounce') }
elsif (/^(InMsgs|Ops)/) { p1($_,$avg,'InMsgs') }
elsif (/^OutMsgsSize\z/) { p1_size($_,$avg,'InMsgsSize') }
elsif (/^OutMsgsSize/) { p1_size($_,$avg,'OutMsgsSize') }
elsif (/^OutMsgs\z/) { p1($_,$avg,'InMsgs') }
elsif (/^Out/) { p1($_,$avg,'OutMsgs') }
elsif (/^QuarMsgsSize\z/) { p1_size($_,$avg,'InMsgsSize') }
elsif (/^QuarMsgsSize/) { p1_size($_,$avg,'QuarMsgsSize') }
elsif (/^Quar/) { p1($_,$avg,'QuarMsgs') }
elsif (/^LogEntries\z/) { p1($_,$avg,'InMsgs') }
elsif (/^Log/) { p1($_,$avg,'LogEntries') }
elsif (/^GenMailIdRetries/) { p1($_,$avg,'InMsgs') }
elsif (/^PenPalsAttempts\z/) { p1($_,$avg,'InMsgsRecipsLocal') }
elsif (/^PenPalsHits\z/) { p1($_,$avg,'PenPalsAttempts')}
elsif (/^PenPalsHits./) { p1($_,$avg,'PenPalsHits') }
elsif (/^PenPals/) { p1($_,$avg,'PenPalsAttempts') }
elsif (/^SqlAddrSenderAttempts\z/) { p1($_,$avg,'InMsgs') }
elsif (/^SqlAddrSender/) { p1($_,$avg,'SqlAddrSenderAttempts') }
elsif (/^SqlAddrRecipAttempts\z/) { p1($_,$avg,'InMsgsRecips') }
elsif (/^SqlAddrRecip/) { p1($_,$avg,'SqlAddrRecipAttempts') }
elsif (/^banned\.byOS/) { p1($_,$avg,'InMsgs') }
elsif (/^TimeElapsed/i) { p1_time($_,$dv,$dcnt,'InMsgs') }
else { p1($_,$avg,undef) }
}
for (sort { $values{$b}<=>$values{$a} } grep {/^OpsDecTyp/} keys %values) {
my($avg,$dv,$dt,$dcnt,$n) =
enqueue($_, $now, $values{$_}, $msgcnt, $avg_int);
p1($_,$avg,'InMsgs');
}
for my $href (\%virus_by_name,\%virus_by_os,\%spam_by_os,\%ham_by_os) {
for (keys %$href)
{ $href->{$_} = $1 if $href->{$_} =~ /^(?:C32|C64) (.*)\z/ }
}
for my $href (\%virus_by_os,\%spam_by_os,\%ham_by_os) {
for (keys %$href) {
/^[a-zA-Z]+\.byOS\.(.*)\z/; my($os) = $1;
$values{"all.byOS.$os"} += $href->{$_};
}
}
my($separated) = 0;
for my $pair ([\%virus_by_name, 'ContentVirusMsgs',],
[\%virus_by_os, 'ContentVirusMsgs',],
[\%spam_by_os, 'ContentSpamMsgs', ],
[\%ham_by_os, 'ContentCleanMsgs' ] ) {
my($href,$tot_k) = @$pair;
for (sort {$href->{$b} <=> $href->{$a}} keys %$href) {
if (!$separated) { print "\n"; $separated = 1 }
my($avg,$dv,$dt,$dcnt,$n) =
enqueue($_, $now, $href->{$_}, $msgcnt, $avg_int);
p2($_,$avg,$tot_k,$href);
}
}
if (0) { # disabled
$separated = 0;
for my $href (\%virus_by_os, \%spam_by_os, \%ham_by_os) {
for (sort {$href->{$b} <=> $href->{$a}} keys %$href) {
if (!$separated) { print "\n"; $separated = 1 }
my($avg,$dv,$dt,$dcnt,$n) =
enqueue($_, $now, $href->{$_}, $msgcnt, $avg_int);
/^[a-zA-Z]+\.byOS\.(.*)\z/; my($os) = $1;
p2($_,$avg,"all.byOS.$os",$href);
}
}
$separated = 0;
for (sort { $values{$b}<=>$values{$a} }
grep {/^all\.byOS\./} keys %values) {
if (!$separated) { print "\n"; $separated = 1 }
my($avg,$dv,$dt,$dcnt,$n) =
enqueue($_, $now, $values{$_}, $msgcnt, $avg_int);
p1($_,$avg,'InMsgs');
}
}
$| = 1;
last if defined $repeatcount && $repeatcount <= 0;
Time::HiRes::sleep($wakeuptime) if $wakeuptime > 0;
} # forever
$normal_termination = 1;
END {
if (defined $db) {
$cursor->c_close if defined $cursor; # ignoring status
$db->db_close==0 or die "BDB db_close error: $BerkeleyDB::Error $!";
}
print STDERR "exited\n" if !$normal_termination;
}