Blame contrib/mrtg-mail/mailstats-horowitz

Packit 667938
#!/usr/bin/perl
Packit 667938
#
Packit 667938
# Author by Rick Horowitz <rick@techstop.com> 1998-12-16
Packit 667938
# Inspired by, and may show remnants of code from: 
Packit 667938
#            "mailstats" by Petter Reinholdtsen <pere@td.org.uit.no> 
Packit 667938
#             dated 1997-07-09 and part of mrtg2.54c dist
Packit 667938
# Petter credits Rachel Polanskis <rachel@juno.virago.org.au> for 
Packit 667938
# the original. 
Packit 667938
# Type "perldoc mrtg-mailstat" from a shell prompt for more information
Packit 667938
# on this script and its use. 
Packit 667938
#
Packit 667938
Packit 667938
use strict;
Packit 667938
use Socket;
Packit 667938
use Getopt::Long;
Packit 667938
Packit 667938
# IMPORTANT: THIS NEXT LINE ENSURE THAT CASE MATTERS ON OPTIONS!!!
Packit 667938
$Getopt::Long::ignorecase = 0;    
Packit 667938
Packit 667938
use vars qw($datafile $server $sourceport $oldfrm $oldto $help
Packit 667938
            $newfrm $newto $uptime $mailtype $logbase);
Packit 667938
Packit 667938
# Assign options.  ("Illegal" options will be possible, 
Packit 667938
# but we'll warn about them via Usage().)
Packit 667938
#     h = runs the perldoc program to show the mrtg-mailstat manual
Packit 667938
#     m = specifies the type of mail we're checking for 
Packit 667938
#     p = specifies the port for reaching the mailstats on the mailserver
Packit 667938
#     s = specifies the location of the mailserver 
Packit 667938
# See the mrtg-mailstat man page for details.  
Packit 667938
GetOptions("help"          => \$help,
Packit 667938
           "logbase=s"     => \$logbase, 
Packit 667938
           "mailtype=s"    => \$mailtype, 
Packit 667938
           "port=i"        => \$sourceport, 
Packit 667938
           "server=s"      => \$server, 
Packit 667938
	   "<>"            => \&Usage); 
