[net.sources] cfs - check file states

rex%erebus@adm.UUCP (02/16/87)

"Here it is, take it"

-- Rex
#! /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:
#	README
#	cfs.man.out
#	cfs.man
#	Makefile
#	TODO
#	cfs.h
#	addname.c
#	cavn.c
#	cfs.c
#	create.c
#	deco.c
#	delete.c
#	mkmode.c
#	movefile.c
#	openread.c
#	openwrite.c
#	poparg.c
#	print2stat.c
#	printstat.c
#	readstat.c
#	statcheck.c
#	statcomp.c
#	table.c
#	update.c
#	writestat.c
# This archive created: Sun Feb 15 20:16:13 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1227 characters)'
if test -f 'README'
then
 echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
X							February 12, 1987
X
XThis directory contains the source code and man page for "cfs", a program that
Xchecks file states on 4.2/4.3 BSD Unix systems.  Cfs has been tested on a VAX
X750 4.2/4.3 BSD system, and a Sun 100U running Sun Unix version 2.  Cfs can
Xcheck the states of over 60 files per CPU second on either system.
X
XYou should be able to type:
X
X  make
X  make test
X  make install
X  make clean
X
XYou'll probably want to edit the Makefile before you type "make install".
XYou must install the man entry by hand.
X
XSystem managers should use cfs to check almost all files in the following
Xdirectories:
X
X  /
X  /etc
X  /bin
X  /lib
X  /usr
X  /usr/bin
X  /usr/ucb
X  /usr/lib
X  /usr/include
X  /usr/src
X  /usr/local/bin  -  or any other dirs in most everyone's path
X
XGradually, you can weed out the volatile files.  Don't forget to add "hidden"
Xfiles starting with ., etc., that *'s don't pick up.  I have crontab run cfs
Xevery night and mail the results to root.
X
XIf you make useful changes to cfs, particularly if you port cfs to System V,
Xplease mail the changes back to me.
X
X-- Rex Sanders
X   rex@erebus.stanford.edu	(internet)
X   ????!erebus!rex		(uucp)
X   US Geological Survey, 345 Middlefield Rd, MS 999, Menlo Park CA 94025
SHAR_EOF
if test 1227 -ne "`wc -c < 'README'`"
then
 echo shar: error transmitting "'README'" '(should have been 1227 characters)'
fi
chmod +x 'README'
fi # end of overwriting check
echo shar: extracting "'cfs.man.out'" '(5382 characters)'
if test -f 'cfs.man.out'
then
 echo shar: will not over-write existing file "'cfs.man.out'"
