[comp.sources.misc] v05i062: another "last" -- this one is PD

ckern@killer.Dallas.TX.US (Chris Kern) (11/27/88)

Posting-number: Volume 5, Issue 62
Submitted-by: "Chris Kern" <ckern@killer.Dallas.TX.US>
Archive-name: pd-last

I don't like to complain about any source offering, and certainly
the copyright holder of any code has a right to impose
limitations on its use, but I thought Harvey Moran's restrictions
on his Berkeley `last' look-alike were excessively severe.  Taken
at face value, they would prevent an administrator of several
systems from installing an executable on each system and
archiving the source on only one machine.  ("The source code in
machine readable format [must be] included with any binary
distribution.")

Anyway, at the risk initiating "source wars" (hmmm, better
perhaps than "flame wars"), I'm enclosing a version of last.c
that I wrote a couple of years ago for our System V machines.  Its
output is slightly different from Harvey's, and it is even less
Berkeley compatible (although, if someone insists on "still
logged in" as an alternative to not showing the logout time, the
change would be easy to make), but it is not encumbered with
restrictions of any kind.  I have placed the code in the public
domain.

Any replies should be directed to my account ckern@killer, since
voa3 is not currently on the net.

Cheers,

Chris Kern


#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by ck on Sun Nov 20 14:54:34 EST 1988
# Contents:  last.c last.1
 
echo x - last.c
sed 's/^XX//' > "last.c" <<'@//E*O*F last.c//'
XX#include <stdio.h>
XX#include <sys/types.h>
XX#include <string.h>
XX#include <time.h>
XX#include <utmp.h>


XX#define	 OWTMP_FILE		"/usr/adm/acct/nite/owtmp"		/* file to search after /etc/wtmp */

XXstatic char *prog;
XXstatic char *wtmpfile[] = { OWTMP_FILE, WTMP_FILE, NULL };

XXstruct list {
XX		struct utmp rec;
XX		struct list *next;
XX		struct list *previous;
XX};



XXmain(argc, argv)			/* last: show recent logins in last-to-first order */
XXint argc;
XXchar *argv[];
XX{
XX	int    i;
XX	void   prproc();
XX	struct list *listp = NULL, *p, *addlist();
XX	struct utmp *entry;
XX	extern void utmpname();
XX	extern struct utmp *getutent();

XX	prog = argv[0];

XX	for (i = 0; wtmpfile[i] != NULL; i++) {
XX		utmpname(wtmpfile[i]);
XX		while ((entry = getutent()) != NULL)
XX			listp = addlist(listp, entry);
XX	}

XX	/* listp points to most recent wtmp entry */

XX	for (p = listp; p != NULL; p = p->previous)
XX		if (p->rec.ut_type == USER_PROCESS) {
XX			if (argc == 1)
XX				prproc(p, listp);
XX			else
XX				for (i = 1; i < argc; i++) {
XX					if (strcmp(p->rec.ut_user, argv[i]) == 0) {
XX						prproc(p, listp);
XX						break;
XX					}
XX				}
XX		}

XX	return (0);
XX}



XXstruct list *addlist(head, wtmp)	/* add new wtmp entry to head of list */
XXstruct list *head;
XXstruct utmp *wtmp;
XX{
XX	void	 errexit();
XX	register struct list *new;
XX	extern	 char *malloc();

XX	if ((new = (struct list *) malloc(sizeof(struct list))) == NULL)
XX		errexit("memory error", NULL);
XX	else {
XX		new->rec = *wtmp;
XX		new->next = new;		/* no next yet */
XX		new->previous = head;
XX		if (head != NULL)
XX			head->next = new;
XX	}
XX	return (new);
XX}



XXvoid prproc(start, last)		/* print entries for process */
XXstruct list *start, *last;
XX{
XX	void	 prentry();
XX	register struct list *p;

XX	prentry(start->rec);
XX	for (p = start->next; p != last; p = p->next)
XX		if (p->rec.ut_pid == start->rec.ut_pid)
XX			prentry(p->rec);
XX	putchar('\n');
XX}


XX	
XXvoid prentry(wtmp)			/* print wtmp entry */
XXstruct utmp wtmp;
XX{
XX	static char *wkday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
XX	static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

XX	char   line[12 + 1], user[8 + 1];			/* magic numbers courtesy of /usr/include/utmp.h */
XX	struct tm *time;
XX	extern struct tm *localtime();

XX	strncpy(line, wtmp.ut_line, 12);
XX	strncpy(user, wtmp.ut_user, 8);
XX	line[12] = user[8] = '\0';
XX	time = localtime(&wtmp.ut_time);
XX	switch (wtmp.ut_type) {
XX	case USER_PROCESS:
XX		printf("%-8s %-12s %s %s %2d %02d:%02d",
XX			user, line, wkday[time->tm_wday], month[time->tm_mon], time->tm_mday, time->tm_hour, time->tm_min);
XX		break;
XX	case DEAD_PROCESS:
XX		printf("  -  %02d:%02d %s", time->tm_hour, time->tm_min, wkday[time->tm_wday]);
XX		break;
XX	default:
XX		sprintf(line, "%d", wtmp.ut_type);
XX		errexit("illegal wtmp.ut_type entry:", line);
XX	}
XX}



XXvoid errexit(s1, s2)			/* print error message and die */
XXchar s1[], s2[];
XX{
XX	extern void exit();

XX	fprintf(stderr, s2 == NULL ? "%s: %s\n" : "%s: %s %s\n", prog, s1, s2);
XX	exit(-1);
XX}
@//E*O*F last.c//
chmod u=rw,g=r,o=r last.c
 
echo x - last.1
sed 's/^XX//' > "last.1" <<'@//E*O*F last.1//'
XX.TH LAST 1 VOA
XX.SH NAME
XXlast  \-  show recent logins in last-to-first order
XX.SH SYNOPSIS
XX.B last
XX[
XXuser ...
XX]
XX.SH DESCRIPTION
XX.I Last
XXdisplays recent login and logout times
XXin last-to-first order.
XXIf invoked with
XX.IR user s,
XXoutput is restricted
XXto the login and logout times
XXof the specified account(s).
XX.SH FILES
XX.TP 30
XX/etc/wtmp
XXcurrent accounting file
XX.TP 30
XX/usr/adm/acct/nite/owtmp
XXprevious day's accounting file
XX.SH BUGS
XXCertain types of system errors
XXwill result in
XX.I last
XXfailing to report
XXa user's logout time.
@//E*O*F last.1//
chmod u=rw,g=r,o=r last.1
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
    134    418   2944 last.c
     30     88    522 last.1
    164    506   3466 total
!!!
wc  last.c last.1 | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0