Annotation of 43BSDReno/usr.bin/last/last.c, revision 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.