OSDN Git Service

Cleanup dmesg (as posted to the list).
authorRob Landley <rob@landley.net>
Fri, 9 Jun 2017 19:59:51 +0000 (14:59 -0500)
committerRob Landley <rob@landley.net>
Fri, 9 Jun 2017 19:59:51 +0000 (14:59 -0500)
toys/pending/dmesg.c

index 198f64a..b915656 100644 (file)
@@ -2,10 +2,13 @@
  *
  * Copyright 2006, 2007 Rob Landley <rob@landley.net>
  *
- * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
+ *
+ * Don't ask me why the horrible new dmesg API is still in "testing":
+ * http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
 
 // We care that FLAG_c is 1, so keep c at the end.
-USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc]", TOYFLAG_BIN))
+USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]", TOYFLAG_BIN))
 
 config DMESG
   bool "dmesg"
@@ -35,7 +38,7 @@ GLOBALS(
   long size;
 
   int use_color;
-  struct sysinfo info;
+  time_t tea;
 )
 
 static void color(int c)
@@ -43,50 +46,44 @@ static void color(int c)
   if (TT.use_color) printf("\033[%dm", c);
 }
 
-static void format_message(char *msg, int new) {
-  unsigned long long time_s;
-  unsigned long long time_us;
+static void format_message(char *msg, int new)
+{
+  unsigned long long time_s, time_us;
   int facpri, subsystem, pos;
   char *p, *text;
 
   // The new /dev/kmsg and the old syslog(2) formats differ slightly.
   if (new) {
-    if (sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos) != 2)
+    if (sscanf(msg, "%u,%*u,%llu,%*[^;]; %n", &facpri, &time_us, &pos) != 2)
       return;
 
     time_s = time_us/1000000;
     time_us %= 1000000;
-  } else {
-    if (sscanf(msg, "<%u>[%llu.%llu] %n",
-               &facpri, &time_s, &time_us, &pos) != 3)
-      return;
-  }
+  } else if (sscanf(msg, "<%u>[%llu.%llu] %n",
+                    &facpri, &time_s, &time_us, &pos) != 3) return;
 
   // Drop extras after end of message text.
-  text = msg + pos;
-  if ((p = strchr(text, '\n'))) *p = 0;
+  if ((p = strchr(text = msg+pos, '\n'))) *p = 0;
 
   // Is there a subsystem? (The ": " is just a convention.)
   p = strstr(text, ": ");
-  subsystem = p ? (p - text) : 0;
+  subsystem = p ? (p-text) : 0;
 
-  // "Raw" is a lie for /dev/kmsg. In practice, it just means we show the
-  // syslog facility/priority at the start of each line to emulate the
-  // historical syslog(2) format.
-  if (toys.optflags&FLAG_r) printf("<%d>", facpri);
+  // To get "raw" output for /dev/kmsg we need to add priority to each line
+  if (toys.optflags&FLAG_r) {
+    color(0);
+    printf("<%d>", facpri);
+  }
 
   // Format the time.
   if (!(toys.optflags&FLAG_t)) {
     color(32);
     if (toys.optflags&FLAG_T) {
-      time_t t = (time(NULL) - TT.info.uptime) + time_s;
+      time_t t = TT.tea+time_s;
       char *ts = ctime(&t);
 
-      printf("[%.*s] ", (int)(strlen(ts) - 1), ts);
-    } else {
-      printf("[%5lld.%06lld] ", time_s, time_us);
-    }
-    color(0);
+      printf("[%.*s] ", (int)(strlen(ts)-1), ts);
+    } else printf("[%5lld.%06lld] ", time_s, time_us);
   }
 
   // Errors (or worse) are shown in red, subsystems are shown in yellow.
@@ -94,15 +91,9 @@ static void format_message(char *msg, int new) {
     color(33);
     printf("%.*s", subsystem, text);
     text += subsystem;
-    color(0);
-  }
-  if (!((facpri&7) <= 3)) xputs(text);
-  else {
-    color(31);
-    printf("%s", text);
-    color(0);
-    xputc('\n');
   }
+  color(31*((facpri&7)<=3));
+  xputs(text);
 }
 
 static int xklogctl(int type, char *buf, int len)
@@ -114,74 +105,75 @@ static int xklogctl(int type, char *buf, int len)
   return rc;
 }
 
