[BACK]Return to last.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / last

Annotation of src/usr.bin/last/last.c, Revision 1.3

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