# /* * NAME: last * * SYNOPSIS: last [list] * * DESCRIPTION: Displays login history of named users or tty's. * Last with no argument prints history for all users. * * AUTHOR - Howard P. Katseff */ # include <sys/types.h> # include <stdio.h> # include <stat.h> # include <utmp.h> char yes = 1, no = 0, *wtmp = "/usr/adm/wtmp", b [512], Arg [25] [9], tty_names [48] [9], *ctime (), *move (), *rmchar (); long logouts [48], bl, rec, nblock; struct utmp buf [128]; /* buf takes exactly 5 blocks */ main (argc, argv) char **argv; { char f, narg, *bend, *p, *q; short n_byte, n_record; long i, k, ntime, otime, intrp (); struct stat sbuf; for (i = 1; i < argc; i++) { if ( length (argv [i]) > 2 /* long tty or user name */ || equal (argv [i], "~") /* tilde */ || getpwnam (argv [i]) /* user name */ ) { move (argv [i], Arg [narg++]); } else /* short tty name */ { move (argv [i], move ("tty", Arg [narg++])); } } f = open (wtmp, 0); if (f < 0) { perror (wtmp); fflush (stdout); exit (); } if (fstat (f, &sbuf) < 0) { perror ("/usr/adm/wtmp"); fflush (stdout); exit (); } nblock = (sbuf.st_size + 2559) / 2560; signal (2, intrp); for (bl = nblock - 1; bl >= 0; bl--) { lseek (f, bl * 2560, 0); n_byte = read (f, buf, 2560); n_record = n_byte / sizeof buf [0]; for (rec = n_record - 1; rec >= 0; rec--) { if (should_print ()) { q = ctime (&buf[rec].ut_time); printf ( "%-8.8s %-8.8s %10.10s %5.5s ", buf[rec].ut_name, buf[rec].ut_line, q, 11+q ); otime = buf[rec].ut_time; /* * look up the logout time for the tty */ for (i = 0;; i++) { if (!*tty_names [i]) /* not in the table, therefore add it */ { move ( buf[rec].ut_line, tty_names [i] ); ntime = 0; break; } if ( equal ( tty_names [i], buf [rec].ut_line ) ) { ntime = logouts [i]; break; } } if (ntime == 0) { printf (" still logged in\n"); } else { if (ntime < 0) { ntime = -ntime; printf ("- crash"); } else { printf ("- %5.5s", ctime (&ntime) + 11); } /* * calculate how long logged in */ otime = ntime - otime; otime += 231220830 + 10800; if (otime < 231220830 + 86400 + 10800) { printf ( " (%5.5s)\n", ctime (&otime) + 11 ); } else { printf ( " (%ld+%5.5s)\n", (otime - (231330830-86400-10800))/86400, ctime (&otime) + 11 ); } } fflush (stdout); } if ( equal (buf[rec].ut_line, "~") || equal (buf[rec].ut_line, "tty~") ) { for (i = 0; *tty_names [i]; i++) { logouts [i] = -buf[rec].ut_time; } } else { for (k = 0;; k++) { if (!*tty_names [k]) { move ( buf[rec].ut_line, tty_names [k] ); logouts [k] = buf[rec].ut_time; break; } if (equal (tty_names [k], buf[rec].ut_line)) { logouts [k] = buf[rec].ut_time; break; } } } } } q = ctime (&buf [0].ut_time); printf ( "\nwtmp begins %10.10s %5.5s \n", q, q + 11 ); } equal (a, b) char *a, *b; { char i; for (i = 0; i < 8; i++) { if (!*a) return (!*b); if (*a++ != *b++) return (0); } return (1); } intrp () { char *q; signal (2, 1); /* ignore further interrupts */ q = ctime (&buf[rec].ut_time); printf ( "\ninterrupted %10.10s %5.5s \n", q, q + 11 ); exit (); } char * rmchar (c, s) char c, *s; { for (; *s; s++) { if (*s == c) { *s = 0; return (s); } } return (0); } length (a) char *a; { char *b; for (b = a; *b; b++); return (b - a); } char * move (a, b) char *a, *b; { while (*b++ = *a++); return (b - 1); } should_print () { short i; if (buf [rec].ut_name [0] == no) return no; /* a logout entry */ if (!**Arg) return yes; /* no arguments? Print all login entries */ for (i = 0; i < *Arg [i]; i++) { if ( equal (Arg [i], buf[rec].ut_name) || equal (Arg [i], buf[rec].ut_line) ) return yes; } return no; }