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>
44 #include <asl_private.h>
45 #include <asl_store.h>
49 #include <mach/mach.h>
50 #include <mach/std_types.h>
52 #include <mach/mach_types.h>
53 #include <servers/bootstrap.h>
59 #endif /* UTMP_COMPAT */
61 __private_extern__
const char __utx_magic__
[UTMPX_MAGIC
] = __UTX_MAGIC__
;
63 extern const char _utmpx_vers
[]; /* in utmpx.c */
65 static void msg2lastlogx(const aslmsg
, struct lastlogx
*);
66 static void msg2utmpx(const aslmsg
, struct utmpx
*);
67 static void utmpx2msg(const struct utmpx
*, aslmsg
);
69 static int pw_size
= 0;
71 #define FACILITY "Facility"
74 /* ASL timeout in microseconds */
75 #define ASL_QUERY_TIMEOUT 4000000
77 /* indirection causes argument to be substituted before stringification */
78 #define STR(x) __STRING(x)
82 _pwnam_r(const char *user
, struct passwd
*pw
)
88 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
92 if ((buf
= malloc(pw_size
)) == NULL
)
95 getpwnam_r(user
, pw
, buf
, pw_size
, &p
);
105 _pwuid_r(uid_t uid
, struct passwd
*pw
)
111 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
115 if ((buf
= malloc(pw_size
)) == NULL
)
118 getpwuid_r(uid
, pw
, buf
, pw_size
, &p
);
127 getlastlogx(uid_t uid
, struct lastlogx
*lx
)
133 if ((buf
= _pwuid_r(uid
, &pw
)) == NULL
)
136 l
= getlastlogxbyname(pw
.pw_name
, lx
);
142 getlastlogxbyname(const char *user
, struct lastlogx
*lx
)
146 asl_search_result_t query
, *res
;
149 struct lastlogx
*result
= NULL
;
152 if (!user
|| !*user
) return NULL
;
155 status
= asl_store_open_read(NULL
, &store
);
156 if (status
!= 0) return NULL
;
157 if (store
== NULL
) return NULL
;
160 * We search for the last LASTLOG_FACILITY entry that has the
161 * ut_user entry matching the user's name.
163 if ((m
= asl_new(ASL_TYPE_QUERY
)) == NULL
)
165 asl_store_close(store
);
169 asl_set_query(m
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
170 asl_set_query(m
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
171 qm
[0] = (asl_msg_t
*)m
;
178 asl_store_match_timeout(store
, &query
, &res
, &cmax
, -1, 1, -1, ASL_QUERY_TIMEOUT
);
179 asl_store_close(store
);
182 if (status
!= 0) return NULL
;
183 if (res
== NULL
) return NULL
;
185 m
= aslresponse_next(res
);
188 aslresponse_free(res
);
194 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
)
196 aslresponse_free(res
);
202 aslresponse_free(res
);
208 #define IGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
209 u->p##_##e = strtol(cp, NULL, 10);
210 #define LGET(e,p) IGET(e,p)
211 #define SGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
212 strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
214 /* fill in a struct lastlogx from a aslmsg */
216 msg2lastlogx(const aslmsg m
, struct lastlogx
*u
)
220 bzero(u
, sizeof(*u
));
223 IGET(tv
.tv_usec
, ll
);
227 /* fill in a struct utmpx from a aslmsg */
229 msg2utmpx(const aslmsg m
, struct utmpx
*u
)
233 bzero(u
, sizeof(*u
));
240 IGET(tv
.tv_usec
, ut
);
244 /* fill in a aslmsg from a struct utmpx */
246 utmpx2msg(const struct utmpx
*u
, aslmsg m
)
248 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
250 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
251 asl_set(m, #e, buf); }
252 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
253 asl_set(m, #e, buf); }
254 #define SSET(e) if (*(u->e)) { \
255 strncpy(buf, u->e, sizeof(u->e)); \
256 buf[sizeof(u->e)] = 0; \
257 asl_set(m, #e, buf); \
261 cp
= (char *)u
->ut_id
+ sizeof(u
->ut_id
);
262 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
266 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
267 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
268 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
269 asl_set(m
, "ut_id", buf
);
280 static const char *utmpx_types
[] = {
286 "INIT_PROCESS", /* 5 */
287 "LOGIN_PROCESS", /* 6 */
288 "USER_PROCESS", /* 7 */
289 "DEAD_PROCESS", /* 8 */
290 "ACCOUNTING", /* 9 */
291 "SIGNATURE", /* 10 */
292 "SHUTDOWN_TIME", /* 11 */
295 /* send a struct utmpx record using asl */
296 __private_extern__
void
297 _utmpx_asl(const struct utmpx
*u
)
299 aslclient asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); /* could be NULL, but still works */
303 if (u
->ut_type
== EMPTY
)
305 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
310 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
311 * otherwise we use the UTMPX_FACILITY. This makes it easy to
312 * search for lastlog entries, but for wtmp, we have to search
313 * for both facilities.
315 if (u
->ut_type
== USER_PROCESS
)
316 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
318 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
319 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
322 /* Make a visible message for system.log */
323 switch (u
->ut_type
) {
328 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
332 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
336 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
339 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
340 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
342 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
345 asl_set(m
, ASL_KEY_MSG
, msg
);
352 #define UT_USER (1 << 0)
353 #define UT_ID (1 << 1)
354 #define UT_LINE (1 << 2)
355 #define UT_PID (1 << 3)
356 #define UT_TV (1 << 4)
358 __private_extern__
const struct utmpx
*
359 _utmpx_working_copy(const struct utmpx
*utx
, struct utmpx
*temp
, int onlyid
)
362 static char idzero
[_UTX_IDSIZE
];
364 if ((utx
->ut_type
& (UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
)) == 0)
366 memcpy(temp
, utx
, sizeof(*temp
));
367 temp
->ut_type
&= ~(UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
);
369 if ((utx
->ut_type
& UTMPX_AUTOFILL_MASK
) == 0)
372 which
= UT_TV
; /* they all need time */
373 switch(temp
->ut_type
) {
377 which
|= (UT_USER
| UT_LINE
| UT_PID
);
378 /* Set UT_ID if ut_id isn't there */
379 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
386 which
|= (UT_USER
| UT_PID
);
390 /* Set UT_ID if ut_id isn't there. We will also need UT_LINE */
391 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
392 which
|= (UT_ID
| UT_LINE
);
396 * If onlyid is set: if ut_id isn't set but is needed, then set
397 * which to (UT_LINE | UT_ID), otherwise zero
400 which
= (which
& UT_ID
) ? (UT_LINE
| UT_ID
) : 0;
401 if ((which
& UT_LINE
) && !*temp
->ut_line
) {
407 err
= ttyname_r(0, buf
, sizeof(buf
));
409 err
= ttyname_r(1, buf
, sizeof(buf
));
411 err
= ttyname_r(2, buf
, sizeof(buf
));
414 #else /* !__DARWIN_UNIX03 */
415 cp
= ttyname_r(0, buf
, sizeof(buf
));
417 cp
= ttyname_r(1, buf
, sizeof(buf
));
419 cp
= ttyname_r(2, buf
, sizeof(buf
));
422 #endif /* __DARWIN_UNIX03 */
423 cp
= strrchr(buf
, '/');
428 strncpy(temp
->ut_line
, cp
, sizeof(temp
->ut_line
));
430 /* UT_ID is set only if we already know we need to add it */
431 if ((which
& UT_ID
)) {
433 int i
= sizeof(temp
->ut_line
);
435 for(cp
= temp
->ut_line
; i
> 0 && *cp
; i
--)
437 i
= cp
- temp
->ut_line
;
438 if(i
>= sizeof(temp
->ut_id
))
439 memcpy(temp
->ut_id
, cp
- sizeof(temp
->ut_id
), sizeof(temp
->ut_id
));
441 memcpy(temp
->ut_id
, temp
->ut_line
, i
);
443 if ((which
& UT_PID
) && !temp
->ut_pid
)
444 temp
->ut_pid
= getpid();
445 if ((which
& UT_USER
) && !*temp
->ut_user
) {
449 if ((buf
= _pwuid_r(getuid(), &pw
)) == NULL
)
451 strncpy(temp
->ut_user
, pw
.pw_name
, sizeof(temp
->ut_user
));
454 if ((which
& UT_TV
) && !temp
->ut_tv
.tv_sec
&& !temp
->ut_tv
.tv_usec
)
455 gettimeofday(&temp
->ut_tv
, NULL
);
460 * We can read from either asl or from a file, so we need to switch between
463 static void end_asl(void);
464 static void end_file(void);
465 static struct utmpx
*get_asl(void);
466 static struct utmpx
*get_file(void);
467 static void set_asl(int);
468 static void set_file(int);
470 enum {WTMP_ASL
, WTMP_FILE
};
475 struct utmpx
*(*get
)(void);
486 asl_search_result_t
*res
;
491 } wtmp_asl
= {-1, 1};
500 struct utmpx32
*next
;
504 #endif /* __LP64__ */
506 } wtmp_file
= {-1, -1};
517 return wtmp_func
.get();
521 setutxent_wtmp(int dir
)
526 /* use the given file, or if NULL, read from asl */
528 wtmpxname(const char *fname
)
533 if (wtmp_func
.which
== WTMP_ASL
) {
538 wtmp_func
.which
= WTMP_ASL
;
539 wtmp_func
.end
= end_asl
;
540 wtmp_func
.get
= get_asl
;
541 wtmp_func
.set
= set_asl
;
546 if (len
>= MAXPATHLEN
)
550 if (fname
[len
- 1] != 'x')
553 if (wtmp_func
.which
== WTMP_ASL
)
555 else if (wtmp_file
.fd
>= 0) {
561 free(wtmp_file
.file
);
563 wtmp_file
.file
= strdup(fname
);
564 if (wtmp_file
.file
== NULL
)
567 wtmp_func
.which
= WTMP_FILE
;
568 wtmp_func
.end
= end_file
;
569 wtmp_func
.get
= get_file
;
570 wtmp_func
.set
= set_file
;
577 if (wtmp_asl
.res
!= NULL
)
579 aslresponse_free(wtmp_asl
.res
);
590 if (wtmp_file
.fd
>= 0) {
596 wtmp_file
.buf
= NULL
;
600 static struct utmpx
*
604 static struct utmpx utx
;
606 if (wtmp_asl
.inited
== 0) set_asl(-1);
607 if (wtmp_asl
.done
!= 0) return NULL
;
609 m
= aslresponse_next(wtmp_asl
.res
);
612 aslresponse_free(wtmp_asl
.res
);
623 static struct utmpx
*
629 static struct utmpx ux
;
630 #endif /* __LP64__ */
633 if (wtmp_file
.left
> 0) {
635 struct utmpx32
*u
= wtmp_file
.next
;
637 struct utmpx
*u
= wtmp_file
.next
;
638 #endif /* __LP64__ */
639 wtmp_file
.next
+= wtmp_file
.dir
;
646 #endif /* __LP64__ */
647 } else if (wtmp_file
.fd
< 0) {
648 set_file(-1); /* keep current read direction */
649 if (wtmp_file
.fd
< 0)
651 goto get_file_repeat
;
653 if (wtmp_file
.count
<= 0)
657 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
659 n
= WTMP_COUNT
* sizeof(struct utmpx
);
660 #endif /* __LP64__ */
661 if (wtmp_file
.dir
> 0)
662 wtmp_file
.next
= wtmp_file
.buf
;
664 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
666 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
673 cp
= (char *)wtmp_file
.buf
;
675 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
676 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
681 } while((n
-= r
) > 0);
683 wtmp_file
.left
= WTMP_COUNT
;
684 wtmp_file
.count
-= WTMP_COUNT
;
686 goto get_file_repeat
;
690 * This sets the directions for both asl and reading from a file. If forward
694 _set_dir(int forward
)
696 if (forward
< 0) return;
719 asl_search_result_t query
;
729 if (wtmp_asl
.res
!= NULL
)
731 aslresponse_free(wtmp_asl
.res
);
736 status
= asl_store_open_read(NULL
, &store
);
737 if (status
!= 0) return;
738 if (store
== NULL
) return;
741 * Create a search query that matches either UTMPX_FACILITY
742 * or LASTLOG_FACILITY.
744 q0
= asl_new(ASL_TYPE_QUERY
);
745 q1
= asl_new(ASL_TYPE_QUERY
);
747 if ((q0
== NULL
) || (q1
== NULL
))
749 asl_store_close(store
);
750 if (q0
!= NULL
) free(q0
);
751 if (q1
!= NULL
) free(q1
);
755 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
756 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
758 m
[0] = (asl_msg_t
*)q0
;
759 m
[1] = (asl_msg_t
*)q1
;
765 asl_store_match_timeout(store
, &query
, &(wtmp_asl
.res
), &cmax
, wtmp_asl
.start
, 0, wtmp_asl
.dir
, ASL_QUERY_TIMEOUT
);
766 asl_store_close(store
);
771 if (wtmp_asl
.res
== NULL
) return;
778 set_file(int forward
)
787 if (wtmp_file
.buf
== NULL
&&
788 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
790 if (wtmp_file
.buf
== NULL
&&
791 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
792 #endif /* __LP64__ */
794 if (wtmp_file
.fd
>= 0)
796 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
798 if (fstat(wtmp_file
.fd
, &s
) < 0)
801 * We must have a file at least 2 sizeof(struct utmpx) in size,
802 * with the first struct utmpx matching a signature record.
805 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
807 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
808 #endif /* __LP64__ */
811 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
813 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
814 #endif /* __LP64__ */
816 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
817 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
822 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
823 * either at the beginning or the end, so that all subsequent reads
824 * must contain WTMP_COUNT records.
826 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
827 wtmp_file
.left
= wtmp_file
.count
- c
;
828 wtmp_file
.count
-= wtmp_file
.left
;
830 /* Seek to the end for reverse reading */
831 if (wtmp_file
.dir
< 0) {
833 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
835 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
836 #endif /* __LP64__ */
837 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
841 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
843 n
= wtmp_file
.left
* sizeof(struct utmpx
);
844 #endif /* __LP64__ */
845 cp
= (char *)wtmp_file
.buf
;
847 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
848 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
853 } while((n
-= r
) > 0);
855 /* Point to either the beginning or end of the buffer */
856 if(wtmp_file
.dir
> 0)
857 wtmp_file
.next
= wtmp_file
.buf
;
859 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
871 * these routines assume natural alignment so that struct utmpx32 has
872 * the same size and layout as the 32-bit struct utmpx
874 __private_extern__
void
875 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
877 bzero(u
, sizeof(*u
));
878 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
879 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
880 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
881 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
882 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
883 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
886 __private_extern__
void
887 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
889 bzero(u32
, sizeof(*u32
));
890 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
891 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
892 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
893 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
894 (char *)u
+ offsetof(struct utmpx
, ut_host
),
895 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
897 #endif /* __LP64__ */
901 __private_extern__
void
902 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
905 bzero(u
, sizeof(*u
));
906 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
907 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
908 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
909 u
->ut_time
= ux
->ut_tv
.tv_sec
;
911 #endif /* __LP64__ */
914 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
915 * described in utmp(5). It then returns a value that specifies what
916 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
917 * write utmp only if a matching record with the same ut_line value is found;
918 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
920 __private_extern__
int
922 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
924 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
925 #endif /* __LP64__ */
931 #endif /* __LP64__ */
933 switch (ux
->ut_type
) {
936 bzero(u
->ut_line
, sizeof(u
->ut_line
));
938 bzero(u
->ut_name
, sizeof(u
->ut_name
));
939 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
940 return UTMP_COMPAT_WTMP
;
943 bzero(u
->ut_line
, sizeof(u
->ut_line
));
944 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
945 bzero(u
->ut_name
, sizeof(u
->ut_name
));
946 strcpy(u
->ut_name
, "date");
947 return UTMP_COMPAT_WTMP
;
949 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
951 bzero(u
->ut_name
, sizeof(u
->ut_name
));
952 bzero(u
->ut_host
, sizeof(u
->ut_host
));
953 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
955 return 0; /* skip */;
959 * Write _PATH_LASTLOG given a struct utmp record. We use
960 * advisory record locking.
962 __private_extern__
void
964 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
966 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
967 #endif /* __LP64__ */
974 #endif /* __LP64__ */
977 // sizeof(ux->ut_user) > sizeof(u->ut_name)
978 char name
[sizeof(ux
->ut_user
) + 1];
986 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
987 name
[sizeof(ux
->ut_user
)] = 0;
991 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
992 name
[sizeof(u
->ut_name
)] = 0;
994 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
997 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
999 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
1000 #endif /* __LP64__ */
1003 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
1005 (void)lseek(fd
, off
, SEEK_SET
);
1006 bzero(&lock
, sizeof(lock
));
1007 lock
.l_type
= F_WRLCK
;
1008 lock
.l_whence
= SEEK_SET
;
1011 lock
.l_len
= sizeof(struct lastlog32
);
1012 #else /* __LP64__ */
1013 lock
.l_len
= sizeof(struct lastlog
);
1014 #endif /* __LP64__ */
1015 /* try to lock, but give up after retry times, and write anyways */
1016 while(retry
-- > 0) {
1017 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1021 l
.ll_time
= u
->ut_time
;
1022 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1023 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1024 (void) write(fd
, &l
, sizeof(l
));
1025 lock
.l_type
= F_UNLCK
;
1026 (void) fcntl(fd
, F_SETLK
, &lock
);
1031 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1034 __private_extern__
void
1036 _write_utmp(const struct utmp32
*u
, int mustexist
)
1037 #else /* __LP64__ */
1038 _write_utmp(const struct utmp
*u
, int mustexist
)
1039 #endif /* __LP64__ */
1042 struct ttyent
*ttyp
;
1045 #else /* __LP64__ */
1047 #endif /* __LP64__ */
1050 char line
[sizeof(u
->ut_line
)];
1054 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1057 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1061 /* do equivalent of ttyslot(), but using u->ut_line */
1066 if ((ttyp
= getttyent()) == NULL
)
1068 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1069 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1079 if (!found
) { /* no assigned slot */
1081 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1082 #else /* __LP64__ */
1083 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1084 #endif /* __LP64__ */
1086 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1088 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1089 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1098 if (!found
&& mustexist
) {
1103 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1104 (void)write(fd
, u
, sizeof(struct utmp32
));
1105 #else /* __LP64__ */
1106 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1107 (void)write(fd
, u
, sizeof(struct utmp
));
1108 #endif /* __LP64__ */
1113 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1114 * given struct utmpx.
1116 __private_extern__
void
1117 _write_utmp_compat(const struct utmpx
*ux
)
1121 #else /* __LP64__ */
1123 #endif /* __LP64__ */
1126 which
= _utmp_compat(ux
, &u
);
1127 if (which
& UTMP_COMPAT_UTMP0
)
1129 else if (which
& UTMP_COMPAT_UTMP1
)
1131 if (which
& UTMP_COMPAT_WTMP
)
1133 if (which
& UTMP_COMPAT_LASTLOG
)
1134 _write_lastlog(&u
, ux
);
1137 /* Append a struct wtmp to _PATH_WTMP */
1138 __private_extern__
void
1140 _write_wtmp(const struct utmp32
*u
)
1141 #else /* __LP64__ */
1142 _write_wtmp(const struct utmp
*u
)
1143 #endif /* __LP64__ */
1148 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1150 if (fstat(fd
, &buf
) == 0) {
1151 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1152 (void) ftruncate(fd
, buf
.st_size
);
1156 #endif /* UTMP_COMPAT */
1162 _openutx(const char *name
)
1166 if ((U
= calloc(1, sizeof(struct _utmpx
))) == NULL
)
1168 memcpy(U
->magic
, __utx_magic__
, UTMPX_MAGIC
);
1169 U
->utmpx_mutex
= (pthread_mutex_t
)PTHREAD_MUTEX_INITIALIZER
;
1170 if (__utmpxname(U
, name
) == 0) {
1171 if (!U
->utfile_system
)
1181 _closeutx(utmpx_t u
)
1183 struct _utmpx
*U
= (struct _utmpx
*)u
;
1185 if (!U
|| memcmp(U
->magic
, __utx_magic__
, UTMPX_MAGIC
) != 0) {
1191 if (!U
->utfile_system
)