[mod.sources] v07i036: Erik Fair's UUCP & Usenet toolbox

sources-request@mirror.UUCP (10/24/86)

Submitted by: fair@ucbarpa.Berkeley.EDU (Erik E. Fair)
Mod.sources: Volume 7, Issue 36
Archive-name: uucp+nuztools

[  This shar file contains three separate awk or shell scripts that
   generate very useful information from the logs produced by INEWS
   and UUCP.  If you make changes in them to accomodate other versions
   of those programs, please feed them back to Erik for incorporation.
   Erik sent me the scripts without any names; the ones I gave are
   not great.  The scripts are extensively commented, and my usual
   requirement of a manpage and Makefile don't make sense here.  I
   recommend that all Sys Admin's at least unshar this article and
   peruse the scripts -- they are very useful.  -r$ ]

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "No problems found."

# Exit status; set to 1 on "wc" errors or if would overwrite.
STATUS=0
# Contents:  logfiles_sh report_awk syslog_awk
 
echo x - logfiles_sh
if test -f logfiles_sh ; then
    echo logfiles_sh exists, putting output in $$logfiles_sh
    OUT=$$logfiles_sh
    STATUS=1
else
    OUT=logfiles_sh
fi
sed 's/^X//' > $OUT <<'@//E*O*F logfiles_sh//'
X#!/bin/sh
X# Feed me UUCP LOGFILEs, as many as you can, and I'll spit out pathalias
X# data for your UUCP map entry!
X#
X# Base premise: frequency of contact is more important than what's in your
X# L.sys file (i.e. the times you actually call them) because regardless of
X# who initiates the connection, all the queued files from BOTH sides will be
X# sent along...
X#
X# Algorithmn: find all the "OK (startup)" LOGFILE entries (these indicate
X# a protcol startup succeeded), and pick out the date (convert to julian
X# date to make things easy to calculate), and the host name. The period
X# granularity is 24 hours (or one day).  Thus you end up with frequency
X# counts, which, given the number of days over which the data ranges, can
X# be used to calculate average frequency of contact per 24 hour period,
X# and assign a pathalias(1) value to that connection.
X#
X# The output will be a list of the sites that connected to your system,
X# as indicated by your LOGFILEs with pathalias values in parentheses.
X# If a system connected to you that is not in your L.sys file, it will be
X# commented out. If a system in your L.sys did not connect during the
X# period covered by your LOGFILEs, it will be marked DEAD. There will
X# also be comments about the statistical validity of your input data.
X#
X# Of course, if you don't like the output, please feel free to edit it to
X# your satisfaction. This is just an aid to making more consistent and
X# accurate UUCP map data.
X#
X# KNOWN DESIGN DEFICIENCIES: watch out for crossing New Year's!
X#
X# V7/4BSD:	uucp lll-crg (6/26-00:06-2236) OK (startup ttyhf 1200 baud)
X# System V:	ucbvax!uucp (8/8-1:36:55) (C,23563,2) OK (startup)
X# HoneyDanBer:	uucp utzoo  (6/17-0:39:42,27164,0) OK (startup)
X#
X# Erik E. Fair <ucbvax!fair>
X# August 8, 1986
X#
Xif test $# -lt 1
Xthen
X	echo "USAGE: $0 LOGFILE [LOGFILE ...]" 1>&2
X	exit 1
Xfi
Xtmp=/tmp/uuname$$
Xtrap "rm -f ${tmp}; exit 1" 1 2 3 15
X(echo '@@uuname'; uuname; echo '@@end') > ${tmp}
Xawk -e '
XBEGIN{
X	dpm[1] = 31;	dpm[2] = 28;	dpm[3] = 31;	dpm[4] = 30;
X	dpm[5] = 31;	dpm[6] = 30;	dpm[7] = 31;	dpm[8] = 31;
X	dpm[9] = 30;	dpm[10] = 31;	dpm[11] = 30;	dpm[12] = 31;
X	cumu[1] = 0;
X# handle leap year
X	tod="'"`date`"'";
X	n = split(tod, date);
X	year = date[n];
X	if ((year % 4) == 0) dpm[2] = 29;
X	for(x = 2; x <= 12; x++) {
X		i = x - 1;
X		cumu[x] = cumu[i] + dpm[i];
X	}
X	uuname = 0;
X	jmin = 367;
X	jmax = 0;

X}
X/^@@uuname/	{ uuname = 1; next }
X/^@@end/	{ uuname = 0; next }
X{if (uuname == 1) { Lsys[$1] = $1; next } }
X/OK..startup/	{
X#
X# first, is this a V7/4BSD/System III UUCP or a System V UUCP?
X# Or possibly a HoneyDanBer?
X#
X	n = split($1, crud, "!");
X	if (n > 1) {
X# Ugh, System V
X		host = crud[1];
X		timestamp = $2;
X	} else {
X# Ah, V7/4BSD
X		host = $2;
X		timestamp = $3;
X	}

X# check the syntax of the timestamp for validity
X	if ( timestamp !~ /([0-9\/]*-[0-9:]*-[0-9]*)/ && timestamp !~ /([0-9\/]*-[0-9:]*,[0-9,]*)/ ) {
X		printf("# syntax error: %s: %s\n", FILENAME, $0);
X		next;
X	}

X# count for this system
X	count[host]++

X# parse the date to find the time period over which we are counting
X	dttmpid = substr(timestamp, 2, length(timestamp) - 2);
X	split(dttmpid, time, "-");
X	split(time[1], date, "/");
X	mo = date[1];
X	dy = date[2];
X	julian = cumu[mo] + dy;
X	if (julian < jmin)	jmin = julian;
X	if (julian > jmax)	jmax = julian;

X# connections per day (histogram)
X	cpd[julian]++;
X}
XEND{
X#
X# pathalias values
X	LOCAL		= 25;
X	DEDICATED	= 95;
X	DIRECT		= 200;
X	DEMAND		= 300;
X	HOURLY		= 500;
X	EVENING		= 1800;
X	DAILY		= 5000;
X	WEEKLY		= 30000;
X#
X# find out the length of the longest name from the LOGFILES.
X# then truncate every name in the Lsys list to that length for
X# comparisons, on the assumption that UUCP will truncate names
X# to that length in the records it keeps. System V keeps records
X# in 6 character system names. v7, System III, 4.1, and 4.2 keep
X# records in 7 character system names. 4.3 keeps the whole name.
X#
X	maxlen = 0;
X	for(host in count) {
X		len = length(host);
X		if (len > maxlen) maxlen = len;
X	}
X	for(host in Lsys) {
X		len = length(host);
X		if (len > maxlen) trunc[substr(host, 1, maxlen)] = host;
X		else trunc[host] = host;
X	}

X#
X# First cut guess at how many days worth of data we have
X#
X	days = jmax - jmin;
X	if (days == 0) days = 1;
X#
X# some statistical analysis of the data to guess at validity.
X#
X	last = -1;
X	dash = 0;
X	xdays = 0;
X	warning = 0;
X	median = int((jmin + jmax) / 2);
X	median = cpd[median];
X	for(d = jmin; d <= jmax; d++) mean += cpd[d];
X	mean = int(mean / days);
X	for(d = jmin; d <= jmax; d++) {
X		tmp = cpd[d] - mean;
X		if (tmp < 0) tmp = (0 - tmp);
X		mad += tmp;
X		if (cpd[d] == 0) {
X			if (!warning) {
X				printf("# WARNING: data is discontinuous; no connections for ");
X				warning = 1;
X				last = d;
X				printf("%d ", d);
X			} else {
X				if (d == (last + 1)) {
X					last = d;
X					dash = 1;
X				} else {
X					if (dash) printf("- %d, %d, ", last, d);
X					else printf("%d, ", d);
X					dash = 0;
X					last = d;
X				}
X			}
X		} else xdays++;
X	}
X	if (warning) {
X		if (dash) printf("- %d ", last);
X		printf("Julian\n");
X	}
X	mad = int(mad / days);
X	printf("# Mean conn/day = %d, Median c/d = %d, Mean Absolute Deviation = %d\n", mean, median, mad);
X#
X# If we ended up with discontinuous data, use the number of days for which
X# we have data as the denominator instead of the range.
X#
X	if (warning) range = xdays;
X	else range = days;

X#
X# OK, determine pathalias data...
X#
X	for(host in count) {
X		nhosts++;
X		freq = count[host] / range;
X		val = DAILY / freq;
X		value = "";

X		if (val <= DEDICATED)	value = "(DEDICATED),";
X		if (val <= DIRECT)	value = "(DIRECT),";
X		if (val <= DEMAND)	value = "(DEMAND),";
X		if (val <= HOURLY)	value = "(HOURLY),";

X		if (value == "") {
X			if (freq >= 2)
X				value = sprintf("(DAILY/%d),", freq);
X			else if (freq >= 1 && freq < 2)
X				value = "(DAILY),";
X			else if (freq < 1 && freq > 0) {
X				pweek = freq * 7 + 0.5;
X				if (pweek >= 2)
X					value = sprintf("(WEEKLY/%d),", pweek);
X				else if (pweek >= 1 && pweek < 2)
X					value = "(WEEKLY),";
X				else if (pweek < 1 && pweek > 0) {
X					pmonth = pweek * 4.3 + 0.5;
X					if (pmonth >= 2)
X						value = sprintf("(WEEKLY*4/%d),", pmonth);
X					else if (pmonth >= 1 && pmonth < 2)
X						value = "(WEEKLY*4),";
X					else
X						value = "(DEAD),";
X				} else
X					value = sprintf("(count=%d/range=%d),", count[host], range);
X			} else
X				value = sprintf("(count=%d/range=%d),", count[host], range);
X		}
X		name = trunc[host];
X		if (name == "") {
X			printf("# %s%s\n", host, value);
X			data[host]++;
X		} else {
X			printf("%s%s\n", name, value);
X			data[name]++;
X		}
X	}

X	for(host in Lsys) {
X		if (! data[host]) {
X			printf("%s(DEAD),\n", host);
X		}
X	}

X	printf("# Data Ranges over %d days from %d to %d Julian; %d hosts connected\n", days, jmin, jmax, nhosts);

X}' ${tmp} $* | sort
Xrm -f ${tmp}


