Loading...
gen/NetBSD/utmpx.c Libc-1725.40.4 Libc-583
--- Libc/Libc-1725.40.4/gen/NetBSD/utmpx.c
+++ Libc/Libc-583/gen/NetBSD/utmpx.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $	 */
+/*	$NetBSD: utmpx.c,v 1.21 2003/09/06 16:42:10 wiz Exp $	 */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -15,6 +15,13 @@
  * 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 NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@@ -31,7 +38,7 @@
 #include <sys/cdefs.h>
 
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $");
+__RCSID("$NetBSD: utmpx.c,v 1.21 2003/09/06 16:42:10 wiz Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include "namespace.h"
@@ -42,251 +49,119 @@
 #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>
-#ifdef UNIFDEF_LEGACY_UTMP_APIS
 #include <utmp.h>
-#endif /* UNIFDEF_LEGACY_UTMP_APIS */
+/* don't define earlier, has side effects in fcntl.h */
+#define __LIBC12_SOURCE__
 #include <utmpx.h>
-#include <utmpx-darwin.h>
-#include <errno.h>
 #include <vis.h>
-#include <notify.h>
-
-#include "libc_private.h" // for LIBC_ABORT
-
-static struct _utmpx *__utx__ = NULL;
-
-static void
-__default_utx_init(void)
-{
-	__utx__ = calloc(1, sizeof(struct _utmpx));
-	const char magic[] = __UTX_MAGIC__;
-	memcpy(&__utx__->magic, magic, UTMPX_MAGIC);
-	pthread_mutex_init(&__utx__->utmpx_mutex, NULL);
-	__utx__->utfile = _PATH_UTMPX;
-	__utx__->utfile_system = 1;
-}
-
-struct _utmpx *
-__default_utx(void)
-{
-	static pthread_once_t once = PTHREAD_ONCE_INIT;
-	pthread_once(&once, &__default_utx_init);
-	return __utx__;
-}
-
-static struct utmpx *__getutxid(struct _utmpx *, const struct utmpx *);
-
-__private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
-
-__private_extern__ void
-__setutxent(struct _utmpx *U)
-{
-
-	(void)memset(&U->ut, 0, sizeof(U->ut));
-	if (U->fp == NULL)
+
+__warn_references(getlastlogx,
+    "warning: reference to compatibility getlastlogx(); include <utmpx.h> for correct reference")
+__warn_references(lastlogxname,
+    "warning: reference to deprecated lastlogxname()")
+
+static FILE *fp;
+static int readonly = 0;
+static struct utmpx ut;
+static char utfile[MAXPATHLEN] = _PATH_UTMPX;
+static char llfile[MAXPATHLEN] = _PATH_LASTLOGX;
+
+static struct utmpx *utmp_update(const struct utmpx *);
+
+static const char vers[] = "utmpx-1.00";
+
+void
+setutxent()
+{
+
+	(void)memset(&ut, 0, sizeof(ut));
+	if (fp == NULL)
 		return;
-#ifdef __LP64__
-	(void)fseeko(U->fp, (off_t)sizeof(struct utmpx32), SEEK_SET);
-#else /* __LP64__ */
-	(void)fseeko(U->fp, (off_t)sizeof(U->ut), SEEK_SET);
-#endif /* __LP64__ */
-}
+	(void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
+}
+
 
 void
-_setutxent(struct _utmpx *U)
-{
-
-	TEST_UTMPX_T("_setutxent", U);
-	UTMPX_LOCK(U);
-	__setutxent(U);
-	UTMPX_UNLOCK(U);
-}
-
-
-void
-setutxent(void)
-{
-	_setutxent(__default_utx());
-}
-
-
-__private_extern__ void
-__endutxent(struct _utmpx *U)
-{
-	(void)memset(&U->ut, 0, sizeof(U->ut));
-	if (U->fp != NULL) {
-		int saveerrno = errno;
-		(void)fclose(U->fp);
-		errno = saveerrno;
-		U->fp = NULL;
-		U->readonly = 0;
-	}
-}
-
-
-void
-_endutxent(struct _utmpx *U)
-{
-	TEST_UTMPX_T("_endutxent", U);
-	UTMPX_LOCK(U);
-	__endutxent(U);
-	UTMPX_UNLOCK(U);
-}
-
-
-void
-endutxent(void)
-{
-	_endutxent(__default_utx());
-}
-
-
-__private_extern__ struct utmpx *
-__getutxent(struct _utmpx *U)
-{
-	int saveerrno;
-#ifdef __LP64__
-	struct utmpx32 ut32;
-#endif /* __LP64__ */
-
-	if (U->fp == NULL) {
+endutxent()
+{
+
+	(void)memset(&ut, 0, sizeof(ut));
+	if (fp != NULL) {
+		(void)fclose(fp);
+		fp = NULL;
+		readonly = 0;
+	}
+}
+
+
+struct utmpx *
+getutxent()
+{
+
+	if (fp == NULL) {
 		struct stat st;
 
-		if ((U->fp = fopen(U->utfile, "r+")) == NULL)
-			if ((U->fp = fopen(U->utfile, "w+")) == NULL) {
-				if ((U->fp = fopen(U->utfile, "r")) == NULL)
+		if ((fp = fopen(utfile, "r+")) == NULL)
+			if ((fp = fopen(utfile, "w+")) == NULL) {
+				if ((fp = fopen(utfile, "r")) == NULL)
 					goto fail;
 				else
-					U->readonly = 1;
+					readonly = 1;
 			}
-
-		fcntl(fileno(U->fp), F_SETFD, 1); /* set close-on-exec flag */
+					
 
 		/* get file size in order to check if new file */
-		if (fstat(fileno(U->fp), &st) == -1)
+		if (fstat(fileno(fp), &st) == -1)
 			goto failclose;
 
 		if (st.st_size == 0) {
 			/* new file, add signature record */
-#ifdef __LP64__
-			(void)memset(&ut32, 0, sizeof(ut32));
-			ut32.ut_type = SIGNATURE;
-			(void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
-			if (fwrite(&ut32, sizeof(ut32), 1, U->fp) != 1)
-#else /* __LP64__ */
-			(void)memset(&U->ut, 0, sizeof(U->ut));
-			U->ut.ut_type = SIGNATURE;
-			(void)memcpy(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
-			if (fwrite(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
-#endif /* __LP64__ */
+			(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 */
-#ifdef __LP64__
-			if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
-#else /* __LP64__ */
-			if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
-#endif /* __LP64__ */
+			if (fread(&ut, sizeof(ut), 1, fp) != 1)
 				goto failclose;
-#ifdef __LP64__
-			if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
-			    ut32.ut_type != SIGNATURE)
-#else /* __LP64__ */
-			if (memcmp(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
-			    U->ut.ut_type != SIGNATURE)
-#endif /* __LP64__ */
-			{
-				errno = EINVAL;
+			if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 ||
+			    ut.ut_type != SIGNATURE)
 				goto failclose;
-			}
 		}
 	}
 
-#ifdef __LP64__
-	if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
-#else /* __LP64__ */
-	if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
-#endif /* __LP64__ */
+	if (fread(&ut, sizeof(ut), 1, fp) != 1)
 		goto fail;
 
-#ifdef __LP64__
-	_utmpx32_64(&ut32, &U->ut);
-#endif /* __LP64__ */
-	return &U->ut;
+	return &ut;
 failclose:
-	saveerrno = errno;
-	(void)fclose(U->fp);
-	errno = saveerrno;
-	U->fp = NULL;
+	(void)fclose(fp);
 fail:
-	(void)memset(&U->ut, 0, sizeof(U->ut));
+	(void)memset(&ut, 0, sizeof(ut));
 	return NULL;
 }
 
 
 struct utmpx *
-_getutxent(struct _utmpx *U)
-{
-	struct utmpx *ret;
-
-	TEST_UTMPX_T("_getutxent", U);
-	UTMPX_LOCK(U);
-	ret = __getutxent(U);
-	UTMPX_UNLOCK(U);
-	return ret;
-}
-
-
-struct utmpx *
-getutxent(void)
-{
-	return _getutxent(__default_utx());
-}
-
-
-struct utmpx *
-_getutxid(struct _utmpx *U, const struct utmpx *utx)
-{
-	struct utmpx temp;
-	const struct utmpx *ux;
-	struct utmpx *ret;
+getutxid(const struct utmpx *utx)
+{
+
+	_DIAGASSERT(utx != NULL);
 
 	if (utx->ut_type == EMPTY)
 		return NULL;
 
-	TEST_UTMPX_T("_getutxid", U);
-	UTMPX_LOCK(U);
-	/* make a copy as needed, and auto-fill if requested */
-	ux = _utmpx_working_copy(utx, &temp, 1);
-	if (!ux) {
-		UTMPX_UNLOCK(U);
-		return NULL;
-	}
-
-	ret = __getutxid(U, ux);
-	UTMPX_UNLOCK(U);
-	return ret;
-}
-
-
-struct utmpx *
-getutxid(const struct utmpx *utx)
-{
-	return _getutxid(__default_utx(), utx);
-}
-
-
-static struct utmpx *
-__getutxid(struct _utmpx *U, const struct utmpx *utx)
-{
-
 	do {
-		if (U->ut.ut_type == EMPTY)
+		if (ut.ut_type == EMPTY)
 			continue;
 		switch (utx->ut_type) {
 		case EMPTY:
@@ -295,21 +170,21 @@
 		case BOOT_TIME:
 		case OLD_TIME:
 		case NEW_TIME:
-			if (U->ut.ut_type == utx->ut_type)
-				return &U->ut;
+			if (ut.ut_type == utx->ut_type)
+				return &ut;
 			break;
 		case INIT_PROCESS:
 		case LOGIN_PROCESS:
 		case USER_PROCESS:
 		case DEAD_PROCESS:
-			switch (U->ut.ut_type) {
+			switch (ut.ut_type) {
 			case INIT_PROCESS:
 			case LOGIN_PROCESS:
 			case USER_PROCESS:
 			case DEAD_PROCESS:
-				if (memcmp(U->ut.ut_id, utx->ut_id,
-				    sizeof(U->ut.ut_id)) == 0)
-					return &U->ut;
+				if (memcmp(ut.ut_id, utx->ut_id,
+				    sizeof(ut.ut_id)) == 0)
+					return &ut;
 				break;
 			default:
 				break;
@@ -318,253 +193,188 @@
 		default:
 			return NULL;
 		}
-	} while (__getutxent(U) != NULL);
+	} while (getutxent() != NULL);
 	return NULL;
 }
 
 
-static struct utmpx *
-__getutxline(struct _utmpx *U, const struct utmpx *utx)
-{
+struct utmpx *
+getutxline(const struct utmpx *utx)
+{
+
+	_DIAGASSERT(utx != NULL);
+
 	do {
-		switch (U->ut.ut_type) {
+		switch (ut.ut_type) {
 		case EMPTY:
 			break;
 		case LOGIN_PROCESS:
 		case USER_PROCESS:
-			if (strncmp(U->ut.ut_line, utx->ut_line,
-			    sizeof(U->ut.ut_line)) == 0)
-				return &U->ut;
+			if (strncmp(ut.ut_line, utx->ut_line,
+			    sizeof(ut.ut_line)) == 0)
+				return &ut;
 			break;
 		default:
 			break;
 		}
-	} while (__getutxent(U) != NULL);
+	} while (getutxent() != NULL);
 	return NULL;
-}
-
-
-struct utmpx *
-_getutxline(struct _utmpx *U, const struct utmpx *utx)
-{
-	struct utmpx *ret;
-
-	TEST_UTMPX_T("_getutxline", U);
-	UTMPX_LOCK(U);
-	ret = __getutxline(U, utx);
-	UTMPX_UNLOCK(U);
-	return ret;
-}
-
-
-struct utmpx *
-getutxline(const struct utmpx *utx)
-{
-	return _getutxline(__default_utx(), utx);
-}
-
-
-struct utmpx *
-_pututxline(struct _utmpx *U, const struct utmpx *utx)
-{
-	struct utmpx *ux;
-
-	if (utx == NULL) {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	TEST_UTMPX_T("_pututxline", U);
-	UTMPX_LOCK(U);
-	if ((ux = __pututxline(__default_utx(), utx)) != NULL && __default_utx()->utfile_system) {
-		_utmpx_asl(ux);	/* the equivalent of wtmpx and lastlogx */
-#ifdef UTMP_COMPAT
-		_write_utmp_compat(ux);
-#endif /* UTMP_COMPAT */
-	}
-	UTMPX_UNLOCK(U);
-	return ux;
 }
 
 
 struct utmpx *
 pututxline(const struct utmpx *utx)
 {
-	return _pututxline(__default_utx(), utx);
-}
-
-__private_extern__ struct utmpx *
-__pututxline(struct _utmpx *U, const struct utmpx *utx)
-{
-	struct utmpx temp, *u = NULL, *x;
-	const struct utmpx *ux;
-#ifdef __LP64__
-	struct utmpx32 ut32;
-#endif /* __LP64__ */
-	struct flock fl;
-#define gotlock		(fl.l_start >= 0)
-
-	fl.l_start = -1; /* also means we haven't locked */
-	if (U->utfile_system)
-		if ((U->fp != NULL && U->readonly) || (U->fp == NULL && geteuid() != 0)) {
-			errno = EPERM;
-			return NULL;
-		}
-
-	if (U->fp == NULL) {
-		(void)__getutxent(U);
-		if (U->fp == NULL || U->readonly) {
-			errno = EPERM;
-			return NULL;
-		}
-	}
-
-	/* make a copy as needed, and auto-fill if requested */
-	ux = _utmpx_working_copy(utx, &temp, 0);
-	if (!ux)
+	struct utmpx temp, *u = NULL;
+	int gotlock = 0;
+
+	_DIAGASSERT(utx != NULL);
+
+	if (utx == NULL)
 		return NULL;
 
-	if ((x = __getutxid(U, ux)) == NULL) {
-		__setutxent(U);
-		if ((x = __getutxid(U, ux)) == NULL) {
-			/*
-			 * utx->ut_type has any original mask bits, while
-			 * ux->ut_type has those mask bits removed.  If we
-			 * are trying to record a dead process, and
-			 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
-			 * there is no matching entry, we return NULL.
-			 */
-			if (ux->ut_type == DEAD_PROCESS &&
-			    (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) {
-				errno = EINVAL;
+	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;
-			}
-			/*
-			 * Replace lockf() with fcntl() and a fixed start
-			 * value.  We should already be at EOF.
-			 */
-			if ((fl.l_start = lseek(fileno(U->fp), 0, SEEK_CUR)) < 0)
-				return NULL;
-			fl.l_len = 0;
-			fl.l_whence = SEEK_SET;
-			fl.l_type = F_WRLCK;
-			if (fcntl(fileno(U->fp), F_SETLKW, &fl) == -1)
-				return NULL;
-			if (fseeko(U->fp, (off_t)0, SEEK_END) == -1)
+			gotlock++;
+			if (fseeko(fp, (off_t)0, SEEK_END) == -1)
 				goto fail;
 		}
 	}
 
 	if (!gotlock) {
-		/*
-		 * utx->ut_type has any original mask bits, while
-		 * ux->ut_type has those mask bits removed.  If we
-		 * are trying to record a dead process, if
-		 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
-		 * entry is not a (matching) USER_PROCESS, then return NULL.
-		 */
-		if (ux->ut_type == DEAD_PROCESS &&
-		    (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) &&
-		    x->ut_type != USER_PROCESS) {
-			errno = EINVAL;
-			return NULL;
-		}
 		/* we are not appending */
-#ifdef __LP64__
-		if (fseeko(U->fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1)
-#else /* __LP64__ */
-		if (fseeko(U->fp, -(off_t)sizeof(U->ut), SEEK_CUR) == -1)
-#endif /* __LP64__ */
-			return NULL;
-	}
-
-#ifdef __LP64__
-	_utmpx64_32(ux, &ut32);
-	if (fwrite(&ut32, sizeof (ut32), 1, U->fp) != 1)
-#else /* __LP64__ */
-	if (fwrite(ux, sizeof (*ux), 1, U->fp) != 1)
-#endif /* __LP64__ */
+		if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
+			return NULL;
+	}
+
+	if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
 		goto fail;
 
-	if (fflush(U->fp) == -1)
+	if (fflush(fp) == -1)
 		goto fail;
 
-	u = memcpy(&U->ut, ux, sizeof(U->ut));
-	notify_post(UTMPX_CHANGE_NOTIFICATION);
+	u = memcpy(&ut, &temp, sizeof(ut));
 fail:
 	if (gotlock) {
-		int save = errno;
-		fl.l_type = F_UNLCK;
-		if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1)
-			return NULL;
-		errno = save;
+		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.
  */
-__private_extern__ int
-__utmpxname(struct _utmpx *U, const char *fname)
+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;
 
-	if (fname == NULL) {
-		if(!U->utfile_system)
-			free(U->utfile);
-		U->utfile = _PATH_UTMPX;
-		U->utfile_system = 1;
-		__endutxent(U);
-		return 1;
-	}
+	_DIAGASSERT(fname != NULL);
 
 	len = strlen(fname);
 
-	if (len >= MAXPATHLEN)
+	if (len >= sizeof(utfile))
 		return 0;
 
 	/* must end in x! */
 	if (fname[len - 1] != 'x')
 		return 0;
 
-	if (U->utfile_system)
-		U->utfile = NULL;
-	U->utfile_system = 0;
-	if ((U->utfile = reallocf(U->utfile, len + 1)) == NULL)
-		return 0;
-
-	(void)strcpy(U->utfile, fname);
-	__endutxent(U);
+	(void)strlcpy(utfile, fname, sizeof(utfile));
+	endutxent();
 	return 1;
 }
 
-int
-_utmpxname(struct _utmpx *U, const char *fname)
-{
-	int ret;
-
-	TEST_UTMPX_T("_utmpxname", U);
-	UTMPX_LOCK(U);
-	ret = __utmpxname(U, fname);
-	UTMPX_UNLOCK(U);
-	return ret;
-}
-
-int
-utmpxname(const char *fname)
-{
-	return _utmpxname(__default_utx(), fname);
-}
-
-#ifdef UNIFDEF_LEGACY_UTMP_APIS
+
 void
 getutmp(const struct utmpx *ux, struct utmp *u)
 {
 
-	bzero(u, sizeof(*u));
-	(void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
+	_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;
@@ -574,16 +384,109 @@
 getutmpx(const struct utmp *u, struct utmpx *ux)
 {
 
-	bzero(ux, sizeof(*ux));
-	(void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
-	ux->ut_user[sizeof(u->ut_name)] = 0;
+	_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));
-	ux->ut_line[sizeof(u->ut_line)] = 0;
 	(void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
-	ux->ut_host[sizeof(u->ut_host)] = 0;
 	ux->ut_tv.tv_sec = u->ut_time;
 	ux->ut_tv.tv_usec = 0;
-	ux->ut_pid = getpid();
+	(void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss));
+	ux->ut_pid = 0;
 	ux->ut_type = USER_PROCESS;
-}
-#endif /* UNIFDEF_LEGACY_UTMP_APIS */
+	ux->ut_session = 0;
+	ux->ut_exit.e_termination = 0;
+	ux->ut_exit.e_exit = 0;
+}
+
+int
+lastlogxname(const char *fname)
+{
+	size_t len;
+
+	_DIAGASSERT(fname != NULL);
+
+	len = strlen(fname);
+
+	if (len >= sizeof(llfile))
+		return 0;
+
+	/* must end in x! */
+	if (fname[len - 1] != 'x')
+		return 0;
+
+	(void)strlcpy(llfile, fname, sizeof(llfile));
+	return 1;
+}
+
+struct lastlogx *
+getlastlogx(uid_t uid, struct lastlogx *ll)
+{
+
+	return __getlastlogx13(_PATH_LASTLOGX, uid, ll);
+}
+
+struct lastlogx *
+__getlastlogx13(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, 0, 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;
+}