else
sed 's/^X//' << \SHAR_EOF > 'cfs.man.out'
X
X
X
XCFS(1)              UNIX Programmer's Manual               CFS(1)
X
X
X
XNAME
X     cfs - check file states
X
XSYNOPSIS
X     cfs -[scudt][v]  statfile  [filename ...]
X
XDESCRIPTION
X     _C_f_s maintains a _s_t_a_t_f_i_l_e for checking the states of many
X     files.  _C_f_s checks for changes in most of the parameters
X     returned by the stat(2) system call, including: inode
X     number, file mode, link count, owner, group, length, modifi-
X     cation date/time, and inode change date/time.  Access
X     date/time is not checked for obvious reasons, and modifica-
X     tion date/time is not checked for character or block special
X     devices.  By checking file states on a regular basis, you
X     can help insure the security of the files checked.
X
X     Normal use of _c_f_s is with the -s option, as in:
X
X          cfs  -s  statfile
X
XOPTIONS
X     -s   checks the Status of each filename in _s_t_a_t_f_i_l_e against
X          the recorded status.  If any differences are found, a
X          warning message is printed on standard output, and _c_f_s
X          exits with an error status.
X
X     -c   Creates a _s_t_a_t_f_i_l_e from a list of filenames read from
X          standard input.
X
X     -u   Updates _s_t_a_t_f_i_l_e for each _f_i_l_e_n_a_m_e. If no entry is
X          found, the entry is added.
X
X     -d   Deletes the entry for each _f_i_l_e_n_a_m_e from _s_t_a_t_f_i_l_e.
X
X     -t   prints a Table of contents for the entire _s_t_a_t_f_i_l_e if
X          no filename present.  With -tv, prints the status
X          information.  Output format is similar to the output
X          from "ls  -lig", with the addition of inode change time
X          after the modification time.
X
X     v    Verbose option, prints a file-by-file description of
X          the actions taken.  Can be added to any of the other
X          options, i.e.  -sv, -cv, -uv, -dv, -tv.
X
XEXAMPLES
X     To create a _s_t_a_t_f_i_l_e for your home directory you could use
X     the following sequence:
X
X          echo  $HOME/.??*  $HOME/*  |  cfs  -c  statfile
X
X     To remove the volatile entries ".msgsrc" and "calendar":
X
X
X
XPrinted 2/15/87               LOCAL                             1
X
X
X
X
X
X
XCFS(1)              UNIX Programmer's Manual               CFS(1)
X
X
X
X          cfs  -d  statfile  $HOME/.msgsrc  $HOME/calendar
X
X     To check file states:
X
X          cfs  -s  statfile
X
XNOTES
X     The _s_t_a_t_f_i_l_e is exclusively locked using _f_l_o_c_k(2) for _a_n_y
X     operation.  _C_f_s will exit with an error message if the _s_t_a_t_-
X     _f_i_l_e is locked.
X
X     When creating a _s_t_a_t_f_i_l_e, use absolute pathnames for best
X     results e.g. "/we/foo/bar" not just "bar".
X
X     _S_t_a_t_f_i_l_es may be glued together using cat(1).  Otherwise,
X     the status data is stored in binary form, and the _s_t_a_t_f_i_l_es
X     should not be read or edited.
X
XDIAGNOSTICS
X     cfs: status check FAILED for _F_I_L_E_N_A_M_E
X          The file status stored in the statfile doesn't match
X          the current status of _F_I_L_E_N_A_M_E, or _F_I_L_E_N_A_M_E doesn't
X          exist.  With the -v option, more detail is printed.
X          You should investigate this potential security viola-
X          tion.
X
X     cfs: can't open _S_T_A_T_F_I_L_E for reading
X
X     cfs: can't open _S_T_A_T_F_I_L_E for writing
X
X     cfs: statfile _S_T_A_T_F_I_L_E is in use and locked
X          Another _c_f_s program is using the _S_T_A_T_F_I_L_E.  Try again
X          later.
X
X     cfs: error - truncated statfile
X          The statfile was not as long as expected.  Perhaps you
X          specified a file that is not really a statfile.
X
X     cfs: error - bad pathname in statfile
X          A mangled pathname is in the statfile.  Perhaps the
X          statfile is truncated or trashed, or perhaps you speci-
X          fied a statfile that is not really a statfile.
X
X     cfs: _S_T_A_T_F_I_L_E not changed
X          If _c_f_s encounters an error during an update (-u) or
X          delete (-d) operation, the original _S_T_A_T_F_I_L_E will not
X          be changed.
X
X     cfs: option _X not recognized
X          You specified a command line option other than -scudtv.
X
X     cfs: no statfile specified
X
X
X
XPrinted 2/15/87               LOCAL                             2
X
X
X
X
X
X
XCFS(1)              UNIX Programmer's Manual               CFS(1)
X
X
X
X          You did not specify the name of the statfile to be used
X          on the command line.
X
X     cfs: _X: only one of {scudt} may be specified
X          You gave more than one action option on the command
X          line, e.g.  -ut.
X
X     cfs: one of {-s -c -u -d -t} must be specified
X          You did not give any action options on the command
X          line, e.g.  -v.
X
XFILES
X     ./cfs.XXXXXX - temporary file for update and delete opera-
X     tions.
X
XBUGS
X     _C_f_s can't properly check the status of the _s_t_a_t_f_i_l_e using
X     _s_t_a_t_f_i_l_e. This bug is not a fault of the program - "Time is
X     Mother Nature's way of keeping everything from happening at
X     once."
X
XAUTHOR
X     Rex Sanders, USGS Pacific Marine Geology
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XPrinted 2/15/87               LOCAL                             3
X
X
X
SHAR_EOF
echo shar: 235 control characters may be missing from "'cfs.man.out'"
if test 5382 -ne "`wc -c < 'cfs.man.out'`"
then
 echo shar: error transmitting "'cfs.man.out'" '(should have been 5382 characters)'
fi
chmod +x 'cfs.man.out'
fi # end of overwriting check
echo shar: extracting "'cfs.man'" '(4336 characters)'
if test -f 'cfs.man'
then
 echo shar: will not over-write existing file "'cfs.man'"
else
sed 's/^X//' << \SHAR_EOF > 'cfs.man'
X.lg 0
X.hy 0
X.TH CFS 1 LOCAL "USGS Pacific Marine Geology"
X.SH NAME
Xcfs \- check file states
X.SH SYNOPSIS
X.B cfs
X\-[scudt][v]  statfile  [filename ...]
X.SH DESCRIPTION
X.I Cfs
Xmaintains a
X.I statfile
Xfor checking the states of many files.
X.I Cfs
Xchecks for changes in most of the parameters returned by the
X.BR stat (2)
Xsystem call, including:
Xinode number,
Xfile mode,
Xlink count,
Xowner,
Xgroup,
Xlength,
Xmodification date/time,
Xand
Xinode change date/time.
XAccess date/time is not checked for obvious reasons,
Xand modification date/time is not checked for character or block special
Xdevices.
XBy checking file states on a regular basis,
Xyou can help insure the security of the files checked.
X.PP
XNormal use of
X.I cfs
Xis with the
X.B \-s
Xoption, as in:
X.sp
X.RS
Xcfs  \-s  statfile
X.RE
X.SH OPTIONS
X.IP "\-s"
Xchecks the Status of each filename in
X.I statfile
Xagainst the recorded status.
XIf any differences are found,
Xa warning message is printed on standard output,
Xand
X.I cfs
Xexits with an error status.
X.IP "\-c"
XCreates a
X.I statfile
Xfrom a list of filenames read from standard input.
X.IP "\-u"
XUpdates
X.I statfile
Xfor each
X.I filename.
XIf no entry is found, the entry is added.
X.IP "\-d"
XDeletes the entry for each
X.I filename
Xfrom
X.I statfile.
X.IP "\-t"
Xprints a Table of contents for the entire
X.I statfile
Xif no filename present.
XWith 
X.B \-tv,
Xprints the status information.
XOutput format is similar to the output from \*(lqls  \-lig\*(rq,
Xwith the addition of inode change time after the modification time.
X.IP "v"
XVerbose option,
Xprints a file-by-file description of the actions taken.
XCan be added to any of the other options, 
Xi.e.
X.BR \-sv ,
X.BR \-cv ,
X.BR \-uv ,
X.BR \-dv ,
X.BR \-tv .
X.SH EXAMPLES
XTo create a
X.I statfile
Xfor your home directory you could use the following sequence:
X.sp
X.RS
X.nf
Xecho  $HOME/.??*  $HOME/*  |  cfs  \-c  statfile
X.fi
X.RE
X.sp
XTo remove the volatile entries \*(lq.msgsrc\*(rq and \*(lqcalendar\*(rq:
X.sp
X.RS
X.nf
Xcfs  \-d  statfile  $HOME/.msgsrc  $HOME/calendar
X.fi
X.RE
X.sp
XTo check file states:
X.sp
X.RS
X.nf
Xcfs  \-s  statfile
X.fi
X.RE
X.SH NOTES
X.PP
XThe
X.I statfile
Xis exclusively locked using
X.IR flock (2)
Xfor
X.I any
Xoperation.
X.I Cfs
Xwill exit with an error message if the
X.I statfile
Xis locked.
X.PP
XWhen creating a
X.I statfile,
Xuse absolute pathnames for best results
Xe.g. \*(lq/we/foo/bar\*(rq not just \*(lqbar\*(rq.
X.PP
X.IR Statfile s
Xmay be glued together using
X.BR cat (1).
XOtherwise, the status data is stored in binary form,
Xand the
X.IR statfile s
Xshould not be read or edited.
X.SH DIAGNOSTICS
X.TP
Xcfs: status check FAILED for \f2FILENAME\f1
XThe file status stored in the statfile doesn't match the current status of
X.IR FILENAME ,
Xor
X.I FILENAME
Xdoesn't exist.
XWith the
X.B \-v
Xoption, more detail is printed.
XYou should investigate this potential security violation.
X.TP
Xcfs: can't open \f2STATFILE\f1 for reading
X.TP
Xcfs: can't open \f2STATFILE\f1 for writing
X.TP
Xcfs: statfile \f2STATFILE\f1 is in use and locked
XAnother
X.I cfs
Xprogram is using the
X.IR STATFILE .
XTry again later.
X.TP
Xcfs: error - truncated statfile
XThe statfile was not as long as expected.
XPerhaps you specified a file that is not really a statfile.
X.TP
Xcfs: error - bad pathname in statfile
XA mangled pathname is in the statfile.
XPerhaps the statfile is truncated or trashed, or
Xperhaps you specified a statfile that is not really a statfile.
X.TP
Xcfs: \f2STATFILE\f1 not changed
XIf
X.I cfs
Xencounters an error during an update (\f3\-u\f1) or delete (\f3\-d\f1)
Xoperation,
Xthe original
X.I STATFILE
Xwill not be changed.
X.TP
Xcfs: option \f2X\f1 not recognized
XYou specified a command line option other than
X.BR -scudtv .
X.TP
Xcfs: no statfile specified
XYou did not specify the name of the statfile to be used on the command line.
X.TP
Xcfs: \f2X\f1: only one of {scudt} may be specified
XYou gave more than one action option on the command line, e.g.
X.BR \-ut .
X.TP
Xcfs: one of {-s -c -u -d -t} must be specified
XYou did not give any action options on the command line, e.g.
X.BR \-v .
X.SH FILES
X\&./cfs.XXXXXX \- temporary file for update and delete operations.
X.SH BUGS
X.I Cfs
Xcan't properly check the status of the
X.I statfile
Xusing
X.I statfile.
XThis bug is not a fault of the program \-
X\*(lqTime is Mother Nature's way of keeping everything
Xfrom happening at once.\*(rq
X.SH AUTHOR
XRex Sanders, USGS Pacific Marine Geology
SHAR_EOF
if test 4336 -ne "`wc -c < 'cfs.man'`"
then
 echo shar: error transmitting "'cfs.man'" '(should have been 4336 characters)'
fi
chmod +x 'cfs.man'
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1075 characters)'
if test -f 'Makefile'
then
 echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X#  Makefile for cfs
X#    Rex Sanders, USGS, 12-86
X#
XCFLAGS=-O
XOBJ=	addname.o cavn.o cfs.o create.o deco.o delete.o mkmode.o \
X	movefile.o openread.o openwrite.o poparg.o print2stat.o \
X	printstat.o readstat.o statcheck.o statcomp.o table.o update.o \
X	writestat.o
XPRINTER=enscript -q
X
Xcfs:  ${OBJ}
X	cc ${CFLAGS} -o cfs ${OBJ}
X
X
X${OBJ}: cfs.h
X
Xlint:
X	lint -bchx *.h *.c
X
Xprint:
X	${PRINTER} Makefile *.h *.c
X
Xtest:  cfs
X	echo `pwd`/*.c `pwd`/test.statfile | ./cfs -cv test.statfile
X	-./cfs -sv	test.statfile
X	./cfs -t	test.statfile
X	./cfs -tv	test.statfile	`pwd`/test.statfile
X	./cfs -dv	test.statfile	`pwd`/test.statfile
X	-./cfs -sv	test.statfile
X	./cfs -tv	test.statfile	`pwd`/test.statfile
X	./cfs -uv	test.statfile	`pwd`/test.statfile
X	-./cfs -sv	test.statfile	`pwd`/test.statfile
X	./cfs -uv	test.statfile	`pwd`/test.statfile
X	./cfs -t	test.statfile	`pwd`/test.statfile
X	-./cfs
X	-./cfs -junkt
X	-./cfs -t
X	-./cfs -t	NONEXISTENTFILE
X
Xinstall: cfs
X	install -s -o bin -g bin -m 0111 cfs /usr/local/bin
X
Xclean:
X	/bin/rm -f ${OBJ} cfs cfs.?????? test.statfile make.out lint.out
SHAR_EOF
if test 1075 -ne "`wc -c < 'Makefile'`"
then
 echo shar: error transmitting "'Makefile'" '(should have been 1075 characters)'
fi
chmod +x 'Makefile'
fi # end of overwriting check
echo shar: extracting "'TODO'" '(214 characters)'
if test -f 'TODO'
then
 echo shar: will not over-write existing file "'TODO'"
else
sed 's/^X//' << \SHAR_EOF > 'TODO'
X- add signal handler to clean up temp file on breakout or bomb
X
X- make checking parts of status optional, e.g. don't check modify time
X  on /etc/passwd, but check everything else.
X
X- Add ifdefs for SysV and others
SHAR_EOF
if test 214 -ne "`wc -c < 'TODO'`"
then
 echo shar: error transmitting "'TODO'" '(should have been 214 characters)'
fi
chmod +x 'TODO'
fi # end of overwriting check
echo shar: extracting "'cfs.h'" '(146 characters)'
if test -f 'cfs.h'
then
 echo shar: will not over-write existing file "'cfs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'cfs.h'
X#include <stdio.h>
X#include <strings.h>
X#include <sys/param.h>
X#include <sys/stat.h>
X#include <sys/file.h>
X
Xint     errno;
Xchar   *sys_errlist[];
SHAR_EOF
if test 146 -ne "`wc -c < 'cfs.h'`"
then
 echo shar: error transmitting "'cfs.h'" '(should have been 146 characters)'
fi
chmod +x 'cfs.h'
fi # end of overwriting check
echo shar: extracting "'addname.c'" '(356 characters)'
if test -f 'addname.c'
then
 echo shar: will not over-write existing file "'addname.c'"
else
sed 's/^X//' << \SHAR_EOF > 'addname.c'
X/*
X * addname - add name to statfile on fp for cfs
X */
X
X#include "cfs.h"
X
Xaddname (fp, name)
XFILE   *fp;
Xchar   *name;
X{
X    extern char *myname;
X    int     errflg = 0;
X    struct stat sbuf;
X
X    if (stat (name, &sbuf)) {
X	fprintf (stderr, "%s: ", myname);
X	perror (name);
X	errflg = 1;
X    }
X    else
X	writestat (fp, name, &sbuf);
X
X    return (errflg);
X}
SHAR_EOF
if test 356 -ne "`wc -c < 'addname.c'`"
then
 echo shar: error transmitting "'addname.c'" '(should have been 356 characters)'
