utmpx.c.patch   [plain text]


--- utmpx.c.orig	2010-06-24 19:43:32.000000000 -0700
+++ utmpx.c	2010-06-29 11:25:57.000000000 -0700
@@ -42,111 +42,240 @@ __RCSID("$NetBSD: utmpx.c,v 1.25 2008/04
 #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 */
 #include <utmpx.h>
+#include <utmpx-darwin.h>
+#include <errno.h>
 #include <vis.h>
+#include <notify.h>
 
-static FILE *fp;
-static int readonly = 0;
-static struct utmpx ut;
-static char utfile[MAXPATHLEN] = _PATH_UTMPX;
+/* This is the default struct _utmpx shared by the POSIX APIs */
+__private_extern__
+struct _utmpx __utx__ = {
+	__UTX_MAGIC__,			/* magic */
+	{},				/* ut */
+	PTHREAD_MUTEX_INITIALIZER,	/* utmpx_mutex */
+	_PATH_UTMPX,			/* utfile */
+	NULL,				/* fp */
+	1,				/* utfile_system */
+	0,				/* readonly */
+};
+
+static struct utmpx *__getutxid(struct _utmpx *, const struct utmpx *);
 
-static struct utmpx *utmp_update(const struct utmpx *);
+__private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
 
-static const char vers[] = "utmpx-1.00";
+__private_extern__ void
+__setutxent(struct _utmpx *U)
+{
+
+	(void)memset(&U->ut, 0, sizeof(U->ut));
+	if (U->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
-setutxent()
+_setutxent(struct _utmpx *U)
 {
 
-	(void)memset(&ut, 0, sizeof(ut));
-	if (fp == NULL)
-		return;
-	(void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
+	TEST_UTMPX_T("_setutxent", U);
+	UTMPX_LOCK(U);
+	__setutxent(U);
+	UTMPX_UNLOCK(U);
 }
 
 
 void
-endutxent()
+setutxent()
 {
+	_setutxent(&__utx__);
+}
+
 
-	(void)memset(&ut, 0, sizeof(ut));
-	if (fp != NULL) {
-		(void)fclose(fp);
-		fp = NULL;
-		readonly = 0;
+__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;
 	}
 }
 
 
-struct utmpx *
-getutxent()
+void
+_endutxent(struct _utmpx *U)
 {
+	TEST_UTMPX_T("_endutxent", U);
+	UTMPX_LOCK(U);
+	__endutxent(U);
+	UTMPX_UNLOCK(U);
+}
 
-	if (fp == NULL) {
+
+void
+endutxent()
+{
+	_endutxent(&__utx__);
+}
+
+
+__private_extern__ struct utmpx *
+__getutxent(struct _utmpx *U)
+{
+	int saveerrno;
+#ifdef __LP64__
+	struct utmpx32 ut32;
+#endif /* __LP64__ */
+
+	if (U->fp == NULL) {
 		struct stat st;
 
-		if ((fp = fopen(utfile, "r+")) == NULL)
-			if ((fp = fopen(utfile, "w+")) == NULL) {
-				if ((fp = fopen(utfile, "r")) == NULL)
+		if ((U->fp = fopen(U->utfile, "r+")) == NULL)
+			if ((U->fp = fopen(U->utfile, "w+")) == NULL) {
+				if ((U->fp = fopen(U->utfile, "r")) == NULL)
 					goto fail;
 				else
-					readonly = 1;
+					U->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(fp), &st) == -1)
+		if (fstat(fileno(U->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)
+#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__ */
 				goto failclose;
 		} else {
 			/* old file, read signature record */
-			if (fread(&ut, sizeof(ut), 1, fp) != 1)
+#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__ */
 				goto failclose;
-			if (memcmp(ut.ut_user, vers, sizeof(vers)) != 0 ||
-			    ut.ut_type != SIGNATURE)
+#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;
 				goto failclose;
+			}
 		}
 	}
 
-	if (fread(&ut, sizeof(ut), 1, fp) != 1)
+#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__ */
 		goto fail;
 
-	return &ut;
+#ifdef __LP64__
+	_utmpx32_64(&ut32, &U->ut);
+#endif /* __LP64__ */
+	return &U->ut;
 failclose:
-	(void)fclose(fp);
+	saveerrno = errno;
+	(void)fclose(U->fp);
+	errno = saveerrno;
+	U->fp = NULL;
 fail:
-	(void)memset(&ut, 0, sizeof(ut));
+	(void)memset(&U->ut, 0, sizeof(U->ut));
 	return NULL;
 }
 
 
 struct utmpx *
-getutxid(const struct utmpx *utx)
+_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()
+{
+	return _getutxent(&__utx__);
+}
 
-	_DIAGASSERT(utx != NULL);
+
+struct utmpx *
+_getutxid(struct _utmpx *U, const struct utmpx *utx)
+{
+	struct utmpx temp;
+	const struct utmpx *ux;
+	struct utmpx *ret;
 
 	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(&__utx__, utx);
+}
+
+
+static struct utmpx *
+__getutxid(struct _utmpx *U, const struct utmpx *utx)
+{
+
 	do {
-		if (ut.ut_type == EMPTY)
+		if (U->ut.ut_type == EMPTY)
 			continue;
 		switch (utx->ut_type) {
 		case EMPTY:
@@ -155,21 +284,21 @@ getutxid(const struct utmpx *utx)
 		case BOOT_TIME:
 		case OLD_TIME:
 		case NEW_TIME:
-			if (ut.ut_type == utx->ut_type)
-				return &ut;
+			if (U->ut.ut_type == utx->ut_type)
+				return &U->ut;
 			break;
 		case INIT_PROCESS:
 		case LOGIN_PROCESS:
 		case USER_PROCESS:
 		case DEAD_PROCESS:
-			switch (ut.ut_type) {
+			switch (U->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;
+				if (memcmp(U->ut.ut_id, utx->ut_id,
+				    sizeof(U->ut.ut_id)) == 0)
+					return &U->ut;
 				break;
 			default:
 				break;
@@ -178,188 +307,253 @@ getutxid(const struct utmpx *utx)
 		default:
 			return NULL;
 		}
-	} while (getutxent() != NULL);
+	} while (__getutxent(U) != NULL);
 	return NULL;
 }
 
 
-struct utmpx *
-getutxline(const struct utmpx *utx)
+static struct utmpx *
+__getutxline(struct _utmpx *U, const struct utmpx *utx)
 {
-
-	_DIAGASSERT(utx != NULL);
-
 	do {
-		switch (ut.ut_type) {
+		switch (U->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;
+			if (strncmp(U->ut.ut_line, utx->ut_line,
+			    sizeof(U->ut.ut_line)) == 0)
+				return &U->ut;
 			break;
 		default:
 			break;
 		}
-	} while (getutxent() != NULL);
+	} while (__getutxent(U) != NULL);
 	return NULL;
 }
 
 
 struct utmpx *
-pututxline(const struct utmpx *utx)
+_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)
 {
-	struct utmpx temp, *u = NULL;
-	int gotlock = 0;
+	return _getutxline(&__utx__, utx);
+}
 
-	_DIAGASSERT(utx != NULL);
 
-	if (utx == NULL)
+struct utmpx *
+_pututxline(struct _utmpx *U, const struct utmpx *utx)
+{
+	struct utmpx *ux;
+
+	if (utx == NULL) {
+		errno = EINVAL;
 		return NULL;
+	}
 
-	if (strcmp(_PATH_UTMPX, utfile) == 0)
-		if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0))
-			return utmp_update(utx);
+	TEST_UTMPX_T("_pututxline", U);
+	UTMPX_LOCK(U);
+	if ((ux = __pututxline(&__utx__, utx)) != NULL && __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;
+}
 
 
-	(void)memcpy(&temp, utx, sizeof(temp));
+struct utmpx *
+pututxline(const struct utmpx *utx)
+{
+	return _pututxline(&__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 (fp == NULL) {
-		(void)getutxent();
-		if (fp == NULL || readonly)
+	if (U->fp == NULL) {
+		(void)__getutxent(U);
+		if (U->fp == NULL || U->readonly) {
+			errno = EPERM;
 			return NULL;
+		}
 	}
 
-	if (getutxid(&temp) == NULL) {
-		setutxent();
-		if (getutxid(&temp) == NULL) {
-			if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
+	/* make a copy as needed, and auto-fill if requested */
+	ux = _utmpx_working_copy(utx, &temp, 0);
+	if (!ux)
+		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;
 				return NULL;
-			gotlock++;
-			if (fseeko(fp, (off_t)0, SEEK_END) == -1)
+			}
+			/*
+			 * 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)
 				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 */
-		if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
+#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;
 	}
 
-	if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
+#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__ */
 		goto fail;
 
-	if (fflush(fp) == -1)
+	if (fflush(U->fp) == -1)
 		goto fail;
 
-	u = memcpy(&ut, &temp, sizeof(ut));
+	u = memcpy(&U->ut, ux, sizeof(U->ut));
+	notify_post(UTMPX_CHANGE_NOTIFICATION);
 fail:
 	if (gotlock) {
-		if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
+		int save = errno;
+		fl.l_type = F_UNLCK;
+		if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1)
 			return NULL;
+		errno = save;
 	}
 	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)
+__private_extern__ int
+__utmpxname(struct _utmpx *U, const char *fname)
 {
 	size_t len;
 
-	_DIAGASSERT(fname != NULL);
+	if (fname == NULL) {
+		if(!U->utfile_system)
+			free(U->utfile);
+		U->utfile = _PATH_UTMPX;
+		U->utfile_system = 1;
+		__endutxent(U);
+		return 1;
+	}
 
 	len = strlen(fname);
 
-	if (len >= sizeof(utfile))
+	if (len >= MAXPATHLEN)
 		return 0;
 
 	/* must end in x! */
 	if (fname[len - 1] != 'x')
 		return 0;
 
-	(void)strlcpy(utfile, fname, sizeof(utfile));
-	endutxent();
+	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);
 	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(&__utx__, fname);
+}
 
+#ifdef UNIFDEF_LEGACY_UTMP_APIS
 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));
+	bzero(u, sizeof(*u));
+	(void)memcpy(u->ut_name, ux->ut_user, 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;
@@ -369,82 +563,16 @@ 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));
+	bzero(ux, sizeof(*ux));
+	(void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
+	ux->ut_user[sizeof(u->ut_name)] = 0;
 	(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;
-	(void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss));
-	ux->ut_pid = 0;
+	ux->ut_pid = getpid();
 	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;
 }
+#endif /* UNIFDEF_LEGACY_UTMP_APIS */