last and init - update for wtmpx
authorAlex Hornung <ahornung@gmail.com>
Wed, 15 Dec 2010 19:06:01 +0000 (19:06 +0000)
committerAlex Hornung <ahornung@gmail.com>
Wed, 15 Dec 2010 19:06:01 +0000 (19:06 +0000)
sbin/init/Makefile
sbin/init/init.c
usr.bin/last/Makefile
usr.bin/last/last.c

index 4a63947..1aae303 100644 (file)
@@ -10,7 +10,7 @@ INSTALLFLAGS= -b -B.bak
 .if !defined(NOFSCHG)
 INSTALLFLAGS+= -fschg
 .endif
-CFLAGS+=-DDEBUGSHELL -DSECURE -DLOGIN_CAP -DCOMPAT_SYSV_INIT
+CFLAGS+=-DDEBUGSHELL -DSECURE -DLOGIN_CAP -DCOMPAT_SYSV_INIT -DSUPPORT_UTMPX
 DPADD= ${LIBUTIL} ${LIBCRYPT}
 LDADD= -lutil -lcrypt
 
index 49a66ea..2734f61 100644 (file)
@@ -50,6 +50,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <libutil.h>
+#include <utmpx.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdio.h>
@@ -109,7 +110,7 @@ static void setctty(const char *);
 typedef struct init_session {
        int     se_index;               /* index of entry in ttys file */
        pid_t   se_process;             /* controlling process */
-       time_t  se_started;             /* used to avoid thrashing */
+       struct timeval  se_started;             /* used to avoid thrashing */
        int     se_flags;               /* status of session */
 #define        SE_SHUTDOWN     0x1             /* session won't be restarted */
 #define        SE_PRESENT      0x2             /* session is in /etc/ttys */
@@ -137,6 +138,14 @@ static void         badsys(int);
 static int      runshutdown(void);
 static char    *strk(char *);
 
+#define        DEATH           'd'
+#define        SINGLE_USER     's'
+#define        RUNCOM          'r'
+#define        READ_TTYS       't'
+#define        MULTI_USER      'm'
+#define        CLEAN_TTYS      'T'
+#define        CATATONIA       'c'
+
 static state_func_t    single_user(void);
 static state_func_t    runcom(void);
 static state_func_t    read_ttys(void);
@@ -171,6 +180,16 @@ static void        add_session(session_t *);
 static void    del_session(session_t *);
 static session_t *find_session(pid_t);
 
+#ifdef SUPPORT_UTMPX
+static struct timeval boot_time;
+state_t current_state = death;
+static void session_utmpx(const session_t *, int);
+static void make_utmpx(const char *, const char *, int, pid_t,
+    const struct timeval *, int);
+static char get_runlevel(const state_t);
+static void utmpx_set_runlevel(char, char);
+#endif
+
 static int Reboot = FALSE;
 static int howto = RB_AUTOBOOT;
 
@@ -179,6 +198,7 @@ static volatile sig_atomic_t clang;
 static session_t *sessions;
 state_t requested_transition = runcom;
 
+
 /*
  * The mother of all processes.
  */
@@ -191,6 +211,9 @@ main(int argc, char **argv)
        sigset_t mask;
        struct stat sts;
 
+#ifdef SUPPORT_UTMPX
+       (void)gettimeofday(&boot_time, NULL);
+#endif /* SUPPORT_UTMPX */
 
        /* Dispose of random users. */
        if (getuid() != 0)
@@ -560,8 +583,14 @@ setsecuritylevel(int newlevel)
 static void
 transition(state_t s)
 {
-       for (;;)
+       for (;;) {
+#ifdef SUPPORT_UTMPX
+               utmpx_set_runlevel(get_runlevel(current_state),
+                   get_runlevel(s));
+               current_state = s;
+#endif
                s = (state_t) (*s)();
+       }
 }
 
 /*
@@ -573,6 +602,10 @@ clear_session_logs(session_t *sp)
 {
        char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
 
+#ifdef SUPPORT_UTMPX
+       if (logoutx(line, 0, DEAD_PROCESS))
+                logwtmpx(line, "", "", 0, DEAD_PROCESS);
+#endif
        if (logout(line))
                logwtmp(line, "", "");
 }
@@ -836,6 +869,9 @@ runcom(void)
 
        runcom_mode = AUTOBOOT;         /* the default */
        /* NB: should send a message to the session logger to avoid blocking. */
+#ifdef SUPPORT_UTMPX
+       logwtmpx("~", "reboot", "", 0, INIT_PROCESS);
+#endif
        logwtmp("~", "reboot", "");
        return (state_func_t) read_ttys;
 }
