well, I started looking at this to add a flag to allow the use of a
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 10 Dec 1986 14:14:52 +0000 (06:14 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 10 Dec 1986 14:14:52 +0000 (06:14 -0800)
file other than /usr/adm/wtmp.  The code was pretty bad.  Don't diff
this version against any of the previous ones.

SCCS-vsn: usr.bin/last/last.c 5.4

usr/src/usr.bin/last/last.c

index c656727..bd778db 100644 (file)
@@ -11,204 +11,226 @@ char copyright[] =
 #endif not lint
 
 #ifndef lint
 #endif not lint
 
 #ifndef lint
-static char sccsid[] = "@(#)last.c     5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)last.c     5.4 (Berkeley) %G%";
 #endif not lint
 
 /*
  * last
  */
 #include <sys/types.h>
 #endif not lint
 
 /*
  * last
  */
 #include <sys/types.h>
-#include <stdio.h>
-#include <signal.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <time.h>
+#include <pwd.h>
 #include <utmp.h>
 #include <utmp.h>
+#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
 
 
-#define NMAX   sizeof(buf[0].ut_name)
-#define LMAX   sizeof(buf[0].ut_line)
-#define        HMAX    sizeof(buf[0].ut_host)
-#define        SECDAY  (24*60*60)
-
-#define        lineq(a,b)      (!strncmp(a,b,LMAX))
-#define        nameq(a,b)      (!strncmp(a,b,NMAX))
-#define        hosteq(a,b)     (!strncmp(a,b,HMAX))
+#define MAXTTYS        200                             /* max ttys last can handle */
+#define SECDAY (24*60*60)                      /* seconds in a day */
+#define NO     0                               /* false/no */
+#define YES    1                               /* true/yes */
 
 
-#define MAXTTYS 256
+static struct utmp     buf[500];               /* utmp read buffer */
+#define HMAX   sizeof(buf[0].ut_host)          /* size of utmp host field */
+#define LMAX   sizeof(buf[0].ut_line)          /* size of utmp tty field */
+#define NMAX   sizeof(buf[0].ut_name)          /* size of utmp name field */
 
 
-char   **argv;
-int    argc;
-int    nameargs;
+#define lineq(a,b)     (!strncmp(a,b,LMAX))
+#define nameq(a,b)     (!strncmp(a,b,NMAX))
+#define hosteq(a,b)    (!strncmp(a,b,HMAX))
 
 
-struct utmp buf[128];
-char   ttnames[MAXTTYS][LMAX+1];
-long   logouts[MAXTTYS];
+typedef struct ttytab {
+       long    logout;                         /* log out time */
+       char    tty[LMAX + 1];                  /* terminal name */
+} TTYS;
 
 
-char   *ctime(), *strspl();
-int    onintr();
+static TTYS    tab[MAXTTYS + 1];               /* tty table */
+static char    **sargs;                        /* start of selections args */
 
 
-main(ac, av)
-       char **av;
+main(argc,argv)
+int    argc;
+char   **argv;
 {
 {
-       register int i, k;
-       int bl, wtmp;
-       char *ct;
-       register struct utmp *bp;
-       long otime;
-       struct stat stb;
-       int print;
-       char * crmsg = (char *)0;
-       long crtime;
-       long outrec = 0;
-       long maxrec = 0x7fffffffL;
-       time(&buf[0].ut_time);
-       ac--, av++;
-       nameargs = argc = ac;
-       argv = av;
-       for (i = 0; i < argc; i++) {
-               if (argv[i][0] == '-' &&
-                   argv[i][1] >= '0' && argv[i][1] <= '9') {
-                       maxrec = atoi(argv[i]+1);
-                       nameargs--;
+       register struct utmp    *bp;            /* current structure */
+       register TTYS   *T;                     /* table entry */
+       register long   maxrec = -1;            /* records to display */
+       register int    indx;                   /* array offsets */
+       struct stat     stb;                    /* stat of file for size */
+       long    delta,                          /* time difference */
+               atol(), lseek(), time();
+       int     bl,                             /* reads to do */
+               bytes,                          /* bytes read */
+               wtmp,                           /* wtmp file descriptor */
+               onintr();
+       char    *ct,                            /* ctime return */
+               *crmsg,                         /* crash message */
+               *file,                          /* user specified file */
+               *asctime(), *ctime(), *strspl();
+
+       file = "/usr/adm/wtmp";
+       for (--argc,sargs = argv = ++argv,indx = 0;indx < argc;++indx) {
+               if (argv[indx][0] == '-' && isdigit(argv[indx][1])) {
+                       if ((maxrec = atol(argv[indx] + 1)) <= 0) {
+                               fputs("last: bad line count value.\n",stderr);
+                               exit(1);
+                       }
+                       ++sargs;
                        continue;
                }
                        continue;
                }
-               if (strlen(argv[i])>2)
-                       continue;
-               if (!strcmp(argv[i], "~"))
+               if (!strncmp(argv[indx],"-f",2)) {
+                       if (argv[indx][2]) {
+                               file = argv[indx] + 2;
+                               ++sargs;
+                       }
+                       else if (++indx == argc) {
+                               fputs("last: option requires an argument -- f\n",stderr);
+                               exit(1);
+                       }
+                       else {
+                               file = argv[indx];
+                               sargs += 2;
+                       }
                        continue;
                        continue;
-               if (!strcmp(argv[i], "ftp"))
+               }
+               if (strlen(argv[indx]) > 2)
                        continue;
                        continue;
-               if (!strcmp(argv[i], "uucp"))
+               if (!strcmp(argv[indx],"~"))
                        continue;
                        continue;
-               if (getpwnam(argv[i]))
+               if (getpwnam(argv[indx]))
                        continue;
                        continue;
-               argv[i] = strspl("tty", argv[i]);
+               argv[indx] = strspl(argv[indx]);
        }
        }
-       wtmp = open("/usr/adm/wtmp", 0);
-       if (wtmp < 0) {
-               perror("/usr/adm/wtmp");
+
+       if ((wtmp = open(file,O_RDONLY,0)) < 0 || fstat(wtmp,&stb) == -1) {
+               perror(file);
                exit(1);
        }
                exit(1);
        }
-       fstat(wtmp, &stb);
-       bl = (stb.st_size + sizeof (buf)-1) / sizeof (buf);
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
-               signal(SIGINT, onintr);
-               signal(SIGQUIT, onintr);
-       }
-       for (bl--; bl >= 0; bl--) {
-               lseek(wtmp, bl * sizeof (buf), 0);
-               bp = &buf[read(wtmp, buf, sizeof (buf)) / sizeof(buf[0]) - 1];
-               for ( ; bp >= buf; bp--) {
-                       print = want(bp);
-                       if (print) {
-                               ct = ctime(&bp->ut_time);
-                               printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s ",
-                                   NMAX, NMAX, bp->ut_name,
-                                   LMAX, LMAX, bp->ut_line,
-                                   HMAX, HMAX, bp->ut_host,
-                                   ct, 11+ct);
+       bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
+
+       time(&buf[0].ut_time);
+       signal(SIGINT,onintr);
+       signal(SIGQUIT,onintr);
+
+       tab[MAXTTYS].logout = -1;               /* end flag value */
+       while (--bl >= 0) {
+               if (lseek(wtmp,(long)(bl * sizeof(buf)),L_SET) == -1 || (bytes = read(wtmp,(char *)buf,sizeof(buf))) == -1) {
+                       perror(file);
+                       exit(1);
+               }
+               for (bp = &buf[bytes / sizeof(buf[0]) - 1];bp >= buf;--bp) {
+                       if (lineq(bp->ut_line,"~")) {
+                               /*
+                                * if the name is empty and the terminal
+                                * line is '~', it's a shutdown of some
+                                * sort; see utmp(5) for more info.
+                                */
+                               for (T = tab;T->logout != -1;++T)
+                                       T->logout = -bp->ut_time;
+                               crmsg = nameq(bp->ut_name,"shutdown") ? "down " : "crash";
+                               if (!bp->ut_name[0])
+                                       strcpy(bp->ut_name,"reboot");
+                               if (want(bp,NO)) {
+                                       ct = ctime(&bp->ut_time);
+                                       printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s \n",NMAX,NMAX,bp->ut_name,LMAX,LMAX,bp->ut_line,HMAX,HMAX,bp->ut_host,ct,ct + 11);
+                                       if (maxrec != -1 && !--maxrec)
+                                               exit(0);
+                               }
+                               continue;
                        }
                        }
-                       for (i = 0; i < MAXTTYS; i++) {
-                               if (ttnames[i][0] == 0) {
-                                       strncpy(ttnames[i], bp->ut_line,
-                                           sizeof(bp->ut_line));
-                                       otime = logouts[i];
-                                       logouts[i] = bp->ut_time;
+                       for (T = tab;;) {
+                               if (T->logout <= 0) {
+                                       bcopy(bp->ut_line,T->tty,LMAX);
                                        break;
                                }
                                        break;
                                }
-                               if (lineq(ttnames[i], bp->ut_line)) {
-                                       otime = logouts[i];
-                                       logouts[i] = bp->ut_time;
+                               if (lineq(T->tty,bp->ut_line))
                                        break;
                                        break;
+                               if ((++T)->logout == -1) {
+                                       fputs("last: too many terminals.\n",stderr);
+                                       exit(1);
                                }
                        }
                                }
                        }
-                       if (print) {
-                               if (lineq(bp->ut_line, "~"))
-                                       printf("\n");
-                               else if (otime == 0)
-                                       printf("  still logged in\n");
+                       if (bp->ut_name[0] && want(bp,YES)) {
+                               ct = ctime(&bp->ut_time);
+                               printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s ",NMAX,NMAX,bp->ut_name,LMAX,LMAX,bp->ut_line,HMAX,HMAX,bp->ut_host,ct,ct + 11);
+                               if (!T->logout)
+                                       puts("  still logged in");
                                else {
                                else {
-                                       long delta;
-                                       if (otime < 0) {
-                                               otime = -otime;
-                                               printf("- %s", crmsg);
-                                       } else
-                                               printf("- %5.5s",
-                                                   ctime(&otime)+11);
-                                       delta = otime - bp->ut_time;
+                                       if (T->logout < 0) {
+                                               T->logout = -T->logout;
+                                               printf("- %s",crmsg);
+                                       }
+                                       else
+                                               printf("- %5.5s",ctime(&T->logout)+11);
+                                       delta = T->logout - bp->ut_time;
                                        if (delta < SECDAY)
                                        if (delta < SECDAY)
-                                           printf("  (%5.5s)\n",
-                                               asctime(gmtime(&delta))+11);
+                                               printf("  (%5.5s)\n",asctime(gmtime(&delta))+11);
                                        else
                                        else
-                                           printf(" (%ld+%5.5s)\n",
-                                               delta / SECDAY,
-                                               asctime(gmtime(&delta))+11);
+                                               printf(" (%ld+%5.5s)\n",delta / SECDAY,asctime(gmtime(&delta))+11);
                                }
                                }
-                               fflush(stdout);
-                               if (++outrec >= maxrec)
+                               if (maxrec != -1 && !--maxrec)
                                        exit(0);
                        }
                                        exit(0);
                        }
-                       if (lineq(bp->ut_line, "~")) {
-                               for (i = 0; i < MAXTTYS; i++)
-                                       logouts[i] = -bp->ut_time;
-                               if (nameq(bp->ut_name, "shutdown"))
-                                       crmsg = "down ";
-                               else
-                                       crmsg = "crash";
-                       }
+                       T->logout = bp->ut_time;
                }
        }
        ct = ctime(&buf[0].ut_time);
                }
        }
        ct = ctime(&buf[0].ut_time);
-       printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
+       printf("\nwtmp begins %10.10s %5.5s \n",ct,ct + 11);
        exit(0);
 }
 
 onintr(signo)
        exit(0);
 }
 
 onintr(signo)
