1 /* $NetBSD: utmpx.c,v 1.25 2008/04/28 20:22:59 martin Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
31 #include <sys/cdefs.h>
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 */
37 #include "namespace.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
50 #ifdef UNIFDEF_LEGACY_UTMP_APIS
52 #endif /* UNIFDEF_LEGACY_UTMP_APIS */
54 #include <utmpx-darwin.h>
59 static struct _utmpx
*__utx__
= NULL
;
62 __default_utx_init(void)
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;
75 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
76 pthread_once(&once
, &__default_utx_init
);
80 static struct utmpx
*__getutxid(struct _utmpx
*, const struct utmpx
*);
82 __private_extern__
const char _utmpx_vers
[] = "utmpx-1.00";
84 __private_extern__
void
85 __setutxent(struct _utmpx
*U
)
88 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
92 (void)fseeko(U
->fp
, (off_t
)sizeof(struct utmpx32
), SEEK_SET
);
94 (void)fseeko(U
->fp
, (off_t
)sizeof(U
->ut
), SEEK_SET
);
99 _setutxent(struct _utmpx
*U
)
102 TEST_UTMPX_T("_setutxent", U
);
112 _setutxent(__default_utx());
116 __private_extern__
void
117 __endutxent(struct _utmpx
*U
)
119 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
121 int saveerrno
= errno
;
131 _endutxent(struct _utmpx
*U
)
133 TEST_UTMPX_T("_endutxent", U
);
143 _endutxent(__default_utx());
147 __private_extern__
struct utmpx
*
148 __getutxent(struct _utmpx
*U
)
153 #endif /* __LP64__ */
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
)
166 fcntl(fileno(U
->fp
), F_SETFD
, 1); /* set close-on-exec flag */
168 /* get file size in order to check if new file */
169 if (fstat(fileno(U
->fp
), &st
) == -1)
172 if (st
.st_size
== 0) {
173 /* new file, add signature record */
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)
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__ */
187 /* old file, read signature record */
189 if (fread(&ut32
, sizeof(ut32
), 1, U
->fp
) != 1)
191 if (fread(&U
->ut
, sizeof(U
->ut
), 1, U
->fp
) != 1)
192 #endif /* __LP64__ */
195 if (memcmp(ut32
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
)) != 0 ||
196 ut32
.ut_type
!= SIGNATURE
)
198 if (memcmp(U
->ut
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
)) != 0 ||
199 U
->ut
.ut_type
!= SIGNATURE
)
200 #endif /* __LP64__ */
209 if (fread(&ut32
, sizeof(ut32
), 1, U
->fp
) != 1)
211 if (fread(&U
->ut
, sizeof(U
->ut
), 1, U
->fp
) != 1)
212 #endif /* __LP64__ */
216 _utmpx32_64(&ut32
, &U
->ut
);
217 #endif /* __LP64__ */
225 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
231 _getutxent(struct _utmpx
*U
)
235 TEST_UTMPX_T("_getutxent", U
);
237 ret
= __getutxent(U
);
246 return _getutxent(__default_utx());
251 _getutxid(struct _utmpx
*U
, const struct utmpx
*utx
)
254 const struct utmpx
*ux
;
257 if (utx
->ut_type
== EMPTY
)
260 TEST_UTMPX_T("_getutxid", U
);
262 /* make a copy as needed, and auto-fill if requested */
263 ux
= _utmpx_working_copy(utx
, &temp
, 1);
269 ret
= __getutxid(U
, ux
);
276 getutxid(const struct utmpx
*utx
)
278 return _getutxid(__default_utx(), utx
);
282 static struct utmpx
*
283 __getutxid(struct _utmpx
*U
, const struct utmpx
*utx
)
287 if (U
->ut
.ut_type
== EMPTY
)
289 switch (utx
->ut_type
) {
296 if (U
->ut
.ut_type
== utx
->ut_type
)
303 switch (U
->ut
.ut_type
) {
308 if (memcmp(U
->ut
.ut_id
, utx
->ut_id
,
309 sizeof(U
->ut
.ut_id
)) == 0)
319 } while (__getutxent(U
) != NULL
);
324 static struct utmpx
*
325 __getutxline(struct _utmpx
*U
, const struct utmpx
*utx
)
328 switch (U
->ut
.ut_type
) {
333 if (strncmp(U
->ut
.ut_line
, utx
->ut_line
,
334 sizeof(U
->ut
.ut_line
)) == 0)
340 } while (__getutxent(U
) != NULL
);
346 _getutxline(struct _utmpx
*U
, const struct utmpx
*utx
)
350 TEST_UTMPX_T("_getutxline", U
);
352 ret
= __getutxline(U
, utx
);
359 getutxline(const struct utmpx
*utx
)
361 return _getutxline(__default_utx(), utx
);
366 _pututxline(struct _utmpx
*U
, const struct utmpx
*utx
)
375 TEST_UTMPX_T("_pututxline", U
);
377 if ((ux
= __pututxline(__default_utx(), utx
)) != NULL
&& __default_utx()->utfile_system
) {
378 _utmpx_asl(ux
); /* the equivalent of wtmpx and lastlogx */
380 _write_utmp_compat(ux
);
381 #endif /* UTMP_COMPAT */
389 pututxline(const struct utmpx
*utx
)
391 return _pututxline(__default_utx(), utx
);
394 __private_extern__
struct utmpx
*
395 __pututxline(struct _utmpx
*U
, const struct utmpx
*utx
)
397 struct utmpx temp
, *u
= NULL
, *x
;
398 const struct utmpx
*ux
;
401 #endif /* __LP64__ */
403 #define gotlock (fl.l_start >= 0)
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)) {
413 (void)__getutxent(U
);
414 if (U
->fp
== NULL
|| U
->readonly
) {
420 /* make a copy as needed, and auto-fill if requested */
421 ux
= _utmpx_working_copy(utx
, &temp
, 0);
425 if ((x
= __getutxid(U
, ux
)) == NULL
) {
427 if ((x
= __getutxid(U
, ux
)) == NULL
) {
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.
435 if (ux
->ut_type
== DEAD_PROCESS
&&
436 (utx
->ut_type
& UTMPX_DEAD_IF_CORRESPONDING_MASK
)) {
441 * Replace lockf() with fcntl() and a fixed start
442 * value. We should already be at EOF.
444 if ((fl
.l_start
= lseek(fileno(U
->fp
), 0, SEEK_CUR
)) < 0)
447 fl
.l_whence
= SEEK_SET
;
449 if (fcntl(fileno(U
->fp
), F_SETLKW
, &fl
) == -1)
451 if (fseeko(U
->fp
, (off_t
)0, SEEK_END
) == -1)
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.
464 if (ux
->ut_type
== DEAD_PROCESS
&&
465 (utx
->ut_type
& UTMPX_DEAD_IF_CORRESPONDING_MASK
) &&
466 x
->ut_type
!= USER_PROCESS
) {
470 /* we are not appending */
472 if (fseeko(U
->fp
, -(off_t
)sizeof(ut32
), SEEK_CUR
) == -1)
474 if (fseeko(U
->fp
, -(off_t
)sizeof(U
->ut
), SEEK_CUR
) == -1)
475 #endif /* __LP64__ */
480 _utmpx64_32(ux
, &ut32
);
481 if (fwrite(&ut32
, sizeof (ut32
), 1, U
->fp
) != 1)
483 if (fwrite(ux
, sizeof (*ux
), 1, U
->fp
) != 1)
484 #endif /* __LP64__ */
487 if (fflush(U
->fp
) == -1)
490 u
= memcpy(&U
->ut
, ux
, sizeof(U
->ut
));
491 notify_post(UTMPX_CHANGE_NOTIFICATION
);
496 if (fcntl(fileno(U
->fp
), F_SETLK
, &fl
) == -1)
505 * The following are extensions and not part of the X/Open spec.
507 __private_extern__
int
508 __utmpxname(struct _utmpx
*U
, const char *fname
)
513 if(!U
->utfile_system
)
515 U
->utfile
= _PATH_UTMPX
;
516 U
->utfile_system
= 1;
523 if (len
>= MAXPATHLEN
)
527 if (fname
[len
- 1] != 'x')
530 if (U
->utfile_system
)
532 U
->utfile_system
= 0;
533 if ((U
->utfile
= reallocf(U
->utfile
, len
+ 1)) == NULL
)
536 (void)strcpy(U
->utfile
, fname
);
542 _utmpxname(struct _utmpx
*U
, const char *fname
)
546 TEST_UTMPX_T("_utmpxname", U
);
548 ret
= __utmpxname(U
, fname
);
554 utmpxname(const char *fname
)
556 return _utmpxname(__default_utx(), fname
);
559 #ifdef UNIFDEF_LEGACY_UTMP_APIS
561 getutmp(const struct utmpx
*ux
, struct utmp
*u
)
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
;
572 getutmpx(const struct utmp
*u
, struct utmpx
*ux
)
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
;
587 #endif /* UNIFDEF_LEGACY_UTMP_APIS */