[mod.sources] uucpanz for System V

sources-request@genrad.UUCP (11/12/84)

From: decvax!sun!amdahl!gam (Gordon A. Moffett)

[Editor's note: I seem to have accidentally deleted the intro information
 for this article.  This is basically a System V version of the program
 previously posted here, but there are several enchancements as well, and
 a man page and a Makefile to boot!  I have not tried this program out,
 since the only System V I have access to is not currently running uucp
 -  john ]

------------------- Cut Here ---------------------
: This is a shar archive.  Extract with sh, not csh.
echo x - README
sed -e 's/^X//' > README << '!Funky!Stuff!'
XThe files herein are:
X
Xuucpanz.h - header file for uucpanz.c
Xuucpanz.c - C program source
XMakefile  - instructions for compilation for make(1)
Xuucpanz.1 - manual page
XREADME    - this file.
X
XNote that this is assured to work only on System V Release 2 sites.
!Funky!Stuff!
echo x - uucpanz.1
sed -e 's/^X//' > uucpanz.1 << '!Funky!Stuff!'
X.TH UUCPANZ 1
X.SH NAME
Xuucpanz \- summarize uucp statistics
X.SH SYNOPSIS
X.B uucpanz
X[
X.B \-l
Xlogfile ] [
X.B \-s
Xsyslog ]
X.SH DESCRIPTION
X.I Uucpanz
Xexamines the files
X.I logfile
Xand
X.I syslog
X(by default, /usr/spool/uucp/LOGFILE and /usr/spool/uucp/SYSLOG,
Xrespectively) and produces a report summarizing the data therein.
X.P
XThe report consists of 4 parts:
X.TP 15
XBy system:
XThe number of bytes sent to and received from each uucp node,
Xas well as the number of calls and their status, and the number
Xof files transfered.  An average number of bytes per second transmitted
Xis printed for both directions, if applicable.
X.TP 15
XBy user:
XThe number of files and bytes sent by users (directly, via
X.IR uucp (1),
Xor indirectly by use of some other command).  This list is roughly
Xsorted in reverse order.
X.TP 15
XBy commands:
XCommands issued directly or indirectly via
X.IR uux (1),
Xwith a repetition count.
X.TP 15
XBy day:
XTotal number of bytes sent or received for each day.
X.P
XThe users, uucp nodes, commands, and days are those found in the
Xtwo input files; if no activity occurs for some uucp site it is
Xnot reported.
X.SH FILES
X.TP 24
X/usr/spool/uucp/LOGFILE
Xdefault
X.I logfile
Xfrom which the summary of commands, phone calls, and file counts
Xis created.
X.TP 24
X/usr/spool/uucp/SYSLOG
Xdefault
X.I syslog
Xfrom which the summary of bytes and connect times is created.
X.SH SEE ALSO
Xuusub(1), uustat(1)
X.br
X``UUCP Adminstration'' in the
X.I
XUnix Administrator Guide
X.SH DIAGNOSTICS
X.TP 20
X``Out of memory''
X.I Uucpanz
Xdynamically allocates memory to build linked lists for the
Xcommand and user summaries.  The greater the number of unique
Xcommands and usernames, the more memory is allocated.
X.SH WARNINGS
XThe program is very sensitive to the file formats for
X.I logfile
Xand
X.I syslog
Xand expects them to be just as they are produced by
X.IR uucico (1m).
X.SH BUGS
XDoes not recover well from garbage data.
X.P
XThis program should be written in
X.IR awk (1).
!Funky!Stuff!
echo x - uucpanz.h
sed -e 's/^X//' > uucpanz.h << '!Funky!Stuff!'
X#define	SYSLOG	"/usr/spool/uucp/SYSLOG"
X#define	LOGFILE	"/usr/spool/uucp/LOGFILE"
X#define	MAXSYS	32
X
Xstruct	dayrec {
X    int used;	/* used */
X    long recv;	/* bytes recv */
X    long sent;	/* bytes sent */
X    long trecv;	/* seconds spent rec */
X    long tsent;	/* seconds spent sending */
X};
X
Xstruct	sys1 {
X    char sname[9];	/* system name */
X    long bbsent;	/* bytes sent */
X    long brec;	/* bytes rec. */
X    long btsent;	/* time spen sending */
X    long btrec;	/* time spent rec */
X    int suc;	/* succesfull calls */
X    int fail;	/* calls fail */
X    int ugot;	/* number of files we got */
X    int lock;	/* times of locked */
X    int usent;	/* number of files we sent */
X    int okstr;	/* number of conversations started */
X    int okstop;	/* number of conversations stop */
X};
X
Xstruct	users {
X    char *name;	/* login name */
X    long bsent;	/* bytes sent */
X    long utim;	/* time spent */
X    long nsent;	/* number sent */
X    struct	users	*nuser;
X};
X
Xstruct	call {
X    int times;
X    char *cname;
X    struct call *ncall;
X};
!Funky!Stuff!
echo x - uucpanz.c
sed -e 's/^X//' > uucpanz.c << '!Funky!Stuff!'
X/*
X* uucpanz.c
X*	program to print out stats about uucp usage.
X*
X*  Permission is given by me [ Brad Smith ] for the use,
X* modification, and distribution of this program
X* exception:  It may not be sold for profit individually nor as part of any
X* software package, regardless of modifications.
X*
X*
X*	Bradley Smith
X*	Bradley University
X*	{ihnp4,cepu,uiucdcs,noao}!bradley!brad
X*
X*       modified for System V Release 2
X*       by Gordon A. Moffett
X*       Amdahl Corporation
X*       {ihnp4,hplabs}!amdahl!gam
X*/
X#include	<stdio.h>
X#include	<ctype.h>
X
X#include	"uucpanz.h"
X
Xstruct	dayrec	dayacc[13] [32];
Xstruct	sys1	sysacc[MAXSYS];
Xstruct	call	*cmd, *tcall();
Xstruct	users	*usage;
X
Xstruct	users	*tree();
Xchar	*getfield();
Xchar	*strchr();
Xchar	*malloc(), *strsave();
Xchar	*strcpy(), *strcat();
Xvoid	exit();
X
Xlong	byt, tim, atol();
Xint	cmdcount;
Xlong	hour, min,second, hourtmp;
XFILE *fpin;
Xchar	*logfile = LOGFILE;
Xchar	*syslog = SYSLOG;
X
Xchar            *Cmdname;
X
Xmain(argc, argv)
X	int argc;
X	char *argv[];
X{
X    char line[512], field[128], cx[128],*cp, *sp, *c;
X    char junk[512];
X    char sysname[18], username[9];
X    register int i,j;
X    int d, m;
X    int opt;
X    extern char *optarg;
X    extern int   optind;
X
X    Cmdname = argv[0];
X
X    while ( (opt = getopt(argc, argv, "l:s:")) != EOF) {
X	switch(opt) {
X	case 'l':
X		logfile = optarg;
X		break;
X	case 's':
X		syslog = optarg;
X		break;
X	case '?':
X	default:
X		tellem();
X	}
X    }
X/* intialize */
X    usage = NULL;
X    cmdcount = 0;
X    cmd = NULL;
X
X/* lets do SYSLOG first */
X
X    if((fpin = fopen(syslog,"r")) == NULL)
X	    error(syslog);
X
X    while(fgets(line, sizeof line, fpin) != NULL) {
X	    fgets(junk, sizeof junk, fpin); 	/* skip over 2nd line */
X	    strcpy(cx,getfield(2,line,' '));
X	    cp = cx;
X	    cp++;	/* puts at first number */
X	    c = cp;
X	    cp++;
X	    if(isdigit(*cp))
X		    cp++;
X	    *cp = '\0';
X	    m = atoi(c);
X	    cp++;
X	    c = cp;
X	    cp++;
X	    if(isdigit(*cp))
X		    cp++;
X	    *cp = '\0';
X	    d = atoi(c);
X	    strcpy(sysname, getfield(0,line,' '));
X	    cp = strchr(sysname, '!');
X	    if (cp == NULL) {
X		fprintf(stderr, "%s\n", line);
X		error("no '!' in 0th field");
X	    }
X	    *cp++ = '\0';	/* cp now points to user name */
X	    byt = atol(getfield(7,line,' '));
X	    tim = atol(getfield(9,line,' '));
X	    strcpy(username, cp);
X	    strcpy(field,getfield(6,line,' '));
X
X	    if(tindex(field,"->") != -1) {
X		    for(i = 0;i < MAXSYS;i ++) {
X		      if(strlen(sysacc[i].sname) <= 0) {
X			    strcpy(sysacc[i].sname, sysname);
X			    sysacc[i].bbsent = byt;
X			    sysacc[i].btsent = tim;
X			    break;
X		      }
X		      else if(strcmp(sysacc[i].sname, sysname) == 0) {
X			    sysacc[i].bbsent += byt;
X			    sysacc[i].btsent += tim;
X			    break;
X		      }
X		    }
X		    usage = tree(usage, username);
X		    dayacc[m][d].sent += byt;
X		    dayacc[m][d].tsent += tim;
X		    dayacc[m][d].used = 1;
X	    }
X	    else {
X		    dayacc[m][d].recv += byt;
X		    dayacc[m][d].trecv += tim;
X		    dayacc[m][d].used = 1;
X		    for(i=0;i< MAXSYS; i++) {
X		      if(strlen(sysacc[i].sname) <= 0) {
X			    strcpy(sysacc[i].sname, sysname);
X			    sysacc[i].brec = byt;
X			    sysacc[i].btrec = tim;
X			    break;
X		      }
X		      else if(strcmp(sysacc[i].sname, sysname) == 0) {
X			    sysacc[i].brec += byt;
X			    sysacc[i].btrec += tim;
X			    break;
X		      }
X		    }
X	    }
X    }
X    fclose(fpin);
X
X    if((fpin = fopen(logfile,"r")) == NULL )
X	    error(logfile);
X
X    while(fgets(line, sizeof line, fpin) != NULL) {
X	    c = getfield(3,line,' ');
X	    strcpy(sysname, getfield(0, line, ' '));
X	    sp = strchr(sysname, '!');
X	    if (sp == NULL) {
X		fprintf(stderr, "%s\n", line);
X		error("no '!' in 0th field");
X	    }
X	    *sp++ = '\0';
X	    if(strcmp(c,"XQT") == 0) {
X		    strcpy(field, sysname);
X		    strcat(field, "!");
X		    strcat(field,getfield(3,line,'('));
X		    field[strlen(field)-3] = '\0';
X		    cmd = tcall(cmd,field);
X	    }
X	    else if(tindex(getfield(4,line,' '),"call") != -1) {
X		    cp = getfield(3,line,' ');
X		    if(strcmp(cp,"SUCCEEDED") == 0)
X			    for(i=0;i< MAXSYS;i++) {
X			      if(strcmp(sysacc[i].sname,sysname) == 0)
X				    sysacc[i].suc++;
X		    }
X		    else if(strcmp(cp,"FAILED") == 0) {
X			    for(i=0;i< MAXSYS;i++)
X			      if(strcmp(sysacc[i].sname,sysname) == 0)
X				    sysacc[i].fail++;
X		    }
X		    else if(strcmp(cp,"LOCKED") == 0) {
X			    for(i=0;i< MAXSYS;i++)
X			      if(strcmp(sysacc[i].sname,sysname) == 0)
X				    sysacc[i].lock++;
X		    }
X	    }
X	    cp = getfield(3,line,' ');
X	    if(strcmp(cp,"REQUESTED") == 0) {
X		    for(i=0;i< MAXSYS;i++)
X		      if(strcmp(sysacc[i].sname,sysname) == 0)
X			    sysacc[i].usent++;
X	    }
X	    else if(strcmp(cp,"COPY") == 0) {
X		    for(i=0;i< MAXSYS;i++) {
X		      if(strcmp(sysacc[i].sname,sysname) == 0)
X			    sysacc[i].ugot++;
X		    }
X	    }
X	    else if(strcmp(cp,"OK") == 0) {
X		    if(tindex(getfield(4,line,' '),"startup") != -1 ) {
X			    for(i=0;i<MAXSYS;i++) {
X				    if(strcmp(sysacc[i].sname,
X					    sysname) == 0)
X					    sysacc[i].okstr++;
X			    }
X		    }
X		    else if(tindex(getfield(4,line,' '),"convers") != -1 ) {
X			    for(i=0;i < MAXSYS;i++) {
X				    if(strcmp(sysacc[i].sname,
X					    sysname) == 0)
X					    sysacc[i].okstop++;
X			    }
X		    }
X	    }
X    }
X    fclose(fpin);
X    printf("UUCP ANALYZER:\n");
X    printf("%5sBy system:\n","");
X    for(i=0;i < MAXSYS;i++) {
X	if(strlen(sysacc[i].sname) > 0) {
X	    printf("%10s%s\n", "", sysacc[i].sname);
X	    hourtmp = sysacc[i].btsent / 60;	/* gives interger min */
X	    second = sysacc[i].btsent - ( hourtmp * 60); /* seconds */
X	    hour =  hourtmp / 60;	/* gives integer hour */
X	    min = hourtmp - ( hour * 60);
X	    printf("%15ssent       %10ld bytes %5stime ", "", sysacc[i].bbsent,"");
X	    printf("%02ld:%02ld:%02ld", hour, min, second);
X	    if (sysacc[i].btsent != 0)
X		    printf("    %3d bytes/sec", sysacc[i].bbsent / sysacc[i].btsent);
X	    putchar('\n');
X	    printf("%15sreceived   %10ld bytes %5stime ","",sysacc[i].brec,"");
X	    hourtmp = sysacc[i].btrec / 60;	/* gives interger min */
X	    second = sysacc[i].btrec - ( hourtmp * 60); /* seconds */
X	    hour =  hourtmp / 60;	/* gives integer hour */
X	    min = hourtmp - ( hour * 60);
X	    printf("%02ld:%02ld:%02ld", hour, min, second);
X	    if (sysacc[i].btrec != 0)
X		    printf("    %3d bytes/sec", sysacc[i].brec / sysacc[i].btrec);
X	    putchar('\n');
X	    printf("%15s# of files %10d sent   %5s %5d received\n",
X		    "",sysacc[i].usent, "",sysacc[i].ugot);
X	    printf("%15s# of calls %10d suc     %10d fail   %10d lock\n",
X		    "", sysacc[i].suc, sysacc[i].fail, sysacc[i].lock);
X	    printf("%15sConversations OK %5d (startup)   %5d (completed)\n",
X		    "", sysacc[i].okstr, sysacc[i].okstop);
X	    /* next do total */
X	    hour = sysacc[i].bbsent - sysacc[i].brec;
X	    if(hour < 0) {	/* means we rec more */
X		    hour *= -1;
X		    printf("%15sreceived %ld bytes more than sent\n",
X			    "", hour);
X	    }
X	    else if(hour > 0)	/* means we sent more */
X		    printf("%15ssent %ld bytes more that received\n",
X			    "", hour);
X	    else
X		    printf("%15ssent the same amount as received\n","");
X	    hourtmp = (sysacc[i].btrec + sysacc[i].btsent)  / 60;
X	    second = (sysacc[i].btrec + sysacc[i].btsent) 
X			    - ( hourtmp * 60); /* seconds */
X	    hour =  hourtmp / 60;	/* gives integer hour */
X	    min = hourtmp - ( hour * 60);
X	    printf("%15stotal connect time %02ld:%02ld:%02ld\n",
X		    "", hour, min, second);
X	}
X    }
X    printf("\n%5sBy user:\n", "");
X    treeprint(usage);
X    printf("\n%5sBy commands:\n", "");
X    trsort();
X    tcallpr(cmd);
X    printf("\n%5sBy day:\n","");
X    for(i = 1; i <= 12; i++)
X	    for(j = 1; j <= 31; j++) {
X		    if(dayacc[i][j].used) {
X			    hourtmp = dayacc[i][j].trecv / 60;
X			    second = dayacc[i][j].trecv - ( hourtmp * 60);
X			    hour =  hourtmp / 60;	/* gives integer hour */
X			    min = hourtmp - ( hour * 60);
X			    printf("%5s%2d/%02d ", "", i,j);
X			    printf("received %8ld bytes in ", dayacc[i][j].recv);
X			    printf("%02ld:%02ld:%02ld/sent %8ld bytes in ",
X				    hour,min,second, dayacc[i][j].sent);
X			    hourtmp = dayacc[i][j].tsent / 60;
X			    second = dayacc[i][j].tsent - ( hourtmp * 60);
X			    hour =  hourtmp / 60;	/* gives integer hour */
X			    min = hourtmp - ( hour * 60);
X			    printf("%02ld:%02ld:%02ld\n", hour,min,second);
X		    }
X	    }
X    exit(0);
X}
X
Xerror(s)
Xchar *s;
X{
X    void perror();
X
X    perror(s);
X    exit(1);
X}
X
Xtindex(s,t)
Xchar s[], t[];
X{
X    register int j,k,i;
X
X    if (s == NULL || t == NULL) {
X	error("tindex: pointer is null");
X    }
X    for(i=0;s[i] != '\0'; i++) {
X	    for(j=i,k=0;t[k] != '\0' && s[j]== t[k]; j++, k++)
X		    ;
X	    if(t[k] == '\0')
X		    return(i);
X    }
X    return(-1);
X}
Xchar *strsave(s)	/* save string s somewhere */
Xchar *s;
X{
X    char *p;
X    char *strcpy();
X
X    if((p = malloc( (unsigned) (strlen(s)+1) )) == NULL) {
X	    error("strsave: out of mem");
X    }
X    return strcpy(p,s);
X}
Xstruct users *tree(p,w)
Xstruct users *p;
Xchar *w;
X{
X    if(p == NULL) { /* new word */
X	    p = (struct users *) malloc (sizeof(struct users));
X	    if (p == NULL) {
X		error("tree: out of memory");
X	    }
X	    p->name = strsave(w);
X	    p->bsent = byt;
X	    p->utim = tim;
X	    p->nsent = 1;
X	    p->nuser = NULL;
X    }
X    else if(strcmp(w,p->name) == 0) {
X	    p->bsent += byt;
X	    p->utim += tim;
X	    p->nsent++;
X    }
X    else {
X	    p->nuser = tree(p->nuser,w);
X    }
X    return(p);
X}
Xstruct call *tcall(p,w)
Xstruct call *p;
Xchar *w;
X{
X    if(p == NULL) { /* new cmd */
X	    p = (struct call *) malloc (sizeof(struct call));
X	    if(p == NULL)
X		    error("tcall out of Mem");
X	    p->ncall = NULL;
X	    p->cname = strsave(w);
X	    p->times = 1;
X	    cmdcount++;
X    }
X    else if(strcmp(w,p->cname) == 0) {
X	    p->times++;
X    }
X    else {
X	    p->ncall = tcall(p->ncall,w);
X    }
X    return(p);
X}
Xtreeprint(p)
Xstruct users *p;
X{
X    if(p != NULL) {
X	    printf("%10s%10s ", "", p->name);
X	    printf("sent %4ld files & %10ld bytes ", p->nsent, p->bsent);
X	    hourtmp = p->utim /60;
X	    second = p->utim - ( hourtmp * 60 );
X	    hour = hourtmp / 60;
X	    min = hourtmp - (hour * 60);
X	    printf("%02ld:%02ld:%02ld\n", hour,min,second);
X	    treeprint(p->nuser);
X    }
X}
Xtcallpr(p)
Xstruct call *p;
X{
X    if(p != NULL ) {
X	    printf("%10d %s\n", p->times, p->cname);
X	    tcallpr(p->ncall);
X    }
X}
Xtrsort()
X{
X    struct call *q;
X    struct call *p;
X    register int i, sw, n,m;
X    char *c;
X    char *d;
X
Xloop:
X    p = cmd;
X    sw = 0;
X    for(i=0;i< cmdcount-1; i++) {
X	    q = p->ncall;
X	    if(p->times < q->times) { /* switch */
X		    c = p->cname;
X		    n = p->times;
X		    d = q->cname;
X		    m = q->times;
X		    p->cname = d;
X		    p->times = m;
X		    q->cname = c;
X		    q->times = n;
X		    sw = 1;
X	    }
X	    p = p->ncall;
X    }
X    if(sw)
X	    goto loop;
X}
X#define NULLP ""
Xchar *
Xgetfield(field,buffer,separator)
Xchar separator;
Xchar buffer[];
Xint field;
X{
X    register int i;
X    char *bp, *p, buff[512];
X    int sht;
X
X    sht = 0;
X    strcpy(buff,buffer);
X    p = &buff[0];
X    i = 0;
X    if((*p == separator) && (field != 0)) {
X	    field--;
X	    sht = 1;
X    }
X    while( i != field) {
X	    for(++p; *p != separator; p++) {
X		    if (*p == '\0') {
X			    return(NULLP);
X		    }
X	    }
X	    i++;
X    }
X    if(sht)
X	    field += 1;
X    if(field != 0) p++;
X    bp =p;
X    for (; *p != separator; p++)
X	    if(*p == '\0')
X		    return(bp);
X    *p = '\0';
X    return(bp);
X}
X
Xtellem()
X{
X	fprintf(stderr, "usage: %s [-l logfile] [-s syslog]\n",
X		Cmdname);
X	exit(1);
X}
!Funky!Stuff!

echo 'x - Makefile'
sed -e 's/^X//' > Makefile << '!Funky!Stuff!'
XSHELL = /bin/sh
XI = /usr/include
XDEST = /usr/hippo/gam/bin
X
Xuucpanz: uucpanz.c	uucpanz.h $I/stdio.h $I/ctype.h 
X	$(CC) $(CFLAGS) -o uucpanz uucpanz.c
X
Xinstall: uucpanz
X	cp uucpanz $(DEST)
X
Xclean:
Xclobber: clean
X	-rm -f uucpanz
X
!Funky!Stuff!

exit