1*cf5a6c84SAndroid Build Coastguard Worker /* dmesg.c - display/control kernel ring buffer.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2006, 2007 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * Linux 6.0 celebrates the 10th anniversary of this being in "testing":
8*cf5a6c84SAndroid Build Coastguard Worker * http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker USE_DMESG(NEWTOY(dmesg, "w(follow)W(follow-new)CSTtrs#<1n#c[!Ttr][!Cc][!SWw]", TOYFLAG_BIN|TOYFLAG_LINEBUF))
11*cf5a6c84SAndroid Build Coastguard Worker
12*cf5a6c84SAndroid Build Coastguard Worker config DMESG
13*cf5a6c84SAndroid Build Coastguard Worker bool "dmesg"
14*cf5a6c84SAndroid Build Coastguard Worker default y
15*cf5a6c84SAndroid Build Coastguard Worker help
16*cf5a6c84SAndroid Build Coastguard Worker usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w|-W]
17*cf5a6c84SAndroid Build Coastguard Worker
18*cf5a6c84SAndroid Build Coastguard Worker Print or control the kernel ring buffer.
19*cf5a6c84SAndroid Build Coastguard Worker
20*cf5a6c84SAndroid Build Coastguard Worker -C Clear ring buffer without printing
21*cf5a6c84SAndroid Build Coastguard Worker -c Clear ring buffer after printing
22*cf5a6c84SAndroid Build Coastguard Worker -n Set kernel logging LEVEL (1-8)
23*cf5a6c84SAndroid Build Coastguard Worker -r Raw output (with <level markers>)
24*cf5a6c84SAndroid Build Coastguard Worker -S Use syslog(2) rather than /dev/kmsg
25*cf5a6c84SAndroid Build Coastguard Worker -s Show the last SIZE many bytes
26*cf5a6c84SAndroid Build Coastguard Worker -T Human readable timestamps
27*cf5a6c84SAndroid Build Coastguard Worker -t Don't print timestamps
28*cf5a6c84SAndroid Build Coastguard Worker -w Keep waiting for more output (aka --follow)
29*cf5a6c84SAndroid Build Coastguard Worker -W Wait for output, only printing new messages
30*cf5a6c84SAndroid Build Coastguard Worker */
31*cf5a6c84SAndroid Build Coastguard Worker
32*cf5a6c84SAndroid Build Coastguard Worker #define FOR_dmesg
33*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
34*cf5a6c84SAndroid Build Coastguard Worker #include <sys/klog.h>
35*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(long n,s;int use_color;time_t tea;)36*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
37*cf5a6c84SAndroid Build Coastguard Worker long n, s;
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker int use_color;
40*cf5a6c84SAndroid Build Coastguard Worker time_t tea;
41*cf5a6c84SAndroid Build Coastguard Worker )
42*cf5a6c84SAndroid Build Coastguard Worker
43*cf5a6c84SAndroid Build Coastguard Worker static void color(int c)
44*cf5a6c84SAndroid Build Coastguard Worker {
45*cf5a6c84SAndroid Build Coastguard Worker if (TT.use_color) printf("\e[%dm", c);
46*cf5a6c84SAndroid Build Coastguard Worker }
47*cf5a6c84SAndroid Build Coastguard Worker
format_message(char * msg,int new)48*cf5a6c84SAndroid Build Coastguard Worker static void format_message(char *msg, int new)
49*cf5a6c84SAndroid Build Coastguard Worker {
50*cf5a6c84SAndroid Build Coastguard Worker unsigned long long time_s, time_us;
51*cf5a6c84SAndroid Build Coastguard Worker int facpri, subsystem, pos, ii, jj, in, out;
52*cf5a6c84SAndroid Build Coastguard Worker char *p, *text;
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker // The new /dev/kmsg and the old syslog(2) formats differ slightly.
55*cf5a6c84SAndroid Build Coastguard Worker if (new) {
56*cf5a6c84SAndroid Build Coastguard Worker if (sscanf(msg, "%u,%*u,%llu,%*[^;]; %n", &facpri, &time_us, &pos) != 2)
57*cf5a6c84SAndroid Build Coastguard Worker return;
58*cf5a6c84SAndroid Build Coastguard Worker
59*cf5a6c84SAndroid Build Coastguard Worker time_s = time_us/1000000;
60*cf5a6c84SAndroid Build Coastguard Worker time_us %= 1000000;
61*cf5a6c84SAndroid Build Coastguard Worker } else if (sscanf(msg, "<%u>[%llu.%llu] %n",
62*cf5a6c84SAndroid Build Coastguard Worker &facpri, &time_s, &time_us, &pos) != 3) return;
63*cf5a6c84SAndroid Build Coastguard Worker
64*cf5a6c84SAndroid Build Coastguard Worker // Drop extras after end of message text.
65*cf5a6c84SAndroid Build Coastguard Worker if ((p = strchr(text = msg+pos, '\n'))) *p = 0;
66*cf5a6c84SAndroid Build Coastguard Worker
67*cf5a6c84SAndroid Build Coastguard Worker // Is there a subsystem? (The ": " is just a convention.)
68*cf5a6c84SAndroid Build Coastguard Worker p = strstr(text, ": ");
69*cf5a6c84SAndroid Build Coastguard Worker subsystem = p ? (p-text) : 0;
70*cf5a6c84SAndroid Build Coastguard Worker
71*cf5a6c84SAndroid Build Coastguard Worker // To get "raw" output for /dev/kmsg we need to add priority to each line
72*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(r)) {
73*cf5a6c84SAndroid Build Coastguard Worker color(0);
74*cf5a6c84SAndroid Build Coastguard Worker printf("<%d>", facpri);
75*cf5a6c84SAndroid Build Coastguard Worker } else for (in = out = subsystem;; ) {
76*cf5a6c84SAndroid Build Coastguard Worker jj = 0;
77*cf5a6c84SAndroid Build Coastguard Worker if (text[in]=='\\'&& 1==sscanf(text+in, "\\x%2x%n", &ii, &jj) && jj==4) {
78*cf5a6c84SAndroid Build Coastguard Worker in += 4;
79*cf5a6c84SAndroid Build Coastguard Worker text[out++] = ii;
80*cf5a6c84SAndroid Build Coastguard Worker } else if (!(text[out++] = text[in++])) break;
81*cf5a6c84SAndroid Build Coastguard Worker }
82*cf5a6c84SAndroid Build Coastguard Worker
83*cf5a6c84SAndroid Build Coastguard Worker // Format the time.
84*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(t)) {
85*cf5a6c84SAndroid Build Coastguard Worker color(32);
86*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(T)) {
87*cf5a6c84SAndroid Build Coastguard Worker time_t t = TT.tea+time_s;
88*cf5a6c84SAndroid Build Coastguard Worker char *ts = ctime(&t);
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker printf("[%.*s] ", (int)(strlen(ts)-1), ts);
91*cf5a6c84SAndroid Build Coastguard Worker } else printf("[%5lld.%06lld] ", time_s, time_us);
92*cf5a6c84SAndroid Build Coastguard Worker }
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker // Errors (or worse) are shown in red, subsystems are shown in yellow.
95*cf5a6c84SAndroid Build Coastguard Worker if (subsystem) {
96*cf5a6c84SAndroid Build Coastguard Worker color(33);
97*cf5a6c84SAndroid Build Coastguard Worker printf("%.*s", subsystem, text);
98*cf5a6c84SAndroid Build Coastguard Worker text += subsystem;
99*cf5a6c84SAndroid Build Coastguard Worker }
100*cf5a6c84SAndroid Build Coastguard Worker color(31*((facpri&7)<=3));
101*cf5a6c84SAndroid Build Coastguard Worker xputs(text);
102*cf5a6c84SAndroid Build Coastguard Worker }
103*cf5a6c84SAndroid Build Coastguard Worker
xklogctl(int type,char * buf,int len)104*cf5a6c84SAndroid Build Coastguard Worker static int xklogctl(int type, char *buf, int len)
105*cf5a6c84SAndroid Build Coastguard Worker {
106*cf5a6c84SAndroid Build Coastguard Worker int rc = klogctl(type, buf, len);
107*cf5a6c84SAndroid Build Coastguard Worker
108*cf5a6c84SAndroid Build Coastguard Worker if (rc<0) perror_exit("klogctl");
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Worker return rc;
111*cf5a6c84SAndroid Build Coastguard Worker }
112*cf5a6c84SAndroid Build Coastguard Worker
dmesg_cleanup(void)113*cf5a6c84SAndroid Build Coastguard Worker static void dmesg_cleanup(void)
114*cf5a6c84SAndroid Build Coastguard Worker {
115*cf5a6c84SAndroid Build Coastguard Worker color(0);
116*cf5a6c84SAndroid Build Coastguard Worker }
117*cf5a6c84SAndroid Build Coastguard Worker
dmesg_main(void)118*cf5a6c84SAndroid Build Coastguard Worker void dmesg_main(void)
119*cf5a6c84SAndroid Build Coastguard Worker {
120*cf5a6c84SAndroid Build Coastguard Worker TT.use_color = isatty(1);
121*cf5a6c84SAndroid Build Coastguard Worker
122*cf5a6c84SAndroid Build Coastguard Worker if (TT.use_color) sigatexit(dmesg_cleanup);
123*cf5a6c84SAndroid Build Coastguard Worker // If we're displaying output, is it klogctl or /dev/kmsg?
124*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(C)||FLAG(n)) goto no_output;
125*cf5a6c84SAndroid Build Coastguard Worker
126*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(T)) {
127*cf5a6c84SAndroid Build Coastguard Worker struct sysinfo info;
128*cf5a6c84SAndroid Build Coastguard Worker
129*cf5a6c84SAndroid Build Coastguard Worker sysinfo(&info);
130*cf5a6c84SAndroid Build Coastguard Worker TT.tea = time(0)-info.uptime;
131*cf5a6c84SAndroid Build Coastguard Worker }
132*cf5a6c84SAndroid Build Coastguard Worker
133*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(S)) {
134*cf5a6c84SAndroid Build Coastguard Worker char msg[8193]; // CONSOLE_EXT_LOG_MAX+1
135*cf5a6c84SAndroid Build Coastguard Worker ssize_t len;
136*cf5a6c84SAndroid Build Coastguard Worker int fd;
137*cf5a6c84SAndroid Build Coastguard Worker
138*cf5a6c84SAndroid Build Coastguard Worker // Each read returns one message. By default, we block when there are no
139*cf5a6c84SAndroid Build Coastguard Worker // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
140*cf5a6c84SAndroid Build Coastguard Worker fd = open("/dev/kmsg", O_RDONLY|O_NONBLOCK*!(FLAG(w) || FLAG(W)));
141*cf5a6c84SAndroid Build Coastguard Worker if (fd == -1) goto klogctl_mode;
142*cf5a6c84SAndroid Build Coastguard Worker
143*cf5a6c84SAndroid Build Coastguard Worker // SYSLOG_ACTION_CLEAR(5) doesn't actually remove anything from /dev/kmsg,
144*cf5a6c84SAndroid Build Coastguard Worker // you need to seek to the last clear point.
145*cf5a6c84SAndroid Build Coastguard Worker lseek(fd, 0, FLAG(W) ? SEEK_END : SEEK_DATA);
146*cf5a6c84SAndroid Build Coastguard Worker
147*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
148*cf5a6c84SAndroid Build Coastguard Worker // why does /dev/kmesg return EPIPE instead of EAGAIN if oldest message
149*cf5a6c84SAndroid Build Coastguard Worker // expires as we read it?
150*cf5a6c84SAndroid Build Coastguard Worker if (-1==(len = read(fd, msg, sizeof(msg)-1)) && errno==EPIPE) continue;
151*cf5a6c84SAndroid Build Coastguard Worker // read() from kmsg always fails on a pre-3.5 kernel.
152*cf5a6c84SAndroid Build Coastguard Worker if (len==-1 && errno==EINVAL) goto klogctl_mode;
153*cf5a6c84SAndroid Build Coastguard Worker if (len<1) break;
154*cf5a6c84SAndroid Build Coastguard Worker
155*cf5a6c84SAndroid Build Coastguard Worker msg[len] = 0;
156*cf5a6c84SAndroid Build Coastguard Worker format_message(msg, 1);
157*cf5a6c84SAndroid Build Coastguard Worker }
158*cf5a6c84SAndroid Build Coastguard Worker close(fd);
159*cf5a6c84SAndroid Build Coastguard Worker } else {
160*cf5a6c84SAndroid Build Coastguard Worker char *data, *to, *from, *end;
161*cf5a6c84SAndroid Build Coastguard Worker int size;
162*cf5a6c84SAndroid Build Coastguard Worker
163*cf5a6c84SAndroid Build Coastguard Worker klogctl_mode:
164*cf5a6c84SAndroid Build Coastguard Worker // Figure out how much data we need, and fetch it.
165*cf5a6c84SAndroid Build Coastguard Worker if (!(size = TT.s)) size = xklogctl(10, 0, 0);
166*cf5a6c84SAndroid Build Coastguard Worker data = from = xmalloc(size+1);
167*cf5a6c84SAndroid Build Coastguard Worker data[size = xklogctl(3+FLAG(c), data, size)] = 0;
168*cf5a6c84SAndroid Build Coastguard Worker
169*cf5a6c84SAndroid Build Coastguard Worker // Send each line to format_message.
170*cf5a6c84SAndroid Build Coastguard Worker to = data + size;
171*cf5a6c84SAndroid Build Coastguard Worker while (from < to) {
172*cf5a6c84SAndroid Build Coastguard Worker if (!(end = memchr(from, '\n', to-from))) break;
173*cf5a6c84SAndroid Build Coastguard Worker *end = 0;
174*cf5a6c84SAndroid Build Coastguard Worker format_message(from, 0);
175*cf5a6c84SAndroid Build Coastguard Worker from = end + 1;
176*cf5a6c84SAndroid Build Coastguard Worker }
177*cf5a6c84SAndroid Build Coastguard Worker
178*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) free(data);
179*cf5a6c84SAndroid Build Coastguard Worker }
180*cf5a6c84SAndroid Build Coastguard Worker
181*cf5a6c84SAndroid Build Coastguard Worker no_output:
182*cf5a6c84SAndroid Build Coastguard Worker // Set the log level?
183*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(n)) xklogctl(8, 0, TT.n);
184*cf5a6c84SAndroid Build Coastguard Worker
185*cf5a6c84SAndroid Build Coastguard Worker // Clear the buffer?
186*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(C)||FLAG(c)) xklogctl(5, 0, 0);
187*cf5a6c84SAndroid Build Coastguard Worker }
188