v05i078: last2 take 2: bugs fixed
Chris Kern
ckern at killer.dallas.tx.us
Sat Dec 10 12:14:51 AEST 1988
Posting-number: Volume 5, Issue 78
Submitted-by: "Chris Kern" <ckern at killer.dallas.tx.us>
Archive-name: last2.2.s5
Brandon --
My idiosyncratic implementation of a BSD last(1)-style program
for System V had one idiosyncrasy I didn't intend: when invoked
with a user name, it failed to match logins that were longer than
eight characters. That is the size of the ut_user field in
/etc/wtmp. However, it is possible to create a login name that
has more than eight characters. (Always test for obvious
violations of boundary conditions. Sigh.)
Because the program is short, I am providing a fixed version
rather than posting context diffs for the original version,
which you distributed as v05i062.
Thanks to Doug Wells (dmw at cloud9.UUCP) for pointing this out.
Comments or reports of other bugs should be directed to my
account ckern at killer.Dallas.TX.US.
Chris
#!/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 Thu Dec 8 11:44:39 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 */
XX#define LINE_FIELD_LEN 12 /* magic numbers courtesy of /usr/include/utmp.h */
XX#define USER_FIELD_LEN 8
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 (strncmp(p->rec.ut_user, argv[i], USER_FIELD_LEN) == 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[LINE_FIELD_LEN + 1], user[USER_FIELD_LEN + 1];
XX struct tm *time;
XX extern struct tm *localtime();
XX strncpy(line, wtmp.ut_line, LINE_FIELD_LEN);
XX strncpy(user, wtmp.ut_user, USER_FIELD_LEN);
XX line[LINE_FIELD_LEN] = user[USER_FIELD_LEN] = '\0';
XX time = localtime(&wtmp.ut_time);
XX switch (wtmp.ut_type) {
XX case USER_PROCESS:
XX printf("%-*s %-*s %s %s %2d %02d:%02d", USER_FIELD_LEN, user, LINE_FIELD_LEN, line,
XX 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 <<\!!!
137 427 3126 last.c
30 88 522 last.1
167 515 3648 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
More information about the Comp.sources.misc
mailing list