fi
chmod +x 'addname.c'
fi # end of overwriting check
echo shar: extracting "'cavn.c'" '(313 characters)'
if test -f 'cavn.c'
then
 echo shar: will not over-write existing file "'cavn.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cavn.c'
X/*
X *  cavn - compare argv versus name
X */
X
Xcavn (argc, argv, foundlist, name)
Xint     argc;
Xchar  **argv;
Xint    *foundlist;
Xchar   *name;
X{
X    int     retval = 0;
X
X    while (argc-- > 0) {
X	if (!strcmp (*argv, name)) {
X	    (*foundlist)++;
X	    retval++;
X	}
X	argv++;
X	foundlist++;
X    }
X    return (retval);
X}
SHAR_EOF
if test 313 -ne "`wc -c < 'cavn.c'`"
then
 echo shar: error transmitting "'cavn.c'" '(should have been 313 characters)'
fi
chmod +x 'cavn.c'
fi # end of overwriting check
echo shar: extracting "'cfs.c'" '(927 characters)'
if test -f 'cfs.c'
then
 echo shar: will not over-write existing file "'cfs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cfs.c'
X/*
X *  cfs - check file states
X *
X *	Rex Sanders, US Geological Survey, 12/86
X */
X
X#include "cfs.h"
X
Xchar   *myname;
X
Xmain (argc, argv)
Xint     argc;
Xchar  **argv;
X{
X    char   *statfile;
X    int     verbose = 0;
X    int     option = 0;
X    int     errflg = 0;
X
X
X/*
X * Switch to the proper action procedure
X */
X    switch (option = deco (&argc, &argv, &statfile, &verbose)) {
X	case 's': 
X	    errflg = statcheck (statfile, verbose);
X	    break;
X	case 'c': 
X	    errflg = create (statfile, verbose);
X	    break;
X	case 'u': 
X	    errflg = update (statfile, argc, argv, verbose);
X	    break;
X	case 'd': 
X	    errflg = delete (statfile, argc, argv, verbose);
X	    break;
X	case 't': 
X	    errflg = table (statfile, argc, argv, verbose);
X	    break;
X	default: 
X	    fprintf (stderr, "usage:  %s [-scudt][v] ", myname);
X	    fprintf (stderr, "statfile [filename ...]\n");
X	    errflg = option;
X	    break;
X    }
X
X    exit (errflg);
X}
SHAR_EOF
if test 927 -ne "`wc -c < 'cfs.c'`"
then
 echo shar: error transmitting "'cfs.c'" '(should have been 927 characters)'
