xref: /aosp_15_r20/external/toybox/toys/lsb/dmesg.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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