2 * Copyright (c) 2005-2008 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>
43 #include <asl_private.h>
44 #include <asl_store.h>
48 #include <mach/mach.h>
49 #include <mach/std_types.h>
51 #include <mach/mach_types.h>
52 #include <servers/bootstrap.h>
58 #endif /* UTMP_COMPAT */
60 extern const char _utmpx_vers
[]; /* in utmpx.c */
61 extern char *asl_list_to_string(asl_search_result_t
*, uint32_t *);
62 extern asl_search_result_t
*asl_list_from_string(const char *);
64 static void msg2lastlogx(const aslmsg
, struct lastlogx
*);
65 static void msg2utmpx(const aslmsg
, struct utmpx
*);
66 static void utmpx2msg(const struct utmpx
*, aslmsg
);
68 static int pw_size
= 0;
70 #define FACILITY "Facility"
73 /* ASL timeout in microseconds */
74 #define ASL_QUERY_TIMEOUT 4000000
76 /* indirection causes argument to be substituted before stringification */
77 #define STR(x) __STRING(x)
80 _pwnam_r(const char *user
, struct passwd
*pw
)
86 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
90 if ((buf
= malloc(pw_size
)) == NULL
)
93 getpwnam_r(user
, pw
, buf
, pw_size
, &p
);
102 _pwuid_r(uid_t uid
, struct passwd
*pw
)
108 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
112 if ((buf
= malloc(pw_size
)) == NULL
)
115 getpwuid_r(uid
, pw
, buf
, pw_size
, &p
);
124 getlastlogx(uid_t uid
, struct lastlogx
*lx
)
130 if ((buf
= _pwuid_r(uid
, &pw
)) == NULL
)
133 l
= getlastlogxbyname(pw
.pw_name
, lx
);
139 getlastlogxbyname(const char *user
, struct lastlogx
*lx
)
143 asl_search_result_t query
, *res
;
146 struct lastlogx
*result
= NULL
;
149 if (!user
|| !*user
) return NULL
;
152 status
= asl_store_open_read(NULL
, &store
);
153 if (status
!= 0) return NULL
;
154 if (store
== NULL
) return NULL
;
157 * We search for the last LASTLOG_FACILITY entry that has the
158 * ut_user entry matching the user's name.
160 if ((m
= asl_new(ASL_TYPE_QUERY
)) == NULL
)
162 asl_store_close(store
);
166 asl_set_query(m
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
167 asl_set_query(m
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
175 asl_store_match_timeout(store
, &query
, &res
, &cmax
, -1, 1, -1, ASL_QUERY_TIMEOUT
);
176 asl_store_close(store
);
179 if (status
!= 0) return NULL
;
180 if (res
== NULL
) return NULL
;
182 m
= aslresponse_next(res
);
185 aslresponse_free(res
);
191 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
)
193 aslresponse_free(res
);
199 aslresponse_free(res
);
205 #define IGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
206 u->p##_##e = strtol(cp, NULL, 10);
207 #define LGET(e,p) IGET(e,p)
208 #define SGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
209 strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
211 /* fill in a struct lastlogx from a aslmsg */
213 msg2lastlogx(const aslmsg m
, struct lastlogx
*u
)
217 bzero(u
, sizeof(*u
));
220 IGET(tv
.tv_usec
, ll
);
224 /* fill in a struct utmpx from a aslmsg */
226 msg2utmpx(const aslmsg m
, struct utmpx
*u
)
230 bzero(u
, sizeof(*u
));
237 IGET(tv
.tv_usec
, ut
);
241 /* fill in a aslmsg from a struct utmpx */
243 utmpx2msg(const struct utmpx
*u
, aslmsg m
)
245 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
247 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
248 asl_set(m, #e, buf); }
249 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
250 asl_set(m, #e, buf); }
251 #define SSET(e) if (*(u->e)) { \
252 strncpy(buf, u->e, sizeof(u->e)); \
253 buf[sizeof(u->e)] = 0; \
254 asl_set(m, #e, buf); \
258 cp
= u
->ut_id
+ sizeof(u
->ut_id
);
259 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
263 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
264 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
265 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
266 asl_set(m
, "ut_id", buf
);
277 static const char *utmpx_types
[] = {
283 "INIT_PROCESS", /* 5 */
284 "LOGIN_PROCESS", /* 6 */
285 "USER_PROCESS", /* 7 */
286 "DEAD_PROCESS", /* 8 */
287 "ACCOUNTING", /* 9 */
288 "SIGNATURE", /* 10 */
289 "SHUTDOWN_TIME", /* 11 */
292 /* send a struct utmpx record using asl */
293 __private_extern__
void
294 _utmpx_asl(const struct utmpx
*u
)
296 aslclient asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); /* could be NULL, but still works */
300 if (u
->ut_type
== EMPTY
)
302 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
307 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
308 * otherwise we use the UTMPX_FACILITY. This makes it easy to
309 * search for lastlog entries, but for wtmp, we have to search
310 * for both facilities.
312 if (u
->ut_type
== USER_PROCESS
)
313 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
315 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
316 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
319 /* Make a visible message for system.log */
320 switch (u
->ut_type
) {
325 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
329 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
333 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
336 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
337 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
339 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
342 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 int 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);
483 asl_search_result_t
*res
;
488 } wtmp_asl
= {-1, 1};
492 char file
[MAXPATHLEN
];
497 struct utmpx32
*next
;
501 #endif /* __LP64__ */
503 } wtmp_file
= {-1, -1};
514 return wtmp_func
.get();
518 setutxent_wtmp(int dir
)
523 /* use the given file, or if NULL, read from asl */
525 wtmpxname(const char *fname
)
530 if (wtmp_func
.which
== WTMP_ASL
) {
535 wtmp_func
.which
= WTMP_ASL
;
536 wtmp_func
.end
= end_asl
;
537 wtmp_func
.get
= get_asl
;
538 wtmp_func
.set
= set_asl
;
543 if (len
>= sizeof(wtmp_file
.file
))
547 if (fname
[len
- 1] != 'x')
550 (void)strlcpy(wtmp_file
.file
, fname
, sizeof(wtmp_file
.file
));
552 if (wtmp_func
.which
== WTMP_ASL
)
554 else if (wtmp_file
.fd
>= 0) {
558 wtmp_func
.which
= WTMP_FILE
;
559 wtmp_func
.end
= end_file
;
560 wtmp_func
.get
= get_file
;
561 wtmp_func
.set
= set_file
;
568 if (wtmp_asl
.res
!= NULL
)
570 aslresponse_free(wtmp_asl
.res
);
581 if (wtmp_file
.fd
>= 0) {
587 wtmp_file
.buf
= NULL
;
591 static struct utmpx
*
595 static struct utmpx utx
;
597 if (wtmp_asl
.inited
== 0) set_asl(-1);
598 if (wtmp_asl
.done
!= 0) return NULL
;
600 m
= aslresponse_next(wtmp_asl
.res
);
603 aslresponse_free(wtmp_asl
.res
);
614 static struct utmpx
*
620 static struct utmpx ux
;
621 #endif /* __LP64__ */
624 if (wtmp_file
.left
> 0) {
626 struct utmpx32
*u
= wtmp_file
.next
;
628 struct utmpx
*u
= wtmp_file
.next
;
629 #endif /* __LP64__ */
630 wtmp_file
.next
+= wtmp_file
.dir
;
637 #endif /* __LP64__ */
638 } else if (wtmp_file
.fd
< 0) {
639 set_file(-1); /* keep current read direction */
640 if (wtmp_file
.fd
< 0)
642 goto get_file_repeat
;
644 if (wtmp_file
.count
<= 0)
648 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
650 n
= WTMP_COUNT
* sizeof(struct utmpx
);
651 #endif /* __LP64__ */
652 if (wtmp_file
.dir
> 0)
653 wtmp_file
.next
= wtmp_file
.buf
;
655 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
657 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
664 cp
= (char *)wtmp_file
.buf
;
666 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
667 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
672 } while((n
-= r
) > 0);
674 wtmp_file
.left
= WTMP_COUNT
;
675 wtmp_file
.count
-= WTMP_COUNT
;
677 goto get_file_repeat
;
681 * This sets the directions for both asl and reading from a file. If forward
685 _set_dir(int forward
)
687 if (forward
< 0) return;
710 asl_search_result_t query
;
720 if (wtmp_asl
.res
!= NULL
)
722 aslresponse_free(wtmp_asl
.res
);
727 status
= asl_store_open_read(NULL
, &store
);
728 if (status
!= 0) return;
729 if (store
== NULL
) return;
732 * Create a search query that matches either UTMPX_FACILITY
733 * or LASTLOG_FACILITY.
735 q0
= asl_new(ASL_TYPE_QUERY
);
736 q1
= asl_new(ASL_TYPE_QUERY
);
738 if ((q0
== NULL
) || (q1
== NULL
))
740 asl_store_close(store
);
741 if (q0
!= NULL
) free(q0
);
742 if (q1
!= NULL
) free(q1
);
746 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
747 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
756 asl_store_match_timeout(store
, &query
, &(wtmp_asl
.res
), &cmax
, wtmp_asl
.start
, 0, wtmp_asl
.dir
, ASL_QUERY_TIMEOUT
);
757 asl_store_close(store
);
762 if (wtmp_asl
.res
== NULL
) return;
769 set_file(int forward
)
778 if (wtmp_file
.buf
== NULL
&&
779 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
781 if (wtmp_file
.buf
== NULL
&&
782 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
783 #endif /* __LP64__ */
785 if (wtmp_file
.fd
>= 0)
787 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
789 if (fstat(wtmp_file
.fd
, &s
) < 0)
792 * We must have a file at least 2 sizeof(struct utmpx) in size,
793 * with the first struct utmpx matching a signature record.
796 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
798 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
799 #endif /* __LP64__ */
802 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
804 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
805 #endif /* __LP64__ */
807 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
808 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
813 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
814 * either at the beginning or the end, so that all subsequent reads
815 * must contain WTMP_COUNT records.
817 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
818 wtmp_file
.left
= wtmp_file
.count
- c
;
819 wtmp_file
.count
-= wtmp_file
.left
;
821 /* Seek to the end for reverse reading */
822 if (wtmp_file
.dir
< 0) {
824 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
826 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
827 #endif /* __LP64__ */
828 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
832 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
834 n
= wtmp_file
.left
* sizeof(struct utmpx
);
835 #endif /* __LP64__ */
836 cp
= (char *)wtmp_file
.buf
;
838 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
839 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
844 } while((n
-= r
) > 0);
846 /* Point to either the beginning or end of the buffer */
847 if(wtmp_file
.dir
> 0)
848 wtmp_file
.next
= wtmp_file
.buf
;
850 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
862 * these routines assume natural alignment so that struct utmpx32 has
863 * the same size and layout as the 32-bit struct utmpx
865 __private_extern__
void
866 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
868 bzero(u
, sizeof(*u
));
869 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
870 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
871 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
872 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
873 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
874 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
877 __private_extern__
void
878 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
880 bzero(u32
, sizeof(*u32
));
881 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
882 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
883 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
884 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
885 (char *)u
+ offsetof(struct utmpx
, ut_host
),
886 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
888 #endif /* __LP64__ */
892 __private_extern__
void
893 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
896 bzero(u
, sizeof(*u
));
897 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
898 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
899 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
900 u
->ut_time
= ux
->ut_tv
.tv_sec
;
902 #endif /* __LP64__ */
905 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
906 * described in utmp(5). It then returns a value that specifies what
907 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
908 * write utmp only if a matching record with the same ut_line value is found;
909 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
911 __private_extern__
int
913 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
915 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
916 #endif /* __LP64__ */
922 #endif /* __LP64__ */
924 switch (ux
->ut_type
) {
927 bzero(u
->ut_line
, sizeof(u
->ut_line
));
929 bzero(u
->ut_name
, sizeof(u
->ut_name
));
930 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
931 return UTMP_COMPAT_WTMP
;
934 bzero(u
->ut_line
, sizeof(u
->ut_line
));
935 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
936 bzero(u
->ut_name
, sizeof(u
->ut_name
));
937 strcpy(u
->ut_name
, "date");
938 return UTMP_COMPAT_WTMP
;
940 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
942 bzero(u
->ut_name
, sizeof(u
->ut_name
));
943 bzero(u
->ut_host
, sizeof(u
->ut_host
));
944 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
946 return 0; /* skip */;
950 * Write _PATH_LASTLOG given a struct utmp record. We use
951 * advisory record locking.
953 __private_extern__
void
955 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
957 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
958 #endif /* __LP64__ */
965 #endif /* __LP64__ */
968 // sizeof(ux->ut_user) > sizeof(u->ut_name)
969 char name
[sizeof(ux
->ut_user
) + 1];
977 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
978 name
[sizeof(ux
->ut_user
)] = 0;
982 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
983 name
[sizeof(u
->ut_name
)] = 0;
985 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
988 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
990 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
991 #endif /* __LP64__ */
994 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
996 (void)lseek(fd
, off
, SEEK_SET
);
997 bzero(&lock
, sizeof(lock
));
998 lock
.l_type
= F_WRLCK
;
999 lock
.l_whence
= SEEK_SET
;
1002 lock
.l_len
= sizeof(struct lastlog32
);
1003 #else /* __LP64__ */
1004 lock
.l_len
= sizeof(struct lastlog
);
1005 #endif /* __LP64__ */
1006 /* try to lock, but give up after retry times, and write anyways */
1007 while(retry
-- > 0) {
1008 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1012 l
.ll_time
= u
->ut_time
;
1013 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1014 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1015 (void) write(fd
, &l
, sizeof(l
));
1016 lock
.l_type
= F_UNLCK
;
1017 (void) fcntl(fd
, F_SETLK
, &lock
);
1022 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1025 __private_extern__
void
1027 _write_utmp(const struct utmp32
*u
, int mustexist
)
1028 #else /* __LP64__ */
1029 _write_utmp(const struct utmp
*u
, int mustexist
)
1030 #endif /* __LP64__ */
1033 struct ttyent
*ttyp
;
1036 #else /* __LP64__ */
1038 #endif /* __LP64__ */
1041 char line
[sizeof(u
->ut_line
)];
1045 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1048 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1052 /* do equivalent of ttyslot(), but using u->ut_line */
1057 if ((ttyp
= getttyent()) == NULL
)
1059 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1060 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1070 if (!found
) { /* no assigned slot */
1072 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1073 #else /* __LP64__ */
1074 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1075 #endif /* __LP64__ */
1077 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1079 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1080 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1089 if (!found
&& mustexist
) {
1094 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1095 (void)write(fd
, u
, sizeof(struct utmp32
));
1096 #else /* __LP64__ */
1097 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1098 (void)write(fd
, u
, sizeof(struct utmp
));
1099 #endif /* __LP64__ */
1104 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1105 * given struct utmpx.
1107 __private_extern__
void
1108 _write_utmp_compat(const struct utmpx
*ux
)
1112 #else /* __LP64__ */
1114 #endif /* __LP64__ */
1117 which
= _utmp_compat(ux
, &u
);
1118 if (which
& UTMP_COMPAT_UTMP0
)
1120 else if (which
& UTMP_COMPAT_UTMP1
)
1122 if (which
& UTMP_COMPAT_WTMP
)
1124 if (which
& UTMP_COMPAT_LASTLOG
)
1125 _write_lastlog(&u
, ux
);
1128 /* Append a struct wtmp to _PATH_WTMP */
1129 __private_extern__
void
1131 _write_wtmp(const struct utmp32
*u
)
1132 #else /* __LP64__ */
1133 _write_wtmp(const struct utmp
*u
)
1134 #endif /* __LP64__ */
1139 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1141 if (fstat(fd
, &buf
) == 0) {
1142 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1143 (void) ftruncate(fd
, buf
.st_size
);
1147 #endif /* UTMP_COMPAT */