fi
chmod +x 'cfs.c'
fi # end of overwriting check
echo shar: extracting "'create.c'" '(475 characters)'
if test -f 'create.c'
then
 echo shar: will not over-write existing file "'create.c'"
else
sed 's/^X//' << \SHAR_EOF > 'create.c'
X/*
X * create - creates a statfile for cfs
X */
X
X#include "cfs.h"
X
Xcreate (statfile, verbose)
Xchar   *statfile;
Xint     verbose;
X{
X    extern char *myname;
X    FILE   *sfp;
X    int     errflg = 0;
X    char    name[MAXPATHLEN];
X    FILE   *openwrite ();
X
X    sfp = openwrite (statfile);
X
X/* 
X *	add each name in stdin
X */
X    while (scanf ("%s", name) != EOF)
X	if (!addname (sfp, name))
X	    if (verbose)
X		printf ("a %s\n", name);
X	    else
X		errflg++;
X
X    return (errflg);
X}
SHAR_EOF
if test 475 -ne "`wc -c < 'create.c'`"
then
 echo shar: error transmitting "'create.c'" '(should have been 475 characters)'
fi
chmod +x 'create.c'
fi # end of overwriting check
echo shar: extracting "'deco.c'" '(1456 characters)'
if test -f 'deco.c'
then
 echo shar: will not over-write existing file "'deco.c'"
else
sed 's/^X//' << \SHAR_EOF > 'deco.c'
X/*
X *  decode option flags for cfs
X */
X#include <stdio.h>
X#include <strings.h>
X
Xdeco (argc, argv, statfile, verbose)
Xint    *argc;
Xchar ***argv;
Xchar  **statfile;
Xint    *verbose;
X
X{
X    extern char *myname;
X    char   *slash;
X    int     option = 0;
X    int     errflg = 0;
X    char   *arg;
X    char   *poparg ();
X
X    myname = poparg (argc, argv);
X    slash  = rindex (myname, '/');
X    myname = slash ? (slash + 1) : myname;
X/*
X *  looking for command line formed:
X *    cfs -[scudt][v] statfile [more args ...]
X *  where one and only one of s, c, u, d, t must be specified.
X */
X    arg = poparg (argc, argv);
X    if (arg != NULL && *arg == '-') {
X	for (arg++; *arg != '\0'; arg++)
X	    switch (*arg) {
X		case 's': 
X		case 'c': 
X		case 'u': 
X		case 'd': 
X		case 't': 
X		    if (!option) {
X			option = *arg;
X			*statfile = poparg (argc, argv);
X			if (*statfile == NULL) {
X			    fprintf (stderr,
X				    "%s: no statfile specified\n",
X				    myname);
X			    errflg++;
X			}
X		    }
X		    else {
X			fprintf (stderr,
X			    "%s: %c: only one of {scudt} may be specified\n",
X			    myname, *arg);
X			errflg++;
X		    }
X		    break;
X		case 'v':
X		    (*verbose)++;
X		    break;
X		default: 
X		    fprintf (stderr, "%s: option %c not recognized\n",
X			    myname, *arg);
X		    errflg++;
X		    break;
X	    }
X    }
X    else {
X	fprintf (stderr,
X		"%s: one of {-s -c -u -d -t} must be specified\n",
X		myname);
X	errflg++;
X    }
X
X    return (errflg ? -1 : option);
X}
SHAR_EOF
if test 1456 -ne "`wc -c < 'deco.c'`"
then
 echo shar: error transmitting "'deco.c'" '(should have been 1456 characters)'
