1 /* dmesg.c - display/control kernel ring buffer. 2 * 3 * Copyright 2006, 2007 Rob Landley <rob (at) landley.net> 4 * 5 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html 6 7 // We care that FLAG_c is 1, so keep c at the end. 8 USE_DMESG(NEWTOY(dmesg, "w(follow)Ctrs#<1n#c[!tr][!Cc]", TOYFLAG_BIN)) 9 10 config DMESG 11 bool "dmesg" 12 default n 13 help 14 usage: dmesg [-Cc] [-r|-t] [-n LEVEL] [-s SIZE] [-w] 15 16 Print or control the kernel ring buffer. 17 18 -C Clear ring buffer without printing 19 -c Clear ring buffer after printing 20 -n Set kernel logging LEVEL (1-9) 21 -r Raw output (with <level markers>) 22 -s Show the last SIZE many bytes 23 -t Don't print kernel's timestamps 24 -w Keep waiting for more output (aka --follow) 25 */ 26 27 #define FOR_dmesg 28 #include "toys.h" 29 #include <sys/klog.h> 30 31 GLOBALS( 32 long level; 33 long size; 34 35 int color; 36 ) 37 38 static int xklogctl(int type, char *buf, int len) 39 { 40 int rc = klogctl(type, buf, len); 41 42 if (rc<0) perror_exit("klogctl"); 43 44 return rc; 45 } 46 47 // Use klogctl for reading if we're on a pre-3.5 kernel. 48 static void legacy_mode() 49 { 50 char *data, *to, *from; 51 int size; 52 53 // Figure out how much data we need, and fetch it. 54 if (!(size = TT.size)) size = xklogctl(10, 0, 0); 55 data = to = from = xmalloc(size+1); 56 data[size = xklogctl(3 + (toys.optflags & FLAG_c), data, size)] = 0; 57 58 // Filter out level markers and optionally time markers 59 if (!(toys.optflags & FLAG_r)) while ((from - data) < size) { 60 if (from == data || from[-1] == '\n') { 61 char *to; 62 63 if (*from == '<' && (to = strchr(from, '>'))) from = ++to; 64 if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']'))) 65 from = to+1+(to[1]==' '); 66 } 67 *(to++) = *(from++); 68 } else to = data+size; 69 70 // Write result. The odds of somebody requesting a buffer of size 3 and 71 // getting "<1>" are remote, but don't segfault if they do. 72 if (to != data) { 73 xwrite(1, data, to-data); 74 if (to[-1] != '\n') xputc('\n'); 75 } 76 if (CFG_TOYBOX_FREE) free(data); 77 } 78 79 static void color(int c) 80 { 81 if (TT.color) printf("\033[%dm", c); 82 } 83 84 static void print_all(void) 85 { 86 // http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg 87 88 // Each read returns one message. By default, we block when there are no 89 // more messages (--follow); O_NONBLOCK is needed for for usual behavior. 90 int fd = xopen("/dev/kmsg", O_RDONLY | ((toys.optflags&FLAG_w)?0:O_NONBLOCK)); 91 92 // With /dev/kmsg, SYSLOG_ACTION_CLEAR (5) doesn't actually remove anything; 93 // you need to seek to the last clear point. 94 lseek(fd, 0, SEEK_DATA); 95 96 while (1) { 97 char msg[8192]; // CONSOLE_EXT_LOG_MAX. 98 unsigned long long time_us; 99 int facpri, subsystem, pos; 100 char *p, *text; 101 ssize_t len; 102 103 // kmsg fails with EPIPE if we try to read while the buffer moves under 104 // us; the next read will succeed and return the next available entry. 105 do { 106 len = read(fd, msg, sizeof(msg)); 107 } while (len == -1 && errno == EPIPE); 108 // All reads from kmsg fail if you're on a pre-3.5 kernel. 109 if (len == -1 && errno == EINVAL) { 110 close(fd); 111 return legacy_mode(); 112 } 113 if (len <= 0) break; 114 115 msg[len] = 0; 116 117 if (sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos) != 2) 118 continue; 119 120 // Drop extras after end of message text. 121 text = msg + pos; 122 if ((p = strchr(text, '\n'))) *p = 0; 123 124 // Is there a subsystem? (The ": " is just a convention.) 125 p = strstr(text, ": "); 126 subsystem = p ? (p - text) : 0; 127 128 // "Raw" is a lie for /dev/kmsg. In practice, it just means we show the 129 // syslog facility/priority at the start of each line. 130 if (toys.optflags&FLAG_r) printf("<%d>", facpri); 131 132 if (!(toys.optflags&FLAG_t)) { 133 color(32); 134 printf("[%5lld.%06lld] ", time_us/1000000, time_us%1000000); 135 color(0); 136 } 137 138 // Errors (or worse) are shown in red, subsystems are shown in yellow. 139 if (subsystem) { 140 color(33); 141 printf("%.*s", subsystem, text); 142 text += subsystem; 143 color(0); 144 } 145 if (!((facpri&7) <= 3)) xputs(text); 146 else { 147 color(31); 148 printf("%s", text); 149 color(0); 150 xputc('\n'); 151 } 152 } 153 close(fd); 154 } 155 156 void dmesg_main(void) 157 { 158 TT.color = isatty(1); 159 160 if (!(toys.optflags & (FLAG_C|FLAG_n))) print_all(); 161 162 // Set the log level? 163 if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level); 164 165 // Clear the buffer? 166 if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0); 167 } 168