]> git.saurik.com Git - apple/libc.git/blame_incremental - gen/utmpx-nbsd.c
Libc-498.1.1.tar.gz
[apple/libc.git] / gen / utmpx-nbsd.c
... / ...
CommitLineData
1/* $NetBSD: utmpx.c,v 1.21 2003/09/06 16:42:10 wiz Exp $ */
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38#include <sys/cdefs.h>
39
40#if defined(LIBC_SCCS) && !defined(lint)
41__RCSID("$NetBSD: utmpx.c,v 1.21 2003/09/06 16:42:10 wiz Exp $");
42#endif /* LIBC_SCCS and not lint */
43
44#include "namespace.h"
45#include <sys/types.h>
46#include <sys/param.h>
47#include <sys/socket.h>
48#include <sys/stat.h>
49#include <sys/time.h>
50#include <sys/wait.h>
51
52#include <fcntl.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57#include <utmp.h>
58#include <utmpx.h>
59#include <utmpx-darwin.h>
60#include <errno.h>
61#include <vis.h>
62#include <notify.h>
63
64static FILE *fp;
65static int readonly = 0;
66static struct utmpx ut;
67static char utfile[MAXPATHLEN] = _PATH_UTMPX;
68__private_extern__ int utfile_system = 1; /* are we using _PATH_UTMPX? */
69
70static struct utmpx *_getutxid(const struct utmpx *);
71
72__private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
73
74void
75setutxent()
76{
77
78 (void)memset(&ut, 0, sizeof(ut));
79 if (fp == NULL)
80 return;
81#ifdef __LP64__
82 (void)fseeko(fp, (off_t)sizeof(struct utmpx32), SEEK_SET);
83#else /* __LP64__ */
84 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
85#endif /* __LP64__ */
86}
87
88
89void
90endutxent()
91{
92
93 (void)memset(&ut, 0, sizeof(ut));
94 if (fp != NULL) {
95 (void)fclose(fp);
96 fp = NULL;
97 readonly = 0;
98 }
99}
100
101
102struct utmpx *
103getutxent()
104{
105#ifdef __LP64__
106 struct utmpx32 ut32;
107#endif /* __LP64__ */
108
109 if (fp == NULL) {
110 struct stat st;
111
112 if ((fp = fopen(utfile, "r+")) == NULL)
113 if ((fp = fopen(utfile, "w+")) == NULL) {
114 if ((fp = fopen(utfile, "r")) == NULL)
115 goto fail;
116 else
117 readonly = 1;
118 }
119
120
121 /* get file size in order to check if new file */
122 if (fstat(fileno(fp), &st) == -1)
123 goto failclose;
124
125 if (st.st_size == 0) {
126 /* new file, add signature record */
127#ifdef __LP64__
128 (void)memset(&ut32, 0, sizeof(ut32));
129 ut32.ut_type = SIGNATURE;
130 (void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
131 if (fwrite(&ut32, sizeof(ut32), 1, fp) != 1)
132#else /* __LP64__ */
133 (void)memset(&ut, 0, sizeof(ut));
134 ut.ut_type = SIGNATURE;
135 (void)memcpy(ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
136 if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
137#endif /* __LP64__ */
138 goto failclose;
139 } else {
140 /* old file, read signature record */
141#ifdef __LP64__
142 if (fread(&ut32, sizeof(ut32), 1, fp) != 1)
143#else /* __LP64__ */
144 if (fread(&ut, sizeof(ut), 1, fp) != 1)
145#endif /* __LP64__ */
146 goto failclose;
147#ifdef __LP64__
148 if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
149 ut32.ut_type != SIGNATURE)
150#else /* __LP64__ */
151 if (memcmp(ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
152 ut.ut_type != SIGNATURE)
153#endif /* __LP64__ */
154 goto failclose;
155 }
156 }
157
158#ifdef __LP64__
159 if (fread(&ut32, sizeof(ut32), 1, fp) != 1)
160#else /* __LP64__ */
161 if (fread(&ut, sizeof(ut), 1, fp) != 1)
162#endif /* __LP64__ */
163 goto fail;
164
165#ifdef __LP64__
166 _utmpx32_64(&ut32, &ut);
167#endif /* __LP64__ */
168 return &ut;
169failclose:
170 (void)fclose(fp);
171 fp = NULL;
172fail:
173 (void)memset(&ut, 0, sizeof(ut));
174 return NULL;
175}
176
177struct utmpx *
178getutxid(const struct utmpx *utx)
179{
180 struct utmpx temp;
181 const struct utmpx *ux;
182
183 _DIAGASSERT(utx != NULL);
184
185 if (utx->ut_type == EMPTY)
186 return NULL;
187
188 /* make a copy as needed, and auto-fill if requested */
189 ux = _utmpx_working_copy(utx, &temp, 1);
190 if (!ux)
191 return NULL;
192
193 return _getutxid(ux);
194}
195
196
197static struct utmpx *
198_getutxid(const struct utmpx *utx)
199{
200
201 do {
202 if (ut.ut_type == EMPTY)
203 continue;
204 switch (utx->ut_type) {
205 case EMPTY:
206 return NULL;
207 case RUN_LVL:
208 case BOOT_TIME:
209 case OLD_TIME:
210 case NEW_TIME:
211 if (ut.ut_type == utx->ut_type)
212 return &ut;
213 break;
214 case INIT_PROCESS:
215 case LOGIN_PROCESS:
216 case USER_PROCESS:
217 case DEAD_PROCESS:
218 switch (ut.ut_type) {
219 case INIT_PROCESS:
220 case LOGIN_PROCESS:
221 case USER_PROCESS:
222 case DEAD_PROCESS:
223 if (memcmp(ut.ut_id, utx->ut_id,
224 sizeof(ut.ut_id)) == 0)
225 return &ut;
226 break;
227 default:
228 break;
229 }
230 break;
231 default:
232 return NULL;
233 }
234 } while (getutxent() != NULL);
235 return NULL;
236}
237
238
239struct utmpx *
240getutxline(const struct utmpx *utx)
241{
242
243 _DIAGASSERT(utx != NULL);
244
245 do {
246 switch (ut.ut_type) {
247 case EMPTY:
248 break;
249 case LOGIN_PROCESS:
250 case USER_PROCESS:
251 if (strncmp(ut.ut_line, utx->ut_line,
252 sizeof(ut.ut_line)) == 0)
253 return &ut;
254 break;
255 default:
256 break;
257 }
258 } while (getutxent() != NULL);
259 return NULL;
260}
261
262
263struct utmpx *
264pututxline(const struct utmpx *utx)
265{
266 struct utmpx *ux;
267
268 _DIAGASSERT(utx != NULL);
269
270 if (utx == NULL) {
271 errno = EINVAL;
272 return NULL;
273 }
274
275 if ((ux = _pututxline(utx)) != NULL && utfile_system) {
276 _utmpx_asl(ux); /* the equivalent of wtmpx and lastlogx */
277#ifdef UTMP_COMPAT
278 _write_utmp_compat(ux);
279#endif /* UTMP_COMPAT */
280 }
281 return ux;
282}
283
284__private_extern__ struct utmpx *
285_pututxline(const struct utmpx *utx)
286{
287 struct utmpx temp, *u = NULL, *x;
288 const struct utmpx *ux;
289#ifdef __LP64__
290 struct utmpx32 ut32;
291#endif /* __LP64__ */
292 int gotlock = 0;
293
294 if (utfile_system)
295 if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0)) {
296 errno = EPERM;
297 return NULL;
298 }
299
300 if (fp == NULL) {
301 (void)getutxent();
302 if (fp == NULL || readonly) {
303 errno = EPERM;
304 return NULL;
305 }
306 }
307
308 /* make a copy as needed, and auto-fill if requested */
309 ux = _utmpx_working_copy(utx, &temp, 0);
310 if (!ux)
311 return NULL;
312
313 if ((x = _getutxid(ux)) == NULL) {
314 setutxent();
315 if ((x = _getutxid(ux)) == NULL) {
316 /*
317 * utx->ut_type has any original mask bits, while
318 * ux->ut_type has those mask bits removed. If we
319 * are trying to record a dead process, and
320 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
321 * there is no matching entry, we return NULL.
322 */
323 if (ux->ut_type == DEAD_PROCESS &&
324 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) {
325 errno = EINVAL;
326 return NULL;
327 }
328 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
329 return NULL;
330 gotlock++;
331 if (fseeko(fp, (off_t)0, SEEK_END) == -1)
332 goto fail;
333 }
334 }
335
336 if (!gotlock) {
337 /*
338 * utx->ut_type has any original mask bits, while
339 * ux->ut_type has those mask bits removed. If we
340 * are trying to record a dead process, if
341 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
342 * entry is not a (matching) USER_PROCESS, then return NULL.
343 */
344 if (ux->ut_type == DEAD_PROCESS &&
345 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) &&
346 x->ut_type != USER_PROCESS) {
347 errno = EINVAL;
348 return NULL;
349 }
350 /* we are not appending */
351#ifdef __LP64__
352 if (fseeko(fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1)
353#else /* __LP64__ */
354 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
355#endif /* __LP64__ */
356 return NULL;
357 }
358
359#ifdef __LP64__
360 _utmpx64_32(ux, &ut32);
361 if (fwrite(&ut32, sizeof (ut32), 1, fp) != 1)
362#else /* __LP64__ */
363 if (fwrite(ux, sizeof (*ux), 1, fp) != 1)
364#endif /* __LP64__ */
365 goto fail;
366
367 if (fflush(fp) == -1)
368 goto fail;
369
370 u = memcpy(&ut, ux, sizeof(ut));
371 notify_post(UTMPX_CHANGE_NOTIFICATION);
372fail:
373 if (gotlock) {
374 int save = errno;
375 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
376 return NULL;
377 errno = save;
378 }
379 return u;
380}
381
382
383/*
384 * The following are extensions and not part of the X/Open spec.
385 */
386int
387utmpxname(const char *fname)
388{
389 size_t len;
390
391 if (fname == NULL) {
392 strcpy(utfile, _PATH_UTMPX);
393 utfile_system = 1;
394 endutxent();
395 return 1;
396 }
397
398 len = strlen(fname);
399
400 if (len >= sizeof(utfile))
401 return 0;
402
403 /* must end in x! */
404 if (fname[len - 1] != 'x')
405 return 0;
406
407 (void)strlcpy(utfile, fname, sizeof(utfile));
408 endutxent();
409 utfile_system = 0;
410 return 1;
411}
412
413
414void
415getutmp(const struct utmpx *ux, struct utmp *u)
416{
417
418 bzero(u, sizeof(*u));
419 (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
420 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
421 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
422 u->ut_time = ux->ut_tv.tv_sec;
423}
424
425void
426getutmpx(const struct utmp *u, struct utmpx *ux)
427{
428
429 bzero(ux, sizeof(*ux));
430 (void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
431 ux->ut_user[sizeof(u->ut_name)] = 0;
432 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
433 ux->ut_line[sizeof(u->ut_line)] = 0;
434 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
435 ux->ut_host[sizeof(u->ut_host)] = 0;
436 ux->ut_tv.tv_sec = u->ut_time;
437 ux->ut_tv.tv_usec = 0;
438 ux->ut_pid = getpid();
439 ux->ut_type = USER_PROCESS;
440}