386BSD 0.1 development
[unix-history] / usr / src / usr.bin / last / last.c
index ca35185..99a4652 100644 (file)
@@ -1,18 +1,45 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+"@(#) Copyright (c) 1987 Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)last.c     5.7 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)last.c     5.18 (Berkeley) 3/1/91";
+#endif /* not lint */
 
 /*
  * last
 
 /*
  * last
@@ -24,18 +51,14 @@ static char sccsid[] = "@(#)last.c  5.7 (Berkeley) %G%";
 #include <time.h>
 #include <utmp.h>
 #include <stdio.h>
 #include <time.h>
 #include <utmp.h>
 #include <stdio.h>
+#include <paths.h>
 
 
-#define        MAXTTYS 500                             /* max ttys last can handle */
 #define        SECDAY  (24*60*60)                      /* seconds in a day */
 #define        NO      0                               /* false/no */
 #define        YES     1                               /* true/yes */
 
 static struct utmp     buf[1024];              /* utmp read buffer */
 
 #define        SECDAY  (24*60*60)                      /* seconds in a day */
 #define        NO      0                               /* false/no */
 #define        YES     1                               /* true/yes */
 
 static struct utmp     buf[1024];              /* 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 */
-
 typedef struct arg {
        char    *name;                          /* argument */
 #define        HOST_TYPE       -2
 typedef struct arg {
        char    *name;                          /* argument */
 #define        HOST_TYPE       -2
@@ -44,27 +67,30 @@ typedef struct arg {
        int     type;                           /* type of arg */
        struct arg      *next;                  /* linked list pointer */
 } ARG;
        int     type;                           /* type of arg */
        struct arg      *next;                  /* linked list pointer */
 } ARG;
-ARG    *head;                                  /* head of linked list */
+ARG    *arglist;                               /* head of linked list */
 
 typedef struct ttytab {
        long    logout;                         /* log out time */
 
 typedef struct ttytab {
        long    logout;                         /* log out time */
-       char    tty[LMAX + 1];                  /* terminal name */
-} TTYS;
+       char    tty[UT_LINESIZE + 1];           /* terminal name */
+       struct ttytab   *next;                  /* linked list pointer */
+} TTY;
+TTY    *ttylist;                               /* head of linked list */
 
 
-static TTYS    tab[MAXTTYS + 1];               /* tty table */
-static long    maxrec;                         /* records to display */
-static char    *file = "/usr/adm/wtmp";        /* wtmp file */
+static long    currentout,                     /* current logout value */
+               maxrec;                         /* records to display */
+static char    *file = _PATH_WTMP;             /* wtmp file */
 
 main(argc, argv)
 
 main(argc, argv)
-       int     argc;
-       char    **argv;
+       int argc;
+       char **argv;
 {
 {
-       extern int      optind;
-       extern char     *optarg;
-       int     ch;
-       char    *malloc();
-       long    atol();
+       extern int optind;
+       extern char *optarg;
+       int ch;
+       long atol();
+       char *p, *ttyconv();
 
 
+       maxrec = -1;
        while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
                switch((char)ch) {
                case '0': case '1': case '2': case '3': case '4':
        while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
                switch((char)ch) {
                case '0': case '1': case '2': case '3': case '4':
@@ -73,8 +99,15 @@ main(argc, argv)
                         * kludge: last was originally designed to take
                         * a number after a dash.
                         */
                         * kludge: last was originally designed to take
                         * a number after a dash.
                         */
-                       if (!maxrec)
-                               maxrec = atol(argv[optind - 1] + 1);
+                       if (maxrec == -1) {
+                               p = argv[optind - 1];
+                               if (p[0] == '-' && p[1] == ch && !p[2])
+                                       maxrec = atol(++p);
+                               else
+                                       maxrec = atol(argv[optind] + 1);
+                               if (!maxrec)
+                                       exit(0);
+                       }
                        break;
                case 'f':
                        file = optarg;
                        break;
                case 'f':
                        file = optarg;
@@ -84,38 +117,25 @@ main(argc, argv)
                        addarg(HOST_TYPE, optarg);
                        break;
                case 't':
                        addarg(HOST_TYPE, optarg);
                        break;
                case 't':
-               {
-                       char    *mval, *strcpy();
-
-                       /*
-                        * kludge -- we assume that all tty's end with
-                        * a two character suffix.
-                        */
-                       if (strlen(optarg) == 2) {
-                               /* either 6 for "ttyxx" or 8 for "console" */
-                               if (!(mval = malloc((u_int)8))) {
-                                       fputs("last: malloc failure.\n", stderr);
-                                       exit(1);
-                               }
-                               if (!strcmp(optarg, "co"))
-                                       (void)strcpy(mval, "console");
-                               else {
-                                       (void)strcpy(mval, "tty");
-                                       (void)strcpy(mval + 3, optarg);
-                               }
-                               addarg(TTY_TYPE, mval);
-                       }
-                       else
-                               addarg(TTY_TYPE, optarg);
+                       addarg(TTY_TYPE, ttyconv(optarg));
                        break;
                        break;
-               }
                case '?':
                default:
                        fputs("usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n", stderr);
                        exit(1);
                }
                case '?':
                default:
                        fputs("usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n", stderr);
                        exit(1);
                }
-       for (argv += optind; *argv; ++argv)
-               addarg(USER_TYPE, *argv);
+
+       if (argc) {
+               setlinebuf(stdout);
+               for (argv += optind; *argv; ++argv) {
+#define        COMPATIBILITY
+#ifdef COMPATIBILITY
+                       /* code to allow "last p5" to work */
+                       addarg(TTY_TYPE, ttyconv(*argv));
+#endif
+                       addarg(USER_TYPE, *argv);
+               }
+       }
        wtmp();
        exit(0);
 }
        wtmp();
        exit(0);
 }
@@ -124,18 +144,18 @@ main(argc, argv)
  * wtmp --
  *     read through the wtmp file
  */
  * wtmp --
  *     read through the wtmp file
  */
-static
 wtmp()
 {
        register struct utmp    *bp;            /* current structure */
 wtmp()
 {
        register struct utmp    *bp;            /* current structure */
-       register TTYS   *T;                     /* table entry */
+       register TTY    *T;                     /* tty list entry */
        struct stat     stb;                    /* stat of file for size */
        long    bl, delta,                      /* time difference */
                lseek(), time();
        struct stat     stb;                    /* stat of file for size */
        long    bl, delta,                      /* time difference */
                lseek(), time();
-       int     bytes, wfd,
-               onintr();
+       int     bytes, wfd;
        char    *ct, *crmsg,
                *asctime(), *ctime(), *strcpy();
        char    *ct, *crmsg,
                *asctime(), *ctime(), *strcpy();
+       TTY     *addtty();
+       void    onintr();
 
        if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) {
                perror(file);
 
        if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) {
                perror(file);
@@ -147,7 +167,6 @@ wtmp()
        (void)signal(SIGINT, onintr);
        (void)signal(SIGQUIT, onintr);
 
        (void)signal(SIGINT, onintr);
        (void)signal(SIGQUIT, onintr);
 
-       tab[MAXTTYS].logout = -1;               /* end flag value */
        while (--bl >= 0) {
                if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
                    (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
        while (--bl >= 0) {
                if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
                    (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
@@ -160,36 +179,48 @@ wtmp()
                         * if the terminal line is '~', the machine stopped.
                         * see utmp(5) for more info.
                         */
                         * if the terminal line is '~', the machine stopped.
                         * see utmp(5) for more info.
                         */
-                       if (!strncmp(bp->ut_line, "~", LMAX)) {
-                               for (T = tab; T->logout != -1; ++T)
+                       if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
+                               /* everybody just logged out */
+                               for (T = ttylist; T; T = T->next)
                                        T->logout = -bp->ut_time;
                                        T->logout = -bp->ut_time;
-                               crmsg = strncmp(bp->ut_name, "shutdown", NMAX)
-                                    ? "crash" : "down ";
-                               if (!bp->ut_name[0])
-                                       (void)strcpy(bp->ut_name, "reboot");
+                               currentout = -bp->ut_time;
+                               crmsg = strncmp(bp->ut_name, "shutdown",
+                                   UT_NAMESIZE) ? "crash" : "shutdown";
+                               if (want(bp, NO)) {
+                                       ct = ctime(&bp->ut_time);
+                                       printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s \n", UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, UT_LINESIZE, UT_LINESIZE, bp->ut_line, UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, ct, ct + 11);
+                                       if (maxrec != -1 && !--maxrec)
+                                               return;
+                               }
+                               continue;
+                       }
+                       /*
+                        * if the line is '{' or '|', date got set; see
+                        * utmp(5) for more info.
+                        */
+                       if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
+                           && !bp->ut_line[1]) {
                                if (want(bp, NO)) {
                                        ct = ctime(&bp->ut_time);
                                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);
+                                       printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s \n", UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, UT_LINESIZE, UT_LINESIZE, bp->ut_line, UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, ct, ct + 11);
                                        if (maxrec && !--maxrec)
                                                return;
                                }
                                continue;
                        }
                                        if (maxrec && !--maxrec)
                                                return;
                                }
                                continue;
                        }
-                       for (T = tab;;) {               /* find assoc. tty */
-                               if (T->logout <= 0) {   /* unused entry */
-                                       bcopy(bp->ut_line, T->tty, LMAX);
+                       /* find associated tty */
+                       for (T = ttylist;; T = T->next) {
+                               if (!T) {
+                                       /* add new one */
+                                       T = addtty(bp->ut_line);
                                        break;
                                }
                                        break;
                                }
-                               if (!strncmp(T->tty, bp->ut_line, LMAX))
+                               if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE))
                                        break;
                                        break;
-                               if ((++T)->logout == -1) {
-                                       fputs("last: too many terminals.\n", stderr);
-                                       exit(1);
-                               }
                        }
                        if (bp->ut_name[0] && want(bp, YES)) {
                                ct = ctime(&bp->ut_time);
                        }
                        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);
+                               printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s ", UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, UT_LINESIZE, UT_LINESIZE, bp->ut_line, UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, ct, ct + 11);
                                if (!T->logout)
                                        puts("  still logged in");
                                else {
                                if (!T->logout)
                                        puts("  still logged in");
                                else {
@@ -219,38 +250,37 @@ wtmp()
  * want --
  *     see if want this entry
  */
  * want --
  *     see if want this entry
  */
-static
 want(bp, check)
 want(bp, check)
-       register struct utmp    *bp;
-       int     check;
+       register struct utmp *bp;
+       int check;
 {
 {
-       register ARG    *step;
+       register ARG *step;
 
        if (check)
                /*
 
        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.
+                * 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))
+               if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
                        bp->ut_line[3] = '\0';
                        bp->ut_line[3] = '\0';
-               else if (!strncmp(bp->ut_line, "uucp", 4))
+               else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
                        bp->ut_line[4] = '\0';
                        bp->ut_line[4] = '\0';
-       if (!head)
+       if (!arglist)
                return(YES);
 
                return(YES);
 
-       for (step = head; step; step = step->next)
+       for (step = arglist; step; step = step->next)
                switch(step->type) {
                case HOST_TYPE:
                switch(step->type) {
                case HOST_TYPE:
-                       if (!strncasecmp(step->name, bp->ut_host, HMAX))
+                       if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE))
                                return(YES);
                        break;
                case TTY_TYPE:
                                return(YES);
                        break;
                case TTY_TYPE:
-                       if (!strncmp(step->name, bp->ut_line, LMAX))
+                       if (!strncmp(step->name, bp->ut_line, UT_LINESIZE))
                                return(YES);
                        break;
                case USER_TYPE:
                                return(YES);
                        break;
                case USER_TYPE:
-                       if (!strncmp(step->name, bp->ut_name, NMAX))
+                       if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE))
                                return(YES);
                        break;
        }
                                return(YES);
                        break;
        }
@@ -261,22 +291,42 @@ want(bp, check)
  * addarg --
  *     add an entry to a linked list of arguments
  */
  * addarg --
  *     add an entry to a linked list of arguments
  */
-static
 addarg(type, arg)
 addarg(type, arg)
-       int     type;
-       char    *arg;
+       int type;
+       char *arg;
 {
 {
-       register ARG    *cur;
-       char    *malloc();
+       register ARG *cur;
+       char *malloc();
 
        if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) {
                fputs("last: malloc failure.\n", stderr);
                exit(1);
        }
 
        if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) {
                fputs("last: malloc failure.\n", stderr);
                exit(1);
        }
-       cur->next = head;
+       cur->next = arglist;
        cur->type = type;
        cur->name = arg;
        cur->type = type;
        cur->name = arg;
-       head = cur;
+       arglist = cur;
+}
+
+/*
+ * addtty --
+ *     add an entry to a linked list of ttys
+ */
+TTY *
+addtty(ttyname)
+       char *ttyname;
+{
+       register TTY *cur;
+       char *malloc();
+
+       if (!(cur = (TTY *)malloc((u_int)sizeof(TTY)))) {
+               fputs("last: malloc failure.\n", stderr);
+               exit(1);
+       }
+       cur->next = ttylist;
+       cur->logout = currentout;
+       bcopy(ttyname, cur->tty, UT_LINESIZE);
+       return(ttylist = cur);
 }
 
 /*
 }
 
 /*
@@ -285,14 +335,12 @@ addarg(type, arg)
  *     has a domain attached that is the same as the current domain, rip
  *     off the domain suffix since that's what login(1) does.
  */
  *     has a domain attached that is the same as the current domain, rip
  *     off the domain suffix since that's what login(1) does.
  */
-static
 hostconv(arg)
 hostconv(arg)
-       char    *arg;
+       char *arg;
 {
 {
-       static int      first = 1;
-       static char     *hostdot,
-                       name[MAXHOSTNAMELEN];
-       char    *argdot, *index();
+       static int first = 1;
+       static char *hostdot, name[MAXHOSTNAMELEN];
+       char *argdot, *index();
 
        if (!(argdot = index(arg, '.')))
                return;
 
        if (!(argdot = index(arg, '.')))
                return;
@@ -308,15 +356,48 @@ hostconv(arg)
                *argdot = '\0';
 }
 
                *argdot = '\0';
 }
 
+/*
+ * ttyconv --
+ *     convert tty to correct name.
+ */
+char *
+ttyconv(arg)
+       char *arg;
+{
+       char *mval, *malloc(), *strcpy();
+
+       /*
+        * kludge -- we assume that all tty's end with
+        * a two character suffix.
+        */
+       if (strlen(arg) == 2) {
+               /* either 6 for "ttyxx" or 8 for "console" */
+               if (!(mval = malloc((u_int)8))) {
+                       fputs("last: malloc failure.\n", stderr);
+                       exit(1);
+               }
+               if (!strcmp(arg, "co"))
+                       (void)strcpy(mval, "console");
+               else {
+                       (void)strcpy(mval, "tty");
+                       (void)strcpy(mval + 3, arg);
+               }
+               return(mval);
+       }
+       if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
+               return(arg + 5);
+       return(arg);
+}
+
 /*
  * onintr --
  *     on interrupt, we inform the user how far we've gotten
  */
 /*
  * onintr --
  *     on interrupt, we inform the user how far we've gotten
  */
-static
+void
 onintr(signo)
 onintr(signo)
-       int     signo;
+       int signo;
 {
 {
-       char    *ct, *ctime();
+       char *ct, *ctime();
 
        ct = ctime(&buf[0].ut_time);
        printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
 
        ct = ctime(&buf[0].ut_time);
        printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);