-// Use klogctl for reading if we're on a pre-3.5 kernel.
-static void legacy_mode()
+static void dmesg_cleanup(void)
 {
-  char *data, *to, *from;
-  int size;
-
-  // Figure out how much data we need, and fetch it.
-  if (!(size = TT.size)) size = xklogctl(10, 0, 0);
-  data = to = from = xmalloc(size+1);
-  data[size = xklogctl(3 + (toys.optflags & FLAG_c), data, size)] = 0;
-
-  // Break into messages (one per line) and send each one to format_message.
-  to = data + size;
-  while (from < to) {
-    char *msg_end = memchr(from, '\n', (to-from));
-
-    if (!msg_end) break;
-    *msg_end = '\0';
-    format_message(from, 0);
-    from = msg_end + 1;
-  }
-
-  if (CFG_TOYBOX_FREE) free(data);
+  color(0);
 }
 
-static void print_all(void)
+void dmesg_main(void)
 {
-  if (toys.optflags&FLAG_T) sysinfo(&TT.info);
-  if (toys.optflags&FLAG_S) return legacy_mode();
+  TT.use_color = isatty(1);
 
-  // http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
+  if (TT.use_color) sigatexit(dmesg_cleanup);
+  // If we're displaying output, is it klogctl or /dev/kmsg?
+  if (toys.optflags & (FLAG_C|FLAG_n)) goto no_output;
 
-  // Each read returns one message. By default, we block when there are no
-  // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
-  int fd = xopen("/dev/kmsg", O_RDONLY | ((toys.optflags&FLAG_w)?0:O_NONBLOCK));
+  if (toys.optflags&FLAG_T) {
+    struct sysinfo info;
 
-  // With /dev/kmsg, SYSLOG_ACTION_CLEAR (5) doesn't actually remove anything;
-  // you need to seek to the last clear point.
-  lseek(fd, 0, SEEK_DATA);
+    sysinfo(&info);
+    TT.tea = time(0)-info.uptime;
+  }
 
-  while (1) {
-    char msg[8192]; // CONSOLE_EXT_LOG_MAX.
+  if (!(toys.optflags&FLAG_S)) {
+    char msg[8193]; // CONSOLE_EXT_LOG_MAX+1
     ssize_t len;
-
-    // kmsg fails with EPIPE if we try to read while the buffer moves under
-    // us; the next read will succeed and return the next available entry.
-    do {
-      len = read(fd, msg, sizeof(msg));
-    } while (len == -1 && errno == EPIPE);
-    // All reads from kmsg fail if you're on a pre-3.5 kernel.
-    if (len == -1 && errno == EINVAL) {
-      close(fd);
-      return legacy_mode();
+    int fd;
+
+    // Each read returns one message. By default, we block when there are no
+    // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
+    fd = open("/dev/kmsg", O_RDONLY|(O_NONBLOCK*!(toys.optflags&FLAG_w)));
+    if (fd == -1) goto klogctl_mode;
+
+    // SYSLOG_ACTION_CLEAR(5) doesn't actually remove anything from /dev/kmsg,
+    // you need to seek to the last clear point.
+    lseek(fd, 0, SEEK_DATA);
+
+    for (;;) {
+      // why does /dev/kmesg return EPIPE instead of EAGAIN if oldest message
+      // expires as we read it?
+      if (-1==(len = read(fd, msg, sizeof(msg))) && errno==EPIPE) continue;
+      // read() from kmsg always fails on a pre-3.5 kernel.
+      if (len==-1 && errno==EINVAL) goto klogctl_mode;
+      if (len<1) break;
+
+      msg[len] = 0;
+      format_message(msg, 1);
+    }
+    close(fd);
+  } else {
+    char *data, *to, *from, *end;
+    int size;
+
+klogctl_mode:
+    // Figure out how much data we need, and fetch it.
+    if (!(size = TT.size)) size = xklogctl(10, 0, 0);
+    data = from = xmalloc(size+1);
+    data[size = xklogctl(3+(toys.optflags&FLAG_c), data, size)] = 0;
+
+    // Send each line to format_message.
+    to = data + size;
+    while (from < to) {
+      if (!(end = memchr(from, '\n', to-from))) break;
+      *end = 0;
+      format_message(from, 0);
+      from = end + 1;
     }
-    if (len <= 0) break;
 
-    msg[len] = 0;
-    format_message(msg, 1);
+    if (CFG_TOYBOX_FREE) free(data);
   }
-  close(fd);
-}
-
-void dmesg_main(void)
-{
-  TT.use_color = isatty(1);
-
-  if (!(toys.optflags & (FLAG_C|FLAG_n))) print_all();
 
+no_output:
   // Set the log level?
   if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level);