loglook & logfix; admin pgms (source) for UNIXPC/3B1/PC7300

Thad P Floryan thad at cup.portal.com
Wed Feb 28 20:50:34 AEST 1990


Enclosed are two administrative programs for the UNIXPC/3B1/PC7300 you may
find useful.  If nothing else, the example usage of qsort(3C) is worthwhile
considering the number of questions I'm asked about its usage.

Thad Floryan  [ thad at cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]

#! /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:
#	README
#	Makefile
#	loglook.c
#	logfix.c
# This archive created: Wed Feb 28 01:42:02 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(2150 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XPresented for your amusement, edification, enjoyment, and/or horror are the
Xloglook and logfix programs.
X
X``loglook'' reads the UNIXPC's /etc/pwcntl file and displays its contents
Xordered by the most recent login date and time.
X
XBesides providing a useful administrative view of recent login activity,
Xloglook also serves to illustrate one use of the system's qsort(3C) routine.
XI receive many questions about qsort(3C)'s usage from people who grow weary
Xof doing "rm core" while developing their own programs!   :-)
X
XFor those wary of loglook reading the entire /etc/pwcntl file into memory
Xfor the sort, the following should allay your fears:
X
X	$ ls -l /etc/pwcntl
X	-rw-r--r--  1 bin     bin         182 Feb 27 23:58 /etc/pwcntl
X
XA typical display by loglook is:
X
XLogin ID          Last                   First            Name
X--------  ----------------------  ----------------------  --------------------
Xthad      Tue 27-Feb-90 23:58:56  Tue 24-Nov-87  1:01:11  Thad Floryan
Xinstall   Sun 18-Feb-90 17:10:32  Sat 20-Jul-85 13:40:55  Administration Login
Xutc       Mon 12-Feb-90 22:25:06  Sat 14-Oct-89 17:59:07  UTC time service
Xjim       Thu  1-Feb-90 21:31:31  Fri  1-Jul-88  1:14:10  Jim Sanchez
Xroot      Tue 12-Dec-89 12:56:17  Sat 28-Nov-87  1:12:40  Root
Xtutor     Tue  9-Feb-88  3:28:01  Tue 24-Nov-87  1:18:26  Tutorial
Xguest     Sun 29-Nov-87 20:11:58  Fri 27-Nov-87  6:34:52  Anonymous Login
X
X
XThe text appearing in the "Name" column is that from /etc/passwd.
X
XAs one's system endures remote dialins by modem, there will occasionally be
Xgarbage entries appearing for a "Login ID" such as "CONNECT", "i{", etc.
XSuch garbage entries are pruned using ``logfix'' (a quick hack) which simply
Xreads /etc/pwcntl and writes a new copy in the presently cd'd directory while
Xomitting records whose "Login ID" doesn't exist in /etc/passwd.  You must
Xmanually copy the new file over /etc/pwcntl to save the repairs.
X
X``loglook'' and ``logfix'' are based on Lenny Tropiano's discoveries as
Xembodied in his ``look_pwcntl'' program dated 13-Dec-1988.
X
XEnjoy!
X
XThad Floryan  [ thad at cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
X
X27-Feb-1990
SHAR_EOF
if test 2150 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 2150 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(1072 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Makefile for:
X#	loglook	(/etc/pwcntl dump program)
X#	logfix	(/etc/pwcntl repair program)
X#
X# No presumptions are made for installing these programs on your system.
X# Use the commented-out ``install :'' (below) as a suggestion only.
X#
X# And, yes, I know this Makefile is verbose.  I do this so every step is
X# shown (for the curious).
X#
X# Simply typing "make" will compile and load both programs.  "make clean"
X# prunes the *.o files and removes traces of your meddling with qsort! :-)
X#
X# Thad Floryan, Feb. 1990
X#
XCC=		cc
XCFLAGS=		-O
XLDFLAGS=	-s
XLIBS=		/lib/crt0s.o /lib/shlib.ifile
XDEST=		/usr/local/bin/
X
Xall :		loglook logfix
X
Xloglook :	loglook.o
X		$(LD) $(LDFLAGS) -o loglook loglook.o $(LIBS) 
X
Xloglook.o :	loglook.c
X		$(CC) $(CFLAGS) -c loglook.c
X
Xlogfix :	logfix.o
X		$(LD) $(LDFLAGS) -o logfix logfix.o $(LIBS) 
X
Xlogfix.o :	logfix.c
X		$(CC) $(CFLAGS) -c logfix.c
X
X#install :
X#		cp loglook logfix ${DEST}
X#		chown bin ${DEST}/loglook ${DEST}/logfix
X#		chgrp bin ${DEST}/loglook ${DEST}/logfix
X#		chmod 750 ${DEST}/loglook ${DEST}/logfix
X
Xclean :
X		rm -f *.o core
SHAR_EOF
if test 1072 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 1072 characters)
'
fi
fi
echo shar: "extracting 'loglook.c'" '(6834 characters)'
if test -f 'loglook.c'
then
	echo shar: "will not over-write existing file 'loglook.c'"
else
sed 's/^X//' << \SHAR_EOF > 'loglook.c'
X/* loglook
X *
X * Displays the UNIXPC's /etc/pwcntl file in a human-readable format.
X *
X * Revision history:
X *
X *	Version 2.0 by Thad Floryan, 19-Feb-1990
X *		- reverse sorts data by most recent last-login date
X *
X *	Version 1.0 by Thad Floryan, 15-Dec-1988
X *		- displays data in file-record creation order
X *
X * Credits:
X *
X *	based on look_pwcntl.c by Lenny Tropiano, ICUS Software Systems,
X *		13-Dec-88
X */
X
X#include <stdio.h>
X#include <sys/stat.h>
X#include <sys/types.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <time.h>
X
X/*
X *	Structure of the /etc/pwcntl file (3B1/UNIXPC/PC7300 systems only).
X */
Xstruct pwcntl {
X	char	login[8];	/* login name (matches name in /etc/passwd) */
X	int	uid;		/* login username's UID			    */
X	char	expert;		/* set non-zero for "expert" users	    */
X	char	pad;		/* filler				    */
X	time_t	laston;		/* time of this login; set by /bin/login    */
X	time_t	tcreat;		/* time of first login (record creation)    */
X	long	space;		/* filler				    */
X};
X
Xstatic char *version = "@(#) loglook 2.0 by Thad Floryan, 19-Feb-1990";
X
Xstatic char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
X
Xstatic char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
X
Xstatic char *heading1 =
X"Login ID          Last                   First            Name\n";
Xstatic char *heading2 =
X"--------  ----------------------  ----------------------  ----\
X----------------\n";
X
X/*****************************************************************************
X *
X *		L O G L O O K
X */
Xmain()
X{
Xextern	int		close();
X	int		cmpdate();	/* sequencer for qsort() */
X	void		dpydat();	/* displays date & time  */
Xextern	void		endpwent();
Xextern	void		exit();
Xextern	void		fprintf();
Xextern	void		free();
Xextern	int		fstat();
Xextern	struct passwd  *getpwnam();
Xextern	struct tm      *localtime();
Xextern	char	       *malloc();
Xextern	int		open();
Xextern	void		perror();
Xextern	void		qsort();
Xextern	int		read();
X
X	int		fd;	 /* file descriptor for /etc/pwcntl	*/
X	struct stat	finfo;	 /* file statistics for /etc/pwcntl	*/
X	int		i;	 /* general loop counter		*/
X	int		numrecs; /* /etc/pwcntl record count		*/
X	struct passwd  *psw;	 /* pointer to /etc/passwd data		*/
X	struct pwcntl  *recbase; /* memory pointer to /etc/pwcntl	*/
X	struct pwcntl  *recptr;	 /* working /etc/pwcntl record pointer	*/
X	long		timval;	 /* time buffer for localtime()		*/
X
X
X/*
X *	Open database file, abort if any error(s).
X */
X	if ((fd = open("/etc/pwcntl", O_RDONLY)) < 0) {
X		perror("open()");
X		exit(1);
X	}
X/*
X *	Start heading display now so that (hopefully) the data starts
X *	displaying by the time the heading display is completed.
X */
X	fprintf(stdout, heading1);
X	fprintf(stdout, heading2);
X/*
X *	Get the file statistics; all we care about is the file's size.
X */
X	if (fstat(fd, &finfo) != 0) {
X		perror("fstat()");
X		exit(1);
X	}
X/*
X *	Test the file's size and abort if it's not an integral multiple of
X *	the record size.
X */
X	if ((finfo.st_size % sizeof(struct pwcntl)) != 0 ) {
X		fprintf(stderr, "pwcntl file size error\n");
X		exit(1);
X	}
X/*
X *	Compute the number of records in the file.  This count will be used
X *	for the sort and for the display functions.
X */
X	numrecs = finfo.st_size / sizeof(struct pwcntl);
X/*
X *	Allocate a memory buffer for the entire database file since we're going
X *	to read the entire file into the buffer for use by the sort.  Abort if
X *	memory cannot be allocated.
X */
X	if ((recbase = (struct pwcntl *) malloc(finfo.st_size)) == NULL) {
X		perror("malloc()");
X		exit(1);
X	}
X/*
X *	Read the database into the buffer, abort if any error(s), then close
X *	the file.
X */
X	if (read(fd, recbase, finfo.st_size) != finfo.st_size) {
X		fprintf(stderr, "pwcntl read error\n");
X		exit(1);
X	}
X	close(fd);
X/*
X *	Sort the database records.  The cmpdate() routine is called with two
X *	arguments by qsort() per "ptr to record 1" and "ptr to record 2",
X *	compares the last login dates of each record, and returns:
X *
X *		<0 if record 1's date is newer than record 2's date
X *		=0 if record 1's date is the same as record 2's date
X *		>0 if record 1's date is older than record 2's date
X */
X	qsort(recbase, numrecs, sizeof(struct pwcntl), cmpdate);
X/*
X *	Form a working pointer to the database records; recbase is needed
X *	later for the free().
X */
X	recptr = recbase;
X/*
X *	Process each database record.
X */
X	for (; numrecs > 0; numrecs--) {
X/*
X *	Edit-out "garbage" characters in the name to avoid display problems;
X *	the "garbage" characters are replaced by "." to indicate "something".
X */
X		for (i = 0; i < 8; i++)
X		{
X			if ((recptr->login[i] > 0 && recptr->login[i] < ' ') ||
X			     recptr->login[i] > 126)
X				recptr->login[i] = '.';
X		}
X/*
X *	Display the "Login ID"
X */
X		fprintf(stdout, "%-8.8s", recptr->login);
X/*
X *	Get and display the last login date & time
X */
X		timval = recptr->laston;
X		dpydat(localtime(&timval));
X/*
X *	Check if the first login date & time is the same as the last login
X *	date & time; if so, display "------" else display the date & time.
X */
X		if (recptr->tcreat == recptr->laston)
X			fprintf(stdout, "  ----------------------");
X		else {
X			timval = recptr->tcreat;
X			dpydat(localtime(&timval));
X		}
X/*
X *	Lookup the "Login ID" in the /etc/passwd file.
X *	Display "???" if no passwd entry, else display the full name.
X */
X		psw = (struct passwd *)getpwnam(recptr->login);
X		if (psw == (struct passwd *)NULL) 
X			fprintf(stdout, "  ???\n");
X		else
X			fprintf(stdout, "  %s\n", psw->pw_gecos);
X/*
X *	Advance record pointer to next entry and continue the loop.
X */
X		recptr++;
X	}
X/*
X *	Release resources we've used:
X *		close /etc/passwd file
X *		release allocated memory
X */
X	endpwent();
X	free(recbase);
X/*
X *	Exit back to system.
X */
X	exit(0);
X}
X
X/*****************************************************************************
X *	Forces a reverse-order record sort on last-login date & time.
X *
X *	This routine is called by qsort().  For the purposes of this program,
X *	the date comparison is optimally performed by a simple subtraction of
X *	the two date values resulting in the return value:
X *
X *		<0 if arg1's date is newer than arg2's date
X *		=0 if arg1's date is the same as arg2's date
X *		>0 if arg1's date is older than arg2's date
X */
Xint cmpdate(arg1, arg2)
X	struct pwcntl *arg1;
X	struct pwcntl *arg2;
X{
X	return(arg2->laston - arg1->laston);
X}
X
X/*****************************************************************************
X *	Displays the login date & time in a form conducive to displaying two
X *	dates and other information on a single line < 80 characters long.
X *
X */
Xvoid dpydat(timptr)
X	struct tm *timptr;
X{
X	fprintf(stdout, "  %s %2d-%s-%02d %2d:%02d:%02d",
X		weekday[timptr->tm_wday],
X		timptr->tm_mday,
X		month[timptr->tm_mon],
X		timptr->tm_year,
X		timptr->tm_hour,
X		timptr->tm_min,
X		timptr->tm_sec);
X}
X
SHAR_EOF
if test 6834 -ne "`wc -c < 'loglook.c'`"
then
	echo shar: "error transmitting 'loglook.c'" '(should have been 6834 characters
)'
fi
fi
echo shar: "extracting 'logfix.c'" '(2320 characters)'
if test -f 'logfix.c'
then
	echo shar: "will not over-write existing file 'logfix.c'"
