From 1f33eeb683e729681419c29ac831c6e71e6774fa Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 9 Jun 2017 15:01:07 -0500 Subject: Promote dmesg back to lsb. --- toys/lsb/dmesg.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++ toys/pending/dmesg.c | 182 --------------------------------------------------- 2 files changed, 182 insertions(+), 182 deletions(-) create mode 100644 toys/lsb/dmesg.c delete mode 100644 toys/pending/dmesg.c diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c new file mode 100644 index 00000000..30f90e3a --- /dev/null +++ b/toys/lsb/dmesg.c @@ -0,0 +1,182 @@ +/* dmesg.c - display/control kernel ring buffer. + * + * Copyright 2006, 2007 Rob Landley + * + * 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][!Sw]", TOYFLAG_BIN)) + +config DMESG + bool "dmesg" + default y + help + usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w] + + Print or control the kernel ring buffer. + + -C Clear ring buffer without printing + -c Clear ring buffer after printing + -n Set kernel logging LEVEL (1-9) + -r Raw output (with ) + -S Use syslog(2) rather than /dev/kmsg + -s Show the last SIZE many bytes + -T Show human-readable timestamps + -t Don't print timestamps + -w Keep waiting for more output (aka --follow) +*/ + +#define FOR_dmesg +#include "toys.h" +#include + +GLOBALS( + long level; + long size; + + int use_color; + time_t tea; +) + +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, 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) + 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; + + // Drop extras after end of message text. + 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; + + // 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 = TT.tea+time_s; + char *ts = ctime(&t); + + 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. + if (subsystem) { + color(33); + printf("%.*s", subsystem, text); + text += subsystem; + } + color(31*((facpri&7)<=3)); + xputs(text); +} + +static int xklogctl(int type, char *buf, int len) +{ + int rc = klogctl(type, buf, len); + + if (rc<0) perror_exit("klogctl"); + + return rc; +} + +static void dmesg_cleanup(void) +{ + color(0); +} + +void dmesg_main(void) +{ + TT.use_color = isatty(1); + + 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; + + if (toys.optflags&FLAG_T) { + struct sysinfo info; + + sysinfo(&info); + TT.tea = time(0)-info.uptime; + } + + if (!(toys.optflags&FLAG_S)) { + char msg[8193]; // CONSOLE_EXT_LOG_MAX+1 + ssize_t len; + 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 (CFG_TOYBOX_FREE) free(data); + } + +no_output: + // Set the log level? + if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level); + + // Clear the buffer? + if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0); +} diff --git a/toys/pending/dmesg.c b/toys/pending/dmesg.c deleted file mode 100644 index b9156562..00000000 --- a/toys/pending/dmesg.c +++ /dev/null @@ -1,182 +0,0 @@ -/* dmesg.c - display/control kernel ring buffer. - * - * Copyright 2006, 2007 Rob Landley - * - * 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][!Sw]", TOYFLAG_BIN)) - -config DMESG - bool "dmesg" - default n - help - usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w] - - Print or control the kernel ring buffer. - - -C Clear ring buffer without printing - -c Clear ring buffer after printing - -n Set kernel logging LEVEL (1-9) - -r Raw output (with ) - -S Use syslog(2) rather than /dev/kmsg - -s Show the last SIZE many bytes - -T Show human-readable timestamps - -t Don't print timestamps - -w Keep waiting for more output (aka --follow) -*/ - -#define FOR_dmesg -#include "toys.h" -#include - -GLOBALS( - long level; - long size; - - int use_color; - time_t tea; -) - -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, 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) - 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; - - // Drop extras after end of message text. - 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; - - // 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 = TT.tea+time_s; - char *ts = ctime(&t); - - 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. - if (subsystem) { - color(33); - printf("%.*s", subsystem, text); - text += subsystem; - } - color(31*((facpri&7)<=3)); - xputs(text); -} - -static int xklogctl(int type, char *buf, int len) -{ - int rc = klogctl(type, buf, len); - - if (rc<0) perror_exit("klogctl"); - - return rc; -} - -static void dmesg_cleanup(void) -{ - color(0); -} - -void dmesg_main(void) -{ - TT.use_color = isatty(1); - - 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; - - if (toys.optflags&FLAG_T) { - struct sysinfo info; - - sysinfo(&info); - TT.tea = time(0)-info.uptime; - } - - if (!(toys.optflags&FLAG_S)) { - char msg[8193]; // CONSOLE_EXT_LOG_MAX+1 - ssize_t len; - 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 (CFG_TOYBOX_FREE) free(data); - } - -no_output: - // Set the log level? - if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level); - - // Clear the buffer? - if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0); -} -- cgit v1.2.3