fi
chmod +x 'deco.c'
fi # end of overwriting check
echo shar: extracting "'delete.c'" '(1449 characters)'
if test -f 'delete.c'
then
 echo shar: will not over-write existing file "'delete.c'"
else
sed 's/^X//' << \SHAR_EOF > 'delete.c'
X/*
X * delete - deletes names from statfile for cfs
X */
X
X#include "cfs.h"
X
Xchar   *mktemp ();
Xchar   *calloc ();
X
Xdelete (statfile, argc, argv, verbose)
Xchar   *statfile;
Xint     argc;
Xchar  **argv;
Xint     verbose;
X{
X    extern char *myname;
X    FILE   *sfp;
X    char   *tfname;
X    FILE   *tfp;
X    int     errflg = 0;
X    int     rstat = 0;
X    char    name[MAXPATHLEN];
X    struct stat sbuf;
X    int    *foundlist;
X    char   *arg;
X    char   *mktemp ();
X    char   *poparg ();
X    FILE   *openread ();
X    FILE   *openwrite ();
X
X    sfp = openread (statfile);
X    tfname = mktemp ("cfs.XXXXXX");
X    tfp = openwrite (tfname);
X/*
X *	get storage for foundlist
X */
X/*NOSTRICT*/
X    if (!(foundlist = (int *) calloc ((unsigned) argc, sizeof (int)))) {
X	fprintf (stderr, "cfs: can't calloc %d ints\n", argc);
X	exit (1);
X    }
X/*
X *  for each entry in statfile
X */
X    while (!(rstat = readstat (sfp, statfile, name, &sbuf))) {
X	if (!cavn (argc, argv, foundlist, name))
X	    writestat (tfp, name, &sbuf);
X    }
X    fclose (tfp);
X    fclose (sfp);
X    if (rstat > 0) {
X	while ((arg = poparg (&argc, &argv)) != NULL) {
X	    if (*foundlist && verbose)
X		printf ("d %s\n", arg);
X	    foundlist++;
X	}
X	if (movefile (tfname, statfile)) {
X	    fprintf (stderr, "%s: %s not changed\n", myname, statfile);
X	    errflg++;
X	}
X    }
X    else {
X	unlink (tfname);
X	fprintf (stderr, "%s: %s not changed\n", myname, statfile);
X	errflg++;
X    }
X    return (errflg);
X}
SHAR_EOF
if test 1449 -ne "`wc -c < 'delete.c'`"
then
 echo shar: error transmitting "'delete.c'" '(should have been 1449 characters)'
fi
chmod +x 'delete.c'
fi # end of overwriting check
echo shar: extracting "'mkmode.c'" '(763 characters)'
if test -f 'mkmode.c'
then
 echo shar: will not over-write existing file "'mkmode.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mkmode.c'
X#include "cfs.h"
X
Xchar *
Xmkmode(mode)
Xu_short mode;
X{
X	static char     ms[11];
X
X	strcpy(ms, "----------");
X	switch (mode & S_IFMT) {
X	case S_IFREG:
X	default:
X		break;
X	case S_IFDIR:
X		ms[0] = 'd'; break;
X	case S_IFCHR:
X		ms[0] = 'c'; break;
X	case S_IFBLK:
X		ms[0] = 'b'; break;
X	case S_IFLNK:
X		ms[0] = 'l'; break;
X	case S_IFSOCK:
X		ms[0] = 's'; break;
X	}
X
X	if (mode & 00400) ms[1] = 'r';
X	if (mode & 00200) ms[2] = 'w';
X	if (mode & 00200) ms[3] = 'x';
X	if (mode & 00040) ms[4] = 'r';
X	if (mode & 00020) ms[5] = 'w';
X	if (mode & 00010) ms[6] = 'x';
X	if (mode & 00004) ms[7] = 'r';
X	if (mode & 00002) ms[8] = 'w';
X	if (mode & 00001) ms[9] = 'x';
X
X	if (mode & S_ISUID) ms[3] = 's';
X	if (mode & S_ISGID) ms[6] = 's';
X	if (mode & S_ISVTX) ms[9] = 't';
X	return(ms);
X}
SHAR_EOF
if test 763 -ne "`wc -c < 'mkmode.c'`"
then
 echo shar: error transmitting "'mkmode.c'" '(should have been 763 characters)'
fi
chmod +x 'mkmode.c'
fi # end of overwriting check
echo shar: extracting "'movefile.c'" '(390 characters)'
if test -f 'movefile.c'
then
 echo shar: will not over-write existing file "'movefile.c'"
else
sed 's/^X//' << \SHAR_EOF > 'movefile.c'
X/*
X * movefile - move old to new; bomb if unsuccessful
X */
X
X#include "cfs.h"
X
Xmovefile (old, new)
Xchar   *old;
Xchar   *new;
X{
X    extern char *myname;
X    char	sysline[5 + (2 * MAXPATHLEN)];
X
X    if (rename (old, new)) {	/* if rename doesn't do it, try cp */
X	sprintf (sysline, "cp %s %s", old, new);
X	if (system (sysline))
X	    return (1);
X	else
X	    unlink (old);
X    }
X    return (0);
X}
SHAR_EOF
if test 390 -ne "`wc -c < 'movefile.c'`"
then
 echo shar: error transmitting "'movefile.c'" '(should have been 390 characters)'
