]> git.saurik.com Git - apple/libc.git/blame - gen/utmpx-nbsd.c
Libc-583.tar.gz
[apple/libc.git] / gen / utmpx-nbsd.c
CommitLineData
224c7076
A
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>
b5d655f7 57#ifdef LEGACY_UTMP_APIS
224c7076 58#include <utmp.h>
b5d655f7 59#endif /* LEGACY_UTMP_APIS */
224c7076
A
60#include <utmpx.h>
61#include <utmpx-darwin.h>
62#include <errno.h>
63#include <vis.h>
64#include <notify.h>
65
66static FILE *fp;
67static int readonly = 0;
68static struct utmpx ut;
69static char utfile[MAXPATHLEN] = _PATH_UTMPX;
70__private_extern__ int utfile_system = 1; /* are we using _PATH_UTMPX? */
34e8f829 71__private_extern__ pthread_mutex_t utmpx_mutex = PTHREAD_MUTEX_INITIALIZER;
224c7076
A
72
73static struct utmpx *_getutxid(const struct utmpx *);
74
75__private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
76
34e8f829
A
77__private_extern__ void
78_setutxent()
224c7076
A
79{
80
81 (void)memset(&ut, 0, sizeof(ut));
82 if (fp == NULL)
83 return;
84#ifdef __LP64__
85 (void)fseeko(fp, (off_t)sizeof(struct utmpx32), SEEK_SET);
86#else /* __LP64__ */
87 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
88#endif /* __LP64__ */
89}
90
91
92void
34e8f829
A
93setutxent()
94{
95 UTMPX_LOCK;
96 _setutxent();
97 UTMPX_UNLOCK;
98}
99
100
101__private_extern__ void
102_endutxent()
224c7076
A
103{
104
105 (void)memset(&ut, 0, sizeof(ut));
106 if (fp != NULL) {
107 (void)fclose(fp);
108 fp = NULL;
109 readonly = 0;
110 }
111}
112
113
34e8f829
A
114void
115endutxent()
116{
117 UTMPX_LOCK;
118 _endutxent();
119 UTMPX_UNLOCK;
120}
121
122
123static struct utmpx *
124_getutxent()
224c7076
A
125{
126#ifdef __LP64__
127 struct utmpx32 ut32;
128#endif /* __LP64__ */
129
130 if (fp == NULL) {
131 struct stat st;
132
133 if ((fp = fopen(utfile, "r+")) == NULL)
134 if ((fp = fopen(utfile, "w+")) == NULL) {
135 if ((fp = fopen(utfile, "r")) == NULL)
136 goto fail;
137 else
138 readonly = 1;
139 }
34e8f829
A
140
141 fcntl(fileno(fp), F_SETFD, 1); /* set close-on-exec flag */
224c7076
A
142
143 /* get file size in order to check if new file */
144 if (fstat(fileno(fp), &st) == -1)
145 goto failclose;
146
147 if (st.st_size == 0) {
148 /* new file, add signature record */
149#ifdef __LP64__
150 (void)memset(&ut32, 0, sizeof(ut32));
151 ut32.ut_type = SIGNATURE;
152 (void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
153 if (fwrite(&ut32, sizeof(ut32), 1, fp) != 1)
154#else /* __LP64__ */
155 (void)memset(&ut, 0, sizeof(ut));
156 ut.ut_type = SIGNATURE;
157 (void)memcpy(ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
158 if (fwrite(&ut, sizeof(ut), 1, fp) != 1)
159#endif /* __LP64__ */
160 goto failclose;
161 } else {
162 /* old file, read signature record */
163#ifdef __LP64__
164 if (fread(&ut32, sizeof(ut32), 1, fp) != 1)
165#else /* __LP64__ */
166 if (fread(&ut, sizeof(ut), 1, fp) != 1)
167#endif /* __LP64__ */
168 goto failclose;
169#ifdef __LP64__
170 if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
171 ut32.ut_type != SIGNATURE)
172#else /* __LP64__ */
173 if (memcmp(ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
174 ut.ut_type != SIGNATURE)
175#endif /* __LP64__ */
176 goto failclose;
177 }
178 }
179
180#ifdef __LP64__
181 if (fread(&ut32, sizeof(ut32), 1, fp) != 1)
182#else /* __LP64__ */
183 if (fread(&ut, sizeof(ut), 1, fp) != 1)
184#endif /* __LP64__ */
185 goto fail;
186
187#ifdef __LP64__
188 _utmpx32_64(&ut32, &ut);
189#endif /* __LP64__ */
190 return &ut;
191failclose:
192 (void)fclose(fp);
193 fp = NULL;
194fail:
195 (void)memset(&ut, 0, sizeof(ut));
196 return NULL;
197}
198
34e8f829
A
199
200struct utmpx *
201getutxent()
202{
203 struct utmpx *ret;
204 UTMPX_LOCK;
205 ret = _getutxent();
206 UTMPX_UNLOCK;
207 return ret;
208}
209
224c7076
A
210struct utmpx *
211getutxid(const struct utmpx *utx)
212{
213 struct utmpx temp;
214 const struct utmpx *ux;
34e8f829 215 struct utmpx *ret;
224c7076
A
216
217 _DIAGASSERT(utx != NULL);
218
219 if (utx->ut_type == EMPTY)
220 return NULL;
221
34e8f829 222 UTMPX_LOCK;
224c7076
A
223 /* make a copy as needed, and auto-fill if requested */
224 ux = _utmpx_working_copy(utx, &temp, 1);
34e8f829
A
225 if (!ux) {
226 UTMPX_UNLOCK;
224c7076 227 return NULL;
34e8f829 228 }
224c7076 229
34e8f829
A
230 ret = _getutxid(ux);
231 UTMPX_UNLOCK;
232 return ret;
224c7076
A
233}
234
235
236static struct utmpx *
237_getutxid(const struct utmpx *utx)
238{
239
240 do {
241 if (ut.ut_type == EMPTY)
242 continue;
243 switch (utx->ut_type) {
244 case EMPTY:
245 return NULL;
246 case RUN_LVL:
247 case BOOT_TIME:
248 case OLD_TIME:
249 case NEW_TIME:
250 if (ut.ut_type == utx->ut_type)
251 return &ut;
252 break;
253 case INIT_PROCESS:
254 case LOGIN_PROCESS:
255 case USER_PROCESS:
256 case DEAD_PROCESS:
257 switch (ut.ut_type) {
258 case INIT_PROCESS:
259 case LOGIN_PROCESS:
260 case USER_PROCESS:
261 case DEAD_PROCESS:
262 if (memcmp(ut.ut_id, utx->ut_id,
263 sizeof(ut.ut_id)) == 0)
264 return &ut;
265 break;
266 default:
267 break;
268 }
269 break;
270 default:
271 return NULL;
272 }
34e8f829 273 } while (_getutxent() != NULL);
224c7076
A
274 return NULL;
275}
276
277
278struct utmpx *
279getutxline(const struct utmpx *utx)
280{
281
282 _DIAGASSERT(utx != NULL);
283
34e8f829 284 UTMPX_LOCK;
224c7076
A
285 do {
286 switch (ut.ut_type) {
287 case EMPTY:
288 break;
289 case LOGIN_PROCESS:
290 case USER_PROCESS:
291 if (strncmp(ut.ut_line, utx->ut_line,
34e8f829
A
292 sizeof(ut.ut_line)) == 0) {
293 UTMPX_UNLOCK;
224c7076 294 return &ut;
34e8f829 295 }
224c7076
A
296 break;
297 default:
298 break;
299 }
34e8f829
A
300 } while (_getutxent() != NULL);
301 UTMPX_UNLOCK;
224c7076
A
302 return NULL;
303}
304
305
306struct utmpx *
307pututxline(const struct utmpx *utx)
308{
309 struct utmpx *ux;
310
311 _DIAGASSERT(utx != NULL);
312
313 if (utx == NULL) {
314 errno = EINVAL;
315 return NULL;
316 }
317
34e8f829 318 UTMPX_LOCK;
224c7076
A
319 if ((ux = _pututxline(utx)) != NULL && utfile_system) {
320 _utmpx_asl(ux); /* the equivalent of wtmpx and lastlogx */
321#ifdef UTMP_COMPAT
322 _write_utmp_compat(ux);
323#endif /* UTMP_COMPAT */
324 }
34e8f829 325 UTMPX_UNLOCK;
224c7076
A
326 return ux;
327}
328
329__private_extern__ struct utmpx *
330_pututxline(const struct utmpx *utx)
331{
332 struct utmpx temp, *u = NULL, *x;
333 const struct utmpx *ux;
334#ifdef __LP64__
335 struct utmpx32 ut32;
336#endif /* __LP64__ */
34e8f829
A
337 struct flock fl;
338#define gotlock (fl.l_start >= 0)
224c7076 339
34e8f829 340 fl.l_start = -1; /* also means we haven't locked */
224c7076
A
341 if (utfile_system)
342 if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0)) {
343 errno = EPERM;
344 return NULL;
345 }
346
347 if (fp == NULL) {
34e8f829 348 (void)_getutxent();
224c7076
A
349 if (fp == NULL || readonly) {
350 errno = EPERM;
351 return NULL;
352 }
353 }
354
355 /* make a copy as needed, and auto-fill if requested */
356 ux = _utmpx_working_copy(utx, &temp, 0);
357 if (!ux)
358 return NULL;
359
360 if ((x = _getutxid(ux)) == NULL) {
34e8f829 361 _setutxent();
224c7076
A
362 if ((x = _getutxid(ux)) == NULL) {
363 /*
364 * utx->ut_type has any original mask bits, while
365 * ux->ut_type has those mask bits removed. If we
366 * are trying to record a dead process, and
367 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
368 * there is no matching entry, we return NULL.
369 */
370 if (ux->ut_type == DEAD_PROCESS &&
371 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) {
372 errno = EINVAL;
373 return NULL;
374 }
34e8f829
A
375 /*
376 * Replace lockf() with fcntl() and a fixed start
377 * value. We should already be at EOF.
378 */
379 if ((fl.l_start = lseek(fileno(fp), 0, SEEK_CUR)) < 0)
380 return NULL;
381 fl.l_len = 0;
382 fl.l_whence = SEEK_SET;
383 fl.l_type = F_WRLCK;
384 if (fcntl(fileno(fp), F_SETLKW, &fl) == -1)
224c7076 385 return NULL;
224c7076
A
386 if (fseeko(fp, (off_t)0, SEEK_END) == -1)
387 goto fail;
388 }
389 }
390
391 if (!gotlock) {
392 /*
393 * utx->ut_type has any original mask bits, while
394 * ux->ut_type has those mask bits removed. If we
395 * are trying to record a dead process, if
396 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
397 * entry is not a (matching) USER_PROCESS, then return NULL.
398 */
399 if (ux->ut_type == DEAD_PROCESS &&
400 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) &&
401 x->ut_type != USER_PROCESS) {
402 errno = EINVAL;
403 return NULL;
404 }
405 /* we are not appending */
406#ifdef __LP64__
407 if (fseeko(fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1)
408#else /* __LP64__ */
409 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
410#endif /* __LP64__ */
411 return NULL;
412 }
413
414#ifdef __LP64__
415 _utmpx64_32(ux, &ut32);
416 if (fwrite(&ut32, sizeof (ut32), 1, fp) != 1)
417#else /* __LP64__ */
418 if (fwrite(ux, sizeof (*ux), 1, fp) != 1)
419#endif /* __LP64__ */
420 goto fail;
421
422 if (fflush(fp) == -1)
423 goto fail;
424
425 u = memcpy(&ut, ux, sizeof(ut));
426 notify_post(UTMPX_CHANGE_NOTIFICATION);
427fail:
428 if (gotlock) {
429 int save = errno;
34e8f829
A
430 fl.l_type = F_UNLCK;
431 if (fcntl(fileno(fp), F_SETLK, &fl) == -1)
224c7076
A
432 return NULL;
433 errno = save;
434 }
435 return u;
436}
437
438
439/*
440 * The following are extensions and not part of the X/Open spec.
441 */
442int
443utmpxname(const char *fname)
444{
445 size_t len;
446
34e8f829 447 UTMPX_LOCK;
224c7076
A
448 if (fname == NULL) {
449 strcpy(utfile, _PATH_UTMPX);
450 utfile_system = 1;
34e8f829
A
451 _endutxent();
452 UTMPX_UNLOCK;
224c7076
A
453 return 1;
454 }
455
456 len = strlen(fname);
457
34e8f829
A
458 if (len >= sizeof(utfile)) {
459 UTMPX_UNLOCK;
224c7076 460 return 0;
34e8f829 461 }
224c7076
A
462
463 /* must end in x! */
34e8f829
A
464 if (fname[len - 1] != 'x') {
465 UTMPX_UNLOCK;
224c7076 466 return 0;
34e8f829 467 }
224c7076
A
468
469 (void)strlcpy(utfile, fname, sizeof(utfile));
34e8f829 470 _endutxent();
224c7076 471 utfile_system = 0;
34e8f829 472 UTMPX_UNLOCK;
224c7076
A
473 return 1;
474}
475
b5d655f7 476#ifdef LEGACY_UTMP_APIS
224c7076
A
477void
478getutmp(const struct utmpx *ux, struct utmp *u)
479{
480
481 bzero(u, sizeof(*u));
482 (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
483 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
484 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
485 u->ut_time = ux->ut_tv.tv_sec;
486}
487
488void
489getutmpx(const struct utmp *u, struct utmpx *ux)
490{
491
492 bzero(ux, sizeof(*ux));
493 (void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
494 ux->ut_user[sizeof(u->ut_name)] = 0;
495 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
496 ux->ut_line[sizeof(u->ut_line)] = 0;
497 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
498 ux->ut_host[sizeof(u->ut_host)] = 0;
499 ux->ut_tv.tv_sec = u->ut_time;
500 ux->ut_tv.tv_usec = 0;
501 ux->ut_pid = getpid();
502 ux->ut_type = USER_PROCESS;
503}
b5d655f7 504#endif /* LEGACY_UTMP_APIS */