@@ -874,6 +910,9 @@ add_session(session_t *sp)
 
        if ((*session_db->put)(session_db, &key, &data, 0))
                emergency("insert %d: %s", sp->se_process, strerror(errno));
+#ifdef SUPPORT_UTMPX
+       session_utmpx(sp, 1);
+#endif
 }
 
 /*
@@ -889,6 +928,9 @@ del_session(session_t *sp)
 
        if ((*session_db->del)(session_db, &key, 0))
                emergency("delete %d: %s", sp->se_process, strerror(errno));
+#ifdef SUPPORT_UTMPX
+       session_utmpx(sp, 0);
+#endif
 }
 
 /*
@@ -1061,6 +1103,25 @@ read_ttys(void)
        session_t *sp, *snext;
        struct ttyent *typ;
 
+#ifdef SUPPORT_UTMPX
+       if (sessions == NULL) {
+               struct stat st;
+
+               make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0);
+
+               /*
+                * If wtmpx is not empty, pick the down time from there
+                */
+               if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) {
+                       struct timeval down_time;
+
+                       TIMESPEC_TO_TIMEVAL(&down_time, 
+                           st.st_atime > st.st_mtime ?
+                           &st.st_atimespec : &st.st_mtimespec);
+                       make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0);
+               }
+       }
+#endif
        /*
         * Destroy any previous session state.
         * There shouldn't be any, but just in case...
@@ -1144,8 +1205,8 @@ start_getty(session_t *sp)
        int too_quick = 0;
        char term[64], *env[2];
 
-       if (current_time >= sp->se_started &&
-           current_time - sp->se_started < GETTY_SPACING) {
+       if (current_time >= sp->se_started.tv_sec &&
+           current_time - sp->se_started.tv_sec < GETTY_SPACING) {
                if (++sp->se_nspace > GETTY_NSPACE) {
                        sp->se_nspace = 0;
                        too_quick = 1;
@@ -1233,7 +1294,7 @@ collect_child(pid_t pid)
        }
 
        sp->se_process = pid;
-       sp->se_started = time(NULL);
+       gettimeofday(&sp->se_started, NULL);
        add_session(sp);
 }
 
@@ -1295,7 +1356,7 @@ multi_user(void)
                        break;
                }
                sp->se_process = pid;
-               sp->se_started = time(NULL);
+               gettimeofday(&sp->se_started, NULL);
                add_session(sp);
        }
 
@@ -1373,7 +1434,7 @@ clean_ttys(void)
                                ) {
                                /* Don't set SE_SHUTDOWN here */
                                sp->se_nspace = 0;
-                               sp->se_started = 0;
+                               sp->se_started.tv_sec = sp->se_started.tv_usec = 0;
                                kill(sp->se_process, SIGHUP);
                        }
                        if (old_getty)
@@ -1439,6 +1500,9 @@ death(void)
        static const int death_sigs[2] = { SIGTERM, SIGKILL };
 
        /* NB: should send a message to the session logger to avoid blocking. */
+#ifdef SUPPORT_UTMPX
+       logwtmpx("~", "shutdown", "", 0, INIT_PROCESS);
+#endif
        logwtmp("~", "shutdown", "");
 
        for (sp = sessions; sp; sp = sp->se_next) {
@@ -1663,3 +1727,86 @@ setprocresources(const char *cname)
        }
 }
 #endif
