summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authordd <dd@FreeBSD.org>2001-05-28 01:22:37 +0000
committerdd <dd@FreeBSD.org>2001-05-28 01:22:37 +0000
commit315d04216a024b672d86764ea09a860493672bb5 (patch)
tree1982e917eadf8a3f091db5d61faf2e0f92e95468 /usr.bin
parent723d7c5d157709bfe0f34cdb3ea2060ca183657b (diff)
downloadFreeBSD-src-315d04216a024b672d86764ea09a860493672bb5.zip
FreeBSD-src-315d04216a024b672d86764ea09a860493672bb5.tar.gz
Implement snapshots. The new -d option allows the user to find out
who was logged in at a certain time and date. Obtained from: OpenBSD
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/last/last.180
-rw-r--r--usr.bin/last/last.c241
2 files changed, 248 insertions, 73 deletions
diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1
index d7fd095..ea9d25d 100644
--- a/usr.bin/last/last.1
+++ b/usr.bin/last/last.1
@@ -32,7 +32,7 @@
.\" @(#)last.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
-.Dd June 6, 1993
+.Dd May 2, 2001
.Dt LAST 1
.Os BSD 4
.Sh NAME
@@ -41,6 +41,15 @@
.Sh SYNOPSIS
.Nm
.Op Fl Ns Ar n
+.Oo
+.Fl d
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Op Ar MM DD
+.Ar hh mm
+.Op Ar .SS
+.Sm on
+.Oc
.Op Fl f Ar file
.Op Fl h Ar host
.Op Fl s
@@ -49,12 +58,13 @@
.Op user ...
.Sh DESCRIPTION
.Nm Last
-will list the sessions of specified
+will either list the sessions of specified
.Ar users ,
.Ar ttys ,
and
.Ar hosts ,
-in reverse time order.
+in reverse time order,
+or list the users logged in at a specified date and time.
Each line of output contains
the user name, the tty from which the session was conducted, any
hostname, the start and stop times for the session, and the duration
@@ -69,6 +79,65 @@ will so indicate.
Limits the report to
.Ar n
lines.
+.It Fl d Ar date
+Specify the snapshot date and time.
+All users logged in at the snapshot date and time will
+be reported.
+This may be used with the
+.Fl f
+option to derive the results from stored wtmp files.
+When this argument is provided, all other options except for
+.Fl f
+and
+.Fl Ar n
+are ignored.
+The argument should be in the form
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Op Ar MM DD
+.Ar hh mm
+.Op Ar .SS
+.Sm on
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+If
+.Ar YY
+is specified, but
+.Ar CC
+is not, a value for
+.Ar YY
+between 69 and 99 results in a
+.Ar CC
+value of 19.
+Otherwise, a
+.Ar CC
+value of 20 is used.
+.It Ar MM
+Month of the year, from 1 to 12.
+.It Ar DD
+Day of the month, from 1 to 31.
+.It Ar hh
+Hour of the day, from 0 to 23.
+.It Ar mm
+Minute of the hour, from 0 to 59.
+.It Ar SS
+Second of the minute, from 0 to 61.
+.El
+.Pp
+If the
+.Ar CC
+and
+.Ar YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Ar SS
+letter pair is not specified, the value defaults to 0.
.It Fl f Ar file
.Nm Last
reads the file
@@ -94,8 +163,9 @@ Widen the duration field to show seconds, as well as the
default days, hours and minutes.
.El
.Pp
-If
-multiple arguments are given, the information which applies to any of the
+If multiple arguments are given,
+and a snapshot time is not specified,
+the information which applies to any of the
arguments is printed, e.g.,
.Dq Li "last root -t console"
would list all of
diff --git a/usr.bin/last/last.c b/usr.bin/last/last.c
index 57412b5..79d6010 100644
--- a/usr.bin/last/last.c
+++ b/usr.bin/last/last.c
@@ -62,6 +62,7 @@ static char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94";
#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 */
@@ -89,11 +90,16 @@ static char *file = _PATH_WTMP; /* wtmp file */
static int sflag = 0; /* show delta in seconds */
static int width = 5; /* show seconds in delta */
static int d_first;
+static time_t snaptime; /* if != 0, we will only
+ * report users logged in
+ * at this snapshot time
+ */
void addarg __P((int, char *));
void hostconv __P((char *));
void onintr __P((int));
char *ttyconv __P((char *));
+time_t dateconv __P((char *));
int want __P((struct utmp *));
void wtmp __P((void));
@@ -117,7 +123,8 @@ main(argc, argv)
d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
maxrec = -1;
- while ((ch = getopt(argc, argv, "0123456789f:h:st:w")) != -1)
+ snaptime = 0;
+ while ((ch = getopt(argc, argv, "0123456789d:f:h:st:w")) != -1)
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@@ -135,6 +142,9 @@ main(argc, argv)
exit(0);
}
break;
+ case 'd':
+ snaptime = dateconv(optarg);
+ break;
case 'f':
file = optarg;
break;
@@ -189,6 +199,7 @@ wtmp()
char *crmsg;
char ct[80];
struct tm *tm;
+ int snapfound = 0; /* found snapshot entry? */
LIST_INIT(&ttylist);
@@ -220,7 +231,19 @@ wtmp()
currentout = -bp->ut_time;
crmsg = strncmp(bp->ut_name, "shutdown",
UT_NAMESIZE) ? "crash" : "shutdown";
- if (want(bp)) {
+ /*
+ * if we're in snapshot mode, we want to
+ * exit if this shutdown/reboot appears
+ * while we we are tracking the active
+ * range
+ */
+ if (snaptime && snapfound)
+ return;
+ /*
+ * don't print shutdown/reboot entries
+ * unless flagged for
+ */
+ if (!snaptime && want(bp)) {
tm = localtime(&bp->ut_time);
(void) strftime(ct, sizeof(ct),
d_first ? "%a %e %b %R" :
@@ -243,7 +266,7 @@ wtmp()
*/
if ((bp->ut_line[0] == '{' || bp->ut_line[0] == '|')
&& !bp->ut_line[1]) {
- if (want(bp)) {
+ if (want(bp) && !snaptime) {
tm = localtime(&bp->ut_time);
(void) strftime(ct, sizeof(ct),
d_first ? "%a %e %b %R" :
@@ -259,77 +282,82 @@ wtmp()
}
continue;
}
- if (bp->ut_name[0] == '\0' || want(bp)) {
- /* find associated tty */
- LIST_FOREACH(tt, &ttylist, list)
- if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE))
- break;
-
- if (tt == NULL) {
- /* add new one */
- tt = malloc(sizeof(struct ttytab));
- if (tt == NULL)
- err(1, "malloc failure");
- tt->logout = currentout;
- strncpy(tt->tty, bp->ut_line, UT_LINESIZE);
- LIST_INSERT_HEAD(&ttylist, tt, list);
- }
-
- if (bp->ut_name[0]) {
- /*
- * 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';
- tm = localtime(&bp->ut_time);
- (void) strftime(ct, sizeof(ct),
- d_first ? "%a %e %b %R" :
- "%a %b %e %R",
- tm);
- printf("%-*.*s %-*.*s %-*.*s %s ",
- UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
- UT_LINESIZE, UT_LINESIZE, bp->ut_line,
- UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
- ct);
- if (!tt->logout)
- puts(" still logged in");
+ /* find associated tty */
+ LIST_FOREACH(tt, &ttylist, list)
+ if (!strncmp(tt->tty, bp->ut_line, UT_LINESIZE))
+ break;
+
+ if (tt == NULL) {
+ /* add new one */
+ tt = malloc(sizeof(struct ttytab));
+ if (tt == NULL)
+ err(1, "malloc failure");
+ tt->logout = currentout;
+ strncpy(tt->tty, bp->ut_line, UT_LINESIZE);
+ LIST_INSERT_HEAD(&ttylist, 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 &&
+ (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';
+ tm = localtime(&bp->ut_time);
+ (void) strftime(ct, sizeof(ct),
+ d_first ? "%a %e %b %R" :
+ "%a %b %e %R",
+ tm);
+ printf("%-*.*s %-*.*s %-*.*s %s ",
+ UT_NAMESIZE, UT_NAMESIZE, bp->ut_name,
+ UT_LINESIZE, UT_LINESIZE, bp->ut_line,
+ UT_HOSTSIZE, UT_HOSTSIZE, bp->ut_host,
+ ct);
+ if (!tt->logout)
+ puts(" still logged in");
+ else {
+ if (tt->logout < 0) {
+ tt->logout = -tt->logout;
+ printf("- %s", crmsg);
+ }
else {
- if (tt->logout < 0) {
- tt->logout = -tt->logout;
- printf("- %s", crmsg);
- }
- else {
- tm = localtime(&tt->logout);
- (void) strftime(ct, sizeof(ct), "%R", tm);
- printf("- %s", ct);
- }
- delta = tt->logout - bp->ut_time;
- if ( sflag ) {
- printf(" (%8lu)\n",
- delta);
- } else {
- tm = gmtime(&delta);
- (void) strftime(ct, sizeof(ct),
- width >= 8 ? "%T" : "%R",
- tm);
- if (delta < 86400)
+ tm = localtime(&tt->logout);
+ (void) strftime(ct, sizeof(ct), "%R", tm);
+ printf("- %s", ct);
+ }
+ delta = tt->logout - bp->ut_time;
+ if ( sflag ) {
+ printf(" (%8lu)\n",
+ delta);
+ } else {
+ tm = gmtime(&delta);
+ (void) strftime(ct, sizeof(ct),
+ width >= 8 ? "%T" : "%R",
+ tm);
+ if (delta < 86400)
printf(" (%s)\n", ct);
- else
+ else
printf(" (%ld+%s)\n",
delta / 86400, ct);
- }
}
- LIST_REMOVE(tt, list);
- free(tt);
- if (maxrec != -1 && !--maxrec)
- return;
- } else {
- tt->logout = bp->ut_time;
}
+ LIST_REMOVE(tt, list);
+ free(tt);
+ if (maxrec != -1 && !--maxrec)
+ return;
+ } else {
+ tt->logout = bp->ut_time;
}
}
}
@@ -348,6 +376,9 @@ want(bp)
{
ARG *step;
+ if (snaptime)
+ return (NO);
+
if (!arglist)
return (YES);
@@ -446,6 +477,80 @@ ttyconv(arg)
}
/*
+ * dateconv --
+ * Convert the snapshot time in command line given in the format
+ * [[CC]YY]MMDDhhmm[.SS]] to a time_t.
+ * Derived from atime_arg1() in usr.bin/touch/touch.c
+ */
+time_t
+dateconv(arg)
+ char *arg;
+{
+ time_t timet;
+ struct tm *t;
+ int yearset;
+ char *p;
+
+ /* Start with the current time. */
+ if (time(&timet) < 0)
+ err(1, "time");
+ if ((t = localtime(&timet)) == NULL)
+ err(1, "localtime");
+
+ /* [[CC]YY]MMDDhhmm[.SS] */
+ if ((p = strchr(arg, '.')) == NULL)
+ t->tm_sec = 0; /* Seconds defaults to 0. */
+ else {
+ if (strlen(p + 1) != 2)
+ goto terr;
+ *p++ = '\0';
+ t->tm_sec = ATOI2(p);
+ }
+
+ yearset = 0;
+ switch (strlen(arg)) {
+ case 12: /* CCYYMMDDhhmm */
+ t->tm_year = ATOI2(arg);
+ t->tm_year *= 100;
+ yearset = 1;
+ /* FALLTHOUGH */
+ case 10: /* YYMMDDhhmm */
+ if (yearset) {
+ yearset = ATOI2(arg);
+ t->tm_year += yearset;
+ } else {
+ yearset = ATOI2(arg);
+ if (yearset < 69)
+ t->tm_year = yearset + 2000;
+ else
+ t->tm_year = yearset + 1900;
+ }
+ t->tm_year -= 1900; /* Convert to UNIX time. */
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ t->tm_mon = ATOI2(arg);
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ break;
+ case 4: /* hhmm */
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ break;
+ default:
+ goto terr;
+ }
+ t->tm_isdst = -1; /* Figure out DST. */
+ timet = mktime(t);
+ if (timet == -1)
+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
*/
OpenPOWER on IntegriCloud