utmpx - Bring in utmpx,wtmpx and lastlogx support
authorAlex Hornung <ahornung@gmail.com>
Sun, 4 Oct 2009 17:44:56 +0000 (18:44 +0100)
committerAlex Hornung <ahornung@gmail.com>
Thu, 16 Dec 2010 15:34:09 +0000 (15:34 +0000)
* This commit introduces the necessary support for utmpx, wtmpx and
  lastlogx, as well as updating many base utils to work with these
  while mostly maintaining compatibility with the old utmp, wtmp and
  lastlog.

* The new last(1) supports wtmpx but defaults to wtmp as not all wtmp
  writers have been updated for wtmpx.

* All utmp readers support both utmp and utmpx now.

* lastlogin (the only lastlog reader) supports both lastlog and
  lastlogx.

* The utils who(1) and finger have been almost directly replaced by
  their NetBSD equivalent. In case of who(1) the only custom
  modification is the behaviour of '-b' to be as it has always been.

* Partially-Obtained-from: NetBSD

54 files changed:
etc/Makefile
etc/newsyslog.conf
games/dm/Makefile
games/dm/dm.c
include/Makefile
include/utmp.h
include/utmpx.h [new file with mode: 0644]
lib/libc/gen/Makefile.inc
lib/libc/gen/utmp.c [new file with mode: 0644]
lib/libc/gen/utmpx.c [new file with mode: 0644]
lib/libutil/Makefile
lib/libutil/libutil.h
lib/libutil/loginx.3 [new file with mode: 0644]
lib/libutil/loginx.c [copied from include/utmp.h with 54% similarity]
lib/libutil/logoutx.c [copied from include/utmp.h with 54% similarity]
lib/libutil/logwtmpx.c [copied from include/utmp.h with 54% similarity]
lib/pam_module/pam_lastlog/pam_lastlog.c
libexec/Makefile
libexec/talkd/Makefile
libexec/talkd/process.c
libexec/utmp_update/Makefile [new file with mode: 0644]
libexec/utmp_update/utmp_update.8 [new file with mode: 0644]
libexec/utmp_update/utmp_update.c [new file with mode: 0644]
sbin/init/Makefile
sbin/init/init.c
share/man/man5/Makefile
share/man/man5/utmpx.5 [new file with mode: 0644]
usr.bin/finger/Makefile
usr.bin/finger/extern.h
usr.bin/finger/finger.c
usr.bin/finger/finger.h
usr.bin/finger/util.c
usr.bin/last/Makefile
usr.bin/last/last.c
usr.bin/login/login.c
usr.bin/systat/Makefile
usr.bin/systat/vmstat.c
usr.bin/users/Makefile
usr.bin/users/users.c
usr.bin/w/Makefile
usr.bin/w/w.c
usr.bin/wall/Makefile
usr.bin/wall/wall.c
usr.bin/who/Makefile
usr.bin/who/utmpentry.c [new file with mode: 0644]
usr.bin/who/utmpentry.h [new file with mode: 0644]
usr.bin/who/who.1
usr.bin/who/who.c
usr.bin/write/Makefile
usr.bin/write/write.c
usr.sbin/lastlogin/lastlogin.8
usr.sbin/lastlogin/lastlogin.c
usr.sbin/syslogd/Makefile
usr.sbin/syslogd/syslogd.c

index a282667..a1846a5 100644 (file)
@@ -323,6 +323,8 @@ distribution:
            ${DESTDIR}/var/log/maillog
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
            ${DESTDIR}/var/log/lastlog
+       ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+           ${DESTDIR}/var/log/lastlogx
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
            ${DESTDIR}/var/log/messages
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 600 /dev/null \
@@ -333,8 +335,12 @@ distribution:
            ${DESTDIR}/var/log/ppp.log
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
            ${DESTDIR}/var/log/wtmp
+       ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+           ${DESTDIR}/var/log/wtmpx
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
            ${DESTDIR}/var/run/utmp
+       ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+           ${DESTDIR}/var/run/utmpx
        ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 ${.CURDIR}/minfree \
            ${DESTDIR}/var/crash
        cd ${.CURDIR}/..; ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 \
index 790f4cb..af62974 100644 (file)
@@ -32,6 +32,7 @@
 /var/log/ppp.log       root:network    640  3     100  *     Z
 /var/log/security                      600  10    100  *     Z
 /var/log/wtmp                          644  3     *    @01T05 B
+/var/log/wtmpx                         644  3     *    @01T05 B
 /var/log/daily.log                     640  7     *    @T00  ZN
 /var/log/weekly.log                    640  5     1    $W6D0 ZN
 /var/log/monthly.log                   640  12    *    $M1D0 ZN
index 3d153f6..f32d29f 100644 (file)
@@ -3,9 +3,17 @@
 # $DragonFly: src/games/dm/Makefile,v 1.4 2006/10/08 16:22:35 pavalos Exp $
 
 # -DLOG                log games
+.PATH: ${.CURDIR}/../../usr.bin/who
+
 PROG=  dm
+SRCS=  dm.c utmpentry.c
 MAN=   dm.8 dm.conf.5
 BINGRP= games
 BINMODE=2555
 
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index 83d86d6..9be520a 100644 (file)
@@ -50,7 +50,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
 #include "pathnames.h"
 
