diff options
author | Elliott Hughes <enh@google.com> | 2016-11-11 15:45:33 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2016-11-11 15:45:56 -0800 |
commit | 4be718d62ee544f58f1eb7da188a08b610e14c53 (patch) | |
tree | dd81217bab65cb0ac4f107732838b8628a73d164 /toys | |
parent | 991623dec1421da4d78f5fc3dd8e6694af348166 (diff) | |
parent | 45058fb2735dd5a81a6bd224e35bb34044a02ce5 (diff) | |
download | toybox-4be718d62ee544f58f1eb7da188a08b610e14c53.tar.gz |
Merge remote-tracking branch 'toybox/master' into HEAD
Change-Id: I3a54258f757180bc8a40231ed6a72fc0149943c8
Diffstat (limited to 'toys')
-rw-r--r-- | toys/lsb/dmesg.c | 148 | ||||
-rw-r--r-- | toys/posix/ps.c | 10 | ||||
-rw-r--r-- | toys/posix/split.c | 2 |
3 files changed, 123 insertions, 37 deletions
diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c index d6084466..45319b60 100644 --- a/toys/lsb/dmesg.c +++ b/toys/lsb/dmesg.c @@ -5,21 +5,23 @@ * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html // We care that FLAG_c is 1, so keep c at the end. -USE_DMESG(NEWTOY(dmesg, "trs#<1n#c[!tr]", TOYFLAG_BIN)) +USE_DMESG(NEWTOY(dmesg, "w(follow)Ctrs#<1n#c[!tr]", TOYFLAG_BIN)) config DMESG bool "dmesg" default y help - usage: dmesg [-c] [-r|-t] [-n LEVEL] [-s SIZE] + usage: dmesg [-Cc] [-r|-t] [-n LEVEL] [-s SIZE] [-w] Print or control the kernel ring buffer. + -C Clear the ring buffer -c Clear the ring buffer after printing -n Set kernel logging LEVEL (1-9) -r Raw output (with <level markers>) -s Show the last SIZE many bytes -t Don't print kernel's timestamps + -w Keep waiting for more output (aka --follow) */ #define FOR_dmesg @@ -29,43 +31,125 @@ config DMESG GLOBALS( long level; long size; + + int color; ) +// Use klogctl for reading if we're on a pre-3.5 kernel. +static void legacy_mode() { + char *data, *to, *from; + int size; + + // Figure out how much data we need, and fetch it. + size = TT.size; + if (!size && 1>(size = klogctl(10, 0, 0))) perror_exit("klogctl");; + data = to = from = xmalloc(size+1); + size = klogctl(3 + (toys.optflags & FLAG_c), data, size); + if (size < 0) perror_exit("klogctl"); + data[size] = 0; + + // Filter out level markers and optionally time markers + if (!(toys.optflags & FLAG_r)) while ((from - data) < size) { + if (from == data || from[-1] == '\n') { + char *to; + + if (*from == '<' && (to = strchr(from, '>'))) from = ++to; + if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']'))) + from = to+1+(to[1]==' '); + } + *(to++) = *(from++); + } else to = data+size; + + // Write result. The odds of somebody requesting a buffer of size 3 and + // getting "<1>" are remote, but don't segfault if they do. + if (to != data) { + xwrite(1, data, to-data); + if (to[-1] != '\n') xputc('\n'); + } + if (CFG_TOYBOX_FREE) free(data); +} + +static void color(int c) { + if (TT.color) printf("\033[%dm", c); +} + void dmesg_main(void) { // For -n just tell kernel to which messages to keep. if (toys.optflags & FLAG_n) { if (klogctl(8, NULL, TT.level)) perror_exit("klogctl"); - } else { - char *data, *to, *from; - int size; - - // Figure out how much data we need, and fetch it. - size = TT.size; - if (!size && 1>(size = klogctl(10, 0, 0))) perror_exit("klogctl");; - data = to = from = xmalloc(size+1); - size = klogctl(3 + (toys.optflags & FLAG_c), data, size); - if (size < 0) perror_exit("klogctl"); - data[size] = 0; - - // Filter out level markers and optionally time markers - if (!(toys.optflags & FLAG_r)) while ((from - data) < size) { - if (from == data || from[-1] == '\n') { - char *to; - - if (*from == '<' && (to = strchr(from, '>'))) from = ++to; - if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']'))) - from = to+1+(to[1]==' '); - } - *(to++) = *(from++); - } else to = data+size; - - // Write result. The odds of somebody requesting a buffer of size 3 and - // getting "<1>" are remote, but don't segfault if they do. - if (to != data) { - xwrite(1, data, to-data); - if (to[-1] != '\n') xputc('\n'); + return; + } + + // For -C just tell kernel to throw everything out. + if (toys.optflags & FLAG_C) { + if (klogctl(5, NULL, 0)) perror_exit("klogctl"); + return; + } + + TT.color = isatty(1); + + // http://lxr.free-electrons.com/source/Documentation/ABI/testing/dev-kmsg + + // 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)); + while (1) { + char msg[8192]; // CONSOLE_EXT_LOG_MAX. + unsigned long long time_us; + int facpri, subsystem, pos; + char *p, *text; + 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(); + } + if (len <= 0) break; + + msg[len] = 0; + + if (sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos) != 2) + continue; + + // Drop extras after end of message text. + text = msg + pos; + if ((p = strchr(text, '\n'))) *p = 0; + + // Is there a subsystem? (The ": " is just a convention.) + p = strstr(text, ": "); + 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. + if (toys.optflags&FLAG_r) printf("<%d>", facpri); + + if (!(toys.optflags&FLAG_t)) { + color(32); + printf("[%5lld.%06lld] ", time_us/1000000, time_us%1000000); + color(0); + } + + // Errors (or worse) are shown in red, subsystems are shown in yellow. + if (subsystem) { + color(33); + printf("%.*s", subsystem, text); + text += subsystem; + color(0); + } + if (!((facpri&7) <= 3)) puts(text); + else { + color(31); + printf("%s", text); + color(0); + xputc('\n'); } - if (CFG_TOYBOX_FREE) free(data); } + close(fd); } diff --git a/toys/posix/ps.c b/toys/posix/ps.c index 15acc84f..77d777bd 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -544,8 +544,9 @@ static char *string_field(struct carveup *tb, struct strawberry *field) } // Display process data that get_ps() read from /proc, formatting with TT.fields -static void show_ps(struct carveup *tb) +static void show_ps(void *p) { + struct carveup *tb = p; struct strawberry *field; int pad, len, width = TT.width, abslen, sign, olen, extra = 0; @@ -1215,7 +1216,7 @@ void ps_main(void) // print headers now (for low memory/nommu systems). TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf)); if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf); - if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = (void *)show_ps; + if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = show_ps; TT.match_process = ps_match_process; dt = dirtree_read("/proc", ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT))) @@ -1671,8 +1672,9 @@ static void do_pgk(struct carveup *tb) } } -static void match_pgrep(struct carveup *tb) +static void match_pgrep(void *p) { + struct carveup *tb = p; regmatch_t match; struct regex_list *reg; char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);; @@ -1744,7 +1746,7 @@ void pgrep_main(void) TT.pgrep.regexes = reg; } TT.match_process = pgrep_match_process; - TT.show_process = (void *)match_pgrep; + TT.show_process = match_pgrep; // pgrep should return failure if there are no matches. toys.exitval = 1; diff --git a/toys/posix/split.c b/toys/posix/split.c index 075a4147..98d70c2a 100644 --- a/toys/posix/split.c +++ b/toys/posix/split.c @@ -8,7 +8,7 @@ * - should splitting an empty file produce an empty outfile? (Went with "no".) * - permissions on output file -USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1", TOYFLAG_USR|TOYFLAG_BIN)) +USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1[!bl]", TOYFLAG_USR|TOYFLAG_BIN)) config SPLIT bool "split" |