From 6d640118578b872e41214af63f644eb553348703 Mon Sep 17 00:00:00 2001 From: ed Date: Wed, 13 Jan 2010 18:06:31 +0000 Subject: Port last(1) to use utmpx. Basically there are three major things I changed about last(1): - It should use ut_type instead of determining by hand what type of record was given. - It should now keep track of ut_id's instead of TTYs. This means the ttylist has been renamed to the idlist, storing all the ut_id's it has processed until the next reboot. - I've removed the signal handler. Because our wtmp is rotated so often, it makes little sense. Even on a simple piece of hardware it should be capable of grinding through megabytes of logs in a second. --- usr.bin/last/last.c | 185 +++++++++++++++++++++++----------------------------- 1 file changed, 83 insertions(+), 102 deletions(-) (limited to 'usr.bin/last/last.c') diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c index d9877b4..a202b31 100644 --- a/usr.bin/last/last.c +++ b/usr.bin/last/last.c @@ -59,15 +59,13 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #define NO 0 /* false/no */ #define YES 1 /* true/yes */ #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; -static struct utmp buf[1024]; /* utmp read buffer */ - typedef struct arg { char *name; /* argument */ #define HOST_TYPE -2 @@ -78,18 +76,18 @@ typedef struct arg { } ARG; ARG *arglist; /* head of linked list */ -LIST_HEAD(ttylisthead, ttytab) ttylist; +LIST_HEAD(idlisthead, idtab) idlist; -struct ttytab { +struct idtab { time_t logout; /* log out time */ - char tty[UT_LINESIZE + 1]; /* terminal name */ - LIST_ENTRY(ttytab) list; + char id[sizeof ((struct utmpx *)0)->ut_id]; /* identifier */ + LIST_ENTRY(idtab) list; }; static const char *crmsg; /* cause of last reboot */ -static long currentout, /* current logout value */ - maxrec; /* records to display */ -static const char *file = _PATH_WTMP; /* wtmp file */ +static time_t currentout; /* current logout value */ +static long maxrec; /* records to display */ +static const char *file = NULL; /* wtmp file */ static int sflag = 0; /* show delta in seconds */ static int width = 5; /* show seconds in delta */ static int yflag; /* show year */ @@ -102,12 +100,11 @@ static time_t snaptime; /* if != 0, we will only void addarg(int, char *); time_t dateconv(char *); -void doentry(struct utmp *); +void doentry(struct utmpx *); void hostconv(char *); -void onintr(int); -void printentry(struct utmp *, struct ttytab *); +void printentry(struct utmpx *, struct idtab *); char *ttyconv(char *); -int want(struct utmp *); +int want(struct utmpx *); void usage(void); void wtmp(void); @@ -199,6 +196,8 @@ main(int argc, char *argv[]) exit(0); } +#define MAXUTXENTRIES 1024 + /* * wtmp -- * read through the wtmp file @@ -206,33 +205,34 @@ main(int argc, char *argv[]) void wtmp(void) { - struct utmp *bp; /* current structure */ - struct stat stb; /* stat of file for size */ - long bl; - int bytes, wfd; + struct utmpx buf[MAXUTXENTRIES]; + struct utmpx *ut; + static unsigned int first = 0, amount = 0; + time_t t; char ct[80]; struct tm *tm; - time_t t; - LIST_INIT(&ttylist); + LIST_INIT(&idlist); + (void)time(&t); - if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) + /* Load the last entries from the file. */ + if (setutxdb(UTXDB_LOG, file) != 0) err(1, "%s", file); - bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf); - - (void)time(&t); - buf[0].ut_time = _time_to_int(t); - (void)signal(SIGINT, onintr); - (void)signal(SIGQUIT, onintr); - - while (--bl >= 0) { - if (lseek(wfd, (off_t)(bl * sizeof(buf)), L_SET) == -1 || - (bytes = read(wfd, buf, sizeof(buf))) == -1) - err(1, "%s", file); - for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) - doentry(bp); + while ((ut = getutxent()) != NULL) { + memcpy(&buf[(first + amount) % MAXUTXENTRIES], ut, sizeof *ut); + if (amount == MAXUTXENTRIES) + first++; + else + amount++; + if (t > ut->ut_tv.tv_sec) + t = ut->ut_tv.tv_sec; } - t = _int_to_time(buf[0].ut_time); + endutxent(); + + /* Display them in reverse order. */ + while (amount > 0) + doentry(&buf[(first + amount--) % MAXUTXENTRIES]); + tm = localtime(&t); (void) strftime(ct, sizeof(ct), "\nwtmp begins %+\n", tm); printf("%s", ct); @@ -243,24 +243,21 @@ wtmp(void) * process a single wtmp entry */ void -doentry(struct utmp *bp) +doentry(struct utmpx *bp) { - struct ttytab *tt, *ttx; /* ttylist entry */ + struct idtab *tt, *ttx; /* idlist entry */ - /* - * if the terminal line is '~', the machine stopped. - * see utmp(5) for more info. - */ - if (bp->ut_line[0] == '~' && !bp->ut_line[1]) { + /* the machine stopped */ + if (bp->ut_type == BOOT_TIME || bp->ut_type == SHUTDOWN_TIME) { /* everybody just logged out */ - for (tt = LIST_FIRST(&ttylist); tt;) { + for (tt = LIST_FIRST(&idlist); tt;) { LIST_REMOVE(tt, list); ttx = tt; tt = LIST_NEXT(tt, list); free(ttx); } - currentout = -bp->ut_time; - crmsg = strncmp(bp->ut_name, "shutdown", UT_NAMESIZE) ? + currentout = -bp->ut_tv.tv_sec; + crmsg = bp->ut_type != SHUTDOWN_TIME ? "crash" : "shutdown"; /* * if we're in snapshot mode, we want to exit if this @@ -276,50 +273,42 @@ doentry(struct utmp *bp) printentry(bp, NULL); return; } - /* - * if the line is '{' or '|', date got set; see - * utmp(5) for more info. - */ - if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|') && - !bp->ut_line[1]) { + /* date got set */ + if (bp->ut_type == OLD_TIME || bp->ut_type == NEW_TIME) { if (want(bp) && !snaptime) printentry(bp, NULL); return; } - /* find associated tty */ - LIST_FOREACH(tt, &ttylist, list) - if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE)) + + if (bp->ut_type != USER_PROCESS && bp->ut_type != DEAD_PROCESS) + return; + + /* find associated identifier */ + LIST_FOREACH(tt, &idlist, list) + if (!memcmp(tt->id, bp->ut_id, sizeof bp->ut_id)) break; if (tt == NULL) { /* add new one */ - tt = malloc(sizeof(struct ttytab)); + tt = malloc(sizeof(struct idtab)); if (tt == NULL) errx(1, "malloc failure"); tt->logout = currentout; - strncpy(tt->tty, bp->ut_line, UT_LINESIZE); - LIST_INSERT_HEAD(&ttylist, tt, list); + memcpy(tt->id, bp->ut_id, sizeof bp->ut_id); + LIST_INSERT_HEAD(&idlist, tt, list); } /* * print record if not in snapshot mode and wanted * or in snapshot mode and in snapshot range */ - if (bp->ut_name[0] && (want(bp) || (bp->ut_time < snaptime && + if (bp->ut_type == USER_PROCESS && (want(bp) || + (bp->ut_tv.tv_sec < snaptime && (tt->logout > snaptime || tt->logout < 1)))) { snapfound = 1; - /* - * when uucp and ftp log in over a network, the entry in - * the utmp file is the name plus their process id. See - * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. - */ - if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1)) - bp->ut_line[3] = '\0'; - else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1)) - bp->ut_line[4] = '\0'; printentry(bp, tt); } - tt->logout = bp->ut_time; + tt->logout = bp->ut_tv.tv_sec; } /* @@ -330,7 +319,7 @@ doentry(struct utmp *bp) * logout type (crash/shutdown) as appropriate. */ void -printentry(struct utmp *bp, struct ttytab *tt) +printentry(struct utmpx *bp, struct idtab *tt) { char ct[80]; struct tm *tm; @@ -339,16 +328,30 @@ printentry(struct utmp *bp, struct ttytab *tt) if (maxrec != -1 && !maxrec--) exit(0); - t = _int_to_time(bp->ut_time); + t = bp->ut_tv.tv_sec; tm = localtime(&t); (void) strftime(ct, sizeof(ct), d_first ? (yflag ? "%a %e %b %Y %R" : "%a %e %b %R") : (yflag ? "%a %b %e %Y %R" : "%a %b %e %R"), tm); - printf("%-*.*s %-*.*s %-*.*s %s%c", - UT_NAMESIZE, UT_NAMESIZE, bp->ut_name, - UT_LINESIZE, UT_LINESIZE, bp->ut_line, - UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host, - ct, tt == NULL ? '\n' : ' '); + switch (bp->ut_type) { + case BOOT_TIME: + printf("%-42s", "boot time"); + break; + case SHUTDOWN_TIME: + printf("%-42s", "shutdown time"); + break; + case OLD_TIME: + printf("%-42s", "old time"); + break; + case NEW_TIME: + printf("%-42s", "new time"); + break; + case USER_PROCESS: + printf("%-10s %-8s %-22.22s", + bp->ut_user, bp->ut_line, bp->ut_host); + break; + } + printf(" %s%c", ct, tt == NULL ? '\n' : ' '); if (tt == NULL) return; if (!tt->logout) { @@ -363,7 +366,7 @@ printentry(struct utmp *bp, struct ttytab *tt) (void) strftime(ct, sizeof(ct), "%R", tm); printf("- %s", ct); } - delta = tt->logout - bp->ut_time; + delta = tt->logout - bp->ut_tv.tv_sec; if (sflag) { printf(" (%8ld)\n", (long)delta); } else { @@ -381,7 +384,7 @@ printentry(struct utmp *bp, struct ttytab *tt) * see if want this entry */ int -want(struct utmp *bp) +want(struct utmpx *bp) { ARG *step; @@ -394,15 +397,15 @@ want(struct utmp *bp) for (step = arglist; step; step = step->next) switch(step->type) { case HOST_TYPE: - if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE)) + if (!strcasecmp(step->name, bp->ut_host)) return (YES); break; case TTY_TYPE: - if (!strncmp(step->name, bp->ut_line, UT_LINESIZE)) + if (!strcmp(step->name, bp->ut_line)) return (YES); break; case USER_TYPE: - if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE)) + if (!strcmp(step->name, bp->ut_user)) return (YES); break; } @@ -552,25 +555,3 @@ terr: errx(1, "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); return timet; } - - -/* - * onintr -- - * on interrupt, we inform the user how far we've gotten - */ -void -onintr(int signo) -{ - char ct[80]; - struct tm *tm; - time_t t = _int_to_time(buf[0].ut_time); - - tm = localtime(&t); - (void) strftime(ct, sizeof(ct), - d_first ? "%a %e %b %R" : "%a %b %e %R", - tm); - printf("\ninterrupted %s\n", ct); - if (signo == SIGINT) - exit(1); - (void)fflush(stdout); /* fix required for rsh */ -} -- cgit v1.1