else
sed 's/^X//' << \SHAR_EOF > 'logfix.c'
X/* logfix
X *
X * fixes the /etc/pwcntl file removing junk entries by not copying them to
X * a new copy of the file named pwcntl in the current directory.
X *
X * by Thad Floryan, 5-Oct-1989
X *
X * based on look_pwcntl.c by Lenny Tropiano, ICUS Software Systems, 13-Dec-88
X * based on loglook.c by Thad Floryan, 15-Dec-88
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <time.h>
X
Xstatic char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
Xstatic char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
X
Xmain()
X{
X	int fd;
X	int ofd;
X	int i;
X	struct tm *lfirst;
X	struct tm *llast;
X	struct pwcntl {
X	    char   login[8];
X	    int    uid;
X	    char   expert;
X	    char   pad;
X	    time_t laston;
X	    time_t tcreat;
X	    long   space;	
X	} pwrec;
X
X	if ((fd = open("/etc/pwcntl", O_RDONLY)) < 0) {
X		perror("open() /etc/pwcntl");
X		exit(1);
X	}
X	if ((ofd = creat("./pwcntl", 0666)) < 0) {
X		perror("open() ./pwcntl");
X		exit(1);
X	}
X
X	printf("Login ID         First                    Last            Action\n");
X	printf("--------  ----------------------  ----------------------  -----------
---------\n");
X	while (read(fd, &pwrec, sizeof(pwrec)) == sizeof(pwrec)) {
X
X	        for (i = 0; i < 8; i++)
X		{
X		    if ((pwrec.login[i] > 0 && pwrec.login[i] < ' ') ||
X			 pwrec.login[i] > 126)
X			pwrec.login[i] = '.';
X		}
X
X		printf("%-8.8s", pwrec.login);
X
X		lfirst = localtime(&pwrec.tcreat);
X
X		printf("  %s %2d-%s-%02d %2d:%02d:%02d",
X		       weekday[lfirst->tm_wday],
X		       lfirst->tm_mday,
X		       month[lfirst->tm_mon],
X		       lfirst->tm_year,
X		       lfirst->tm_hour,
X		       lfirst->tm_min,
X		       lfirst->tm_sec);
X
X		if (pwrec.tcreat == pwrec.laston)
X		    printf("  ----------------------");
X		else {
X		    llast = localtime(&pwrec.laston);
X
X		    printf("  %s %2d-%s-%02d %2d:%02d:%02d",
X		       weekday[llast->tm_wday],
X		       llast->tm_mday,
X		       month[llast->tm_mon],
X		       llast->tm_year,
X		       llast->tm_hour,
X		       llast->tm_min,
X		       llast->tm_sec);
X		  }
X
X		if ((struct passwd *)getpwnam(pwrec.login) ==
X		    (struct passwd *)NULL) {
X			printf("  Not copied\n");
X		}
X		else {
X			printf("  Copied\n");
X			write(ofd, &pwrec, sizeof(pwrec));
X		}
X	}
X	close(fd);
X	close(ofd);
X}
SHAR_EOF
if test 2320 -ne "`wc -c < 'logfix.c'`"
then
	echo shar: "error transmitting 'logfix.c'" '(should have been 2320 characters)
'
fi
fi
exit 0
#	End of shell archive



More information about the Comp.sys.att mailing list