fi
chmod +x 'movefile.c'
fi # end of overwriting check
echo shar: extracting "'openread.c'" '(512 characters)'
if test -f 'openread.c'
then
 echo shar: will not over-write existing file "'openread.c'"
else
sed 's/^X//' << \SHAR_EOF > 'openread.c'
X/*
X * openread - open a file for exclusive read; bomb if unsuccesful
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X
XFILE *
Xopenread (file)
Xchar   *file;
X{
X    extern char *myname;
X    FILE	*fp;
X
X    fp = fopen (file, "r");
X    if (fp == NULL) {
X	fprintf (stderr, "%s: can't open %s for reading\n", myname, file);
X	exit (1);
X    }
X    if (flock (fileno (fp), LOCK_EX | LOCK_NB)) {
X	fprintf (stderr, "%s: statfile %s is in use and locked\n",
X	    myname, file);
X	exit (1);
X    }
X    rewind(fp);
X    return (fp);
X}
SHAR_EOF
if test 512 -ne "`wc -c < 'openread.c'`"
then
 echo shar: error transmitting "'openread.c'" '(should have been 512 characters)'
fi
chmod +x 'openread.c'
fi # end of overwriting check
echo shar: extracting "'openwrite.c'" '(343 characters)'
if test -f 'openwrite.c'
then
 echo shar: will not over-write existing file "'openwrite.c'"
else
sed 's/^X//' << \SHAR_EOF > 'openwrite.c'
X/*
X * openwrite - open a file for write; bomb if unsuccesful
X */
X
X#include <stdio.h>
X#include <sys/file.h>
X
XFILE *
Xopenwrite (file)
Xchar   *file;
X{
X    extern char *myname;
X    FILE	*fd;
X
X    fd = fopen (file, "w+");
X    if (fd == NULL) {
X	fprintf (stderr, "%s: can't open %s for writing\n", myname, file);
X	exit (1);
X    }
X    return (fd);
X}
SHAR_EOF
if test 343 -ne "`wc -c < 'openwrite.c'`"
then
 echo shar: error transmitting "'openwrite.c'" '(should have been 343 characters)'
fi
chmod +x 'openwrite.c'
fi # end of overwriting check
echo shar: extracting "'poparg.c'" '(378 characters)'
if test -f 'poparg.c'
then
 echo shar: will not over-write existing file "'poparg.c'"
else
sed 's/^X//' << \SHAR_EOF > 'poparg.c'
X/*
X * poparg - pop next argument off argv list
X *	    returns pointer to arg; else NULL when no more
X *
X * Rex Sanders, USGS Pacific Marine Geology, 2/87
X */
X
X#include <stdio.h>
X
Xchar   *
Xpoparg (argc, argv)
Xint    *argc;
Xchar ***argv;
X
X{
X    char   *newarg;
X
X    if (*argc > 0) {
X	newarg = **argv;
X	(*argc)--;
X	(*argv)++;
X    }
X    else
X	newarg = NULL;
X
X    return (newarg);
X}
SHAR_EOF
if test 378 -ne "`wc -c < 'poparg.c'`"
then
 echo shar: error transmitting "'poparg.c'" '(should have been 378 characters)'
fi
chmod +x 'poparg.c'
fi # end of overwriting check
echo shar: extracting "'print2stat.c'" '(284 characters)'
if test -f 'print2stat.c'
then
 echo shar: will not over-write existing file "'print2stat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'print2stat.c'
X/*
X *  print2stat - compare and print 2 stat structures side-by-side
X */
X
Xchar   *ctime ();
Xchar   *strcpy ();
X
Xprint2stat (old, new)
Xstruct stat *old;
Xstruct stat *new;
X
X{
X    printf("OLD: ");
X    printstat("", old);
X    printf("NEW: ");
X    printstat("", new);
X    putchar('\n');
X}
SHAR_EOF
if test 284 -ne "`wc -c < 'print2stat.c'`"
then
 echo shar: error transmitting "'print2stat.c'" '(should have been 284 characters)'
fi
chmod +x 'print2stat.c'
fi # end of overwriting check
echo shar: extracting "'printstat.c'" '(784 characters)'
if test -f 'printstat.c'
then
 echo shar: will not over-write existing file "'printstat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'printstat.c'
X/*
X * printstat - print name and stat structure 
X * 	       output similar to 'ls -l'
X */
X
X#include "cfs.h"
X
Xprintstat(name, sbuf)
Xchar           *name;
Xstruct stat    *sbuf;
X{
X	register char  *cmode;
X	register char  *ctp;
X	char           *mkmode();
X	char           *ctime();
X
X
X
X	cmode = mkmode(sbuf -> st_mode);
X	printf("%6d %10s %2d %3d/%-3d ",
X	       sbuf -> st_ino, cmode, sbuf -> st_nlink, sbuf -> st_uid,
X	       sbuf -> st_gid);
X
X	if (*cmode == 'c' || *cmode == 'b')
X	       printf("%2d, %2d ", major(sbuf->st_rdev), minor(sbuf->st_rdev));
X	else
X	       printf("%6d ", sbuf->st_size);
X
X	ctp = ctime (&(sbuf -> st_mtime));
X	printf("%12.12s %4.4s ", ctp + 4, ctp + 20);
X
X	ctp = ctime (&(sbuf -> st_ctime));
X	printf("%12.12s %4.4s ", ctp + 4, ctp + 20);
X	printf("%s\n", name);
X}
SHAR_EOF
if test 784 -ne "`wc -c < 'printstat.c'`"
then
 echo shar: error transmitting "'printstat.c'" '(should have been 784 characters)'