Packit 667938
Packit 667938
# HARDCODING SECTION -- MODIFY THESE ONLY IF YOU KNOW WHAT YOU ARE DOING!!!
Packit 667938
# Set these ONLY if you don't wish to use command line options.  For more 
Packit 667938
# information, type 'mrtg-mailstat -h' or 'perldoc mrtg-mailstat' from a 
Packit 667938
# shell prompt.
Packit 667938
$logbase    = '/tmp' unless $logbase;
Packit 667938
$mailtype   = '' unless $mailtype;
Packit 667938
$server     = '' unless $server;
Packit 667938
$sourceport = '' unless $sourceport;
Packit 667938
Packit 667938
# Location for keeping mail statistics.  The numbers stored here are 
Packit 667938
# compared to the new numbers at each run of this script. 
Packit 667938
$datafile       = "$logbase/${mailtype}-mailstat.old";
Packit 667938
Packit 667938
# Core portions of the program.  Most of retained code from original 
Packit 667938
# comes into play here.  
Packit 667938
GetHelp() if $help; 
Packit 667938
Usage() unless ($mailtype && $server && $sourceport);
Packit 667938
Packit 667938
($oldfrm, $oldto)          = GetOldStats($datafile);
Packit 667938
($newfrm, $newto, $uptime) = GetNewStats($server, $sourceport);
Packit 667938
Packit 667938
PutOldStats($datafile, $newfrm, $newto) || warn "$0: Unable to save stats to $datafile";
Packit 667938
Packit 667938
print $newfrm-$oldfrm,"\n",$newto-$oldto,"\n","$uptime\nthe mail server\n" if ($oldfrm);
Packit 667938
Packit 667938
##
Packit 667938
# Returns first line of file given as param split on (a single) space
Packit 667938
sub GetOldStats {
Packit 667938
    my($datafile) = @_;
Packit 667938
Packit 667938
    if (-e $datafile) { 
Packit 667938
        open(OLD, $datafile) || warn "$0: Unable to open $datafile for reading";
Packit 667938
        my($line) = <OLD>;
Packit 667938
        close(OLD);
Packit 667938
        return split(/ /, $line);
Packit 667938
    } else { 
Packit 667938
        return(0, 0);
Packit 667938
    }
Packit 667938
       
Packit 667938
}
Packit 667938
Packit 667938
sub GetNewStats {
Packit 667938
    my($server, $sourceport) = @_;
Packit 667938
    my(@output, $port, $proto, $iaddr, $paddr, $tempuptime, $curfrm, $curto, $uptime);
Packit 667938
    if ( $server eq "localhost" ) {
Packit 667938
	@output = `/usr/sbin/mailstats`;
Packit 667938
	chomp(@output);
Packit 667938
    } else {
Packit 667938
        if ($sourceport =~ /\D/) { 
Packit 667938
	    $port = getservbyname ($sourceport, 'tcp');
Packit 667938
         } else { 
Packit 667938
            $port = $sourceport;
Packit 667938
         }
Packit 667938
	die "$0: Bad port \"$sourceport\"" unless ($port);
Packit 667938
	$proto = getprotobyname ('tcp') || die "$0: Bad prototype tcp";
Packit 667938
Packit 667938
	$iaddr = inet_aton($server) or die "$0: no host \"$server\"";
Packit 667938
	$paddr = sockaddr_in($port, $iaddr);
Packit 667938
Packit 667938
	socket (SOCK, PF_INET, SOCK_STREAM, $proto) or die "$0: socket error $!";
Packit 667938
	connect (SOCK, $paddr) or die "$0: connect error $!";
Packit 667938
Packit 667938
	while (<SOCK>) {
Packit 667938
	    push(@output, $_);
Packit 667938
	}
Packit 667938
	close(SOCK) || warn "$0: socket close error $!";
Packit 667938
    }
Packit 667938
Packit 667938
    # Parse only the interesting lines. 
Packit 667938
    foreach (@output) {
Packit 667938
	($curfrm, $curto) = (split(/ +/))[2,4] if (/$mailtype/);
Packit 667938
        if (/UPTIME.*?up\s*(.*?), [0-9]* user/) { 
Packit 667938
            $uptime = $1;
Packit 667938
            $uptime =~ s/:([0-9]*)/ hours, $1 minutes/;
Packit 667938
        }
Packit 667938
    }
Packit 667938
Packit 667938
    # This line ensures no negative numbers.  See "perldoc mrtg-mailstat".
Packit 667938
    ($curfrm, $curto) = noNeg($curfrm, $curto);
Packit 667938
Packit 667938
    return ($curfrm, $curto, $uptime);
Packit 667938
Packit 667938
}   # End GetNewStats().
Packit 667938
Packit 667938
# Saves the information to the log file. (Note: Overwrites old contents
Packit 667938
# which aren't needed anymore, anyway.)
Packit 667938
sub PutOldStats {
Packit 667938
    my($datafile, $frm, $to) = @_;
Packit 667938
    open(STAT, ">$datafile") || return "";
Packit 667938
    print STAT "$frm $to\n";
Packit 667938
    close(STAT);
Packit 667938
    return "1";
Packit 667938
}   # End PutOldStats().
Packit 667938
Packit 667938
# Negative values should only occur the first time the script is ever run.
Packit 667938
# These must be converted to positives so subsequent runs of the script 
Packit 667938
# correctly compute new values. 
Packit 667938
sub noNeg  { 
Packit 667938
    
Packit 667938
    my ($frm, $to) = @_;
Packit 667938
Packit 667938
    $frm = -($frm) if ($frm < 0);
Packit 667938
    $to = -($to) if ($to < 0);
Packit 667938
Packit 667938
    return($frm, $to);
Packit 667938
Packit 667938
}   # End noNeg(). 
Packit 667938
Packit 667938
# Usage() simply checks to see that no "illegal" options 
Packit 667938
# have been entered.  If the program is thus improperly 
Packit 667938
# called, it issues a notice explaining how to read the 
Packit 667938
# man page for this program.  
Packit 667938
sub Usage { 
Packit 667938
Packit 667938
   my $option = shift; 
Packit 667938
Packit 667938
   print STDERR "You may wish to read the documentation \n";
Packit 667938
   print STDERR "(type \"perldoc mrtg-mailstat\" or \"mrtg-mailstat -h\")\n";
Packit 667938
Packit 667938
   exit(5); 
Packit 667938
Packit 667938
} # End Usage(). 
Packit 667938
Packit 667938
sub GetHelp { 
Packit 667938
Packit 667938
   system("perldoc mrtg-mailstat");
Packit 667938
   exit(0);
Packit 667938
Packit 667938
}   # End GetHelp().
Packit 667938
Packit 667938
__END__
Packit 667938
Packit 667938
=head1 NAME
Packit 667938
Packit 667938
mrtg-mailstat - Mail Statistics Collector for MRTG
Packit 667938
Packit 667938
=head1 SYNOPSIS
Packit 667938
Packit 667938
mrtg-mailstat S<[B<-h>]> S<[B<-m> I<mailtype>]> S<[B<-p> I<sourceport>]> 
Packit 667938
              S<[B<-s> I<server>]>
