From 1685bd5be8f50c6bb876bdfe331d8fe20b304648 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 23 Dec 2013 09:36:14 -0600 Subject: Two more commands (last and more) submitted by Ashwini Sharma. --- toys/pending/last.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++ toys/pending/more.c | 121 +++++++++++++++++++++++++++++++ 2 files changed, 324 insertions(+) create mode 100644 toys/pending/last.c create mode 100644 toys/pending/more.c diff --git a/toys/pending/last.c b/toys/pending/last.c new file mode 100644 index 00000000..e2e11f8f --- /dev/null +++ b/toys/pending/last.c @@ -0,0 +1,203 @@ +/* last.c - Show listing of last logged in users. + * + * Copyright 2013 Ranjan Kumar + * Copyright 2013 Kyungwan Han + * + * No Standard. + +USE_LAST(NEWTOY(last, "f:W", TOYFLAG_BIN)) + +config LAST + bool "last" + default n + help + Usage: last [-W] [-f FILE] + + Show listing of last logged in users. + + -W Display the information without host-column truncation. + -f FILE Read from file FILE instead of /var/log/wtmp. +*/ +#define FOR_last + +#include "toys.h" +#include + +#ifndef SHUTDOWN_TIME +#define SHUTDOWN_TIME 254 +#endif + +GLOBALS( + char *file; + struct arg_list *list; +) + +static void free_node(void *data) +{ + void *arg = ((struct arg_list*)data)->arg; + + if (arg) free(arg); + free(data); +} + +static void free_list() +{ + if (TT.list) { + llist_traverse(TT.list, free_node); + TT.list = NULL; + } +} + +static void llist_add_node(struct arg_list **old, void *data) +{ + struct arg_list *new = xmalloc(sizeof(struct arg_list)); + + new->arg = (char*)data; + new->next = *old; + *old = new; +} + +// Find a node and dlink it from the list. +static struct arg_list *find_and_dlink(struct arg_list **list, char *devname) +{ + struct arg_list *l = *list; + + while (*list) { + struct utmp *ut = (struct utmp *)l->arg; + + if (!strncmp(ut->ut_line, devname, UT_LINESIZE)) { + *list = (*list)->next; + return l; + } + list = &(*list)->next; + l = *list; + } + return NULL; +} + +// Compute login, logout and duration of login. +static void seize_duration(time_t tm0, time_t tm1) +{ + unsigned days, hours, mins; + double diff = difftime(tm1, tm0); + + diff = (diff > 0) ? (tm1 - tm0) : 0; + toybuf[0] = toybuf[18] = toybuf[28] = '\0'; + strncpy(toybuf, ctime(&tm0), 16); // Login Time. + snprintf(toybuf+18, 8, "- %s", ctime(&tm1) + 11); // Logout Time. + days = (mins = diff/60)/(24*60); + hours = (mins = (mins%(24*60)))/60; + mins = mins%60; + sprintf(toybuf+28, "(%u+%02u:%02u)", days, hours, mins); // Duration. +} + +void last_main(void) +{ + struct utmp ut; + struct stat sb; + time_t tm[3] = {0,}; //array for time avlues, previous, current + char *file = "/var/log/wtmp"; + int fd, pwidth, curlog_type = EMPTY; + off_t loc; + + if (toys.optflags & FLAG_f) file = TT.file; + + TT.list = NULL; + pwidth = (toys.optflags & FLAG_W) ? 46 : 16; + time(&tm[1]); + fd = xopen(file, O_RDONLY); + loc = xlseek(fd, 0, SEEK_END); + // in case of empty file or 'filesize < sizeof(ut)' + fstat(fd, &sb); + if (sizeof(ut) > sb.st_size) { + xclose(fd); + printf("\n%s begins %-24.24s\n", basename(file), ctime(&sb.st_ctime)); + return; + } + loc = xlseek(fd, loc - sizeof(ut), SEEK_SET); + + while (1) { + xreadall(fd, &ut, sizeof(ut)); + tm[0] = (time_t)ut.ut_tv.tv_sec; + if (ut.ut_line[0] == '~') { + if (!strcmp(ut.ut_user, "runlevel")) ut.ut_type = RUN_LVL; + else if (!strcmp(ut.ut_user, "reboot")) ut.ut_type = BOOT_TIME; + else if (!strcmp(ut.ut_user, "shutdown")) ut.ut_type = SHUTDOWN_TIME; + } + else if (ut.ut_user[0] == '\0') ut.ut_type = DEAD_PROCESS; + else if (ut.ut_user[0] && ut.ut_line[0] && (ut.ut_type != DEAD_PROCESS) + && (strcmp(ut.ut_user, "LOGIN")) ) ut.ut_type = USER_PROCESS; + /* The pair of terminal names '|' / '}' logs the + * old/new system time when date changes it. + */ + if (!strcmp(ut.ut_user, "date")) { + if (ut.ut_line[0] == '|') ut.ut_type = OLD_TIME; + if (ut.ut_line[0] == '{') ut.ut_type = NEW_TIME; + } + if ( (ut.ut_type == SHUTDOWN_TIME) || ((ut.ut_type == RUN_LVL) && + (((ut.ut_pid & 255) == '0') || ((ut.ut_pid & 255) == '6')))) { + tm[1] = tm[2] = (time_t)ut.ut_tv.tv_sec; + free_list(); + curlog_type = RUN_LVL; + } else if (ut.ut_type == BOOT_TIME) { + seize_duration(tm[0], tm[1]); + strncpy(ut.ut_line, "system boot", sizeof("system boot")); + free_list(); + printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, + ut.ut_line, pwidth, pwidth, ut.ut_host, + toybuf, toybuf+18, toybuf+28); + curlog_type = BOOT_TIME; + tm[2] = (time_t)ut.ut_tv.tv_sec; + } else if (ut.ut_type == USER_PROCESS && *ut.ut_line) { + struct arg_list *l = find_and_dlink(&TT.list, ut.ut_line); + if (l) { + struct utmp *u = (struct utmp *)l->arg; + seize_duration(tm[0], u->ut_tv.tv_sec); + printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, + ut.ut_line, pwidth, pwidth, ut.ut_host, + toybuf, toybuf+18, toybuf+28); + free(l->arg); + free(l); + } else { + int type = !tm[2] ? EMPTY : curlog_type; + if (!tm[2]) { //check process's current status (alive or dead). + if ((ut.ut_pid > 0) && (kill(ut.ut_pid, 0)!=0) && (errno == ESRCH)) + type = INIT_PROCESS; + } + seize_duration(tm[0], tm[2]); + switch (type) { + case EMPTY: + strncpy(toybuf+18, " still", sizeof(" still")); + strncpy(toybuf+28, "logged in", sizeof("logged in")); + break; + case RUN_LVL: + strncpy(toybuf+18, "- down ", sizeof("- down ")); + break; + case BOOT_TIME: + strncpy(toybuf+18, "- crash", sizeof("- crash")); + break; + case INIT_PROCESS: + strncpy(toybuf+18, " gone", sizeof(" gone")); + strncpy(toybuf+28, "- no logout", sizeof("- no logout")); + break; + default: + break; + } + printf("%-8.8s %-12.12s %-*.*s %-16.16s %-7.7s %s\n", ut.ut_user, + ut.ut_line, pwidth, pwidth, ut.ut_host, + toybuf, toybuf+18, toybuf+28); + } + llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut))); + } else if (ut.ut_type == DEAD_PROCESS && *ut.ut_line) + llist_add_node(&TT.list, memcpy(xmalloc(sizeof(ut)), &ut, sizeof(ut))); + + loc -= sizeof(ut); + if(loc < 0) break; + xlseek(fd, loc, SEEK_SET); + } // End of while. + + fflush(stdout); + xclose(fd); + if (CFG_TOYBOX_FREE) free_list(); + printf("\n%s begins %-24.24s\n", basename(file), ctime(&tm[0])); +} diff --git a/toys/pending/more.c b/toys/pending/more.c new file mode 100644 index 00000000..78eb4e9c --- /dev/null +++ b/toys/pending/more.c @@ -0,0 +1,121 @@ +/* more.c - View FILE (or stdin) one screenful at a time. + * + * Copyright 2013 Bilal Qureshi + * + * No Standard + +USE_MORE(NEWTOY(more, NULL, TOYFLAG_USR|TOYFLAG_BIN)) + +config MORE + bool "more" + default n + help + Usage: more [FILE]... + + View FILE (or stdin) one screenful at a time. +*/ + +#define FOR_more +#include "toys.h" +#include + +GLOBALS( + struct termios inf; + int cin_fd; +) + +static void signal_handler(int sig) +{ + tcsetattr(TT.cin_fd, TCSANOW, &TT.inf); + xputc('\n'); + signal(sig, SIG_DFL); + raise(sig); + _exit(sig | 128); +} + +static void do_cat_operation(int fd, char *name) +{ + char *buf = NULL; + + if(toys.optc > 1) printf(":::::::::::::::::::::::\n" + "%s\n:::::::::::::::::::::::\n",name); + for (; (buf = get_line(fd)); free(buf)) printf("%s\n", buf); +} + +void more_main() +{ + int ch, lines, input_key = 0, disp_more, more_msg_len; + unsigned rows = 24, cols = 80; + struct stat st; + struct termios newf; + FILE *fp, *cin; + + if (!isatty(STDOUT_FILENO) || !(cin = fopen("/dev/tty", "r"))) { + loopfiles(toys.optargs, do_cat_operation); + toys.exitval = 0; + return; + } + + TT.cin_fd = fileno(cin); + tcgetattr(TT.cin_fd,&TT.inf); + //Prepare terminal for input + memcpy(&newf, &TT.inf, sizeof(struct termios)); + newf.c_lflag &= ~(ICANON | ECHO); + newf.c_cc[VMIN] = 1; + newf.c_cc[VTIME] = 0; + tcsetattr(TT.cin_fd, TCSANOW, &newf); + + sigatexit(signal_handler); + + do { + fp = stdin; + if (*toys.optargs && !(fp = fopen(*toys.optargs, "r"))) { + perror_msg("'%s'", *toys.optargs); + continue; + } + st.st_size = disp_more = more_msg_len = lines = 0; + fstat(fileno(fp), &st); + terminal_size(&cols, &rows); + rows--; + if(toys.optc > 1) { + printf(":::::::::::::::::::::::\n" + "%s\n:::::::::::::::::::::::\n",*toys.optargs); + rows -= 3; + } + + while ((ch = getc(fp)) != EOF) { + if (input_key != 'r' && disp_more) { + more_msg_len = printf("--More-- "); + if (st.st_size) + more_msg_len += printf("(%d%% of %lld bytes)", + (int) (100 * ( (double) ftell(fp) / (double) st.st_size)), + st.st_size); + fflush(NULL); + + while (1) { + input_key = getc(cin); + input_key = tolower(input_key); + printf("\r%*s\r", more_msg_len, ""); // Remove previous msg + if (input_key == ' ' || input_key == '\n' || input_key == 'q' + || input_key == 'r') break; + more_msg_len = printf("(Enter:Next line Space:Next page Q:Quit R:Show the rest)"); + } + more_msg_len = lines = disp_more = 0; + if (input_key == 'q') goto stop; + terminal_size(&cols, &rows); + rows--; + } + + if (ch == '\n') + if (++lines >= rows || input_key == '\n') disp_more = 1; + putchar(ch); + } + fclose(fp); + fflush(NULL); + } while (*toys.optargs && *++toys.optargs); + +stop: + tcsetattr(TT.cin_fd, TCSANOW, &TT.inf); + fclose(cin); + toys.exitval = 0; +} -- cgit v1.2.3