dmesg.c revision 1.33 1 /* $NetBSD: dmesg.c,v 1.33 2018/04/14 01:37:34 kre Exp $ */
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 #ifndef lint
33 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
34 The Regents of the University of California. All rights reserved.");
35 #endif /* not lint */
36
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)dmesg.c 8.1 (Berkeley) 6/5/93";
40 #else
41 __RCSID("$NetBSD: dmesg.c,v 1.33 2018/04/14 01:37:34 kre Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/msgbuf.h>
47 #include <sys/sysctl.h>
48
49 #include <err.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <kvm.h>
53 #include <nlist.h>
54 #include <stdio.h>
55 #include <stddef.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <vis.h>
59
60 #ifndef SMALL
61 static struct nlist nl[] = {
62 #define X_MSGBUF 0
63 { .n_name = "_msgbufp" },
64 { .n_name = NULL },
65 };
66
67 __dead static void usage(void);
68
69 #define KREAD(addr, var) \
70 kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
71 #endif
72
73 int
74 main(int argc, char *argv[])
75 {
76 struct kern_msgbuf cur;
77 int ch, newl, log, i;
78 size_t tstamp, size;
79 char *p, *bufdata;
80 char buf[5];
81 #ifndef SMALL
82 char tbuf[64];
83 char *memf, *nlistf;
84 struct timeval boottime;
85 struct timespec lasttime;
86 intmax_t sec;
87 long nsec, fsec;
88 int scale;
89 int deltas, quiet, humantime;
90 bool frac;
91
92 static const int bmib[] = { CTL_KERN, KERN_BOOTTIME };
93 size = sizeof(boottime);
94
95 boottime.tv_sec = 0;
96 boottime.tv_usec = 0;
97 lasttime.tv_sec = 0;
98 lasttime.tv_nsec = 0;
99 deltas = quiet = humantime = 0;
100
101 (void)sysctl(bmib, 2, &boottime, &size, NULL, 0);
102
103 memf = nlistf = NULL;
104 while ((ch = getopt(argc, argv, "dM:N:tT")) != -1)
105 switch(ch) {
106 case 'd':
107 deltas = 1;
108 break;
109 case 'M':
110 memf = optarg;
111 break;
112 case 'N':
113 nlistf = optarg;
114 break;
115 case 't':
116 quiet = 1;
117 break;
118 case 'T':
119 humantime = 1;
120 break;
121 case '?':
122 default:
123 usage();
124 }
125 argc -= optind;
126 argv += optind;
127 if (quiet && humantime)
128 err(EXIT_FAILURE, "-t cannot be used with -T");
129
130 if (memf == NULL) {
131 #endif
132 static const int mmib[2] = { CTL_KERN, KERN_MSGBUF };
133
134 if (sysctl(mmib, 2, NULL, &size, NULL, 0) == -1 ||
135 (bufdata = malloc(size)) == NULL ||
136 sysctl(mmib, 2, bufdata, &size, NULL, 0) == -1)
137 err(1, "can't get msgbuf");
138
139 /* make a dummy struct msgbuf for the display logic */
140 cur.msg_bufx = 0;
141 cur.msg_bufs = size;
142 #ifndef SMALL
143 } else {
144 kvm_t *kd;
145 struct kern_msgbuf *bufp;
146
147 /*
148 * Read in message buffer header and data, and do sanity
149 * checks.
150 */
151 kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
152 if (kd == NULL)
153 exit (1);
154 if (kvm_nlist(kd, nl) == -1)
155 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
156 if (nl[X_MSGBUF].n_type == 0)
157 errx(1, "%s: msgbufp not found", nlistf ? nlistf :
158 "namelist");
159 if (KREAD(nl[X_MSGBUF].n_value, bufp))
160 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
161 nl[X_MSGBUF].n_value);
162 if (kvm_read(kd, (long)bufp, &cur,
163 offsetof(struct kern_msgbuf, msg_bufc)) !=
164 offsetof(struct kern_msgbuf, msg_bufc))
165 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
166 (unsigned long)bufp);
167 if (cur.msg_magic != MSG_MAGIC)
168 errx(1, "magic number incorrect");
169 bufdata = malloc(cur.msg_bufs);
170 if (bufdata == NULL)
171 errx(1, "couldn't allocate space for buffer data");
172 if (kvm_read(kd, (long)&bufp->msg_bufc, bufdata,
173 cur.msg_bufs) != cur.msg_bufs)
174 errx(1, "kvm_read: %s", kvm_geterr(kd));
175 kvm_close(kd);
176 if (cur.msg_bufx >= cur.msg_bufs)
177 cur.msg_bufx = 0;
178 }
179 #endif
180
181 /*
182 * The message buffer is circular; start at the write pointer
183 * (which points the oldest character), and go to the write
184 * pointer - 1 (which points the newest character). I.e, loop
185 * over cur.msg_bufs times. Unused area is skipped since it
186 * contains nul.
187 */
188 #ifndef SMALL
189 frac = false;
190 scale = 0;
191 #endif
192 for (tstamp = 0, newl = 1, log = i = 0, p = bufdata + cur.msg_bufx;
193 i < cur.msg_bufs; i++, p++) {
194
195 #ifndef SMALL
196 if (p == bufdata + cur.msg_bufs)
197 p = bufdata;
198 #define ADDC(c) \
199 do { \
200 if (tstamp < sizeof(tbuf) - 1) \
201 tbuf[tstamp++] = (c); \
202 if (frac) \
203 scale++; \
204 } while (/*CONSTCOND*/0)
205 #else
206 #define ADDC(c)
207 #endif
208 ch = *p;
209 if (ch == '\0')
210 continue;
211 /* Skip "\n<.*>" syslog sequences. */
212 /* Gather timestamp sequences */
213 if (newl) {
214 #ifndef SMALL
215 int j;
216 #endif
217
218 switch (ch) {
219 case '[':
220 #ifndef SMALL
221 frac = false;
222 scale = 0;
223 #endif
224 ADDC(ch);
225 continue;
226 case '<':
227 log = 1;
228 continue;
229 case '>':
230 log = 0;
231 continue;
232 case ']':
233 #ifndef SMALL
234 frac = false;
235 #endif
236 ADDC(ch);
237 ADDC('\0');
238 tstamp = 0;
239 #ifndef SMALL
240 sec = fsec = 0;
241 switch (sscanf(tbuf, "[%jd.%ld]", &sec, &fsec)){
242 case EOF:
243 case 0:
244 /*???*/
245 continue;
246 case 1:
247 fsec = 0;
248 break;
249 case 2:
250 break;
251 default:
252 /* Help */
253 continue;
254 }
255
256 for (nsec = fsec, j = 9 - scale; --j >= 0; )
257 nsec *= 10;
258 if (!quiet || deltas)
259 printf("[");
260 if (humantime) {
261 time_t t;
262 struct tm tm;
263
264 t = boottime.tv_sec + sec;
265 if (localtime_r(&t, &tm) != NULL) {
266 strftime(tbuf, sizeof(tbuf),
267 "%a %b %e %H:%M:%S %Z %Y",
268 &tm);
269 printf("%s", tbuf);
270 }
271 } else if (!quiet) {
272 if (scale > 6)
273 printf("% 5jd.%6.6ld",
274 sec, (nsec + 499) / 1000);
275 else
276 printf("% 5jd.%*.*ld%.*s",
277 sec, scale, scale, fsec,
278 6 - scale, "000000");
279 }
280 if (deltas) {
281 struct timespec nt = { sec, nsec };
282 struct timespec dt;
283
284 timespecsub(&nt, &lasttime, &dt);
285 if (humantime || !quiet)
286 printf(" ");
287 printf("<% 4jd.%06ld>", (intmax_t)
288 dt.tv_sec, (dt.tv_nsec+499) / 1000);
289 lasttime = nt;
290 }
291 if (!quiet || deltas)
292 printf("] ");
293 #endif
294 continue;
295 case ' ':
296 if (!tstamp)
297 continue;
298 /*FALLTHROUGH*/
299 default:
300 if (tstamp) {
301 ADDC(ch);
302 #ifndef SMALL
303 if (ch == '.')
304 frac = true;
305 #endif
306 continue;
307 }
308 if (log)
309 continue;
310 break;
311 }
312 newl = 0;
313 }
314 newl = ch == '\n';
315 (void)vis(buf, ch, VIS_NOSLASH, 0);
316 #ifndef SMALL
317 if (buf[1] == 0)
318 (void)putchar(buf[0]);
319 else
320 #endif
321 (void)printf("%s", buf);
322 }
323 if (!newl)
324 (void)putchar('\n');
325 return EXIT_SUCCESS;
326 }
327
328 #ifndef SMALL
329 static void
330 usage(void)
331 {
332
333 (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n",
334 getprogname());
335 exit(EXIT_FAILURE);
336 }
337 #endif
338