2 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
24 #include <sys/cdefs.h>
25 #include <sys/types.h>
26 #include <sys/param.h>
39 #endif /* UTMP_COMPAT */
41 #include <utmpx-darwin.h>
42 #include <utmpx_thread.h>
47 #include <mach/mach.h>
48 #include <mach/std_types.h>
50 #include <mach/mach_types.h>
51 #include <servers/bootstrap.h>
56 #endif /* UTMP_COMPAT */
58 #if ASL_API_VERSION < 20131108
59 #include <asl_private.h>
60 #include <asl_store.h>
63 __private_extern__
const char __utx_magic__
[UTMPX_MAGIC
] = __UTX_MAGIC__
;
65 extern const char _utmpx_vers
[]; /* in utmpx.c */
67 #if ASL_API_VERSION < 20131108
68 static void msg2lastlogx(const aslmsg
, struct lastlogx
*);
69 static void msg2utmpx(const aslmsg
, struct utmpx
*);
70 static void utmpx2msg(const struct utmpx
*, aslmsg
);
72 static void msg2lastlogx(asl_object_t
, struct lastlogx
*);
73 static void msg2utmpx(asl_object_t
, struct utmpx
*);
74 static void utmpx2msg(const struct utmpx
*, asl_object_t
);
77 static size_t pw_size
= 0;
79 #define FACILITY "Facility"
82 /* ASL timeout in microseconds */
83 #define ASL_QUERY_TIMEOUT 4000000
85 /* indirection causes argument to be substituted before stringification */
86 #define STR(x) __STRING(x)
90 _pwnam_r(const char *user
, struct passwd
*pw
)
96 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
100 if ((buf
= malloc(pw_size
)) == NULL
)
103 getpwnam_r(user
, pw
, buf
, pw_size
, &p
);
113 _pwuid_r(uid_t uid
, struct passwd
*pw
)
119 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
123 if ((buf
= malloc(pw_size
)) == NULL
)
126 getpwuid_r(uid
, pw
, buf
, pw_size
, &p
);
135 getlastlogx(uid_t uid
, struct lastlogx
*lx
)
141 if ((buf
= _pwuid_r(uid
, &pw
)) == NULL
)
144 l
= getlastlogxbyname(pw
.pw_name
, lx
);
150 getlastlogxbyname(const char *user
, struct lastlogx
*lx
)
152 #if ASL_API_VERSION < 20131108
155 asl_search_result_t query
, *res
;
157 asl_store_t
*store
= NULL
;
160 asl_object_t m
, query
, res
;
163 struct lastlogx
*result
= NULL
;
165 if (!user
|| !*user
) return NULL
;
167 #if ASL_API_VERSION < 20131108
168 status
= asl_store_open_read(NULL
, &store
);
169 if (status
!= 0) return NULL
;
170 if (store
== NULL
) return NULL
;
174 * We search for the last LASTLOG_FACILITY entry that has the
175 * ut_user entry matching the user's name.
177 m
= asl_new(ASL_TYPE_QUERY
);
180 #if ASL_API_VERSION < 20131108
181 asl_store_close(store
);
186 asl_set_query(m
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
187 asl_set_query(m
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
189 #if ASL_API_VERSION < 20131108
190 qm
[0] = (asl_msg_t
*)m
;
194 query
= asl_new(ASL_TYPE_LIST
);
201 asl_append(query
, m
);
208 #if ASL_API_VERSION < 20131108
209 asl_store_match_timeout(store
, &query
, &res
, &cmax
, -1, 1, -1, ASL_QUERY_TIMEOUT
);
210 asl_store_close(store
);
213 res
= asl_match(NULL
, query
, &cmax
, -1, 1, ASL_QUERY_TIMEOUT
, ASL_MATCH_DIRECTION_REVERSE
);
217 if (res
== NULL
) return NULL
;
219 #if ASL_API_VERSION < 20131108
220 m
= aslresponse_next(res
);
227 #if ASL_API_VERSION < 20131108
228 aslresponse_free(res
);
237 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
)
239 #if ASL_API_VERSION < 20131108
240 aslresponse_free(res
);
249 #if ASL_API_VERSION < 20131108
250 aslresponse_free(res
);
259 #define IGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
260 u->p##_##e = strtol(cp, NULL, 10);
261 #define LGET(e,p) IGET(e,p)
262 #define SGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
263 strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
265 /* fill in a struct lastlogx from an ASL message */
267 #if ASL_API_VERSION < 20131108
268 msg2lastlogx(const aslmsg m
, struct lastlogx
*u
)
270 msg2lastlogx(asl_object_t m
, struct lastlogx
*u
)
275 bzero(u
, sizeof(*u
));
278 IGET(tv
.tv_usec
, ll
);
282 /* fill in a struct utmpx from an ASL message */
284 #if ASL_API_VERSION < 20131108
285 msg2utmpx(aslmsg m
, struct utmpx
*u
)
287 msg2utmpx(asl_object_t m
, struct utmpx
*u
)
292 bzero(u
, sizeof(*u
));
299 IGET(tv
.tv_usec
, ut
);
303 /* fill in an ASL message from a struct utmpx */
305 #if ASL_API_VERSION < 20131108
306 utmpx2msg(const struct utmpx
*u
, aslmsg m
)
308 utmpx2msg(const struct utmpx
*u
, asl_object_t m
)
311 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
313 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
314 asl_set(m, #e, buf); }
315 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
316 asl_set(m, #e, buf); }
317 #define SSET(e) if (*(u->e)) { \
318 strncpy(buf, u->e, sizeof(u->e)); \
319 buf[sizeof(u->e)] = 0; \
320 asl_set(m, #e, buf); \
324 cp
= (char *)u
->ut_id
+ sizeof(u
->ut_id
);
325 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
329 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
330 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
331 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
332 asl_set(m
, "ut_id", buf
);
343 static const char *utmpx_types
[] = {
349 "INIT_PROCESS", /* 5 */
350 "LOGIN_PROCESS", /* 6 */
351 "USER_PROCESS", /* 7 */
352 "DEAD_PROCESS", /* 8 */
353 "ACCOUNTING", /* 9 */
354 "SIGNATURE", /* 10 */
355 "SHUTDOWN_TIME", /* 11 */
358 /* send a struct utmpx record using ASL */
359 __private_extern__
void
360 _utmpx_asl(const struct utmpx
*u
)
362 #if ASL_API_VERSION < 20131108
363 aslclient asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); /* could be NULL, but still works */
366 asl_object_t asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
371 if (u
->ut_type
== EMPTY
)
373 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
374 #if ASL_API_VERSION < 20131108
382 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
383 * otherwise we use the UTMPX_FACILITY. This makes it easy to
384 * search for lastlog entries, but for wtmp, we have to search
385 * for both facilities.
387 if (u
->ut_type
== USER_PROCESS
)
388 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
390 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
391 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
394 /* Make a visible message for system.log */
395 switch (u
->ut_type
) {
400 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
404 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
408 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
411 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
412 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
414 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
417 asl_set(m
, ASL_KEY_MSG
, msg
);
419 #if ASL_API_VERSION < 20131108
428 #define UT_USER (1 << 0)
429 #define UT_ID (1 << 1)
430 #define UT_LINE (1 << 2)
431 #define UT_PID (1 << 3)
432 #define UT_TV (1 << 4)
434 __private_extern__
const struct utmpx
*
435 _utmpx_working_copy(const struct utmpx
*utx
, struct utmpx
*temp
, int onlyid
)
438 static char idzero
[_UTX_IDSIZE
];
440 if ((utx
->ut_type
& (UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
)) == 0)
442 memcpy(temp
, utx
, sizeof(*temp
));
443 temp
->ut_type
&= ~(UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
);
445 if ((utx
->ut_type
& UTMPX_AUTOFILL_MASK
) == 0)
448 which
= UT_TV
; /* they all need time */
449 switch(temp
->ut_type
) {
453 which
|= (UT_USER
| UT_LINE
| UT_PID
);
454 /* Set UT_ID if ut_id isn't there */
455 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
462 which
|= (UT_USER
| UT_PID
);
466 /* Set UT_ID if ut_id isn't there. We will also need UT_LINE */
467 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
468 which
|= (UT_ID
| UT_LINE
);
472 * If onlyid is set: if ut_id isn't set but is needed, then set
473 * which to (UT_LINE | UT_ID), otherwise zero
476 which
= (which
& UT_ID
) ? (UT_LINE
| UT_ID
) : 0;
477 if ((which
& UT_LINE
) && !*temp
->ut_line
) {
483 err
= ttyname_r(0, buf
, sizeof(buf
));
485 err
= ttyname_r(1, buf
, sizeof(buf
));
487 err
= ttyname_r(2, buf
, sizeof(buf
));
490 #else /* !__DARWIN_UNIX03 */
491 cp
= ttyname_r(0, buf
, sizeof(buf
));
493 cp
= ttyname_r(1, buf
, sizeof(buf
));
495 cp
= ttyname_r(2, buf
, sizeof(buf
));
498 #endif /* __DARWIN_UNIX03 */
499 cp
= strrchr(buf
, '/');
504 strncpy(temp
->ut_line
, cp
, sizeof(temp
->ut_line
));
506 /* UT_ID is set only if we already know we need to add it */
507 if ((which
& UT_ID
)) {
509 int i
= sizeof(temp
->ut_line
);
511 for(cp
= temp
->ut_line
; i
> 0 && *cp
; i
--)
513 i
= cp
- temp
->ut_line
;
514 if(i
>= sizeof(temp
->ut_id
))
515 memcpy(temp
->ut_id
, cp
- sizeof(temp
->ut_id
), sizeof(temp
->ut_id
));
517 memcpy(temp
->ut_id
, temp
->ut_line
, i
);
519 if ((which
& UT_PID
) && !temp
->ut_pid
)
520 temp
->ut_pid
= getpid();
521 if ((which
& UT_USER
) && !*temp
->ut_user
) {
525 if ((buf
= _pwuid_r(getuid(), &pw
)) == NULL
)
527 strncpy(temp
->ut_user
, pw
.pw_name
, sizeof(temp
->ut_user
));
530 if ((which
& UT_TV
) && !temp
->ut_tv
.tv_sec
&& !temp
->ut_tv
.tv_usec
)
531 gettimeofday(&temp
->ut_tv
, NULL
);
536 * We can read from either asl or from a file, so we need to switch between
539 static void end_asl(void);
540 static void end_file(void);
541 static struct utmpx
*get_asl(void);
542 static struct utmpx
*get_file(void);
543 static void set_asl(int);
544 static void set_file(int);
546 enum {WTMP_ASL
, WTMP_FILE
};
551 struct utmpx
*(*get
)(void);
563 #if ASL_API_VERSION < 20131108
564 asl_search_result_t
*res
;
572 } wtmp_asl
= {-1, 1};
581 struct utmpx32
*next
;
585 #endif /* __LP64__ */
587 } wtmp_file
= {-1, -1};
598 return wtmp_func
.get();
602 setutxent_wtmp(int dir
)
607 /* use the given file, or if NULL, read from asl */
609 wtmpxname(const char *fname
)
614 if (wtmp_func
.which
== WTMP_ASL
) {
619 wtmp_func
.which
= WTMP_ASL
;
620 wtmp_func
.end
= end_asl
;
621 wtmp_func
.get
= get_asl
;
622 wtmp_func
.set
= set_asl
;
627 if (len
>= MAXPATHLEN
)
631 if (fname
[len
- 1] != 'x')
634 if (wtmp_func
.which
== WTMP_ASL
)
636 else if (wtmp_file
.fd
>= 0) {
642 free(wtmp_file
.file
);
644 wtmp_file
.file
= strdup(fname
);
645 if (wtmp_file
.file
== NULL
)
648 wtmp_func
.which
= WTMP_FILE
;
649 wtmp_func
.end
= end_file
;
650 wtmp_func
.get
= get_file
;
651 wtmp_func
.set
= set_file
;
658 if (wtmp_asl
.res
!= NULL
)
660 #if ASL_API_VERSION < 20131108
661 aslresponse_free(wtmp_asl
.res
);
663 asl_release(wtmp_asl
.res
);
675 if (wtmp_file
.fd
>= 0) {
681 wtmp_file
.buf
= NULL
;
685 static struct utmpx
*
688 #if ASL_API_VERSION < 20131108
693 static struct utmpx utx
;
695 if (wtmp_asl
.inited
== 0) set_asl(-1);
696 if (wtmp_asl
.done
!= 0) return NULL
;
698 #if ASL_API_VERSION < 20131108
699 m
= aslresponse_next(wtmp_asl
.res
);
701 m
= asl_next(wtmp_asl
.res
);
705 #if ASL_API_VERSION < 20131108
706 aslresponse_free(wtmp_asl
.res
);
708 asl_release(wtmp_asl
.res
);
720 static struct utmpx
*
726 static struct utmpx ux
;
727 #endif /* __LP64__ */
730 if (wtmp_file
.left
> 0) {
732 struct utmpx32
*u
= wtmp_file
.next
;
734 struct utmpx
*u
= wtmp_file
.next
;
735 #endif /* __LP64__ */
736 wtmp_file
.next
+= wtmp_file
.dir
;
743 #endif /* __LP64__ */
744 } else if (wtmp_file
.fd
< 0) {
745 set_file(-1); /* keep current read direction */
746 if (wtmp_file
.fd
< 0)
748 goto get_file_repeat
;
750 if (wtmp_file
.count
<= 0)
754 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
756 n
= WTMP_COUNT
* sizeof(struct utmpx
);
757 #endif /* __LP64__ */
758 if (wtmp_file
.dir
> 0)
759 wtmp_file
.next
= wtmp_file
.buf
;
761 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
763 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
770 cp
= (char *)wtmp_file
.buf
;
772 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
773 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
778 } while((n
-= r
) > 0);
780 wtmp_file
.left
= WTMP_COUNT
;
781 wtmp_file
.count
-= WTMP_COUNT
;
783 goto get_file_repeat
;
787 * This sets the directions for both asl and reading from a file. If forward
791 _set_dir(int forward
)
793 if (forward
< 0) return;
814 #if ASL_API_VERSION < 20131108
817 asl_search_result_t query
;
818 asl_store_t
*store
= NULL
;
822 asl_object_t q0
, q1
, query
;
831 if (wtmp_asl
.res
!= NULL
)
833 #if ASL_API_VERSION < 20131108
834 aslresponse_free(wtmp_asl
.res
);
836 asl_release(wtmp_asl
.res
);
841 #if ASL_API_VERSION < 20131108
842 status
= asl_store_open_read(NULL
, &store
);
843 if (status
!= 0) return;
844 if (store
== NULL
) return;
848 * Create a search query that matches either UTMPX_FACILITY
849 * or LASTLOG_FACILITY.
851 q0
= asl_new(ASL_TYPE_QUERY
);
852 if (q0
== NULL
) return;
854 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
856 q1
= asl_new(ASL_TYPE_QUERY
);
859 #if ASL_API_VERSION < 20131108
867 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
869 #if ASL_API_VERSION < 20131108
870 m
[0] = (asl_msg_t
*)q0
;
871 m
[1] = (asl_msg_t
*)q1
;
875 query
= asl_new(ASL_TYPE_LIST
);
883 asl_append(query
, q0
);
884 asl_append(query
, q1
);
892 #if ASL_API_VERSION < 20131108
893 asl_store_match_timeout(store
, &query
, &(wtmp_asl
.res
), &cmax
, wtmp_asl
.start
, 0, wtmp_asl
.dir
, ASL_QUERY_TIMEOUT
);
894 asl_store_close(store
);
898 wtmp_asl
.res
= asl_match(NULL
, query
, &cmax
, wtmp_asl
.start
, 0, ASL_QUERY_TIMEOUT
, wtmp_asl
.dir
);
902 if (wtmp_asl
.res
== NULL
) return;
909 set_file(int forward
)
918 if (wtmp_file
.buf
== NULL
&&
919 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
921 if (wtmp_file
.buf
== NULL
&&
922 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
923 #endif /* __LP64__ */
925 if (wtmp_file
.fd
>= 0)
927 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
929 if (fstat(wtmp_file
.fd
, &s
) < 0)
932 * We must have a file at least 2 sizeof(struct utmpx) in size,
933 * with the first struct utmpx matching a signature record.
936 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
938 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
939 #endif /* __LP64__ */
942 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
944 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
945 #endif /* __LP64__ */
947 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
948 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
953 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
954 * either at the beginning or the end, so that all subsequent reads
955 * must contain WTMP_COUNT records.
957 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
958 wtmp_file
.left
= wtmp_file
.count
- c
;
959 wtmp_file
.count
-= wtmp_file
.left
;
961 /* Seek to the end for reverse reading */
962 if (wtmp_file
.dir
< 0) {
964 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
966 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
967 #endif /* __LP64__ */
968 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
972 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
974 n
= wtmp_file
.left
* sizeof(struct utmpx
);
975 #endif /* __LP64__ */
976 cp
= (char *)wtmp_file
.buf
;
978 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
979 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
984 } while((n
-= r
) > 0);
986 /* Point to either the beginning or end of the buffer */
987 if(wtmp_file
.dir
> 0)
988 wtmp_file
.next
= wtmp_file
.buf
;
990 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
1002 * these routines assume natural alignment so that struct utmpx32 has
1003 * the same size and layout as the 32-bit struct utmpx
1005 __private_extern__
void
1006 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
1008 bzero(u
, sizeof(*u
));
1009 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
1010 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
1011 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
1012 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
1013 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
1014 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
1017 __private_extern__
void
1018 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
1020 bzero(u32
, sizeof(*u32
));
1021 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
1022 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
1023 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
1024 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
1025 (char *)u
+ offsetof(struct utmpx
, ut_host
),
1026 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
1028 #endif /* __LP64__ */
1032 __private_extern__
void
1033 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
1036 bzero(u
, sizeof(*u
));
1037 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
1038 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
1039 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
1040 u
->ut_time
= ux
->ut_tv
.tv_sec
;
1042 #endif /* __LP64__ */
1045 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
1046 * described in utmp(5). It then returns a value that specifies what
1047 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
1048 * write utmp only if a matching record with the same ut_line value is found;
1049 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
1051 __private_extern__
int
1053 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
1054 #else /* __LP64__ */
1055 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
1056 #endif /* __LP64__ */
1060 #else /* __LP64__ */
1062 #endif /* __LP64__ */
1064 switch (ux
->ut_type
) {
1067 bzero(u
->ut_line
, sizeof(u
->ut_line
));
1068 u
->ut_line
[0] = '~';
1069 bzero(u
->ut_name
, sizeof(u
->ut_name
));
1070 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
1071 return UTMP_COMPAT_WTMP
;
1074 bzero(u
->ut_line
, sizeof(u
->ut_line
));
1075 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
1076 bzero(u
->ut_name
, sizeof(u
->ut_name
));
1077 strcpy(u
->ut_name
, "date");
1078 return UTMP_COMPAT_WTMP
;
1080 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
1082 bzero(u
->ut_name
, sizeof(u
->ut_name
));
1083 bzero(u
->ut_host
, sizeof(u
->ut_host
));
1084 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
1086 return 0; /* skip */;
1090 * Write _PATH_LASTLOG given a struct utmp record. We use
1091 * advisory record locking.
1093 __private_extern__
void
1095 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
1096 #else /* __LP64__ */
1097 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
1098 #endif /* __LP64__ */
1103 #else /* __LP64__ */
1105 #endif /* __LP64__ */
1108 // sizeof(ux->ut_user) > sizeof(u->ut_name)
1109 char name
[sizeof(ux
->ut_user
) + 1];
1117 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
1118 name
[sizeof(ux
->ut_user
)] = 0;
1122 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
1123 name
[sizeof(u
->ut_name
)] = 0;
1125 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
1128 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
1129 #else /* __LP64__ */
1130 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
1131 #endif /* __LP64__ */
1134 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
1136 (void)lseek(fd
, off
, SEEK_SET
);
1137 bzero(&lock
, sizeof(lock
));
1138 lock
.l_type
= F_WRLCK
;
1139 lock
.l_whence
= SEEK_SET
;
1142 lock
.l_len
= sizeof(struct lastlog32
);
1143 #else /* __LP64__ */
1144 lock
.l_len
= sizeof(struct lastlog
);
1145 #endif /* __LP64__ */
1146 /* try to lock, but give up after retry times, and write anyways */
1147 while(retry
-- > 0) {
1148 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1152 l
.ll_time
= u
->ut_time
;
1153 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1154 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1155 (void) write(fd
, &l
, sizeof(l
));
1156 lock
.l_type
= F_UNLCK
;
1157 (void) fcntl(fd
, F_SETLK
, &lock
);
1162 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1165 __private_extern__
void
1167 _write_utmp(const struct utmp32
*u
, int mustexist
)
1168 #else /* __LP64__ */
1169 _write_utmp(const struct utmp
*u
, int mustexist
)
1170 #endif /* __LP64__ */
1173 struct ttyent
*ttyp
;
1176 #else /* __LP64__ */
1178 #endif /* __LP64__ */
1181 char line
[sizeof(u
->ut_line
)];
1185 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1188 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1192 /* do equivalent of ttyslot(), but using u->ut_line */
1197 if ((ttyp
= getttyent()) == NULL
)
1199 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1200 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1210 if (!found
) { /* no assigned slot */
1212 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1213 #else /* __LP64__ */
1214 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1215 #endif /* __LP64__ */
1217 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1219 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1220 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1229 if (!found
&& mustexist
) {
1234 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1235 (void)write(fd
, u
, sizeof(struct utmp32
));
1236 #else /* __LP64__ */
1237 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1238 (void)write(fd
, u
, sizeof(struct utmp
));
1239 #endif /* __LP64__ */
1244 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1245 * given struct utmpx.
1247 __private_extern__
void
1248 _write_utmp_compat(const struct utmpx
*ux
)
1252 #else /* __LP64__ */
1254 #endif /* __LP64__ */
1257 which
= _utmp_compat(ux
, &u
);
1258 if (which
& UTMP_COMPAT_UTMP0
)
1260 else if (which
& UTMP_COMPAT_UTMP1
)
1262 if (which
& UTMP_COMPAT_WTMP
)
1264 if (which
& UTMP_COMPAT_LASTLOG
)
1265 _write_lastlog(&u
, ux
);
1268 /* Append a struct wtmp to _PATH_WTMP */
1269 __private_extern__
void
1271 _write_wtmp(const struct utmp32
*u
)
1272 #else /* __LP64__ */
1273 _write_wtmp(const struct utmp
*u
)
1274 #endif /* __LP64__ */
1279 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1281 if (fstat(fd
, &buf
) == 0) {
1282 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1283 (void) ftruncate(fd
, buf
.st_size
);
1287 #endif /* UTMP_COMPAT */
1293 _openutx(const char *name
)
1297 if ((U
= calloc(1, sizeof(struct _utmpx
))) == NULL
)
1299 memcpy(U
->magic
, __utx_magic__
, UTMPX_MAGIC
);
1300 U
->utmpx_mutex
= (pthread_mutex_t
)PTHREAD_MUTEX_INITIALIZER
;
1301 if (__utmpxname(U
, name
) == 0) {
1302 if (!U
->utfile_system
)
1312 _closeutx(utmpx_t u
)
1314 struct _utmpx
*U
= (struct _utmpx
*)u
;
1316 if (!U
|| memcmp(U
->magic
, __utx_magic__
, UTMPX_MAGIC
) != 0) {
1322 if (!U
->utfile_system
)