changeset 1163:972d4fc0c8a2 draft

Two more commands (last and more) submitted by Ashwini Sharma.
author Rob Landley <rob@landley.net>
date Mon, 23 Dec 2013 09:36:14 -0600
parents 213c00e7978e
children 9482222e51f5
files toys/pending/last.c toys/pending/more.c
diffstat 2 files changed, 324 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/last.c	Mon Dec 23 09:36:14 2013 -0600
@@ -0,0 +1,203 @@
+/* last.c - Show listing of last logged in users.
+ *
+ * Copyright 2013 Ranjan Kumar <ranjankumar.bth@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * 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 <utmp.h>
+
+#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]));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/more.c	Mon Dec 23 09:36:14 2013 -0600
@@ -0,0 +1,121 @@
+/* more.c - View FILE (or stdin) one screenful at a time.
+ *
+ * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com>
+ *
+ * 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 <signal.h>
+
+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;
+}