getutxent.c revision 233345
1294190Sdes/*-
2255581Sdes * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3255581Sdes * All rights reserved.
4255581Sdes *
5255581Sdes * Redistribution and use in source and binary forms, with or without
6255581Sdes * modification, are permitted provided that the following conditions
7255581Sdes * are met:
8255581Sdes * 1. Redistributions of source code must retain the above copyright
9255581Sdes *    notice, this list of conditions and the following disclaimer.
10255581Sdes * 2. Redistributions in binary form must reproduce the above copyright
11255581Sdes *    notice, this list of conditions and the following disclaimer in the
12255581Sdes *    documentation and/or other materials provided with the distribution.
13255581Sdes *
14255581Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15255581Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16255581Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17255581Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18255581Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19255581Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20255581Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21255581Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22255581Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23255581Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24255581Sdes * SUCH DAMAGE.
25255581Sdes */
26255581Sdes
27285206Sdes#include <sys/cdefs.h>
28255581Sdes__FBSDID("$FreeBSD: head/lib/libc/gen/getutxent.c 233345 2012-03-23 08:26:31Z ed $");
29255581Sdes
30255581Sdes#include "namespace.h"
31255581Sdes#include <sys/endian.h>
32255581Sdes#include <sys/param.h>
33255581Sdes#include <sys/stat.h>
34285206Sdes#include <errno.h>
35255581Sdes#include <stdio.h>
36255581Sdes#include <string.h>
37255581Sdes#include <utmpx.h>
38255581Sdes#include "utxdb.h"
39255581Sdes#include "un-namespace.h"
40255581Sdes
41255581Sdes#ifdef __NO_TLS
42255581Sdesstatic FILE *uf = NULL;
43255581Sdesstatic int udb;
44255581Sdes#else
45255581Sdesstatic _Thread_local FILE *uf = NULL;
46255581Sdesstatic _Thread_local int udb;
47255581Sdes#endif
48255581Sdes
49255581Sdesint
50255581Sdessetutxdb(int db, const char *file)
51255581Sdes{
52255581Sdes	struct stat sb;
53255581Sdes
54255581Sdes	switch (db) {
55255581Sdes	case UTXDB_ACTIVE:
56255581Sdes		if (file == NULL)
57255581Sdes			file = _PATH_UTX_ACTIVE;
58255581Sdes		break;
59255581Sdes	case UTXDB_LASTLOGIN:
60255581Sdes		if (file == NULL)
61255581Sdes			file = _PATH_UTX_LASTLOGIN;
62255581Sdes		break;
63255581Sdes	case UTXDB_LOG:
64255581Sdes		if (file == NULL)
65255581Sdes			file = _PATH_UTX_LOG;
66255581Sdes		break;
67255581Sdes	default:
68255581Sdes		errno = EINVAL;
69255581Sdes		return (-1);
70255581Sdes	}
71255581Sdes
72255581Sdes	if (uf != NULL)
73255581Sdes		fclose(uf);
74255581Sdes	uf = fopen(file, "r");
75255581Sdes	if (uf == NULL)
76255581Sdes		return (-1);
77255581Sdes
78255581Sdes	if (db != UTXDB_LOG) {
79255581Sdes		/* Safety check: never use broken files. */
80255581Sdes		if (_fstat(fileno(uf), &sb) != -1 &&
81255581Sdes		    sb.st_size % sizeof(struct futx) != 0) {
82255581Sdes			fclose(uf);
83255581Sdes			uf = NULL;
84255581Sdes			errno = EFTYPE;
85255581Sdes			return (-1);
86255581Sdes		}
87255581Sdes		/* Prevent reading of partial records. */
88255581Sdes		(void)setvbuf(uf, NULL, _IOFBF,
89255581Sdes		    rounddown(BUFSIZ, sizeof(struct futx)));
90255581Sdes	}
91255581Sdes
92255581Sdes	udb = db;
93255581Sdes	return (0);
94255581Sdes}
95255581Sdes
96255581Sdesvoid
97255581Sdessetutxent(void)
98255581Sdes{
99255581Sdes
100255581Sdes	setutxdb(UTXDB_ACTIVE, NULL);
101255581Sdes}
102255581Sdes
103255581Sdesvoid
104255581Sdesendutxent(void)
105255581Sdes{
106255581Sdes
107255581Sdes	if (uf != NULL) {
108255581Sdes		fclose(uf);
109255581Sdes		uf = NULL;
110255581Sdes	}
111255581Sdes}
112255581Sdes
113255581Sdesstatic int
114255581Sdesgetfutxent(struct futx *fu)
115255581Sdes{
116255581Sdes
117255581Sdes	if (uf == NULL)
118255581Sdes		setutxent();
119255581Sdes	if (uf == NULL)
120255581Sdes		return (-1);
121255581Sdes
122255581Sdes	if (udb == UTXDB_LOG) {
123255581Sdes		uint16_t len;
124255581Sdes
125255581Sdes		if (fread(&len, sizeof(len), 1, uf) != 1)
126255581Sdes			return (-1);
127255581Sdes		len = be16toh(len);
128255581Sdes		if (len > sizeof *fu) {
129255581Sdes			/* Forward compatibility. */
130255581Sdes			if (fread(fu, sizeof(*fu), 1, uf) != 1)
131255581Sdes				return (-1);
132255581Sdes			fseek(uf, len - sizeof(*fu), SEEK_CUR);
133255581Sdes		} else {
134255581Sdes			/* Partial record. */
135255581Sdes			memset(fu, 0, sizeof(*fu));
136255581Sdes			if (fread(fu, len, 1, uf) != 1)
137255581Sdes				return (-1);
138255581Sdes		}
139255581Sdes	} else {
140255581Sdes		if (fread(fu, sizeof(*fu), 1, uf) != 1)
141285206Sdes			return (-1);
142255581Sdes	}
143255581Sdes	return (0);
144255581Sdes}
145255581Sdes
146255581Sdesstruct utmpx *
147255581Sdesgetutxent(void)
148255581Sdes{
149255581Sdes	struct futx fu;
150255581Sdes
151255581Sdes	if (getfutxent(&fu) != 0)
152255581Sdes		return (NULL);
153255581Sdes	return (futx_to_utx(&fu));
154255581Sdes}
155255581Sdes
156255581Sdesstruct utmpx *
157255581Sdesgetutxid(const struct utmpx *id)
158255581Sdes{
159255581Sdes	struct futx fu;
160255581Sdes
161255581Sdes	for (;;) {
162255581Sdes		if (getfutxent(&fu) != 0)
163255581Sdes			return (NULL);
164255581Sdes
165255581Sdes		switch (fu.fu_type) {
166255581Sdes		case USER_PROCESS:
167255581Sdes		case INIT_PROCESS:
168255581Sdes		case LOGIN_PROCESS:
169255581Sdes		case DEAD_PROCESS:
170255581Sdes			switch (id->ut_type) {
171255581Sdes			case USER_PROCESS:
172255581Sdes			case INIT_PROCESS:
173255581Sdes			case LOGIN_PROCESS:
174255581Sdes			case DEAD_PROCESS:
175255581Sdes				if (memcmp(fu.fu_id, id->ut_id,
176				    MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
177				    0)
178					goto found;
179			}
180			break;
181		default:
182			if (fu.fu_type == id->ut_type)
183				goto found;
184			break;
185		}
186	}
187
188found:
189	return (futx_to_utx(&fu));
190}
191
192struct utmpx *
193getutxline(const struct utmpx *line)
194{
195	struct futx fu;
196
197	for (;;) {
198		if (getfutxent(&fu) != 0)
199			return (NULL);
200
201		switch (fu.fu_type) {
202		case USER_PROCESS:
203		case LOGIN_PROCESS:
204			if (strncmp(fu.fu_line, line->ut_line,
205			    MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
206			    0)
207				goto found;
208			break;
209		}
210	}
211
212found:
213	return (futx_to_utx(&fu));
214}
215
216struct utmpx *
217getutxuser(const char *user)
218{
219	struct futx fu;
220
221	for (;;) {
222		if (getfutxent(&fu) != 0)
223			return (NULL);
224
225		switch (fu.fu_type) {
226		case USER_PROCESS:
227			if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
228				goto found;
229			break;
230		}
231	}
232
233found:
234	return (futx_to_utx(&fu));
235}
236