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 __private_extern__
const char __utx_magic__
[UTMPX_MAGIC
] = __UTX_MAGIC__
;
60 extern const char _utmpx_vers
[]; /* in utmpx.c */
62 static void msg2lastlogx(asl_object_t
, struct lastlogx
*);
63 static void msg2utmpx(asl_object_t
, struct utmpx
*);
64 static void utmpx2msg(const struct utmpx
*, asl_object_t
);
66 static size_t pw_size
= 0;
68 #define FACILITY "Facility"
71 /* ASL timeout in microseconds */
72 #define ASL_QUERY_TIMEOUT 4000000
74 /* indirection causes argument to be substituted before stringification */
75 #define STR(x) __STRING(x)
77 #pragma clang diagnostic push
78 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
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
)
144 asl_object_t m
, query
, res
;
146 struct lastlogx
*result
= NULL
;
148 if (!user
|| !*user
) return NULL
;
151 * We search for the last LASTLOG_FACILITY entry that has the
152 * ut_user entry matching the user's name.
154 m
= asl_new(ASL_TYPE_QUERY
);
160 asl_set_query(m
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
161 asl_set_query(m
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
163 query
= asl_new(ASL_TYPE_LIST
);
170 asl_append(query
, m
);
176 res
= asl_match(NULL
, query
, &cmax
, -1, 1, ASL_QUERY_TIMEOUT
, ASL_MATCH_DIRECTION_REVERSE
);
179 if (res
== NULL
) return NULL
;
191 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
)
205 #define IGET(e,p) do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
206 u->p##_##e = (int)strtol(cp, NULL, 10); } while (0)
207 #define LGET(e,p) do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
208 u->p##_##e = strtol(cp, NULL, 10); } while (0)
209 #define SGET(e,p) do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
210 strncpy(u->p##_##e, cp, sizeof(u->p##_##e)); } while (0)
212 /* fill in a struct lastlogx from an ASL message */
214 msg2lastlogx(asl_object_t m
, struct lastlogx
*u
)
218 bzero(u
, sizeof(*u
));
221 IGET(tv
.tv_usec
, ll
);
225 /* fill in a struct utmpx from an ASL message */
227 msg2utmpx(asl_object_t m
, struct utmpx
*u
)
231 bzero(u
, sizeof(*u
));
238 IGET(tv
.tv_usec
, ut
);
242 /* fill in an ASL message from a struct utmpx */
244 utmpx2msg(const struct utmpx
*u
, asl_object_t m
)
246 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
248 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
249 asl_set(m, #e, buf); }
250 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
251 asl_set(m, #e, buf); }
252 #define SSET(e) if (*(u->e)) { \
253 strncpy(buf, u->e, sizeof(u->e)); \
254 buf[sizeof(u->e)] = 0; \
255 asl_set(m, #e, buf); \
259 cp
= (char *)u
->ut_id
+ sizeof(u
->ut_id
);
260 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
264 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
265 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
266 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
267 asl_set(m
, "ut_id", buf
);
278 static const char *utmpx_types
[] = {
284 "INIT_PROCESS", /* 5 */
285 "LOGIN_PROCESS", /* 6 */
286 "USER_PROCESS", /* 7 */
287 "DEAD_PROCESS", /* 8 */
288 "ACCOUNTING", /* 9 */
289 "SIGNATURE", /* 10 */
290 "SHUTDOWN_TIME", /* 11 */
293 /* send a struct utmpx record using ASL */
294 __private_extern__
void
295 _utmpx_asl(const struct utmpx
*u
)
297 asl_object_t asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
);
301 if (u
->ut_type
== EMPTY
)
303 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
308 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
309 * otherwise we use the UTMPX_FACILITY. This makes it easy to
310 * search for lastlog entries, but for wtmp, we have to search
311 * for both facilities.
313 if (u
->ut_type
== USER_PROCESS
)
314 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
316 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
317 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
320 /* Make a visible message for system.log */
321 switch (u
->ut_type
) {
326 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
330 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
334 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
337 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
338 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
340 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
343 asl_set(m
, ASL_KEY_MSG
, msg
);
349 #define UT_USER (1 << 0)
350 #define UT_ID (1 << 1)
351 #define UT_LINE (1 << 2)
352 #define UT_PID (1 << 3)
353 #define UT_TV (1 << 4)
355 __private_extern__
const struct utmpx
*
356 _utmpx_working_copy(const struct utmpx
*utx
, struct utmpx
*temp
, int onlyid
)
359 static char idzero
[_UTX_IDSIZE
];
361 if ((utx
->ut_type
& (UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
)) == 0)
363 memcpy(temp
, utx
, sizeof(*temp
));
364 temp
->ut_type
&= ~(UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
);
366 if ((utx
->ut_type
& UTMPX_AUTOFILL_MASK
) == 0)
369 which
= UT_TV
; /* they all need time */
370 switch(temp
->ut_type
) {
374 which
|= (UT_USER
| UT_LINE
| UT_PID
);
375 /* Set UT_ID if ut_id isn't there */
376 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
383 which
|= (UT_USER
| UT_PID
);
387 /* Set UT_ID if ut_id isn't there. We will also need UT_LINE */
388 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
389 which
|= (UT_ID
| UT_LINE
);
393 * If onlyid is set: if ut_id isn't set but is needed, then set
394 * which to (UT_LINE | UT_ID), otherwise zero
397 which
= (which
& UT_ID
) ? (UT_LINE
| UT_ID
) : 0;
398 if ((which
& UT_LINE
) && !*temp
->ut_line
) {
404 err
= ttyname_r(0, buf
, sizeof(buf
));
406 err
= ttyname_r(1, buf
, sizeof(buf
));
408 err
= ttyname_r(2, buf
, sizeof(buf
));
411 #else /* !__DARWIN_UNIX03 */
412 cp
= ttyname_r(0, buf
, sizeof(buf
));
414 cp
= ttyname_r(1, buf
, sizeof(buf
));
416 cp
= ttyname_r(2, buf
, sizeof(buf
));
419 #endif /* __DARWIN_UNIX03 */
420 cp
= strrchr(buf
, '/');
425 strncpy(temp
->ut_line
, cp
, sizeof(temp
->ut_line
));
427 /* UT_ID is set only if we already know we need to add it */
428 if ((which
& UT_ID
)) {
430 ssize_t i
= sizeof(temp
->ut_line
);
432 for(cp
= temp
->ut_line
; i
> 0 && *cp
; i
--)
434 i
= cp
- temp
->ut_line
;
435 if(i
>= sizeof(temp
->ut_id
))
436 memcpy(temp
->ut_id
, cp
- sizeof(temp
->ut_id
), sizeof(temp
->ut_id
));
438 memcpy(temp
->ut_id
, temp
->ut_line
, i
);
440 if ((which
& UT_PID
) && !temp
->ut_pid
)
441 temp
->ut_pid
= getpid();
442 if ((which
& UT_USER
) && !*temp
->ut_user
) {
446 if ((buf
= _pwuid_r(getuid(), &pw
)) == NULL
)
448 strncpy(temp
->ut_user
, pw
.pw_name
, sizeof(temp
->ut_user
));
451 if ((which
& UT_TV
) && !temp
->ut_tv
.tv_sec
&& !temp
->ut_tv
.tv_usec
)
452 gettimeofday(&temp
->ut_tv
, NULL
);
457 * We can read from either asl or from a file, so we need to switch between
460 static void end_asl(void);
461 static void end_file(void);
462 static struct utmpx
*get_asl(void);
463 static struct utmpx
*get_file(void);
464 static void set_asl(int);
465 static void set_file(int);
467 enum {WTMP_ASL
, WTMP_FILE
};
472 struct utmpx
*(*get
)(void);
489 } wtmp_asl
= {-1, 1};
498 struct utmpx32
*next
;
502 #endif /* __LP64__ */
504 } wtmp_file
= {-1, -1};
515 return wtmp_func
.get();
519 setutxent_wtmp(int dir
)
524 /* use the given file, or if NULL, read from asl */
526 wtmpxname(const char *fname
)
531 if (wtmp_func
.which
== WTMP_ASL
) {
536 wtmp_func
.which
= WTMP_ASL
;
537 wtmp_func
.end
= end_asl
;
538 wtmp_func
.get
= get_asl
;
539 wtmp_func
.set
= set_asl
;
544 if (len
>= MAXPATHLEN
)
548 if (fname
[len
- 1] != 'x')
551 if (wtmp_func
.which
== WTMP_ASL
)
553 else if (wtmp_file
.fd
>= 0) {
559 free(wtmp_file
.file
);
561 wtmp_file
.file
= strdup(fname
);
562 if (wtmp_file
.file
== NULL
)
565 wtmp_func
.which
= WTMP_FILE
;
566 wtmp_func
.end
= end_file
;
567 wtmp_func
.get
= get_file
;
568 wtmp_func
.set
= set_file
;
575 if (wtmp_asl
.res
!= NULL
)
577 asl_release(wtmp_asl
.res
);
588 if (wtmp_file
.fd
>= 0) {
594 wtmp_file
.buf
= NULL
;
598 static struct utmpx
*
602 static struct utmpx utx
;
604 if (wtmp_asl
.inited
== 0) set_asl(-1);
605 if (wtmp_asl
.done
!= 0) return NULL
;
607 m
= asl_next(wtmp_asl
.res
);
610 asl_release(wtmp_asl
.res
);
621 static struct utmpx
*
627 static struct utmpx ux
;
628 #endif /* __LP64__ */
631 if (wtmp_file
.left
> 0) {
633 struct utmpx32
*u
= wtmp_file
.next
;
635 struct utmpx
*u
= wtmp_file
.next
;
636 #endif /* __LP64__ */
637 wtmp_file
.next
+= wtmp_file
.dir
;
644 #endif /* __LP64__ */
645 } else if (wtmp_file
.fd
< 0) {
646 set_file(-1); /* keep current read direction */
647 if (wtmp_file
.fd
< 0)
649 goto get_file_repeat
;
651 if (wtmp_file
.count
<= 0)
655 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
657 n
= WTMP_COUNT
* sizeof(struct utmpx
);
658 #endif /* __LP64__ */
659 if (wtmp_file
.dir
> 0)
660 wtmp_file
.next
= wtmp_file
.buf
;
662 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
664 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
671 cp
= (char *)wtmp_file
.buf
;
673 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
674 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
679 } while((n
-= r
) > 0);
681 wtmp_file
.left
= WTMP_COUNT
;
682 wtmp_file
.count
-= WTMP_COUNT
;
684 goto get_file_repeat
;
688 * This sets the directions for both asl and reading from a file. If forward
692 _set_dir(int forward
)
694 if (forward
< 0) return;
715 asl_object_t q0
, q1
, query
;
723 if (wtmp_asl
.res
!= NULL
)
725 asl_release(wtmp_asl
.res
);
730 * Create a search query that matches either UTMPX_FACILITY
731 * or LASTLOG_FACILITY.
733 q0
= asl_new(ASL_TYPE_QUERY
);
734 if (q0
== NULL
) return;
736 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
738 q1
= asl_new(ASL_TYPE_QUERY
);
745 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
747 query
= asl_new(ASL_TYPE_LIST
);
755 asl_append(query
, q0
);
756 asl_append(query
, q1
);
763 wtmp_asl
.res
= asl_match(NULL
, query
, &cmax
, wtmp_asl
.start
, 0, ASL_QUERY_TIMEOUT
, wtmp_asl
.dir
);
766 if (wtmp_asl
.res
== NULL
) return;
773 set_file(int forward
)
782 if (wtmp_file
.buf
== NULL
&&
783 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
785 if (wtmp_file
.buf
== NULL
&&
786 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
787 #endif /* __LP64__ */
789 if (wtmp_file
.fd
>= 0)
791 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
793 if (fstat(wtmp_file
.fd
, &s
) < 0)
796 * We must have a file at least 2 sizeof(struct utmpx) in size,
797 * with the first struct utmpx matching a signature record.
800 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
802 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
803 #endif /* __LP64__ */
806 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
808 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
809 #endif /* __LP64__ */
811 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
812 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
817 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
818 * either at the beginning or the end, so that all subsequent reads
819 * must contain WTMP_COUNT records.
821 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
822 wtmp_file
.left
= wtmp_file
.count
- c
;
823 wtmp_file
.count
-= wtmp_file
.left
;
825 /* Seek to the end for reverse reading */
826 if (wtmp_file
.dir
< 0) {
828 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
830 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
831 #endif /* __LP64__ */
832 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
836 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
838 n
= wtmp_file
.left
* sizeof(struct utmpx
);
839 #endif /* __LP64__ */
840 cp
= (char *)wtmp_file
.buf
;
842 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
843 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
848 } while((n
-= r
) > 0);
850 /* Point to either the beginning or end of the buffer */
851 if(wtmp_file
.dir
> 0)
852 wtmp_file
.next
= wtmp_file
.buf
;
854 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
866 * these routines assume natural alignment so that struct utmpx32 has
867 * the same size and layout as the 32-bit struct utmpx
869 __private_extern__
void
870 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
872 bzero(u
, sizeof(*u
));
873 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
874 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
875 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
876 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
877 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
878 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
881 __private_extern__
void
882 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
884 bzero(u32
, sizeof(*u32
));
885 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
886 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
887 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
888 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
889 (char *)u
+ offsetof(struct utmpx
, ut_host
),
890 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
892 #endif /* __LP64__ */
896 __private_extern__
void
897 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
900 bzero(u
, sizeof(*u
));
901 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
902 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
903 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
904 u
->ut_time
= ux
->ut_tv
.tv_sec
;
906 #endif /* __LP64__ */
909 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
910 * described in utmp(5). It then returns a value that specifies what
911 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
912 * write utmp only if a matching record with the same ut_line value is found;
913 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
915 __private_extern__
int
917 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
919 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
920 #endif /* __LP64__ */
926 #endif /* __LP64__ */
928 switch (ux
->ut_type
) {
931 bzero(u
->ut_line
, sizeof(u
->ut_line
));
933 bzero(u
->ut_name
, sizeof(u
->ut_name
));
934 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
935 return UTMP_COMPAT_WTMP
;
938 bzero(u
->ut_line
, sizeof(u
->ut_line
));
939 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
940 bzero(u
->ut_name
, sizeof(u
->ut_name
));
941 strcpy(u
->ut_name
, "date");
942 return UTMP_COMPAT_WTMP
;
944 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
946 bzero(u
->ut_name
, sizeof(u
->ut_name
));
947 bzero(u
->ut_host
, sizeof(u
->ut_host
));
948 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
950 return 0; /* skip */;
954 * Write _PATH_LASTLOG given a struct utmp record. We use
955 * advisory record locking.
957 __private_extern__
void
959 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
961 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
962 #endif /* __LP64__ */
969 #endif /* __LP64__ */
972 // sizeof(ux->ut_user) > sizeof(u->ut_name)
973 char name
[sizeof(ux
->ut_user
) + 1];
981 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
982 name
[sizeof(ux
->ut_user
)] = 0;
986 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
987 name
[sizeof(u
->ut_name
)] = 0;
989 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
992 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
994 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
995 #endif /* __LP64__ */
998 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
1000 (void)lseek(fd
, off
, SEEK_SET
);
1001 bzero(&lock
, sizeof(lock
));
1002 lock
.l_type
= F_WRLCK
;
1003 lock
.l_whence
= SEEK_SET
;
1006 lock
.l_len
= sizeof(struct lastlog32
);
1007 #else /* __LP64__ */
1008 lock
.l_len
= sizeof(struct lastlog
);
1009 #endif /* __LP64__ */
1010 /* try to lock, but give up after retry times, and write anyways */
1011 while(retry
-- > 0) {
1012 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1016 l
.ll_time
= u
->ut_time
;
1017 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1018 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1019 (void) write(fd
, &l
, sizeof(l
));
1020 lock
.l_type
= F_UNLCK
;
1021 (void) fcntl(fd
, F_SETLK
, &lock
);
1026 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1029 __private_extern__
void
1031 _write_utmp(const struct utmp32
*u
, int mustexist
)
1032 #else /* __LP64__ */
1033 _write_utmp(const struct utmp
*u
, int mustexist
)
1034 #endif /* __LP64__ */
1037 struct ttyent
*ttyp
;
1040 #else /* __LP64__ */
1042 #endif /* __LP64__ */
1045 char line
[sizeof(u
->ut_line
)];
1049 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1052 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1056 /* do equivalent of ttyslot(), but using u->ut_line */
1061 if ((ttyp
= getttyent()) == NULL
)
1063 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1064 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1074 if (!found
) { /* no assigned slot */
1076 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1077 #else /* __LP64__ */
1078 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1079 #endif /* __LP64__ */
1081 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1083 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1084 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1093 if (!found
&& mustexist
) {
1098 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1099 (void)write(fd
, u
, sizeof(struct utmp32
));
1100 #else /* __LP64__ */
1101 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1102 (void)write(fd
, u
, sizeof(struct utmp
));
1103 #endif /* __LP64__ */
1108 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1109 * given struct utmpx.
1111 __private_extern__
void
1112 _write_utmp_compat(const struct utmpx
*ux
)
1116 #else /* __LP64__ */
1118 #endif /* __LP64__ */
1121 which
= _utmp_compat(ux
, &u
);
1122 if (which
& UTMP_COMPAT_UTMP0
)
1124 else if (which
& UTMP_COMPAT_UTMP1
)
1126 if (which
& UTMP_COMPAT_WTMP
)
1128 if (which
& UTMP_COMPAT_LASTLOG
)
1129 _write_lastlog(&u
, ux
);
1132 /* Append a struct wtmp to _PATH_WTMP */
1133 __private_extern__
void
1135 _write_wtmp(const struct utmp32
*u
)
1136 #else /* __LP64__ */
1137 _write_wtmp(const struct utmp
*u
)
1138 #endif /* __LP64__ */
1143 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1145 if (fstat(fd
, &buf
) == 0) {
1146 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1147 (void) ftruncate(fd
, buf
.st_size
);
1151 #endif /* UTMP_COMPAT */
1157 _openutx(const char *name
)
1161 if ((U
= calloc(1, sizeof(struct _utmpx
))) == NULL
)
1163 memcpy(U
->magic
, __utx_magic__
, UTMPX_MAGIC
);
1164 U
->utmpx_mutex
= (pthread_mutex_t
)PTHREAD_MUTEX_INITIALIZER
;
1165 if (__utmpxname(U
, name
) == 0) {
1166 if (!U
->utfile_system
)
1176 _closeutx(utmpx_t u
)
1178 struct _utmpx
*U
= (struct _utmpx
*)u
;
1180 if (!U
|| memcmp(U
->magic
, __utx_magic__
, UTMPX_MAGIC
) != 0) {
1186 if (!U
->utfile_system
)
1193 #pragma clang diagnostic pop