|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.