diff options
-rw-r--r-- | toys/pending/dmesg.c | 168 |
1 files changed, 80 insertions, 88 deletions
diff --git a/toys/pending/dmesg.c b/toys/pending/dmesg.c index 198f64a1..b9156562 100644 --- a/toys/pending/dmesg.c +++ b/toys/pending/dmesg.c @@ -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); |