]> git.saurik.com Git - apple/libc.git/blame - gen/NetBSD/utmpx.c
Libc-997.1.1.tar.gz
[apple/libc.git] / gen / NetBSD / utmpx.c
CommitLineData
1f2f436a 1/* $NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $ */
3d9156a7
A
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.
3d9156a7
A
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32
33#if defined(LIBC_SCCS) && !defined(lint)
1f2f436a 34__RCSID("$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $");
3d9156a7
A
35#endif /* LIBC_SCCS and not lint */
36
37#include "namespace.h"
38#include <sys/types.h>
39#include <sys/param.h>
40#include <sys/socket.h>
41#include <sys/stat.h>
42#include <sys/time.h>
43#include <sys/wait.h>
44
3d9156a7
A
45#include <fcntl.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
ad3c9f2a 50#ifdef UNIFDEF_LEGACY_UTMP_APIS
3d9156a7 51#include <utmp.h>
ad3c9f2a 52#endif /* UNIFDEF_LEGACY_UTMP_APIS */
3d9156a7 53#include <utmpx.h>
ad3c9f2a
A
54#include <utmpx-darwin.h>
55#include <errno.h>
3d9156a7 56#include <vis.h>
ad3c9f2a
A
57#include <notify.h>
58
6465356a
A
59static struct _utmpx *__utx__ = NULL;
60
61static void
62__default_utx_init(void)
63{
64 __utx__ = calloc(1, sizeof(struct _utmpx));
65 const char magic[] = __UTX_MAGIC__;
66 memcpy(&__utx__->magic, magic, UTMPX_MAGIC);
67 pthread_mutex_init(&__utx__->utmpx_mutex, NULL);
68 __utx__->utfile = _PATH_UTMPX;
69 __utx__->utfile_system = 1;
70}
71
72struct _utmpx *
73__default_utx(void)
74{
75 static pthread_once_t once = PTHREAD_ONCE_INIT;
76 pthread_once(&once, &__default_utx_init);
77 return __utx__;
78}
ad3c9f2a
A
79
80static struct utmpx *__getutxid(struct _utmpx *, const struct utmpx *);
81
82__private_extern__ const char _utmpx_vers[] = "utmpx-1.00";
83
84__private_extern__ void
85__setutxent(struct _utmpx *U)
86{
3d9156a7 87
ad3c9f2a
A
88 (void)memset(&U->ut, 0, sizeof(U->ut));
89 if (U->fp == NULL)
90 return;
91#ifdef __LP64__
92 (void)fseeko(U->fp, (off_t)sizeof(struct utmpx32), SEEK_SET);
93#else /* __LP64__ */
94 (void)fseeko(U->fp, (off_t)sizeof(U->ut), SEEK_SET);
95#endif /* __LP64__ */
96}
3d9156a7 97
ad3c9f2a
A
98void
99_setutxent(struct _utmpx *U)
100{
101
102 TEST_UTMPX_T("_setutxent", U);
103 UTMPX_LOCK(U);
104 __setutxent(U);
105 UTMPX_UNLOCK(U);
106}
3d9156a7 107
3d9156a7
A
108
109void
6465356a 110setutxent(void)
3d9156a7 111{
6465356a 112 _setutxent(__default_utx());
ad3c9f2a 113}
3d9156a7 114
ad3c9f2a
A
115
116__private_extern__ void
117__endutxent(struct _utmpx *U)
118{
119 (void)memset(&U->ut, 0, sizeof(U->ut));
120 if (U->fp != NULL) {
121 int saveerrno = errno;
122 (void)fclose(U->fp);
123 errno = saveerrno;
124 U->fp = NULL;
125 U->readonly = 0;
126 }
3d9156a7
A
127}
128
129
130void
ad3c9f2a 131_endutxent(struct _utmpx *U)
3d9156a7 132{
ad3c9f2a
A
133 TEST_UTMPX_T("_endutxent", U);
134 UTMPX_LOCK(U);
135 __endutxent(U);
136 UTMPX_UNLOCK(U);
137}
3d9156a7 138
ad3c9f2a
A
139
140void
6465356a 141endutxent(void)
ad3c9f2a 142{
6465356a 143 _endutxent(__default_utx());
3d9156a7
A
144}
145
146
ad3c9f2a
A
147__private_extern__ struct utmpx *
148__getutxent(struct _utmpx *U)
3d9156a7 149{
ad3c9f2a
A
150 int saveerrno;
151#ifdef __LP64__
152 struct utmpx32 ut32;
153#endif /* __LP64__ */
3d9156a7 154
ad3c9f2a 155 if (U->fp == NULL) {
3d9156a7
A
156 struct stat st;
157
ad3c9f2a
A
158 if ((U->fp = fopen(U->utfile, "r+")) == NULL)
159 if ((U->fp = fopen(U->utfile, "w+")) == NULL) {
160 if ((U->fp = fopen(U->utfile, "r")) == NULL)
3d9156a7
A
161 goto fail;
162 else
ad3c9f2a 163 U->readonly = 1;
3d9156a7 164 }
ad3c9f2a
A
165
166 fcntl(fileno(U->fp), F_SETFD, 1); /* set close-on-exec flag */
3d9156a7
A
167
168 /* get file size in order to check if new file */
ad3c9f2a 169 if (fstat(fileno(U->fp), &st) == -1)
3d9156a7
A
170 goto failclose;
171
172 if (st.st_size == 0) {
173 /* new file, add signature record */
ad3c9f2a
A
174#ifdef __LP64__
175 (void)memset(&ut32, 0, sizeof(ut32));
176 ut32.ut_type = SIGNATURE;
177 (void)memcpy(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
178 if (fwrite(&ut32, sizeof(ut32), 1, U->fp) != 1)
179#else /* __LP64__ */
180 (void)memset(&U->ut, 0, sizeof(U->ut));
181 U->ut.ut_type = SIGNATURE;
182 (void)memcpy(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers));
183 if (fwrite(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
184#endif /* __LP64__ */
3d9156a7
A
185 goto failclose;
186 } else {
187 /* old file, read signature record */
ad3c9f2a
A
188#ifdef __LP64__
189 if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
190#else /* __LP64__ */
191 if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
192#endif /* __LP64__ */
3d9156a7 193 goto failclose;
ad3c9f2a
A
194#ifdef __LP64__
195 if (memcmp(ut32.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
196 ut32.ut_type != SIGNATURE)
197#else /* __LP64__ */
198 if (memcmp(U->ut.ut_user, _utmpx_vers, sizeof(_utmpx_vers)) != 0 ||
199 U->ut.ut_type != SIGNATURE)
200#endif /* __LP64__ */
201 {
202 errno = EINVAL;
3d9156a7 203 goto failclose;
ad3c9f2a 204 }
3d9156a7
A
205 }
206 }
207
ad3c9f2a
A
208#ifdef __LP64__
209 if (fread(&ut32, sizeof(ut32), 1, U->fp) != 1)
210#else /* __LP64__ */
211 if (fread(&U->ut, sizeof(U->ut), 1, U->fp) != 1)
212#endif /* __LP64__ */
3d9156a7
A
213 goto fail;
214
ad3c9f2a
A
215#ifdef __LP64__
216 _utmpx32_64(&ut32, &U->ut);
217#endif /* __LP64__ */
218 return &U->ut;
3d9156a7 219failclose:
ad3c9f2a
A
220 saveerrno = errno;
221 (void)fclose(U->fp);
222 errno = saveerrno;
223 U->fp = NULL;
3d9156a7 224fail:
ad3c9f2a 225 (void)memset(&U->ut, 0, sizeof(U->ut));
3d9156a7
A
226 return NULL;
227}
228
229
230struct utmpx *
ad3c9f2a 231_getutxent(struct _utmpx *U)
3d9156a7 232{
ad3c9f2a
A
233 struct utmpx *ret;
234
235 TEST_UTMPX_T("_getutxent", U);
236 UTMPX_LOCK(U);
237 ret = __getutxent(U);
238 UTMPX_UNLOCK(U);
239 return ret;
240}
241
242
243struct utmpx *
6465356a 244getutxent(void)
ad3c9f2a 245{
6465356a 246 return _getutxent(__default_utx());
ad3c9f2a
A
247}
248
3d9156a7 249
ad3c9f2a
A
250struct utmpx *
251_getutxid(struct _utmpx *U, const struct utmpx *utx)
252{
253 struct utmpx temp;
254 const struct utmpx *ux;
255 struct utmpx *ret;
3d9156a7
A
256
257 if (utx->ut_type == EMPTY)
258 return NULL;
259
ad3c9f2a
A
260 TEST_UTMPX_T("_getutxid", U);
261 UTMPX_LOCK(U);
262 /* make a copy as needed, and auto-fill if requested */
263 ux = _utmpx_working_copy(utx, &temp, 1);
264 if (!ux) {
265 UTMPX_UNLOCK(U);
266 return NULL;
267 }
268
269 ret = __getutxid(U, ux);
270 UTMPX_UNLOCK(U);
271 return ret;
272}
273
274
275struct utmpx *
276getutxid(const struct utmpx *utx)
277{
6465356a 278 return _getutxid(__default_utx(), utx);
ad3c9f2a
A
279}
280
281
282static struct utmpx *
283__getutxid(struct _utmpx *U, const struct utmpx *utx)
284{
285
3d9156a7 286 do {
ad3c9f2a 287 if (U->ut.ut_type == EMPTY)
3d9156a7
A
288 continue;
289 switch (utx->ut_type) {
290 case EMPTY:
291 return NULL;
292 case RUN_LVL:
293 case BOOT_TIME:
294 case OLD_TIME:
295 case NEW_TIME:
ad3c9f2a
A
296 if (U->ut.ut_type == utx->ut_type)
297 return &U->ut;
3d9156a7
A
298 break;
299 case INIT_PROCESS:
300 case LOGIN_PROCESS:
301 case USER_PROCESS:
302 case DEAD_PROCESS:
ad3c9f2a 303 switch (U->ut.ut_type) {
3d9156a7
A
304 case INIT_PROCESS:
305 case LOGIN_PROCESS:
306 case USER_PROCESS:
307 case DEAD_PROCESS:
ad3c9f2a
A
308 if (memcmp(U->ut.ut_id, utx->ut_id,
309 sizeof(U->ut.ut_id)) == 0)
310 return &U->ut;
3d9156a7
A
311 break;
312 default:
313 break;
314 }
315 break;
316 default:
317 return NULL;
318 }
ad3c9f2a 319 } while (__getutxent(U) != NULL);
3d9156a7
A
320 return NULL;
321}
322
323
ad3c9f2a
A
324static struct utmpx *
325__getutxline(struct _utmpx *U, const struct utmpx *utx)
3d9156a7 326{
3d9156a7 327 do {
ad3c9f2a 328 switch (U->ut.ut_type) {
3d9156a7
A
329 case EMPTY:
330 break;
331 case LOGIN_PROCESS:
332 case USER_PROCESS:
ad3c9f2a
A
333 if (strncmp(U->ut.ut_line, utx->ut_line,
334 sizeof(U->ut.ut_line)) == 0)
335 return &U->ut;
3d9156a7
A
336 break;
337 default:
338 break;
339 }
ad3c9f2a 340 } while (__getutxent(U) != NULL);
3d9156a7
A
341 return NULL;
342}
343
344
345struct utmpx *
ad3c9f2a 346_getutxline(struct _utmpx *U, const struct utmpx *utx)
3d9156a7 347{
ad3c9f2a
A
348 struct utmpx *ret;
349
350 TEST_UTMPX_T("_getutxline", U);
351 UTMPX_LOCK(U);
352 ret = __getutxline(U, utx);
353 UTMPX_UNLOCK(U);
354 return ret;
355}
3d9156a7 356
3d9156a7 357
ad3c9f2a
A
358struct utmpx *
359getutxline(const struct utmpx *utx)
360{
6465356a 361 return _getutxline(__default_utx(), utx);
ad3c9f2a
A
362}
363
364
365struct utmpx *
366_pututxline(struct _utmpx *U, const struct utmpx *utx)
367{
368 struct utmpx *ux;
369
370 if (utx == NULL) {
371 errno = EINVAL;
3d9156a7 372 return NULL;
ad3c9f2a 373 }
3d9156a7 374
ad3c9f2a
A
375 TEST_UTMPX_T("_pututxline", U);
376 UTMPX_LOCK(U);
6465356a 377 if ((ux = __pututxline(__default_utx(), utx)) != NULL && __default_utx()->utfile_system) {
ad3c9f2a
A
378 _utmpx_asl(ux); /* the equivalent of wtmpx and lastlogx */
379#ifdef UTMP_COMPAT
380 _write_utmp_compat(ux);
381#endif /* UTMP_COMPAT */
382 }
383 UTMPX_UNLOCK(U);
384 return ux;
385}
3d9156a7
A
386
387
ad3c9f2a
A
388struct utmpx *
389pututxline(const struct utmpx *utx)
390{
6465356a 391 return _pututxline(__default_utx(), utx);
ad3c9f2a
A
392}
393
394__private_extern__ struct utmpx *
395__pututxline(struct _utmpx *U, const struct utmpx *utx)
396{
397 struct utmpx temp, *u = NULL, *x;
398 const struct utmpx *ux;
399#ifdef __LP64__
400 struct utmpx32 ut32;
401#endif /* __LP64__ */
402 struct flock fl;
403#define gotlock (fl.l_start >= 0)
404
405 fl.l_start = -1; /* also means we haven't locked */
406 if (U->utfile_system)
407 if ((U->fp != NULL && U->readonly) || (U->fp == NULL && geteuid() != 0)) {
408 errno = EPERM;
409 return NULL;
410 }
3d9156a7 411
ad3c9f2a
A
412 if (U->fp == NULL) {
413 (void)__getutxent(U);
414 if (U->fp == NULL || U->readonly) {
415 errno = EPERM;
3d9156a7 416 return NULL;
ad3c9f2a 417 }
3d9156a7
A
418 }
419
ad3c9f2a
A
420 /* make a copy as needed, and auto-fill if requested */
421 ux = _utmpx_working_copy(utx, &temp, 0);
422 if (!ux)
423 return NULL;
424
425 if ((x = __getutxid(U, ux)) == NULL) {
426 __setutxent(U);
427 if ((x = __getutxid(U, ux)) == NULL) {
428 /*
429 * utx->ut_type has any original mask bits, while
430 * ux->ut_type has those mask bits removed. If we
431 * are trying to record a dead process, and
432 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
433 * there is no matching entry, we return NULL.
434 */
435 if (ux->ut_type == DEAD_PROCESS &&
436 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK)) {
437 errno = EINVAL;
3d9156a7 438 return NULL;
ad3c9f2a
A
439 }
440 /*
441 * Replace lockf() with fcntl() and a fixed start
442 * value. We should already be at EOF.
443 */
444 if ((fl.l_start = lseek(fileno(U->fp), 0, SEEK_CUR)) < 0)
445 return NULL;
446 fl.l_len = 0;
447 fl.l_whence = SEEK_SET;
448 fl.l_type = F_WRLCK;
449 if (fcntl(fileno(U->fp), F_SETLKW, &fl) == -1)
450 return NULL;
451 if (fseeko(U->fp, (off_t)0, SEEK_END) == -1)
3d9156a7
A
452 goto fail;
453 }
454 }
455
456 if (!gotlock) {
ad3c9f2a
A
457 /*
458 * utx->ut_type has any original mask bits, while
459 * ux->ut_type has those mask bits removed. If we
460 * are trying to record a dead process, if
461 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
462 * entry is not a (matching) USER_PROCESS, then return NULL.
463 */
464 if (ux->ut_type == DEAD_PROCESS &&
465 (utx->ut_type & UTMPX_DEAD_IF_CORRESPONDING_MASK) &&
466 x->ut_type != USER_PROCESS) {
467 errno = EINVAL;
468 return NULL;
469 }
3d9156a7 470 /* we are not appending */
ad3c9f2a
A
471#ifdef __LP64__
472 if (fseeko(U->fp, -(off_t)sizeof(ut32), SEEK_CUR) == -1)
473#else /* __LP64__ */
474 if (fseeko(U->fp, -(off_t)sizeof(U->ut), SEEK_CUR) == -1)
475#endif /* __LP64__ */
3d9156a7
A
476 return NULL;
477 }
478
ad3c9f2a
A
479#ifdef __LP64__
480 _utmpx64_32(ux, &ut32);
481 if (fwrite(&ut32, sizeof (ut32), 1, U->fp) != 1)
482#else /* __LP64__ */
483 if (fwrite(ux, sizeof (*ux), 1, U->fp) != 1)
484#endif /* __LP64__ */
3d9156a7
A
485 goto fail;
486
ad3c9f2a 487 if (fflush(U->fp) == -1)
3d9156a7
A
488 goto fail;
489
ad3c9f2a
A
490 u = memcpy(&U->ut, ux, sizeof(U->ut));
491 notify_post(UTMPX_CHANGE_NOTIFICATION);
3d9156a7
A
492fail:
493 if (gotlock) {
ad3c9f2a
A
494 int save = errno;
495 fl.l_type = F_UNLCK;
496 if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1)
3d9156a7 497 return NULL;
ad3c9f2a 498 errno = save;
3d9156a7
A
499 }
500 return u;
501}
502
503
3d9156a7
A
504/*
505 * The following are extensions and not part of the X/Open spec.
506 */
ad3c9f2a
A
507__private_extern__ int
508__utmpxname(struct _utmpx *U, const char *fname)
3d9156a7
A
509{
510 size_t len;
511
ad3c9f2a
A
512 if (fname == NULL) {
513 if(!U->utfile_system)
514 free(U->utfile);
515 U->utfile = _PATH_UTMPX;
516 U->utfile_system = 1;
517 __endutxent(U);
518 return 1;
519 }
3d9156a7
A
520
521 len = strlen(fname);
522
ad3c9f2a 523 if (len >= MAXPATHLEN)
3d9156a7
A
524 return 0;
525
526 /* must end in x! */
527 if (fname[len - 1] != 'x')
528 return 0;
529
ad3c9f2a
A
530 if (U->utfile_system)
531 U->utfile = NULL;
532 U->utfile_system = 0;
533 if ((U->utfile = reallocf(U->utfile, len + 1)) == NULL)
534 return 0;
535
536 (void)strcpy(U->utfile, fname);
537 __endutxent(U);
3d9156a7
A
538 return 1;
539}
540
ad3c9f2a
A
541int
542_utmpxname(struct _utmpx *U, const char *fname)
543{
544 int ret;
545
546 TEST_UTMPX_T("_utmpxname", U);
547 UTMPX_LOCK(U);
548 ret = __utmpxname(U, fname);
549 UTMPX_UNLOCK(U);
550 return ret;
551}
552
553int
554utmpxname(const char *fname)
555{
6465356a 556 return _utmpxname(__default_utx(), fname);
ad3c9f2a 557}
3d9156a7 558
ad3c9f2a 559#ifdef UNIFDEF_LEGACY_UTMP_APIS
3d9156a7
A
560void
561getutmp(const struct utmpx *ux, struct utmp *u)
562{
563
ad3c9f2a
A
564 bzero(u, sizeof(*u));
565 (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
3d9156a7
A
566 (void)memcpy(u->ut_line, ux->ut_line, sizeof(u->ut_line));
567 (void)memcpy(u->ut_host, ux->ut_host, sizeof(u->ut_host));
568 u->ut_time = ux->ut_tv.tv_sec;
569}
570
571void
572getutmpx(const struct utmp *u, struct utmpx *ux)
573{
574
ad3c9f2a
A
575 bzero(ux, sizeof(*ux));
576 (void)memcpy(ux->ut_user, u->ut_name, sizeof(u->ut_name));
577 ux->ut_user[sizeof(u->ut_name)] = 0;
3d9156a7 578 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
ad3c9f2a 579 ux->ut_line[sizeof(u->ut_line)] = 0;
3d9156a7 580 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
ad3c9f2a 581 ux->ut_host[sizeof(u->ut_host)] = 0;
3d9156a7
A
582 ux->ut_tv.tv_sec = u->ut_time;
583 ux->ut_tv.tv_usec = 0;
ad3c9f2a 584 ux->ut_pid = getpid();
3d9156a7 585 ux->ut_type = USER_PROCESS;
3d9156a7 586}
ad3c9f2a 587#endif /* UNIFDEF_LEGACY_UTMP_APIS */