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