Annotation of 43BSDTahoe/ucb/last.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.