1*422de7d1Srin /* $NetBSD: dmesg.c,v 1.51 2022/08/06 10:22:22 rin Exp $ */
261f28255Scgd /*-
37b442030Scgd * Copyright (c) 1991, 1993
47b442030Scgd * The Regents of the University of California. All rights reserved.
561f28255Scgd *
661f28255Scgd * Redistribution and use in source and binary forms, with or without
761f28255Scgd * modification, are permitted provided that the following conditions
861f28255Scgd * are met:
961f28255Scgd * 1. Redistributions of source code must retain the above copyright
1061f28255Scgd * notice, this list of conditions and the following disclaimer.
1161f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1261f28255Scgd * notice, this list of conditions and the following disclaimer in the
1361f28255Scgd * documentation and/or other materials provided with the distribution.
14bf07c871Sagc * 3. Neither the name of the University nor the names of its contributors
1561f28255Scgd * may be used to endorse or promote products derived from this software
1661f28255Scgd * without specific prior written permission.
1761f28255Scgd *
1861f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1961f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2061f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2161f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2261f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2361f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2461f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2561f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2661f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2761f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2861f28255Scgd * SUCH DAMAGE.
2961f28255Scgd */
3061f28255Scgd
315f4e3656Slukem #include <sys/cdefs.h>
3261f28255Scgd #ifndef lint
336543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
346543a91fSlukem The Regents of the University of California. All rights reserved.");
3561f28255Scgd #endif /* not lint */
3661f28255Scgd
3761f28255Scgd #ifndef lint
380114e805Scgd #if 0
397b442030Scgd static char sccsid[] = "@(#)dmesg.c 8.1 (Berkeley) 6/5/93";
400114e805Scgd #else
41*422de7d1Srin __RCSID("$NetBSD: dmesg.c,v 1.51 2022/08/06 10:22:22 rin Exp $");
420114e805Scgd #endif
4361f28255Scgd #endif /* not lint */
4461f28255Scgd
45a7d9e1f9Ssimonb #include <sys/param.h>
4661f28255Scgd #include <sys/msgbuf.h>
47a7d9e1f9Ssimonb #include <sys/sysctl.h>
487b442030Scgd
495eeab43eScgd #include <err.h>
50a1d2abcaSchristos #include <ctype.h>
517b442030Scgd #include <fcntl.h>
52db02d1fbSchristos #include <time.h>
5361f28255Scgd #include <kvm.h>
547b442030Scgd #include <nlist.h>
5561f28255Scgd #include <stdio.h>
56a7d9e1f9Ssimonb #include <stddef.h>
577b442030Scgd #include <stdlib.h>
582ddbb97fSjtc #include <unistd.h>
597b442030Scgd #include <vis.h>
6061f28255Scgd
6173dfacb5Ssimonb #ifndef SMALL
629f61665bSchristos #include <langinfo.h>
639f61665bSchristos #include <locale.h>
649f61665bSchristos
65baa8e84bSjoerg static struct nlist nl[] = {
667b442030Scgd #define X_MSGBUF 0
67064b0504Schristos { .n_name = "_msgbufp" },
68064b0504Schristos { .n_name = NULL },
6961f28255Scgd };
7061f28255Scgd
719f61665bSchristos static const char *radix;
729f61665bSchristos
73baa8e84bSjoerg __dead static void usage(void);
7461f28255Scgd
757b442030Scgd #define KREAD(addr, var) \
767b442030Scgd kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
77a1d2abcaSchristos
78a1d2abcaSchristos static const char *
fmtydhmsf(char * b,size_t l,intmax_t t,long nsec,int ht)792f9f119bSkre fmtydhmsf(char *b, size_t l, intmax_t t, long nsec, int ht)
80a1d2abcaSchristos {
813d4a88b5Skre intmax_t s, m, h;
82a1d2abcaSchristos int z;
830d9f7721Skre int prec;
84a1d2abcaSchristos size_t o;
85a1d2abcaSchristos
86a1d2abcaSchristos s = t % 60;
87a1d2abcaSchristos t /= 60;
88a1d2abcaSchristos
89a1d2abcaSchristos m = t % 60;
90a1d2abcaSchristos t /= 60;
91a1d2abcaSchristos
929f61665bSchristos h = t;
93a1d2abcaSchristos
94a1d2abcaSchristos z = 0;
95a1d2abcaSchristos o = 0;
96a1d2abcaSchristos
97a1d2abcaSchristos #define APPENDFMT(fmt, ...) \
98a1d2abcaSchristos do { \
99a1d2abcaSchristos z = snprintf(b + o, l - o, fmt, __VA_ARGS__); \
100a1d2abcaSchristos if (z == -1) \
101a1d2abcaSchristos return b; \
102a1d2abcaSchristos o += (size_t)z; \
103a1d2abcaSchristos if (o >= l) \
104a1d2abcaSchristos return b; \
105a1d2abcaSchristos } while (/*CONSTCOND*/0)
106a1d2abcaSchristos
107a1d2abcaSchristos #define APPEND(a) \
108a1d2abcaSchristos do if (a) \
1090d9f7721Skre APPENDFMT("%jd%c", a, toupper((unsigned char)__STRING(a)[0])); \
110a1d2abcaSchristos while (/*CONSTCOND*/0)
1110d9f7721Skre #define APPENDS(a, pr, ms) \
1120d9f7721Skre APPENDFMT("%jd%s%.*ld%c", a, radix, pr, ms, \
113a1d2abcaSchristos toupper((unsigned char)__STRING(a)[0]))
114a1d2abcaSchristos
115a1d2abcaSchristos APPENDFMT("%s", "P");
116a1d2abcaSchristos APPENDFMT("%s", "T");
117a1d2abcaSchristos APPEND(h);
118a1d2abcaSchristos APPEND(m);
119a1d2abcaSchristos if (nsec)
1200d9f7721Skre nsec = (nsec + 500000) / 1000000; /* now milliseconds */
1210d9f7721Skre prec = 3;
1222f9f119bSkre if (nsec && ht == 2) {
1230d9f7721Skre while (prec > 0 && (nsec % 10) == 0)
1240d9f7721Skre --prec, nsec /= 10;
1252f9f119bSkre }
1262f9f119bSkre if (nsec || ht > 2)
1270d9f7721Skre APPENDS(s, prec, nsec);
128a1d2abcaSchristos else
129a1d2abcaSchristos APPEND(s);
130a1d2abcaSchristos return b;
131a1d2abcaSchristos }
132a1d2abcaSchristos
133a1d2abcaSchristos static void
pnsec(long nsec,long fsec,int scale)134a1d2abcaSchristos pnsec(long nsec, long fsec, int scale)
135a1d2abcaSchristos {
136a1d2abcaSchristos if (scale > 6)
137a1d2abcaSchristos printf("%6.6ld", (nsec + 499) / 1000);
138a1d2abcaSchristos else
139a1d2abcaSchristos printf("%*.*ld%.*s", scale, scale, fsec, 6 - scale, "000000");
140a1d2abcaSchristos }
141857f572eSdsl #endif
1427b442030Scgd
1437b442030Scgd int
main(int argc,char * argv[])144907def68Ssimonb main(int argc, char *argv[])
14561f28255Scgd {
146a7d9e1f9Ssimonb struct kern_msgbuf cur;
147db02d1fbSchristos int ch, newl, log, i;
148eb7145dcSrin size_t size;
14973dfacb5Ssimonb char *p, *bufdata;
1507b442030Scgd char buf[5];
15173dfacb5Ssimonb #ifndef SMALL
152eb7145dcSrin size_t tstamp;
15382dbd18cSrin char tbuf[64];
154db02d1fbSchristos char *memf, *nlistf;
1557008793dSkre struct timespec boottime;
1562fef76cbSchristos struct timespec lasttime;
1572fef76cbSchristos intmax_t sec;
158329132e2Skre long nsec, fsec;
159329132e2Skre int scale;
1602fef76cbSchristos int deltas, quiet, humantime;
161475a6226Stsutsui bool frac, postts;
162db02d1fbSchristos
163db02d1fbSchristos static const int bmib[] = { CTL_KERN, KERN_BOOTTIME };
164db02d1fbSchristos size = sizeof(boottime);
165db02d1fbSchristos
1669f61665bSchristos (void)setlocale(LC_ALL, "");
1679f61665bSchristos radix = nl_langinfo(RADIXCHAR);
1689f61665bSchristos if (radix == NULL)
1699f61665bSchristos radix = "."; /* could also select "," */
1709f61665bSchristos
171db02d1fbSchristos boottime.tv_sec = 0;
1727008793dSkre boottime.tv_nsec = 0;
1732fef76cbSchristos lasttime.tv_sec = 0;
1742fef76cbSchristos lasttime.tv_nsec = 0;
1752fef76cbSchristos deltas = quiet = humantime = 0;
176db02d1fbSchristos
177db02d1fbSchristos (void)sysctl(bmib, 2, &boottime, &size, NULL, 0);
178db02d1fbSchristos
1797b442030Scgd memf = nlistf = NULL;
1802fef76cbSchristos while ((ch = getopt(argc, argv, "dM:N:tT")) != -1)
18161f28255Scgd switch(ch) {
1822fef76cbSchristos case 'd':
1832fef76cbSchristos deltas = 1;
1842fef76cbSchristos break;
18561f28255Scgd case 'M':
1867b442030Scgd memf = optarg;
18761f28255Scgd break;
18861f28255Scgd case 'N':
1897b442030Scgd nlistf = optarg;
19061f28255Scgd break;
191db02d1fbSchristos case 't':
1922fef76cbSchristos quiet = 1;
1932fef76cbSchristos break;
1942fef76cbSchristos case 'T':
195a1d2abcaSchristos humantime++;
196db02d1fbSchristos break;
19761f28255Scgd case '?':
19861f28255Scgd default:
19961f28255Scgd usage();
20061f28255Scgd }
20161f28255Scgd argc -= optind;
20261f28255Scgd argv += optind;
2032fef76cbSchristos if (quiet && humantime)
2042fef76cbSchristos err(EXIT_FAILURE, "-t cannot be used with -T");
20561f28255Scgd
206643cb3c3Ssimonb if (memf == NULL) {
20773dfacb5Ssimonb #endif
208db02d1fbSchristos static const int mmib[2] = { CTL_KERN, KERN_MSGBUF };
20961f28255Scgd
210db02d1fbSchristos if (sysctl(mmib, 2, NULL, &size, NULL, 0) == -1 ||
211857f572eSdsl (bufdata = malloc(size)) == NULL ||
212db02d1fbSchristos sysctl(mmib, 2, bufdata, &size, NULL, 0) == -1)
213a7d9e1f9Ssimonb err(1, "can't get msgbuf");
214a7d9e1f9Ssimonb
215a7d9e1f9Ssimonb /* make a dummy struct msgbuf for the display logic */
216857f572eSdsl cur.msg_bufx = 0;
217857f572eSdsl cur.msg_bufs = size;
21873dfacb5Ssimonb #ifndef SMALL
219a7d9e1f9Ssimonb } else {
220a7d9e1f9Ssimonb kvm_t *kd;
221a7d9e1f9Ssimonb struct kern_msgbuf *bufp;
222a7d9e1f9Ssimonb
223a7d9e1f9Ssimonb /*
224a7d9e1f9Ssimonb * Read in message buffer header and data, and do sanity
225a7d9e1f9Ssimonb * checks.
226a7d9e1f9Ssimonb */
227a7d9e1f9Ssimonb kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
228a7d9e1f9Ssimonb if (kd == NULL)
2297b442030Scgd exit (1);
2307b442030Scgd if (kvm_nlist(kd, nl) == -1)
2317b442030Scgd errx(1, "kvm_nlist: %s", kvm_geterr(kd));
2327b442030Scgd if (nl[X_MSGBUF].n_type == 0)
233a7d9e1f9Ssimonb errx(1, "%s: msgbufp not found", nlistf ? nlistf :
234a7d9e1f9Ssimonb "namelist");
235f5c4107dSmjacob if (KREAD(nl[X_MSGBUF].n_value, bufp))
2365f4e3656Slukem errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
237f5c4107dSmjacob nl[X_MSGBUF].n_value);
238a7d9e1f9Ssimonb if (kvm_read(kd, (long)bufp, &cur,
239a7d9e1f9Ssimonb offsetof(struct kern_msgbuf, msg_bufc)) !=
240a7d9e1f9Ssimonb offsetof(struct kern_msgbuf, msg_bufc))
2415f4e3656Slukem errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
2425f4e3656Slukem (unsigned long)bufp);
24361f28255Scgd if (cur.msg_magic != MSG_MAGIC)
2447b442030Scgd errx(1, "magic number incorrect");
24571af424fSleo bufdata = malloc(cur.msg_bufs);
24671af424fSleo if (bufdata == NULL)
24771af424fSleo errx(1, "couldn't allocate space for buffer data");
24871af424fSleo if (kvm_read(kd, (long)&bufp->msg_bufc, bufdata,
24971af424fSleo cur.msg_bufs) != cur.msg_bufs)
25071af424fSleo errx(1, "kvm_read: %s", kvm_geterr(kd));
25171af424fSleo kvm_close(kd);
25271af424fSleo if (cur.msg_bufx >= cur.msg_bufs)
25361f28255Scgd cur.msg_bufx = 0;
254a7d9e1f9Ssimonb }
25573dfacb5Ssimonb #endif
25661f28255Scgd
25761f28255Scgd /*
258c6e5d311Senami * The message buffer is circular; start at the write pointer
259c6e5d311Senami * (which points the oldest character), and go to the write
260c6e5d311Senami * pointer - 1 (which points the newest character). I.e, loop
261c6e5d311Senami * over cur.msg_bufs times. Unused area is skipped since it
262c6e5d311Senami * contains nul.
26361f28255Scgd */
264329132e2Skre #ifndef SMALL
265329132e2Skre frac = false;
266475a6226Stsutsui postts = false;
267eb7145dcSrin tstamp = 0;
268329132e2Skre scale = 0;
269329132e2Skre #endif
270eb7145dcSrin for (newl = 1, log = i = 0, p = bufdata + cur.msg_bufx;
271c6e5d311Senami i < cur.msg_bufs; i++, p++) {
272329132e2Skre
273857f572eSdsl #ifndef SMALL
27471af424fSleo if (p == bufdata + cur.msg_bufs)
27571af424fSleo p = bufdata;
276db02d1fbSchristos #define ADDC(c) \
277329132e2Skre do { \
27882dbd18cSrin if (tstamp < sizeof(tbuf) - 1) \
279db02d1fbSchristos tbuf[tstamp++] = (c); \
28082dbd18cSrin else { \
28182dbd18cSrin /* Cannot be a timestamp. */ \
28282dbd18cSrin tstamp = 0; \
28382dbd18cSrin tbuf[sizeof(tbuf) - 1] = '\0'; \
28482dbd18cSrin goto not_tstamp; \
28582dbd18cSrin } \
286329132e2Skre if (frac) \
287329132e2Skre scale++; \
288d67befb6Srin } while (0)
2892a3cf2bfSrin #define PRTBUF() \
2902a3cf2bfSrin for (char *_p = tbuf; *_p != '\0'; _p++) { \
2912a3cf2bfSrin (void)vis(buf, *_p, VIS_NOSLASH, 0); \
2922a3cf2bfSrin if (buf[1] == 0) \
2932a3cf2bfSrin (void)putchar(buf[0]); \
2942a3cf2bfSrin else \
2952a3cf2bfSrin (void)printf("%s", buf); \
2962a3cf2bfSrin }
297857f572eSdsl #endif
29861f28255Scgd ch = *p;
2996d9827c8Schristos if (ch == '\0')
3006d9827c8Schristos continue;
30161f28255Scgd /* Skip "\n<.*>" syslog sequences. */
302db02d1fbSchristos /* Gather timestamp sequences */
303db02d1fbSchristos if (newl) {
304329132e2Skre #ifndef SMALL
305329132e2Skre int j;
306329132e2Skre #endif
307329132e2Skre
308db02d1fbSchristos switch (ch) {
309329132e2Skre #ifndef SMALL
31043729d11Skre case '[':
311329132e2Skre frac = false;
312329132e2Skre scale = 0;
313db02d1fbSchristos ADDC(ch);
314db02d1fbSchristos continue;
31543729d11Skre #endif
316db02d1fbSchristos case '<':
317db02d1fbSchristos log = 1;
318db02d1fbSchristos continue;
319db02d1fbSchristos case '>':
320eb23b853Schristos log = 0;
321db02d1fbSchristos continue;
322329132e2Skre #ifndef SMALL
32343729d11Skre case ']':
32482dbd18cSrin if (tstamp == 0)
32582dbd18cSrin goto prchar;
326329132e2Skre frac = false;
327db02d1fbSchristos ADDC(ch);
328db02d1fbSchristos ADDC('\0');
329db02d1fbSchristos tstamp = 0;
330329132e2Skre sec = fsec = 0;
331329132e2Skre switch (sscanf(tbuf, "[%jd.%ld]", &sec, &fsec)){
332329132e2Skre case 0:
33382dbd18cSrin not_tstamp: /* not a timestamp */
3342a3cf2bfSrin PRTBUF();
335329132e2Skre continue;
336329132e2Skre case 1:
3372a3cf2bfSrin fsec = 0; /* XXX PRTBUF()? */
338329132e2Skre break;
339329132e2Skre case 2:
340329132e2Skre break;
3412a3cf2bfSrin case EOF:
342329132e2Skre default:
343329132e2Skre /* Help */
344329132e2Skre continue;
345329132e2Skre }
346*422de7d1Srin postts = true;
347329132e2Skre
348329132e2Skre for (nsec = fsec, j = 9 - scale; --j >= 0; )
349329132e2Skre nsec *= 10;
3502fef76cbSchristos if (!quiet || deltas)
3512fef76cbSchristos printf("[");
352a1d2abcaSchristos if (humantime == 1) {
3532fef76cbSchristos time_t t;
3542fef76cbSchristos struct tm tm;
355329132e2Skre
356db02d1fbSchristos t = boottime.tv_sec + sec;
3577008793dSkre if (nsec + boottime.tv_nsec >=
3587008793dSkre ( 1L /* 1 second */
3597008793dSkre * 1000L /* ms */
3607008793dSkre * 1000L /* us */
3617008793dSkre * 1000L /* ns */ ))
3627008793dSkre t++;
3637008793dSkre
364db02d1fbSchristos if (localtime_r(&t, &tm) != NULL) {
36582dbd18cSrin strftime(tbuf, sizeof(tbuf),
3662fef76cbSchristos "%a %b %e %H:%M:%S %Z %Y",
367db02d1fbSchristos &tm);
368db02d1fbSchristos printf("%s", tbuf);
369db02d1fbSchristos }
370a1d2abcaSchristos } else if (humantime > 1) {
371a1d2abcaSchristos const char *fp = fmtydhmsf(tbuf,
37282dbd18cSrin sizeof(tbuf), sec, fsec, humantime);
373a1d2abcaSchristos if (fp) {
374a1d2abcaSchristos printf("%s", fp);
375a1d2abcaSchristos }
3762fef76cbSchristos } else if (!quiet) {
3774cf82913Skre printf(" %5jd%s", sec, radix);
378a1d2abcaSchristos pnsec(nsec, fsec, scale);
3792fef76cbSchristos }
3802fef76cbSchristos if (deltas) {
3812fef76cbSchristos struct timespec nt = { sec, nsec };
3822fef76cbSchristos struct timespec dt;
383329132e2Skre
3842fef76cbSchristos timespecsub(&nt, &lasttime, &dt);
3852fef76cbSchristos if (humantime || !quiet)
3862fef76cbSchristos printf(" ");
3874cf82913Skre printf("<% 4jd%s%6.6ld>",
3884cf82913Skre (intmax_t)dt.tv_sec, radix,
3894cf82913Skre (dt.tv_nsec+499) / 1000);
3902fef76cbSchristos lasttime = nt;
3912fef76cbSchristos }
3922fef76cbSchristos if (!quiet || deltas)
3932fef76cbSchristos printf("] ");
394db02d1fbSchristos continue;
39543729d11Skre #endif
396db02d1fbSchristos case ' ':
3976b4ce10fSkre #ifndef SMALL
398475a6226Stsutsui if (!tstamp && postts) {
399475a6226Stsutsui postts = false;
400db02d1fbSchristos continue;
401475a6226Stsutsui }
402eb7145dcSrin #endif
403db02d1fbSchristos /*FALLTHROUGH*/
404db02d1fbSchristos default:
40543729d11Skre #ifndef SMALL
406db02d1fbSchristos if (tstamp) {
407db02d1fbSchristos ADDC(ch);
408329132e2Skre if (ch == '.')
409329132e2Skre frac = true;
41061f28255Scgd continue;
41161f28255Scgd }
41282dbd18cSrin prchar:
41343729d11Skre #endif
414db02d1fbSchristos if (log)
41561f28255Scgd continue;
416db02d1fbSchristos break;
417db02d1fbSchristos }
41861f28255Scgd }
4197b442030Scgd newl = ch == '\n';
4201225b610Saugustss (void)vis(buf, ch, VIS_NOSLASH, 0);
421857f572eSdsl #ifndef SMALL
4227b442030Scgd if (buf[1] == 0)
4237b442030Scgd (void)putchar(buf[0]);
4247b442030Scgd else
425857f572eSdsl #endif
4267b442030Scgd (void)printf("%s", buf);
42771af424fSleo }
4282a3cf2bfSrin #ifndef SMALL
4292a3cf2bfSrin /* non-terminated [.*] */
4302a3cf2bfSrin if (tstamp) {
4312a3cf2bfSrin ADDC('\0');
4322a3cf2bfSrin PRTBUF();
4332a3cf2bfSrin }
4342a3cf2bfSrin #endif
43561f28255Scgd if (!newl)
43661f28255Scgd (void)putchar('\n');
437db02d1fbSchristos return EXIT_SUCCESS;
43861f28255Scgd }
43961f28255Scgd
440857f572eSdsl #ifndef SMALL
441baa8e84bSjoerg static void
usage(void)442907def68Ssimonb usage(void)
44361f28255Scgd {
4448c389fd0Senami
445ba701a99Swiz (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n",
446db02d1fbSchristos getprogname());
447db02d1fbSchristos exit(EXIT_FAILURE);
44861f28255Scgd }
449857f572eSdsl #endif
450