fi
chmod +x 'printstat.c'
fi # end of overwriting check
echo shar: extracting "'readstat.c'" '(1112 characters)'
if test -f 'readstat.c'
then
 echo shar: will not over-write existing file "'readstat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'readstat.c'
X/*
X * readstat - reads pathname & stats from statfile on fp
X *	returns  0 if read OK; +1 if EOF; -1 if error
X */
X
X#include "cfs.h"
X
Xreadstat (fp, statfile, name, sbuf)
XFILE   *fp;
Xchar   *statfile;
Xchar   *name;
Xstruct stat *sbuf;
X{
X    extern char *myname;
X    int     nread;
X    int     retval = 0;
X    char    c;
X    int     nc = 0;
X    struct stat dummy;
X
X/*
X * read the null-terminated pathname
X */
X    while (((nread = fread (&c, 1, 1, fp)) == 1)
X	    && (c != '\0')
X	    && nc < MAXPATHLEN) {
X	name[nc++] = c;
X    }
X    name[nc] = '\0';
X    if (nread == 0) {
X	retval = 1;
X	if (nc != 0) {
X	    fprintf (stderr, "%s: error - truncated statfile %s\n",
X		    myname, statfile);
X	    retval = -1;
X	}
X    }
X    if ((nread > 0) && (c != '\0')) {
X	fprintf (stderr, "%s: error - bad pathname in statfile %s\n",
X		myname, statfile);
X	retval = -1;
X    }
X    if (retval == 0) {
X/*
X * read the fixed-size statbuf
X */
X	nread = fread (sbuf, sizeof (dummy), 1, fp);
X	if (nread != 1) {
X	    fprintf (stderr, "%s: error - truncated statfile %s\n",
X		    myname, statfile);
X	    retval = -1;
X	}
X    }
X    return (retval);
X}
SHAR_EOF
if test 1112 -ne "`wc -c < 'readstat.c'`"
then
 echo shar: error transmitting "'readstat.c'" '(should have been 1112 characters)'
fi
chmod +x 'readstat.c'
fi # end of overwriting check
echo shar: extracting "'statcheck.c'" '(979 characters)'
if test -f 'statcheck.c'
then
 echo shar: will not over-write existing file "'statcheck.c'"
else
sed 's/^X//' << \SHAR_EOF > 'statcheck.c'
X/*
X * statcheck - checks status of files in statfile
X */
X
X#include "cfs.h"
X
Xstatcheck (statfile, verbose)
Xchar   *statfile;
Xint     verbose;
X{
X    extern char *myname;
X    FILE   *fp;
X    int     errflg = 0;
X    int     rstat = 0;
X    char    name[MAXPATHLEN];
X    struct stat osbuf;
X    struct stat nsbuf;
X    FILE   *openread ();
X
X    fp = openread (statfile);
X/*
X *  for each entry in statfile, get stored status
X */
X    while (!(rstat = readstat (fp, statfile, name, &osbuf))) {
X/* 
X *	stat real file
X */
X	if (stat (name, &nsbuf)) {
X	    printf ("status check FAILED for %s\n", name);
X	    if (verbose)
X		printf ("%s: %s - %s\n\n", myname, name,
X			sys_errlist[errno]);
X	    errflg++;
X	}
X/*
X *	    compare old status with new status
X */
X	else
X	    if (statcomp (&osbuf, &nsbuf)) {
X		printf ("status check FAILED for %s\n", name);
X		if (verbose)
X		    print2stat (&osbuf, &nsbuf);
X		errflg++;
X	    }
X    }
X    if (rstat < 0)
X	errflg++;
X    fclose (fp);
X    return (errflg);
X}
SHAR_EOF
if test 979 -ne "`wc -c < 'statcheck.c'`"
then
 echo shar: error transmitting "'statcheck.c'" '(should have been 979 characters)'
fi
chmod +x 'statcheck.c'
fi # end of overwriting check
echo shar: extracting "'statcomp.c'" '(739 characters)'
if test -f 'statcomp.c'
then
 echo shar: will not over-write existing file "'statcomp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'statcomp.c'
X/*
X *  Compare two stat structures
X */
X
X#include "cfs.h"
X
Xstatcomp (old, new)
Xstruct stat *old;
Xstruct stat *new;
X{
X    int     errflg = 0;
X    register u_short mode;
X
X    errflg += (old -> st_ino	!= new -> st_ino);
X    errflg += (old -> st_mode	!= new -> st_mode);
X    errflg += (old -> st_nlink	!= new -> st_nlink);
X    errflg += (old -> st_uid	!= new -> st_uid);
X    errflg += (old -> st_gid	!= new -> st_gid);
X    errflg += (old -> st_ctime	!= new -> st_ctime);
X
X    mode = old -> st_mode & S_IFMT;
X    if (mode == S_IFCHR || mode == S_IFBLK) {
X	errflg += (old -> st_rdev	!= new -> st_rdev);
X    }
X    else {
X	errflg += (old -> st_size	!= new -> st_size);
X	errflg += (old -> st_mtime	!= new -> st_mtime);
X    }
X
X    return (errflg);
X}
SHAR_EOF
if test 739 -ne "`wc -c < 'statcomp.c'`"
then
 echo shar: error transmitting "'statcomp.c'" '(should have been 739 characters)'
fi
chmod +x 'statcomp.c'
fi # end of overwriting check
echo shar: extracting "'table.c'" '(1145 characters)'
if test -f 'table.c'
then
 echo shar: will not over-write existing file "'table.c'"