Packit 667938
Packit 667938
=head1 DESCRIPTION
Packit 667938
Packit 667938
The B<mrtg-mailstat> program retrieves statistical information from the 
Packit 667938
mail server.  It does not matter whether the script is run on the mail 
Packit 667938
server itself, or on a machine remote from the mail server.  
Packit 667938
Packit 667938
=head1  S<   Running mrtg-mailstat >
Packit 667938
Packit 667938
S<                                                                        >
Packit 667938
The proper way to run B<mrtg-mailstat> is to call it from an MRTG configuration
Packit 667938
file.  The following provides an example of a valid configuration file entry: 
Packit 667938
Packit 667938
=over 2
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
C<S<Target[smtp-mail]: `mrtg-mailstat -m smtp -p 7258 -s mail.techstop.com`>
Packit 667938
S<MaxBytes[smtp-mail]: 150                  >
Packit 667938
S<Options[smtp-mail]: gauge                 >
Packit 667938
S<Title[smtp-mail]: TechStop Support Services SMTP Mail Statistics>
Packit 667938
S<PageTop[smtp-mail]: E<lt>H1E<gt>TechStop SMTP Mail Statistics E<lt>/H1E<gt>>
Packit 667938
S<XSize[smtp-mail]: 500                     >
Packit 667938
S<YSize[smtp-mail]: 200                     >
Packit 667938
S<WithPeak[smtp-mail]: dwmy>
Packit 667938
S<YLegend[smtp-mail]: No. of messages>
Packit 667938
S<ShortLegend[smtp-mail]: messages>
Packit 667938
S<LegendI[smtp-mail]:  Incoming:>
Packit 667938
S<LegendO[smtp-mail]:  Outgoing: > >
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
This makes certain assumptions which are outlined below under I<Dependencies>.
Packit 667938
Packit 667938
=head1  S<   Switches >
Packit 667938
Packit 667938
S<                                                                        >
Packit 667938
Packit 667938
=head2  Hardcoding versus Using Switches
Packit 667938
Packit 667938
It is not necessary to provide switches to the program, if you prefer to "hardcode"
Packit 667938
the information in the script itself.  "Hardcoding" allows you to call the script 
Packit 667938
with less (or no) flags; information needed by the script, and not provided by a 
Packit 667938
flag,  must be "hardcoded" by you before this will work.  (This was provided for 
Packit 667938
diehards who hate the flexibility of switches.  I provided enough flexibility for 
Packit 667938
them to be inflexible. ;))
Packit 667938
Packit 667938
To "hardcode" your information into the script, look for the section near the 
Packit 667938
top of the script labeled "HARDCODING SECTION".  Change the "null" entries 
Packit 667938
represented by the double double quotes ("") so that they contain the appropriate
Packit 667938
values.  
Packit 667938
Packit 667938
Example:  
Packit 667938
Packit 667938
Packit 667938
=over 4 
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
C<$server     = "" unless $server; >
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
becomes  
Packit 667938
Packit 667938
=over 4
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
C<$server     = "mail.techstop.com" unless $server; >
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
As stated, this is not necessary; it is not even preferred.  You may, 
Packit 667938
and probably should, use the switches in the next subsection.  
Packit 667938
Packit 667938
=head2  Invoking Switches
Packit 667938
Packit 667938
B<mrtg-mailstat> switches adhere to the POSIX syntax for command-line
Packit 667938
options.  This means options can take a variety of forms.  
Packit 667938
For example, to specify running B<mrtg-mailstat> against port C<7258>
Packit 667938
of the mail server to obtain reports on smtp mail (see "I<mailtype> 
Packit 667938
under I<Available Switches> below) you could use any of the following forms:  
Packit 667938
Packit 667938
=over 5
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat -m smtp -p 7258>
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat -m=smtp -p=7258>       
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat -mailtype smtp -port 7258> 
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat -mailtype=smtp -port=7258> 
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat --m smtp --p 7258> 
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat --m=smtp --p=7258>
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat --mailtype smtp --port 7258>  
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat --mailtype=smtp --port=7258>  
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
Any of the last four forms are preferred.  One way of doing options 
Packit 667938
which is I<not> possible is: 
Packit 667938
Packit 667938
=over 5
Packit 667938
Packit 667938
=item    
Packit 667938
Packit 667938
C<% mrtg-mailstat --msmtp --p7258>
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
Use of that last form may cause results other than you expected. 
Packit 667938
(Important Note: The above examples would also require that the 
Packit 667938
server be "hardcoded" into the script as noted in the subsection on 
Packit 667938
I<Hardcoding versus Using Switches> above.)
Packit 667938
Packit 667938
=head2  Available Switches
Packit 667938
Packit 667938
The following switches are available:  
Packit 667938
Packit 667938
=over 2
Packit 667938
Packit 667938
=item B<--h[elp]>
Packit 667938
Packit 667938
The B<-h> flag causes B<mrtg-mailstat> to print this manual to 
Packit 667938
standard output.  For obvious reasons, this is not normally included in an 
Packit 667938
MRTG configuration file, nor invoked by cron.  
Packit 667938
Packit 667938
=item B<--l[ogbase]>
Packit 667938
Packit 667938
The B<-l> flag can be used to specify the directory in which to store the 
Packit 667938
file that holds the values from each run.  By default, this file is created 
Packit 667938
in I</tmp>, but if you need to store it in another directory, this is the 
Packit 667938
flag for you.  By the way, if the file doesn't exist, one is created.  A side-effect 
Packit 667938
of this is that if you try to use one "logbase" one time, and another the next, 
Packit 667938
the program has no way of warning you.  It simply creates a new file, and uses zero 
Packit 667938
values to begin its calculations.  This can have strange consequences for your 
Packit 667938
mail statistics.  Try to remember where you store your log, or use the hardcoding 
Packit 667938
option (see I<Hardcoding versus Using Switches> above).  
Packit 667938
Packit 667938
=item B<--m[ailtype]>
Packit 667938
Packit 667938
The B<-m> flag is used to specify the mail type.  The two 
Packit 667938
types reported by I</usr/bin/mailstat> are "esmtp" and "local".  The 
Packit 667938
"esmtp" line reports traffic between the mail server and other systems. 
Packit 667938
The "local" line reports traffic between users on the mail server.  For 
Packit 667938
most smaller networks, this likely means that "esmtp" reports mail between 
Packit 667938
their network and the Internet, and "local" reports mail between users 
Packit 667938
within the small network's organization.  Possible values for this flag are 
Packit 667938
"smtp" and "local".  B<Note the flag takes "smtp" and not "esmtp".>
Packit 667938
Packit 667938
=item B<--p[ort]>
Packit 667938
Packit 667938
The B<-p> flag specifies the port whence the statistics are obtained.  See
Packit 667938
the I<Dependencies> section below.  
Packit 667938
Packit 667938
=item B<--s[erver]>
Packit 667938
Packit 667938
The B<-s> flag specifies the mail server.  This can be either a DNS name, 
Packit 667938
or an IP number. 
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
=head1 DEPENDENCIES
Packit 667938
Packit 667938
The B<mrtg-mailstat> program makes certain assumptions.  The following is 
Packit 667938
quoted with a few changes from the documentation for the original B<mailstat> script 
Packit 667938
upon which B<mrtg-mailstat> is based.  In particular, it is important to note that 
Packit 667938
the original instructions were Solaris-centric.  Your system may have different commands 
Packit 667938
for starting and stopping the mail server, and your paths may be different (i.e., may 
Packit 667938
use /usr/local instead of /opt, or whatever).  You are assumed to be able to figure that 
Packit 667938
out yourself.  
Packit 667938
Packit 667938
=over 2
Packit 667938
Packit 667938
=item 1:  Ensure you have I</bin/mailstat> (or I</usr/sbin/mailstat>)on your system.
Packit 667938
Packit 667938
=item 2:  Enable I
Packit 667938
Packit 667938
    To do this you can just make sure the entry for "sendmail.st" in
