1 /* vi: set sw=4 ts=4: */
3 * last implementation for busybox
5 * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org>
7 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
13 /* NB: ut_name and ut_user are the same field, use only one name (ut_user)
14 * to reduce confusion */
17 # define SHUTDOWN_TIME 254
20 /* Grr... utmp char[] members do not have to be nul-terminated.
21 * Do what we can while still keeping this reasonably small.
22 * Note: We are assuming the ut_id[] size is fixed at 4. */
24 #if defined UT_LINESIZE \
25 && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256))
26 #error struct utmp member char[] size(s) have changed!
27 #elif defined __UT_LINESIZE \
28 && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 64) || (__UT_HOSTSIZE != 256))
29 #error struct utmp member char[] size(s) have changed!
32 #if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \
34 #error Values for the ut_type field of struct utmp changed
37 int last_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
38 int last_main(int argc
, char **argv UNUSED_PARAM
)
41 int n
, file
= STDIN_FILENO
;
44 static const char _ut_usr
[] ALIGN1
=
45 "runlevel\0" "reboot\0" "shutdown\0";
46 static const char _ut_lin
[] ALIGN1
=
47 "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */;
49 TYPE_RUN_LVL
= RUN_LVL
, /* 1 */
50 TYPE_BOOT_TIME
= BOOT_TIME
, /* 2 */
51 TYPE_SHUTDOWN_TIME
= SHUTDOWN_TIME
54 _TILDE
= EMPTY
, /* 0 */
55 TYPE_NEW_TIME
, /* NEW_TIME, 3 */
56 TYPE_OLD_TIME
/* OLD_TIME, 4 */
62 file
= xopen(bb_path_wtmp_file
, O_RDONLY
);
64 printf("%-10s %-14s %-18s %-12.12s %s\n",
65 "USER", "TTY", "HOST", "LOGIN", "TIME");
66 /* yikes. We reverse over the file and that is a not too elegant way */
67 pos
= xlseek(file
, 0, SEEK_END
);
68 pos
= lseek(file
, pos
- sizeof(ut
), SEEK_SET
);
69 while ((n
= full_read(file
, &ut
, sizeof(ut
))) > 0) {
70 if (n
!= sizeof(ut
)) {
71 bb_perror_msg_and_die("short read");
73 n
= index_in_strings(_ut_lin
, ut
.ut_line
);
74 if (n
== _TILDE
) { /* '~' */
76 /* do we really need to be cautious here? */
77 n
= index_in_strings(_ut_usr
, ut
.ut_user
);
79 ut
.ut_type
= n
!= 3 ? n
: SHUTDOWN_TIME
;
81 if (strncmp(ut
.ut_user
, "shutdown", 8) == 0)
82 ut
.ut_type
= SHUTDOWN_TIME
;
83 else if (strncmp(ut
.ut_user
, "reboot", 6) == 0)
84 ut
.ut_type
= BOOT_TIME
;
85 else if (strncmp(ut
.ut_user
, "runlevel", 8) == 0)
89 if (ut
.ut_user
[0] == '\0' || strcmp(ut
.ut_user
, "LOGIN") == 0) {
90 /* Don't bother. This means we can't find how long
91 * someone was logged in for. Oh well. */
94 if (ut
.ut_type
!= DEAD_PROCESS
95 && ut
.ut_user
[0] && ut
.ut_line
[0]
97 ut
.ut_type
= USER_PROCESS
;
99 if (strcmp(ut
.ut_user
, "date") == 0) {
100 if (n
== TYPE_OLD_TIME
) { /* '|' */
101 ut
.ut_type
= OLD_TIME
;
103 if (n
== TYPE_NEW_TIME
) { /* '{' */
104 ut
.ut_type
= NEW_TIME
;
109 if (ut
.ut_type
!= USER_PROCESS
) {
110 switch (ut
.ut_type
) {
117 strcpy(ut
.ut_line
, "system boot");
120 /* manpages say ut_tv.tv_sec *is* time_t,
121 * but some systems have it wrong */
122 t_tmp
= (time_t)ut
.ut_tv
.tv_sec
;
123 printf("%-10s %-14s %-18s %-12.12s\n",
124 ut
.ut_user
, ut
.ut_line
, ut
.ut_host
, ctime(&t_tmp
) + 4);
129 xlseek(file
, pos
, SEEK_SET
);
132 fflush_stdout_and_exit(EXIT_SUCCESS
);