@//E*O*F logfiles_sh//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - report_awk
if test -f report_awk ; then
    echo report_awk exists, putting output in $$report_awk
    OUT=$$report_awk
    STATUS=1
else
    OUT=report_awk
fi
sed 's/^X//' > $OUT <<'@//E*O*F report_awk//'
X#  USAGE: awk -f report_awk /usr/lib/news/log
X#  AWK script which eats netnews log files and produces a summary of USENET
X#  traffic and errors over the period of time that the log was collected.
X#
X#  August 31, 1986
X#
X#  Erik E. Fair <dual!fair>
X#  Original Author, May 22, 1984
X#
X#  Brad Eacker <onyx!brad>
X#  Modified to simplify the record processing and to sort the output.
X#
X#  Erik E. Fair <dual!fair>
X#  Modifed to provide information about control messages.
X#
X#  Erik E. Fair <dual!fair>
X#  Bug in system name extraction fixed. It was assumed that the forth field
X#  (system name) always had a dot. local is one that doesn't. Some others
X#  (including 2.9 sites) don't either.
X#
X#  Earl Wallace <pesnta!earlw>
X#  The "sent" field was changed from $5 to $6 in 2.10.2 (beta)
X#  named "newstats" and called with no arguments.
X#
X#  Erik E. Fair <dual!fair>
X#  Remove support for 2.10.1, revise for 2.10.2 to provide information
X#  about junked articles, garbled articles, and bad newsgroups
X#
X#  Erik E. Fair <ucbvax!fair>
X#  Minor bug fix to bad newsgroup reporting, also now counting ``old''
X#  articles as junked, with counter for number that are `old'.
X#
X#  Erik E. Fair <ucbvax!fair>
X#  Fix up the domain & local hosts support
X#
X#  Erik E. Fair <ucbvax!fair>
X#  Fix up the counting of gatewayed material, add counting of "linecount"
X#  problems. Additional cleanup to make things faster.
X#
XBEGIN{
X#
X#	this is the prefix that your site uses in hostnames to identify your
X#	hosts (e.g. ucbarpa, ucbvax, su-score, mit-mc, mit-ai)
X#	You will probably want to change (or add to) the following line
X#
X	lprefix = "ucb";
X	lplen = length(lprefix);
X#
X#	If you do bi-directional USENET gatewaying (e.g. mailing list
X#	to newsgroup where the material flows both ways freely), this
X#	should be the name in the sys file that you use to mail stuff
X#	to the mailing lists.
X#
X	pseudo = "internet";
X	rptname = "(GATEWAY)";
X#
X#	Top level domain names and what network they represent
X#	(for use in counting stuff that is gatewayed)
X#
X	domains["ARPA"] = rptname;
X	domains["arpa"] = rptname;
X	domains["EDU"] = rptname;
X	domains["edu"] = rptname;
X	domains["GOV"] = rptname;
X	domains["gov"] = rptname;
X	domains["COM"] = rptname;
X	domains["com"] = rptname;
X	domains["MIL"] = rptname;
X	domains["mil"] = rptname;
X	domains["ORG"] = rptname;
X	domains["org"] = rptname;
X	domains["NET"] = rptname;
X	domains["net"] = rptname;
X	domains["UK"] = rptname;
X	domains["uk"] = rptname;
X	domains["DEC"] = rptname;
X	domains["dec"] = rptname;
X	domains["CSNET"] = rptname;
X	domains["csnet"] = rptname;
X	domains["BITNET"] = rptname;
X	domains["bitnet"] = rptname;
X	domains["MAILNET"] = rptname;
X	domains["mailnet"] = rptname;
X	domains["UUCP"] = rptname;
X	domains["uucp"] = rptname;
X	domains["OZ"] = rptname;
X	domains["oz"] = rptname;
X	domains["AU"] = rptname;
X	domains["au"] = rptname;
X#
X#	tilde chosen because it is ASCII 126 (don't change this)
X#
X	invalid = "~~~~~~";
X#
X	accept[invalid]   = 0;
X	reject[invalid]   = 0;
X	xmited[invalid]   = 0;
X	control[invalid]  = 0;
X	junked[invalid]   = 0;
X	neighbor[invalid] = 0;
X	badgrp  = 0;
X	garbled = 0;
X	lcount  = 0;
X	canfail = 0;
X	candup  = 0;
X	insfail = 0;
X	old     = 0;
X}
X#
X#	Skip some things that we won't bother with
X#
X/^$/				{ next }
X$5 == "from"			{ next }
X$5 == "make"			{ next }
X$5 == "Cancelling"		{ next }
X#
X#	Or that we just count
X#
X$5 == "Inbound"			{ garbled++; next }
X$6 == "cancel"			{ canfail++; next }
X$6 == "Cancelled"		{ candup++; next }
X$6 == "install"			{ insfail++; next }
X#
X#	Articles sent to remote systems (this is what 2.10.2 (beta) says)
X#
X$6 == "sent"	{
X	for(j = 8; j <= NF; j++) {
X		comma = index( $(j), ",");
X		if (comma != 0) $(j) = substr( $(j), 1, (comma - 1));
X		if ($(j) == pseudo) $(j) = rptname;
X		else neighbor[$(j)] = 1;
X		xmited[$(j)]++;
X	}
X	next;
X}
X#
X#	Articles sent to remote systems (this is what 2.11 says)
X#
X$5 == "sent"	{
X	for(j = 7; j <= NF; j++) {
X		comma = index( $(j), ",");
X		if (comma != 0) $(j) = substr( $(j), 1, (comma - 1));
X		if ($(j) == pseudo) $(j) = rptname;
X		else neighbor[$(j)] = 1;
X		xmited[$(j)]++;
X	}
X	next;
X}
X#
X#	Get the name of the system that did this,
X#	taking into account that not everyone believes in domains.
X#
X{
X#	if we get a route addr (we shouldn't, but...), take the last one
X#
X	nhosts = split($4, hosts, "@");
X	hostname = hosts[nhosts];
X#
X#	get the root domain name, and the hostname
X#
X	ndoms = split(hostname, doms, ".");
X	domain = doms[ndoms];
X	sys = doms[1];
X#
X#	check for local system, and if not that, then internet sites.
X#	special case the network name replacement of specific host names,
X#	such that the network name is there only on a `local' posting
X#	(which is really gatewaying in disguise)
X#
X	if ($5 == "posted") {
X		prefix = substr(sys, 1, lplen);
X		if (prefix == lprefix) {
X			sys = "local";
X		} else {
X			dom = domains[domain];
X			if (dom) sys = dom;
X		}
X	}
X}
X#  
X#	Duplicates & receiveds/posted & control messages
X# 
X$5 == "posted" || $5 == "received" {
X	accept[sys]++;
X	if ($5 == "received") neighbor[sys] = 1;
X	nng = split($8, ngl, ",");
X	for(i = 1; i <= nng; i++) {
X		dot = index(ngl[i], ".");
X		if (dot) ng = substr(ngl[i], 1, (dot - 1));
X		else ng = ngl[i];
X		if (ng) newsgcnt[ng]++;
X	}
X	next;
X}
X$5 == "Duplicate"	{ reject[hostname]++; next }
X$6 == "valid"		{ junked[sys]++; next }
X$6 == "too"		{ junked[sys]++; old++; next }
X$5 == "Unknown"		{
X	x = length($7) - 2;
X	ng = substr($7, 2, x);
X	badng[ng]++;
X	badgrp++;
X	next;
X}
X#
X#	articles who actual line count differs from the Line: header count
X#
X$5 == "linecount"	{
X	expect = $7;
X# awk does very strange things with non-numeric characters in numbers
X	comma = index(expect, ",");
X	if (comma != 0) expect = substr(expect, 1, (comma - 1));
X	got = $9;
X	diff = got - expect;
X	lcount++;
X	alc_host[sys] = 1;
X	neighbor[sys] = 1;
X	if (diff < 0) {
X		diff = 0 - diff;
X		a_nshort[sys]++;
X		a_short[sys] += diff;
X		if (a_smax[sys] < diff) a_smax[sys] = diff;
X	} else {
X		a_nlong[sys]++;
X		a_long[sys] += diff;
X		if (a_lmax[sys] < diff) a_lmax[sys] = diff;
X	}
X	next;
X}
X#
X#	articles who actual line count is Zero
X#
X$7 == "linecount"	{
X	lcount++;
X	a_zero[sys]++;
X	reject[sys]++;
X	next;
X}
X#
X#	Control messages
X#
X$5 == "Ctl"	{
X	ctot++;
X	control[sys]++;
X	ctlcnt[$(10)]++;
X	next;
X}
X#
X#	Print anything we didn't recognize, it's probably an error message.
X#	For the submitted report to USENET, do sed -e '1,/^$/d' file | inews
X#	so that this cruft doesn't get out the door.
X#
X{
X	print;
X}
X#
X#	Summarize and print the report
X#
XEND{
X#	special processing for Duplicates, because we can't tell if
X#	they came from a netnews neighbor or from the gatewaying
X#	activities until we have processed the entire log.
X#
X	for( hostname in reject ) {
X#
X#	get the root domain name, and the hostname
X#
X		ndoms = split(hostname, doms, ".");
X		domain = doms[ndoms];
X		sys = doms[1];
X		if (! neighbor[sys]) {
X			prefix = substr(sys, 1, lplen);
X			if (prefix == lprefix) {
X				sys = "local";
X			} else {
X				dom = domains[domain];
X				if (dom) sys = dom;
X			}
X		}
X		i = reject[hostname];
X		reject[hostname] = 0;
X		reject[sys] += i;
X	}

X	rtot = 0;
X	for( i in reject ) {
X		if (reject[i] > 0) {
X			list[i] = 1;
X			rtot += reject[i];
X		}
X	}

X	atot = 0;
X	for( i in accept ) {
X		list[i] = 1;
X		atot += accept[i];
X	}

X	xtot = 0;
X	for( i in xmited ) {
X		list[i] = 1;
X		xtot += xmited[i];
X	}

X	ctot = 0;
X	for( i in control ) {
X		list[i] = 1;
X		ctot += control[i];
X	}

X	jtot = 0;
X	for( i in junked ) {
X		list[i] = 1;
X		jtot += junked[i];
X	}
X#
X# ctot is part of rtot, so we don't add it in to the grand total.
X#
X	totarticles = atot + rtot;
X	if (totarticles == 0) totarticles = 1;

X	printf("\nSystem       \tAccept\tReject\tJunked\tXmit to\tControl\t%% total\t%% rejct\n");
X	for( ; ; ) {
X# selection sort
X		i = invalid;
X		for( j in list ) {
X			if ( list[j] > 0 && j < i ) i = j;
X		}
X		if ( i == invalid ) break;
X		list[i] = 0;
X#
X#	control & junked are counted under accept.
X#
X		sitetot = accept[i] + reject[i];
X		if (sitetot == 0) sitetot = 1;
X		articles[i] = sitetot;
X#
X# What an 'orrible printf spec
X#
X		printf("%-14s\t%6d\t%6d\t%6d\t%7d\t%7d\t%6d%%\t%6d%%\n", i, accept[i], reject[i], junked[i], xmited[i], control[i], (sitetot * 100) / totarticles, (reject[i] * 100) / sitetot);
X#
X	}
X	printf("\nTOTALS        \t%6d\t%6d\t%6d\t%7d\t%7d\t%6d%%\t%6d%%\n", atot, rtot, jtot, xtot, ctot, 100, (rtot * 100) / totarticles);
X	printf("\nTotal Articles processed %d", totarticles);
X	if (old)	printf(", old %d", old);
X	if (garbled)	printf(", garbled %d", garbled);
X	if (insfail)	printf(", uninstallable %d", insfail);
X	printf("\n");

X	if (ctot) {
X		printf("\nControl	Invocations\n");
X		for( i in ctlcnt ) {
X			if (i == "cancel") {
X				printf("%-12s %6d", i, ctlcnt[i]);
X				if (canfail) printf(", %d failed", canfail);
X				if (candup) printf(", %d duplicate", candup);
X				printf("\n");
X			} else {
X				printf("%-12s %6d\n", i, ctlcnt[i]);
X			}
X		}
X	}

X	if (lcount) {
X		printf("\nReceived Article Length Problems\n");
X		printf("System          Zero Short  Smax  Savg  Long  Lmax  Lavg Total %% Tot\n");
X		for( i in alc_host ) {
X			nlong = a_nlong[i];
X			nshort = a_nshort[i];
X			if (nlong == 0) nlong = 1;
X			if (nshort == 0) nshort = 1;
X			lavg = a_long[i] / nlong;
X			savg = a_short[i] / nshort;
X			sitetot = (a_zero[i] + a_nshort[i] + a_nlong[i]);
X			printf("%-14s %5d %5d %5d %5d %5d %5d %5d %5d %4d%%\n", i, a_zero[i], a_nshort[i], a_smax[i], savg, a_nlong[i], a_lmax[i], lavg, sitetot, (sitetot * 100) / articles[i]);
X		}
X	}

X	if (atot) {
X		printf("\nNetnews Categories Received\n");
X		l = 0;
X		for( i in newsgcnt ) {
X			if (l < length(i)) l = length(i);
X		}
X		fmt = sprintf("%%-%ds %%6d\n", l);
X		for( ; ; ) {
X# selection sort
X			max = 0;
X			for( j in newsgcnt ) {
X				if (newsgcnt[j] > max) {
X					i = j;
X					max = newsgcnt[j];
X				}
X			}
X			if (max == 0) break;
X			printf(fmt, i, newsgcnt[i]);
X			newsgcnt[i] = 0;
X		}
X	}

X	if (badgrp) {
X		printf("\nBad Newsgroups Received\n");
X		l = 0;
X		for( i in badng ) {
X			if (l < length(i)) l = length(i);
X		}
X		fmt = sprintf("%%-%ds %%5d\n", l);
X		for( ; ; ) {
X# selection sort
X			i = invalid;
X			for( j in badng ) {
X				if (badng[j] > 0 && j < i) i = j;
X			}
X			if (i == invalid) break;
X			printf(fmt, i, badng[i]);
X			badng[i] = 0;
X		}
X	}
X}