Packit 667938
    "sendmail.cf" is uncommented.  On the BSD/OS 3.1 system mrtg-mailstat was 
Packit 667938
    tested on, the /etc/sendmail.cf entries look like this:  
Packit 667938
Packit 667938
    OS/var/log/sendmail.st
Packit 667938
    O StatusFile=/var/log/sendmail.st
Packit 667938
Packit 667938
Packit 667938
    Then do the command:
Packit 667938
Packit 667938
        # touch /var/log/sendmail.st
Packit 667938
Packit 667938
    And restart sendmail:
Packit 667938
Packit 667938
        # /etc/init.d/sendmail stop
Packit 667938
        # /etc/init.d/sendmail start
Packit 667938
Packit 667938
Packit 667938
=item 3:  Create the following shell-script (B<Note!> This section is different than the original version!):
Packit 667938
Packit 667938
        #!/bin/sh
Packit 667938
        #
Packit 667938
        # smtp-stats: invoke mailstats from a wrapper for use in inetd.
Packit 667938
        #
Packit 667938
        PATH=/bin:/sbin
Packit 667938
        if [ -x "/usr/sbin/mailstats" ]
Packit 667938
           then
Packit 667938
           temp1=`/usr/sbin/mailstats -f/var/log/sendmail.st`
Packit 667938
        fi
