home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / last / last.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-17  |  10.3 KB  |  408 lines

  1. /*
  2.  * Copyright (c) 1987 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1987 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)last.c    5.18 (Berkeley) 3/1/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * last
  46.  */
  47. #include <sys/param.h>
  48. #include <sys/stat.h>
  49. #include <sys/file.h>
  50. #include <signal.h>
  51. #include <time.h>
  52. #include <utmp.h>
  53. #include <stdio.h>
  54. #include <paths.h>
  55.  
  56. #define    SECDAY    (24*60*60)            /* seconds in a day */
  57. #define    NO    0                /* false/no */
  58. #define    YES    1                /* true/yes */
  59.  
  60. static struct utmp    buf[1024];        /* utmp read buffer */
  61.  
  62. typedef struct arg {
  63.     char    *name;                /* argument */
  64. #define    HOST_TYPE    -2
  65. #define    TTY_TYPE    -3
  66. #define    USER_TYPE    -4
  67.     int    type;                /* type of arg */
  68.     struct arg    *next;            /* linked list pointer */
  69. } ARG;
  70. ARG    *arglist;                /* head of linked list */
  71.  
  72. typedef struct ttytab {
  73.     long    logout;                /* log out time */
  74.     char    tty[UT_LINESIZE + 1];        /* terminal name */
  75.     struct ttytab    *next;            /* linked list pointer */
  76. } TTY;
  77. TTY    *ttylist;                /* head of linked list */
  78.  
  79. static long    currentout,            /* current logout value */
  80.         maxrec;                /* records to display */
  81. static char    *file = _PATH_WTMP;        /* wtmp file */
  82.  
  83. main(argc, argv)
  84.     int argc;
  85.     char **argv;
  86. {
  87.     extern int optind;
  88.     extern char *optarg;
  89.     int ch;
  90.     long atol();
  91.     char *p, *ttyconv();
  92.  
  93.     maxrec = -1;
  94.     while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
  95.         switch((char)ch) {
  96.         case '0': case '1': case '2': case '3': case '4':
  97.         case '5': case '6': case '7': case '8': case '9':
  98.             /*
  99.              * kludge: last was originally designed to take
  100.              * a number after a dash.
  101.              */
  102.             if (maxrec == -1) {
  103.                 p = argv[optind - 1];
  104.                 if (p[0] == '-' && p[1] == ch && !p[2])
  105.                     maxrec = atol(++p);
  106.                 else
  107.                     maxrec = atol(argv[optind] + 1);
  108.                 if (!maxrec)
  109.                     exit(0);
  110.             }
  111.             break;
  112.         case 'f':
  113.             file = optarg;
  114.             break;
  115.         case 'h':
  116.             hostconv(optarg);
  117.             addarg(HOST_TYPE, optarg);
  118.             break;
  119.         case 't':
  120.             addarg(TTY_TYPE, ttyconv(optarg));
  121.             break;
  122.         case '?':
  123.         default:
  124.             fputs("usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n", stderr);
  125.             exit(1);
  126.         }
  127.  
  128.     if (argc) {
  129.         setlinebuf(stdout);
  130.         for (argv += optind; *argv; ++argv) {
  131. #define    COMPATIBILITY
  132. #ifdef    COMPATIBILITY
  133.             /* code to allow "last p5" to work */
  134.             addarg(TTY_TYPE, ttyconv(*argv));
  135. #endif
  136.             addarg(USER_TYPE, *argv);
  137.         }
  138.     }
  139.     wtmp();
  140.     exit(0);
  141. }
  142.  
  143. /*
  144.  * wtmp --
  145.  *    read through the wtmp file
  146.  */
  147. wtmp()
  148. {
  149.     register struct utmp    *bp;        /* current structure */
  150.     register TTY    *T;            /* tty list entry */
  151.     struct stat    stb;            /* stat of file for size */
  152.     long    bl, delta,            /* time difference */
  153.         lseek(), time();
  154.     int    bytes, wfd;
  155.     char    *ct, *crmsg,
  156.         *asctime(), *ctime(), *strcpy();
  157.     TTY    *addtty();
  158.     void    onintr();
  159.  
  160.     if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) {
  161.         perror(file);
  162.         exit(1);
  163.     }
  164.     bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
  165.  
  166.     (void)time(&buf[0].ut_time);
  167.     (void)signal(SIGINT, onintr);
  168.     (void)signal(SIGQUIT, onintr);
  169.  
  170.     while (--bl >= 0) {
  171.         if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
  172.             (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
  173.             fprintf(stderr, "last: %s: ", file);
  174.             perror((char *)NULL);
  175.             exit(1);
  176.         }
  177.         for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
  178.             /*
  179.              * if the terminal line is '~', the machine stopped.
  180.              * see utmp(5) for more info.
  181.              */
  182.             if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
  183.                 /* everybody just logged out */
  184.                 for (T = ttylist; T; T = T->next)
  185.                     T->logout = -bp->ut_time;
  186.                 currentout = -bp->ut_time;
  187.                 crmsg = strncmp(bp->ut_name, "shutdown",
  188.                     UT_NAMESIZE) ? "crash" : "shutdown";
  189.                 if (want(bp, NO)) {
  190.                     ct = ctime(&bp->ut_time);
  191.                     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);
  192.                     if (maxrec != -1 && !--maxrec)
  193.                         return;
  194.                 }
  195.                 continue;
  196.             }
  197.             /*
  198.              * if the line is '{' or '|', date got set; see
  199.              * utmp(5) for more info.
  200.              */
  201.             if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
  202.                 && !bp->ut_line[1]) {
  203.                 if (want(bp, NO)) {
  204.                     ct = ctime(&bp->ut_time);
  205.                     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);
  206.                     if (maxrec && !--maxrec)
  207.                         return;
  208.                 }
  209.                 continue;
  210.             }
  211.             /* find associated tty */
  212.             for (T = ttylist;; T = T->next) {
  213.                 if (!T) {
  214.                     /* add new one */
  215.                     T = addtty(bp->ut_line);
  216.                     break;
  217.                 }
  218.                 if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE))
  219.                     break;
  220.             }
  221.             if (bp->ut_name[0] && want(bp, YES)) {
  222.                 ct = ctime(&bp->ut_time);
  223.                 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);
  224.                 if (!T->logout)
  225.                     puts("  still logged in");
  226.                 else {
  227.                     if (T->logout < 0) {
  228.                         T->logout = -T->logout;
  229.                         printf("- %s", crmsg);
  230.                     }
  231.                     else
  232.                         printf("- %5.5s", ctime(&T->logout)+11);
  233.                     delta = T->logout - bp->ut_time;
  234.                     if (delta < SECDAY)
  235.                         printf("  (%5.5s)\n", asctime(gmtime(&delta))+11);
  236.                     else
  237.                         printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11);
  238.                 }
  239.                 if (maxrec != -1 && !--maxrec)
  240.                     return;
  241.             }
  242.             T->logout = bp->ut_time;
  243.         }
  244.     }
  245.     ct = ctime(&buf[0].ut_time);
  246.     printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
  247. }
  248.  
  249. /*
  250.  * want --
  251.  *    see if want this entry
  252.  */
  253. want(bp, check)
  254.     register struct utmp *bp;
  255.     int check;
  256. {
  257.     register ARG *step;
  258.  
  259.     if (check)
  260.         /*
  261.          * when uucp and ftp log in over a network, the entry in
  262.          * the utmp file is the name plus their process id.  See
  263.          * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
  264.          */
  265.         if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
  266.             bp->ut_line[3] = '\0';
  267.         else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
  268.             bp->ut_line[4] = '\0';
  269.     if (!arglist)
  270.         return(YES);
  271.  
  272.     for (step = arglist; step; step = step->next)
  273.         switch(step->type) {
  274.         case HOST_TYPE:
  275.             if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE))
  276.                 return(YES);
  277.             break;
  278.         case TTY_TYPE:
  279.             if (!strncmp(step->name, bp->ut_line, UT_LINESIZE))
  280.                 return(YES);
  281.             break;
  282.         case USER_TYPE:
  283.             if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE))
  284.                 return(YES);
  285.             break;
  286.     }
  287.     return(NO);
  288. }
  289.  
  290. /*
  291.  * addarg --
  292.  *    add an entry to a linked list of arguments
  293.  */
  294. addarg(type, arg)
  295.     int type;
  296.     char *arg;
  297. {
  298.     register ARG *cur;
  299.     char *malloc();
  300.  
  301.     if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) {
  302.         fputs("last: malloc failure.\n", stderr);
  303.         exit(1);
  304.     }
  305.     cur->next = arglist;
  306.     cur->type = type;
  307.     cur->name = arg;
  308.     arglist = cur;
  309. }
  310.  
  311. /*
  312.  * addtty --
  313.  *    add an entry to a linked list of ttys
  314.  */
  315. TTY *
  316. addtty(ttyname)
  317.     char *ttyname;
  318. {
  319.     register TTY *cur;
  320.     char *malloc();
  321.  
  322.     if (!(cur = (TTY *)malloc((u_int)sizeof(TTY)))) {
  323.         fputs("last: malloc failure.\n", stderr);
  324.         exit(1);
  325.     }
  326.     cur->next = ttylist;
  327.     cur->logout = currentout;
  328.     bcopy(ttyname, cur->tty, UT_LINESIZE);
  329.     return(ttylist = cur);
  330. }
  331.  
  332. /*
  333.  * hostconv --
  334.  *    convert the hostname to search pattern; if the supplied host name
  335.  *    has a domain attached that is the same as the current domain, rip
  336.  *    off the domain suffix since that's what login(1) does.
  337.  */
  338. hostconv(arg)
  339.     char *arg;
  340. {
  341.     static int first = 1;
  342.     static char *hostdot, name[MAXHOSTNAMELEN];
  343.     char *argdot, *index();
  344.  
  345.     if (!(argdot = index(arg, '.')))
  346.         return;
  347.     if (first) {
  348.         first = 0;
  349.         if (gethostname(name, sizeof(name))) {
  350.             perror("last: gethostname");
  351.             exit(1);
  352.         }
  353.         hostdot = index(name, '.');
  354.     }
  355.     if (hostdot && !strcasecmp(hostdot, argdot))
  356.         *argdot = '\0';
  357. }
  358.  
  359. /*
  360.  * ttyconv --
  361.  *    convert tty to correct name.
  362.  */
  363. char *
  364. ttyconv(arg)
  365.     char *arg;
  366. {
  367.     char *mval, *malloc(), *strcpy();
  368.  
  369.     /*
  370.      * kludge -- we assume that all tty's end with
  371.      * a two character suffix.
  372.      */
  373.     if (strlen(arg) == 2) {
  374.         /* either 6 for "ttyxx" or 8 for "console" */
  375.         if (!(mval = malloc((u_int)8))) {
  376.             fputs("last: malloc failure.\n", stderr);
  377.             exit(1);
  378.         }
  379.         if (!strcmp(arg, "co"))
  380.             (void)strcpy(mval, "console");
  381.         else {
  382.             (void)strcpy(mval, "tty");
  383.             (void)strcpy(mval + 3, arg);
  384.         }
  385.         return(mval);
  386.     }
  387.     if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
  388.         return(arg + 5);
  389.     return(arg);
  390. }
  391.  
  392. /*
  393.  * onintr --
  394.  *    on interrupt, we inform the user how far we've gotten
  395.  */
  396. void
  397. onintr(signo)
  398.     int signo;
  399. {
  400.     char *ct, *ctime();
  401.  
  402.     ct = ctime(&buf[0].ut_time);
  403.     printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
  404.     if (signo == SIGINT)
  405.         exit(1);
  406.     (void)fflush(stdout);            /* fix required for rsh */
  407. }
  408.