+
+#ifdef SUPPORT_UTMPX
+static void
+session_utmpx(const session_t *sp, int add)
+{
+       const char *name = sp->se_getty ? sp->se_getty :
+           (sp->se_window ? sp->se_window : "");
+       const char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
+
+       make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS,
+           sp->se_process, &sp->se_started, sp->se_index);
+}
+
+static void
+make_utmpx(const char *name, const char *line, int type, pid_t pid,
+    const struct timeval *tv, int session)
+{
+       struct utmpx ut;
+       const char *eline;
+
+       (void)memset(&ut, 0, sizeof(ut));
+       (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name));
+       ut.ut_type = type;
+       (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
+       ut.ut_pid = pid;
+       if (tv)
+               ut.ut_tv = *tv;
+       else
+               (void)gettimeofday(&ut.ut_tv, NULL);
+       ut.ut_session = session;
+
+       eline = line + strlen(line);
+       if ((size_t)(eline - line) >= sizeof(ut.ut_id))
+               line = eline - sizeof(ut.ut_id);
+       (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id));
+
+       if (pututxline(&ut) == NULL)
+               warning("can't add utmpx record for `%s': %m", ut.ut_line);
+       endutxent();
+}
+
+static char
+get_runlevel(const state_t s)
+{
+       if (s == (state_t)single_user)
+               return SINGLE_USER;
+       if (s == (state_t)runcom)
+               return RUNCOM;
+       if (s == (state_t)read_ttys)
+               return READ_TTYS;
+       if (s == (state_t)multi_user)
+               return MULTI_USER;
+       if (s == (state_t)clean_ttys)
+               return CLEAN_TTYS;
+       if (s == (state_t)catatonia)
+               return CATATONIA;
+       return DEATH;
+}
+
+static void
+utmpx_set_runlevel(char old, char new)
+{
+       struct utmpx ut;
+
+       /*
+        * Don't record any transitions until we did the first transition
+        * to read ttys, which is when we are guaranteed to have a read-write
+        * /var. Perhaps use a different variable for this?
+        */
+       if (sessions == NULL)
+               return;
+
+       (void)memset(&ut, 0, sizeof(ut));
+       (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new);
+       ut.ut_type = RUN_LVL;
+       (void)gettimeofday(&ut.ut_tv, NULL);
+       ut.ut_exit.e_exit = old;
+       ut.ut_exit.e_termination = new;
+       if (pututxline(&ut) == NULL)
+               warning("can't add utmpx record for `runlevel': %m");
+       endutxent();
+}
+#endif
index 8924186..5ef792d 100644 (file)
@@ -5,4 +5,6 @@
 PROG=  last
 WARNS?=        1
 
+CFLAGS+=-DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index 92c5969..0eb4f77 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: last.c,v 1.15 2000/06/30 06:19:58 simonb Exp $ */
+
 /*
  * Copyright (c) 1987, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * 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.
- *
- * $FreeBSD: src/usr.bin/last/last.c,v 1.10.6.11 2002/11/02 23:00:26 mux Exp $
- * $DragonFly: src/usr.bin/last/last.c,v 1.5 2004/09/14 00:13:36 drhodus Exp $
- *
- * @(#) Copyright (c) 1987, 1993, 1994 The Regents of the University of California.  All rights reserved.
- * @(#)last.c  8.2 (Berkeley) 4/2/94
  */
 
+#include <sys/cdefs.h>
+#ifndef lint
+#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 $");
+#endif /* not lint */
+
 #include <sys/param.h>
 #include <sys/stat.h>
 
 #include <err.h>
 #include <fcntl.h>
-#include <langinfo.h>
-#include <locale.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <tzfile.h>
 #include <unistd.h>
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+#ifdef SUPPORT_UTMP
 #include <utmp.h>
-#include <sys/queue.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 */
+
+#define        TBUFLEN 30                      /* length of time string buffer */
+#define        TFMT    "%a %b %d %R"           /* strftime format string */
+#define        LTFMT   "%a %b %d %Y %T"        /* strftime long format string */
+#define        TFMTS   "%R"                    /* strftime format string - time only */
+#define        LTFMTS  "%T"                    /* strftime long format string - " */
 
-#define        NO      0                               /* false/no */
-#define        YES     1                               /* true/yes */
-#define        ATOI2(ar)       ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+/* fmttime() flags */
+#define        FULLTIME        0x1             /* show year, seconds */
+#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 */
+       char    *name;                  /* argument */
 #define        HOST_TYPE       -2
 #define        TTY_TYPE        -3
 #define        USER_TYPE       -4
-       int     type;                           /* type of arg */
-       struct arg      *next;                  /* linked list pointer */
+       int     type;                   /* type of arg */
+       struct arg      *next;          /* linked list pointer */
 } ARG;
