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>
58 #endif /* UTMP_COMPAT */
60 __private_extern__
const char __utx_magic__
[UTMPX_MAGIC
] = __UTX_MAGIC__
;
62 extern const char _utmpx_vers
[]; /* in utmpx.c */
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 size_t 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)
81 _pwnam_r(const char *user
, struct passwd
*pw
)
87 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
91 if ((buf
= malloc(pw_size
)) == NULL
)
94 getpwnam_r(user
, pw
, buf
, pw_size
, &p
);
104 _pwuid_r(uid_t uid
, struct passwd
*pw
)
110 pw_size
= sysconf(_SC_GETPW_R_SIZE_MAX
);
114 if ((buf
= malloc(pw_size
)) == NULL
)
117 getpwuid_r(uid
, pw
, buf
, pw_size
, &p
);
126 getlastlogx(uid_t uid
, struct lastlogx
*lx
)
132 if ((buf
= _pwuid_r(uid
, &pw
)) == NULL
)
135 l
= getlastlogxbyname(pw
.pw_name
, lx
);
141 getlastlogxbyname(const char *user
, struct lastlogx
*lx
)
145 asl_search_result_t query
, *res
;
148 struct lastlogx
*result
= NULL
;
151 if (!user
|| !*user
) return NULL
;
154 status
= asl_store_open_read(NULL
, &store
);
155 if (status
!= 0) return NULL
;
156 if (store
== NULL
) return NULL
;
159 * We search for the last LASTLOG_FACILITY entry that has the
160 * ut_user entry matching the user's name.
162 if ((m
= asl_new(ASL_TYPE_QUERY
)) == NULL
)
164 asl_store_close(store
);
168 asl_set_query(m
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
169 asl_set_query(m
, "ut_user", user
, ASL_QUERY_OP_EQUAL
);
170 qm
[0] = (asl_msg_t
*)m
;
177 asl_store_match_timeout(store
, &query
, &res
, &cmax
, -1, 1, -1, ASL_QUERY_TIMEOUT
);
178 asl_store_close(store
);
181 if (status
!= 0) return NULL
;
182 if (res
== NULL
) return NULL
;
184 m
= aslresponse_next(res
);
187 aslresponse_free(res
);
193 if ((lx
= (struct lastlogx
*)malloc(sizeof(*lx
))) == NULL
)
195 aslresponse_free(res
);
201 aslresponse_free(res
);
207 #define IGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
208 u->p##_##e = strtol(cp, NULL, 10);
209 #define LGET(e,p) IGET(e,p)
210 #define SGET(e,p) if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
211 strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
213 /* fill in a struct lastlogx from a aslmsg */
215 msg2lastlogx(const aslmsg m
, struct lastlogx
*u
)
219 bzero(u
, sizeof(*u
));
222 IGET(tv
.tv_usec
, ll
);
226 /* fill in a struct utmpx from a aslmsg */
228 msg2utmpx(const aslmsg m
, struct utmpx
*u
)
232 bzero(u
, sizeof(*u
));
239 IGET(tv
.tv_usec
, ut
);
243 /* fill in a aslmsg from a struct utmpx */
245 utmpx2msg(const struct utmpx
*u
, aslmsg m
)
247 char buf
[_UTX_HOSTSIZE
+ 1]; /* the largest string in struct utmpx */
249 #define ISET(e) { snprintf(buf, sizeof(buf), "%d", u->e); \
250 asl_set(m, #e, buf); }
251 #define LSET(e) { snprintf(buf, sizeof(buf), "%ld", u->e); \
252 asl_set(m, #e, buf); }
253 #define SSET(e) if (*(u->e)) { \
254 strncpy(buf, u->e, sizeof(u->e)); \
255 buf[sizeof(u->e)] = 0; \
256 asl_set(m, #e, buf); \
260 cp
= (char *)u
->ut_id
+ sizeof(u
->ut_id
);
261 while(--cp
>= u
->ut_id
&& isprint(*cp
)) {}
265 snprintf(buf
, sizeof(buf
), "0x%02x 0x%02x 0x%02x 0x%02x",
266 (unsigned)u
->ut_id
[0], (unsigned)u
->ut_id
[1],
267 (unsigned)u
->ut_id
[2], (unsigned)u
->ut_id
[3]);
268 asl_set(m
, "ut_id", buf
);
279 static const char *utmpx_types
[] = {
285 "INIT_PROCESS", /* 5 */
286 "LOGIN_PROCESS", /* 6 */
287 "USER_PROCESS", /* 7 */
288 "DEAD_PROCESS", /* 8 */
289 "ACCOUNTING", /* 9 */
290 "SIGNATURE", /* 10 */
291 "SHUTDOWN_TIME", /* 11 */
294 /* send a struct utmpx record using asl */
295 __private_extern__
void
296 _utmpx_asl(const struct utmpx
*u
)
298 aslclient asl
= asl_open(NULL
, NULL
, ASL_OPT_NO_REMOTE
); /* could be NULL, but still works */
302 if (u
->ut_type
== EMPTY
)
304 if ((m
= asl_new(ASL_TYPE_MSG
)) == NULL
) {
309 * If the ut_type is USER_PROCESS, we use the LASTLOG_FACILITY,
310 * otherwise we use the UTMPX_FACILITY. This makes it easy to
311 * search for lastlog entries, but for wtmp, we have to search
312 * for both facilities.
314 if (u
->ut_type
== USER_PROCESS
)
315 asl_set(m
, FACILITY
, LASTLOG_FACILITY
);
317 asl_set(m
, FACILITY
, UTMPX_FACILITY
);
318 asl_set(m
, ASL_KEY_LEVEL
, STR(ASL_LEVEL_NOTICE
));
321 /* Make a visible message for system.log */
322 switch (u
->ut_type
) {
327 sprintf(msg
, "%s: %ld %d", utmpx_types
[u
->ut_type
], u
->ut_tv
.tv_sec
, u
->ut_tv
.tv_usec
);
331 sprintf(msg
, "%s: %d", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
);
335 sprintf(msg
, "%s: %d %.*s", utmpx_types
[u
->ut_type
], (int)u
->ut_pid
, (int)sizeof(u
->ut_line
), u
->ut_line
);
338 if (u
->ut_type
>= 0 && u
->ut_type
< (sizeof(utmpx_types
) / sizeof(*utmpx_types
)))
339 sprintf(msg
, "%s", utmpx_types
[u
->ut_type
]);
341 sprintf(msg
, "ut_type=%d", (int)u
->ut_type
);
344 asl_set(m
, ASL_KEY_MSG
, msg
);
351 #define UT_USER (1 << 0)
352 #define UT_ID (1 << 1)
353 #define UT_LINE (1 << 2)
354 #define UT_PID (1 << 3)
355 #define UT_TV (1 << 4)
357 __private_extern__
const struct utmpx
*
358 _utmpx_working_copy(const struct utmpx
*utx
, struct utmpx
*temp
, int onlyid
)
361 static char idzero
[_UTX_IDSIZE
];
363 if ((utx
->ut_type
& (UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
)) == 0)
365 memcpy(temp
, utx
, sizeof(*temp
));
366 temp
->ut_type
&= ~(UTMPX_AUTOFILL_MASK
| UTMPX_DEAD_IF_CORRESPONDING_MASK
);
368 if ((utx
->ut_type
& UTMPX_AUTOFILL_MASK
) == 0)
371 which
= UT_TV
; /* they all need time */
372 switch(temp
->ut_type
) {
376 which
|= (UT_USER
| UT_LINE
| UT_PID
);
377 /* Set UT_ID if ut_id isn't there */
378 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
385 which
|= (UT_USER
| UT_PID
);
389 /* Set UT_ID if ut_id isn't there. We will also need UT_LINE */
390 if (memcmp(temp
->ut_id
, idzero
, sizeof(temp
->ut_id
)) == 0)
391 which
|= (UT_ID
| UT_LINE
);
395 * If onlyid is set: if ut_id isn't set but is needed, then set
396 * which to (UT_LINE | UT_ID), otherwise zero
399 which
= (which
& UT_ID
) ? (UT_LINE
| UT_ID
) : 0;
400 if ((which
& UT_LINE
) && !*temp
->ut_line
) {
406 err
= ttyname_r(0, buf
, sizeof(buf
));
408 err
= ttyname_r(1, buf
, sizeof(buf
));
410 err
= ttyname_r(2, buf
, sizeof(buf
));
413 #else /* !__DARWIN_UNIX03 */
414 cp
= ttyname_r(0, buf
, sizeof(buf
));
416 cp
= ttyname_r(1, buf
, sizeof(buf
));
418 cp
= ttyname_r(2, buf
, sizeof(buf
));
421 #endif /* __DARWIN_UNIX03 */
422 cp
= strrchr(buf
, '/');
427 strncpy(temp
->ut_line
, cp
, sizeof(temp
->ut_line
));
429 /* UT_ID is set only if we already know we need to add it */
430 if ((which
& UT_ID
)) {
432 int i
= sizeof(temp
->ut_line
);
434 for(cp
= temp
->ut_line
; i
> 0 && *cp
; i
--)
436 i
= cp
- temp
->ut_line
;
437 if(i
>= sizeof(temp
->ut_id
))
438 memcpy(temp
->ut_id
, cp
- sizeof(temp
->ut_id
), sizeof(temp
->ut_id
));
440 memcpy(temp
->ut_id
, temp
->ut_line
, i
);
442 if ((which
& UT_PID
) && !temp
->ut_pid
)
443 temp
->ut_pid
= getpid();
444 if ((which
& UT_USER
) && !*temp
->ut_user
) {
448 if ((buf
= _pwuid_r(getuid(), &pw
)) == NULL
)
450 strncpy(temp
->ut_user
, pw
.pw_name
, sizeof(temp
->ut_user
));
453 if ((which
& UT_TV
) && !temp
->ut_tv
.tv_sec
&& !temp
->ut_tv
.tv_usec
)
454 gettimeofday(&temp
->ut_tv
, NULL
);
459 * We can read from either asl or from a file, so we need to switch between
462 static void end_asl(void);
463 static void end_file(void);
464 static struct utmpx
*get_asl(void);
465 static struct utmpx
*get_file(void);
466 static void set_asl(int);
467 static void set_file(int);
469 enum {WTMP_ASL
, WTMP_FILE
};
474 struct utmpx
*(*get
)(void);
485 asl_search_result_t
*res
;
490 } wtmp_asl
= {-1, 1};
499 struct utmpx32
*next
;
503 #endif /* __LP64__ */
505 } wtmp_file
= {-1, -1};
516 return wtmp_func
.get();
520 setutxent_wtmp(int dir
)
525 /* use the given file, or if NULL, read from asl */
527 wtmpxname(const char *fname
)
532 if (wtmp_func
.which
== WTMP_ASL
) {
537 wtmp_func
.which
= WTMP_ASL
;
538 wtmp_func
.end
= end_asl
;
539 wtmp_func
.get
= get_asl
;
540 wtmp_func
.set
= set_asl
;
545 if (len
>= MAXPATHLEN
)
549 if (fname
[len
- 1] != 'x')
552 if (wtmp_func
.which
== WTMP_ASL
)
554 else if (wtmp_file
.fd
>= 0) {
560 free(wtmp_file
.file
);
562 wtmp_file
.file
= strdup(fname
);
563 if (wtmp_file
.file
== NULL
)
566 wtmp_func
.which
= WTMP_FILE
;
567 wtmp_func
.end
= end_file
;
568 wtmp_func
.get
= get_file
;
569 wtmp_func
.set
= set_file
;
576 if (wtmp_asl
.res
!= NULL
)
578 aslresponse_free(wtmp_asl
.res
);
589 if (wtmp_file
.fd
>= 0) {
595 wtmp_file
.buf
= NULL
;
599 static struct utmpx
*
603 static struct utmpx utx
;
605 if (wtmp_asl
.inited
== 0) set_asl(-1);
606 if (wtmp_asl
.done
!= 0) return NULL
;
608 m
= aslresponse_next(wtmp_asl
.res
);
611 aslresponse_free(wtmp_asl
.res
);
622 static struct utmpx
*
628 static struct utmpx ux
;
629 #endif /* __LP64__ */
632 if (wtmp_file
.left
> 0) {
634 struct utmpx32
*u
= wtmp_file
.next
;
636 struct utmpx
*u
= wtmp_file
.next
;
637 #endif /* __LP64__ */
638 wtmp_file
.next
+= wtmp_file
.dir
;
645 #endif /* __LP64__ */
646 } else if (wtmp_file
.fd
< 0) {
647 set_file(-1); /* keep current read direction */
648 if (wtmp_file
.fd
< 0)
650 goto get_file_repeat
;
652 if (wtmp_file
.count
<= 0)
656 n
= WTMP_COUNT
* sizeof(struct utmpx32
);
658 n
= WTMP_COUNT
* sizeof(struct utmpx
);
659 #endif /* __LP64__ */
660 if (wtmp_file
.dir
> 0)
661 wtmp_file
.next
= wtmp_file
.buf
;
663 wtmp_file
.next
= wtmp_file
.buf
+ WTMP_COUNT
- 1;
665 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0) {
672 cp
= (char *)wtmp_file
.buf
;
674 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
675 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
680 } while((n
-= r
) > 0);
682 wtmp_file
.left
= WTMP_COUNT
;
683 wtmp_file
.count
-= WTMP_COUNT
;
685 goto get_file_repeat
;
689 * This sets the directions for both asl and reading from a file. If forward
693 _set_dir(int forward
)
695 if (forward
< 0) return;
718 asl_search_result_t query
;
728 if (wtmp_asl
.res
!= NULL
)
730 aslresponse_free(wtmp_asl
.res
);
735 status
= asl_store_open_read(NULL
, &store
);
736 if (status
!= 0) return;
737 if (store
== NULL
) return;
740 * Create a search query that matches either UTMPX_FACILITY
741 * or LASTLOG_FACILITY.
743 q0
= asl_new(ASL_TYPE_QUERY
);
744 q1
= asl_new(ASL_TYPE_QUERY
);
746 if ((q0
== NULL
) || (q1
== NULL
))
748 asl_store_close(store
);
749 if (q0
!= NULL
) free(q0
);
750 if (q1
!= NULL
) free(q1
);
754 asl_set_query(q0
, FACILITY
, UTMPX_FACILITY
, ASL_QUERY_OP_EQUAL
);
755 asl_set_query(q1
, FACILITY
, LASTLOG_FACILITY
, ASL_QUERY_OP_EQUAL
);
757 m
[0] = (asl_msg_t
*)q0
;
758 m
[1] = (asl_msg_t
*)q1
;
764 asl_store_match_timeout(store
, &query
, &(wtmp_asl
.res
), &cmax
, wtmp_asl
.start
, 0, wtmp_asl
.dir
, ASL_QUERY_TIMEOUT
);
765 asl_store_close(store
);
770 if (wtmp_asl
.res
== NULL
) return;
777 set_file(int forward
)
786 if (wtmp_file
.buf
== NULL
&&
787 (wtmp_file
.buf
= (struct utmpx32
*)malloc(WTMP_COUNT
* sizeof(struct utmpx32
))) == NULL
)
789 if (wtmp_file
.buf
== NULL
&&
790 (wtmp_file
.buf
= (struct utmpx
*)malloc(WTMP_COUNT
* sizeof(struct utmpx
))) == NULL
)
791 #endif /* __LP64__ */
793 if (wtmp_file
.fd
>= 0)
795 if ((wtmp_file
.fd
= open(wtmp_file
.file
, O_RDONLY
, 0)) < 0)
797 if (fstat(wtmp_file
.fd
, &s
) < 0)
800 * We must have a file at least 2 sizeof(struct utmpx) in size,
801 * with the first struct utmpx matching a signature record.
804 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx32
)) <= 1)
806 if ((wtmp_file
.count
= s
.st_size
/ sizeof(struct utmpx
)) <= 1)
807 #endif /* __LP64__ */
810 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx32
)) != sizeof(struct utmpx32
))
812 if (read(wtmp_file
.fd
, wtmp_file
.buf
, sizeof(struct utmpx
)) != sizeof(struct utmpx
))
813 #endif /* __LP64__ */
815 if (strcmp(wtmp_file
.buf
->ut_user
, _utmpx_vers
) != 0 ||
816 wtmp_file
.buf
->ut_type
!= SIGNATURE
)
821 * We will first read any records modulo WTMP_COUNT (or WTMP_COUNT),
822 * either at the beginning or the end, so that all subsequent reads
823 * must contain WTMP_COUNT records.
825 c
= WTMP_COUNT
* ((wtmp_file
.count
- 1) / WTMP_COUNT
);
826 wtmp_file
.left
= wtmp_file
.count
- c
;
827 wtmp_file
.count
-= wtmp_file
.left
;
829 /* Seek to the end for reverse reading */
830 if (wtmp_file
.dir
< 0) {
832 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx32
);
834 wtmp_file
.off
= (c
+ 1) * sizeof(struct utmpx
);
835 #endif /* __LP64__ */
836 if (lseek(wtmp_file
.fd
, wtmp_file
.off
, SEEK_SET
) < 0)
840 n
= wtmp_file
.left
* sizeof(struct utmpx32
);
842 n
= wtmp_file
.left
* sizeof(struct utmpx
);
843 #endif /* __LP64__ */
844 cp
= (char *)wtmp_file
.buf
;
846 if((r
= read(wtmp_file
.fd
, cp
, n
)) <= 0) {
847 if (r
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
852 } while((n
-= r
) > 0);
854 /* Point to either the beginning or end of the buffer */
855 if(wtmp_file
.dir
> 0)
856 wtmp_file
.next
= wtmp_file
.buf
;
858 wtmp_file
.next
= wtmp_file
.buf
+ wtmp_file
.left
- 1;
870 * these routines assume natural alignment so that struct utmpx32 has
871 * the same size and layout as the 32-bit struct utmpx
873 __private_extern__
void
874 _utmpx32_64(const struct utmpx32
*u32
, struct utmpx
*u
)
876 bzero(u
, sizeof(*u
));
877 memcpy(u
, u32
, offsetof(struct utmpx
, ut_type
) + sizeof(u
->ut_type
));
878 u
->ut_tv
.tv_sec
= u32
->ut_tv
.tv_sec
;
879 u
->ut_tv
.tv_usec
= u32
->ut_tv
.tv_usec
;
880 memcpy((char *)u
+ offsetof(struct utmpx
, ut_host
),
881 (char *)u32
+ offsetof(struct utmpx32
, ut_host
),
882 sizeof(struct utmpx
) - offsetof(struct utmpx
, ut_host
));
885 __private_extern__
void
886 _utmpx64_32(const struct utmpx
*u
, struct utmpx32
*u32
)
888 bzero(u32
, sizeof(*u32
));
889 memcpy(u32
, u
, offsetof(struct utmpx32
, ut_type
) + sizeof(u32
->ut_type
));
890 u32
->ut_tv
.tv_sec
= u
->ut_tv
.tv_sec
;
891 u32
->ut_tv
.tv_usec
= u
->ut_tv
.tv_usec
;
892 memcpy((char *)u32
+ offsetof(struct utmpx32
, ut_host
),
893 (char *)u
+ offsetof(struct utmpx
, ut_host
),
894 sizeof(struct utmpx32
) - offsetof(struct utmpx32
, ut_host
));
896 #endif /* __LP64__ */
900 __private_extern__
void
901 _getutmp32(const struct utmpx
*ux
, struct utmp32
*u
)
904 bzero(u
, sizeof(*u
));
905 (void)memcpy(u
->ut_name
, ux
->ut_user
, sizeof(u
->ut_name
));
906 (void)memcpy(u
->ut_line
, ux
->ut_line
, sizeof(u
->ut_line
));
907 (void)memcpy(u
->ut_host
, ux
->ut_host
, sizeof(u
->ut_host
));
908 u
->ut_time
= ux
->ut_tv
.tv_sec
;
910 #endif /* __LP64__ */
913 * _utmp_compat converts a struct utmpx to a struct utmp, using the conventions
914 * described in utmp(5). It then returns a value that specifies what
915 * combination of utmp, wtmp and lastlog to write. UTMP_COMPAT_UTMP1 will
916 * write utmp only if a matching record with the same ut_line value is found;
917 * UTMP_COMPAT_UTMP0 replaces an existing record or writes a new one.
919 __private_extern__
int
921 _utmp_compat(const struct utmpx
*ux
, struct utmp32
*u
)
923 _utmp_compat(const struct utmpx
*ux
, struct utmp
*u
)
924 #endif /* __LP64__ */
930 #endif /* __LP64__ */
932 switch (ux
->ut_type
) {
935 bzero(u
->ut_line
, sizeof(u
->ut_line
));
937 bzero(u
->ut_name
, sizeof(u
->ut_name
));
938 strcpy(u
->ut_name
, (ux
->ut_type
== BOOT_TIME
? "reboot" : "shutdown"));
939 return UTMP_COMPAT_WTMP
;
942 bzero(u
->ut_line
, sizeof(u
->ut_line
));
943 u
->ut_line
[0] = (ux
->ut_type
== OLD_TIME
? '|' : '{');
944 bzero(u
->ut_name
, sizeof(u
->ut_name
));
945 strcpy(u
->ut_name
, "date");
946 return UTMP_COMPAT_WTMP
;
948 return UTMP_COMPAT_UTMP0
| UTMP_COMPAT_WTMP
| UTMP_COMPAT_LASTLOG
;
950 bzero(u
->ut_name
, sizeof(u
->ut_name
));
951 bzero(u
->ut_host
, sizeof(u
->ut_host
));
952 return UTMP_COMPAT_UTMP1
| UTMP_COMPAT_WTMP
;
954 return 0; /* skip */;
958 * Write _PATH_LASTLOG given a struct utmp record. We use
959 * advisory record locking.
961 __private_extern__
void
963 _write_lastlog(const struct utmp32
*u
, const struct utmpx
*ux
)
965 _write_lastlog(const struct utmp
*u
, const struct utmpx
*ux
)
966 #endif /* __LP64__ */
973 #endif /* __LP64__ */
976 // sizeof(ux->ut_user) > sizeof(u->ut_name)
977 char name
[sizeof(ux
->ut_user
) + 1];
985 strncpy(name
, ux
->ut_user
, sizeof(ux
->ut_user
));
986 name
[sizeof(ux
->ut_user
)] = 0;
990 strncpy(name
, u
->ut_name
, sizeof(u
->ut_name
));
991 name
[sizeof(u
->ut_name
)] = 0;
993 if ((buf
= _pwnam_r(name
, &pw
)) == NULL
)
996 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog32
);
998 off
= (off_t
)pw
.pw_uid
* sizeof(struct lastlog
);
999 #endif /* __LP64__ */
1002 if ((fd
= open(_PATH_LASTLOG
, O_WRONLY
, 0)) < 0)
1004 (void)lseek(fd
, off
, SEEK_SET
);
1005 bzero(&lock
, sizeof(lock
));
1006 lock
.l_type
= F_WRLCK
;
1007 lock
.l_whence
= SEEK_SET
;
1010 lock
.l_len
= sizeof(struct lastlog32
);
1011 #else /* __LP64__ */
1012 lock
.l_len
= sizeof(struct lastlog
);
1013 #endif /* __LP64__ */
1014 /* try to lock, but give up after retry times, and write anyways */
1015 while(retry
-- > 0) {
1016 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
1020 l
.ll_time
= u
->ut_time
;
1021 strncpy(l
.ll_line
, u
->ut_line
, sizeof(l
.ll_line
));
1022 strncpy(l
.ll_host
, u
->ut_host
, sizeof(l
.ll_host
));
1023 (void) write(fd
, &l
, sizeof(l
));
1024 lock
.l_type
= F_UNLCK
;
1025 (void) fcntl(fd
, F_SETLK
, &lock
);
1030 * Write _PATH_UTMP, given a struct utmp, depending on the value of
1033 __private_extern__
void
1035 _write_utmp(const struct utmp32
*u
, int mustexist
)
1036 #else /* __LP64__ */
1037 _write_utmp(const struct utmp
*u
, int mustexist
)
1038 #endif /* __LP64__ */
1041 struct ttyent
*ttyp
;
1044 #else /* __LP64__ */
1046 #endif /* __LP64__ */
1049 char line
[sizeof(u
->ut_line
)];
1053 if ((fd
= open(_PATH_UTMP
, O_RDWR
, 0)) < 0)
1056 if (!strncmp(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1060 /* do equivalent of ttyslot(), but using u->ut_line */
1065 if ((ttyp
= getttyent()) == NULL
)
1067 if (!strncmp(ttyp
->ty_name
, u
->ut_line
, sizeof(u
->ut_line
))) {
1068 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1078 if (!found
) { /* no assigned slot */
1080 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1081 #else /* __LP64__ */
1082 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1083 #endif /* __LP64__ */
1085 if (read(fd
, &tmp
, sizeof(tmp
)) != sizeof(tmp
))
1087 if (!strncmp(tmp
.ut_line
, u
->ut_line
, sizeof(u
->ut_line
))) {
1088 strncpy(cache
.line
, u
->ut_line
, sizeof(u
->ut_line
));
1097 if (!found
&& mustexist
) {
1102 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp32
), SEEK_SET
);
1103 (void)write(fd
, u
, sizeof(struct utmp32
));
1104 #else /* __LP64__ */
1105 (void)lseek(fd
, (off_t
)slot
* sizeof(struct utmp
), SEEK_SET
);
1106 (void)write(fd
, u
, sizeof(struct utmp
));
1107 #endif /* __LP64__ */
1112 * Write all the necessary files (utmp, wtmp, lastlog), depending on the
1113 * given struct utmpx.
1115 __private_extern__
void
1116 _write_utmp_compat(const struct utmpx
*ux
)
1120 #else /* __LP64__ */
1122 #endif /* __LP64__ */
1125 which
= _utmp_compat(ux
, &u
);
1126 if (which
& UTMP_COMPAT_UTMP0
)
1128 else if (which
& UTMP_COMPAT_UTMP1
)
1130 if (which
& UTMP_COMPAT_WTMP
)
1132 if (which
& UTMP_COMPAT_LASTLOG
)
1133 _write_lastlog(&u
, ux
);
1136 /* Append a struct wtmp to _PATH_WTMP */
1137 __private_extern__
void
1139 _write_wtmp(const struct utmp32
*u
)
1140 #else /* __LP64__ */
1141 _write_wtmp(const struct utmp
*u
)
1142 #endif /* __LP64__ */
1147 if ((fd
= open(_PATH_WTMP
, O_WRONLY
| O_APPEND
, 0)) < 0)
1149 if (fstat(fd
, &buf
) == 0) {
1150 if (write(fd
, u
, sizeof(*u
)) != sizeof(*u
))
1151 (void) ftruncate(fd
, buf
.st_size
);
1155 #endif /* UTMP_COMPAT */
1161 _openutx(const char *name
)
1165 if ((U
= calloc(1, sizeof(struct _utmpx
))) == NULL
)
1167 memcpy(U
->magic
, __utx_magic__
, UTMPX_MAGIC
);
1168 U
->utmpx_mutex
= (pthread_mutex_t
)PTHREAD_MUTEX_INITIALIZER
;
1169 if (__utmpxname(U
, name
) == 0) {
1170 if (!U
->utfile_system
)
1180 _closeutx(utmpx_t u
)
1182 struct _utmpx
*U
= (struct _utmpx
*)u
;
1184 if (!U
|| memcmp(U
->magic
, __utx_magic__
, UTMPX_MAGIC
) != 0) {
1190 if (!U
->utfile_system
)