xref: /dflybsd-src/lib/libc/gen/utmpx.c (revision 59a92d1877d6bb6c4fc9d7be5e51943661e50c2f)
1*59a92d18SAlex Hornung /*-
2*59a92d18SAlex Hornung  * Copyright (c) 2002 The NetBSD Foundation, Inc.
3*59a92d18SAlex Hornung  * All rights reserved.
4*59a92d18SAlex Hornung  *
5*59a92d18SAlex Hornung  * This code is derived from software contributed to The NetBSD Foundation
6*59a92d18SAlex Hornung  * by Christos Zoulas.
7*59a92d18SAlex Hornung  *
8*59a92d18SAlex Hornung  * Redistribution and use in source and binary forms, with or without
9*59a92d18SAlex Hornung  * modification, are permitted provided that the following conditions
10*59a92d18SAlex Hornung  * are met:
11*59a92d18SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
12*59a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
13*59a92d18SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
14*59a92d18SAlex Hornung  *    notice, this list of conditions and the following disclaimer in the
15*59a92d18SAlex Hornung  *    documentation and/or other materials provided with the distribution.
16*59a92d18SAlex Hornung  *
17*59a92d18SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18*59a92d18SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19*59a92d18SAlex Hornung  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20*59a92d18SAlex Hornung  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21*59a92d18SAlex Hornung  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*59a92d18SAlex Hornung  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*59a92d18SAlex Hornung  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*59a92d18SAlex Hornung  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*59a92d18SAlex Hornung  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*59a92d18SAlex Hornung  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*59a92d18SAlex Hornung  * POSSIBILITY OF SUCH DAMAGE.
28*59a92d18SAlex Hornung  */
29*59a92d18SAlex Hornung #include <sys/cdefs.h>
30*59a92d18SAlex Hornung 
31*59a92d18SAlex Hornung #include "namespace.h"
32*59a92d18SAlex Hornung #include <sys/types.h>
33*59a92d18SAlex Hornung #include <sys/param.h>
34*59a92d18SAlex Hornung #include <sys/socket.h>
35*59a92d18SAlex Hornung #include <sys/stat.h>
36*59a92d18SAlex Hornung #include <sys/time.h>
37*59a92d18SAlex Hornung #include <sys/wait.h>
38*59a92d18SAlex Hornung 
39*59a92d18SAlex Hornung #include <assert.h>
40*59a92d18SAlex Hornung #include <db.h>
41*59a92d18SAlex Hornung #include <errno.h>
42*59a92d18SAlex Hornung #include <fcntl.h>
43*59a92d18SAlex Hornung #include <stdio.h>
44*59a92d18SAlex Hornung #include <stdlib.h>
45*59a92d18SAlex Hornung #include <string.h>
46*59a92d18SAlex Hornung #include <unistd.h>
47*59a92d18SAlex Hornung #include <pwd.h>
48*59a92d18SAlex Hornung #include <utmp.h>
49*59a92d18SAlex Hornung #include <utmpx.h>
50*59a92d18SAlex Hornung #include <vis.h>
51*59a92d18SAlex Hornung 
52*59a92d18SAlex Hornung static FILE *fp = NULL;
53*59a92d18SAlex Hornung static int readonly = 0;
54*59a92d18SAlex Hornung static struct utmpx ut;
55*59a92d18SAlex Hornung static char utfile[MAXPATHLEN] = _PATH_UTMPX;
56*59a92d18SAlex Hornung 
57*59a92d18SAlex Hornung static struct utmpx *utmp_update(const struct utmpx *);
58*59a92d18SAlex Hornung 
59*59a92d18SAlex Hornung static const char vers[] = "utmpx-2.00";
60*59a92d18SAlex Hornung static utx_db_t dbtype = UTX_DB_UTMPX;
61*59a92d18SAlex Hornung DB *lastlogx_db = NULL;
62*59a92d18SAlex Hornung 
63*59a92d18SAlex Hornung static int
64*59a92d18SAlex Hornung _open_db(char *fname)
65*59a92d18SAlex Hornung {
66*59a92d18SAlex Hornung 	struct stat st;
67*59a92d18SAlex Hornung 
68*59a92d18SAlex Hornung 	if ((fp = fopen(fname, "r+")) == NULL)
69*59a92d18SAlex Hornung 		if ((fp = fopen(fname, "w+")) == NULL) {
70*59a92d18SAlex Hornung 			if ((fp = fopen(fname, "r")) == NULL)
71*59a92d18SAlex Hornung 				goto fail;
72*59a92d18SAlex Hornung 			else
73*59a92d18SAlex Hornung 				readonly = 1;
74*59a92d18SAlex Hornung 		}
75*59a92d18SAlex Hornung 
76*59a92d18SAlex Hornung 	/* get file size in order to check if new file */
77*59a92d18SAlex Hornung 	if (fstat(fileno(fp), &st) == -1)
78*59a92d18SAlex Hornung 		goto failclose;
79*59a92d18SAlex Hornung 
80*59a92d18SAlex Hornung 	if (st.st_size == 0) {
81*59a92d18SAlex Hornung 		/* new file, add signature record */
82*59a92d18SAlex Hornung 		(void)memset(&ut, 0, sizeof(ut));
83*59a92d18SAlex Hornung 		ut.ut_type = SIGNATURE;
84*59a92d18SAlex Hornung 		(void)memcpy(ut.ut_user, vers, sizeof(vers));
85*59a92d18SAlex Hornung 		if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
86*59a92d18SAlex Hornung 			goto failclose;
87*59a92d18SAlex Hornung 	} else {
88*59a92d18SAlex Hornung 		/* old file, read signature record */
89*59a92d18SAlex Hornung 		if (fread(&ut, sizeof(ut), 1, fp) != 1)
90*59a92d18SAlex Hornung 			goto failclose;
91*59a92d18SAlex Hornung 		if (memcmp(ut.ut_user, vers, 5) != 0 ||
92*59a92d18SAlex Hornung 		    ut.ut_type != SIGNATURE) {
93*59a92d18SAlex Hornung 			errno = EINVAL;
94*59a92d18SAlex Hornung 			goto failclose;
95*59a92d18SAlex Hornung 		}
96*59a92d18SAlex Hornung 	}
97*59a92d18SAlex Hornung 
98*59a92d18SAlex Hornung 	return 0;
99*59a92d18SAlex Hornung failclose:
100*59a92d18SAlex Hornung 	(void)fclose(fp);
101*59a92d18SAlex Hornung fail:
102*59a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
103*59a92d18SAlex Hornung 	return -1;
104*59a92d18SAlex Hornung }
105*59a92d18SAlex Hornung 
106*59a92d18SAlex Hornung int
107*59a92d18SAlex Hornung setutxdb(utx_db_t db_type, char *fname)
108*59a92d18SAlex Hornung {
109*59a92d18SAlex Hornung 	switch (db_type) {
110*59a92d18SAlex Hornung 	case UTX_DB_UTMPX:
111*59a92d18SAlex Hornung 		if (fname == NULL)
112*59a92d18SAlex Hornung 			fname = _PATH_UTMPX;
113*59a92d18SAlex Hornung 		break;
114*59a92d18SAlex Hornung 
115*59a92d18SAlex Hornung 	case UTX_DB_WTMPX:
116*59a92d18SAlex Hornung 		if (fname == NULL)
117*59a92d18SAlex Hornung 			fname = _PATH_WTMPX;
118*59a92d18SAlex Hornung 		break;
119*59a92d18SAlex Hornung 
120*59a92d18SAlex Hornung 	default:
121*59a92d18SAlex Hornung 		errno = EINVAL;
122*59a92d18SAlex Hornung 		return -1;
123*59a92d18SAlex Hornung 	}
124*59a92d18SAlex Hornung 
125*59a92d18SAlex Hornung 	/* A previous db file is still open */
126*59a92d18SAlex Hornung 	if (fp != NULL) {
127*59a92d18SAlex Hornung 		fclose(fp);
128*59a92d18SAlex Hornung 		fp = NULL;
129*59a92d18SAlex Hornung 	}
130*59a92d18SAlex Hornung 	if ((_open_db(fname)) == -1)
131*59a92d18SAlex Hornung 		return -1;
132*59a92d18SAlex Hornung 
133*59a92d18SAlex Hornung done:
134*59a92d18SAlex Hornung 	dbtype = db_type;
135*59a92d18SAlex Hornung 	return 0;
136*59a92d18SAlex Hornung }
137*59a92d18SAlex Hornung 
138*59a92d18SAlex Hornung void
139*59a92d18SAlex Hornung setutxent()
140*59a92d18SAlex Hornung {
141*59a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
142*59a92d18SAlex Hornung 	if (fp == NULL)
143*59a92d18SAlex Hornung 		return;
144*59a92d18SAlex Hornung 
145*59a92d18SAlex Hornung #if 0
146*59a92d18SAlex Hornung 	if (dbtype != UTX_DB_UTMPX)
147*59a92d18SAlex Hornung 		setutxdb(UTX_DB_UTMPX, utfile);
148*59a92d18SAlex Hornung #endif
149*59a92d18SAlex Hornung 	(void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
150*59a92d18SAlex Hornung }
151*59a92d18SAlex Hornung 
152*59a92d18SAlex Hornung void
153*59a92d18SAlex Hornung endutxent()
154*59a92d18SAlex Hornung {
155*59a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
156*59a92d18SAlex Hornung 
157*59a92d18SAlex Hornung 	if (fp != NULL) {
158*59a92d18SAlex Hornung 		(void)fclose(fp);
159*59a92d18SAlex Hornung 		fp = NULL;
160*59a92d18SAlex Hornung 		readonly = 0;
161*59a92d18SAlex Hornung 	}
162*59a92d18SAlex Hornung }
163*59a92d18SAlex Hornung 
164*59a92d18SAlex Hornung struct utmpx *
165*59a92d18SAlex Hornung getutxent()
166*59a92d18SAlex Hornung {
167*59a92d18SAlex Hornung 	if (fp == NULL) {
168*59a92d18SAlex Hornung 		if ((_open_db(utfile)) == -1)
169*59a92d18SAlex Hornung 			goto fail;
170*59a92d18SAlex Hornung 	}
171*59a92d18SAlex Hornung 
172*59a92d18SAlex Hornung 	if (fread(&ut, sizeof(ut), 1, fp) != 1)
173*59a92d18SAlex Hornung 		goto fail;
174*59a92d18SAlex Hornung 
175*59a92d18SAlex Hornung 	return &ut;
176*59a92d18SAlex Hornung fail:
177*59a92d18SAlex Hornung 	(void)memset(&ut, 0, sizeof(ut));
178*59a92d18SAlex Hornung 	return NULL;
179*59a92d18SAlex Hornung }
180*59a92d18SAlex Hornung 
181*59a92d18SAlex Hornung struct utmpx *
182*59a92d18SAlex Hornung getutxid(const struct utmpx *utx)
183*59a92d18SAlex Hornung {
184*59a92d18SAlex Hornung 
185*59a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
186*59a92d18SAlex Hornung 
187*59a92d18SAlex Hornung 	if (utx->ut_type == EMPTY)
188*59a92d18SAlex Hornung 		return NULL;
189*59a92d18SAlex Hornung 
190*59a92d18SAlex Hornung 	do {
191*59a92d18SAlex Hornung 		if (ut.ut_type == EMPTY)
192*59a92d18SAlex Hornung 			continue;
193*59a92d18SAlex Hornung 		switch (utx->ut_type) {
194*59a92d18SAlex Hornung 		case EMPTY:
195*59a92d18SAlex Hornung 			return NULL;
196*59a92d18SAlex Hornung 		case RUN_LVL:
197*59a92d18SAlex Hornung 		case BOOT_TIME:
198*59a92d18SAlex Hornung 		case OLD_TIME:
199*59a92d18SAlex Hornung 		case NEW_TIME:
200*59a92d18SAlex Hornung 			if (ut.ut_type == utx->ut_type)
201*59a92d18SAlex Hornung 				return &ut;
202*59a92d18SAlex Hornung 			break;
203*59a92d18SAlex Hornung 		case INIT_PROCESS:
204*59a92d18SAlex Hornung 		case LOGIN_PROCESS:
205*59a92d18SAlex Hornung 		case USER_PROCESS:
206*59a92d18SAlex Hornung 		case DEAD_PROCESS:
207*59a92d18SAlex Hornung 			switch (ut.ut_type) {
208*59a92d18SAlex Hornung 			case INIT_PROCESS:
209*59a92d18SAlex Hornung 			case LOGIN_PROCESS:
210*59a92d18SAlex Hornung 			case USER_PROCESS:
211*59a92d18SAlex Hornung 			case DEAD_PROCESS:
212*59a92d18SAlex Hornung 				if (memcmp(ut.ut_id, utx->ut_id,
213*59a92d18SAlex Hornung 				    sizeof(ut.ut_id)) == 0)
214*59a92d18SAlex Hornung 					return &ut;
215*59a92d18SAlex Hornung 				break;
216*59a92d18SAlex Hornung 			default:
217*59a92d18SAlex Hornung 				break;
218*59a92d18SAlex Hornung 			}
219*59a92d18SAlex Hornung 			break;
220*59a92d18SAlex Hornung 		default:
221*59a92d18SAlex Hornung 			return NULL;
222*59a92d18SAlex Hornung 		}
223*59a92d18SAlex Hornung 	} while (getutxent() != NULL);
224*59a92d18SAlex Hornung 	return NULL;
225*59a92d18SAlex Hornung }
226*59a92d18SAlex Hornung 
227*59a92d18SAlex Hornung struct utmpx *
228*59a92d18SAlex Hornung getutxline(const struct utmpx *utx)
229*59a92d18SAlex Hornung {
230*59a92d18SAlex Hornung 
231*59a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
232*59a92d18SAlex Hornung 
233*59a92d18SAlex Hornung 	do {
234*59a92d18SAlex Hornung 		switch (ut.ut_type) {
235*59a92d18SAlex Hornung 		case EMPTY:
236*59a92d18SAlex Hornung 			break;
237*59a92d18SAlex Hornung 		case LOGIN_PROCESS:
238*59a92d18SAlex Hornung 		case USER_PROCESS:
239*59a92d18SAlex Hornung 			if (strncmp(ut.ut_line, utx->ut_line,
240*59a92d18SAlex Hornung 			    sizeof(ut.ut_line)) == 0)
241*59a92d18SAlex Hornung 				return &ut;
242*59a92d18SAlex Hornung 			break;
243*59a92d18SAlex Hornung 		default:
244*59a92d18SAlex Hornung 			break;
245*59a92d18SAlex Hornung 		}
246*59a92d18SAlex Hornung 	} while (getutxent() != NULL);
247*59a92d18SAlex Hornung 	return NULL;
248*59a92d18SAlex Hornung }
249*59a92d18SAlex Hornung 
250*59a92d18SAlex Hornung struct utmpx *
251*59a92d18SAlex Hornung pututxline(const struct utmpx *utx)
252*59a92d18SAlex Hornung {
253*59a92d18SAlex Hornung 	struct passwd *pw;
254*59a92d18SAlex Hornung 	struct lastlogx ll;
255*59a92d18SAlex Hornung 	struct utmpx temp, *u = NULL;
256*59a92d18SAlex Hornung 	int gotlock = 0;
257*59a92d18SAlex Hornung 
258*59a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
259*59a92d18SAlex Hornung 
260*59a92d18SAlex Hornung 	if (utx == NULL)
261*59a92d18SAlex Hornung 		return NULL;
262*59a92d18SAlex Hornung 
263*59a92d18SAlex Hornung 	if (utx->ut_type == USER_PROCESS) {
264*59a92d18SAlex Hornung 		ll.ll_tv = utx->ut_tv;
265*59a92d18SAlex Hornung 		strcpy(ll.ll_host, utx->ut_host);
266*59a92d18SAlex Hornung 		strcpy(ll.ll_line, utx->ut_line);
267*59a92d18SAlex Hornung 		pw = getpwnam(utx->ut_name);
268*59a92d18SAlex Hornung 		if (pw != NULL)
269*59a92d18SAlex Hornung 			updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll);
270*59a92d18SAlex Hornung 	}
271*59a92d18SAlex Hornung 
272*59a92d18SAlex Hornung 	if (strcmp(_PATH_UTMPX, utfile) == 0)
273*59a92d18SAlex Hornung 		if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0))
274*59a92d18SAlex Hornung 			return utmp_update(utx);
275*59a92d18SAlex Hornung 
276*59a92d18SAlex Hornung 
277*59a92d18SAlex Hornung 	(void)memcpy(&temp, utx, sizeof(temp));
278*59a92d18SAlex Hornung 
279*59a92d18SAlex Hornung 	if (fp == NULL) {
280*59a92d18SAlex Hornung 		(void)getutxent();
281*59a92d18SAlex Hornung 		if (fp == NULL || readonly)
282*59a92d18SAlex Hornung 			return NULL;
283*59a92d18SAlex Hornung 	}
284*59a92d18SAlex Hornung 
285*59a92d18SAlex Hornung 	if (getutxid(&temp) == NULL) {
286*59a92d18SAlex Hornung 		setutxent();
287*59a92d18SAlex Hornung 		if (getutxid(&temp) == NULL) {
288*59a92d18SAlex Hornung 			if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
289*59a92d18SAlex Hornung 				return NULL;
290*59a92d18SAlex Hornung 			gotlock++;
291*59a92d18SAlex Hornung 			if (fseeko(fp, (off_t)0, SEEK_END) == -1)
292*59a92d18SAlex Hornung 				goto fail;
293*59a92d18SAlex Hornung 		}
294*59a92d18SAlex Hornung 	}
295*59a92d18SAlex Hornung 
296*59a92d18SAlex Hornung 	if (!gotlock) {
297*59a92d18SAlex Hornung 		/* we are not appending */
298*59a92d18SAlex Hornung 		if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
299*59a92d18SAlex Hornung 			return NULL;
300*59a92d18SAlex Hornung 	}
301*59a92d18SAlex Hornung 
302*59a92d18SAlex Hornung 	if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
303*59a92d18SAlex Hornung 		goto fail;
304*59a92d18SAlex Hornung 
305*59a92d18SAlex Hornung 	if (fflush(fp) == -1)
306*59a92d18SAlex Hornung 		goto fail;
307*59a92d18SAlex Hornung 
308*59a92d18SAlex Hornung 	u = memcpy(&ut, &temp, sizeof(ut));
309*59a92d18SAlex Hornung fail:
310*59a92d18SAlex Hornung 	if (gotlock) {
311*59a92d18SAlex Hornung 		if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
312*59a92d18SAlex Hornung 			return NULL;
313*59a92d18SAlex Hornung 	}
314*59a92d18SAlex Hornung 	return u;
315*59a92d18SAlex Hornung }
316*59a92d18SAlex Hornung 
317*59a92d18SAlex Hornung static struct utmpx *
318*59a92d18SAlex Hornung utmp_update(const struct utmpx *utx)
319*59a92d18SAlex Hornung {
320*59a92d18SAlex Hornung 	char buf[sizeof(*utx) * 4 + 1];
321*59a92d18SAlex Hornung 	pid_t pid;
322*59a92d18SAlex Hornung 	int status;
323*59a92d18SAlex Hornung 
324*59a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
325*59a92d18SAlex Hornung 
326*59a92d18SAlex Hornung 	(void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
327*59a92d18SAlex Hornung 	    VIS_WHITE);
328*59a92d18SAlex Hornung 	switch (pid = fork()) {
329*59a92d18SAlex Hornung 	case 0:
330*59a92d18SAlex Hornung 		(void)execl(_PATH_UTMP_UPDATE,
331*59a92d18SAlex Hornung 		    strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL);
332*59a92d18SAlex Hornung 		_exit(1);
333*59a92d18SAlex Hornung 		/*NOTREACHED*/
334*59a92d18SAlex Hornung 	case -1:
335*59a92d18SAlex Hornung 		return NULL;
336*59a92d18SAlex Hornung 	default:
337*59a92d18SAlex Hornung 		if (waitpid(pid, &status, 0) == -1)
338*59a92d18SAlex Hornung 			return NULL;
339*59a92d18SAlex Hornung 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
340*59a92d18SAlex Hornung 			return memcpy(&ut, utx, sizeof(ut));
341*59a92d18SAlex Hornung 		return NULL;
342*59a92d18SAlex Hornung 	}
343*59a92d18SAlex Hornung 
344*59a92d18SAlex Hornung }
345*59a92d18SAlex Hornung 
346*59a92d18SAlex Hornung /*
347*59a92d18SAlex Hornung  * The following are extensions and not part of the X/Open spec.
348*59a92d18SAlex Hornung  */
349*59a92d18SAlex Hornung int
350*59a92d18SAlex Hornung updwtmpx(const char *file, const struct utmpx *utx)
351*59a92d18SAlex Hornung {
352*59a92d18SAlex Hornung 	int fd;
353*59a92d18SAlex Hornung 	int saved_errno;
354*59a92d18SAlex Hornung 
355*59a92d18SAlex Hornung 	_DIAGASSERT(file != NULL);
356*59a92d18SAlex Hornung 	_DIAGASSERT(utx != NULL);
357*59a92d18SAlex Hornung 
358*59a92d18SAlex Hornung 	fd = open(file, O_WRONLY|O_APPEND|O_SHLOCK);
359*59a92d18SAlex Hornung 
360*59a92d18SAlex Hornung 	if (fd == -1) {
361*59a92d18SAlex Hornung 		if ((fd = open(file, O_CREAT|O_WRONLY|O_EXLOCK, 0644)) == -1)
362*59a92d18SAlex Hornung 			return -1;
363*59a92d18SAlex Hornung 		(void)memset(&ut, 0, sizeof(ut));
364*59a92d18SAlex Hornung 		ut.ut_type = SIGNATURE;
365*59a92d18SAlex Hornung 		(void)memcpy(ut.ut_user, vers, sizeof(vers));
366*59a92d18SAlex Hornung 		if (write(fd, &ut, sizeof(ut)) == -1)
367*59a92d18SAlex Hornung 			goto failed;
368*59a92d18SAlex Hornung 	}
369*59a92d18SAlex Hornung 	if (write(fd, utx, sizeof(*utx)) == -1)
370*59a92d18SAlex Hornung 		goto failed;
371*59a92d18SAlex Hornung 	if (close(fd) == -1)
372*59a92d18SAlex Hornung 		return -1;
373*59a92d18SAlex Hornung 	return 0;
374*59a92d18SAlex Hornung 
375*59a92d18SAlex Hornung   failed:
376*59a92d18SAlex Hornung 	saved_errno = errno;
377*59a92d18SAlex Hornung 	(void) close(fd);
378*59a92d18SAlex Hornung 	errno = saved_errno;
379*59a92d18SAlex Hornung 	return -1;
380*59a92d18SAlex Hornung }
381*59a92d18SAlex Hornung 
382*59a92d18SAlex Hornung int
383*59a92d18SAlex Hornung utmpxname(const char *fname)
384*59a92d18SAlex Hornung {
385*59a92d18SAlex Hornung 	size_t len;
386*59a92d18SAlex Hornung 
387*59a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
388*59a92d18SAlex Hornung 
389*59a92d18SAlex Hornung 	len = strlen(fname);
390*59a92d18SAlex Hornung 
391*59a92d18SAlex Hornung 	if (len >= sizeof(utfile))
392*59a92d18SAlex Hornung 		return 0;
393*59a92d18SAlex Hornung 
394*59a92d18SAlex Hornung 	/* must end in x! */
395*59a92d18SAlex Hornung 	if (fname[len - 1] != 'x')
396*59a92d18SAlex Hornung 		return 0;
397*59a92d18SAlex Hornung 
398*59a92d18SAlex Hornung 	(void)strlcpy(utfile, fname, sizeof(utfile));
399*59a92d18SAlex Hornung 	endutxent();
400*59a92d18SAlex Hornung 	return 1;
401*59a92d18SAlex Hornung }
402*59a92d18SAlex Hornung 
403*59a92d18SAlex Hornung void
404*59a92d18SAlex Hornung getutmp(const struct utmpx *ux, struct utmp *u)
405*59a92d18SAlex Hornung {
406*59a92d18SAlex Hornung 
407*59a92d18SAlex Hornung 	_DIAGASSERT(ux != NULL);
408*59a92d18SAlex Hornung 	_DIAGASSERT(u != NULL);
409*59a92d18SAlex Hornung 
410*59a92d18SAlex Hornung 	(void)memcpy(u->ut_name, ux->ut_name, sizeof(u->ut_name));
411*59a92d18SAlex Hornung 	(void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
412*59a92d18SAlex Hornung 	(void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
413*59a92d18SAlex Hornung 	u->ut_time = ux->ut_tv.tv_sec;
414*59a92d18SAlex Hornung }
415*59a92d18SAlex Hornung 
416*59a92d18SAlex Hornung void
417*59a92d18SAlex Hornung getutmpx(const struct utmp *u, struct utmpx *ux)
418*59a92d18SAlex Hornung {
419*59a92d18SAlex Hornung 
420*59a92d18SAlex Hornung 	_DIAGASSERT(ux != NULL);
421*59a92d18SAlex Hornung 	_DIAGASSERT(u != NULL);
422*59a92d18SAlex Hornung 
423*59a92d18SAlex Hornung 	(void)memcpy(ux->ut_name, u->ut_name, sizeof(u->ut_name));
424*59a92d18SAlex Hornung 	(void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
425*59a92d18SAlex Hornung 	(void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
426*59a92d18SAlex Hornung 	ux->ut_tv.tv_sec = u->ut_time;
427*59a92d18SAlex Hornung 	ux->ut_tv.tv_usec = 0;
428*59a92d18SAlex Hornung 	(void)memset(&ux->ut_ss, 0, sizeof(ux->ut_ss));
429*59a92d18SAlex Hornung 	ux->ut_pid = 0;
430*59a92d18SAlex Hornung 	ux->ut_type = USER_PROCESS;
431*59a92d18SAlex Hornung 	ux->ut_session = 0;
432*59a92d18SAlex Hornung 	ux->ut_exit.e_termination = 0;
433*59a92d18SAlex Hornung 	ux->ut_exit.e_exit = 0;
434*59a92d18SAlex Hornung }
435*59a92d18SAlex Hornung 
436*59a92d18SAlex Hornung struct lastlogx *
437*59a92d18SAlex Hornung getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
438*59a92d18SAlex Hornung {
439*59a92d18SAlex Hornung 	DBT key, data;
440*59a92d18SAlex Hornung 	DB *db;
441*59a92d18SAlex Hornung 
442*59a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
443*59a92d18SAlex Hornung 	_DIAGASSERT(ll != NULL);
444*59a92d18SAlex Hornung 
445*59a92d18SAlex Hornung 	db = dbopen(fname, O_RDONLY|O_SHLOCK, 0, DB_HASH, NULL);
446*59a92d18SAlex Hornung 
447*59a92d18SAlex Hornung 	if (db == NULL)
448*59a92d18SAlex Hornung 		return NULL;
449*59a92d18SAlex Hornung 
450*59a92d18SAlex Hornung 	key.data = &uid;
451*59a92d18SAlex Hornung 	key.size = sizeof(uid);
452*59a92d18SAlex Hornung 
453*59a92d18SAlex Hornung 	if ((db->get)(db, &key, &data, 0) != 0)
454*59a92d18SAlex Hornung 		goto error;
455*59a92d18SAlex Hornung 
456*59a92d18SAlex Hornung 	if (data.size != sizeof(*ll)) {
457*59a92d18SAlex Hornung 		errno = EFTYPE;
458*59a92d18SAlex Hornung 		goto error;
459*59a92d18SAlex Hornung 	}
460*59a92d18SAlex Hornung 
461*59a92d18SAlex Hornung 	if (ll == NULL)
462*59a92d18SAlex Hornung 		if ((ll = malloc(sizeof(*ll))) == NULL)
463*59a92d18SAlex Hornung 			goto done;
464*59a92d18SAlex Hornung 
465*59a92d18SAlex Hornung 	(void)memcpy(ll, data.data, sizeof(*ll));
466*59a92d18SAlex Hornung 	goto done;
467*59a92d18SAlex Hornung error:
468*59a92d18SAlex Hornung 	ll = NULL;
469*59a92d18SAlex Hornung done:
470*59a92d18SAlex Hornung 	(db->close)(db);
471*59a92d18SAlex Hornung 	return ll;
472*59a92d18SAlex Hornung }
473*59a92d18SAlex Hornung 
474*59a92d18SAlex Hornung int
475*59a92d18SAlex Hornung updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll)
476*59a92d18SAlex Hornung {
477*59a92d18SAlex Hornung 	DBT key, data;
478*59a92d18SAlex Hornung 	int error = 0;
479*59a92d18SAlex Hornung 	DB *db;
480*59a92d18SAlex Hornung 
481*59a92d18SAlex Hornung 	_DIAGASSERT(fname != NULL);
482*59a92d18SAlex Hornung 	_DIAGASSERT(ll != NULL);
483*59a92d18SAlex Hornung 
484*59a92d18SAlex Hornung 	db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK, 0644, DB_HASH, NULL);
485*59a92d18SAlex Hornung 
486*59a92d18SAlex Hornung 	if (db == NULL)
487*59a92d18SAlex Hornung 		return -1;
488*59a92d18SAlex Hornung 
489*59a92d18SAlex Hornung 	key.data = &uid;
490*59a92d18SAlex Hornung 	key.size = sizeof(uid);
491*59a92d18SAlex Hornung 	data.data = ll;
492*59a92d18SAlex Hornung 	data.size = sizeof(*ll);
493*59a92d18SAlex Hornung 	if ((db->put)(db, &key, &data, 0) != 0)
494*59a92d18SAlex Hornung 		error = -1;
495*59a92d18SAlex Hornung 
496*59a92d18SAlex Hornung 	(db->close)(db);
497*59a92d18SAlex Hornung 	return error;
498*59a92d18SAlex Hornung }
499