diff options
Diffstat (limited to 'util-linux/last.c')
-rw-r--r-- | util-linux/last.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/util-linux/last.c b/util-linux/last.c new file mode 100644 index 000000000..b3f125c3f --- /dev/null +++ b/util-linux/last.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * last implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2003-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | //config:config LAST | ||
10 | //config: bool "last" | ||
11 | //config: default y | ||
12 | //config: depends on FEATURE_WTMP | ||
13 | //config: help | ||
14 | //config: 'last' displays a list of the last users that logged into the system. | ||
15 | //config: | ||
16 | //config:config FEATURE_LAST_FANCY | ||
17 | //config: bool "Output extra information" | ||
18 | //config: default y | ||
19 | //config: depends on LAST | ||
20 | //config: help | ||
21 | //config: 'last' displays detailed information about the last users that | ||
22 | //config: logged into the system (mimics sysvinit last). +900 bytes. | ||
23 | |||
24 | //applet:IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||
25 | |||
26 | //kbuild:ifeq ($(CONFIG_FEATURE_LAST_FANCY),y) | ||
27 | //kbuild:lib-$(CONFIG_FEATURE_LAST_FANCY) += last_fancy.o | ||
28 | //kbuild:else | ||
29 | //kbuild:lib-$(CONFIG_LAST) += last.o | ||
30 | //kbuild:endif | ||
31 | |||
32 | //usage:#define last_trivial_usage | ||
33 | //usage: ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]") | ||
34 | //usage:#define last_full_usage "\n\n" | ||
35 | //usage: "Show listing of the last users that logged into the system" | ||
36 | //usage: IF_FEATURE_LAST_FANCY( "\n" | ||
37 | /* //usage: "\n -H Show header line" */ | ||
38 | //usage: "\n -W Display with no host column truncation" | ||
39 | //usage: "\n -f FILE Read from FILE instead of /var/log/wtmp" | ||
40 | //usage: ) | ||
41 | |||
42 | #include "libbb.h" | ||
43 | |||
44 | /* NB: ut_name and ut_user are the same field, use only one name (ut_user) | ||
45 | * to reduce confusion */ | ||
46 | |||
47 | #ifndef SHUTDOWN_TIME | ||
48 | # define SHUTDOWN_TIME 254 | ||
49 | #endif | ||
50 | |||
51 | /* Grr... utmp char[] members do not have to be nul-terminated. | ||
52 | * Do what we can while still keeping this reasonably small. | ||
53 | * Note: We are assuming the ut_id[] size is fixed at 4. */ | ||
54 | |||
55 | #if defined UT_LINESIZE \ | ||
56 | && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256)) | ||
57 | #error struct utmpx member char[] size(s) have changed! | ||
58 | #elif defined __UT_LINESIZE \ | ||
59 | && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 32) || (__UT_HOSTSIZE != 256)) | ||
60 | /* __UT_NAMESIZE was checked with 64 above, but glibc-2.11 definitely uses 32! */ | ||
61 | #error struct utmpx member char[] size(s) have changed! | ||
62 | #endif | ||
63 | |||
64 | #if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \ | ||
65 | OLD_TIME != 4 | ||
66 | #error Values for the ut_type field of struct utmpx changed | ||
67 | #endif | ||
68 | |||
69 | int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
70 | int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
71 | { | ||
72 | struct utmpx ut; | ||
73 | int n, file = STDIN_FILENO; | ||
74 | time_t t_tmp; | ||
75 | off_t pos; | ||
76 | static const char _ut_usr[] ALIGN1 = | ||
77 | "runlevel\0" "reboot\0" "shutdown\0"; | ||
78 | static const char _ut_lin[] ALIGN1 = | ||
79 | "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */; | ||
80 | enum { | ||
81 | TYPE_RUN_LVL = RUN_LVL, /* 1 */ | ||
82 | TYPE_BOOT_TIME = BOOT_TIME, /* 2 */ | ||
83 | TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME | ||
84 | }; | ||
85 | enum { | ||
86 | _TILDE = EMPTY, /* 0 */ | ||
87 | TYPE_NEW_TIME, /* NEW_TIME, 3 */ | ||
88 | TYPE_OLD_TIME /* OLD_TIME, 4 */ | ||
89 | }; | ||
90 | |||
91 | if (argv[1]) { | ||
92 | bb_show_usage(); | ||
93 | } | ||
94 | file = xopen(bb_path_wtmp_file, O_RDONLY); | ||
95 | |||
96 | printf("%-10s %-14s %-18s %-12.12s %s\n", | ||
97 | "USER", "TTY", "HOST", "LOGIN", "TIME"); | ||
98 | /* yikes. We reverse over the file and that is a not too elegant way */ | ||
99 | pos = xlseek(file, 0, SEEK_END); | ||
100 | pos = lseek(file, pos - sizeof(ut), SEEK_SET); | ||
101 | while ((n = full_read(file, &ut, sizeof(ut))) > 0) { | ||
102 | if (n != sizeof(ut)) { | ||
103 | bb_perror_msg_and_die("short read"); | ||
104 | } | ||
105 | n = index_in_strings(_ut_lin, ut.ut_line); | ||
106 | if (n == _TILDE) { /* '~' */ | ||
107 | #if 1 | ||
108 | /* do we really need to be cautious here? */ | ||
109 | n = index_in_strings(_ut_usr, ut.ut_user); | ||
110 | if (++n > 0) | ||
111 | ut.ut_type = n != 3 ? n : SHUTDOWN_TIME; | ||
112 | #else | ||
113 | if (is_prefixed_with(ut.ut_user, "shutdown")) | ||
114 | ut.ut_type = SHUTDOWN_TIME; | ||
115 | else if (is_prefixed_with(ut.ut_user, "reboot")) | ||
116 | ut.ut_type = BOOT_TIME; | ||
117 | else if (is_prefixed_with(ut.ut_user, "runlevel")) | ||
118 | ut.ut_type = RUN_LVL; | ||
119 | #endif | ||
120 | } else { | ||
121 | if (ut.ut_user[0] == '\0' || strcmp(ut.ut_user, "LOGIN") == 0) { | ||
122 | /* Don't bother. This means we can't find how long | ||
123 | * someone was logged in for. Oh well. */ | ||
124 | goto next; | ||
125 | } | ||
126 | if (ut.ut_type != DEAD_PROCESS | ||
127 | && ut.ut_user[0] | ||
128 | && ut.ut_line[0] | ||
129 | ) { | ||
130 | ut.ut_type = USER_PROCESS; | ||
131 | } | ||
132 | if (strcmp(ut.ut_user, "date") == 0) { | ||
133 | if (n == TYPE_OLD_TIME) { /* '|' */ | ||
134 | ut.ut_type = OLD_TIME; | ||
135 | } | ||
136 | if (n == TYPE_NEW_TIME) { /* '{' */ | ||
137 | ut.ut_type = NEW_TIME; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | if (ut.ut_type != USER_PROCESS) { | ||
143 | switch (ut.ut_type) { | ||
144 | case OLD_TIME: | ||
145 | case NEW_TIME: | ||
146 | case RUN_LVL: | ||
147 | case SHUTDOWN_TIME: | ||
148 | goto next; | ||
149 | case BOOT_TIME: | ||
150 | strcpy(ut.ut_line, "system boot"); | ||
151 | } | ||
152 | } | ||
153 | /* manpages say ut_tv.tv_sec *is* time_t, | ||
154 | * but some systems have it wrong */ | ||
155 | t_tmp = (time_t)ut.ut_tv.tv_sec; | ||
156 | printf("%-10s %-14s %-18s %-12.12s\n", | ||
157 | ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4); | ||
158 | next: | ||
159 | pos -= sizeof(ut); | ||
160 | if (pos <= 0) | ||
161 | break; /* done. */ | ||
162 | xlseek(file, pos, SEEK_SET); | ||
163 | } | ||
164 | |||
165 | fflush_stdout_and_exit(EXIT_SUCCESS); | ||
166 | } | ||