-ARG    *arglist;                               /* head of linked list */
-
-LIST_HEAD(ttylisthead, ttytab) ttylist;
-
-struct ttytab {
-       time_t  logout;                         /* log out time */
-       char    tty[UT_LINESIZE + 1];           /* terminal name */
-       LIST_ENTRY(ttytab) 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 int     sflag = 0;                      /* show delta in seconds */
-static int     width = 5;                      /* show seconds in delta */
-static int     yflag;                          /* show year */
-static int      d_first;
-static int     snapfound = 0;                  /* found snapshot entry? */
-static time_t  snaptime;                       /* if != 0, we will only
-                                                * report users logged in
-                                                * at this snapshot time
-                                                */
+static ARG     *arglist;               /* head of linked list */
+
+typedef struct ttytab {
+       time_t  logout;                 /* log out time */
+       char    tty[128];               /* terminal name */
+       struct ttytab   *next;          /* linked list pointer */
+} TTY;
+static TTY     *ttylist;               /* head of linked list */
+
+static time_t  currentout;             /* current logout value */
+static long    maxrec;                 /* records to display */
+static int     fulltime = 0;           /* Display seconds? */
 
 int     main(int, char *[]);
-void    addarg(int, char *);
-time_t  dateconv(char *);
-void    doentry(struct utmp *);
-void    hostconv(char *);
-void    onintr(int);
-void    printentry(struct utmp *, struct ttytab *);
-char   *ttyconv(char *);
-char   *ttyconv(char *);
-int     want(struct utmp *);
-void    usage(void);
-void    wtmp(void);
-
-void
-usage(void)
+
+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: last [-#] [-y] [-d [[CC]YY][MMDD]hhmm[.SS]] [-f file] [-h host]\n"
-"\t[-t tty] [-s|w] [user ...]\n");
+       (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(int argc, char **argv)
+main(int argc, char *argv[])
 {
        int ch;
        char *p;
-
-       (void) setlocale(LC_TIME, "");
-       d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+       char    *file = NULL;
+       int namesize = UT_NAMESIZE;
+       int linesize = UT_LINESIZE;
+       int hostsize = UT_HOSTSIZE;
 
        maxrec = -1;
-       snaptime = 0;
-       while ((ch = getopt(argc, argv, "0123456789d:f:h:st:wy")) != -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':
@@ -134,17 +159,15 @@ main(int argc, char **argv)
                         * a number after a dash.
                         */
                        if (maxrec == -1) {
-                               p = strchr(argv[optind - 1], ch);
-                               if (p == NULL)
-                                       p = strchr(argv[optind], ch);
-                               maxrec = atol(p);
+                               p = argv[optind - 1];
+                               if (p[0] == '-' && p[1] == ch && !p[2])
+                                       maxrec = atol(++p);
+                               else
+                                       maxrec = atol(argv[optind] + 1);
                                if (!maxrec)
                                        exit(0);
                        }
                        break;
-               case 'd':
-                       snaptime = dateconv(optarg);
-                       break;
                case 'f':
                        file = optarg;
                        break;
@@ -152,25 +175,26 @@ main(int argc, char **argv)
                        hostconv(optarg);
                        addarg(HOST_TYPE, optarg);
                        break;
-               case 's':
-                       sflag++;        /* Show delta as seconds */
-                       break;
                case 't':
                        addarg(TTY_TYPE, ttyconv(optarg));
                        break;
-               case 'w':
-                       width = 8;
+               case 'U':
+                       namesize = atoi(optarg);
+                       break;
+               case 'L':
+                       linesize = atoi(optarg);
+                       break;
+               case 'H':
+                       hostsize = atoi(optarg);
                        break;
-               case 'y':
-                       yflag++;
+               case 'T':
+                       fulltime = 1;
                        break;
                case '?':
                default:
                        usage();
                }
 
-       if (sflag && width == 8) usage();
-
        if (argc) {
                setlinebuf(stdout);
                for (argv += optind; *argv; ++argv) {
@@ -182,220 +206,50 @@ main(int argc, char **argv)
                        addarg(USER_TYPE, *argv);
                }
        }
-       wtmp();
-       exit(0);
-}
-
-/*
- * wtmp --
- *     read through the wtmp file
- */
-void
-wtmp(void)
-{
-       struct utmp     *bp;                    /* current structure */
-       struct stat     stb;                    /* stat of file for size */
-       long    bl;
-       int     bytes, wfd;
-       char ct[80];
-       struct tm *tm;
-
-       LIST_INIT(&ttylist);
-
-       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, (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);
-       }
-       tm = localtime(&buf[0].ut_time);
-       (void) strftime(ct, sizeof(ct), "\nwtmp begins %+\n", tm);
-       printf("%s", ct);
-}
-
-/*
- * doentry --
- *     process a single wtmp entry
- */
-void
-doentry(struct utmp *bp)
-{
-       struct ttytab   *tt, *ttx;              /* ttylist entry */
-
-       /*
-        * 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 (tt = LIST_FIRST(&ttylist); 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) ?
-                   "crash" : "shutdown";
-               /*
-                * 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)
-                       exit(0);
-               /*
-                * don't print shutdown/reboot entries unless flagged for
-                */
-               if (!snaptime && want(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]) {
-               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))
-                   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';
-               printentry(bp, tt);
-       }
-       tt->logout = bp->ut_time;
-}
-
-/*
- * printentry --
- *     output an entry
- *
- * If `tt' is non-NULL, use it and `crmsg' to print the logout time or
- * logout type (crash/shutdown) as appropriate.
- */
-void
-printentry(struct utmp *bp, struct ttytab *tt)
-{
-       char ct[80];
-       struct tm *tm;
-       time_t  delta;                          /* time difference */
-
-       if (maxrec != -1 && !maxrec--)
-               exit(0);
-       tm = localtime(&bp->ut_time);
-       (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' : ' ');
-       if (tt == NULL)
-               return;
-       if (!tt->logout) {
-               puts("  still logged in");
-               return;
-       }
-       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("  (%8ld)\n", (long)delta);
-       } else {
-               tm = gmtime(&delta);
-               (void) strftime(ct, sizeof(ct), width >= 8 ? "%T" : "%R", tm);
-               if (delta < 86400)
-                       printf("  (%s)\n", ct);
+       if (file == NULL) {
+               /* XXX: for now, default to utmp */
+#ifdef SUPPORT_UTMP
+               if (access(_PATH_WTMP, R_OK) == 0)
+                       file = _PATH_WTMP;
                else
-                       printf(" (%ld+%s)\n", (long)delta / 86400, ct);
+#endif
+#ifdef SUPPORT_UTMPX
+               if (access(_PATH_WTMPX, R_OK) == 0)
+                       file = _PATH_WTMPX;
+#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);
 }
 
-/*
- * want --
- *     see if want this entry
- */
-int
-want(struct utmp *bp)
-{
-       ARG *step;
-
-       if (snaptime)
-               return (NO);
-
-       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
+static void
 addarg(int type, char *arg)
 {
        ARG *cur;
@@ -409,16 +263,33 @@ addarg(int type, char *arg)
 }
 
 /*
+ * addtty --
+ *     add an entry to a linked list of ttys
+ */
+static TTY *
+addtty(const char *ttyname)
+{
+       TTY *cur;
+
+       if (!(cur = (TTY *)malloc((u_int)sizeof(TTY))))
+               err(1, "malloc failure");
+       cur->next = ttylist;
+       cur->logout = currentout;
+       memmove(cur->tty, ttyname, sizeof(cur->tty));
+       return (ttylist = cur);
+}
+
+/*
  * hostconv --
  *     convert the hostname to search pattern; if the supplied host name
  *     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
+static void
 hostconv(char *arg)
 {
        static int first = 1;
-       static char *hostdot, name[MAXHOSTNAMELEN];
+       static char *hostdot, name[MAXHOSTNAMELEN + 1];
        char *argdot;
 
        if (!(argdot = strchr(arg, '.')))
@@ -427,6 +298,7 @@ hostconv(char *arg)
                first = 0;
                if (gethostname(name, sizeof(name)))
                        err(1, "gethostname");
+               name[sizeof(name) - 1] = '\0';
                hostdot = strchr(name, '.');
        }
        if (hostdot && !strcasecmp(hostdot, argdot))
@@ -437,7 +309,7 @@ hostconv(char *arg)
  * ttyconv --
  *     convert tty to correct name.
  */
-char *
+static char *
 ttyconv(char *arg)
 {
        char *mval;
@@ -464,94 +336,51 @@ ttyconv(char *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
+ * fmttime --
+ *     return pointer to (static) formatted time string.
  */
-time_t
-dateconv(char *arg)
+static char *
+fmttime(time_t t, int flags)
 {
-        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;
-                /* FALLTHROUGH */
-        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;
+       struct tm *tm;
+       static char tbuf[TBUFLEN];
+
+       tm = (flags & GMT) ? gmtime(&t) : localtime(&t);
+       strftime(tbuf, sizeof(tbuf),
+           (flags & TIMEONLY)
+            ? (flags & FULLTIME ? LTFMTS : TFMTS)
+            : (flags & FULLTIME ? LTFMT : TFMT),
+           tm);
+       return (tbuf);
 }
 
+#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
+#undef NAMESIZE
+#undef LINESIZE
+#undef HOSTSIZE
+#undef ut_timefld
+#undef FIRSTVALID
+#endif
 
-/*
- * onintr --
- *     on interrupt, we inform the user how far we've gotten
- */
-void
-onintr(int signo)
-{
-       char ct[80];
-       struct tm *tm;
-
-       tm = localtime(&buf[0].ut_time);
-       (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 */
-}
+#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