@@ -257,18 +257,13 @@ load(void)
 static int
 users(void)
 {
+       struct utmpentry *ep;
+       int nusers = 0;
 
-       int nusers, utmp;
-       struct utmp buf;
+       getutentries(NULL, &ep);
+       for (; ep; ep = ep->next)
+               ++nusers;
 
-       if ((utmp = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
-               fprintf(stderr, "dm: %s: %s\n",
-                   _PATH_UTMP, strerror(errno));
-               exit(1);
-       }
-       for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
-               if (buf.ut_name[0] != '\0')
-                       ++nusers;
        return(nusers);
 }
 
index d7fcf49..f004309 100644 (file)
@@ -24,8 +24,8 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \
        stddef.h stdint.h stdio.h stdlib.h \
        string.h stringlist.h strings.h struct.h sysexits.h tar.h time.h \
        timeconv.h \
-       timers.h ttyent.h tzfile.h unistd.h ulimit.h utime.h utmp.h uuid.h \
-       vis.h \
+       timers.h ttyent.h tzfile.h unistd.h ulimit.h utime.h utmp.h utmpx.h \
+       uuid.h vis.h \
        wchar.h wctype.h wordexp.h
 
 .if defined(WANT_HESIOD)
index 6431f8c..7316087 100644 (file)
@@ -64,4 +64,9 @@ struct utmp {
        time_t  ut_time;
 };
 
+int utmpname(const char *);
+void setutent(void);
+struct utmp *getutent(void);
+void endutent(void);
+
 #endif /* !_UTMP_H_ */
diff --git a/include/utmpx.h b/include/utmpx.h
new file mode 100644 (file)
index 0000000..7e6aada
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef        _UTMPX_H_
+#define        _UTMPX_H_
+
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#define        _PATH_UTMPX             "/var/run/utmpx"
+#define        _PATH_WTMPX             "/var/log/wtmpx"
+#define        _PATH_LASTLOGX          "/var/log/lastlogx"
+#define        _PATH_UTMP_UPDATE       "/usr/libexec/utmp_update"
+
+#define _UTX_USERSIZE  32
+#define _UTX_LINESIZE  32
+#define        _UTX_IDSIZE     4
+#define _UTX_HOSTSIZE  256
+
+#define UTX_USERSIZE   _UTX_USERSIZE
+#define UTX_LINESIZE   _UTX_LINESIZE
+#define        UTX_IDSIZE      _UTX_IDSIZE
+#define UTX_HOSTSIZE   _UTX_HOSTSIZE
+
+
+#define EMPTY          0
+#define RUN_LVL                1
+#define BOOT_TIME      2
+#define OLD_TIME       3
+#define NEW_TIME       4
+#define INIT_PROCESS   5
+#define LOGIN_PROCESS  6
+#define USER_PROCESS   7
+#define DEAD_PROCESS   8
+
+#define ACCOUNTING     9
+#define SIGNATURE      10
+#define DOWN_TIME      11
+
+/*
+ * Strings placed in the ut_line field to indicate special type entries
+ */
+#define        RUNLVL_MSG      "run-level %c"
+#define        BOOT_MSG        "system boot"
+#define        OTIME_MSG       "old time"
+#define        NTIME_MSG       "new time"
+#define        DOWN_MSG        "system down"
+
+#define ut_user ut_name
+#define ut_xtime ut_tv.tv_sec
+
+typedef enum {
+       UTX_DB_UTMPX,
+       UTX_DB_WTMPX,
+       UTX_DB_LASTLOGX
+} utx_db_t;
+
+struct exit_status
+{
+       uint16_t e_termination;         /* termination status */
+       uint16_t e_exit;                /* exit status */
+};
+
+struct utmpx {
+       char ut_name[_UTX_USERSIZE];    /* login name */
+       char ut_id[_UTX_IDSIZE];        /* inittab id */
+       char ut_line[_UTX_LINESIZE];    /* tty name */
+       char ut_host[_UTX_HOSTSIZE];    /* host name */
+       uint8_t ut_unused[16];          /* reserved for future use */
+       uint16_t ut_session;            /* session id used for windowing */
+       uint16_t ut_type;               /* type of this entry */
+       pid_t ut_pid;                   /* process id creating the entry */
+       struct exit_status ut_exit;     /* process termination/exit status */
+       struct sockaddr_storage ut_ss;  /* address where entry was made from */
+       struct timeval ut_tv;           /* time entry was created */
+       uint8_t ut_unused2[16];         /* reserved for future use */
+};
+
+
+void          endutxent(void);
+struct utmpx *getutxent(void);
+struct utmpx *getutxid(const struct utmpx *);
+struct utmpx *getutxline(const struct utmpx *);
+struct utmpx *pututxline(const struct utmpx *);
+void          setutxent(void);
+
+/* NON-STANDARD functions, NetBSD specific stuff */
+struct lastlogx {
+       struct timeval ll_tv;           /* time entry was created */
+       char ll_line[_UTX_LINESIZE];    /* tty name */
+       char ll_host[_UTX_HOSTSIZE];    /* host name */
+       struct sockaddr_storage ll_ss;  /* address where entry was made from */
+};
+
+int updwtmpx(const char *, const struct utmpx *);
+struct lastlogx *getlastlogx(const char *, uid_t, struct lastlogx *);
+int updlastlogx(const char *, uid_t, struct lastlogx *);
+struct utmp;
+void getutmp(const struct utmpx *, struct utmp *);
+void getutmpx(const struct utmp *, struct utmpx *);
+int utmpxname(const char *);
+int setutxdb(utx_db_t, char *);
+
+#endif /* _UTMPX_H_ */
+
index 4a7c246..8756c5a 100644 (file)
@@ -36,6 +36,7 @@ SRCS+=  _pthread_stubs.c _rand48.c _spinlock_stub.c _thread_init.c \
        sysctlnametomib.c syslog.c telldir.c termios.c time.c times.c \
        toascii.c tolower.c toupper.c ttyname.c ttyslot.c \
        ualarm.c ucontext.c ulimit.c uname.c unvis.c usleep.c utime.c \
+       utmp.c utmpx.c \
        valloc.c vis.c wait.c wait3.c waitpid.c wordexp.c
 
 .if ${LIB} != {c_rtld}
diff --git a/lib/libc/gen/utmp.c b/lib/libc/gen/utmp.c
new file mode 100644 (file)
index 0000000..6446d73
--- /dev/null
@@ -0,0 +1,102 @@
+/*     $NetBSD: utmp.c,v 1.8 2009/01/11 02:46:27 christos Exp $         */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utmp.h>
+#include <sys/stat.h>
+
+static struct utmp utmp;
+static FILE *ut;
+static char utfile[MAXPATHLEN] = _PATH_UTMP;
+
+void
+setutent(void)
+{
+       if (ut == NULL)
+               return;
+       (void)fseeko(ut, (off_t)0, SEEK_SET);
+}
+
+struct utmp *
+getutent(void)
+{
+       if (ut == NULL) {
+               struct stat st;
+               off_t numentries;
+               if ((ut = fopen(utfile, "r")) == NULL)
+                       return NULL;
+               if (fstat(fileno(ut), &st) == -1)
+                       goto out;
+               /*
+                * If we have a an old version utmp file bail.
+                */
+               numentries = st.st_size / sizeof(utmp);
+               if ((off_t)(numentries * sizeof(utmp)) != st.st_size)
+                       goto out;
+       }
+       if (fread(&utmp, sizeof(utmp), 1, ut) == 1)
+               return &utmp;
+out:
+       (void)fclose(ut);
+       return NULL;
+}
+
+void
+endutent(void)
+{
+       if (ut != NULL) {
+               (void)fclose(ut);
+               ut = NULL;
+       }
+}
+
+int
+utmpname(const char *fname)
+{
+       size_t len = strlen(fname);
+
+       if (len >= sizeof(utfile))
+               return 0;
+
+       /* must not end in x! */
+       if (fname[len - 1] == 'x')
+               return 0;
+
+       (void)strlcpy(utfile, fname, sizeof(utfile));
+       endutent();
+       return 1;
+}
diff --git a/lib/libc/gen/utmpx.c b/lib/libc/gen/utmpx.c
new file mode 100644 (file)
index 0000000..3b41791
--- /dev/null
@@ -0,0 +1,498 @@
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#include <sys/cdefs.h>
+
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <utmp.h>
+#include <utmpx.h>
+#include <vis.h>
+
+static FILE *fp = NULL;
+static int readonly = 0;
+static struct utmpx ut;
+static char utfile[MAXPATHLEN] = _PATH_UTMPX;
+
+static struct utmpx *utmp_update(const struct utmpx *);
+
+static const char vers[] = "utmpx-2.00";
+static utx_db_t dbtype = UTX_DB_UTMPX;
+DB *lastlogx_db = NULL;
+
+static int
+_open_db(char *fname)
+{
+       struct stat st;
+
+       if ((fp = fopen(fname, "r+")) == NULL)
+               if ((fp = fopen(fname, "w+")) == NULL) {
+                       if ((fp = fopen(fname, "r")) == NULL)
+                               goto fail;
+                       else
+                               readonly = 1;
+               }
+
+       /* get file size in order to check if new file */
+       if (fstat(fileno(fp), &st) == -1)
+               goto failclose;
+
+       if (st.st_size == 0) {
+               /* new file, add signature record */
+               (void)memset(&ut, 0, sizeof(ut));
+               ut.ut_type = SIGNATURE;
+               (void)memcpy(ut.ut_user, vers, sizeof(vers));
+               if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
+                       goto failclose;
+       } else {
+               /* old file, read signature record */
+               if (fread(&ut, sizeof(ut), 1, fp) != 1)
+                       goto failclose;
+               if (memcmp(ut.ut_user, vers, 5) != 0 ||
+                   ut.ut_type != SIGNATURE) {
+                       errno = EINVAL;
+                       goto failclose;
+               }
+       }
+
+       return 0;
+failclose:
+       (void)fclose(fp);
+fail:
+       (void)memset(&ut, 0, sizeof(ut));
+       return -1;
+}
+
+int
+setutxdb(utx_db_t db_type, char *fname)
+{
+       switch (db_type) {
+       case UTX_DB_UTMPX:
+               if (fname == NULL)
+                       fname = _PATH_UTMPX;
+               break;
+
+       case UTX_DB_WTMPX:
+               if (fname == NULL)
+                       fname = _PATH_WTMPX;
+               break;
+
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* A previous db file is still open */
+       if (fp != NULL) {
+               fclose(fp);
+               fp = NULL;
+       }
+       if ((_open_db(fname)) == -1)
+               return -1;
+
+done:
+       dbtype = db_type;
+       return 0;
+}
+
+void
+setutxent()
+{
+       (void)memset(&ut, 0, sizeof(ut));
+       if (fp == NULL)
+               return;
+
+#if 0
+       if (dbtype != UTX_DB_UTMPX)
+               setutxdb(UTX_DB_UTMPX, utfile);
+#endif
+       (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
+}
+
+void
+endutxent()
+{
+       (void)memset(&ut, 0, sizeof(ut));
+
+       if (fp != NULL) {
+               (void)fclose(fp);
+               fp = NULL;
+               readonly = 0;
+       }
+}
+
+struct utmpx *
+getutxent()
+{
+       if (fp == NULL) {
+               if ((_open_db(utfile)) == -1)
+                       goto fail;
+       }
+
+       if (fread(&ut, sizeof(ut), 1, fp) != 1)
+               goto fail;
+
+       return &ut;
+fail:
+       (void)memset(&ut, 0, sizeof(ut));
+       return NULL;
+}
+
+struct utmpx *
+getutxid(const struct utmpx *utx)
+{
+
+       _DIAGASSERT(utx != NULL);
+
+       if (utx->ut_type == EMPTY)
+               return NULL;
+
+       do {
+               if (ut.ut_type == EMPTY)
+                       continue;
+               switch (utx->ut_type) {
+               case EMPTY:
+                       return NULL;
+               case RUN_LVL:
+               case BOOT_TIME:
+               case OLD_TIME:
+               case NEW_TIME:
+                       if (ut.ut_type == utx->ut_type)
+                               return &ut;
+                       break;
+               case INIT_PROCESS:
+               case LOGIN_PROCESS:
+               case USER_PROCESS:
+               case DEAD_PROCESS:
+                       switch (ut.ut_type) {
+                       case INIT_PROCESS:
+                       case LOGIN_PROCESS:
+                       case USER_PROCESS:
+                       case DEAD_PROCESS:
+                               if (memcmp(ut.ut_id, utx->ut_id,
+                                   sizeof(ut.ut_id)) == 0)
+                                       return &ut;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               default:
+                       return NULL;
+               }
+       } while (getutxent() != NULL);
+       return NULL;
+}
+
+struct utmpx *
+getutxline(const struct utmpx *utx)
+{
+
+       _DIAGASSERT(utx != NULL);
+
+       do {
+               switch (ut.ut_type) {
+               case EMPTY:
+                       break;
+               case LOGIN_PROCESS:
+               case USER_PROCESS:
+                       if (strncmp(ut.ut_line, utx->ut_line,
+                           sizeof(ut.ut_line)) == 0)
+                               return &ut;
+                       break;
+               default:
+                       break;
+               }
+       } while (getutxent() != NULL);
+       return NULL;
+}
+
+struct utmpx *
+pututxline(const struct utmpx *utx)
+{
+       struct passwd *pw;
+       struct lastlogx ll;
+       struct utmpx temp, *u = NULL;
+       int gotlock = 0;
+
+       _DIAGASSERT(utx != NULL);
+
+       if (utx == NULL)
+               return NULL;
+
+       if (utx->ut_type == USER_PROCESS) {
+               ll.ll_tv = utx->ut_tv;
+               strcpy(ll.ll_host, utx->ut_host);
+               strcpy(ll.ll_line, utx->ut_line);
+               pw = getpwnam(utx->ut_name);
+               if (pw != NULL)
+                       updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll);
+       }
+
+       if (strcmp(_PATH_UTMPX, utfile) == 0)
+               if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0))
+                       return utmp_update(utx);
+
+
+       (void)memcpy(&temp, utx, sizeof(temp));
+
+       if (fp == NULL) {
+               (void)getutxent();
+               if (fp == NULL || readonly)
+                       return NULL;
+       }
+
+       if (getutxid(&temp) == NULL) {
+               setutxent();
+               if (getutxid(&temp) == NULL) {
+                       if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
+                               return NULL;
+                       gotlock++;
+                       if (fseeko(fp, (off_t)0, SEEK_END) == -1)
+                               goto fail;
+               }
+       }
+
+       if (!gotlock) {
+               /* we are not appending */
+               if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
+                       return NULL;
+       }
+
+       if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
+               goto fail;
+
+       if (fflush(fp) == -1)
+               goto fail;
+
+       u = memcpy(&ut, &temp, sizeof(ut));
+fail:
+       if (gotlock) {
+               if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
+                       return NULL;
+       }
+       return u;
+}
+
+static struct utmpx *
+utmp_update(const struct utmpx *utx)
+{
+       char buf[sizeof(*utx) * 4 + 1];
+       pid_t pid;
+       int status;
+
+       _DIAGASSERT(utx != NULL);
+
+       (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
+           VIS_WHITE);
+       switch (pid = fork()) {
+       case 0:
+               (void)execl(_PATH_UTMP_UPDATE,
+                   strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL);
+               _exit(1);
+               /*NOTREACHED*/
+       case -1:
+               return NULL;
+       default:
+               if (waitpid(pid, &status, 0) == -1)
+                       return NULL;
+               if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+                       return memcpy(&ut, utx, sizeof(ut));
+               return NULL;
+       }
+
+}
+
+/*
+ * The following are extensions and not part of the X/Open spec.
+ */
+int
+updwtmpx(const char *file, const struct utmpx *utx)
+{
+       int fd;
+       int saved_errno;
+
+       _DIAGASSERT(file != NULL);
+       _DIAGASSERT(utx != NULL);
+
+       fd = open(file, O_WRONLY|O_APPEND|O_SHLOCK);
+
+       if (fd == -1) {
+               if ((fd = open(file, O_CREAT|O_WRONLY|O_EXLOCK, 0644)) == -1)
+                       return -1;
+               (void)memset(&ut, 0, sizeof(ut));
+               ut.ut_type = SIGNATURE;
+               (void)memcpy(ut.ut_user, vers, sizeof(vers));
+               if (write(fd, &ut, sizeof(ut)) == -1)
+                       goto failed;
+       }
+       if (write(fd, utx, sizeof(*utx)) == -1)
+               goto failed;
+       if (close(fd) == -1)
+               return -1;
+       return 0;
+
+  failed:
+       saved_errno = errno;
+       (void) close(fd);
+       errno = saved_errno;
+       return -1;
+}
+
+int
+utmpxname(const char *fname)
+{
+       size_t len;
+
+       _DIAGASSERT(fname != NULL);
+
+       len = strlen(fname);
+
+       if (len >= sizeof(utfile))
+               return 0;
+
+       /* must end in x! */
+       if (fname[len - 1] != 'x')
+               return 0;
+
+       (void)strlcpy(utfile, fname, sizeof(utfile));
+       endutxent();
+       return 1;
+}
+
+void
+getutmp(const struct utmpx *ux, struct utmp *u)
+{
+
+       _DIAGASSERT(ux != NULL);
+       _DIAGASSERT(u != NULL);
+
+       (void)memcpy(u->ut_name, ux->ut_name, sizeof(u->ut_name));
+       (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
+       (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
+       u->ut_time = ux->ut_tv.tv_sec;
+}
+
+void
+getutmpx(const struct utmp *u, struct utmpx *ux)
+{
+
+       _DIAGASSERT(ux != NULL);
+       _DIAGASSERT(u != NULL);
+
+       (void)memcpy(ux->ut_name, u->ut_name, sizeof(u->ut_name));
+       (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
+       (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
+       ux->ut_tv.tv_sec = u->ut_time;
+       ux->ut_tv.tv_usec = 0;
+       (void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss));
+       ux->ut_pid = 0;
+       ux->ut_type = USER_PROCESS;
+       ux->ut_session = 0;
+       ux->ut_exit.e_termination = 0;
+       ux->ut_exit.e_exit = 0;
+}
+
+struct lastlogx *
+getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
+{
+       DBT key, data;
+       DB *db;
+
+       _DIAGASSERT(fname != NULL);
+       _DIAGASSERT(ll != NULL);
+
+       db = dbopen(fname, O_RDONLY|O_SHLOCK, 0, DB_HASH, NULL);
+
+       if (db == NULL)
+               return NULL;
+
+       key.data = &uid;
+       key.size = sizeof(uid);
+
+       if ((db->get)(db, &key, &data, 0) != 0)
+               goto error;
+
+       if (data.size != sizeof(*ll)) {
+               errno = EFTYPE;
+               goto error;
+       }
+
+       if (ll == NULL)
+               if ((ll = malloc(sizeof(*ll))) == NULL)
+                       goto done;
+
+       (void)memcpy(ll, data.data, sizeof(*ll));
+       goto done;
+error:
+       ll = NULL;
+done:
+       (db->close)(db);
+       return ll;
+}
+
+int
+updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
+{
+       DBT key, data;
+       int error = 0;
+       DB *db;
+
+       _DIAGASSERT(fname != NULL);
+       _DIAGASSERT(ll != NULL);
+
+       db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK, 0644, DB_HASH, NULL);
+
+       if (db == NULL)
+               return -1;
+
+       key.data = &uid;
+       key.size = sizeof(uid);
+       data.data = ll;
+       data.size = sizeof(*ll);
+       if ((db->put)(db, &key, &data, 0) != 0)
+               error = -1;
+
+       (db->close)(db);
+       return error;
+}
index 3a81293..a5fdef6 100644 (file)
@@ -6,9 +6,10 @@ LIB=   util
 SHLIB_MAJOR= 4
 CFLAGS+=-DINET6
 CFLAGS+=-D_CTYPE_H_DISABLE_MACROS_ 
-SRCS=  flopen.c login.c login_tty.c logout.c logwtmp.c pty.c \
+SRCS=  flopen.c login.c login_tty.c logout.c logwtmp.c logwtmpx.c pty.c \
        login_cap.c login_class.c login_auth.c login_times.c login_ok.c \
-       login_crypt.c _secure_path.c uucplock.c property.c auth.c \
+       login_crypt.c loginx.c logoutx.c _secure_path.c uucplock.c \
+       property.c auth.c \
        realhostname.c fparseln.c stub.c pidfile.c trimdomain.c \
        dehumanize_number.c humanize_number.c humanize_unsigned.c pw_util.c
 INCS=  libutil.h login_cap.h
@@ -16,7 +17,8 @@ WARNS?=       3
 
 CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../libc/gen/
 
-MAN+=  flopen.3 login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
+MAN+=  flopen.3 login.3 loginx.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 \
+       pty.3 \
        login_cap.3 login_class.3 login_times.3 login_ok.3 \
        _secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
        realhostname_sa.3 trimdomain.3 fparseln.3 pidfile.3 \
@@ -35,6 +37,7 @@ MLINKS+=login_cap.3 login_getclassbyname.3 login_cap.3 login_close.3 \
        login_cap.3 login_getcapnum.3 login_cap.3 login_getcapsize.3 \
        login_cap.3 login_getcapbool.3 login_cap.3 login_getpath.3 \
        login_cap.3 login_getpwclass.3 login_cap.3 login_setcryptfmt.3
+MLINKS+=loginx.3 logoutx.3 loginx.3 logwtmpx.3
 MLINKS+=login_class.3 setusercontext.3 login_class.3 setclasscontext.3 \
        login_class.3 setclassenvironment.3 login_class.3 setclassresources.3
 MLINKS+=login_times.3 parse_lt.3 login_times.3 in_ltm.3 \
index 77bf3df..c79b25e 100644 (file)
@@ -59,15 +59,19 @@ typedef struct _property {
 struct termios;
 struct winsize;
 struct utmp;
+struct utmpx;
 struct in_addr;
 struct sockaddr;
 
 __BEGIN_DECLS
 int    flopen(const char *, int, ...);
 void   login(struct utmp *);
+void   loginx(const struct utmpx *);
 int    login_tty(int);
 int    logout(const char *);
+int    logoutx(const char *, int, int);
 void   logwtmp(const char *, const char *, const char *);
+void   logwtmpx(const char *, const char *, const char *, int, int);
 void   trimdomain(char *, int);
 int    openpty(int *, int *, char *, struct termios *, struct winsize *);
 int    forkpty(int *, char *, struct termios *, struct winsize *);
diff --git a/lib/libutil/loginx.3 b/lib/libutil/loginx.3
new file mode 100644 (file)
index 0000000..a2962a9
--- /dev/null
@@ -0,0 +1,93 @@
+.\"    $NetBSD: loginx.3,v 1.2 2003/04/16 13:35:15 wiz Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Thomas Klausner.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd September 26, 2002
+.Dt LOGINX 3
+.Os
+.Sh NAME
+.Nm loginx ,
+.Nm logoutx ,
+.Nm logwtmpx
+.Nd login utility functions
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In util.h
+.Ft void
+.Fn loginx "const struct utmpx *ut"
+.Ft int
+.Fn logoutx "const char *line" "int status" "int type"
+.Ft void
+.Fn logwtmpx "const char *line" "const char *name" "const char *host" "int status" "int type"
+.Sh DESCRIPTION
+The
+.Fn loginx ,
+.Fn logoutx ,
+and
+.Fn logwtmpx
+operate on the
+.Xr utmpx 5
+database of currently logged in users, and the
+.Xr wtmpx 5
+database of logins and logouts.
+.Pp
+The
+.Fn loginx
+function updates the
+.Pa /var/run/utmpx
+and
+.Pa /var/log/wtmpx
+databases with the information from
+.Fa ut .
+.Pp
+.Fn logoutx
+updates the entry corresponding to
+.Fa line
+with the type and status from
+.Fa type
+and
+.Fa status .
+.Pp
+.Fn logwtmpx
+writes an entry filled with data from
+.Fa line ,
+.Fa name ,
+.Fa host ,
+.Fa status ,
+and
+.Fa type
+to the
+.Xr wtmpx 5
+database.
+.Sh RETURN VALUES
+.Fn logoutx
+returns 1 on success, and 0 if no corresponding entry was found.
+.Sh SEE ALSO
+.Xr endutxent 3 ,
+.Xr utmpx 5
similarity index 54%
copy from include/utmp.h
copy to lib/libutil/loginx.c
index 6431f8c..d111b3a 100644 (file)
@@ -1,11 +1,8 @@
+/*     $NetBSD: loginx.c,v 1.2 2003/08/07 16:44:59 agc Exp $   */
+
 /*
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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
+ * 3. 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.
  *
  * 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.
- *
- *     @(#)utmp.h      8.2 (Berkeley) 1/21/94
- * $FreeBSD: src/include/utmp.h,v 1.9 1999/08/27 23:44:53 peter Exp $
- * $DragonFly: src/include/utmp.h,v 1.2 2003/06/17 04:25:56 dillon Exp $
  */
 
-#ifndef        _UTMP_H_
-#define        _UTMP_H_
-
-#define        _PATH_UTMP      "/var/run/utmp"
-#define        _PATH_WTMP      "/var/log/wtmp"
-#define        _PATH_LASTLOG   "/var/log/lastlog"
-
-#define        UT_NAMESIZE     16      /* see MAXLOGNAME in <sys/param.h> */
-#define        UT_LINESIZE     8
-#define        UT_HOSTSIZE     16
+#include <sys/cdefs.h>
 
-struct lastlog {
-       time_t  ll_time;
-       char    ll_line[UT_LINESIZE];
-       char    ll_host[UT_HOSTSIZE];
-};
+#include <sys/types.h>
 
-struct utmp {
-       char    ut_line[UT_LINESIZE];
-       char    ut_name[UT_NAMESIZE];
-       char    ut_host[UT_HOSTSIZE];
-       time_t  ut_time;
-};
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <utmp.h>
+#include <utmpx.h>
 
-#endif /* !_UTMP_H_ */
+void
+loginx(const struct utmpx *ut)
+{
+       (void)pututxline(ut);
+       (void)updwtmpx(_PATH_WTMPX, ut);
+}
similarity index 54%
copy from include/utmp.h
copy to lib/libutil/logoutx.c
index 6431f8c..6793853 100644 (file)
@@ -1,11 +1,8 @@
+/*     $NetBSD: logoutx.c,v 1.2 2003/08/07 16:44:59 agc Exp $  */
+
 /*
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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
+ * 3. 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.
  *
  * 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.
- *
- *     @(#)utmp.h      8.2 (Berkeley) 1/21/94
- * $FreeBSD: src/include/utmp.h,v 1.9 1999/08/27 23:44:53 peter Exp $
- * $DragonFly: src/include/utmp.h,v 1.2 2003/06/17 04:25:56 dillon Exp $
  */
 
-#ifndef        _UTMP_H_
-#define        _UTMP_H_
-
-#define        _PATH_UTMP      "/var/run/utmp"
-#define        _PATH_WTMP      "/var/log/wtmp"
-#define        _PATH_LASTLOG   "/var/log/lastlog"
-
-#define        UT_NAMESIZE     16      /* see MAXLOGNAME in <sys/param.h> */
-#define        UT_LINESIZE     8
-#define        UT_HOSTSIZE     16
+#include <sys/cdefs.h>
 
-struct lastlog {
-       time_t  ll_time;
-       char    ll_line[UT_LINESIZE];
-       char    ll_host[UT_HOSTSIZE];
-};
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
 
-struct utmp {
-       char    ut_line[UT_LINESIZE];
-       char    ut_name[UT_NAMESIZE];
-       char    ut_host[UT_HOSTSIZE];
-       time_t  ut_time;
-};
+#include <assert.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <utmp.h>
+#include <utmpx.h>
 
-#endif /* !_UTMP_H_ */
+int
+logoutx(const char *line, int status, int type)
+{
+       struct utmpx *utp, ut;
+       (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
+       if ((utp = getutxline(&ut)) == NULL) {
+               endutxent();
+               return 0;
+       }
+       utp->ut_type = type;
+       if (WIFEXITED(status))
+               utp->ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
+       if (WIFSIGNALED(status))
+               utp->ut_exit.e_termination = (uint16_t)WTERMSIG(status);
+       (void)gettimeofday(&utp->ut_tv, NULL);
+       (void)pututxline(utp);
+       endutxent();
+       return 1;
+}
similarity index 54%
copy from include/utmp.h
copy to lib/libutil/logwtmpx.c
index 6431f8c..f703149 100644 (file)
@@ -1,11 +1,8 @@
+/*     $NetBSD: logwtmpx.c,v 1.2 2003/08/07 16:44:59 agc Exp $ */
+
 /*
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
- * (c) UNIX System Laboratories, Inc.
- * All or some portions of this file are derived from material licensed
- * to the University of California by American Telephone and Telegraph
- * Co. or Unix System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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
+ * 3. 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.
  *
  * 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.
- *
- *     @(#)utmp.h      8.2 (Berkeley) 1/21/94
- * $FreeBSD: src/include/utmp.h,v 1.9 1999/08/27 23:44:53 peter Exp $
- * $DragonFly: src/include/utmp.h,v 1.2 2003/06/17 04:25:56 dillon Exp $
  */
 
-#ifndef        _UTMP_H_
-#define        _UTMP_H_
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
 
-#define        _PATH_UTMP      "/var/run/utmp"
-#define        _PATH_WTMP      "/var/log/wtmp"
-#define        _PATH_LASTLOG   "/var/log/lastlog"
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <utmpx.h>
+#include <libutil.h>
 
-#define        UT_NAMESIZE     16      /* see MAXLOGNAME in <sys/param.h> */
-#define        UT_LINESIZE     8
-#define        UT_HOSTSIZE     16
+void
+logwtmpx(const char *line, const char *name, const char *host, int status,
+    int type)
+{
+       struct utmpx ut;
 
-struct lastlog {
-       time_t  ll_time;
-       char    ll_line[UT_LINESIZE];
-       char    ll_host[UT_HOSTSIZE];
-};
+       _DIAGASSERT(line != NULL);
+       _DIAGASSERT(name != NULL);
+       _DIAGASSERT(host != NULL);
 
-struct utmp {
-       char    ut_line[UT_LINESIZE];
-       char    ut_name[UT_NAMESIZE];
-       char    ut_host[UT_HOSTSIZE];
-       time_t  ut_time;
-};
+       (void)memset(&ut, 0, sizeof(ut));
+       (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+       (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+       (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+       ut.ut_type = type;
+       if (WIFEXITED(status))
+               ut.ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
+       if (WIFSIGNALED(status))
+               ut.ut_exit.e_termination = (uint16_t)WTERMSIG(status);
+       (void)gettimeofday(&ut.ut_tv, NULL);
+       (void)updwtmpx(_PATH_WTMPX, &ut);
+}
 
-#endif /* !_UTMP_H_ */
index 5cb931c..52d0e6a 100644 (file)
@@ -57,7 +57,6 @@
 #include <syslog.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
 
 #define PAM_SM_SESSION
 
 #include <security/pam_modules.h>
 #include <security/pam_mod_misc.h>
 
+#define SUPPORT_UTMP 1
+#define SUPPORT_UTMPX 1
+
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+static void doutmp(const char *, const char *, const char *,
+    const struct timeval *);
+static void dolastlog(pam_handle_t *, int, const struct passwd *, const char *,
+    const char *, const struct timeval *);
+#endif
+
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+static void doutmpx(const char *, const char *, const char *,
+    const struct sockaddr_storage *ss, const struct timeval *);
+static void dolastlogx(pam_handle_t *, int, const struct passwd *, const char *,
+    const char *, const struct sockaddr_storage *ss, const struct timeval *);
+#endif
+
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void domsg(pam_handle_t *, time_t, const char *, size_t, const char *,
+    size_t);
+#endif
+
+static void
+logit(int level, const char *fmt, ...)
+{
+       va_list ap;
+
+       openlog("pam_lastlog", LOG_PID, LOG_AUTHPRIV);
+       va_start(ap, fmt);
+       vsyslog(level, fmt, ap);
+       va_end(ap);
+       closelog();
+}
+
+
 PAM_EXTERN int
 pam_sm_open_session(pam_handle_t *pamh, int flags,
-                   int argc __unused, const char *argv[] __unused)
+    int argc __unused, const char *argv[] __unused)
 {
-       struct passwd *pwd;
-       struct utmp utmp;
-       struct lastlog ll;
-       time_t t;
-       const char *user;
-       const void *rhost, *tty;
-       off_t llpos;
-       int fd, pam_err;
+       struct passwd *pwd, pwres;
+       struct timeval now;
+       const char *user, *rhost, *tty;
+       const void *vrhost, *vtty;
+       int pam_err;
+       int quiet;
+       char pwbuf[1024];
+#ifdef LOGIN_CAP
+       login_cap_t *lc;
+#endif
 
        pam_err = pam_get_user(pamh, &user, NULL);
        if (pam_err != PAM_SUCCESS)
-               return (pam_err);
-       if (user == NULL || (pwd = getpwnam(user)) == NULL)
-               return (PAM_SERVICE_ERR);
+               return pam_err;
+
+       if (user == NULL ||
+           getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
+           pwd == NULL)
+               return PAM_SERVICE_ERR;
+
        PAM_LOG("Got user: %s", user);
 
-       pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
-       if (pam_err != PAM_SUCCESS) {
-               PAM_LOG("No PAM_RHOST");
+       pam_err = pam_get_item(pamh, PAM_RHOST, &vrhost);
+       if (pam_err != PAM_SUCCESS)
                goto err;
-       }
-       pam_err = pam_get_item(pamh, PAM_TTY, &tty);
-       if (pam_err != PAM_SUCCESS) {
-               PAM_LOG("No PAM_TTY");
+       rhost = (const char *)vrhost;
+
+       pam_err = pam_get_item(pamh, PAM_TTY, &vtty);
+       if (pam_err != PAM_SUCCESS)
                goto err;
-       }
+       tty = (const char *)vtty;
+
        if (tty == NULL) {
-               PAM_LOG("No PAM_TTY");
                pam_err = PAM_SERVICE_ERR;
                goto err;
        }
+
        if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
-               tty = (const char *)tty + strlen(_PATH_DEV);
-       if (*(const char *)tty == '\0')
-               return (PAM_SERVICE_ERR);
-
-       fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT, 0644);
-       if (fd == -1) {
-               PAM_LOG("Failed to open %s", _PATH_LASTLOG);
-               goto file_err;
-       }
+               tty = tty + strlen(_PATH_DEV);
 
-       /*
-        * Record session in lastlog(5).
-        */
-       llpos = (off_t)(pwd->pw_uid * sizeof(ll));
-       if (lseek(fd, llpos, L_SET) != llpos)
-               goto file_err;
-       if ((flags & PAM_SILENT) == 0) {
-               if (read(fd, &ll, sizeof ll) == sizeof ll && ll.ll_time != 0) {
-                       t = ll.ll_time;
-                       if (*ll.ll_host != '\0')
-                               pam_info(pamh, "Last login: %.*s from %.*s",
-                                   24 - 5, ctime(&t),
-                                   (int)sizeof(ll.ll_host), ll.ll_host);
-                       else
-                               pam_info(pamh, "Last login: %.*s on %.*s",
-                                   24 - 5, ctime(&t),
-                                   (int)sizeof(ll.ll_line), ll.ll_line);
-               }
-               if (lseek(fd, llpos, L_SET) != llpos)
-                       goto file_err;
+       if (*tty == '\0') {
+               pam_err = PAM_SERVICE_ERR;
+               goto err;
        }
 
-       bzero(&ll, sizeof(ll));
-       ll.ll_time = time(NULL);
+       (void)gettimeofday(&now, NULL);
+
+       if ((flags & PAM_SILENT) != 0)
+               quiet = 1;
+       else {
+#ifdef LOGIN_CAP
+               lc = login_getpwclass(pwd);
+               quiet = login_getcapbool(lc, "hushlogin", 0);
+               login_close(lc);
+#else
+               quiet = 0;
+#endif
+       }
+#ifdef SUPPORT_UTMPX
+       dolastlogx(pamh, quiet, pwd, rhost, tty, NULL, &now);
+       doutmpx(user, rhost, tty, NULL, &now);
+       quiet = 1;
+#endif
+#ifdef SUPPORT_UTMP
+       doutmp(user, rhost, tty, &now);
+       dolastlog(pamh, quiet, pwd, rhost, tty, &now);
+#endif
+err:
+       if (openpam_get_option(pamh, "no_fail"))
+               return PAM_SUCCESS;
+       return pam_err;
+}
 
-       /* note: does not need to be NUL-terminated */
-       strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
-       if (rhost != NULL && *(const char *)rhost != '\0')
-               /* note: does not need to be NUL-terminated */
-               strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
+PAM_EXTERN int
+pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
+    int argc __unused, const char *argv[] __unused)
+{
+       const void *vtty;
+       const char *tty;
 
-       if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
-               goto file_err;
+       pam_get_item(pamh, PAM_TTY, &vtty);
+       if (vtty == NULL)
+               return PAM_SERVICE_ERR;
+       tty = (const char *)vtty;
 
-       PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
+       if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
+               tty = tty + strlen(_PATH_DEV);
 
-       /*
-        * Record session in utmp(5) and wtmp(5).
-        */
-       bzero(&utmp, sizeof(utmp));
-       utmp.ut_time = time(NULL);
-       /* note: does not need to be NUL-terminated */
-       strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
-       if (rhost != NULL && *(const char *)rhost != '\0')
-               strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
-       strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
-       login(&utmp);
+       if (*tty == '\0')
+               return PAM_SERVICE_ERR;
 
-       return (PAM_SUCCESS);
+#ifdef SUPPORT_UTMPX
+       if (logoutx(tty, 0, DEAD_PROCESS))
+               logwtmpx(tty, "", "", 0, DEAD_PROCESS);
+       else
+               logit(LOG_NOTICE, "%s(): no utmpx record for %s",
+                   __func__, tty);
+#endif
 
-file_err:
-       syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
-       if (fd != -1)
-               close(fd);
-       pam_err = PAM_SYSTEM_ERR;
-err:
-       if (openpam_get_option(pamh, "no_fail"))
-               return (PAM_SUCCESS);
-       return (pam_err);
+#ifdef SUPPORT_UTMP
+       if (logout(tty))
+               logwtmp(tty, "", "");
+       else
+               logit(LOG_NOTICE, "%s(): no utmp record for %s",
+                   __func__, tty);
+#endif
+        return PAM_SUCCESS;
 }
 
-PAM_EXTERN int
-pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
-                    int argc __unused, const char *argv[] __unused)
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void
+domsg(pam_handle_t *pamh, time_t t, const char *host, size_t hsize,
+    const char *line, size_t lsize)
 {
-       const void *tty;
+       char buf[MAXHOSTNAMELEN + 32], *promptresp = NULL;
        int pam_err;
 
-       pam_err = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
-       if (pam_err != PAM_SUCCESS)
-               goto err;
-       if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
-               tty = (const char *)tty + strlen(_PATH_DEV);
-       if (*(const char *)tty == '\0')
-               return (PAM_SERVICE_ERR);
-       if (logout(tty) != 1)
-               syslog(LOG_ERR, "%s(): no utmp record for %s",
-                   __func__, (const char *)tty);
-       logwtmp(tty, "", "");
-       return (PAM_SUCCESS);
-
- err:
-       if (openpam_get_option(pamh, "no_fail"))
-               return (PAM_SUCCESS);
-       return (pam_err);
+       if (*host) {
+               (void)snprintf(buf, sizeof(buf), "from %.*s ",
+                   (int)hsize, host);
+               host = buf;
+       }
+
+       pam_err = pam_prompt(pamh, PAM_TEXT_INFO, &promptresp,
+           "Last login: %.24s %son %.*s\n", ctime(&t), host, (int)lsize, line);
+
+       if (pam_err == PAM_SUCCESS && promptresp)
+               free(promptresp);
+}
+#endif
+
+#ifdef SUPPORT_UTMPX
+static void
+doutmpx(const char *username, const char *hostname, const char *tty,
+    const struct sockaddr_storage *ss, const struct timeval *now)
+{
+       struct utmpx utmpx;
+       const char *t;
+
+       memset((void *)&utmpx, 0, sizeof(utmpx));
+       utmpx.ut_tv = *now;
+       (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name));
+       if (hostname) {
+               (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host));
+               if (ss)
+                       utmpx.ut_ss = *ss;
+       }
+       (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line));
+       utmpx.ut_type = USER_PROCESS;
+       utmpx.ut_pid = getpid();
+       t = tty + strlen(tty);
+       if ((size_t)(t - tty) >= sizeof(utmpx.ut_id)) {
+               (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id),
+                   sizeof(utmpx.ut_id));
+       } else {
+               (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id));
+       }
+       if (pututxline(&utmpx) == NULL)
+               logit(LOG_NOTICE, "Cannot update utmpx %m");
+       endutxent();
+       if (updwtmpx(_PATH_WTMPX, &utmpx) != 0)
+               logit(LOG_NOTICE, "Cannot update wtmpx %m");
+}
+
+static void
+dolastlogx(pam_handle_t *pamh, int quiet, const struct passwd *pwd,
+    const char *hostname __unused, const char *tty __unused,
+    const struct sockaddr_storage *ss __unused,
+    const struct timeval *now __unused)
+{
+       struct lastlogx ll;
+       if (!quiet) {
+           if (getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL)
+                   domsg(pamh, (time_t)ll.ll_tv.tv_sec, ll.ll_host,
+                       sizeof(ll.ll_host), ll.ll_line,
+                       sizeof(ll.ll_line));
+       }
+#if 0
+       ll.ll_tv = *now;
+       (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+
+       if (hostname)
+               (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+       else
+               (void)memset(ll.ll_host, 0, sizeof(ll.ll_host));
+
+       if (ss)
+               ll.ll_ss = *ss;
+       else
+               (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss));
+
+       if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0)
+               logit(LOG_NOTICE, "Cannot update lastlogx %m");
+       PAM_LOG("Login recorded in %s", _PATH_LASTLOGX);
+#endif
 }
