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 Unix-pc.sources
mailing list