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 /* This is the default struct _utmpx shared by the POSIX APIs */
61 struct _utmpx __utx__
= {
62 __UTX_MAGIC__
, /* magic */
64 PTHREAD_MUTEX_INITIALIZER
, /* utmpx_mutex */
65 _PATH_UTMPX
, /* utfile */
67 1, /* utfile_system */
71 static struct utmpx
*__getutxid(struct _utmpx
*, const struct utmpx
*);
73 __private_extern__
const char _utmpx_vers
[] = "utmpx-1.00";
75 __private_extern__
void
76 __setutxent(struct _utmpx
*U
)
79 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
83 (void)fseeko(U
->fp
, (off_t
)sizeof(struct utmpx32
), SEEK_SET
);
85 (void)fseeko(U
->fp
, (off_t
)sizeof(U
->ut
), SEEK_SET
);
90 _setutxent(struct _utmpx
*U
)
93 TEST_UTMPX_T("_setutxent", U
);
103 _setutxent(&__utx__
);
107 __private_extern__
void
108 __endutxent(struct _utmpx
*U
)
110 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
112 int saveerrno
= errno
;
122 _endutxent(struct _utmpx
*U
)
124 TEST_UTMPX_T("_endutxent", U
);
134 _endutxent(&__utx__
);
138 __private_extern__
struct utmpx
*
139 __getutxent(struct _utmpx
*U
)
144 #endif /* __LP64__ */
149 if ((U
->fp
= fopen(U
->utfile
, "r+")) == NULL
)
150 if ((U
->fp
= fopen(U
->utfile
, "w+")) == NULL
) {
151 if ((U
->fp
= fopen(U
->utfile
, "r")) == NULL
)
157 fcntl(fileno(U
->fp
), F_SETFD
, 1); /* set close-on-exec flag */
159 /* get file size in order to check if new file */
160 if (fstat(fileno(U
->fp
), &st
) == -1)
163 if (st
.st_size
== 0) {
164 /* new file, add signature record */
166 (void)memset(&ut32
, 0, sizeof(ut32
));
167 ut32
.ut_type
= SIGNATURE
;
168 (void)memcpy(ut32
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
));
169 if (fwrite(&ut32
, sizeof(ut32
), 1, U
->fp
) != 1)
171 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
172 U
->ut
.ut_type
= SIGNATURE
;
173 (void)memcpy(U
->ut
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
));
174 if (fwrite(&U
->ut
, sizeof(U
->ut
), 1, U
->fp
) != 1)
175 #endif /* __LP64__ */
178 /* old file, read signature record */
180 if (fread(&ut32
, sizeof(ut32
), 1, U
->fp
) != 1)
182 if (fread(&U
->ut
, sizeof(U
->ut
), 1, U
->fp
) != 1)
183 #endif /* __LP64__ */
186 if (memcmp(ut32
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
)) != 0 ||
187 ut32
.ut_type
!= SIGNATURE
)
189 if (memcmp(U
->ut
.ut_user
, _utmpx_vers
, sizeof(_utmpx_vers
)) != 0 ||
190 U
->ut
.ut_type
!= SIGNATURE
)
191 #endif /* __LP64__ */
200 if (fread(&ut32
, sizeof(ut32
), 1, U
->fp
) != 1)
202 if (fread(&U
->ut
, sizeof(U
->ut
), 1, U
->fp
) != 1)
203 #endif /* __LP64__ */
207 _utmpx32_64(&ut32
, &U
->ut
);
208 #endif /* __LP64__ */
216 (void)memset(&U
->ut
, 0, sizeof(U
->ut
));
222 _getutxent(struct _utmpx
*U
)
226 TEST_UTMPX_T("_getutxent", U
);
228 ret
= __getutxent(U
);
237 return _getutxent(&__utx__
);
242 _getutxid(struct _utmpx
*U
, const struct utmpx
*utx
)
245 const struct utmpx
*ux
;
248 if (utx
->ut_type
== EMPTY
)
251 TEST_UTMPX_T("_getutxid", U
);
253 /* make a copy as needed, and auto-fill if requested */
254 ux
= _utmpx_working_copy(utx
, &temp
, 1);
260 ret
= __getutxid(U
, ux
);
267 getutxid(const struct utmpx
*utx
)
269 return _getutxid(&__utx__
, utx
);
273 static struct utmpx
*
274 __getutxid(struct _utmpx
*U
, const struct utmpx
*utx
)
278 if (U
->ut
.ut_type
== EMPTY
)
280 switch (utx
->ut_type
) {
287 if (U
->ut
.ut_type
== utx
->ut_type
)
294 switch (U
->ut
.ut_type
) {
299 if (memcmp(U
->ut
.ut_id
, utx
->ut_id
,
300 sizeof(U
->ut
.ut_id
)) == 0)
310 } while (__getutxent(U
) != NULL
);
315 static struct utmpx
*
316 __getutxline(struct _utmpx
*U
, const struct utmpx
*utx
)
319 switch (U
->ut
.ut_type
) {
324 if (strncmp(U
->ut
.ut_line
, utx
->ut_line
,
325 sizeof(U
->ut
.ut_line
)) == 0)
331 } while (__getutxent(U
) != NULL
);
337 _getutxline(struct _utmpx
*U
, const struct utmpx
*utx
)
341 TEST_UTMPX_T("_getutxline", U
);
343 ret
= __getutxline(U
, utx
);
350 getutxline(const struct utmpx
*utx
)
352 return _getutxline(&__utx__
, utx
);
357 _pututxline(struct _utmpx
*U
, const struct utmpx
*utx
)
366 TEST_UTMPX_T("_pututxline", U
);
368 if ((ux
= __pututxline(&__utx__
, utx
)) != NULL
&& __utx__
.utfile_system
) {
369 _utmpx_asl(ux
); /* the equivalent of wtmpx and lastlogx */
371 _write_utmp_compat(ux
);
372 #endif /* UTMP_COMPAT */
380 pututxline(const struct utmpx
*utx
)
382 return _pututxline(&__utx__
, utx
);
385 __private_extern__
struct utmpx
*
386 __pututxline(struct _utmpx
*U
, const struct utmpx
*utx
)
388 struct utmpx temp
, *u
= NULL
, *x
;
389 const struct utmpx
*ux
;
392 #endif /* __LP64__ */
394 #define gotlock (fl.l_start >= 0)
396 fl
.l_start
= -1; /* also means we haven't locked */
397 if (U
->utfile_system
)
398 if ((U
->fp
!= NULL
&& U
->readonly
) || (U
->fp
== NULL
&& geteuid() != 0)) {
404 (void)__getutxent(U
);
405 if (U
->fp
== NULL
|| U
->readonly
) {
411 /* make a copy as needed, and auto-fill if requested */
412 ux
= _utmpx_working_copy(utx
, &temp
, 0);
416 if ((x
= __getutxid(U
, ux
)) == NULL
) {
418 if ((x
= __getutxid(U
, ux
)) == NULL
) {
420 * utx->ut_type has any original mask bits, while
421 * ux->ut_type has those mask bits removed. If we
422 * are trying to record a dead process, and
423 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, then since
424 * there is no matching entry, we return NULL.
426 if (ux
->ut_type
== DEAD_PROCESS
&&
427 (utx
->ut_type
& UTMPX_DEAD_IF_CORRESPONDING_MASK
)) {
432 * Replace lockf() with fcntl() and a fixed start
433 * value. We should already be at EOF.
435 if ((fl
.l_start
= lseek(fileno(U
->fp
), 0, SEEK_CUR
)) < 0)
438 fl
.l_whence
= SEEK_SET
;
440 if (fcntl(fileno(U
->fp
), F_SETLKW
, &fl
) == -1)
442 if (fseeko(U
->fp
, (off_t
)0, SEEK_END
) == -1)
449 * utx->ut_type has any original mask bits, while
450 * ux->ut_type has those mask bits removed. If we
451 * are trying to record a dead process, if
452 * UTMPX_DEAD_IF_CORRESPONDING_MASK is set, but the found
453 * entry is not a (matching) USER_PROCESS, then return NULL.
455 if (ux
->ut_type
== DEAD_PROCESS
&&
456 (utx
->ut_type
& UTMPX_DEAD_IF_CORRESPONDING_MASK
) &&
457 x
->ut_type
!= USER_PROCESS
) {
461 /* we are not appending */
463 if (fseeko(U
->fp
, -(off_t
)sizeof(ut32
), SEEK_CUR
) == -1)
465 if (fseeko(U
->fp
, -(off_t
)sizeof(U
->ut
), SEEK_CUR
) == -1)
466 #endif /* __LP64__ */
471 _utmpx64_32(ux
, &ut32
);
472 if (fwrite(&ut32
, sizeof (ut32
), 1, U
->fp
) != 1)
474 if (fwrite(ux
, sizeof (*ux
), 1, U
->fp
) != 1)
475 #endif /* __LP64__ */
478 if (fflush(U
->fp
) == -1)
481 u
= memcpy(&U
->ut
, ux
, sizeof(U
->ut
));
482 notify_post(UTMPX_CHANGE_NOTIFICATION
);
487 if (fcntl(fileno(U
->fp
), F_SETLK
, &fl
) == -1)
496 * The following are extensions and not part of the X/Open spec.
498 __private_extern__
int
499 __utmpxname(struct _utmpx
*U
, const char *fname
)
504 if(!U
->utfile_system
)
506 U
->utfile
= _PATH_UTMPX
;
507 U
->utfile_system
= 1;
514 if (len
>= MAXPATHLEN
)
518 if (fname
[len
- 1] != 'x')
521 if (U
->utfile_system
)
523 U
->utfile_system
= 0;
524 if ((U
->utfile
= reallocf(U
->utfile
, len
+ 1)) == NULL
)
527 (void)strcpy(U
->utfile
, fname
);
533 _utmpxname(struct _utmpx
*U
, const char *fname
)
537 TEST_UTMPX_T("_utmpxname", U
);
539 ret
= __utmpxname(U
, fname
);
545 utmpxname(const char *fname
)
547 return _utmpxname(&__utx__
, fname
);
550 #ifdef UNIFDEF_LEGACY_UTMP_APIS
552 getutmp(const struct utmpx
*ux
, struct utmp
*u
)
555 bzero(u
, sizeof(*u
));
556 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
557 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
558 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
559 u
->ut_time
= ux
->ut_tv
.tv_sec
;
563 getutmpx(const struct utmp
*u
, struct utmpx
*ux
)
566 bzero(ux
, sizeof(*ux
));
567 (void)memcpy(ux
->ut_user
, u
->ut_name
, sizeof(u
->ut_name
));
568 ux
->ut_user
[sizeof(u
->ut_name
)] = 0;
569 (void)memcpy(ux
->ut_line
, u
->ut_line
, sizeof(u
->ut_line
));
570 ux
->ut_line
[sizeof(u
->ut_line
)] = 0;
571 (void)memcpy(ux
->ut_host
, u
->ut_host
, sizeof(u
->ut_host
));
572 ux
->ut_host
[sizeof(u
->ut_host
)] = 0;
573 ux
->ut_tv
.tv_sec
= u
->ut_time
;
574 ux
->ut_tv
.tv_usec
= 0;
575 ux
->ut_pid
= getpid();
576 ux
->ut_type
= USER_PROCESS
;
578 #endif /* UNIFDEF_LEGACY_UTMP_APIS */