From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- release/src/router/busybox/miscutils/last_fancy.c | 297 ++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 release/src/router/busybox/miscutils/last_fancy.c (limited to 'release/src/router/busybox/miscutils/last_fancy.c') diff --git a/release/src/router/busybox/miscutils/last_fancy.c b/release/src/router/busybox/miscutils/last_fancy.c new file mode 100644 index 00000000..f3ea0375 --- /dev/null +++ b/release/src/router/busybox/miscutils/last_fancy.c @@ -0,0 +1,297 @@ +/* vi: set sw=4 ts=4: */ +/* + * (sysvinit like) last implementation + * + * Copyright (C) 2008 by Patricia Muscalu + * + * Licensed under the GPLv2 or later, see the file LICENSE in this tarball. + */ + +#include "libbb.h" +#include + +/* NB: ut_name and ut_user are the same field, use only one name (ut_user) + * to reduce confusion */ + +#ifndef SHUTDOWN_TIME +# define SHUTDOWN_TIME 254 +#endif + +#define HEADER_FORMAT "%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n" +#define HEADER_LINE "USER", "TTY", \ + INET_ADDRSTRLEN, INET_ADDRSTRLEN, "HOST", "LOGIN", " TIME", "" +#define HEADER_LINE_WIDE "USER", "TTY", \ + INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", " TIME", "" + +enum { + NORMAL, + LOGGED, + DOWN, + REBOOT, + CRASH, + GONE +}; + +enum { + LAST_OPT_W = (1 << 0), /* -W wide */ + LAST_OPT_f = (1 << 1), /* -f input file */ + LAST_OPT_H = (1 << 2), /* -H header */ +}; + +#define show_wide (option_mask32 & LAST_OPT_W) + +static void show_entry(struct utmp *ut, int state, time_t dur_secs) +{ + unsigned days, hours, mins; + char duration[32]; + char login_time[17]; + char logout_time[8]; + const char *logout_str; + const char *duration_str; + time_t tmp; + + /* manpages say ut_tv.tv_sec *is* time_t, + * but some systems have it wrong */ + tmp = ut->ut_tv.tv_sec; + safe_strncpy(login_time, ctime(&tmp), 17); + snprintf(logout_time, 8, "- %s", ctime(&dur_secs) + 11); + + dur_secs = MAX(dur_secs - (time_t)ut->ut_tv.tv_sec, (time_t)0); + /* unsigned int is easier to divide than time_t (which may be signed long) */ + mins = dur_secs / 60; + days = mins / (24*60); + mins = mins % (24*60); + hours = mins / 60; + mins = mins % 60; + +// if (days) { + sprintf(duration, "(%u+%02u:%02u)", days, hours, mins); +// } else { +// sprintf(duration, " (%02u:%02u)", hours, mins); +// } + + logout_str = logout_time; + duration_str = duration; + switch (state) { + case NORMAL: + break; + case LOGGED: + logout_str = " still"; + duration_str = "logged in"; + break; + case DOWN: + logout_str = "- down "; + break; + case REBOOT: + break; + case CRASH: + logout_str = "- crash"; + break; + case GONE: + logout_str = " gone"; + duration_str = "- no logout"; + break; + } + + printf(HEADER_FORMAT, + ut->ut_user, + ut->ut_line, + show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, + show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, + ut->ut_host, + login_time, + logout_str, + duration_str); +} + +static int get_ut_type(struct utmp *ut) +{ + if (ut->ut_line[0] == '~') { + if (strcmp(ut->ut_user, "shutdown") == 0) { + return SHUTDOWN_TIME; + } + if (strcmp(ut->ut_user, "reboot") == 0) { + return BOOT_TIME; + } + if (strcmp(ut->ut_user, "runlevel") == 0) { + return RUN_LVL; + } + return ut->ut_type; + } + + if (ut->ut_user[0] == 0) { + return DEAD_PROCESS; + } + + if ((ut->ut_type != DEAD_PROCESS) + && (strcmp(ut->ut_user, "LOGIN") != 0) + && ut->ut_user[0] + && ut->ut_line[0] + ) { + ut->ut_type = USER_PROCESS; + } + + if (strcmp(ut->ut_user, "date") == 0) { + if (ut->ut_line[0] == '|') { + return OLD_TIME; + } + if (ut->ut_line[0] == '{') { + return NEW_TIME; + } + } + return ut->ut_type; +} + +static int is_runlevel_shutdown(struct utmp *ut) +{ + if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) { + return 1; + } + + return 0; +} + +int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int last_main(int argc UNUSED_PARAM, char **argv) +{ + struct utmp ut; + const char *filename = _PATH_WTMP; + llist_t *zlist; + off_t pos; + time_t start_time; + time_t boot_time; + time_t down_time; + int file; + unsigned opt; + smallint going_down; + smallint boot_down; + + opt = getopt32(argv, "Wf:" /* "H" */, &filename); +#ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT + if (opt & LAST_OPT_H) { + /* Print header line */ + if (opt & LAST_OPT_W) { + printf(HEADER_FORMAT, HEADER_LINE_WIDE); + } else { + printf(HEADER_FORMAT, HEADER_LINE); + } + } +#endif + + file = xopen(filename, O_RDONLY); + { + /* in case the file is empty... */ + struct stat st; + fstat(file, &st); + start_time = st.st_ctime; + } + + time(&down_time); + going_down = 0; + boot_down = NORMAL; /* 0 */ + zlist = NULL; + boot_time = 0; + /* get file size, rounding down to last full record */ + pos = xlseek(file, 0, SEEK_END) / sizeof(ut) * sizeof(ut); + for (;;) { + pos -= (off_t)sizeof(ut); + if (pos < 0) { + /* Beyond the beginning of the file boundary => + * the whole file has been read. */ + break; + } + xlseek(file, pos, SEEK_SET); + xread(file, &ut, sizeof(ut)); + /* rewritten by each record, eventially will have + * first record's ut_tv.tv_sec: */ + start_time = ut.ut_tv.tv_sec; + + switch (get_ut_type(&ut)) { + case SHUTDOWN_TIME: + down_time = ut.ut_tv.tv_sec; + boot_down = DOWN; + going_down = 1; + break; + case RUN_LVL: + if (is_runlevel_shutdown(&ut)) { + down_time = ut.ut_tv.tv_sec; + going_down = 1; + boot_down = DOWN; + } + break; + case BOOT_TIME: + strcpy(ut.ut_line, "system boot"); + show_entry(&ut, REBOOT, down_time); + boot_down = CRASH; + going_down = 1; + break; + case DEAD_PROCESS: + if (!ut.ut_line[0]) { + break; + } + /* add_entry */ + llist_add_to(&zlist, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut))); + break; + case USER_PROCESS: { + int show; + + if (!ut.ut_line[0]) { + break; + } + /* find_entry */ + show = 1; + { + llist_t *el, *next; + for (el = zlist; el; el = next) { + struct utmp *up = (struct utmp *)el->data; + next = el->link; + if (strncmp(up->ut_line, ut.ut_line, UT_LINESIZE) == 0) { + if (show) { + show_entry(&ut, NORMAL, up->ut_tv.tv_sec); + show = 0; + } + llist_unlink(&zlist, el); + free(el->data); + free(el); + } + } + } + + if (show) { + int state = boot_down; + + if (boot_time == 0) { + state = LOGGED; + /* Check if the process is alive */ + if ((ut.ut_pid > 0) + && (kill(ut.ut_pid, 0) != 0) + && (errno == ESRCH)) { + state = GONE; + } + } + show_entry(&ut, state, boot_time); + } + /* add_entry */ + llist_add_to(&zlist, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut))); + break; + } + } + + if (going_down) { + boot_time = ut.ut_tv.tv_sec; + llist_free(zlist, free); + zlist = NULL; + going_down = 0; + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + llist_free(zlist, free); + } + + printf("\nwtmp begins %s", ctime(&start_time)); + + if (ENABLE_FEATURE_CLEAN_UP) + close(file); + fflush_stdout_and_exit(EXIT_SUCCESS); +} -- cgit v1.2.3-54-g00ecf