else
sed 's/^X//' << \SHAR_EOF > 'table.c'
X/*
X * table - print table of contents for statfile
X */
X#include "cfs.h"
X
Xchar   *calloc ();
X
Xtable (statfile, argc, argv, verbose)
Xchar   *statfile;
Xint     argc;
Xchar  **argv;
Xint     verbose;
X{
X    extern char *myname;
X    FILE   *fp;
X    char    name[MAXPATHLEN];
X    struct stat sbuf;
X    int     errflg = 0;
X    int     rstat;
X    int    *foundlist;
X    FILE   *openread ();
X
X    fp = openread (statfile);
X/* 
X *  if no arguments, table entire statfile
X */
X    if (argc == 0)
X	while (!(rstat = readstat (fp, statfile, name, &sbuf)))
X	    if (verbose)
X		printstat (name, &sbuf);
X	    else
X		printf ("%s\n", name);
X    else {
X/*
X *	get storage for foundlist
X */
X	if (!(foundlist = (int *) calloc
X		    ((unsigned) argc, sizeof (int)))) {
X	    fprintf (stderr, "%s: can't calloc %d ints\n",
X		    myname, argc);
X	    exit (1);
X	}
X/*
X *  for each entry in statfile
X */
X	while (!(rstat = readstat (fp, statfile, name, &sbuf))) {
X	    if (cavn (argc, argv, foundlist, name)) {
X		if (verbose)
X		    printstat (name, &sbuf);
X		else
X		    printf ("%s\n", name);
X	    }
X	}
X	if (rstat < 0)
X	    errflg++;
X    }
X    fclose (fp);
X    return (errflg);
X}
SHAR_EOF
if test 1145 -ne "`wc -c < 'table.c'`"
then
 echo shar: error transmitting "'table.c'" '(should have been 1145 characters)'
fi
chmod +x 'table.c'
fi # end of overwriting check
echo shar: extracting "'update.c'" '(2438 characters)'
if test -f 'update.c'
then
 echo shar: will not over-write existing file "'update.c'"
else
sed 's/^X//' << \SHAR_EOF > 'update.c'
X/*
X * update - update argv names in statfile for cfs
X */
X
X#include "cfs.h"
X
Xchar   *mktemp ();
Xchar   *calloc ();
X
Xupdate (statfile, argc, argv, verbose)
Xchar   *statfile;
Xint     argc;
Xchar  **argv;
Xint     verbose;
X{
X    extern char *myname;
X    FILE   *sfp;		/* statfile file pointer */
X    char   *tfname;		/* temporary statfile file name */
X    FILE   *tfp;		/* tempstat file pointer */
X    int     errflg = 0;		/* returned error flag */
X    int     rstat;		/* readline status flag */
X    char    name[MAXPATHLEN];	/* path name */
X    char   *arg;		/* argument for processing */
X    struct stat sbuf;		/* stat data */
X    int    *ufl;		/* updated filenames found list */
X    int    *tfl;		/* temporary filenames found list */
X    int     nargs;		/* temporary copy of argc */
X    char   *poparg ();
X    FILE   *openread ();
X    FILE   *openwrite ();
X
X    sfp = openread (statfile);
X    tfname = mktemp ("cfs.XXXXXX");
X    tfp = openwrite (tfname);
X/*
X *	get storage for ufl & tfl
X */
X    if (!(ufl = (int *) calloc ((unsigned) argc, sizeof (int)))) {
X	fprintf (stderr, "cfs: can't calloc %d ints\n", argc);
X	exit (1);
X    }
X    if (!(tfl = (int *) calloc ((unsigned) argc, sizeof (int)))) {
X	fprintf (stderr, "cfs: can't calloc %d ints\n", argc);
X	exit (1);
X    }
X/*
X *  for each entry in statfile
X */
X    while (!(rstat = readstat (sfp, statfile, name, &sbuf))) {
X	if (!cavn (argc, argv, tfl, name)) {
X/* 
X *	    no match - write entry to tempstat
X */
X	    writestat (tfp, name, &sbuf);
X	}
X	else {
X/*
X *	    match found - update tempstat
X */
X	    nargs = argc;
X	    while (nargs-- > 0) {
X		if (*tfl && !*ufl)
X		    if (!addname (tfp, name)) {
X			if (verbose)
X			    printf ("u %s\n", name);
X			*ufl = 1;
X		    }
X		    else
X			errflg++;
X		*tfl = 0;
X		tfl++;
X		ufl++;
X	    }
X	    tfl -= argc;
X	    ufl -= argc;
X	}
X    }
X
X    if (rstat > 0) {
X/*
X *    check each arg - add if not updated
X */
X	arg = poparg (&argc, &argv);
X	while (arg != NULL) {
X	    if (!*ufl) {
X		if (!addname (tfp, arg)) {
X		    if (verbose)
X			printf ("a %s\n", arg);
X		}
X		else
X		    errflg++;
X	    }
X	    arg = poparg (&argc, &argv);
X	    ufl++;
X	}
X	fclose (tfp);
X	fclose (sfp);
X	if (movefile (tfname, statfile)) {
X	    fprintf (stderr, "%s: %s not changed\n", myname, statfile);
X	    errflg++;
X	}
X    }
X    else {
X	fclose (tfp);
X	fclose (sfp);
X	unlink (tfname);
X	fprintf (stderr, "%s: %s not changed\n", myname, statfile);
X	errflg++;
X    }
X    return (errflg);
X}
SHAR_EOF
if test 2438 -ne "`wc -c < 'update.c'`"
then
 echo shar: error transmitting "'update.c'" '(should have been 2438 characters)'
fi
chmod +x 'update.c'
fi # end of overwriting check
echo shar: extracting "'writestat.c'" '(269 characters)'
if test -f 'writestat.c'
then
 echo shar: will not over-write existing file "'writestat.c'"
else
sed 's/^X//' << \SHAR_EOF > 'writestat.c'
X/*
X * writestat - write name and stats to statfile for cfs
X */
X
X#include "cfs.h"
X
Xwritestat (fp, name, sbuf)
XFILE   *fp;
Xchar   *name;
Xstruct stat *sbuf;
X{
X    struct stat dummy;
X
X    fwrite (name, strlen (name) + 1, 1, fp);
X    fwrite (sbuf, sizeof (dummy), 1, fp);
X}
SHAR_EOF
if test 269 -ne "`wc -c < 'writestat.c'`"
then
 echo shar: error transmitting "'writestat.c'" '(should have been 269 characters)'
fi
chmod +x 'writestat.c'
fi # end of overwriting check
#	End of shell archive
exit 0