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