summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/gen/Makefile.inc12
-rw-r--r--lib/libc/gen/Symbol.map12
-rw-r--r--lib/libc/gen/getutxent.3440
-rw-r--r--lib/libc/gen/getutxent.c232
-rw-r--r--lib/libc/gen/pututxline.c277
-rw-r--r--lib/libc/gen/utxdb.c162
-rw-r--r--lib/libc/gen/utxdb.h61
7 files changed, 1190 insertions, 6 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 2abfe57..2c0cb78 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -18,12 +18,12 @@ SRCS+= __getosreldate.c __xuname.c \
gethostname.c getloadavg.c getlogin.c getmntinfo.c getnetgrent.c \
getosreldate.c getpagesize.c getpagesizes.c \
getpeereid.c getprogname.c getpwent.c getttyent.c \
- getusershell.c getvfsbyname.c glob.c \
+ getusershell.c getutxent.c getvfsbyname.c glob.c \
initgroups.c isatty.c isinf.c isnan.c jrand48.c lcong48.c \
lockf.c lrand48.c mrand48.c nftw.c nice.c \
nlist.c nrand48.c opendir.c \
pause.c pmadvise.c popen.c posix_spawn.c \
- psignal.c pw_scan.c pwcache.c \
+ psignal.c pututxline.c pw_scan.c pwcache.c \
raise.c readdir.c readpassphrase.c rewinddir.c \
scandir.c seed48.c seekdir.c sem.c sem_new.c semctl.c \
setdomainname.c sethostname.c setjmperr.c setmode.c \
@@ -32,7 +32,7 @@ SRCS+= __getosreldate.c __xuname.c \
sysconf.c sysctl.c sysctlbyname.c sysctlnametomib.c \
syslog.c telldir.c termios.c time.c times.c timezone.c tls.c \
ttyname.c ttyslot.c ualarm.c ulimit.c uname.c unvis.c \
- usleep.c utime.c valloc.c vis.c wait.c wait3.c waitpid.c \
+ usleep.c utime.c utxdb.c valloc.c vis.c wait.c wait3.c waitpid.c \
wordexp.c
SYM_MAPS+=${.CURDIR}/gen/Symbol.map
@@ -54,7 +54,7 @@ MAN+= alarm.3 arc4random.3 \
getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \
getmntinfo.3 getnetgrent.3 getosreldate.3 getpagesize.3 \
getpagesizes.3 getpass.3 getpeereid.3 getprogname.3 getpwent.3 \
- getttyent.3 getusershell.3 getvfsbyname.3 \
+ getttyent.3 getusershell.3 getutxent.3 getvfsbyname.3 \
glob.3 initgroups.3 isgreater.3 ldexp.3 lockf.3 makecontext.3 \
modf.3 \
nice.3 nlist.3 pause.3 popen.3 \
@@ -126,6 +126,10 @@ MLINKS+=getttyent.3 endttyent.3 getttyent.3 getttynam.3 \
getttyent.3 isdialuptty.3 getttyent.3 isnettty.3 \
getttyent.3 setttyent.3
MLINKS+=getusershell.3 endusershell.3 getusershell.3 setusershell.3
+MLINKS+=getutxent.3 endutxent.3 getutxent.3 getutxid.3 \
+ getutxent.3 getutxline.3 getutxent.3 getutxuser.3 \
+ getutxent.3 pututxline.3 getutxent.3 setutxdb.3 \
+ getutxent.3 setutxent.3
MLINKS+=glob.3 globfree.3
MLINKS+=isgreater.3 isgreaterequal.3 isgreater.3 isless.3 \
isgreater.3 islessequal.3 isgreater.3 islessgreater.3 \
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index e7d59bb..534c81a 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -359,17 +359,25 @@ FBSD_1.1 {
FBSD_1.2 {
basename_r;
+ endutxent;
getpagesizes;
+ getutxent;
+ getutxid;
+ getutxline;
+ getutxuser;
+ pututxline;
sem_close;
sem_destroy;
sem_getvalue;
sem_init;
sem_open;
+ sem_post;
sem_timedwait;
sem_trywait;
- sem_post;
- sem_wait;
sem_unlink;
+ sem_wait;
+ setutxdb;
+ setutxent;
};
FBSDprivate_1.0 {
diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3
new file mode 100644
index 0000000..57887b1
--- /dev/null
+++ b/lib/libc/gen/getutxent.3
@@ -0,0 +1,440 @@
+.\" Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 8, 2010
+.Os
+.Dt GETUTXENT 3
+.Sh NAME
+.Nm endutxent ,
+.Nm getutxent ,
+.Nm getutxid ,
+.Nm getutxline ,
+.Nm getutxuser ,
+.Nm pututxline ,
+.Nm setutxdb ,
+.Nm setutxent
+.Nd user accounting database functions
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In utmpx.h
+.Ft void
+.Fn endutxent "void"
+.Ft struct utmpx *
+.Fn getutxent "void"
+.Ft struct utmpx *
+.Fn getutxid "const struct utmpx *id"
+.Ft struct utmpx *
+.Fn getutxline "const struct utmpx *line"
+.Ft struct utmpx *
+.Fn getutxuser "const char *user"
+.Ft struct utmpx *
+.Fn pututxline "const struct utmpx *utmpx"
+.Ft int
+.Fn setutxdb "int type" "const char *file"
+.Ft void
+.Fn setutxent "void"
+.Sh DESCRIPTION
+These functions operate on the user accounting database which stores
+records of various system activities, such as user login and logouts,
+but also system startups and shutdowns and modifications to the system's
+clock.
+The system stores these records in three databases, each having a
+different purpose:
+.Bl -tag -width indent
+.It Pa /var/run/utx.active
+Log of currently active user login sessions.
+This file is similar to the traditional
+.Pa utmp
+file.
+This file only contains process related entries, such as user login and
+logout records.
+.It Pa /var/log/utx.lastlogin
+Log of last user login entries per user.
+This file is similar to the traditional
+.Pa lastlog
+file.
+This file only contains user login records for users who have at least
+logged in once.
+.It Pa /var/log/utx.log
+Log of all entries, sorted by date of addition.
+This file is similar to the traditional
+.Pa wtmp
+file.
+This file may contain any type of record described below.
+.El
+.Pp
+Each entry in these databases is defined by the structure
+.Vt utmpx
+found in the include file
+.In utmpx.h :
+.Bd -literal -offset indent
+struct utmpx {
+ short ut_type; /* Type of entry. */
+ struct timeval ut_tv; /* Time entry was made. */
+ char ut_id[]; /* Record identifier. */
+ pid_t ut_pid; /* Process ID. */
+ char ut_user[]; /* User login name. */
+ char ut_line[]; /* Device name. */
+ char ut_host[]; /* Remote hostname. */
+};
+.Ed
+.Pp
+The
+.Fa ut_type
+field indicates the type of the log entry, which can have one of the
+following values:
+.Bl -tag -width LOGIN_PROCESS
+.It Dv EMPTY
+No valid user accounting information.
+.It Dv BOOT_TIME
+Identifies time of system boot.
+.It Dv SHUTDOWN_TIME
+Identifies time of system shutdown.
+.It Dv OLD_TIME
+Identifies time when system clock changed.
+.It Dv NEW_TIME
+Identifies time after system clock changed.
+.It Dv USER_PROCESS
+Identifies a process.
+.It Dv INIT_PROCESS
+Identifies a process spawned by the init process.
+.It Dv LOGIN_PROCESS
+Identifies the session leader of a logged-in user.
+.It Dv DEAD_PROCESS
+Identifies a session leader who has exited.
+.El
+.Pp
+Entries of type
+.Dv INIT_PROCESS
+and
+.Dv LOGIN_PROCESS
+are not processed by this implementation.
+.Pp
+Other fields inside the structure are:
+.Bl -tag -width ut_user
+.It Fa ut_tv
+The time the event occured.
+This field is used for all types of entries.
+.It Fa ut_id
+An identifier that is used to refer to the entry.
+This identifier can be used to remove or replace a login entry by
+writing a new entry to the database containing the same value for
+.Fa ut_id .
+This field is only applicable to entries of type
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+and
+.Dv DEAD_PROCESS .
+.It Fa ut_pid
+The process identifier of the session leader of the login session.
+This field is only applicable to entries of type
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+and
+.Dv DEAD_PROCESS .
+.It Fa ut_user
+The user login name corresponding with the login session.
+This field is only applicable to entries of type
+.Dv USER_PROCESS
+and
+.Dv INIT_PROCESS .
+For
+.Dv INIT_PROCESS
+entries this entry typically contains the name of the login process.
+.It Fa ut_line
+The name of the TTY character device, without the leading
+.Pa /dev/
+prefix, corresponding with the device used to facilitate the user login
+session.
+If no TTY character device is used, this field is left blank.
+This field is only applicable to entries of type
+.Dv USER_PROCESS .
+.It Fa ut_host
+The network hostname of the remote system, connecting to perform a user
+login.
+If the user login session is not performed across a network, this field
+is left blank.
+This field is only applicable to entries of type
+.Dv USER_PROCESS .
+.El
+.Pp
+This implementation guarantees all inapplicable fields are discarded.
+The
+.Fa ut_user ,
+.Fa ut_line
+and
+.Fa ut_host
+fields of the structure returned by the library functions are also
+guaranteed to be null-terminated in this implementation.
+.Pp
+The
+.Fn getutxent
+function can be used to read the next entry from the user accounting
+database.
+.Pp
+The
+.Fn getutxid
+function searches for the next entry in the database of which the
+behaviour is based on the
+.Fa ut_type
+field of
+.Fa id .
+If
+.Fa ut_type
+has a value of
+.Dv BOOT_TIME ,
+.Dv SHUTDOWN_TIME ,
+.Dv OLD_TIME
+or
+.Dv NEW_TIME ,
+it will return the next entry whose
+.Fa ut_type
+has an equal value.
+If
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS ,
+.Dv LOGIN_PROCESS
+or
+.Dv DEAD_PROCESS ,
+it will return the next entry whose
+.Fa ut_type
+has one of the previously mentioned values and whose
+.Fa ut_id
+is equal.
+.Pp
+The
+.Fn getutxline
+function searches for the next entry in the database whose
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS
+or
+.Dv LOGIN_PROCESS
+and whose
+.Fa ut_line
+is equal to the the same field in
+.Fa line .
+.Pp
+The
+.Fn getutxuser
+function searches for the next entry in the database whose
+.Fa ut_type
+has a value of
+.Dv USER_PROCESS
+and whose
+.Fa ut_user
+is equal to
+.Fa user .
+.Pp
+The previously mentioned functions will automatically try to open the
+user accounting database if not already done so.
+The
+.Fn setutxdb
+and
+.Fn setutxent
+functions allow the database to be opened manually, causing the offset
+within the user accounting database to be rewound.
+The
+.Fn endutxent
+function closes the database.
+.Pp
+The
+.Fn setutxent
+database always opens the active sessions database.
+The
+.Fn setutxdb
+function opens the database identified by
+.Fa type ,
+whose value is either
+.Dv UTXDB_ACTIVE ,
+.Dv UTXDB_LASTLOGIN
+or
+.Dv UTXDB_LOG .
+It will open a custom file with filename
+.Fa file
+instead of the system-default if
+.Fa file
+is not null.
+Care must be taken that when using a custom filename,
+.Fa type
+still has to match with the actual format, since each database may use
+its own file format.
+.Pp
+The
+.Fn pututxline
+function writes record
+.Fa utmpx
+to the system-default user accounting databases.
+The value of
+.Fa ut_type
+determines which databases are modified.
+.Pp
+Entries of type
+.Dv BOOT_TIME ,
+.Dv SHUTDOWN_TIME ,
+.Dv OLD_TIME
+and
+.Dv NEW_TIME
+will only be written to
+.Pa /var/log/utx.log .
+.Pp
+Entries of type
+.Dv USER_PROCESS
+will also be written to
+.Pa /var/run/utx.active .
+It will only be written to
+.Pa /var/log/utx.lastlogin
+if
+.Fa ut_tv
+for that user has a greater value than the existing entry or when no
+entry for the user has been found.
+.Pp
+Entries of type
+.Dv DEAD_PROCESS
+will only be written to
+.Pa /var/log/utx.log
+and
+.Pa /var/run/utx.active
+if a corresponding
+.Dv USER_PROCESS ,
+.Dv INIT_PROCESS
+or
+.Dv LOGIN_PROCESS
+entry whose
+.Fa ut_id
+is equal has been found in the latter.
+.Pp
+In addition, entries of type
+.Dv BOOT_TIME
+and
+.Dv SHUTDOWN_TIME
+will cause all entries in
+.Pa /var/run/utx.active
+to be discarded.
+.Pp
+All entries whose type has not been mentioned previously, are discarded
+by this implementation of
+.Fn pututxline .
+.Sh RETURN VALUES
+The
+.Fn getutxent ,
+.Fn getutxid ,
+.Fn getutxline ,
+and
+.Fn getutxuser
+functions return a pointer to an
+.Vt utmpx
+structure that matches the mentioned constraints on success or
+.Dv NULL
+when reaching the end-of-file or when an error occurs.
+.Pp
+The
+.Fn pututxline
+function returns a pointer to an
+.Vt utmpx
+structure containing a copy of the structure written to disk upon
+success.
+It returns
+.Dv NULL
+when the provided
+.Vt utmpx
+is invalid.
+This may be because
+.Fa ut_type
+is invalid or
+.Fa ut_type
+has a value of
+.Dv DEAD_PROCESS
+and an entry with an identifier with a value equal to the field
+.Fa ut_id
+was not found.
+.Pp
+The
+.Fn setutxdb
+function returns 0 if the user accounting database was opened
+successfully.
+Otherwise, -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+In addition to the error conditions described in
+.Xr fopen 3 ,
+the
+.Fn setutxdb
+function can generate the following errors:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa type
+argument contains a value not supported by this implementation.
+.It Bq Er EFTYPE
+The file format is invalid.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr write 1 ,
+.Xr getpid 2 ,
+.Xr gettimeofday 2 ,
+.Xr tty 4 ,
+.Xr ac 8 ,
+.Xr newsyslog 8
+.Sh STANDARDS
+The
+.Fn endutxent ,
+.Fn getutxent ,
+.Fn getutxid ,
+.Fn getutxline ,
+.Fn pututxline
+and
+.Fn setutxent
+functions are expected to conform to
+.St -p1003.1-2008 .
+.Pp
+The
+.Fn getutxuser
+and
+.Fn setutxdb
+functions,
+the
+.Fa ut_host
+field of the
+.Vt utmpx
+structure and
+.Dv SHUTDOWN_TIME
+are extensions.
+.Sh HISTORY
+These functions appeared in
+.Fx 9.0 .
+They replaced the
+.In utmp.h
+interface.
+.Sh AUTHORS
+.An Ed Schouten Aq ed@FreeBSD.org
diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c
new file mode 100644
index 0000000..13efac0
--- /dev/null
+++ b/lib/libc/gen/getutxent.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+static FILE *uf = NULL;
+static int udb;
+static struct utmpx utx;
+
+int
+setutxdb(int db, const char *file)
+{
+ struct stat sb;
+
+ switch (db) {
+ case UTXDB_ACTIVE:
+ if (file == NULL)
+ file = _PATH_UTX_ACTIVE;
+ break;
+ case UTXDB_LASTLOGIN:
+ if (file == NULL)
+ file = _PATH_UTX_LASTLOGIN;
+ break;
+ case UTXDB_LOG:
+ if (file == NULL)
+ file = _PATH_UTX_LOG;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (uf != NULL)
+ fclose(uf);
+ uf = fopen(file, "r");
+ if (uf == NULL)
+ return (-1);
+
+ /* Safety check: never use broken files. */
+ if (db != UTXDB_LOG && _fstat(fileno(uf), &sb) != -1 &&
+ sb.st_size % sizeof(struct futx) != 0) {
+ fclose(uf);
+ uf = NULL;
+ errno = EFTYPE;
+ return (-1);
+ }
+
+ udb = db;
+ return (0);
+}
+
+void
+setutxent(void)
+{
+
+ setutxdb(UTXDB_ACTIVE, NULL);
+}
+
+void
+endutxent(void)
+{
+
+ if (uf != NULL) {
+ fclose(uf);
+ uf = NULL;
+ }
+}
+
+static struct futx *
+getfutxent(void)
+{
+ static struct futx fu;
+
+ if (uf == NULL)
+ setutxent();
+ if (uf == NULL)
+ return (NULL);
+
+ if (udb == UTXDB_LOG) {
+ uint16_t len;
+
+ if (fread(&len, sizeof len, 1, uf) != 1)
+ return (NULL);
+ len = be16toh(len);
+ if (len > sizeof fu) {
+ /* Forward compatibility. */
+ if (fread(&fu, sizeof fu, 1, uf) != 1)
+ return (NULL);
+ fseek(uf, len - sizeof fu, SEEK_CUR);
+ } else {
+ /* Partial record. */
+ memset(&fu, 0, sizeof fu);
+ if (fread(&fu, len, 1, uf) != 1)
+ return (NULL);
+ }
+ } else {
+ if (fread(&fu, sizeof fu, 1, uf) != 1)
+ return (NULL);
+ }
+ return (&fu);
+}
+
+struct utmpx *
+getutxent(void)
+{
+ struct futx *fu;
+
+ fu = getfutxent();
+ if (fu == NULL)
+ return (NULL);
+ futx_to_utx(fu, &utx);
+ return (&utx);
+}
+
+struct utmpx *
+getutxid(const struct utmpx *id)
+{
+ struct futx *fu;
+
+ for (;;) {
+ fu = getfutxent();
+ if (fu == NULL)
+ return (NULL);
+
+ switch (fu->fu_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ case SHUTDOWN_TIME:
+ if (fu->fu_type == id->ut_type)
+ goto found;
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ switch (id->ut_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ if (memcmp(fu->fu_id, id->ut_id,
+ MIN(sizeof fu->fu_id, sizeof id->ut_id)) == 0)
+ goto found;
+ }
+ }
+ }
+
+found:
+ futx_to_utx(fu, &utx);
+ return (&utx);
+}
+
+struct utmpx *
+getutxline(const struct utmpx *line)
+{
+ struct futx *fu;
+
+ for (;;) {
+ fu = getfutxent();
+ if (fu == NULL)
+ return (NULL);
+
+ switch (fu->fu_type) {
+ case USER_PROCESS:
+ case LOGIN_PROCESS:
+ if (strncmp(fu->fu_line, line->ut_line,
+ MIN(sizeof fu->fu_line, sizeof line->ut_line)) == 0)
+ goto found;
+ }
+ }
+
+found:
+ futx_to_utx(fu, &utx);
+ return (&utx);
+}
+
+struct utmpx *
+getutxuser(const char *user)
+{
+ struct futx *fu;
+
+ for (;;) {
+ fu = getfutxent();
+ if (fu == NULL)
+ return (NULL);
+
+ switch (fu->fu_type) {
+ case USER_PROCESS:
+ if (strncmp(fu->fu_user, user, sizeof fu->fu_user) == 0)
+ goto found;
+ }
+ }
+
+found:
+ futx_to_utx(fu, &utx);
+ return (&utx);
+}
diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c
new file mode 100644
index 0000000..8c2e91d
--- /dev/null
+++ b/lib/libc/gen/pututxline.c
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+static FILE *
+futx_open(const char *file)
+{
+ int fd;
+ FILE *fp;
+ struct stat sb;
+
+ fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644);
+ if (fd < 0)
+ return (NULL);
+
+ /* Safety check: never use broken files. */
+ if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
+ _close(fd);
+ return (NULL);
+ }
+
+ fp = fdopen(fd, "r+");
+ if (fp == NULL) {
+ _close(fd);
+ return (NULL);
+ }
+
+ return (fp);
+}
+
+static void
+utx_active_add(const struct futx *fu)
+{
+ FILE *fp;
+ struct futx fe;
+ off_t partial = -1;
+
+ /*
+ * Register user login sessions. Overwrite entries of sessions
+ * that have already been terminated.
+ */
+ fp = futx_open(_PATH_UTX_ACTIVE);
+ if (fp == NULL)
+ return;
+ while (fread(&fe, sizeof fe, 1, fp) == 1) {
+ switch (fe.fu_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case DEAD_PROCESS:
+ /* Overwrite when ut_id matches. */
+ if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) {
+ fseeko(fp, -sizeof fe, SEEK_CUR);
+ goto exact;
+ }
+ if (fe.fu_type != DEAD_PROCESS)
+ break;
+ /* FALLTHROUGH */
+ default:
+ /* Allow us to overwrite unused records. */
+ if (partial == -1)
+ partial = fseeko(fp, 0, SEEK_CUR) - sizeof fe;
+ break;
+ }
+ }
+
+ /*
+ * No exact match found. Use the partial match. If no partial
+ * match was found, just append a new record.
+ */
+ if (partial != -1)
+ fseeko(fp, partial, SEEK_SET);
+exact:
+ fwrite(fu, sizeof *fu, 1, fp);
+ fclose(fp);
+}
+
+static int
+utx_active_remove(struct futx *fu)
+{
+ FILE *fp;
+ struct futx fe;
+
+ /*
+ * Remove user login sessions, having the same ut_id.
+ */
+ fp = futx_open(_PATH_UTX_ACTIVE);
+ if (fp == NULL)
+ return (0);
+ while (fread(&fe, sizeof fe, 1, fp) == 1) {
+ switch (fe.fu_type) {
+ case USER_PROCESS:
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0)
+ continue;
+
+ /*
+ * Prevent login sessions from having a negative
+ * timespan.
+ */
+ if (be64toh(fu->fu_tv) < be64toh(fe.fu_tv))
+ fu->fu_tv = fe.fu_tv;
+
+ /* Terminate session. */
+ fseeko(fp, -sizeof fe, SEEK_CUR);
+ fwrite(fu, sizeof *fu, 1, fp);
+ fclose(fp);
+ return (0);
+ }
+ }
+
+ fclose(fp);
+ return (1);
+}
+
+static void
+utx_active_purge(void)
+{
+
+ truncate(_PATH_UTX_ACTIVE, 0);
+}
+
+static void
+utx_lastlogin_add(const struct futx *fu)
+{
+ FILE *fp;
+ struct futx fe;
+
+ /*
+ * Write an entry to lastlogin. Overwrite the entry if the
+ * current user already has an entry. If not, append a new
+ * entry.
+ */
+ fp = futx_open(_PATH_UTX_LASTLOGIN);
+ if (fp == NULL)
+ return;
+ while (fread(&fe, sizeof fe, 1, fp) == 1) {
+ if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
+ continue;
+
+ /* Prevent lowering the time value. */
+ if (be64toh(fu->fu_tv) <= be64toh(fe.fu_tv))
+ goto done;
+
+ /* Found a previous lastlogin entry for this user. */
+ fseeko(fp, -sizeof fe, SEEK_CUR);
+ break;
+ }
+ fwrite(fu, sizeof *fu, 1, fp);
+done:
+ fclose(fp);
+}
+
+static void
+utx_lastlogin_upgrade(void)
+{
+ int fd;
+ struct stat sb;
+
+ fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644);
+ if (fd < 0)
+ return;
+
+ /*
+ * Truncate broken lastlogin files. In the future we should
+ * check for older versions of the file format here and try to
+ * upgrade it.
+ */
+ if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
+ ftruncate(fd, 0);
+ _close(fd);
+}
+
+static void
+utx_log_add(const struct futx *fu)
+{
+ int fd;
+ uint16_t l;
+ struct iovec vec[2];
+
+ /*
+ * Append an entry to the log file. We only need to append
+ * records to this file, so to conserve space, trim any trailing
+ * zero-bytes. Prepend a length field, indicating the length of
+ * the record, excluding the length field itself.
+ */
+ for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--);
+ vec[0].iov_base = &l;
+ vec[0].iov_len = sizeof l;
+ vec[1].iov_base = __DECONST(void *, fu);
+ vec[1].iov_len = l;
+ l = htobe16(l);
+
+ fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644);
+ if (fd < 0)
+ return;
+ _writev(fd, vec, 2);
+ _close(fd);
+}
+
+struct utmpx *
+pututxline(const struct utmpx *utmpx)
+{
+ struct futx fu;
+ static struct utmpx ut;
+
+ utx_to_futx(utmpx, &fu);
+
+ switch (fu.fu_type) {
+ case BOOT_TIME:
+ case SHUTDOWN_TIME:
+ utx_active_purge();
+ utx_lastlogin_upgrade();
+ break;
+ case OLD_TIME:
+ case NEW_TIME:
+ break;
+ case USER_PROCESS:
+ utx_active_add(&fu);
+ utx_lastlogin_add(&fu);
+ break;
+#if 0 /* XXX: Are these records of any use to us? */
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ utx_active_add(&fu);
+ break;
+#endif
+ case DEAD_PROCESS:
+ if (utx_active_remove(&fu) != 0)
+ return (NULL);
+ break;
+ default:
+ return (NULL);
+ }
+
+ utx_log_add(&fu);
+ futx_to_utx(&fu, &ut);
+ return (&ut);
+}
diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c
new file mode 100644
index 0000000..d7e2b34
--- /dev/null
+++ b/lib/libc/gen/utxdb.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <string.h>
+#include <utmpx.h>
+#include "utxdb.h"
+#include "un-namespace.h"
+
+#define UTOF_STRING(ut, fu, field) do { \
+ strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \
+ MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \
+} while (0)
+#define UTOF_ID(ut, fu) do { \
+ memcpy((fu)->fu_id, (ut)->ut_id, \
+ MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \
+} while (0)
+#define UTOF_PID(ut, fu) do { \
+ (fu)->fu_pid = htobe32((ut)->ut_pid); \
+} while (0)
+#define UTOF_TYPE(ut, fu) do { \
+ (fu)->fu_type = (ut)->ut_type; \
+} while (0)
+#define UTOF_TV(ut, fu) do { \
+ (fu)->fu_tv = htobe64((uint64_t)(ut)->ut_tv.tv_sec * 1000000 + \
+ (uint64_t)(ut)->ut_tv.tv_usec); \
+} while (0)
+
+void
+utx_to_futx(const struct utmpx *ut, struct futx *fu)
+{
+
+ memset(fu, 0, sizeof *fu);
+
+ switch (ut->ut_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ /* Extension: shutdown time. */
+ case SHUTDOWN_TIME:
+ break;
+ case USER_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_STRING(ut, fu, user);
+ UTOF_STRING(ut, fu, line);
+ /* Extension: host name. */
+ UTOF_STRING(ut, fu, host);
+ UTOF_PID(ut, fu);
+ break;
+ case INIT_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_PID(ut, fu);
+ break;
+ case LOGIN_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_STRING(ut, fu, user);
+ UTOF_PID(ut, fu);
+ break;
+ case DEAD_PROCESS:
+ UTOF_ID(ut, fu);
+ UTOF_PID(ut, fu);
+ break;
+ default:
+ fu->fu_type = EMPTY;
+ return;
+ }
+
+ UTOF_TYPE(ut, fu);
+ UTOF_TV(ut, fu);
+}
+
+#define FTOU_STRING(fu, ut, field) do { \
+ strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \
+ MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \
+} while (0)
+#define FTOU_ID(fu, ut) do { \
+ memcpy((ut)->ut_id, (fu)->fu_id, \
+ MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \
+} while (0)
+#define FTOU_PID(fu, ut) do { \
+ (ut)->ut_pid = be32toh((fu)->fu_pid); \
+} while (0)
+#define FTOU_TYPE(fu, ut) do { \
+ (ut)->ut_type = (fu)->fu_type; \
+} while (0)
+#define FTOU_TV(fu, ut) do { \
+ uint64_t t; \
+ t = be64toh((fu)->fu_tv); \
+ (ut)->ut_tv.tv_sec = t / 1000000; \
+ (ut)->ut_tv.tv_usec = t % 1000000; \
+} while (0)
+
+void
+futx_to_utx(const struct futx *fu, struct utmpx *ut)
+{
+
+ memset(ut, 0, sizeof *ut);
+
+ switch (fu->fu_type) {
+ case BOOT_TIME:
+ case OLD_TIME:
+ case NEW_TIME:
+ /* Extension: shutdown time. */
+ case SHUTDOWN_TIME:
+ break;
+ case USER_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_STRING(fu, ut, user);
+ FTOU_STRING(fu, ut, line);
+ /* Extension: host name. */
+ FTOU_STRING(fu, ut, host);
+ FTOU_PID(fu, ut);
+ break;
+ case INIT_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_PID(fu, ut);
+ break;
+ case LOGIN_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_STRING(fu, ut, user);
+ FTOU_PID(fu, ut);
+ break;
+ case DEAD_PROCESS:
+ FTOU_ID(fu, ut);
+ FTOU_PID(fu, ut);
+ break;
+ default:
+ ut->ut_type = EMPTY;
+ return;
+ }
+
+ FTOU_TYPE(fu, ut);
+ FTOU_TV(fu, ut);
+}
diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h
new file mode 100644
index 0000000..ec02013
--- /dev/null
+++ b/lib/libc/gen/utxdb.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _UTXDB_H_
+#define _UTXDB_H_
+
+#include <stdint.h>
+
+#define _PATH_UTX_ACTIVE "/var/run/utx.active"
+#define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin"
+#define _PATH_UTX_LOG "/var/log/utx.log"
+
+/*
+ * Entries in struct futx are ordered by how often they are used. In
+ * utx.log only entries will be written until the last non-zero byte,
+ * which means we want to put the hostname at the end. Most primitive
+ * records only store a ut_type and ut_tv, which means we want to store
+ * those at the front.
+ */
+
+struct utmpx;
+
+struct futx {
+ uint8_t fu_type;
+ uint64_t fu_tv;
+ char fu_id[8];
+ uint32_t fu_pid;
+ char fu_user[32];
+ char fu_line[16];
+ char fu_host[128];
+} __packed;
+
+void utx_to_futx(const struct utmpx *, struct futx *);
+void futx_to_utx(const struct futx *, struct utmpx *);
+
+#endif /* !_UTXDB_H_ */
OpenPOWER on IntegriCloud