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

unix.superglobalmegacorp.com

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