2 * Copyright (c) 2005 Apple Computer, 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 #include <utmpx-darwin.h>
41 #include <asl_private.h>
45 #include <mach/mach.h>
46 #include <mach/std_types.h>
48 #include <mach/mach_types.h>
49 #include <servers/bootstrap.h>
55 #endif /* UTMP_COMPAT */
57 extern const char _utmpx_vers
[]; /* in utmpx.c */
58 extern char *asl_list_to_string(asl_search_result_t
*, uint32_t *);
59 extern asl_search_result_t
*asl_list_from_string(const char *);
61 static void msg2lastlogx(const aslmsg
, struct lastlogx
*);
62 static void msg2utmpx(const aslmsg
, struct utmpx
*);
63 static void utmpx2msg(const struct utmpx
*, aslmsg
);
65 static mach_port_t asl_server_port
= MACH_PORT_NULL
;
66 static int pw_size
= 0;
68 #define ASL_SERVICE_NAME "com.apple.system.logger"
69 #define FACILITY "Facility"
72 /* ASL timeout in milliseconds */
73 #define ASL_QUERY_TIMEOUT 4000
75 /* indirection causes argument to be substituted before stringification */
76 #define STR(x) __STRING(x)
79 _pwnam_r(const char *user
, struct passwd
*pw
)
85 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
89 if ((buf
= malloc(pw_size
)) == NULL
)
92 getpwnam_r(user
, pw
, buf
, pw_size
, &p
);
101 _pwuid_r(uid_t uid
, struct passwd
*pw
)
107 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
111 if ((buf
= malloc(pw_size
)) == NULL
)
114 getpwuid_r(uid
, pw
, buf
, pw_size
, &p
);
123 getlastlogx(uid_t uid
, struct lastlogx
*lx
)
129 if ((buf
= _pwuid_r(uid
, &pw
)) == NULL
)
132 l
= getlastlogxbyname(pw
.pw_name
, lx
);
138 getlastlogxbyname(const char *user
, struct lastlogx
*lx
)
142 asl_search_result_t s
, *l
;
144 uint32_t len
, reslen
, status
;
146 security_token_t sec
;
148 struct lastlogx
*result
= NULL
;
154 if (bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &port
) != KERN_SUCCESS
)
158 * We search for the last LASTLOG_FACILITY entry that has the
159 * ut_user entry matching the user's name.
161 if ((q
= asl_new(ASL_TYPE_QUERY
)) == NULL
)
163 asl_set_query(q
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
164 asl_set_query(q
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
170 qstr
= asl_list_to_string(&s
, &len
);
176 /* the server frees this memory */
177 if (vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, len
, TRUE
) != KERN_SUCCESS
) {
192 _asl_server_query_timeout(port
, vmstr
, len
, -1, 1, 1, ASL_QUERY_TIMEOUT
, (caddr_t
*)&res
, &reslen
, &cmax
, (int *)&status
, &sec
);
196 l
= asl_list_from_string(res
);
197 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
198 q
= aslresponse_next(l
);
205 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
) {
214 mach_port_deallocate(mach_task_self(), port
);
218 #define IGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
219 u->p##_##e = strtol(cp, NULL, 10);
220 #define LGET(e,p) IGET(e,p)
221 #define SGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
222 strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
224 /* fill in a struct lastlogx from a aslmsg */
226 msg2lastlogx(const aslmsg m
, struct lastlogx
*u
)
230 bzero(u
, sizeof(*u
));
233 IGET(tv
.tv_usec
, ll
);
237 /* fill in a struct utmpx from a aslmsg */
239 msg2utmpx(const aslmsg m
, struct utmpx
*u
)
243 bzero(u
, sizeof(*u
));
250 IGET(tv
.tv_usec
, ut
);
254 /* fill in a aslmsg from a struct utmpx */
256 utmpx2msg(const struct utmpx
*u
, aslmsg m
)
258 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
260 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
261 asl_set(m, #e, buf); }
262 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
263 asl_set(m, #e, buf); }
264 #define SSET(e) if (*(u->e)) { \
265 strncpy(buf, u->e, sizeof(u->e)); \
266 buf[sizeof(u->e)] = 0; \
267 asl_set(m, #e, buf); \
271 cp
= u
->ut_id
+ sizeof(u
->ut_id
);
272 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
276 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
277 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
278 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
279 asl_set(m
, "ut_id", buf
);
290 static const char *utmpx_types
[] = {
296 "INIT_PROCESS", /* 5 */
297 "LOGIN_PROCESS", /* 6 */
298 "USER_PROCESS", /* 7 */
299 "DEAD_PROCESS", /* 8 */
300 "ACCOUNTING", /* 9 */
301 "SIGNATURE", /* 10 */
302 "SHUTDOWN_TIME", /* 11 */
305 /* send a struct utmpx record using asl */
306 __private_extern__
void
307 _utmpx_asl(const struct utmpx
*u
)
309 aslclient asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); /* could be NULL, but still works */
313 if (u
->ut_type
== EMPTY
)
315 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
320 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
321 * otherwise we use the UTMPX_FACILITY. This makes it easy to
322 * search for lastlog entries, but for wtmp, we have to search
323 * for both facilities.
325 if (u
->ut_type
== USER_PROCESS
)
326 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
328 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
329 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
332 /* Make a visible message for system.log */
333 switch (u
->ut_type
) {
338 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
342 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
346 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
349 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
350 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
352 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
355 asl_set(m
, ASL_KEY_MSG
, msg
);
362 #define UT_USER (1 << 0)
363 #define UT_ID (1 << 1)
364 #define UT_LINE (1 << 2)
365 #define UT_PID (1 << 3)
366 #define UT_TV (1 << 4)
368 __private_extern__
const struct utmpx
*
369 _utmpx_working_copy(const struct utmpx
*utx
, struct utmpx
*temp
, int onlyid
)
372 static char idzero
[_UTX_IDSIZE
];
374 if ((utx
->ut_type
& (UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
)) == 0)
376 memcpy(temp
, utx
, sizeof(*temp
));
377 temp
->ut_type
&= ~(UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
);
379 if ((utx
->ut_type
& UTMPX_AUTOFILL_MASK
) == 0)
382 which
= UT_TV
; /* they all need time */
383 switch(temp
->ut_type
) {
387 which
|= (UT_USER
| UT_LINE
| UT_PID
);
388 /* Set UT_ID if ut_id isn't there */
389 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
396 which
|= (UT_USER
| UT_PID
);
400 /* Set UT_ID if ut_id isn't there. We will also need UT_LINE */
401 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
402 which
|= (UT_ID
| UT_LINE
);
406 * If onlyid is set: if ut_id isn't set but is needed, then set
407 * which to (UT_LINE | UT_ID), otherwise zero
410 which
= (which
& UT_ID
) ? (UT_LINE
| UT_ID
) : 0;
411 if ((which
& UT_LINE
) && !*temp
->ut_line
) {
417 err
= ttyname_r(0, buf
, sizeof(buf
));
419 err
= ttyname_r(1, buf
, sizeof(buf
));
421 err
= ttyname_r(2, buf
, sizeof(buf
));
424 #else /* !__DARWIN_UNIX03 */
425 cp
= ttyname_r(0, buf
, sizeof(buf
));
427 cp
= ttyname_r(1, buf
, sizeof(buf
));
429 cp
= ttyname_r(2, buf
, sizeof(buf
));
432 #endif /* __DARWIN_UNIX03 */
433 cp
= strrchr(buf
, '/');
438 strncpy(temp
->ut_line
, cp
, sizeof(temp
->ut_line
));
440 /* UT_ID is set only if we already know we need to add it */
441 if ((which
& UT_ID
)) {
443 int i
= sizeof(temp
->ut_line
);
445 for(cp
= temp
->ut_line
; i
> 0 && *cp
; i
--)
447 i
= cp
- temp
->ut_line
;
448 if(i
>= sizeof(temp
->ut_id
))
449 memcpy(temp
->ut_id
, cp
- sizeof(temp
->ut_id
), sizeof(temp
->ut_id
));
451 memcpy(temp
->ut_id
, temp
->ut_line
, i
);
453 if ((which
& UT_PID
) && !temp
->ut_pid
)
454 temp
->ut_pid
= getpid();
455 if ((which
& UT_USER
) && !*temp
->ut_user
) {
459 if ((buf
= _pwuid_r(getuid(), &pw
)) == NULL
)
461 strncpy(temp
->ut_user
, pw
.pw_name
, sizeof(temp
->ut_user
));
464 if ((which
& UT_TV
) && !temp
->ut_tv
.tv_sec
&& !temp
->ut_tv
.tv_usec
)
465 gettimeofday(&temp
->ut_tv
, NULL
);
470 * We can read from either asl or from a file, so we need to switch between
473 static void end_asl(void);
474 static void end_file(void);
475 static struct utmpx
*get_asl(void);
476 static struct utmpx
*get_file(void);
477 static void set_asl(int);
478 static void set_file(int);
480 enum {WTMP_ASL
, WTMP_FILE
};
485 struct utmpx
*(*get
)(void);
496 asl_search_result_t
*res
;
501 } wtmp_asl
= {-1, 1};
505 char file
[MAXPATHLEN
];
510 struct utmpx32
*next
;
514 #endif /* __LP64__ */
516 } wtmp_file
= {-1, -1};
527 return wtmp_func
.get();
531 setutxent_wtmp(int dir
)
536 /* use the given file, or if NULL, read from asl */
538 wtmpxname(const char *fname
)
543 if (wtmp_func
.which
== WTMP_ASL
) {
548 wtmp_func
.which
= WTMP_ASL
;
549 wtmp_func
.end
= end_asl
;
550 wtmp_func
.get
= get_asl
;
551 wtmp_func
.set
= set_asl
;
556 if (len
>= sizeof(wtmp_file
.file
))
560 if (fname
[len
- 1] != 'x')
563 (void)strlcpy(wtmp_file
.file
, fname
, sizeof(wtmp_file
.file
));
565 if (wtmp_func
.which
== WTMP_ASL
)
567 else if (wtmp_file
.fd
>= 0) {
571 wtmp_func
.which
= WTMP_FILE
;
572 wtmp_func
.end
= end_file
;
573 wtmp_func
.get
= get_file
;
574 wtmp_func
.set
= set_file
;
582 aslresponse_free(wtmp_asl
.res
);
587 if (asl_server_port
!= MACH_PORT_NULL
) {
588 mach_port_deallocate(mach_task_self(), asl_server_port
);
589 asl_server_port
= MACH_PORT_NULL
;
596 if (wtmp_file
.fd
>= 0) {
602 wtmp_file
.buf
= NULL
;
606 static struct utmpx
*
611 uint32_t reslen
, status
;
612 security_token_t sec
;
614 static struct utmpx utx
;
618 if ((q
= aslresponse_next(wtmp_asl
.res
)) != NULL
) {
622 aslresponse_free(wtmp_asl
.res
);
624 } else if (!wtmp_asl
.inited
) {
626 if (!wtmp_asl
.inited
)
633 if (asl_server_port
== MACH_PORT_NULL
) {
634 if (bootstrap_look_up(bootstrap_port
, ASL_SERVICE_NAME
, &asl_server_port
) != KERN_SUCCESS
) {
641 /* the server frees this memory */
642 if (vm_allocate(mach_task_self(), (vm_address_t
*)&vmstr
, wtmp_asl
.len
, TRUE
) != KERN_SUCCESS
)
645 /* the search string is defined in set_asl */
646 strcpy(vmstr
, wtmp_asl
.str
);
654 _asl_server_query_timeout(asl_server_port
, vmstr
, wtmp_asl
.len
, wtmp_asl
.start
, WTMP_COUNT
, wtmp_asl
.dir
, ASL_QUERY_TIMEOUT
, (caddr_t
*)&res
, &reslen
, &wtmp_asl
.start
, (int *)&status
, &sec
);
658 wtmp_asl
.res
= asl_list_from_string(res
);
659 vm_deallocate(mach_task_self(), (vm_address_t
)res
, reslen
);
665 static struct utmpx
*
671 static struct utmpx ux
;
672 #endif /* __LP64__ */
675 if (wtmp_file
.left
> 0) {
677 struct utmpx32
*u
= wtmp_file
.next
;
679 struct utmpx
*u
= wtmp_file
.next
;
680 #endif /* __LP64__ */
681 wtmp_file
.next
+= wtmp_file
.dir
;
688 #endif /* __LP64__ */
689 } else if (wtmp_file
.fd
< 0) {
690 set_file(-1); /* keep current read direction */
691 if (wtmp_file
.fd
< 0)
693 goto get_file_repeat
;
695 if (wtmp_file
.count
<= 0)
699 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
701 n
= WTMP_COUNT
* sizeof(struct utmpx
);
702 #endif /* __LP64__ */
703 if (wtmp_file
.dir
> 0)
704 wtmp_file
.next
= wtmp_file
.buf
;
706 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
708 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
715 cp
= (char *)wtmp_file
.buf
;
717 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
718 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
723 } while((n
-= r
) > 0);
725 wtmp_file
.left
= WTMP_COUNT
;
726 wtmp_file
.count
-= WTMP_COUNT
;
728 goto get_file_repeat
;
732 * This sets the directions for both asl and reading from a file. If forward
736 _set_dir(int forward
)
758 asl_search_result_t s
;
761 * Create a search string that matches either UTMPX_FACILITY
762 * or LASTLOG_FACILITY.
764 if ((q0
= asl_new(ASL_TYPE_QUERY
)) == NULL
)
766 if ((q1
= asl_new(ASL_TYPE_QUERY
)) == NULL
) {
770 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
771 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
779 wtmp_asl
.str
= asl_list_to_string(&s
, &wtmp_asl
.len
);
786 aslresponse_free(wtmp_asl
.res
);
794 set_file(int forward
)
803 if (wtmp_file
.buf
== NULL
&&
804 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
806 if (wtmp_file
.buf
== NULL
&&
807 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
808 #endif /* __LP64__ */
810 if (wtmp_file
.fd
>= 0)
812 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
814 if (fstat(wtmp_file
.fd
, &s
) < 0)
817 * We must have a file at least 2 sizeof(struct utmpx) in size,
818 * with the first struct utmpx matching a signature record.
821 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
823 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
824 #endif /* __LP64__ */
827 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
829 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
830 #endif /* __LP64__ */
832 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
833 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
838 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
839 * either at the beginning or the end, so that all subsequent reads
840 * must contain WTMP_COUNT records.
842 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
843 wtmp_file
.left
= wtmp_file
.count
- c
;
844 wtmp_file
.count
-= wtmp_file
.left
;
846 /* Seek to the end for reverse reading */
847 if (wtmp_file
.dir
< 0) {
849 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
851 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
852 #endif /* __LP64__ */
853 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
857 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
859 n
= wtmp_file
.left
* sizeof(struct utmpx
);
860 #endif /* __LP64__ */
861 cp
= (char *)wtmp_file
.buf
;
863 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
864 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
869 } while((n
-= r
) > 0);
871 /* Point to either the beginning or end of the buffer */
872 if(wtmp_file
.dir
> 0)
873 wtmp_file
.next
= wtmp_file
.buf
;
875 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
887 * these routines assume natural alignment so that struct utmpx32 has
888 * the same size and layout as the 32-bit struct utmpx
890 __private_extern__
void
891 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
893 bzero(u
, sizeof(*u
));
894 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
895 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
896 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
897 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
898 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
899 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
902 __private_extern__
void
903 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
905 bzero(u32
, sizeof(*u32
));
906 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
907 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
908 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
909 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
910 (char *)u
+ offsetof(struct utmpx
, ut_host
),
911 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
913 #endif /* __LP64__ */
917 __private_extern__
void
918 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
921 bzero(u
, sizeof(*u
));
922 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
923 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
924 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
925 u
->ut_time
= ux
->ut_tv
.tv_sec
;
927 #endif /* __LP64__ */
930 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
931 * described in utmp(5). It then returns a value that specifies what
932 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
933 * write utmp only if a matching record with the same ut_line value is found;
934 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
936 __private_extern__
int
938 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
940 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
941 #endif /* __LP64__ */
947 #endif /* __LP64__ */
949 switch (ux
->ut_type
) {
952 bzero(u
->ut_line
, sizeof(u
->ut_line
));
954 bzero(u
->ut_name
, sizeof(u
->ut_name
));
955 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
956 return UTMP_COMPAT_WTMP
;
959 bzero(u
->ut_line
, sizeof(u
->ut_line
));
960 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
961 bzero(u
->ut_name
, sizeof(u
->ut_name
));
962 strcpy(u
->ut_name
, "date");
963 return UTMP_COMPAT_WTMP
;
965 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
967 bzero(u
->ut_name
, sizeof(u
->ut_name
));
968 bzero(u
->ut_host
, sizeof(u
->ut_host
));
969 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
971 return 0; /* skip */;
975 * Write _PATH_LASTLOG given a struct utmp record. We use
976 * advisory record locking.
978 __private_extern__
void
980 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
982 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
983 #endif /* __LP64__ */
990 #endif /* __LP64__ */
993 // sizeof(ux->ut_user) > sizeof(u->ut_name)
994 char name
[sizeof(ux
->ut_user
) + 1];
1002 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
1003 name
[sizeof(ux
->ut_user
)] = 0;
1007 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
1008 name
[sizeof(u
->ut_name
)] = 0;
1010 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
1013 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
1014 #else /* __LP64__ */
1015 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
1016 #endif /* __LP64__ */
1019 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
1021 (void)lseek(fd
, off
, SEEK_SET
);
1022 bzero(&lock
, sizeof(lock
));
1023 lock
.l_type
= F_WRLCK
;
1024 lock
.l_whence
= SEEK_SET
;
1027 lock
.l_len
= sizeof(struct lastlog32
);
1028 #else /* __LP64__ */
1029 lock
.l_len
= sizeof(struct lastlog
);
1030 #endif /* __LP64__ */
1031 /* try to lock, but give up after retry times, and write anyways */
1032 while(retry
-- > 0) {
1033 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1037 l
.ll_time
= u
->ut_time
;
1038 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1039 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1040 (void) write(fd
, &l
, sizeof(l
));
1041 lock
.l_type
= F_UNLCK
;
1042 (void) fcntl(fd
, F_SETLK
, &lock
);
1047 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1050 __private_extern__
void
1052 _write_utmp(const struct utmp32
*u
, int mustexist
)
1053 #else /* __LP64__ */
1054 _write_utmp(const struct utmp
*u
, int mustexist
)
1055 #endif /* __LP64__ */
1058 struct ttyent
*ttyp
;
1061 #else /* __LP64__ */
1063 #endif /* __LP64__ */
1066 char line
[sizeof(u
->ut_line
)];
1070 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1073 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1077 /* do equivalent of ttyslot(), but using u->ut_line */
1082 if ((ttyp
= getttyent()) == NULL
)
1084 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1085 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1095 if (!found
) { /* no assigned slot */
1097 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1098 #else /* __LP64__ */
1099 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1100 #endif /* __LP64__ */
1102 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1104 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1105 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1114 if (!found
&& mustexist
) {
1119 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1120 (void)write(fd
, u
, sizeof(struct utmp32
));
1121 #else /* __LP64__ */
1122 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1123 (void)write(fd
, u
, sizeof(struct utmp
));
1124 #endif /* __LP64__ */
1129 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1130 * given struct utmpx.
1132 __private_extern__
void
1133 _write_utmp_compat(const struct utmpx
*ux
)
1137 #else /* __LP64__ */
1139 #endif /* __LP64__ */
1142 which
= _utmp_compat(ux
, &u
);
1143 if (which
& UTMP_COMPAT_UTMP0
)
1145 else if (which
& UTMP_COMPAT_UTMP1
)
1147 if (which
& UTMP_COMPAT_WTMP
)
1149 if (which
& UTMP_COMPAT_LASTLOG
)
1150 _write_lastlog(&u
, ux
);
1153 /* Append a struct wtmp to _PATH_WTMP */
1154 __private_extern__
void
1156 _write_wtmp(const struct utmp32
*u
)
1157 #else /* __LP64__ */
1158 _write_wtmp(const struct utmp
*u
)
1159 #endif /* __LP64__ */
1164 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1166 if (fstat(fd
, &buf
) == 0) {
1167 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1168 (void) ftruncate(fd
, buf
.st_size
);
1172 #endif /* UTMP_COMPAT */