]> git.saurik.com Git - apple/libc.git/blame_incremental - gen/NetBSD/utmpx.c
Libc-997.1.1.tar.gz
[apple/libc.git] / gen / NetBSD / utmpx.c
... / ...
CommitLineData
1/* $NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin 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 *
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)
34__RCSID("$NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $");
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
45#include <fcntl.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#ifdef UNIFDEF_LEGACY_UTMP_APIS
51#include <utmp.h>
52#endif /* UNIFDEF_LEGACY_UTMP_APIS */
53#include <utmpx.h>
54#include <utmpx-darwin.h>
55#include <errno.h>
56#include <vis.h>
57#include <notify.h>
58
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}
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{
87
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}
97
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}
107
108
109void
110setutxent(void)
111{
112 _setutxent(__default_utx());
113}
114
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 }
127}
128
129
130void
131_endutxent(struct _utmpx *U)
132{
133 TEST_UTMPX_T("_endutxent", U);
134 UTMPX_LOCK(U);
135 __endutxent(U);
136 UTMPX_UNLOCK(U);
137}
138
139
140void
141endutxent(void)
142{
143 _endutxent(__default_utx());
144}
145
146
147__private_extern__ struct utmpx *
148__getutxent(struct _utmpx *U)
149{
150 int saveerrno;
151#ifdef __LP64__
152 struct utmpx32 ut32;
153#endif /* __LP64__ */
154
155 if (U->fp == NULL) {
156 struct stat st;
157
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)
161 goto fail;
162 else
163 U->readonly = 1;
164 }
165
166 fcntl(fileno(U->fp), F_SETFD, 1); /* set close-on-exec flag */
167
168 /* get file size in order to check if new file */
169 if (fstat(fileno(U->fp), &st) == -1)
170 goto failclose;
171
172 if (st.st_size == 0) {
173 /* new file, add signature record */
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__ */
185 goto failclose;
186 } else {
187 /* old file, read signature record */
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__ */
193 goto failclose;
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;
203 goto failclose;
204 }
205 }
206 }
207
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__ */
213 goto fail;
214
215#ifdef __LP64__
216 _utmpx32_64(&ut32, &U->ut);
217#endif /* __LP64__ */
218 return &U->ut;
219failclose:
220 saveerrno = errno;
221 (void)fclose(U->fp);
222 errno = saveerrno;
223 U->fp = NULL;
224fail:
225 (void)memset(&U->ut, 0, sizeof(U->ut));
226 return NULL;
227}
228
229
230struct utmpx *
231_getutxent(struct _utmpx *U)
232{
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 *
244getutxent(void)
245{
246 return _getutxent(__default_utx());
247}
248
249
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;
256
257 if (utx->ut_type == EMPTY)
258 return NULL;
259
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{
278 return _getutxid(__default_utx(), utx);
279}
280
281
282static struct utmpx *
283__getutxid(struct _utmpx *U, const struct utmpx *utx)
284{
285
286 do {
287 if (U->ut.ut_type == EMPTY)
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:
296 if (U->ut.ut_type == utx->ut_type)
297 return &U->ut;
298 break;
299 case INIT_PROCESS:
300 case LOGIN_PROCESS:
301 case USER_PROCESS:
302 case DEAD_PROCESS:
303 switch (U->ut.ut_type) {
304 case INIT_PROCESS:
305 case LOGIN_PROCESS:
306 case USER_PROCESS:
307 case DEAD_PROCESS:
308 if (memcmp(U->ut.ut_id, utx->ut_id,
309 sizeof(U->ut.ut_id)) == 0)
310 return &U->ut;
311 break;
312 default:
313 break;
314 }
315 break;
316 default:
317 return NULL;
318 }
319 } while (__getutxent(U) != NULL);
320 return NULL;
321}
322
323
324static struct utmpx *
325__getutxline(struct _utmpx *U, const struct utmpx *utx)
326{
327 do {
328 switch (U->ut.ut_type) {
329 case EMPTY:
330 break;
331 case LOGIN_PROCESS:
332 case USER_PROCESS:
333 if (strncmp(U->ut.ut_line, utx->ut_line,
334 sizeof(U->ut.ut_line)) == 0)
335 return &U->ut;
336 break;
337 default:
338 break;
339 }
340 } while (__getutxent(U) != NULL);
341 return NULL;
342}
343
344
345struct utmpx *
346_getutxline(struct _utmpx *U, const struct utmpx *utx)
347{
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}
356
357
358struct utmpx *
359getutxline(const struct utmpx *utx)
360{
361 return _getutxline(__default_utx(), utx);
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;
372 return NULL;
373 }
374
375 TEST_UTMPX_T("_pututxline", U);
376 UTMPX_LOCK(U);
377 if ((ux = __pututxline(__default_utx(), utx)) != NULL && __default_utx()->utfile_system) {
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}
386
387
388struct utmpx *
389pututxline(const struct utmpx *utx)
390{
391 return _pututxline(__default_utx(), utx);
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 }
411
412 if (U->fp == NULL) {
413 (void)__getutxent(U);
414 if (U->fp == NULL || U->readonly) {
415 errno = EPERM;
416 return NULL;
417 }
418 }
419
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;
438 return NULL;
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)
452 goto fail;
453 }
454 }
455
456 if (!gotlock) {
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 }
470 /* we are not appending */
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__ */
476 return NULL;
477 }
478
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__ */
485 goto fail;
486
487 if (fflush(U->fp) == -1)
488 goto fail;
489
490 u = memcpy(&U->ut, ux, sizeof(U->ut));
491 notify_post(UTMPX_CHANGE_NOTIFICATION);
492fail:
493 if (gotlock) {
494 int save = errno;
495 fl.l_type = F_UNLCK;
496 if (fcntl(fileno(U->fp), F_SETLK, &fl) == -1)
497 return NULL;
498 errno = save;
499 }
500 return u;
501}
502
503
504/*
505 * The following are extensions and not part of the X/Open spec.
506 */
507__private_extern__ int
508__utmpxname(struct _utmpx *U, const char *fname)
509{
510 size_t len;
511
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 }
520
521 len = strlen(fname);
522
523 if (len >= MAXPATHLEN)
524 return 0;
525
526 /* must end in x! */
527 if (fname[len - 1] != 'x')
528 return 0;
529
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);
538 return 1;
539}
540
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{
556 return _utmpxname(__default_utx(), fname);
557}
558
559#ifdef UNIFDEF_LEGACY_UTMP_APIS
560void
561getutmp(const struct utmpx *ux, struct utmp *u)
562{
563
564 bzero(u, sizeof(*u));
565 (void)memcpy(u->ut_name, ux->ut_user, sizeof(u->ut_name));
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
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;
578 (void)memcpy(ux->ut_line, u->ut_line, sizeof(u->ut_line));
579 ux->ut_line[sizeof(u->ut_line)] = 0;
580 (void)memcpy(ux->ut_host, u->ut_host, sizeof(u->ut_host));
581 ux->ut_host[sizeof(u->ut_host)] = 0;
582 ux->ut_tv.tv_sec = u->ut_time;
583 ux->ut_tv.tv_usec = 0;
584 ux->ut_pid = getpid();
585 ux->ut_type = USER_PROCESS;
586}
587#endif /* UNIFDEF_LEGACY_UTMP_APIS */