1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#define FOR_last
23#include "toys.h"
24#include <utmp.h>
25
26#ifndef SHUTDOWN_TIME
27#define SHUTDOWN_TIME 254
28#endif
29
30GLOBALS(
31 char *file;
32
33 struct arg_list *list;
34)
35
36static void free_list()
37{
38 if (TT.list) {
39 llist_traverse(TT.list, llist_free_arg);
40 TT.list = NULL;
41 }
42}
43
44static void llist_add_node(struct arg_list **old, void *data)
45{
46 struct arg_list *new = xmalloc(sizeof(struct arg_list));
47
48 new->arg = (char*)data;
49 new->next = *old;
50 *old = new;
51}
52
53
54static struct arg_list *find_and_dlink(struct arg_list **list, char *devname)
55{
56 struct arg_list *l = *list;
57
58 while (*list) {
59 struct utmp *ut = (struct utmp *)l->arg;
60
61 if (!strncmp(ut->ut_line, devname, UT_LINESIZE)) {
62 *list = (*list)->next;
63 return l;
64 }
65 list = &(*list)->next;
66 l = *list;
67 }
68 return NULL;
69}
70
71
72static void seize_duration(time_t tm0, time_t tm1)
73{
74 unsigned days, hours, mins;
75 double diff = difftime(tm1, tm0);
76
77 diff = (diff > 0) ? (tm1 - tm0) : 0;
78 toybuf[0] = toybuf[18] = toybuf[28] = '\0';
79 strncpy(toybuf, ctime(&tm0), 16);
80 snprintf(toybuf+18, 8, "- %s", ctime(&tm1) + 11);
81 days = (mins = diff/60)/(24*60);
82 hours = (mins = (mins%(24*60)))/60;
83 mins = mins%60;
84 sprintf(toybuf+28, "(%u+%02u:%02u)", days, hours, mins);
85}
86
87void last_main(void)
88{
89 struct utmp ut;
90 time_t tm[3] = {0,};
91 char *file = "/var/log/wtmp";
92 int fd, pwidth, curlog_type = EMPTY;
93 off_t loc;
94
95 if (toys.optflags & FLAG_f) file = TT.file;
96
97 pwidth = (toys.optflags & FLAG_W) ? 46 : 16;
98 *tm = time(tm+1);
99 fd = xopenro(file);
100 loc = xlseek(fd, 0, SEEK_END);
101
102
103 for (;;) {
104 loc -= sizeof(ut);
105 if(loc < 0) break;
106 xlseek(fd, loc, SEEK_SET);
107
108
109 xreadall(fd, &ut, sizeof(ut));
110 *tm = ut.ut_tv.tv_sec;
111 if (*ut.ut_line == '~') {
112 if (!strcmp(ut.ut_user, "runlevel")) ut.ut_type = RUN_LVL;
113 else if (!strcmp(ut.ut_user, "reboot")) ut.ut_type = BOOT_TIME;
114 else if (!strcmp(ut.ut_user, "shutdown")) ut.ut_type = SHUTDOWN_TIME;
115 } else if (!*ut.ut_user) ut.ut_type = DEAD_PROCESS;
116 else if (*ut.ut_user && *ut.ut_line && ut.ut_type != DEAD_PROCESS
117 && strcmp(ut.ut_user, "LOGIN")) ut.ut_type = USER_PROCESS;
118
119
120
121 if (!strcmp(ut.ut_user, "date")) {
122 if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME;
123 if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME;
124 }
125
126 if ((ut.ut_type == SHUTDOWN_TIME) || ((ut.ut_type == RUN_LVL) &&
127 (((ut.ut_pid & 255) == '0') || ((ut.ut_pid & 255) == '6'))))
128 {
129 tm[1] = tm[2] = (time_t)ut.ut_tv.tv_sec;
130 free_list();
131 curlog_type = RUN_LVL;
132 } else if (ut.ut_type == BOOT_TIME) {
133 seize_duration(tm[0], tm[1]);
134 strcpy(ut.ut_line, "system boot");
135 free_list();
136 printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user,
137 ut.ut_line, pwidth, pwidth, ut.ut_host,
138 toybuf, toybuf+18, toybuf+28);
139 curlog_type = BOOT_TIME;
140 tm[2] = (time_t)ut.ut_tv.tv_sec;
141 } else if (ut.ut_type == USER_PROCESS && *ut.ut_line) {
142 struct arg_list *l = find_and_dlink(&TT.list, ut.ut_line);
143
144 if (l) {
145 struct utmp *u = (struct utmp *)l->arg;
146 seize_duration(tm[0], u->ut_tv.tv_sec);
147 printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user,
148 ut.ut_line, pwidth, pwidth, ut.ut_host,
149 toybuf, toybuf+18, toybuf+28);
150 free(l->arg);
151 free(l);
152 } else {
153 int type = !tm[2] ? EMPTY : curlog_type;
154 if (!tm[2]) {
155 if ((ut.ut_pid > 0) && (kill(ut.ut_pid, 0)!=0) && (errno == ESRCH))
156 type = INIT_PROCESS;
157 }
158 seize_duration(tm[0], tm[2]);
159 switch (type) {
160 case EMPTY:
161 strcpy(toybuf+18, " still");
162 strcpy(toybuf+28, "logged in");
163 break;
164 case RUN_LVL:
165 strcpy(toybuf+18, "- down ");
166 break;
167 case BOOT_TIME:
168 strcpy(toybuf+18, "- crash");
169 break;
170 case INIT_PROCESS:
171 strcpy(toybuf+18, " gone");
172 strcpy(toybuf+28, "- no logout");
173 break;
174 default:
175 break;
176 }
177 printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user,
178 ut.ut_line, pwidth, pwidth, ut.ut_host,
179 toybuf, toybuf+18, toybuf+28);
180 }
181 llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
182 } else if (ut.ut_type == DEAD_PROCESS && *ut.ut_line)
183 llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut)));
184
185 loc -= sizeof(ut);
186 if(loc < 0) break;
187 xlseek(fd, loc, SEEK_SET);
188 }
189
190 if (CFG_TOYBOX_FREE) {
191 xclose(fd);
192 free_list();
193 }
194
195 xprintf("\n%s begins %-24.24s\n", basename(file), ctime(tm));
196}
197