[comp.mail.sendmail] Looking for Sendmail.st file format

romain@pyramid.pyramid.com (Romain Kang) (03/19/90)

If you're really curious and you've got Internet or UUNET access, you
can grab the whole sendmail source (about 500-600KB compressed).

As far as I know, no one has seriously examined sendmail statistics.
There's an obvious problem with multiple instances of sendmail
pounding on the statistics file, even on uniprocessor machines.  I
would expect busy machines to undercount messages and bytes in some
proportion to the sendmail load.  Naturally, you could flock() the
statistics file to gain greater accuracy but you would also introduce
a bottleneck.  In the absence of serious study, this would not make
sense.

Serious study would dictate clearing statistics every time the sendmail
configuration was re-frozen, since the index associated with each
mailer depends on the order of mailer declaration in sendmail.cf.

Having said that, here's a perl script that displays the data.  Running
it on pyramid yields:

Messages since 89/08/01 20:53:35:
M#  #msg from    kB from    #msg to      kB to	MAILER
 0      45385     138851      76985     117250	local
 1          0          0       3643      10725	prog
 2     216639    1028497     239446    1015560	uux
 3      43855     130507     230458     528055	ether

#! /usr/local/bin/perl3
#
# quick hack; apologies for lack of programming style...
#
$MSTATS	= '/usr/lib/sendmail.st';
$CONFIG	= '/usr/lib/sendmail.cf';

do readcf();

open MSTATS || die "Can't open $MSTATS";
@st = stat MSTATS;
die "stat($MSTATS) failed" if ($#st < 0);
# $st[7] = st_size
if (($n = read(MSTATS, $buf, $st[7])) != $st[7]) {
   die "read returned $n (expected $st[7])";
}
close MSTATS;

# ($n - (sizeof(time_t) + sizeof(ushort) + pad)) / (4 * sizeof(long));
$nmailers = ($n - (4 + 2 + 2))/(4*4);
$marray = 'L' . 4 * $nmailers;
($stat_itime, $stat_isize, @marray) = unpack("LSxx$marray", $buf);

@lt = localtime($stat_itime);
$lt[4]++;
printf "Messages since %02d/%02d/%02d %02d:%02d:%02d:\n", reverse(@lt[0..5]);

printf "M# %10s %10s %10s %10s\t%s\n",
	'#msg from', 'kB from', '#msg to', 'kB to', 'MAILER';

for ($i = 0; $i < $nmailers; $i++) {
    @m = @marray[$i, $i+$nmailers, $i+2*$nmailers, $i+3*$nmailers];
    if ($m[0] || $m[2]) {
    	printf "%2d %10d %10d %10d %10d\t%s\n", $i, @m, $Mailername[$i];
    }
}

sub readcf {
    if (!open CONFIG) {
	warn "Can't get mailer names from $CONFIG";
	return;
    }
    while (<CONFIG>) {
	chop;
	if (/^M([^,]+)/) {
	    push(Mailername, $1);
	}
    }
    close CONFIG;
}