-       int signo;
+int    signo;
 {
 {
-       char *ct;
+       char    *ct,
+               *ctime();
 
 
-       if (signo == SIGQUIT)
-               signal(SIGQUIT, onintr);
        ct = ctime(&buf[0].ut_time);
        ct = ctime(&buf[0].ut_time);
-       printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
-       fflush(stdout);
+       printf("\ninterrupted %10.10s %5.5s \n",ct,ct + 11);
+       fflush(stdout);                 /* fix required for rsh */
        if (signo == SIGINT)
                exit(1);
 }
 
        if (signo == SIGINT)
                exit(1);
 }
 
-want(bp)
-       struct utmp *bp;
+want(bp,check)
+register struct utmp   *bp;
+int    check;
 {
 {
-       register char **av;
-       register int ac;
-
-       if (bp->ut_line[0] == '~' && bp->ut_name[0] == '\0')
-               strcpy(bp->ut_name, "reboot");          /* bandaid */
-       if (strncmp(bp->ut_line, "ftp", 3) == 0)
-               bp->ut_line[3] = '\0';
-       if (strncmp(bp->ut_line, "uucp", 4) == 0)
-               bp->ut_line[4] = '\0';
-       if (bp->ut_name[0] == 0)
-               return (0);
-       if (nameargs == 0)
-               return (1);
-       av = argv;
-       for (ac = 0; ac < argc; ac++, av++) {
-               if (av[0][0] == '-')
-                       continue;
-               if (nameq(*av, bp->ut_name) || lineq(*av, bp->ut_line))
-                       return (1);
+       register char   **indx;
+
+       if (check) {
+               /*
+                * when uucp and ftp log in over a network, the entry in the
+                * utmp file is the name plus their process id.  See etc/ftpd.c
+                * and usr.bin/uucp/uucpd.c for more information.
+                */
+               if (!strncmp(bp->ut_line,"ftp",3))
+                       bp->ut_line[3] = '\0';
+               else if (!strncmp(bp->ut_line,"uucp",4))
+                       bp->ut_line[4] = '\0';
        }
        }
-       return (0);
+       if (!*sargs)
+               return(YES);
+       for (indx = sargs;*indx;++indx)
+               if (nameq(*indx,bp->ut_name) || lineq(*indx,bp->ut_line))
+                       return(YES);
+       return(NO);
 }
 
 char *
 }
 
 char *
-strspl(left, right)
-       char *left, *right;
+strspl(str)
+char   *str;
 {
 {
-       char *res = (char *)malloc(strlen(left)+strlen(right)+1);
+       register char   *res;
+       char    *malloc();
 
 
-       strcpy(res, left);
-       strcat(res, right);
-       return (res);
+       if (!(res = malloc((u_int)(4 + strlen(str))))) {
+               fputs("last: malloc failure.\n",stderr);
+               exit(1);
+       }
+       strcpy(res,"tty");
+       strcpy(res + 3,str);
+       return(res);
 }
 }