Packit 667938
Packit 667938
        if [ -x "/usr/bin/uptime" ]
Packit 667938
           then
Packit 667938
           temp2=`/usr/bin/uptime`
Packit 667938
        fi
Packit 667938
Packit 667938
        echo -e "$temp1\nUPTIME: $temp2"
Packit 667938
Packit 667938
I run this out of /usr/local/bin, and call it "smtp-stats"
Packit 667938
Packit 667938
=item 4:  Now add the following to /etc/services:
Packit 667938
Packit 667938
        # /etc/services
Packit 667938
        #
Packit 667938
        smtp-stats      7256/tcp                        # smtp-stats
Packit 667938
Packit 667938
I used port 7256 as it was undefined.  You might like to select something
Packit 667938
else.
Packit 667938
Packit 667938
=item 5:  Add the following to /etc/inetd.conf:
Packit 667938
Packit 667938
        # /etc/inetd.conf
Packit 667938
        #
Packit 667938
        smtp-stats      stream  tcp     nowait root \
Packit 667938
        /usr/local/bin/smtp-stats smtp-stats
Packit 667938
Packit 667938
Packit 667938
***Ensure that the above is all on *one* line.  The sample above
Packit 667938
is broken on 2 lines for legibility!!
Packit 667938
Packit 667938
Packit 667938
=item 6:  Restart inetd
Packit 667938
Packit 667938
Packit 667938
=item 7:  Test the port.  you should see the following:
Packit 667938
Packit 667938
S<                                                       >
Packit 667938
S<unixhost:   {26} % telnet mailserver 7258              >
Packit 667938
S<Trying 192.168.1.8...                                  >
Packit 667938
S<Connected to mailserver.yourdomain.com.                >
Packit 667938
S<Escape character is '^]'.                              >
Packit 667938
S<Statistics from Wed Jan 14 03:10:34 1998               >
Packit 667938
S< M msgsfr bytes_from  msgsto   bytes_to  Mailer        >
Packit 667938
S< 3  79372    3623347K 143989    6954437K  local        >
Packit 667938
S< 5   9941     483230K   6669     652586K  esmtp        >
Packit 667938
S<========================================               >
Packit 667938
S< T  89313    4106577K 150658    7607023K               >
Packit 667938
S<UPTIME:  9:02AM  up 52 days, 48 mins, 2 users, load averages: 0.57, 0.56, 0.43>
Packit 667938
S<Connection closed by foreign host.                     >
Packit 667938
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
=head1 FILES
Packit 667938
Packit 667938
Strictly speaking, you needn't worry about the files.  If you've created
Packit 667938
the smtp-stats script noted above, and made the appropriate changes, the 
Packit 667938
only other I<file> you need to be concerned with is B<mrtg-mailstat> itself.
Packit 667938
Packit 667938
For completeness sake, I list all the files with which B<mrtg-mailstat> may 
Packit 667938
depend upon, utilize, create, or use.  
Packit 667938
Packit 667938
=over 5
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I<mrtg-mailstat>
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I</etc/sendmail.cf>
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I</usr/local/bin/smtp-stats>
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I</usr/sbin/mailstats>
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I</usr/bin/uptime>
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I
Packit 667938
Packit 667938
=item 
Packit 667938
Packit 667938
I<$logbase/${mailtype}-mailstat.old>
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
Packit 667938
=head1 AUTHOR
Packit 667938
Packit 667938
This B<mrtg-mailstat> program was written by Rick Horowitz <rick@techstop.com>, 
Packit 667938
tested, and released to the MRTG mailing list on December 16, 1998.  It was 
Packit 667938
inspired by, and contains remnants of code from: 
Packit 667938
Packit 667938
=over 10
Packit 667938
Packit 667938
=item
Packit 667938
Packit 667938
            "mailstats" by Petter Reinholdtsen <pere@td.org.uit.no> 
Packit 667938
             dated 1997-07-09 and part of mrtg2.54c dist
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
Petter credits Rachel Polanskis <rachel@juno.virago.org.au> for 
Packit 667938
the original. 
Packit 667938
Packit 667938
=cut
Packit 667938
Packit 667938
Packit 667938
Packit 667938