Add wtmpx support.

This commit is contained in:
christos 2003-02-17 15:08:57 +00:00
parent d62eb597a2
commit 8475773db1
4 changed files with 389 additions and 225 deletions

View File

@ -1,6 +1,7 @@
# $NetBSD: Makefile,v 1.5 1997/10/19 03:44:21 lukem Exp $
# $NetBSD: Makefile,v 1.6 2003/02/17 15:08:57 christos Exp $
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= last
CPPFLAGS+=-DSUPPORT_UTMPX -DSUPPORT_UTMP
.include <bsd.prog.mk>

View File

@ -1,4 +1,4 @@
.\" $NetBSD: last.1,v 1.9 2002/09/30 11:09:04 grant Exp $
.\" $NetBSD: last.1,v 1.10 2003/02/17 15:08:57 christos Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -46,6 +46,9 @@
.Op Fl f Ar file
.Op Fl h Ar host
.Op Fl t Ar tty
.Op Fl L Ar linesize
.Op Fl N Ar namesize
.Op Fl H Ar hostsize
.Op user ...
.Sh DESCRIPTION
.Nm
@ -70,7 +73,14 @@ will so indicate.
reads the file
.Ar file
instead of the default,
.Pa /var/log/wtmpx
or
.Pa /var/log/wtmp .
If the file ends with `x', it is treated as a
.Xr utmpx 5
format file, else it is treated as a
.Xr utmp 5
format file.
.It Fl Ar n
Limits the report to
.Ar n
@ -88,6 +98,12 @@ equivalent to
names may be names or internet numbers.
.It Fl T
Display better time information, including the year and seconds.
.It Fl L Ar linesize
Use the provided linesize as the width to format the tty field.
.It Fl N Ar namesize
Use the provided namesize as the width to format the login name field.
.It Fl H Ar hostsize
Use the provided hostsize as the width to format the host name field.
.El
.Pp
If
@ -117,12 +133,15 @@ If interrupted with a quit signal
indicates how
far the search has progressed and then continues.
.Sh FILES
.Bl -tag -width /var/log/wtmp -compact
.Bl -tag -width /var/log/wtmpx -compact
.It Pa /var/log/wtmpx
login data base
.It Pa /var/log/wtmp
login data base
.El
.Sh SEE ALSO
.Xr lastcomm 1 ,
.Xr utmpx 5 ,
.Xr utmp 5 ,
.Xr ac 8
.Sh HISTORY

View File

@ -1,4 +1,4 @@
/* $NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $ */
/* $NetBSD: last.c,v 1.16 2003/02/17 15:08:57 christos Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
@ -44,7 +44,7 @@ __COPYRIGHT(
#if 0
static char sccsid[] = "@(#)last.c 8.2 (Berkeley) 4/2/94";
#endif
__RCSID("$NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $");
__RCSID("$NetBSD: last.c,v 1.16 2003/02/17 15:08:57 christos Exp $");
#endif /* not lint */
#include <sys/param.h>
@ -60,7 +60,23 @@ __RCSID("$NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $");
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#ifdef SUPPORT_UTMPX
#include <utmpx.h>
#endif
#ifdef SUPPORT_UTMP
#include <utmp.h>
#endif
#ifndef UT_NAMESIZE
#define UT_NAMESIZE 8
#define UT_LINESIZE 8
#define UT_HOSTSIZE 16
#endif
#ifndef SIGNATURE
#define SIGNATURE -1
#endif
#define NO 0 /* false/no */
#define YES 1 /* true/yes */
@ -76,7 +92,7 @@ __RCSID("$NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $");
#define TIMEONLY 0x2 /* show time only, not date */
#define GMT 0x4 /* show time at GMT, for offsets only */
static struct utmp buf[1024]; /* utmp read buffer */
#define MAXUTMP 1024;
typedef struct arg {
char *name; /* argument */
@ -86,40 +102,61 @@ typedef struct arg {
int type; /* type of arg */
struct arg *next; /* linked list pointer */
} ARG;
ARG *arglist; /* head of linked list */
static ARG *arglist; /* head of linked list */
typedef struct ttytab {
time_t logout; /* log out time */
char tty[UT_LINESIZE + 1]; /* terminal name */
char tty[128]; /* terminal name */
struct ttytab *next; /* linked list pointer */
} TTY;
TTY *ttylist; /* head of linked list */
static TTY *ttylist; /* head of linked list */
static time_t currentout; /* current logout value */
static long maxrec; /* records to display */
static char *file = _PATH_WTMP; /* wtmp file */
static int fulltime = 0; /* Display seconds? */
int main __P((int, char *[]));
void addarg __P((int, char *));
TTY *addtty __P((char *));
void hostconv __P((char *));
void onintr __P((int));
char *ttyconv __P((char *));
int want __P((struct utmp *, int));
void wtmp __P((void));
char *fmttime __P((time_t, int));
int main(int, char *[]);
static void addarg(int, char *);
static TTY *addtty(const char *);
static void hostconv(char *);
static char *ttyconv(char *);
#ifdef SUPPORT_UTMPX
static void wtmpx(const char *, int, int, int);
#endif
#ifdef SUPPORT_UTMP
static void wtmp(const char *, int, int, int);
#endif
static char *fmttime(time_t, int);
static void usage(void);
static
void usage(void)
{
(void)fprintf(stderr, "Usage: %s [-#%s] [-f file] [-t tty]"
" [-h hostname] [-T] [user ...]\n", getprogname(),
#ifdef SUPPORT_UTMPX
"w"
#else
""
#endif
);
exit(1);
}
int
main(argc, argv)
int argc;
char *argv[];
main(int argc, char *argv[])
{
int ch;
char *p;
char *file = NULL;
int namesize = UT_NAMESIZE;
int linesize = UT_LINESIZE;
int hostsize = UT_HOSTSIZE;
maxrec = -1;
while ((ch = getopt(argc, argv, "0123456789f:h:t:T")) != -1)
while ((ch = getopt(argc, argv, "0123456789f:h:H:L:N:t:T")) != -1)
switch (ch) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@ -147,14 +184,21 @@ main(argc, argv)
case 't':
addarg(TTY_TYPE, ttyconv(optarg));
break;
case 'U':
namesize = atoi(optarg);
break;
case 'L':
linesize = atoi(optarg);
break;
case 'H':
hostsize = atoi(optarg);
break;
case 'T':
fulltime = 1;
break;
case '?':
default:
(void)fprintf(stderr,
"usage: last [-#] [-f file] [-t tty] [-h hostname] [-T] [user ...]\n");
exit(1);
usage();
}
if (argc) {
@ -168,186 +212,50 @@ main(argc, argv)
addarg(USER_TYPE, *argv);
}
}
wtmp();
if (file == NULL) {
#ifdef SUPPORT_UTMPX
if (access(_PATH_WTMPX, R_OK) == 0)
file = _PATH_WTMPX;
else
#endif
#ifdef SUPPORT_UTMP
if (access(_PATH_WTMP, R_OK) == 0)
file = _PATH_WTMP;
#endif
if (file == NULL)
#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
errx(1, "Cannot access `%s' or `%s'", _PATH_WTMPX,
_PATH_WTMP);
#elif defined(SUPPORT_UTMPX)
errx(1, "Cannot access `%s'", _PATH_WTMPX);
#elif defined(SUPPORT_UTMP)
errx(1, "Cannot access `%s'", _PATH_WTMP);
#else
errx(1, "No utmp or utmpx support compiled in.");
#endif
}
#if defined(SUPPORT_UTMPX) && defined(SUPPORT_UTMP)
if (file[strlen(file) - 1] == 'x')
wtmpx(file, namesize, linesize, hostsize);
else
wtmp(file, namesize, linesize, hostsize);
#elif defined(SUPPORT_UTMPX)
wtmpx(file, namesize, linesize, hostsize);
#elif defined(SUPPORT_UTMP)
wtmp(file, namesize, linesize, hostsize);
#else
errx(1, "Nu utmp or utmpx support compiled in.");
#endif
exit(0);
}
/*
* wtmp --
* read through the wtmp file
*/
void
wtmp()
{
struct utmp *bp; /* current structure */
TTY *T; /* tty list entry */
struct stat stb; /* stat of file for size */
time_t delta; /* time difference */
off_t bl;
int bytes, wfd;
char *ct, *crmsg;
crmsg = NULL;
if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
err(1, "%s", file);
bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
(void)time(&buf[0].ut_time);
(void)signal(SIGINT, onintr);
(void)signal(SIGQUIT, onintr);
while (--bl >= 0) {
if (lseek(wfd, bl * sizeof(buf), SEEK_SET) == -1 ||
(bytes = read(wfd, buf, sizeof(buf))) == -1)
err(1, "%s", file);
for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
/*
* if the terminal line is '~', the machine stopped.
* see utmp(5) for more info.
*/
if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
/* everybody just logged out */
for (T = ttylist; T; T = T->next)
T->logout = -bp->ut_time;
currentout = -bp->ut_time;
crmsg = strncmp(bp->ut_name, "shutdown",
UT_NAMESIZE) ? "crash" : "shutdown";
if (want(bp, NO)) {
ct = fmttime(bp->ut_time, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
(int)UT_NAMESIZE, (int)UT_NAMESIZE,
bp->ut_name, (int)UT_LINESIZE,
(int)UT_LINESIZE, bp->ut_line,
(int)UT_HOSTSIZE, (int)UT_HOSTSIZE,
bp->ut_host, ct);
if (maxrec != -1 && !--maxrec)
return;
}
continue;
}
/*
* 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]) {
if (want(bp, NO)) {
ct = fmttime(bp->ut_time, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
(int)UT_NAMESIZE, (int)UT_NAMESIZE,
bp->ut_name,
(int)UT_LINESIZE, (int)UT_LINESIZE,
bp->ut_line,
(int)UT_HOSTSIZE, (int)UT_HOSTSIZE,
bp->ut_host,
ct);
if (maxrec && !--maxrec)
return;
}
continue;
}
/* find associated tty */
for (T = ttylist;; T = T->next) {
if (!T) {
/* add new one */
T = addtty(bp->ut_line);
break;
}
if (!strncmp(T->tty, bp->ut_line, UT_LINESIZE))
break;
}
if (bp->ut_name[0] && want(bp, YES)) {
ct = fmttime(bp->ut_time, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s ",
(int)UT_NAMESIZE, (int)UT_NAMESIZE, bp->ut_name,
(int)UT_LINESIZE, (int)UT_LINESIZE, bp->ut_line,
(int)UT_HOSTSIZE, (int)UT_HOSTSIZE, bp->ut_host,
ct);
if (!T->logout)
puts(" still logged in");
else {
if (T->logout < 0) {
T->logout = -T->logout;
printf("- %s", crmsg);
}
else
printf("- %s",
fmttime(T->logout,
fulltime | TIMEONLY));
delta = T->logout - bp->ut_time;
if (delta < SECSPERDAY)
printf(" (%s)\n",
fmttime(delta,
fulltime | TIMEONLY | GMT));
else
printf(" (%ld+%s)\n",
delta / SECSPERDAY,
fmttime(delta,
fulltime | TIMEONLY | GMT));
}
if (maxrec != -1 && !--maxrec)
return;
}
T->logout = bp->ut_time;
}
}
fulltime = 1; /* show full time */
ct = fmttime(buf[0].ut_time, FULLTIME);
printf("\nwtmp begins %s\n", ct);
}
/*
* want --
* see if want this entry
*/
int
want(bp, check)
struct utmp *bp;
int check;
{
ARG *step;
if (check) {
/*
* 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';
}
if (!arglist)
return (YES);
for (step = arglist; step; step = step->next)
switch(step->type) {
case HOST_TYPE:
if (!strncasecmp(step->name, bp->ut_host, UT_HOSTSIZE))
return (YES);
break;
case TTY_TYPE:
if (!strncmp(step->name, bp->ut_line, UT_LINESIZE))
return (YES);
break;
case USER_TYPE:
if (!strncmp(step->name, bp->ut_name, UT_NAMESIZE))
return (YES);
break;
}
return (NO);
}
/*
* addarg --
* add an entry to a linked list of arguments
*/
void
addarg(type, arg)
int type;
char *arg;
static void
addarg(int type, char *arg)
{
ARG *cur;
@ -363,9 +271,8 @@ addarg(type, arg)
* addtty --
* add an entry to a linked list of ttys
*/
TTY *
addtty(ttyname)
char *ttyname;
static TTY *
addtty(const char *ttyname)
{
TTY *cur;
@ -373,7 +280,7 @@ addtty(ttyname)
err(1, "malloc failure");
cur->next = ttylist;
cur->logout = currentout;
memmove(cur->tty, ttyname, UT_LINESIZE);
memmove(cur->tty, ttyname, sizeof(cur->tty));
return (ttylist = cur);
}
@ -383,9 +290,8 @@ addtty(ttyname)
* has a domain attached that is the same as the current domain, rip
* off the domain suffix since that's what login(1) does.
*/
void
hostconv(arg)
char *arg;
static void
hostconv(char *arg)
{
static int first = 1;
static char *hostdot, name[MAXHOSTNAMELEN + 1];
@ -408,9 +314,8 @@ hostconv(arg)
* ttyconv --
* convert tty to correct name.
*/
char *
ttyconv(arg)
char *arg;
static char *
ttyconv(char *arg)
{
char *mval;
@ -439,10 +344,8 @@ ttyconv(arg)
* fmttime --
* return pointer to (static) formatted time string.
*/
char *
fmttime(t, flags)
time_t t;
int flags;
static char *
fmttime(time_t t, int flags)
{
struct tm *tm;
static char tbuf[TBUFLEN];
@ -456,17 +359,33 @@ fmttime(t, flags)
return (tbuf);
}
/*
* onintr --
* on interrupt, we inform the user how far we've gotten
*/
void
onintr(signo)
int signo;
{
#ifdef SUPPORT_UTMP
#define TYPE(a) 0
#define NAMESIZE UT_NAMESIZE
#define LINESIZE UT_LINESIZE
#define HOSTSIZE UT_HOSTSIZE
#define ut_timefld ut_time
#define FIRSTVALID 0
#include "want.c"
#undef TYPE(a)
#undef NAMESIZE
#undef LINESIZE
#undef HOSTSIZE
#undef ut_timefld
#undef FIRSTVALID
#endif
printf("\ninterrupted %s\n", fmttime(buf[0].ut_time, FULLTIME));
if (signo == SIGINT)
exit(1);
(void)fflush(stdout); /* fix required for rsh */
}
#ifdef SUPPORT_UTMPX
#define utmp utmpx
#define want wantx
#define wtmp wtmpx
#define buf bufx
#define onintr onintrx
#define TYPE(a) (a)->ut_type
#define NAMESIZE UTX_USERSIZE
#define LINESIZE UTX_LINESIZE
#define HOSTSIZE UTX_HOSTSIZE
#define ut_timefld ut_xtime
#define FIRSTVALID 1
#include "want.c"
#endif

225
usr.bin/last/want.c Normal file
View File

@ -0,0 +1,225 @@
/* $NetBSD: want.c,v 1.1 2003/02/17 15:08:57 christos Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
static struct utmp *buf;
static void onintr(int);
static int want(struct utmp *, int);
/*
* wtmp --
* read through the wtmp file
*/
void
wtmp(const char *file, int namesz, int linesz, int hostsz)
{
struct utmp *bp; /* current structure */
TTY *T; /* tty list entry */
struct stat stb; /* stat of file for sz */
time_t delta; /* time difference */
off_t bl;
int bytes, wfd;
char *ct, *crmsg;
size_t len = sizeof(*buf) * MAXUTMP;
if ((buf = malloc(len)) == NULL)
err(1, "Cannot allocate utmp buffer");
crmsg = NULL;
if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1)
err(1, "%s", file);
bl = (stb.st_size + len - 1) / len;
buf[FIRSTVALID].ut_timefld = time(NULL);
(void)signal(SIGINT, onintr);
(void)signal(SIGQUIT, onintr);
while (--bl >= 0) {
if (lseek(wfd, bl * len, SEEK_SET) == -1 ||
(bytes = read(wfd, buf, len)) == -1)
err(1, "%s", file);
for (bp = &buf[bytes / sizeof(*buf) - 1]; bp >= buf; --bp) {
/*
* if the terminal line is '~', the machine stopped.
* see utmp(5) for more info.
*/
if (bp->ut_line[0] == '~' && !bp->ut_line[1]) {
/* everybody just logged out */
for (T = ttylist; T; T = T->next)
T->logout = -bp->ut_timefld;
currentout = -bp->ut_timefld;
crmsg = strncmp(bp->ut_name, "shutdown",
namesz) ? "crash" : "shutdown";
if (want(bp, NO)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
namesz, namesz, bp->ut_name,
linesz, linesz, bp->ut_line,
hostsz, hostsz, bp->ut_host, ct);
if (maxrec != -1 && !--maxrec)
return;
}
continue;
}
/*
* 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]) {
if (want(bp, NO)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s\n",
namesz, namesz,
bp->ut_name,
linesz, linesz,
bp->ut_line,
hostsz, hostsz,
bp->ut_host,
ct);
if (maxrec && !--maxrec)
return;
}
continue;
}
/* find associated tty */
for (T = ttylist;; T = T->next) {
if (!T) {
/* add new one */
T = addtty(bp->ut_line);
break;
}
if (!strncmp(T->tty, bp->ut_line, LINESIZE))
break;
}
if (TYPE(bp) == SIGNATURE)
continue;
if (bp->ut_name[0] && want(bp, YES)) {
ct = fmttime(bp->ut_timefld, fulltime);
printf("%-*.*s %-*.*s %-*.*s %s ",
namesz, namesz, bp->ut_name,
linesz, linesz, bp->ut_line,
hostsz, hostsz, bp->ut_host,
ct);
if (!T->logout)
puts(" still logged in");
else {
if (T->logout < 0) {
T->logout = -T->logout;
printf("- %s", crmsg);
}
else
printf("- %s",
fmttime(T->logout,
fulltime | TIMEONLY));
delta = T->logout - bp->ut_timefld;
if (delta < SECSPERDAY)
printf(" (%s)\n",
fmttime(delta,
fulltime | TIMEONLY | GMT));
else
printf(" (%ld+%s)\n",
delta / SECSPERDAY,
fmttime(delta,
fulltime | TIMEONLY | GMT));
}
if (maxrec != -1 && !--maxrec)
return;
}
T->logout = bp->ut_timefld;
}
}
fulltime = 1; /* show full time */
crmsg = fmttime(buf[FIRSTVALID].ut_timefld, FULLTIME);
if ((ct = strrchr(file, '/')) != NULL)
ct++;
printf("\n%s begins %s\n", ct ? ct : file, crmsg);
}
/*
* want --
* see if want this entry
*/
static int
want(struct utmp *bp, int check)
{
ARG *step;
if (check) {
/*
* 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';
}
if (!arglist)
return (YES);
for (step = arglist; step; step = step->next)
switch(step->type) {
case HOST_TYPE:
if (!strncasecmp(step->name, bp->ut_host, HOSTSIZE))
return (YES);
break;
case TTY_TYPE:
if (!strncmp(step->name, bp->ut_line, LINESIZE))
return (YES);
break;
case USER_TYPE:
if (!strncmp(step->name, bp->ut_name, NAMESIZE))
return (YES);
break;
}
return (NO);
}
/*
* onintr --
* on interrupt, we inform the user how far we've gotten
*/
static void
onintr(int signo)
{
printf("\ninterrupted %s\n", fmttime(buf[FIRSTVALID].ut_timefld,
FULLTIME));
if (signo == SIGINT)
exit(1);
(void)fflush(stdout); /* fix required for rsh */
}