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