Sort of uusnap (uustatd) for System 5 "flat" dirs
Dennis Bednar
dennis at rlgvax.UUCP
Tue Jul 8 17:07:31 AEST 1986
A few weeks ago I posted a request for a uusnap for System 5
uucp's with a "flat" uucp spool directory. Prior to that request,
I already had a private tool that I call "uustatd" (UUcp STATistics
on spool Directory), but I was hoping to receive a better tool.
By the way, seismo!rick responded that it would be simple to
to change 4.2's uusnap.c to handle "flat" directories. I
spent a short period of time attempting this, but found that
a major rework is still needed because of the way the remote
machine name is embedded in X.machine* files. Our version of
uucp stores all execute files in the form "D.localX*", where local
is our local site (rlgvax). However, the version of uusnap.c
for 4.2 assumes that X files are stored in the form "X.remote*".
To find the machine associated with the D.localX file requires
that the C.remote* file be read.
As a result of this, the hacked up uusnap reports 0 X.* files
for all machines, and reports lots of D.* files destined to
our local machine.
Below is the uustatd program.
-dennis bednar
#--------------- CUT HERE ---------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# Makefile
# README.uustatd
# config.h
# lookdir.c
# machine.h
# sample.out
# uustatd.c
# This archive created: Tue Jul 8 02:51:19 EDT 1986
#
if test -f Makefile
then
echo shar: will not over-write existing file 'Makefile'
else
echo x - Makefile
# ............ F I L E B E G .......... Makefile
cat << '\SHAR_EOF' > Makefile
OBJS = uustatd.o lookdir.o
# CHANGE THIS FOR YOUR LOCAL SITE
# YOU MUST ALSO CHANGE the include file config.h for your local site.
# All that matters for lookdir.c is whether you have
# DIRFIXLEN - USG 14 char fixed length file names
# DIRVARLEN - 4.X BSD variable (up to 255 chars) per directory entry
#
INSTALLDIR = .
uustatd: $(OBJS)
cc $(LDFLAGS) $(OBJS)
mv a.out $@
lookdir.o: machine.h config.h
uustatd.o:
# install uustat with set uid uucp so it has permission read
# the uucp spool files. You must do the install as root.
install: uustatd
chown uucp uustatd
chmod 4751 uustatd
-mv uustatd $(INSTALLDIR)
clean:
rm -f $(OBJS) uustatd a.out core
\SHAR_EOF
# ............ F I L E E N D .......... Makefile
fi # end of overwriting check
if test -f README.uustatd
then
echo shar: will not over-write existing file 'README.uustatd'
else
echo x - README.uustatd
# ............ F I L E B E G .......... README.uustatd
cat << '\SHAR_EOF' > README.uustatd
This is a uucp statistics program for uucp's that use the "flat"
spool directory.
To install it:
Edit machine.h and config.h so that config.h properly defines
either DIRFIXLEN or DIRVARLEN. See the comments in the
Makefile for what these mean.
Change INSTALLDIR in Makefile.
make # make a local copy of uustatd
su root
make install # install it whereever it goes
uustatd # try running the program
LAST,
Report any bugs or improvements to {seismo}!rlgvax!dennis.
\SHAR_EOF
# ............ F I L E E N D .......... README.uustatd
fi # end of overwriting check
if test -f config.h
then
echo shar: will not over-write existing file 'config.h'
else
echo x - config.h
# ............ F I L E B E G .......... config.h
cat << '\SHAR_EOF' > config.h
/*
* config.h
* configure the local options
*
* Based on OS:
* termio.h vs. sgtty.h
* index/rindex vs strchr/strrchr
* if lstat() symbolic link stat is supported
*
* You pick:
* if fixed len or variable len directory entries are supported
*/
/*
* bsd 4.1 and 4.2 uses sgtty for ioctl's
* s3, s5 uses termio.h for ioctls
* On output, defines WTERMIO==1 or undefined
* On output, defines TERMIO to be either sgttyb or termio, for defining
* variables.
*/
#if BSD4_1 == 1 || BSD4_2 == 1
#define TERMIO sgttyb
/* don't want termio so leave WTERMIO undefined */
#else !BSD4_1
#if S3 == 1 || S5 == 1 || S5R2 == 1 || CPGCOS == 1
#define TERMIO termio
#define WTERMIO 1
#else !S3
Unknown version of UNIX. Only BSD 4.[12], S3, S5, S5R2, and CPGCOS known.
#endif S3
#endif BSD4_1
/*
* on 4.1 and 4.2 BSD systems, the S3, S5, and S5R2 string(3)
* names are not around
*/
#if BSD4_1 == 1 || BSD4_2 == 1
#define strchr index
#define strrchr rindex
#endif
#if BSD4_2 == 1 || CPGCOS == 1
#define WSYMLINK 1
#endif
#if BSD4_2 == 1 || CPGCOS == 1
# define DIRVARLEN 1
#else !BSD4_2
# if S3 == 1 || S5 == 1 || S5R2 == 1
# define DIRFIXLEN 1
# else
I don't know the directory conventions on this machine
bsd4.1
# endif
#endif
\SHAR_EOF
# ............ F I L E E N D .......... config.h
fi # end of overwriting check
if test -f lookdir.c
then
echo shar: will not over-write existing file 'lookdir.c'
else
echo x - lookdir.c
# ............ F I L E B E G .......... lookdir.c
cat << '\SHAR_EOF' > lookdir.c
/*
* lookdir.c
* author - dennis bednar 5 3 84
* reads directory entries one at a time for you
* By recompiling with proper ifdef flag, it works with either fixed length
* (S3) or variable length names up to 255 chars as in Berkeley.
*
*
* to use:
*
* setdir (char *name); // to open directory "name" for reading
* // returns -1 iff error
* char *getdir (); // gets next directory name from this directory
* // returns (char *) 0 if done
*
* you do NOT need to call enddir () to close the directory, this
* is automatically done when the eof on the directory is encountered.
*
* TODO
* handle multiple open directories, reading from any.
* allow user to call enddir() when he feels like it.
*/
/* pass DDIRFIXLEN ==1 or DDIRVARLEN == 1 from config.h which is
* included by machine.h
*/
#include <stdio.h>
#include "machine.h"
#ifdef DIRFIXLEN
#include <sys/types.h> /* added for osg5 only */
#include <sys/dir.h> /* old directory format */
#else
#include <sys/types.h> /* define u_long */
#include <sys/dir.h> /* new directory format */
#endif
#ifdef DIRFIXLEN
#ifdef DIRVARLEN
both defined error
#endif
#endif
#ifndef DIRFIXLEN
#ifndef DIRVARLEN
neither defined error
#endif
#endif
#ifdef DIRVARLEN
DIR *opendir (); /* open a directory, Berkley variable len format */
struct direct *readdir (); /* read a filename from a directory */
extern void closedir (); /* finally, close the directory opened by opendir() */
#endif
#define MAXPATH 512
/* globals */
static char errbuf [MAXPATH]; /* build error message here */
#ifdef DIRVARLEN
static DIR *headptr = (DIR *)0; /* pointer to directory structure returned by opendir */
static struct direct *dirptr; /* pointer to directory entry structure returned by readdir */
#else
static int fd = -1; /* file descriptor associated with directory */
static struct direct dirbuf; /* holds directory entry read in from directory */
#endif
/* global routines */
char *getdir ();
/*
* open the directory "name"
* returns
* 0 = good
* -1 = can't open directory
*/
setdir (name)
char *name;
{
/* open the full path name of this dir */
#ifdef DIRFIXLEN
/* if already open, close it first */
if (fd != -1)
enddir ();
if ((fd = open (name, 0)) == -1)
#else
/* if already open, close it first */
if (headptr != (DIR *) 0)
enddir ();
if ((headptr = opendir (name)) == (DIR *) NULL)
#endif
{
return (-1);
}
else
return 0;
/* headptr is a pointer to a memory block containing info about this dir */
}
/*
* return the name of the next directory entry
* (char *) 0 means end of names
*/
char *getdir ()
{
static char filename [MAXPATH]; /* read in file name from directory here */
#ifdef DIRFIXLEN
/* check that directory is indeed open */
if (fd == -1)
{
fprintf (stderr, "dir: getdir: forget to call setdir () first\n");
exit (1);
}
while (read(fd, (char *)&dirbuf, sizeof(dirbuf))>0) { /* not err or eof */
if (dirbuf.d_ino == 0) /* i-node is zero in this slot */
continue; /* skip this slot */
if (strcmp (dirbuf.d_name, ".") == 0 /* then myself */
|| strcmp (dirbuf.d_name, "..") == 0) /* or my parent */
continue; /* skip this dir entry */
strncpy (filename, dirbuf.d_name, 14); /* tail end of name */
#ifdef DEBUG
printf ("debug: %s\n", filename);
fflush (stdout);
#endif
return (filename); /* next call read next entry */
}
#else
/* check that directory is indeed open */
if (headptr == (DIR *) 0)
{
fprintf (stderr, "dir: getdir: forget to call setdir () first\n");
exit (1);
}
while ((dirptr = readdir (headptr)) != (struct direct *)NULL) { /* not err or eof */
/* readdir will automatically skip over inodes which are zero */
if (strcmp (dirptr->d_name, ".") == 0 /* then myself */
|| strcmp (dirptr->d_name, "..") == 0) /* or my parent */
continue; /* skip this dir entry */
strcpy (filename, dirptr->d_name); /* tail end of name */
return (filename); /* next call read next entry */
}
#endif
enddir (); /* have come to eof */
return (char *) 0;
}
/*
* called internally when eof is detected
* sets file descriptor to indicate that file is closed
*/
static enddir ()
{
#ifdef DIRFIXLEN
close (fd);
fd = -1;
#else
closedir (headptr);
headptr = (DIR *) 0;
#endif
}
#ifdef STAND
/*
* standalone test code
* calling format:
readdir // lists all files in the current directory
readdir dir // lists files in "dir"
*/
main (argc, argv)
int argc;
char **argv;
{
int i; /* loop index into nargv [] */
int nargc; /* new arg count returned by getfnames */
char **nargv; /* new argv [] array returned by getfnames */
if (argc == 1)
getfnames (".", &nargc, &nargv);
else if (argc == 2)
getfnames (argv[1], &nargc, &nargv);
else
{
fprintf (stderr, "Wrong number of arguments: usage: %s [directory]\n", argv [0]);
exit (1);
}
if (nargc == -1)
{
fprintf (stderr, "%s: getfnames returned error\n", argv[0]);
exit (1);
}
/* sort file names */
sortargs (nargc-1, &nargv [1]);
/* pretty print in columns */
pretty (nargc, nargv, 80);
}
#endif
/*
* print working directory
* returns the name in curdir
*/
#if 0
pwd (curdir, dirlen)
char *curdir;
int dirlen;
{
FILE *Fd; /* file descriptor for popen */
int fd; /* file descriptor for open */
char *p; /* index within the dir */
static char tempfile [] = "/tmp/pwdXXXXXX"; /* temporary file */
static char pwdcmd [80] = "/bin/pwd >"; /* indirect to a file */
static char rmcmd [80] = "rm "; /* indirect to a file */
/* new way is 10 times cleaner than before !! */
Fd = popen ("/bin/pwd", "r"); /* open a pipe to pwd cmd */
fgets (curdir, dirlen, Fd); /* read in the answer */
pclose (Fd);
curdir[strlen(curdir) - 1] = '\0'; /* change the newline to null */
}
#endif
/*
* returns the file names of all files in "dir" in an argv array
* just like the shell does, with count in argc.
* *pargc = argc returned
* (-1 = error and *pargv is garbage,
* (1 = no files, and argv[0] = ""),
* (2 = 1 file, pointed to by argv[1])
* *pargv = pointer to array of pointers to file names
* ie.
* argv is returned in *pargv.
* argv[0] contains the "" string
* argv[1], ..., argv [argc-1] are pointers to the file names returned
*/
getfnames (dirname, pargc, pargv)
char *dirname;
int *pargc;
char ***pargv;
{
char *rp; /* return pointer to file name returned from getdir */
char **argv; /* argv [] pointer array dynamically growing */
char *fp; /* filename pointer malloc'ed, stuffed into argv[i] */
int argc; /* number of elements in the array so far */
int increase; /* number of bytes to expand argv[] array by */
int numentries; /* number of slots allocated in argv [] array */
int cursize; /* total number of bytes in argv[] currently */
char *malloc (), *realloc (); /* malloc (3) */
if (setdir (dirname) == -1)
{
sprintf (errbuf, "setdir: can't open %s", dirname);
perror (errbuf);
exit (1);
}
/* number of slots in argv array each time expanded by */
#define NUMWANTED 25
/* compute size in bytes for expanding argv[] by NUMWANTED slots */
increase = cursize = NUMWANTED * sizeof (*argv);
/* allocate pointer array the first time */
if ((argv = (char **) malloc (cursize)) == (char **) 0)
{
*pargc = -1;
return;
}
else
{
numentries = NUMWANTED; /* number of slots allocated */
argv [0] = "";
argc = 1; /* number of slots filled so far */
}
while ((rp = getdir ()) != (char *) 0)
{
/* first expand the array if we need to */
if (++argc > numentries)
{
/* have to reallocate a bigger array */
argv = (char **) realloc ((char *)argv, cursize = cursize + increase);
if (argv == (char **) 0)
{
*pargc = -1; /* lost the old array!!! */
return;
}
numentries += NUMWANTED;
}
/* get room to copy file name from static area returned
* from getdir (), if can't, loose filename.
*/
fp = malloc ((strlen (rp) + 1)); /* NULL at end */
if (fp == (char *) 0)
{
--argc;
break;
}
/* now this name will fit in the array, so put it there */
strcpy (fp, rp);
argv [argc-1] = fp;
}
/* return with answers */
*pargc = argc;
*pargv = argv;
}
\SHAR_EOF
# ............ F I L E E N D .......... lookdir.c
fi # end of overwriting check
if test -f machine.h
then
echo shar: will not over-write existing file 'machine.h'
else
echo x - machine.h
# ............ F I L E B E G .......... machine.h
cat << '\SHAR_EOF' > machine.h
/*
* must define only one of S3, S5, S5R2, BSD4_1, or BSD4_2, CPGCOS to be 1
*/
#define CPGCOS 1
#include "config.h"
\SHAR_EOF
# ............ F I L E E N D .......... machine.h
fi # end of overwriting check
if test -f sample.out
then
echo shar: will not over-write existing file 'sample.out'
else
echo x - sample.out
# ............ F I L E B E G .......... sample.out
cat << '\SHAR_EOF' > sample.out
Outgoing Traffic
Machine C Bytes D Bytes X Bytes Files
eli 129 252 60 1
ccicpg 386 25617 195 3
cci632 252 2194 134 2
men1 544 122334 224 4
vrdxhq 710 288291 315 5
dsi1 680 179694 280 5
\SHAR_EOF
# ............ F I L E E N D .......... sample.out
fi # end of overwriting check
if test -f uustatd.c
then
echo shar: will not over-write existing file 'uustatd.c'
else
echo x - uustatd.c
# ............ F I L E B E G .......... uustatd.c
cat << '\SHAR_EOF' > uustatd.c
/*
* uustatd.c
* dennis bednar 05 23 86
* Computer Consoles Inc, 11490 Commerce Park Drive, Reston VA 22091
* seismo!rlgvax!dennis (UUCP address)
*
* uucp statistics program. "d" stands for dennis to avoid confusion
* with the standard "uustat" program.
*
* Read C. "work" files in the current directory, and
* print statistics of what we have for outgoing traffic.
*
* Read X. "local execute" files in the current directory, and
* print statistics of what we have for incoming traffic.
*
* -x99 = debug flag
* -s<sys> = machine name or system name
* -dir<dir> = process directory other that /usr/spool/uucp
*
*
*
* NOTE: This command ONLY works on a version of uucp in which
* there are *no* subdirectories in the UUCPSPOOLDIR. It will
* *NEED* modification to work on versions of uucp which
* have sub-directories. If you decide to modify this code,
* then I suggest you #ifdef it with SUBDIR so that it can easily
* be compiled to work with either kind of machine. Send modifications
* back to the original author (dennis at rlgvax.uucp).
*
* The external directory reading routines can be #ifdef'ed
* for V7/S3/S5 14 character fixed length names or can be
* #ifdefed for 4.2BSD variable (up to 255 chars) file names.
*
*/
#include <stdio.h>
#include <ctype.h> /* isdigit() */
#include <sys/types.h>
#include <sys/stat.h>
#include <dir.h>
#define TRUE 1
#define FALSE 0
#define STR_SAME !strcmp
#define STR_DIFF strcmp
#define STRN_SAME !strncmp
#define STRN_DIFF strncmp
#define MAXFILELEN 100
#define MAXLINE 256
/* routines that read directory entries */
extern int setdir();
extern char *getdir();
extern char *malloc();
#define MAXMCHNAME 20
struct statblock {
/* s_next *must* be first */
struct statblock *s_next; /* next one in queue */
char s_mchname[MAXMCHNAME+1]; /* store machine name here */
long s_csize; /* number of chars in all C. command files */
long s_dsize; /* number of chars in all D. data files */
long s_xsize; /* number of chars in all X. xqt files */
int s_numq; /* number queued up */
};
struct statblock *getstatp(); /* get statistics block pointer */
long filesize();
char *u_errmesg();
char *getmchname();
char *getl_file();
char *cmd;
int debug = 0; /* >=1 prints Warning msgs. >=10 prints all */
char *flag_mch; /* only interested in this machine */
char *flag_dir; /* special case to work in this directory
* instead of default UUCPSPOOLDIR.
*/
/* shared by getstatb(), dump_stat(), and clean_stat() */
static struct statblock *mchlist = NULL;
#define UUCPSPOOLDIR "/usr/spool/uucp"
main(argc, argv)
int argc;
char *argv[];
{
char *wdir; /* name of directory to work in */
cmd = argv[0];
getargs(argc, argv);
if (flag_dir)
wdir = flag_dir; /* user overridden directory */
else
wdir = UUCPSPOOLDIR; /* default directory */
if (chdir( wdir ) == -1)
{
fprintf(stderr, "%s: cannot chdir(%s)\n", cmd, wdir);
exit(1);
}
pass1();
pass2();
exit(0);
}
/*
* Outgoing traffic is processed
* Also each D. and X. file "attached" to a C. file is recorded now.
* Later in pass 2, when the entire directory is rescanned, we
* will report those "detached" D. and X. files.
*/
pass1()
{
char *fname; /* file name */
/* open the current directory */
if ( setdir(".") == -1)
{
fprintf(stderr, "%s: cannot open directory\n", cmd);
exit(1);
}
/* read until eof on directory */
while ( (fname = getdir()) != (char *)NULL)
{
if (debug > 10)
printf("%s\n", fname);
process("C.", fname);
}
if (mchlist) /* have statistics for at least one machine */
{
printf(" Outgoing Traffic\n");
dump_stat();
clean_stat();
}
}
/*
* Incoming traffic is processed
*/
pass2()
{
char *fname; /* file name */
/* open the current directory */
if ( setdir(".") == -1)
{
fprintf(stderr, "%s: cannot open directory\n", cmd);
exit(1);
}
/* read file names */
while ( (fname = getdir()) != (char *)NULL)
{
if (debug > 10)
printf("%s\n", fname);
if (STRN_SAME(fname, "X.", 2) || STRN_SAME(fname, "D.", 2))
chk_detach(fname); /* see if detached */
process("X.", fname);
}
if (mchlist)
{
printf("\n Incoming Traffic (Unprocessed XQT files)\n");
dump_stat();
/* don't worry about clearing statistics 2nd and last time */
}
}
/*
* only process the C. files, because they contain text info
* that points to the attached D. datafile, and attached X.
* execute file.
*
* For example, for outgoing traffic:
* the file C.dsi1AD0060 contains:
S D.dsi1BC0060 D.dsi1BC0060 network - D.dsi1BC0060 0666 network
S D.rlgvaxXA0060 X.rlgvaxXA0060 network - D.rlgvaxXA0060 0666 network
* the file D.dsi1BC0060 contains a news batch created by 'batch',
* and the fiile D.rlgvaxXA0060 contains the commands:
U network rlgvax
F D.dsi1BC0060
I D.dsi1BC0060
C rnews
*
* For incoming traffic, there is an X.<remotesite>... file that
* contains an "F" or "I" line which contains the name of the
* local file which will be processed by /usr/lib/uuxqt.
*/
process(prefix, cfile)
char *cfile; /* name of C. command file */
{
FILE *fp;
char *rtn1,
*rtn2;
char line1[MAXLINE+2];
char line2[MAXLINE+2]; /* room for newline, null */
char *mch; /* name of machine */
char *dfile; /* name of datafile */
char *xfile; /* name of execute file */
static char ddfile[MAXFILELEN+1]; /* room for null */
if (debug > 10) printf("process(%s) called\n", cfile);
if (!isregfile(cfile))
{
if (debug >= 1)
fprintf(stderr, "%s: Warning, ignoring irregular file %s\n", cmd, cfile);
return;
}
/* skip files that don't begin with file prefix */
/* in pass1, (Outgoing files), skip files that don't begin with C. */
/* in pass2, (Incoming files), skip files that don't begin with X. */
if (STRN_DIFF(cfile, prefix, strlen(prefix)))
return;
/* skip files that don't have the desired machine embedded in them */
mch = getmchname(cfile);
if (debug > 10) printf("process: machine name was %s\n", mch);
if (flag_mch && STR_DIFF(mch, flag_mch))
return;
fp = fopen(cfile, "r");
if (fp == NULL)
{
fprintf(stderr, "%s: cannot open %s: %s\n", cmd, cfile, u_errmesg());
exit(1);
}
/* if premature EOF on either line, ignore this file */
if (STR_SAME(prefix, "C."))
{
/* process outgoing C. "work" file */
rtn1 = fgets(line1, sizeof(line1), fp);
rtn2 = fgets(line2, sizeof(line2), fp);
if ( (rtn1 == NULL) || (rtn2 == NULL) )
{
if (debug >= 1) fprintf(stderr, "%s: Warning ignorning file w/o 2 lines: %s\n", cmd, cfile);
return;
}
}
else
{
/* process incoming X. file */
/* in the X. file, search for an F file directive */
/* the file name after it refers to a file on the local mch */
while (fgets(line1, sizeof(line1), fp) != NULL)
{
if (line1[0] == 'F')
break;
}
if (debug > 2) printf("read F line <%s>\n", line1);
}
fclose(fp);
/* Warning *must* copy static dfile to ddfile because getl_file
* reuses the static buffer within.
*/
if (STR_SAME(prefix, "C."))
{
/* process outgoing C. file */
dfile = getl_file("S ", line1); /* get name of D. file from line */
if (dfile && debug > 10) printf("process: Data File = %s\n", dfile);
if (dfile) strcpy(ddfile, dfile);
xfile = getl_file("S ", line2, cfile);
if (xfile && debug > 10) printf("process: XQT File = %s\n", xfile);
if (dfile && xfile)
add_stat(mch, cfile, ddfile, xfile);
else
fprintf(stderr, "%s: Warning, possible bad format in file '%s'\n", cmd, cfile);
}
else
{
/* process incoming X. file */
xfile = cfile; /* file name passed */
dfile = getl_file("F ", line1, cfile);
if (dfile)
add_stat(mch, NULL, dfile, xfile);
else
fprintf(stderr, "%s: Warning, skipping file '%s'\n", cmd, cfile);
}
}
/*
* return UNIX error message associated with errno
* more flexible than perror(3)
*/
char *
u_errmesg()
{
extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];
static char buffer[50];
if (errno < 0 || errno >= sys_nerr)
{
sprintf( buffer, "errno %d undefined (%d=max)", errno, sys_nerr);
return(buffer);
}
return( sys_errlist[errno] );
}
/*
* return true if the file is a regular file (ie not directory, pipe, etc.)
*/
isregfile(fname)
char *fname; /* file name terminated by null */
{
int fd; /* file descriptor */
struct stat statbuf; /* read info about a file into here */
int rtn; /* return code from system call */
fd = open(fname, 0);
if (fd == -1)
{
fprintf(stderr, "%s: isregfile: cannot open %s: %s\n", cmd, fname, u_errmesg());
return FALSE;
}
rtn = fstat(fd, &statbuf);
if (rtn == -1)
{
fprintf(stderr, "%s: cannot stat %s: %s\n", cmd, fname, u_errmesg());
exit(1);
}
close(fd); /* ignore error */
if ( (statbuf.st_mode & S_IFMT) == S_IFREG) /* is a reg file */
return TRUE;
else
return FALSE;
}
/*
* return number of characters in a file
*/
long
filesize(fname)
char *fname; /* file name terminated by null */
{
int fd; /* file descriptor */
struct stat statbuf; /* read info about a file into here */
int rtn; /* return code from system call */
/* no file name was passed */
if (fname == NULL)
return 0L;
fd = open(fname, 0);
if (fd == -1)
{
if (debug >= 1) fprintf(stderr, "%s: Warning, cannot open %s to get size: %s\n", cmd, fname, u_errmesg());
return 0L;
}
rtn = fstat(fd, &statbuf);
if (rtn == -1)
{
fprintf(stderr, "%s: cannot stat %s: %s\n", cmd, fname, u_errmesg());
exit(1);
}
close(fd); /* ignore error */
return (long) statbuf.st_size;
}
/*
* get machine name from a UUCP file name
* format is D.machineXY0000
* C.machineAY0000
* "machine" could end with a digit such as "dsi1"
*
*/
char *
getmchname(fname)
char *fname; /* CANNOT have slash in file name */
{
register char *cp;
#define MCHNAMESIZE 20
static char mchname[MCHNAMESIZE+1]; /* room for null */
int len;
cp = fname;
cp += strlen(fname); /* points to null terminator */
--cp; /* last char of fname */
/* skip backwards over digits until a letter is seen */
/* this works even if the number of digits is not 4 */
while ( (cp > fname) && isdigit(*cp))
--cp;
/* have come to 2nd letter of pair */
cp--; /* cp now points to first letter of pair, or one
* past the machine name.
*/
len = (cp - (fname+2) ); /* compute length of machine name */
if ( (len <= 0) || (len > MCHNAMESIZE) )
{
fprintf(stderr, "%s: getmchname(%s) failed\n", cmd, fname);
exit(1);
}
strncpy(mchname, fname+2, len);
mchname[len] = '\0'; /* strncpy doesn't copy a NULL */
return mchname;
}
/*
* get name of file from the line that looks like:
S file ... more stuff
*/
char *
getl_file(prefix, line, rdfile)
char *prefix; /* either "S " or "F " */
char *line; /* line of data from 'rdfile' */
char *rdfile; /* name of file in case of error */
{
static char filename[MAXFILELEN+1]; /* room for null */
char *cp;
char *dp;
int len;
/* skip over the "S " or "F " part of the line */
cp = line;
if (STRN_DIFF(line, prefix, strlen(prefix)))
{
badformat:
fprintf(stderr, "%s: prefix '%s' expected in file '%s', line '%s'\n", cmd, prefix, rdfile, line);
return NULL;
}
cp += 2;
#define iswhite(c) ( (c == ' ') || (c == '\t') || (c == '\n') || (c == '\0'))
if ( iswhite(*cp) )
{
fprintf(stderr, "%s: iswhite char (%c) found at line+2\n", cmd, *cp);
goto badformat;
}
/* copy the file name from 'cp' to 'filename' */
dp = filename;
len = 0;
while ( !iswhite(*cp))
{
*dp++ = *cp++;
if (++len > MAXFILELEN)
{
fprintf(stderr, "%s: filename in line %s was too long\n", cmd, line);
exit(1);
}
}
*dp = '\0';
return filename;
}
/*
* add statistics for this machine name.
*/
add_stat(mch, cfile, dfile, xfile)
char *mch,
*cfile,
*dfile,
*xfile;
{
struct statblock *sp;
if (debug > 10)
printf("addstat(mch=%s, cfile=%s, dfile=%s, xfile=%s) called\n",
mch, cfile, dfile, xfile);
/* get an existing or brand-new statistics block for this machine */
sp = getstatp(mch);
if (cfile)
sp->s_csize += filesize(cfile);
if (dfile)
{
sp->s_dsize += filesize(dfile);
addtolist(dfile); /* D. file is attached */
}
if (xfile)
{
sp->s_xsize += filesize(xfile);
addtolist(xfile); /* X. file is attached */
}
sp->s_numq++;
if (debug > 10) printf("add_stat: %s %ld %ld %ld %d\n",
sp->s_mchname, sp->s_csize, sp->s_dsize, sp->s_xsize, sp->s_numq);
}
/*
* get a pointer to a statistics block.
* Search the existing list, if found, return it.
* Otherwise allocate a new block, hook onto end of list, zero out
* statistics counters, and return it.
*/
struct statblock *
getstatp(mch)
char *mch;
{
struct statblock **p; /* previous item.ptr in list */
struct statblock *n; /* next item in list */
struct statblock *new; /* new malloced statistics block */
/* search existing list */
for (p = &mchlist; n = *p; p = (struct statblock **)n)
{
if (STR_SAME(mch, n->s_mchname))
return n;
}
/* not found, p points to ptr where new stat block ptr will be stored */
/* note how this code is cleverly written to work even if the
* list is empty the first time, or when the list is non-empty
* the 2nd, 3rd, etc. times.
*/
new = (struct statblock *)malloc(sizeof(struct statblock));
if (new == NULL)
{
fprintf(stderr, "%s: malloc failed\n", cmd);
exit(1);
}
/* hook onto end of existing list if any */
*p = new;
new->s_next = NULL; /* ground end of linked list */
strcpy(new->s_mchname, mch); /* store new machine name */
new->s_csize = new->s_dsize = new->s_xsize = 0L;
new->s_numq = 0;
return new;
}
dump_stat()
{
struct statblock *p;
p = mchlist;
printf("Machine C Bytes D Bytes X Bytes Files\n");
while (p)
{
printf("%s %ld %ld %ld %d\n",
p->s_mchname, p->s_csize, p->s_dsize, p->s_xsize, p->s_numq);
p = p->s_next;
}
}
/*
* discard old statistics by freeing statistics blocks in linked list
*/
clean_stat()
{
struct statblock *p, /* current statblock item */
*n; /* next one after this one */
for (p = mchlist; p; p = n)
{
n = p->s_next; /* save next item ptr ... */
free(p); /* before discarding current item */
}
mchlist = NULL; /* list is empty again */
}
/*
* get arguments from command line, assign global flag variables
*/
getargs(argc, argv)
int argc;
char **argv;
{
register int i;
if (argc != 1)
for (i = 1; i < argc; ++i)
{
if ( STRN_SAME(argv[i], "-x", 2) )
debug = atoi(&argv[1][2]);
else if (STRN_SAME( argv[i], "-s", 2) )
flag_mch = argv[i]+2;
else if (STRN_SAME( argv[i], "-dir", 4) )
flag_dir = argv[i]+4;
}
}
struct node {
struct list *l_next; /* MUST be first, next item in list */
char l_name[1]; /* domain name + 1 for null */
};
struct node *head = NULL;
/*
* standard FIFO implemented by linked list.
* NO sorting.
*/
addtolist(name)
char *name;
{
register struct node **p, /* previous item */
*n; /* next item */
struct node *np; /* node pointer */
/* find node pointed to by p which is the end of the list to tack onto */
for (p = &head; n = *p; p = (struct node **)n)
if (STR_SAME(n->l_name, name))
return; /* already in list */
/* use same trick that cpio uses */
np = (struct node *) malloc( sizeof(struct node) + strlen(name) );
if (np == NULL)
{
perror("out of memory");
exit(1);
}
/* stuff node with domain name */
np->l_next = NULL; /* ground end of list */
strcpy(np->l_name, name);
/* hook onto end of list */
*p = np;
/* printf("dbg: %s\n", name); /* print domains as we hit them */
/* done */
}
/*
* search the linked list, returning TRUE iff found.
* The arg passed will be a D. or X. file name saved during
* pass 1, hopefully. If not, its detached.
*/
inlist(fname)
char *fname;
{
register struct node **p, /* previous item */
*n; /* next item */
for (p = &head; n = *p; p = (struct node **)n)
if (STR_SAME(n->l_name, fname))
return 1;
return 0;
}
chk_detach(fname)
char *fname;
{
if (!inlist(fname))
fprintf(stderr, "%s: Warning: %s is detached\n", cmd, fname);
}
\SHAR_EOF
# ............ F I L E E N D .......... uustatd.c
fi # end of overwriting check
# end of shell archive
exit 0
--
-Dennis Bednar
{decvax,ihnp4,harpo,allegra}!seismo!rlgvax!dennis UUCP
More information about the Comp.sources.unix
mailing list