@//E*O*F report_awk//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - syslog_awk
if test -f syslog_awk ; then
    echo syslog_awk exists, putting output in $$syslog_awk
    OUT=$$syslog_awk
    STATUS=1
else
    OUT=syslog_awk
fi
sed 's/^X//' > $OUT <<'@//E*O*F syslog_awk//'
X#  USAGE: awk -f syslog_awk /usr/spool/uucp/SYSLOG
X# An awk script for printing a pretty report of UUCP activities from the
X# UUCP SYSLOG - Erik E. Fair	October 2, 1984
X#
X# v7 UUCP
X$4 == "received" {
X	sysname[$2] = $2;
X	by_rec[$2] += $6;
X	sec_rec[$2] += $8;
X	sys_xf[$2] ++;
X}
X#
X# 4.2 BSD UUCP
X$5 == "received" {
X	sysname[$2] = $2;
X	by_rec[$2] += $7;
X	sec_rec[$2] += $9;
X	sys_xf[$2] ++;
X}
X#
X# System V UUCP
X$6 == "<-" {
X	$1 = substr($1, 1, (index($1, "!") - 1));
X	sysname[$1] = $1;
X	by_rec[$1] += $7;
X	sec_rec[$1] += $9;
X	sys_xf[$1] ++;
X}
X#
X# v7 UUCP
X$4 == "sent" {
X	sysname[$2] = $2;
X	by_xmt[$2] += $6;
X	sec_xmt[$2] += $8;
X	sys_xf[$2] ++;
X}
X#
X# 4.2 BSD UUCP
X$5 == "sent" {
X	sysname[$2] = $2;
X	by_xmt[$2] += $7;
X	sec_xmt[$2] += $9;
X	sys_xf[$2] ++;
X}
X#
X# System V UUCP
X$6 == "->" {
X	$1 = substr($1, 1, (index($1, "!") - 1));
X	sysname[$1] = $1;
X	by_xmt[$1] += $7;
X	sec_xmt[$1] += $9;
X	sys_xf[$1] ++;
X}
XEND {
X#
X# print a report header
X	printf("System     Xfers  Bytes rec  Bytes xmt   Connect  Avg Xf  Avg rec  Avg xmt\n")
X	for(i in sysname) {
X#
X# sort report by most connect time (selection sort)
X		first = 0;
X		for(j in sysname) {
X			if (sys_xf[j] > 0) {
X				tmp1 = sec_xmt[j];
X				tmp2 = sec_rec[j];
X# Stupid AWK bug - needs a simple expression
X				time = (tmp1 + tmp2);
X				if (time > first) {
X					first = time;
X					sys = sysname[j];
X				}
X			}
X		}
X#
X# 4.2 BSD awk seems to have problems. This check should not be necessary.
X# Oddly enough, this problem also shows up in System V. WHY???
X		if (sys_xf[sys] != 0) {
X#
X# time for some bean counting
X			tmp1       = sec_xmt[sys];
X			tmp2       = sec_rec[sys];
X# Stupid AWK bug - needs a simple expression
X			time       = (tmp1 + tmp2);
X			hours      = time / 3600;
X			sec        = time % 3600;
X			min        = sec / 60;
X			sec        %= 60;
X			tot_xf     += sys_xf[sys];
X			tot_by_rec += by_rec[sys];
X			tot_by_xmt += by_xmt[sys];
X			tot_time   += time;
X#
X# protect myself against mathematical crime (divide by zero)
X			if (sec_rec[sys] == 0)
X				sec_rec[sys] = 1;
X			if (sec_xmt[sys] == 0)
X				sec_xmt[sys] = 1;
X#
X# print a pretty system report (god what an awful printf format...)
X			printf("%-8s%8d%11d%11d%4d:%.2d:%.2d%8d%9d%9d\n", \
Xsysname[sys], sys_xf[sys], by_rec[sys], by_xmt[sys], hours, min, sec, \
X((by_rec[sys] + by_xmt[sys]) / sys_xf[sys]), \
X(by_rec[sys]  / sec_rec[sys]), \
X(by_xmt[sys]  / sec_xmt[sys]));
X#
X# make certain we will not see this system again... (selection sort)
X			sys_xf[sys] = 0;
X		}
X	}
X#
X# calculate time split for total time (and print totals [*shudder*])
X	hours = tot_time / 3600;
X	sec = tot_time % 3600;
X	min = sec / 60;
X	sec %= 60;
X	printf("\n%-8s%8d%11d%11d%4d:%.2d:%.2d\n", \
X	"TOTALS", tot_xf, tot_by_rec, tot_by_xmt, hours, min, sec);
X}

@//E*O*F syslog_awk//
chmod u=rw,g=rw,o=rw $OUT
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     248    1238    6783 logfiles_sh
     420    1740   10191 report_awk
     119     458    2728 syslog_awk
     787    3436   19702 total
!!!
wc  logfiles_sh report_awk syslog_awk | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp ; then
    echo "Ouch [diff of wc output]:"
    cat $dtemp
    STATUS=1
elif test $STATUS = 0 ; then
    echo "No problems found."
else
    echo "WARNING -- PROBLEMS WERE FOUND..."
fi
exit $STATUS