+#endif
+
+#ifdef SUPPORT_UTMP
+static void
+doutmp(const char *username, const char *hostname, const char *tty,
+    const struct timeval *now)
+{
+       struct utmp utmp;
+
+       (void)memset((void *)&utmp, 0, sizeof(utmp));
+       utmp.ut_time = now->tv_sec;
+       (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
+       if (hostname)
+               (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
+       (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+       login(&utmp);
+}
+
+static void
+dolastlog(pam_handle_t *pamh, int quiet, const struct passwd *pwd,
+    const char *hostname, const char *tty, const struct timeval *now)
+{
+       struct lastlog ll;
+       int fd;
+
+       if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) == -1) {
+               logit(LOG_NOTICE, "Cannot open `%s' %m", _PATH_LASTLOG);
+               return;
+       }
+       (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
+
+       if (!quiet) {
+               if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
+                   ll.ll_time != 0)
+                       domsg(pamh, ll.ll_time, ll.ll_host,
+                           sizeof(ll.ll_host), ll.ll_line,
+                           sizeof(ll.ll_line));
+               (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET);
+       }
+
+       ll.ll_time = now->tv_sec;
+       (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+
+       if (hostname)
+               (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+       else
+               (void)memset(ll.ll_host, 0, sizeof(ll.ll_host));
+
+       (void)write(fd, &ll, sizeof(ll));
+       (void)close(fd);
+
+       PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
+}
+#endif
 
 PAM_MODULE_ENTRY("pam_lastlog");
+
index 9c51627..4b158f1 100644 (file)
@@ -29,6 +29,7 @@ SUBDIR=       atrun \
        tcpd \
        telnetd \
        tftpd \
+       utmp_update \
        xtend \
        ypxfr
 
index b85e7e8..501d1d3 100644 (file)
@@ -1,12 +1,16 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/4/93
 # $FreeBSD: src/libexec/talkd/Makefile,v 1.6.2.2 2001/10/18 12:30:42 des Exp $
 
-.PATH:  ${.CURDIR}/../../usr.bin/wall
+.PATH:  ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../../usr.bin/who
 
 PROG=  ntalkd
-SRCS=  talkd.c announce.c process.c table.c print.c ttymsg.c
+SRCS=  talkd.c announce.c process.c table.c print.c ttymsg.c utmpentry.c
 MAN=   talkd.8
 
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
 CFLAGS+=-I${.CURDIR}/../../usr.bin/wall
+CFLAGS+=-I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
 
 .include <bsd.prog.mk>
index 3c7257e..70ec159 100644 (file)
@@ -54,7 +54,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <syslog.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
 #include "extern.h"
 
@@ -183,47 +183,41 @@ do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
 int
 find_user(const char *name, char *tty)
 {
-       struct utmp ubuf;
+       struct utmpentry *ep;
        int status;
-       FILE *fd;
        struct stat statb;
        time_t best = 0;
-       char line[sizeof(ubuf.ut_line) + 1];
-       char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
+       char ftty[sizeof(_PATH_DEV) + sizeof(ep->line)];
+
+       getutentries(NULL, &ep);
 
-       if ((fd = fopen(_PATH_UTMP, "r")) == NULL) {
-               warnx("can't read %s", _PATH_UTMP);
-               return (FAILED);
-       }
 #define SCMPN(a, b)    strncmp(a, b, sizeof (a))
        status = NOT_HERE;
        (void) strcpy(ftty, _PATH_DEV);
-       while (fread((char *) &ubuf, sizeof ubuf, 1, fd) == 1)
-               if (SCMPN(ubuf.ut_name, name) == 0) {
-                       strncpy(line, ubuf.ut_line, sizeof(ubuf.ut_line));
-                       line[sizeof(ubuf.ut_line)] = '\0';
+       for (; ep; ep = ep->next)
+               if (SCMPN(ep->name, name) == 0) {
                        if (*tty == '\0' || best != 0) {
                                if (best == 0)
                                        status = PERMISSION_DENIED;
                                /* no particular tty was requested */
                                (void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
-                                   line);
+                                   ep->line);
                                if (stat(ftty, &statb) == 0) {
                                        if (!(statb.st_mode & 020))
                                                continue;
                                        if (statb.st_atime > best) {
                                                best = statb.st_atime;
-                                               (void) strcpy(tty, line);
+                                               (void) strcpy(tty, ep->line);
                                                status = SUCCESS;
                                                continue;
                                        }
                                }
                        }
-                       if (strcmp(line, tty) == 0) {
+                       if (strcmp(ep->line, tty) == 0) {
                                status = SUCCESS;
                                break;
                        }
                }
-       fclose(fd);
+
        return (status);
 }
diff --git a/libexec/utmp_update/Makefile b/libexec/utmp_update/Makefile
new file mode 100644 (file)
index 0000000..ac9f33f
--- /dev/null
@@ -0,0 +1,8 @@
+#      $NetBSD: Makefile,v 1.2 2002/09/18 06:21:15 lukem Exp $
+
+PROG=  utmp_update
+MAN=   utmp_update.8
+BINOWN=        root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/libexec/utmp_update/utmp_update.8 b/libexec/utmp_update/utmp_update.8
new file mode 100644 (file)
index 0000000..afa7c7a
--- /dev/null
@@ -0,0 +1,61 @@
+.\"    $NetBSD: utmp_update.8,v 1.1 2002/12/16 22:45:15 wiz Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Thomas Klausner.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd December 12, 2002
+.Dt UTMP_UPDATE 8
+.Os
+.Sh NAME
+.Nm utmp_update
+.Nd update utmpx database
+.Sh SYNOPSIS
+.Nm
+.Ar utmpx_entry
+.Sh DESCRIPTION
+.Nm
+is a helper program to allow a user to update his own
+.Xr utmpx 5
+entry.
+.Nm
+does some consistency checks on the
+.Xr strvis 3 Ns No -encoded
+.Ar utmpx_entry
+and then updates the
+.Xr utmpx 5
+database of currently logged in users.
+.Pp
+.Nm
+should not be called directly, but will normally only be called by
+.Xr pututxline 3
+if the privileges of the calling user are not sufficient.
+.Sh EXIT STATUS
+.Nm
+returns 0 on success, and 1 if an error occurred.
+.Sh SEE ALSO
+.Xr pututxline 3 ,
+.Xr utmpx 5
diff --git a/libexec/utmp_update/utmp_update.c b/libexec/utmp_update/utmp_update.c
new file mode 100644 (file)
index 0000000..1722c0d
--- /dev/null
@@ -0,0 +1,137 @@
+/*     $NetBSD: utmp_update.c,v 1.8 2008/04/28 20:23:04 martin Exp $    */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <vis.h>
+#include <err.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <utmpx.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+
+int main(int, char *[]);
+
+int
+main(int argc, char *argv[])
+{
+       struct utmpx *utx;
+       size_t len;
+       struct passwd *pwd;
+       struct stat st;
+       int fd;
+       int res;
+       uid_t euid, ruid;
+       char tty[MAXPATHLEN];
+
+       euid = geteuid();
+       ruid = getuid();
+       if (seteuid(ruid) == -1)
+               err(1, "seteuid");
+
+       if (argc != 2) {
+               (void)fprintf(stderr, "Usage: %s <vis-utmpx-entry>\n",
+                       getprogname());
+               exit(1);
+       }
+
+       len = strlen(argv[1]);
+
+       if (len > sizeof(*utx) * 4 + 1 || len < sizeof(*utx))
+               errx(1, "Bad argument");
+
+       if ((utx = malloc(len)) == NULL)
+               err(1, NULL);
+
+       res = strunvis((char *)utx, argv[1]);
+       if (res != (int)sizeof(*utx))
+               errx(1, "Decoding error %s %d != %zu", argv[1], res, sizeof(*utx));
+
+       switch (utx->ut_type) {
+       case USER_PROCESS:
+       case DEAD_PROCESS:
+               break;
+       default:
+               errx(1, "Invalid utmpx type %d", (int)utx->ut_type);
+       }
+
+       if (ruid != 0) {
+               if ((pwd = getpwuid(ruid)) == NULL)
+                       errx(1, "User %lu does not exist in password database",
+                           (long)ruid);
+
+               if (strcmp(pwd->pw_name, utx->ut_name) != 0)
+                       errx(1, "Current user `%s' does not match "
+                           "`%s' in utmpx entry", pwd->pw_name, utx->ut_name);
+       }
+
+       (void)snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, utx->ut_line);
+       fd = open(tty, O_RDONLY|O_NONBLOCK, 0);
+       if (fd != -1) {
+               if (fstat(fd, &st) == -1)
+                       err(1, "Cannot stat `%s'", tty);
+               if (ruid != 0 && st.st_uid != ruid)
+                       errx(1, "%s: Is not owned by you", tty);
+               if (!isatty(fd))
+                       errx(1, "%s: Not a tty device", tty);
+               (void)close(fd);
+               if (access(tty, W_OK|R_OK) == -1)
+                       err(1, "%s", tty);
+       } else {
+               struct utmpx utold, *utoldp;
+               /*
+                * A daemon like ftpd that does not use a tty line? 
+                * We only allow it to kill its own existing entries 
+                */
+               if (utx->ut_type != DEAD_PROCESS)
+                       err(1, "Cannot open `%s'", tty);
+
+               (void)memcpy(utold.ut_line, utx->ut_line, sizeof(utx->ut_line));
+               if ((utoldp = getutxline(&utold)) == NULL)
+                       err(1, "Cannot find existing entry for `%s'",
+                           utx->ut_line);
+               if (utoldp->ut_pid != getppid())
+                       err(1, "Cannot modify entry for `%s'", tty);
+       }
+
+       (void)seteuid(euid);
+       if (pututxline(utx) == NULL)
+               err(1, "Cannot update utmp entry");
+
+       return 0;
+}
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 d1af3a4..7475127 100644 (file)
@@ -61,6 +61,7 @@ MAN=  acct.5 \
        utf2.5 \
        utf8.5 \
        utmp.5 \
+       utmpx.5 \
        uuids.5 \
        varsym.conf.5
 
@@ -78,5 +79,7 @@ MLINKS+=passwd.5 master.passwd.5
 MLINKS+=resolver.5 resolv.conf.5
 MLINKS+=utmp.5 lastlog.5 \
        utmp.5 wtmp.5
+MLINKS+=utmpx.5 lastlogx.5 \
+       utmpx.5 wtmpx.5
 
 .include <bsd.prog.mk>
diff --git a/share/man/man5/utmpx.5 b/share/man/man5/utmpx.5
new file mode 100644 (file)
index 0000000..26cb4ab
--- /dev/null
@@ -0,0 +1,140 @@
+.\"    $NetBSD: utmpx.5,v 1.7 2008/04/30 13:10:57 martin Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Thomas Klausner.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd January 31, 2007
+.Dt UTMPX 5
+.Os
+.Sh NAME
+.Nm utmpx ,
+.Nm wtmpx ,
+.Nm lastlogx
+.Nd user accounting database
+.Sh SYNOPSIS
+.In utmpx.h
+.Sh DESCRIPTION
+In contrast to
+.Pa utmp
+and
+.Pa wtmp ,
+the extended databases in
+.Pa utmpx
+and
+.Pa wtmpx
+reserve more space for logging hostnames, and also
+information on a process' ID, termination signal and exit status.
+.Pp
+The
+.In utmpx.h
+header defines the structures and functions for logging user.
+Currently logged in users are tracked in
+.Pa /var/run/utmpx ,
+a list of all logins and logouts, as well as all shutdowns, reboots
+and date changes, is kept in
+.Pa /var/log/wtmpx ,
+and the last login of each user is noted in
+.Pa /var/log/lastlogx .
+.Pp
+The interface to the
+.Nm utmpx
+file is described in
+.Xr getutxent 3 .
+.Pp
+The
+.Nm wtmpx
+file can grow rapidly on busy systems, and is normally rotated with
+.Xr newsyslog 8 .
+.Pp
+In the event of a date change, a shutdown, or a reboot, the following
+items are logged in the
+.Nm wtmpx
+file:
+.Bl -tag -width shutdownxx -compact -offset indent
+.It Li date
+The system time has been manually or automatically updated by
+.Xr date 1 .
+The command name
+.Em date
+is recorded in the field
+.Fa ut_name .
+In the field
+.Fa ut_line ,
+the character
+.Ql \\*(Ba
+indicates the time prior to the change, and the character
+.Ql \&{
+indicates the new time.
+.It Li reboot
+.It Li shutdown
+A system reboot or shutdown has been initiated.
+The character
+.Ql \&~
+is placed in the field
+.Fa ut_line ,
+and
+.Li reboot
+or
+.Li shutdown
+in the field
+.Fa ut_name
+(see
+.Xr shutdown 8
+and
+.Xr reboot 8 ) ,
+using
+.Xr logwtmpx 3 .
+.Pp
+.El
+.Sh FILES
+.Bl -tag -width /var/log/lastlogx -compact
+.It Pa /var/run/utmpx
+The
+.Nm utmpx
+file.
+.It Pa /var/log/wtmpx
+The
+.Nm wtmpx
+file.
+.It Pa /var/log/lastlogx
+The
+.Nm lastlogx
+file.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr login 1 ,
+.Xr rwho 1 ,
+.Xr w 1 ,
+.Xr who 1 ,
+.Xr endutxent 3 ,
+.Xr logwtmpx 3 ,
+.Xr utmp 5 ,
+.Xr ac 8 ,
+.Xr init 8 ,
+.Xr newsyslog 8 ,
+.Xr reboot 8
index 4c1b8c8..2117052 100644 (file)
@@ -2,8 +2,15 @@
 # $FreeBSD: src/usr.bin/finger/Makefile,v 1.1.1.1.14.2 2001/04/25 11:29:20 ru Exp $
 # $DragonFly: src/usr.bin/finger/Makefile,v 1.3 2007/08/27 16:50:53 pavalos Exp $
 
+.PATH: ${.CURDIR}/../../usr.bin/who
+
 PROG=  finger
-SRCS=  finger.c lprint.c net.c sprint.c util.c
+SRCS=  finger.c lprint.c net.c sprint.c util.c utmpentry.c
 MAN=   finger.1 finger.conf.5
 
+DPADD+=        ${LIBUTIL}
+LDADD+=        -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index 726322c..26b456f 100644 (file)
@@ -50,10 +50,11 @@ extern int oflag;
 extern int lflag;
 extern int Tflag;
 extern sa_family_t family;
+struct utmpentry;
 
 void    enter_lastlog(PERSON *);
 PERSON *enter_person(struct passwd *);
-void    enter_where(struct utmp *, PERSON *);
+void    enter_where(struct utmpentry *, PERSON *);
 PERSON *find_person(char *);
 int            hide(struct passwd *);
 void    lflag_print(void);
index 4089f76..16a14c7 100644 (file)
@@ -73,7 +73,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 #include <locale.h>
 
 #include "finger.h"
@@ -223,25 +223,19 @@ loginlist(void)
        PERSON *pn;
        DBT data, key;
        struct passwd *pw;
-       struct utmp user;
+       struct utmpentry *ep;
        int r, sflag1;
-       char name[UT_NAMESIZE + 1];
 
-       if (!freopen(_PATH_UTMP, "r", stdin))
-               err(1, "%s", _PATH_UTMP);
-       name[UT_NAMESIZE] = '\0';
-       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
-               if (!user.ut_name[0])
-                       continue;
-               if ((pn = find_person(user.ut_name)) == NULL) {
-                       bcopy(user.ut_name, name, UT_NAMESIZE);
-                       if ((pw = getpwnam(name)) == NULL)
+       getutentries(NULL, &ep);
+       for (; ep; ep = ep->next) {
+               if ((pn = find_person(ep->name)) == NULL) {
+                       if ((pw = getpwnam(ep->name)) == NULL)
                                continue;
                        if (hide(pw))
                                continue;
                        pn = enter_person(pw);
                }
-               enter_where(&user, pn);
+               enter_where(ep, pn);
        }
        if (db && lflag)
                for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
@@ -262,7 +256,7 @@ userlist(int argc, char **argv)
 {
        PERSON *pn;
        DBT data, key;
-       struct utmp user;
+       struct utmpentry *ep;
        struct passwd *pw;
        int r, sflag1, *used, *ip;
        char **ap, **nargv, **np, **p;
@@ -367,14 +361,11 @@ net:      for (p = nargv; *p;) {
         * Scan thru the list of users currently logged in, saving
         * appropriate data whenever a match occurs.
         */
-       if (!freopen(_PATH_UTMP, "r", stdin))
-               err(1, "%s", _PATH_UTMP);
-       while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
-               if (!user.ut_name[0])
-                       continue;
-               if ((pn = find_person(user.ut_name)) == NULL)
+       getutentries(NULL, &ep);
+       for (; ep; ep = ep->next) {
+               if ((pn = find_person(ep->name)) == NULL)
                        continue;
-               enter_where(&user, pn);
+               enter_where(ep, pn);
        }
        if (db)
                for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
index 71edcd4..3913905 100644 (file)
@@ -60,8 +60,8 @@ typedef struct where {
        short writable;                 /* tty is writable */
        time_t loginat;                 /* time of (last) login */
        time_t idletime;                /* how long idle (if logged in) */
-       char tty[UT_LINESIZE+1];        /* null terminated tty line */
-       char host[UT_HOSTSIZE+1];       /* null terminated remote host name */
+       char *tty;      /* null terminated tty line */
+       char *host;     /* null terminated remote host name */
 } WHERE;
 
 #define UNPRIV_NAME    "nobody"        /* Preferred privilege level */
index 5279ec1..7128808 100644 (file)
@@ -52,6 +52,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include "utmpentry.h"
 #include <utmp.h>
 #include "finger.h"
 #include "pathnames.h"
@@ -150,17 +151,15 @@ enter_lastlog(PERSON *pn)
 }
 
 void
-enter_where(struct utmp *ut, PERSON *pn)
+enter_where(struct utmpentry *ep, PERSON *pn)
 {
        WHERE *w;
 
        w = walloc(pn);
        w->info = LOGGEDIN;
-       bcopy(ut->ut_line, w->tty, UT_LINESIZE);
-       w->tty[UT_LINESIZE] = 0;
-       bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
-       w->host[UT_HOSTSIZE] = 0;
-       w->loginat = (time_t)ut->ut_time;
+       w->tty = ep->line;
+       w->host = ep->host;
+       w->loginat = (time_t)ep->tv.tv_sec;
        find_idle_and_ttywrite(w);
 }
 
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;
@@ -408,17 +262,34 @@ addarg(int type, char *arg)
        arglist = cur;
 }
 
+/*
+ * 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
index 554c38b..a3b793c 100644 (file)
@@ -240,8 +240,8 @@ main(int argc, char **argv)
                snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
                ttyn = tname;
        }
-       if ((tty = strrchr(ttyn, '/')) != NULL)
-               ++tty;
+       if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV) -1) == 0)
+               tty = ttyn + sizeof(_PATH_DEV) -1;
        else
                tty = ttyn;
 
index eb67d47..2d8d1f7 100644 (file)
@@ -1,14 +1,22 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
 #      $DragonFly: src/usr.bin/systat/Makefile,v 1.7 2008/11/10 04:59:45 swildner Exp $
 
+.PATH: ${.CURDIR}/../../usr.bin/who
+
 PROG=  systat
 CFLAGS+=-DINET6 -I${.CURDIR}/../../sys
 SRCS=  cmds.c cmdtab.c convtbl.c devs.c fetch.c ifcmds.c ifstat.c iostat.c \
        keyboard.c main.c mbufs.c netcmds.c netstat.c pigs.c sensors.c swap.c \
-       icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c symbols.c
+       icmp.c mode.c ip.c tcp.c vmstat.c ip6.c icmp6.c vmmeter.c symbols.c \
+       utmpentry.c
 DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM} ${LIBDEVSTAT} ${LIBKINFO}
 LDADD= -lcurses -ltermcap -lm -lkvm -ldevstat -lkinfo
 BINGRP=        kmem
 BINMODE=2555
 
+DPADD+=        ${LIBUTIL}
+LDADD+=        -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index 87e1e5a..2ff380b 100644 (file)
@@ -63,7 +63,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 #include <devstat.h>
 #include "systat.h"
 #include "extern.h"
@@ -109,7 +109,6 @@ static void putlongdoublez(long double, int, int, int, int, int);
 static int ucount(void);
 
 static int ncpu;
-static int ut;
 static char buf[26];
 static time_t t;
 static double etime;
@@ -119,16 +118,12 @@ static    char **intrname;
 static int nextintsrow;
 static  int extended_vm_stats;
 
-struct utmp utmp;
 
 
 WINDOW *
 openkre(void)
 {
 
-       ut = open(_PATH_UTMP, O_RDONLY);
-       if (ut < 0)
-               error("No utmp");
        return (stdscr);
 }
 
@@ -136,7 +131,6 @@ void
 closekre(WINDOW *w)
 {
 
-       (void) close(ut);
        if (w == NULL)
                return;
        wclear(w);
@@ -646,15 +640,13 @@ cmdkre(const char *cmd, char *args)
 static int
 ucount(void)
 {
+       struct utmpentry *ep;
        int nusers = 0;
 
-       if (ut < 0)
-               return (0);
-       while (read(ut, &utmp, sizeof(utmp)))
-               if (utmp.ut_name[0] != '\0')
-                       nusers++;
+       getutentries(NULL, &ep);
+       for (; ep; ep = ep->next)
+               nusers++;
 
-       lseek(ut, 0L, L_SET);
        return (nusers);
 }
 
index 6b9ad03..cf0929c 100644 (file)
@@ -1,6 +1,13 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
 # $DragonFly: src/usr.bin/users/Makefile,v 1.3 2007/08/27 16:51:00 pavalos Exp $
+.PATH: ${.CURDIR}/../../usr.bin/who
 
 PROG=  users
+SRCS=  users.c utmpentry.c
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
 
 .include <bsd.prog.mk>
index 473312e..a0ae65e 100644 (file)
@@ -42,9 +42,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
-typedef char   namebuf[UT_NAMESIZE];
+typedef char   namebuf[32];
 
 static int scmp(const void *, const void *);
 static void usage(void);
@@ -52,11 +52,11 @@ static void usage(void);
 int
 main(int argc, char **argv)
 {
+       struct utmpentry *ep;
        namebuf *names = NULL;
        int ncnt = 0;
        int nmax = 0;
        int cnt;
-       struct utmp utmp;
        int ch;
 
        while ((ch = getopt(argc, argv, "")) != -1) {
@@ -68,27 +68,24 @@ main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
-       if (!freopen(_PATH_UTMP, "r", stdin))
-               err(1, "can't open %s", _PATH_UTMP);
-       while (fread((char *)&utmp, sizeof(utmp), 1, stdin) == 1) {
-               if (*utmp.ut_name) {
-                       if (ncnt >= nmax) {
-                               nmax += 32;
-                               names = realloc(names,
-                                       sizeof (*names) * nmax);
-                               if (names == NULL)
-                                       err(1, "realloc");
-                       }
-                       strncpy(names[ncnt], utmp.ut_name, UT_NAMESIZE);
-                       ++ncnt;
+       getutentries(NULL, &ep);
+       for (; ep; ep = ep->next) {
+               if (ncnt >= nmax) {
+                       nmax += 32;
+                       names = realloc(names,
+                               sizeof (*names) * nmax);
+                       if (names == NULL)
+                               err(1, "realloc");
                }
+               strcpy(names[ncnt], ep->name);
+               ++ncnt;
        }
        if (ncnt) {
-               qsort(names, ncnt, UT_NAMESIZE, scmp);
-               printf("%.*s", UT_NAMESIZE, names[0]);
+               qsort(names, ncnt, 32, scmp);
+               printf("%.*s", 32, names[0]);
                for (cnt = 1; cnt < ncnt; ++cnt) {
-                       if (strncmp(names[cnt], names[cnt - 1], UT_NAMESIZE))
-                               printf(" %.*s", UT_NAMESIZE, names[cnt]);
+                       if (strcmp(names[cnt], names[cnt - 1]))
+                               printf(" %.*s", 32, names[cnt]);
                }
                printf("\n");
        }
@@ -105,5 +102,5 @@ usage(void)
 int
 scmp(const void *p, const void *q)
 {
-       return(strncmp(p, q, UT_NAMESIZE));
+       return(strncmp(p, q, 32));
 }
index fa49280..2e668bc 100644 (file)
@@ -12,6 +12,7 @@ LDADD=        -lkvm
 LINKS= ${BINDIR}/w ${BINDIR}/uptime
 WARNS?=        2
 
+CFLAGS+=       -DSUPPORT_UTMP -DSUPPORT_UTMPX
 .PATH: ${.CURDIR}/../../bin/ps
 
 .include <bsd.prog.mk>
index c208f5e..023748b 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#ifdef SUPPORT_UTMP
 #include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
 #include <vis.h>
 
 #include <arpa/nameser.h>
 #include "extern.h"
 
 struct timeval boottime;
+#ifdef SUPPORT_UTMP
 struct utmp    utmp;
+#endif
 struct winsize ws;
 kvm_t         *kd;
 time_t         now;            /* the current time of day */
+time_t         then;
 time_t         uptime;         /* time of last reboot & elapsed time since */
 int            ttywidth;       /* width of tty */
 int            argwidth;       /* width of tty */
@@ -94,24 +102,33 @@ int                use_ampm;       /* use AM/PM time */
 int             use_comma;      /* use comma as floats separator */
 char         **sel_users;      /* login array of particular users selected */
 char           domain[MAXHOSTNAMELEN];
+int maxname = 8, maxline = 3, maxhost = 16;
 
 /*
  * One of these per active utmp entry.
  */
 struct entry {
        struct  entry *next;
-       struct  utmp utmp;
+       char name[UTX_USERSIZE + 1];
+       char line[UTX_LINESIZE + 1];
+       char host[UTX_HOSTSIZE + 1];
+       char type[2];
+       struct timeval tv;
        dev_t   tdev;                   /* dev_t of terminal */
        time_t  idle;                   /* idle time of terminal in seconds */
        struct  kinfo_proc *kp;         /* `most interesting' proc */
        char    *args;                  /* arg list of interesting process */
        struct  kinfo_proc *dkp;        /* debug option proc list */
+       pid_t   pid;                    /* pid or ~0 if not known */
 } *ep, *ehead = NULL, **nextp = &ehead;
 
 #define debugproc(p) *((struct kinfo_proc **)&(p)->kp_spare[0])
 
 static void             pr_header(time_t *, int);
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
 static struct stat     *ttystat(char *, int);
+static void    process(struct entry *);
+#endif
 static void             usage(int);
 static int              this_is_uptime(const char *s);
 
@@ -123,12 +140,15 @@ main(int argc, char **argv)
        struct kinfo_proc *kp;
        struct kinfo_proc *dkp;
        struct hostent *hp;
-       struct stat *stp;
-       FILE *ut;
        in_addr_t l;
-       time_t touched;
        int ch, i, nentries, nusers, wcmd, longidle, dropgid;
        char *memf, *nlistf, *p, *x;
+#ifdef SUPPORT_UTMP
+       struct utmp *ut;
+#endif
+#ifdef SUPPORT_UTMPX
+       struct utmpx *utx;
+#endif
        char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
 
        (void)setlocale(LC_ALL, "");
@@ -195,62 +215,116 @@ main(int argc, char **argv)
                errx(1, "%s", errbuf);
 
        (void)time(&now);
-       if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
-               err(1, "%s", _PATH_UTMP);
+#ifdef SUPPORT_UTMPX
+       setutxent();
+#endif
+#ifdef SUPPORT_UTMP
+       setutent();
+#endif
 
        if (*argv)
                sel_users = argv;
 
-       for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
-               if (utmp.ut_name[0] == '\0')
+       nusers = 0;
+#ifdef SUPPORT_UTMPX
+       while ((utx = getutxent()) != NULL) {
+               if (utx->ut_type != USER_PROCESS)
                        continue;
-               if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
-                       continue;       /* corrupted record */
                ++nusers;
-               if (wcmd == 0)
-                       continue;
+
                if (sel_users) {
                        int usermatch;
                        char **user;
 
                        usermatch = 0;
                        for (user = sel_users; !usermatch && *user; user++)
-                               if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
+                               if (!strncmp(utx->ut_name, *user, UTX_USERSIZE))
                                        usermatch = 1;
                        if (!usermatch)
                                continue;
                }
+
                if ((ep = calloc(1, sizeof(struct entry))) == NULL)
-                       errx(1, "calloc");
-               *nextp = ep;
-               nextp = &ep->next;
-               memmove(&ep->utmp, &utmp, sizeof(struct utmp));
-               ep->tdev = stp->st_rdev;
-#ifdef CPU_CONSDEV
-               /*
-                * If this is the console device, attempt to ascertain
-                * the true console device dev_t.
-                */
-               if (ep->tdev == 0) {
-                       int mib[2];
-                       size_t size;
-
-                       mib[0] = CTL_MACHDEP;
-                       mib[1] = CPU_CONSDEV;
-                       size = sizeof(dev_t);
-                       (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
+                       err(1, NULL);
+               (void)memcpy(ep->name, utx->ut_name, sizeof(utx->ut_name));
+               (void)memcpy(ep->line, utx->ut_line, sizeof(utx->ut_line));
+               (void)memcpy(ep->host, utx->ut_host, sizeof(utx->ut_host));
+               ep->name[sizeof(utx->ut_name)] = '\0';
+               ep->line[sizeof(utx->ut_line)] = '\0';
+               ep->host[sizeof(utx->ut_host)] = '\0';
+#if 1
+               /* XXX: Actually we don't support the utx->ut_ss stuff yet */
+               if (!nflag || getnameinfo((struct sockaddr *)&utx->ut_ss,
+                   utx->ut_ss.ss_len, ep->host, sizeof(ep->host), NULL, 0,
+                   NI_NUMERICHOST) != 0) {
+                       (void)memcpy(ep->host, utx->ut_host,
+                           sizeof(utx->ut_host));
+                       ep->host[sizeof(utx->ut_host)] = '\0';
                }
 #endif
-               touched = stp->st_atime;
-               if (touched < ep->utmp.ut_time) {
-                       /* tty untouched since before login */
-                       touched = ep->utmp.ut_time;
+               ep->type[0] = 'x';
+               ep->tv = utx->ut_tv;
+               ep->pid = utx->ut_pid;
+
+               *nextp = ep;
+               nextp = &(ep->next);
+               if (wcmd != 0)
+                       process(ep);
+       }
+#endif
+
+#ifdef SUPPORT_UTMP
+       while ((ut = getutent()) != NULL) {
+               if (ut->ut_name[0] == '\0')
+                       continue;
+               ++nusers;
+               if (sel_users) {
+                       int usermatch;
+                       char **user;
+
+                       usermatch = 0;
+                       for (user = sel_users; !usermatch && *user; user++)
+                               if (!strncmp(ut->ut_name, *user, UT_NAMESIZE))
+                                       usermatch = 1;
+                       if (!usermatch)
+                               continue;
                }
-               if ((ep->idle = now - touched) < 0)
-                       ep->idle = 0;
+
+               /* Don't process entries that we have utmpx for */
+               for (ep = ehead; ep != NULL; ep = ep->next) {
+                       if (strncmp(ep->line, ut->ut_line,
+                           sizeof(ut->ut_line)) == 0)
+                               break;
+               }
+               if (ep != NULL) {
+                       --nusers; /* Duplicate entry */
+                       continue;
+               }
+
+               if ((ep = calloc(1, sizeof(struct entry))) == NULL)
+                       err(1, NULL);
+               (void)memcpy(ep->name, ut->ut_name, sizeof(ut->ut_name));
+               (void)memcpy(ep->line, ut->ut_line, sizeof(ut->ut_line));
+               (void)memcpy(ep->host, ut->ut_host, sizeof(ut->ut_host));
+               ep->name[sizeof(ut->ut_name)] = '\0';
+               ep->line[sizeof(ut->ut_line)] = '\0';
+               ep->host[sizeof(ut->ut_host)] = '\0';
+               ep->tv.tv_sec = ut->ut_time;
+
+               *nextp = ep;
+               nextp = &(ep->next);
+               if (wcmd != 0)
+                       process(ep);
        }
-       (void)fclose(ut);
+#endif
 
+#ifdef SUPPORT_UTMPX
+       endutxent();
+#endif
+#ifdef SUPPORT_UTMP
+       endutent();
+#endif 
+       
        if (header || wcmd == 0) {
                pr_header(&now, nusers);
                if (wcmd == 0) {
@@ -263,12 +337,12 @@ main(int argc, char **argv)
 #define HEADER_FROM            "FROM"
 #define HEADER_LOGIN_IDLE      "LOGIN@  IDLE "
 #define HEADER_WHAT            "WHAT\n"
-#define WUSED  (UT_NAMESIZE + UT_LINESIZE + UT_HOSTSIZE + \
+#define WUSED  (maxname + maxline + maxhost + \
                sizeof(HEADER_LOGIN_IDLE) + 3)  /* header width incl. spaces */ 
                (void)printf("%-*.*s %-*.*s %-*.*s  %s", 
-                               UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
-                               UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
-                               UT_HOSTSIZE, UT_HOSTSIZE, HEADER_FROM,
+                               maxname, maxname, HEADER_USER,
+                               maxline, maxline, HEADER_TTY,
+                               maxhost, maxhost, HEADER_FROM,
                                HEADER_LOGIN_IDLE HEADER_WHAT);
        }
 
@@ -299,6 +373,10 @@ main(int argc, char **argv)
                                ep->dkp = kp;
                                debugproc(kp) = dkp;
                        }
+                       if (ep->pid != 0 && ep->pid == kp->kp_pid) {
+                               ep->kp = kp;
+                               break;
+                       }
                }
        }
        if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
@@ -337,6 +415,23 @@ main(int argc, char **argv)
                        *nextp = save;
                }
        }
+#if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX)
+       else if (ehead != NULL) {
+               struct entry *from = ehead, *save;
+
+               ehead = NULL;
+               while (from != NULL) {
+                       for (nextp = &ehead;
+                           (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
+                           nextp = &(*nextp)->next)
+                               continue;
+                       save = from;
+                       from = from->next;
+                       save->next = *nextp;
+                       *nextp = save;
+               }
+       }
+#endif
 
        if (!nflag) {
                if (gethostname(domain, sizeof(domain)) < 0 ||
@@ -349,10 +444,10 @@ main(int argc, char **argv)
        }
 
        for (ep = ehead; ep != NULL; ep = ep->next) {
-               char host_buf[UT_HOSTSIZE + 1];
+               char host_buf[UTX_HOSTSIZE + 1];
 
-               host_buf[UT_HOSTSIZE] = '\0';
-               strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
+               host_buf[UTX_HOSTSIZE] = '\0';
+               strncpy(host_buf, ep->host, maxhost);
                p = *host_buf ? host_buf : "-";
                if ((x = strchr(p, ':')) != NULL)
                        *x++ = '\0';
@@ -396,13 +491,14 @@ main(int argc, char **argv)
                        }
                }
                (void)printf("%-*.*s %-*.*s %-*.*s ",
-                   UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
-                   UT_LINESIZE, UT_LINESIZE,
-                   strncmp(ep->utmp.ut_line, "tty", 3) &&
-                   strncmp(ep->utmp.ut_line, "cua", 3) ?
-                   ep->utmp.ut_line : ep->utmp.ut_line + 3,
-                   UT_HOSTSIZE, UT_HOSTSIZE, *p ? p : "-");
-               pr_attime(&ep->utmp.ut_time, &now);
+                   maxname, maxname, ep->name,
+                   maxline, maxline,
+                   strncmp(ep->line, "tty", 3) &&
+                   strncmp(ep->line, "cua", 3) ?
+                   ep->line : ep->line + 3,
+                   maxhost, maxhost, *p ? p : "-");
+               then = (time_t)ep->tv.tv_sec;
+               pr_attime(&then, &now);
                longidle = pr_idle(ep->idle);
                (void)printf("%.*s\n", argwidth - longidle, ep->args);
        }
@@ -516,3 +612,51 @@ this_is_uptime(const char *s)
                return (0);
        return (-1);
 }
+
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+static void
+process(struct entry *ep)
+{
+       struct stat *stp;
+       time_t touched;
+       int max;
+
+       if ((max = strlen(ep->name)) > maxname)
+               maxname = max;
+       if ((max = strlen(ep->line)) > maxline)
+               maxline = max;
+       if ((max = strlen(ep->host)) > maxhost)
+               maxhost = max;
+
+       ep->tdev = 0;
+       ep->idle = (time_t)-1;
+
+       if (!(stp = ttystat(ep->line, maxline)))
+               return; /* corrupted record */
+
+       ep->tdev = stp->st_rdev;
+#ifdef CPU_CONSDEV
+       /*
+        * If this is the console device, attempt to ascertain
+        * the true console device dev_t.
+        */
+       if (ep->tdev == 0) {
+               int mib[2];
+               size_t size;
+
+               mib[0] = CTL_MACHDEP;
+               mib[1] = CPU_CONSDEV;
+               size = sizeof(dev_t);
+               (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
+       }
+#endif
+
+       touched = stp->st_atime;
+       if (touched < ep->tv.tv_sec) {
+               /* tty untouched since before login */
+               touched = ep->tv.tv_sec;
+       }
+       if ((ep->idle = now - touched) < 0)
+               ep->idle = 0;
+}
+#endif
index 46967ae..e0ceefb 100644 (file)
@@ -1,9 +1,16 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
 # $DragonFly: src/usr.bin/wall/Makefile,v 1.2 2007/08/27 16:51:01 pavalos Exp $
 
+.PATH: ${.CURDIR}/../../usr.bin/who
+
 PROG=  wall
-SRCS=  ttymsg.c wall.c
+SRCS=  ttymsg.c wall.c utmpentry.c
 BINGRP=        tty
 BINMODE=2555
 
+DPADD+=        ${LIBUTIL}
+LDADD+=        -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index c5733e6..ab3f335 100644 (file)
@@ -56,7 +56,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
 #include "ttymsg.h"
 
@@ -76,17 +76,14 @@ int
 main(int argc, char *argv[])
 {
        struct iovec iov;
-       struct utmp utmp;
+       struct utmpentry *ep;
        int ch;
        int ingroup;
-       FILE *fp;
        struct wallgroup *g;
        struct group *grp;
        char **np;
        const char *p;
        struct passwd *pw;
-       char line[sizeof(utmp.ut_line) + 1];
-       char username[sizeof(utmp.ut_name) + 1];
 
        (void)setlocale(LC_CTYPE, "");
 
@@ -123,18 +120,15 @@ main(int argc, char *argv[])
 
        makemsg(*argv);
 
-       if (!(fp = fopen(_PATH_UTMP, "r")))
-               err(1, "cannot read %s", _PATH_UTMP);
        iov.iov_base = mbuf;
        iov.iov_len = mbufsize;
+
+       getutentries(NULL, &ep);
        /* NOSTRICT */
-       while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) {
-               if (!utmp.ut_name[0])
-                       continue;
+       for (; ep; ep = ep->next) {
                if (grouplist) {
                        ingroup = 0;
-                       strlcpy(username, utmp.ut_name, sizeof(utmp.ut_name));
-                       pw = getpwnam(username);
+                       pw = getpwnam(ep->name);
                        if (!pw)
                                continue;
                        for (g = grouplist; g && ingroup == 0; g = g->next) {
@@ -144,7 +138,7 @@ main(int argc, char *argv[])
                                        ingroup = 1;
                                else if ((grp = getgrgid(g->gid)) != NULL) {
                                        for (np = grp->gr_mem; *np; np++) {
-                                               if (strcmp(*np, username) == 0) {
+                                               if (strcmp(*np, ep->name) == 0) {
                                                        ingroup = 1;
                                                        break;
                                                }
@@ -154,9 +148,11 @@ main(int argc, char *argv[])
                        if (ingroup == 0)
                                continue;
                }
-               strncpy(line, utmp.ut_line, sizeof(utmp.ut_line));
-               line[sizeof(utmp.ut_line)] = '\0';
-               if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL)
+               /* skip [xgk]dm/xserver entries (":0", ":1", etc.) */
+               if (ep->line[0] == ':' && isdigit((unsigned char)ep->line[1]))
+                       continue;
+               
+               if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL)
                        warnx("%s", p);
        }
        exit(0);
index 63c15dd..68d3b1d 100644 (file)
@@ -3,4 +3,8 @@
 
 PROG=  who
 
+SRCS+= who.c utmpentry.c
+
+CFLAGS+=       -DSUPPORT_UTMPX -DSUPPORT_UTMP
+
 .include <bsd.prog.mk>
diff --git a/usr.bin/who/utmpentry.c b/usr.bin/who/utmpentry.c
new file mode 100644 (file)
index 0000000..8f3c917
--- /dev/null
@@ -0,0 +1,358 @@
+/*     $NetBSD: utmpentry.c,v 1.16 2008/10/28 14:01:46 christos Exp $  */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/stat.h>
+
+#include <time.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+
+#include "utmpentry.h"
+
+/* Operations on timespecs. */
+#define        timespecclear(tsp)      (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define        timespecisset(tsp)      ((tsp)->tv_sec || (tsp)->tv_nsec)
+#define        timespeccmp(tsp, usp, cmp)                                      \
+       (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
+           ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
+           ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define        timespecadd(tsp, usp, vsp)                                      \
+       do {                                                            \
+               (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;          \
+               (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;       \
+               if ((vsp)->tv_nsec >= 1000000000L) {                    \
+                       (vsp)->tv_sec++;                                \
+                       (vsp)->tv_nsec -= 1000000000L;                  \
+               }                                                       \
+       } while (/* CONSTCOND */ 0)
+#define        timespecsub(tsp, usp, vsp)                                      \
+       do {                                                            \
+               (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;          \
+               (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;       \
+               if ((vsp)->tv_nsec < 0) {                               \
+                       (vsp)->tv_sec--;                                \
+                       (vsp)->tv_nsec += 1000000000L;                  \
+               }                                                       \
+       } while (/* CONSTCOND */ 0)
+#define timespec2ns(x) (((uint64_t)(x)->tv_sec) * 1000000000L + (x)->tv_nsec)
+
+
+/* Fail the compile if x is not true, by constructing an illegal type. */
+#define COMPILE_ASSERT(x) /*LINTED null effect */ \
+       ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
+
+
+#ifdef SUPPORT_UTMP
+static void getentry(struct utmpentry *, struct utmp *);
+static struct timespec utmptime = {0, 0};
+#endif
+#ifdef SUPPORT_UTMPX
+static void getentryx(struct utmpentry *, struct utmpx *);
+static struct timespec utmpxtime = {0, 0};
+#endif
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static int setup(const char *);
+static void adjust_size(struct utmpentry *e);
+#endif
+
+int maxname = 8, maxline = 8, maxhost = 16;
+int etype = 1 << USER_PROCESS;
+static int numutmp = 0;
+static struct utmpentry *ehead;
+
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void
+adjust_size(struct utmpentry *e)
+{
+       int max;
+
+       if ((max = strlen(e->name)) > maxname)
+               maxname = max;
+       if ((max = strlen(e->line)) > maxline)
+               maxline = max;
+       if ((max = strlen(e->host)) > maxhost)
+               maxhost = max;
+}
+
+static int
+setup(const char *fname)
+{
+       int what = 3;
+       struct stat st;
+       const char *sfname;
+
+       if (fname == NULL) {
+#ifdef SUPPORT_UTMPX
+               setutxent();
+#endif
+#ifdef SUPPORT_UTMP
+               setutent();
+#endif
+       } else {
+               size_t len = strlen(fname);
+               if (len == 0)
+                       errx(1, "Filename cannot be 0 length.");
+               what = fname[len - 1] == 'x' ? 1 : 2;
+               if (what == 1) {
+#ifdef SUPPORT_UTMPX
+                       if (utmpxname(fname) == 0)
+                               warnx("Cannot set utmpx file to `%s'",
+                                   fname);
+#else
+                       warnx("utmpx support not compiled in");
+#endif
+               } else {
+#ifdef SUPPORT_UTMP
+                       if (utmpname(fname) == 0)
+                               warnx("Cannot set utmp file to `%s'",
+                                   fname);
+#else
+                       warnx("utmp support not compiled in");
+#endif
+               }
+       }
+#ifdef SUPPORT_UTMPX
+       if (what & 1) {
+               sfname = fname ? fname : _PATH_UTMPX;
+               if (stat(sfname, &st) == -1) {
+                       warn("Cannot stat `%s'", sfname);
+                       what &= ~1;
+               } else {
+                       if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
+                           utmpxtime = st.st_mtimespec;
+                       else
+                           what &= ~1;
+               }
+       }
+#endif
+#ifdef SUPPORT_UTMP
+       if (what & 2) {
+               sfname = fname ? fname : _PATH_UTMP;
+               if (stat(sfname, &st) == -1) {
+                       warn("Cannot stat `%s'", sfname);
+                       what &= ~2;
+               } else {
+                       if (timespeccmp(&st.st_mtimespec, &utmptime, >))
+                               utmptime = st.st_mtimespec;
+                       else
+                               what &= ~2;
+               }
+       }
+#endif
+       return what;
+}
+#endif
+
+void
+endutentries(void)
+{
+       struct utmpentry *ep;
+
+#ifdef SUPPORT_UTMP
+       timespecclear(&utmptime);
+#endif
+#ifdef SUPPORT_UTMPX
+       timespecclear(&utmpxtime);
+#endif
+       ep = ehead;
+       while (ep) {
+               struct utmpentry *sep = ep;
+               ep = ep->next;
+               free(sep);
+       }
+       ehead = NULL;
+       numutmp = 0;
+}
+
+int
+getutentries(const char *fname, struct utmpentry **epp)
+{
+#ifdef SUPPORT_UTMPX
+       struct utmpx *utx;
+#endif
+#ifdef SUPPORT_UTMP
+       struct utmp *ut;
+#endif
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+       struct utmpentry *ep;
+       int what = setup(fname);
+       struct utmpentry **nextp = &ehead;
+       switch (what) {
+       case 0:
+               /* No updates */
+               *epp = ehead;
+               return numutmp;
+       default:
+               /* Need to re-scan */
+               ehead = NULL;
+               numutmp = 0;
+       }
+#endif
+
+#ifdef SUPPORT_UTMPX
+       while ((what & 1) && (utx = getutxent()) != NULL) {
+               if (fname == NULL && ((1 << utx->ut_type) & etype) == 0) {
+                       continue;
+               }
+               if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
+                       warn(NULL);
+                       return 0;
+               }
+               getentryx(ep, utx);
+               *nextp = ep;
+               nextp = &(ep->next);
+       }
+#endif
+
+#ifdef SUPPORT_UTMP
+       if ((etype & (1 << USER_PROCESS)) != 0) {
+               while ((what & 2) && (ut = getutent()) != NULL) {
+                       if (fname == NULL && (*ut->ut_name == '\0' ||
+                           *ut->ut_line == '\0'))
+                               continue;
+                       /* Don't process entries that we have utmpx for */
+                       for (ep = ehead; ep != NULL; ep = ep->next) {
+                               if (strncmp(ep->line, ut->ut_line,
+                                   sizeof(ut->ut_line)) == 0)
+                                       break;
+                       }
+                       if (ep != NULL)
+                               continue;
+                       if ((ep = calloc(1, sizeof(*ep))) == NULL) {
+                               warn(NULL);
+                               return 0;
+                       }
+                       getentry(ep, ut);
+                       *nextp = ep;
+                       nextp = &(ep->next);
+               }
+       }
+#endif
+       numutmp = 0;
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+       if (ehead != NULL) {
+               struct utmpentry *from = ehead, *save;
+               
+               ehead = NULL;
+               while (from != NULL) {
+                       for (nextp = &ehead;
+                           (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
+                           nextp = &(*nextp)->next)
+                               continue;
+                       save = from;
+                       from = from->next;
+                       save->next = *nextp;
+                       *nextp = save;
+                       numutmp++;
+               }
+       }
+       *epp = ehead;
+       return numutmp;
+#else
+       *epp = NULL;
+       return 0;
+#endif
+}
+
+#ifdef SUPPORT_UTMP
+static void
+getentry(struct utmpentry *e, struct utmp *up)
+{
+#if 1
+       COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+       COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+       COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+#endif
+
+       /*
+        * e has just been calloc'd. We don't need to clear it or
+        * append null-terminators, because its length is strictly
+        * greater than the source string. Use strncpy to _read_
+        * up->ut_* because they may not be terminated. For this
+        * reason we use the size of the _source_ as the length
+        * argument.
+        */
+       (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+       (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+       (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+       e->tv.tv_sec = up->ut_time;
+       e->tv.tv_usec = 0;
+       e->pid = 0;
+       e->term = 0;
+       e->exit = 0;
+       e->sess = 0;
+       e->type = USER_PROCESS;
+       adjust_size(e);
+}
+#endif
+
+#ifdef SUPPORT_UTMPX
+static void
+getentryx(struct utmpentry *e, struct utmpx *up)
+{
+#if 1
+       COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+       COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+       COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+#endif
+
+       /*
+        * e has just been calloc'd. We don't need to clear it or
+        * append null-terminators, because its length is strictly
+        * greater than the source string. Use strncpy to _read_
+        * up->ut_* because they may not be terminated. For this
+        * reason we use the size of the _source_ as the length
+        * argument.
+        */
+       (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+       (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+       (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+       e->tv = up->ut_tv;
+       e->pid = up->ut_pid;
+       e->term = up->ut_exit.e_termination;
+       e->exit = up->ut_exit.e_exit;
+       e->sess = up->ut_session;
+       e->type = up->ut_type;
+       adjust_size(e);
+}
+#endif
diff --git a/usr.bin/who/utmpentry.h b/usr.bin/who/utmpentry.h
new file mode 100644 (file)
index 0000000..421f36a
--- /dev/null
@@ -0,0 +1,76 @@
+/*     $NetBSD: utmpentry.h,v 1.6 2008/04/28 20:24:15 martin Exp $     */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#if defined(SUPPORT_UTMPX)
+# include <utmpx.h>
+# define WHO_NAME_LEN          _UTX_USERSIZE
+# define WHO_LINE_LEN          _UTX_LINESIZE
+# define WHO_HOST_LEN          _UTX_HOSTSIZE
+#elif defined(SUPPORT_UTMP)
+# include <utmp.h>
+# define WHO_NAME_LEN          UT_NAMESIZE
+# define WHO_LINE_LEN          UT_LINESIZE
+# define WHO_HOST_LEN          UT_HOSTSIZE
+#else
+# error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined!
+#endif
+
+
+struct utmpentry {
+       char name[WHO_NAME_LEN + 1];
+       char line[WHO_LINE_LEN + 1];
+       char host[WHO_HOST_LEN + 1];
+       struct timeval tv;
+       pid_t pid;
+       uint16_t term;
+       uint16_t exit;
+       uint16_t sess;
+       uint16_t type;
+       struct utmpentry *next;
+};
+
+extern int maxname, maxline, maxhost;
+extern int etype;
+
+/*
+ * getutentries provides a linked list of struct utmpentry and returns
+ * the number of entries. The first argument, if not null, names an 
+ * alternate utmp(x) file to look in.
+ *
+ * The memory returned by getutentries belongs to getutentries. The
+ * list returned (or elements of it) may be returned again later if
+ * utmp hasn't changed in the meantime.
+ *
+ * endutentries clears and frees the cached data.
+ */
+
+int getutentries(const char *, struct utmpentry **);
+void endutentries(void);
index 5d27479..8f27d32 100644 (file)
@@ -1,3 +1,5 @@
+.\"    $NetBSD: who.1,v 1.21 2007/01/17 16:37:41 christos Exp $
+.\"
 .\" Copyright (c) 1986, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
@@ -9,11 +11,7 @@
 .\" 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
+.\" 3. 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.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)who.1      8.2 (Berkeley) 12/30/93
-.\" $FreeBSD: src/usr.bin/who/who.1,v 1.7.2.5 2003/02/24 23:04:40 trhodes Exp $
-.\" $DragonFly: src/usr.bin/who/who.1,v 1.3 2004/10/29 17:09:09 liamfoy Exp $
 .\"
-.Dd October 25, 2004
+.Dd January 17, 2007
 .Dt WHO 1
 .Os
 .Sh NAME
 .Nm who
-.Nd display who is on the system
+.Nd display who is logged in
 .Sh SYNOPSIS
 .Nm
-.Op Fl bHmqsTu
-.Op Cm am I
+.Op Fl abdHlmqrstTuv
 .Op Ar file
+.Nm
+.Ar am i
 .Sh DESCRIPTION
 The
 .Nm
-utility displays information about currently logged in users.
-By default, this includes the login name, tty name, date and time of login and
-remote hostname if not local.
+utility displays a list of all users currently logged on, showing for
+each user the login name, tty name, the date and time of login, and
+hostname if not local.
+.Pp
+Available options:
 .Pp
-The options are as follows:
-.Bl -tag -width indent
+.Bl -tag -width file
+.It Fl a
+Same as
+.Fl -bdlprTtuv .
 .It Fl b
-Show date and time of last reboot.
+Time of last system boot.
+.It Fl d
+Print dead processes.
 .It Fl H
-Write column headings above the output.
+Write column headings above the regular output.
+.It Fl l
+Print system login processes.
 .It Fl m
-Show information about the terminal attached to standard input only.
+Only print information about the current terminal.
+This is the
+.Tn POSIX
+way of saying
+.Nm
+.Ar am i .
+.It Fl p
+Print active processes spawned by
+.Xr init 8 .
 .It Fl q
-.Dq "Quick mode" :
-List the names and number of logged in users in columns.
-All other command line options are ignored.
+.Dq Quick mode :
+List only the names and the number of users currently logged on.
+When this option is used, all other options are ignored.
+.It Fl r
+Print the current runlevel.
+Supported runlevels are:
+.Bl -tag -width "s (SINGLE_USER)"
+.It Dv d Pq Dv DEATH
+The system has halted.
+.It Dv s Pq Dv SINGLE_USER
+The system is running in single user mode.
+.It Dv r Pq Dv RUNCOM
+The system is executing
+.Pa /etc/rc .
+.It Dv t Pq Dv READ_TTYS
+The system is processing
+.Pa /etc/ttys .
+.It Dv m Pq Dv MULTI_USER
+The system is running in multi-user mode.
+.It Dv T Pq Dv CLEAN_TTYS
+The system is in the process of stopping processes
+associated with terminal devices.
+.It Dv c Pq Dv CATATONIA
+The system is in the process of shutting down and will
+not create new processes.
+.El
 .It Fl s
-Show the name, line and time fields only.
+List only the name, line and time fields.
 This is the default.
 .It Fl T
-Indicate whether each user is accepting messages.
-One of the following characters is written:
-.Pp
-.Bl -tag -width 1n -compact
-.It Li +
-User is accepting messages.
-.It Li \&-
-User is not accepting messages.
-.It Li \&?
-An error occurred.
-.El
+Print a character after the user name indicating the state of the
+terminal line:
+.Sq +
+if the terminal is writable;
+.Sq -
+if it is not;
+and
+.Sq \&?
+if a bad line is encountered.
+.It Fl t
+Print last system clock change.
 .It Fl u
-Show idle time for each user in hours and minutes as
-.Ar hh Ns : Ns Ar mm ,
-.Ql \&.
-if the user has been idle less that a minute, and
-.Dq Li old
-if the user has been idle more than 24 hours.
-.It Cm am I
-Equivalent to
-.Fl m .
-.El
-.Pp
+Print the idle time for each user, and the associated process ID.
+.It Fl v
+When printing of more information is requested with
+.Fl u ,
+this switch can be used to also printed
+process termination signals,
+process exit status,
+session id for windowing
+and the type of the entry, see documentation of ut_type in
+.Xr getutxent 3 .
+.It Ar \&am I
+Returns the invoker's real user name.
+.It Ar file
 By default,
 .Nm
 gathers information from the file
-.Pa /var/run/utmp .
-An alternate
+.Pa /var/run/utmpx .
+An alternative
 .Ar file
 may be specified which is usually
-.Pa /var/log/wtmp
+.Pa /var/log/wtmpx
 (or
+.Pa /var/log/wtmp ,
+or
+.Pa /var/log/wtmpx.[0-6]
+or
 .Pa /var/log/wtmp.[0-6]
 depending on site policy as
-.Pa wtmp
+.Pa wtmpx
 can grow quite large and daily versions may or may not
 be kept around after compression by
 .Xr ac 8 ) .
 The
+.Pa wtmpx
+and
 .Pa wtmp
 file contains a record of every login, logout,
 crash, shutdown and date change
 since
+.Pa wtmpx
+and
 .Pa wtmp
-was last truncated or
+were last truncated or
 created.
+.El
 .Pp
 If
+.Pa /var/log/wtmpx
+or
 .Pa /var/log/wtmp
-is being used as the file, the user name may be empty
-or one of the special characters '|', '}' and '~'.  Logouts produce
-an output line without any user name.  For more information on the
+are being used as the file, the user name may be empty
+or one of the special characters '|', '}' and '~'.
+Logouts produce an output line without any user name.
+For more information on the
 special characters, see
 .Xr utmp 5 .
-.Sh ENVIRONMENT
-The
-.Ev COLUMNS , LANG , LC_ALL
-and
-.Ev LC_TIME
-environment variables affect the execution of
-.Nm
-as described in
-.Xr environ 7 .
 .Sh FILES
 .Bl -tag -width /var/log/wtmp.[0-6] -compact
 .It Pa /var/run/utmp
+.It Pa /var/run/utmpx
 .It Pa /var/log/wtmp
 .It Pa /var/log/wtmp.[0-6]
+.It Pa /var/log/wtmpx
+.It Pa /var/log/wtmpx.[0-6]
 .El
-.Sh EXIT STATUS
-.Ex -std
 .Sh SEE ALSO
 .Xr last 1 ,
+.Xr mesg 1 ,
 .Xr users 1 ,
-.Xr w 1 ,
-.Xr utmp 5
+.Xr getuid 2 ,
+.Xr utmp 5 ,
+.Xr utmpx 5
 .Sh STANDARDS
 The
 .Nm
-utility conforms to
-.St -p1003.1-2001 .
+utility is expected to conform to
+.St -p1003.2-92 .
 .Sh HISTORY
 A
 .Nm
-command appeared in
-.At v1 .
+utility appeared in
+.At v6 .
index 1176155..ab9aff8 100644 (file)
@@ -1,6 +1,11 @@
-/*-
- * Copyright (c) 2002 Tim J. Robbins.
- * All rights reserved.
+/*     $NetBSD: who.c,v 1.22 2008/07/21 14:19:28 lukem Exp $   */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * 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)
  * 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/who/who.c,v 1.9.2.4 2002/12/21 00:44:58 tjr Exp $
- * $DragonFly: src/usr.bin/who/who.c,v 1.7 2008/06/05 18:06:33 swildner Exp $
  */
 
+#include <sys/cdefs.h>
+#include <sys/sysctl.h>
 #include <sys/types.h>
-#include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <sys/sysctl.h>
 
 #include <err.h>
-#include <errno.h>
-#include <langinfo.h>
-#include <limits.h>
 #include <locale.h>
-#include <paths.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#ifdef SUPPORT_UTMP
 #include <utmp.h>
-
-static void    print_boottime(void);
-static void    heading(void);
-static void    process_utmp(FILE *);
-static void    quick(FILE *);
-static void    row(struct utmp *);
-static int     ttywidth(void);
-static void    usage(void);
-static void    whoami(FILE *);
-
-static int     bflag;                  /* Show date and time of last reboot */
-static int     Hflag;                  /* Write column headings */
-static int     mflag;                  /* Show info about current terminal */
-static int     qflag;                  /* "Quick" mode */
-static int     sflag;                  /* Show name, line, time */
-static int     Tflag;                  /* Show terminal state */
-static int     uflag;                  /* Show idle time */
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+
+#include "utmpentry.h"
+
+static void print_boottime(void);
+static void output_labels(void);
+static void who_am_i(const char *, int);
+static void usage(void);
+static void process(const char *, int);
+static void eprint(const struct utmpentry *);
+static void print(const char *, const char *, time_t, const char *, pid_t pid,
+    uint16_t term, uint16_t xit, uint16_t sess, uint16_t type);
+static void quick(const char *);
+
+static int show_term;                  /* show term state */
+static int show_idle;                  /* show idle time */
+static int show_details;               /* show exit status etc. */
+static int bflag;                      /* Show date and time of last reboot */
+
+struct ut_type_names {
+  int type;
+  const char *name;
+} ut_type_names[] = {
+#ifdef SUPPORT_UTMPX
+  { EMPTY, "empty" },
+  { RUN_LVL, "run level" },
+  { BOOT_TIME, "boot time" },
+  { OLD_TIME, "old time" },
+  { NEW_TIME, "new time" },
+  { INIT_PROCESS, "init process" },
+  { LOGIN_PROCESS, "login process" },
+  { USER_PROCESS, "user process" },
+  { DEAD_PROCESS, "dead process" },
+  { ACCOUNTING, "accounting" },
+  { SIGNATURE, "signature" },
+  { DOWN_TIME, "down time" },
+#endif /* SUPPORT_UTMPX */
+  { -1, "unknown" }
+};
 
 int
-main(int argc, char **argv)
+main(int argc, char *argv[])
 {
-       int ch;
-       const char *file;
-       FILE *fp;
+       int c, only_current_term, show_labels, quick_mode, default_mode;
+       int et = 0;
 
-       setlocale(LC_TIME, "");
+       setlocale(LC_ALL, "");
 
-       while ((ch = getopt(argc, argv, "HTbmqsu")) != -1) {
-               switch (ch) {
-               case 'H':               /* Write column headings */
-                       Hflag = 1;
-                       break;
-               case 'T':               /* Show terminal state */
-                       Tflag = 1;
+       only_current_term = show_term = show_idle = show_labels = 0;
+       quick_mode = default_mode = 0;
+
+       while ((c = getopt(argc, argv, "abdHlmpqrsTtuv")) != -1) {
+               switch (c) {
+               case 'a':
+                       et = -1;
+                       show_idle = show_details = 1;
                        break;
-               case 'b':               /* Show time and date since last boot */
+               case 'b':
+#if 0
+                       et |= (1 << BOOT_TIME);
+#endif
                        bflag = 1;
                        break;
-               case 'm':               /* Show info about current terminal */
-                       mflag = 1;
+               case 'd':
+                       et |= (1 << DEAD_PROCESS);
+                       break;
+               case 'H':
+                       show_labels = 1;
                        break;
-               case 'q':               /* "Quick" mode */
-                       qflag = 1;
+               case 'l':
+                       et |= (1 << LOGIN_PROCESS);
                        break;
-               case 's':               /* Show name, line, time */
-                       sflag = 1;
+               case 'm':
+                       only_current_term = 1;
                        break;
-               case 'u':               /* Show idle time */
-                       uflag = 1;
+               case 'p':
+                       et |= (1 << INIT_PROCESS);
+                       break;
+               case 'q':
+                       quick_mode = 1;
+                       break;
+               case 'r':
+                       et |= (1 << RUN_LVL);
+                       break;
+               case 's':
+                       default_mode = 1;
+                       break;
+               case 'T':
+                       show_term = 1;
+                       break;
+               case 't':
+                       et |= (1 << NEW_TIME);
+                       break;
+               case 'u':
+                       show_idle = 1;
+                       break;
+               case 'v':
+                       show_details = 1;
                        break;
                default:
                        usage();
-                       /*NOTREACHED*/
+                       /* NOTREACHED */
                }
        }
        argc -= optind;
        argv += optind;
 
-       if (argc >= 2 && strcmp(argv[0], "am") == 0 &&
-           strcasecmp(argv[1], "i") == 0) {
-               /* "who am i" or "who am I", equivalent to -m */
-               mflag = 1;
-               argc -= 2;
-               argv += 2;
-       }
-       if (argc > 1)
-               usage();
+       if (et != 0)
+               etype = et;
 
-       if (*argv != NULL)
-               file = *argv;
-       else
-               file = _PATH_UTMP;
-       if ((fp = fopen(file, "r")) == NULL)
-               err(1, "%s", file);
-
-       if (qflag)
-               quick(fp);
-       else {
-               if (sflag)
-                       Tflag = uflag = 0;
-               if (bflag)
-                       print_boottime();
-               if (Hflag)
-                       heading();
-               if (mflag)
-                       whoami(fp);
-               else
-                       process_utmp(fp);
+       if (chdir("/dev")) {
+               err(EXIT_FAILURE, "cannot change directory to /dev");
+               /* NOTREACHED */
        }
 
-       fclose(fp);
+       if (default_mode)
+               only_current_term = show_term = show_idle = 0;
 
-       exit(0);
-}
+       if (!quick_mode && bflag)
+               print_boottime();
 
-static void
-usage(void)
-{
-       fprintf(stderr, "usage: who [-bHmqsTu] [am I] [file]\n");
-       exit(1);
+       switch (argc) {
+       case 0:                                 /* who */
+               if (quick_mode) {
+                       quick(NULL);
+               } else if (only_current_term) {
+                       who_am_i(NULL, show_labels);
+               } else {
+                       process(NULL, show_labels);
+               }
+               break;
+       case 1:                                 /* who utmp_file */
+               if (quick_mode) {
+                       quick(*argv);
+               } else if (only_current_term) {
+                       who_am_i(*argv, show_labels);
+               } else {
+                       process(*argv, show_labels);
+               }
+               break;
+       case 2:                                 /* who am i */
+               who_am_i(NULL, show_labels);
+               break;
+       default:
+               usage();
+               /* NOTREACHED */
+       }
+
+       return 0;
 }
 
 static void
@@ -160,152 +214,185 @@ print_boottime(void)
        }
 }
 
+
+static char *
+strrstr(const char *str, const char *pat)
+{
+       const char *estr;
+       size_t len;
+       if (*pat == '\0')
+               return __DECONST(char *, str);
+
+       len = strlen(pat);
+
+       for (estr = str + strlen(str); str < estr; estr--)
+               if (strncmp(estr, pat, len) == 0)
+                       return __DECONST(char *, estr);
+       return NULL;
+}
+
+static void
+who_am_i(const char *fname, int show_labels)
+{
+       struct passwd *pw;
+       const char *p;
+       char *t;
+       time_t now;
+       struct utmpentry *ehead, *ep;
+
+       /* search through the utmp and find an entry for this tty */
+       if ((p = ttyname(STDIN_FILENO)) != NULL) {
+
+               /* strip directory prefixes for ttys */
+               if ((t = strrstr(p, "/pts/")) != NULL ||
+                   (t = strrchr(p, '/')) != NULL)
+                       p = t + 1;
+
+               (void)getutentries(fname, &ehead);
+               for (ep = ehead; ep; ep = ep->next)
+                       if (strcmp(ep->line, p) == 0) {
+                               if (show_labels)
+                                       output_labels();
+                               eprint(ep);
+                               return;
+                       }
+       } else
+               p = "tty??";
+
+       (void)time(&now);
+       pw = getpwuid(getuid());
+       if (show_labels)
+               output_labels();
+       print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0);
+}
+
+static void
+process(const char *fname, int show_labels)
+{
+       struct utmpentry *ehead, *ep;
+       (void)getutentries(fname, &ehead);
+       if (show_labels)
+               output_labels();
+       for (ep = ehead; ep != NULL; ep = ep->next)
+               eprint(ep);
+}
+
 static void
-heading(void)
+eprint(const struct utmpentry *ep)
 {
-       printf("%-*s ", UT_NAMESIZE, "NAME");
-       if (Tflag)
-               printf("S ");
-       printf("%-*s ", UT_LINESIZE, "LINE");
-       printf("%-*s ", 12, "TIME");
-       if (uflag)
-               printf("IDLE  ");
-       printf("%-*s", UT_HOSTSIZE, "FROM");
-       putchar('\n');
+       print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid,
+           ep->term, ep->exit, ep->sess, ep->type);
 }
 
 static void
-row(struct utmp *ut)
+print(const char *name, const char *line, time_t t, const char *host,
+    pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type)
 {
-       char buf[80], tty[sizeof(_PATH_DEV) + UT_LINESIZE];
        struct stat sb;
-       time_t idle = 0;
-       static int d_first = -1;
-       struct tm *tm;
-       char state = '?';
-
-       if (d_first < 0)
-               d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
-
-       if (Tflag || uflag) {
-               snprintf(tty, sizeof(tty), "%s%.*s", _PATH_DEV,
-                       UT_LINESIZE, ut->ut_line);
-               if (stat(tty, &sb) == 0) {
-                       state = sb.st_mode & (S_IWOTH|S_IWGRP) ?
-                           '+' : '-';
-                       idle = time(NULL) - sb.st_mtime;
-               } else {
-                       err(1, "Cannot open %s", tty);
+       char state;
+       static time_t now = 0;
+       time_t idle;
+       const char *types = NULL;
+       size_t i;
+
+       state = '?';
+       idle = 0;
+
+       for (i = 0; ut_type_names[i].type >= 0; i++) {
+               types = ut_type_names[i].name;
+               if (ut_type_names[i].type == type)
+                       break;
+       }
+
+       if (show_term || show_idle) {
+               if (now == 0)
+                       time(&now);
+
+               if (stat(line, &sb) == 0) {
+                       state = (sb.st_mode & 020) ? '+' : '-';
+                       idle = now - sb.st_atime;
                }
+
        }
 
-       printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, ut->ut_name);
-       if (Tflag)
-               printf("%c ", state);
-       printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, ut->ut_line);
-       tm = localtime(&ut->ut_time);
-       strftime(buf, sizeof(buf), d_first ? "%e %b %R" : "%b %e %R", tm);
-       printf("%-*s ", 12, buf);
-       if (uflag) {
-               if (idle < 60)
-                       printf("  .   ");
-               else if (idle < 24 * 60 * 60)
-                       printf("%02d:%02d ", (int)(idle / 60 / 60),
-                           (int)(idle / 60 % 60));
+       (void)printf("%-*.*s ", maxname, maxname, name);
+
+       if (show_term)
+               (void)printf("%c ", state);
+
+       (void)printf("%-*.*s ", maxline, maxline, line);
+       (void)printf("%.12s ", ctime(&t) + 4);
+
+       if (show_idle) {
+               if (idle < 60) 
+                       (void)printf("  .   ");
+               else if (idle < (24 * 60 * 60))
+                       (void)printf("%02ld:%02ld ", 
+                                    (long)(idle / (60 * 60)),
+                                    (long)(idle % (60 * 60)) / 60);
                else
-                       printf(" old  ");
+                       (void)printf(" old  ");
+
+               (void)printf("\t%6d", pid);
+
+               if (show_details) {
+                       if (type == RUN_LVL)
+                               (void)printf("\tnew=%c old=%c", term, xit);
+                       else
+                               (void)printf("\tterm=%d exit=%d", term, xit);
+                       (void)printf(" sess=%d", sess);
+                       (void)printf(" type=%s ", types);
+               }
        }
-       if (*ut->ut_host != '\0')
-               printf("(%.*s)", UT_HOSTSIZE, ut->ut_host);
-       putchar('\n');
+
+       if (*host)
+               (void)printf("\t(%.*s)", maxhost, host);
+       (void)putchar('\n');
 }
 
 static void
-process_utmp(FILE *fp)
+output_labels(void)
 {
-       struct utmp ut;
+       (void)printf("%-*.*s ", maxname, maxname, "USER");
 
-       while (fread(&ut, sizeof(ut), 1, fp) == 1)
-               if (*ut.ut_name != '\0')
-                       row(&ut);
-}
+       if (show_term)
+               (void)printf("S ");
 
-static void
-quick(FILE *fp)
-{
-       struct utmp ut;
-       int col, ncols, num;
-
-       ncols = ttywidth();
-       col = num = 0;
-       while (fread(&ut, sizeof(ut), 1, fp) == 1) { 
-               if (*ut.ut_name == '\0')
-                       continue;
-               printf("%-*.*s", UT_NAMESIZE, UT_NAMESIZE, ut.ut_name);
-               if (++col < ncols / (UT_NAMESIZE + 1))
-                       putchar(' ');
-               else {
-                       col = 0;
-                       putchar('\n');
-               }
-               num++;
+       (void)printf("%-*.*s ", maxline, maxline, "LINE");
+       (void)printf("WHEN         ");
+
+       if (show_idle) {
+               (void)printf("IDLE  ");
+               (void)printf("\t   PID");
+
+               (void)printf("\tCOMMENT");
        }
-       if (col != 0)
-               putchar('\n');
 
-       printf("# users = %d\n", num);
+       (void)putchar('\n');
 }
 
 static void
-whoami(FILE *fp)
+quick(const char *fname)
 {
-       struct utmp ut;
-       struct passwd *pwd;
-       const char *name, *p, *tty;
-
-       if ((tty = ttyname(STDIN_FILENO)) == NULL)
-               tty = "tty??";
-       else if ((p = strrchr(tty, '/')) != NULL)
-               tty = p + 1;
-
-       /* Search utmp for our tty, dump first matching record. */
-       while (fread(&ut, sizeof(ut), 1, fp) == 1)
-               if (*ut.ut_name != '\0' && strncmp(ut.ut_line, tty,
-                   UT_LINESIZE) == 0) {
-                       row(&ut);
-                       return;
-               }
+       struct utmpentry *ehead, *ep;
+       int num = 0;
+
+       (void)getutentries(fname, &ehead);
+       for (ep = ehead; ep != NULL; ep = ep->next) {
+               (void)printf("%-*s ", maxname, ep->name);
+               if ((++num % 8) == 0)
+                       (void)putchar('\n');
+       }
+       if (num % 8)
+               (void)putchar('\n');
 
-       /* Not found; fill the utmp structure with the information we have. */
-       memset(&ut, 0, sizeof(ut));
-       if ((pwd = getpwuid(getuid())) != NULL)
-               name = pwd->pw_name;
-       else
-               name = "?";
-       strncpy(ut.ut_name, name, UT_NAMESIZE);
-       strncpy(ut.ut_line, tty, UT_LINESIZE);
-       time(&ut.ut_time);
-       row(&ut);
+       (void)printf("# users = %d\n", num);
 }
 
-static int
-ttywidth(void)
+static void
+usage(void)
 {
-       struct winsize ws;
-       long width;
-       char *cols, *ep;
-
-       if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') {
-               errno = 0;
-               width = strtol(cols, &ep, 10);
-               if (errno || width <= 0 || width > INT_MAX || ep == cols ||
-                   *ep != '\0')
-                       warnx("invalid COLUMNS environment variable ignored");
-               else
-                       return (width);
-       }
-       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
-               return (ws.ws_col);
-
-       return (80);
+       (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n",
+           getprogname(), getprogname());
+       exit(EXIT_FAILURE);
 }
index a76bb99..cfb6b4a 100644 (file)
@@ -1,8 +1,16 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/6/93
 # $DragonFly: src/usr.bin/write/Makefile,v 1.3 2007/08/27 16:51:01 pavalos Exp $
 
+.PATH: ${.CURDIR}/../../usr.bin/who
+
 PROG=  write
+SRCS=  write.c utmpentry.c
 BINMODE=2555
 BINGRP=        tty
 
+DPADD+=        ${LIBUTIL}
+LDADD+=        -lutil
+
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 .include <bsd.prog.mk>
index fb2daac..1b461a9 100644 (file)
@@ -54,7 +54,7 @@
 #include <signal.h>
 #include <time.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
 static void    done(int);
 static void    do_write(const char *, const char *, uid_t, int *);
@@ -132,21 +132,17 @@ usage(void)
 static int
 utmp_chk(const char *user, const char *tty)
 {
-       struct utmp u;
-       int ufd;
+       struct utmpentry *ep;
 
-       if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
-               err(1, "open failed: %s\n", _PATH_UTMP);
+       getutentries(NULL, &ep);
 
-       while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u)) {
-               if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
-                   strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
-                       close(ufd);
+       for (; ep; ep = ep->next) {
+               if (strcmp(user, ep->name) == 0 &&
+                   strcmp(tty, ep->line) == 0) {
                        return(0);
                }
        }
 
-       close(ufd);
        return(1);
 }
 
@@ -164,37 +160,33 @@ utmp_chk(const char *user, const char *tty)
 static void
 search_utmp(const char *user, char *tty, size_t ttyl, const char *mytty, uid_t myuid)
 {
-       struct utmp u;
+       struct utmpentry *ep;
        time_t bestatime, atime;
-       int ufd, nloggedttys, nttys, msgsok, user_is_me;
-       char atty[UT_LINESIZE + 1];
+       int nloggedttys, nttys, msgsok, user_is_me;
 
-       if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
-               err(1, "open failed: %s", _PATH_UTMP);
+       getutentries(NULL, &ep);
 
        nloggedttys = nttys = 0;
        bestatime = 0;
        user_is_me = 0;
-       while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
-               if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
+       for (; ep; ep = ep->next)
+               if (strcmp(user, ep->name) == 0) {
                        ++nloggedttys;
-                       strlcpy(atty, u.ut_line, ttyl);
-                       if (term_chk(atty, &msgsok, &atime, 0))
+                       if (term_chk(ep->line, &msgsok, &atime, 0))
                                continue;       /* bad term? skip */
                        if (myuid && !msgsok)
                                continue;       /* skip ttys with msgs off */
-                       if (strcmp(atty, mytty) == 0) {
+                       if (strcmp(ep->line, mytty) == 0) {
                                user_is_me = 1;
                                continue;       /* don't write to yourself */
                        }
                        ++nttys;
                        if (atime > bestatime) {
                                bestatime = atime;
-                               strlcpy(tty, atty, ttyl);
+                               strlcpy(tty, ep->line, ttyl);
                        }
                }
 
-       close(ufd);
        if (nloggedttys == 0)
                errx(1, "%s is not logged in", user);
        if (nttys == 0) {
index b1d9153..7b255ee 100644 (file)
@@ -63,9 +63,11 @@ utility differs from
 in that it only prints information regarding the very last login session.
 The last login database is never turned over or deleted in standard usage.
 .Sh FILES
-.Bl -tag -width /var/log/lastlog -compact
+.Bl -tag -width /var/log/lastlogx -compact
 .It Pa /var/log/lastlog
 last login database
+.It Pa /var/log/lastlogx
+last login database
 .El
 .Sh SEE ALSO
 .Xr last 1 ,
index 505a0e4..5c2c50f 100644 (file)
@@ -35,6 +35,7 @@
  */
 
 #include <sys/cdefs.h>
+#include <sys/user.h>
 
 #include <err.h>
 #include <pwd.h>
 #include <stdlib.h>
 #include <time.h>
 #include <utmp.h>
+#include <utmpx.h>
 #include <unistd.h>
 
 static void    output(struct passwd *, struct lastlog *);
+static void    outputx(struct passwd *, struct lastlogx *);
 static void    usage(void);
 
 int
 main(int argc, char **argv)
 {
        int     ch, i;
+       long offset;
        FILE    *fp;
        struct passwd   *passwd;
        struct lastlog  last;
+       struct lastlogx lastx;
 
        while ((ch = getopt(argc, argv, "")) != -1) {
                usage();
@@ -66,12 +71,16 @@ main(int argc, char **argv)
 
        /* Process usernames given on the command line. */
        if (argc > 1) {
-               long offset;
                for (i = 1; i < argc; ++i) {
                        if ((passwd = getpwnam(argv[i])) == NULL) {
                                warnx("user '%s' not found", argv[i]);
                                continue;
                        }
+                       if ((getlastlogx(_PATH_LASTLOGX, passwd->pw_uid,
+                           &lastx)) != NULL) {
+                               outputx(passwd, &lastx);
+                               goto done;
+                       }
                        /* Calculate the offset into the lastlog file. */
                        offset = (long)(passwd->pw_uid * sizeof(last));
                        if (fseek(fp, offset, SEEK_SET)) {
@@ -88,6 +97,27 @@ main(int argc, char **argv)
        }
        /* Read all lastlog entries, looking for active ones */
        else {
+               while ((passwd = getpwent()) != NULL) {
+                       if ((getlastlogx(_PATH_LASTLOGX, passwd->pw_uid,
+                           &lastx)) != NULL) {
+                               if (lastx.ll_tv.tv_sec == 0)
+                                       continue;
+                               outputx(passwd, &lastx);
+                       } else {
+                               offset = (long)(passwd->pw_uid * sizeof(last));
+
+                               if (fseek(fp, offset, SEEK_SET)) {
+                                       continue;
+                               }
+                               if (fread(&last, sizeof(last), 1, fp) != 1) {
+                                       continue;
+                               }
+                               if (last.ll_time == 0)
+                                       continue;
+                               output(passwd, &last);
+                       }
+               }
+#if 0
                for (i = 0; fread(&last, sizeof(last), 1, fp) == 1; i++) {
                        if (last.ll_time == 0)
                                continue;
@@ -96,8 +126,10 @@ main(int argc, char **argv)
                }
                if (ferror(fp))
                        warnx("fread error");
+#endif
        }
 
+done:
        setpassent(0);  /* Close passwd file pointers */
 
        fclose(fp);
@@ -110,11 +142,21 @@ output(struct passwd *p, struct lastlog *l)
 {
        printf("%-*.*s  %-*.*s %-*.*s   %s",
                UT_NAMESIZE, UT_NAMESIZE, p->pw_name,
-               UT_LINESIZE, UT_LINESIZE, l->ll_line,
+               UT_LINESIZE+4, UT_LINESIZE+4, l->ll_line,
                UT_HOSTSIZE, UT_HOSTSIZE, l->ll_host,
                (l->ll_time) ? ctime(&(l->ll_time)) : "Never logged in\n");
 }
 
+static void
+outputx(struct passwd *p, struct lastlogx *l)
+{
+       printf("%-*.*s  %-*.*s %-*.*s   %s",
+               UT_NAMESIZE, UT_NAMESIZE, p->pw_name,
+               UT_LINESIZE+4, UT_LINESIZE+4, l->ll_line,
+               UT_HOSTSIZE, UT_HOSTSIZE, l->ll_host,
+               (l->ll_tv.tv_sec) ? ctime((&l->ll_tv.tv_sec)) : "Never logged in\n");
+}
+
 static void
 usage(void)
 {
index 147b496..29a488e 100644 (file)
@@ -2,16 +2,18 @@
 # $FreeBSD: src/usr.sbin/syslogd/Makefile,v 1.14 2008/12/17 16:51:40 obrien Exp $
 # $DragonFly: src/usr.sbin/syslogd/Makefile,v 1.3 2004/08/09 20:11:19 dillon Exp $
 
-.PATH: ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../nscd
+.PATH: ${.CURDIR}/../../usr.bin/wall ${.CURDIR}/../nscd ${.CURDIR}/../../usr.bin/who
 
 PROG=  syslogd
 MAN=   syslog.conf.5 syslogd.8
-SRCS=  pidfile.c syslogd.c ttymsg.c
+SRCS=  pidfile.c syslogd.c ttymsg.c utmpentry.c
 
 DPADD= ${LIBUTIL}
 LDADD= -lutil
 
 CFLAGS+= -DINET6
 CFLAGS+= -I${.CURDIR}/../../usr.bin/wall
+CFLAGS+= -I${.CURDIR}/../../usr.bin/who -DSUPPORT_UTMP -DSUPPORT_UTMPX
+
 
 .include <bsd.prog.mk>
index 4aca424..4f72452 100644 (file)
@@ -96,7 +96,7 @@
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
-#include <utmp.h>
+#include "utmpentry.h"
 
 #include "pathnames.h"
 #include "ttymsg.h"
@@ -164,7 +164,7 @@ struct filed {
 #define PRI_GT 0x4
        char    *f_program;             /* program this applies to */
        union {
-               char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
+               char    f_uname[MAXUNAMES][32+1];
                struct {
                        char    f_hname[MAXHOSTNAMELEN];
                        struct addrinfo *f_addr;
@@ -1355,28 +1355,25 @@ static void
 wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
 {
        static int reenter;                     /* avoid calling ourselves */
-       FILE *uf;
-       struct utmp ut;
+
+       struct utmpentry *ep;
        int i;
        const char *p;
-       char line[sizeof(ut.ut_line) + 1];
 
        if (reenter++)
                return;
-       if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
-               logerror(_PATH_UTMP);
+
+       getutentries(NULL, &ep);
+       if (ep == NULL) {
+               logerror("getutentries");
                reenter = 0;
                return;
        }
        /* NOSTRICT */
-       while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
-               if (ut.ut_name[0] == '\0')
-                       continue;
+       for (; ep; ep = ep->next) {
                /* We must use strncpy since ut_* may not be NUL terminated. */
-               strncpy(line, ut.ut_line, sizeof(line) - 1);
-               line[sizeof(line) - 1] = '\0';
                if (f->f_type == F_WALL) {
-                       if ((p = ttymsg(iov, iovlen, line, TTYMSGTIME)) !=
+                       if ((p = ttymsg(iov, iovlen, ep->line, TTYMSGTIME)) !=
                            NULL) {
                                errno = 0;      /* already in msg */
                                logerror(p);
@@ -1387,9 +1384,8 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
                for (i = 0; i < MAXUNAMES; i++) {
                        if (!f->f_un.f_uname[i][0])
                                break;
-                       if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
-                           UT_NAMESIZE)) {
-                               if ((p = ttymsg(iov, iovlen, line, TTYMSGTIME))
+                       if (!strcmp(f->f_un.f_uname[i], ep->name)) {
+                               if ((p = ttymsg(iov, iovlen, ep->line, TTYMSGTIME))
                                    != NULL) {
                                        errno = 0;      /* already in msg */
                                        logerror(p);
@@ -1398,7 +1394,6 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
                        }
                }
        }
-       fclose(uf);
        reenter = 0;
 }
 
@@ -2061,9 +2056,9 @@ cfline(const char *line, struct filed *f, const char *prog, const char *host)
                for (i = 0; i < MAXUNAMES && *p; i++) {
                        for (q = p; *q && *q != ','; )
                                q++;
-                       strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
-                       if ((q - p) > UT_NAMESIZE)
-                               f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
+                       strncpy(f->f_un.f_uname[i], p, 32);
+                       if ((q - p) > 32)
+                               f->f_un.f_uname[i][32] = '\0';
                        else
                                f->f_un.f_uname[i][q - p] = '\0';
                        while (*q == ',' || *q == ' ')