summaryrefslogtreecommitdiffstats
path: root/usr.bin/last/last.c
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2010-01-13 18:06:31 +0000
committered <ed@FreeBSD.org>2010-01-13 18:06:31 +0000
commit6d640118578b872e41214af63f644eb553348703 (patch)
treec38b28bce35df205a85ee167b4e0dcc10e5afdb6 /usr.bin/last/last.c
parent3ad23bc14fedcc56d917aab8b3f25e3a0393631d (diff)
downloadFreeBSD-src-6d640118578b872e41214af63f644eb553348703.zip
FreeBSD-src-6d640118578b872e41214af63f644eb553348703.tar.gz
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.
Diffstat (limited to 'usr.bin/last/last.c')
-rw-r--r--usr.bin/last/last.c185
1 files changed, 83 insertions, 102 deletions
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 <time.h>
#include <timeconv.h>
#include <unistd.h>
-#include <utmp.h>
+#include <utmpx.h>
#include <sys/queue.h>
#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 */
-}
OpenPOWER on IntegriCloud