xref: /freebsd/sbin/dmesg/dmesg.c (revision 0b8224d1cc9dc6c9778ba04a75b2c8d47e5d7481)
18fae3551SRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
48fae3551SRodney W. Grimes  * Copyright (c) 1991, 1993
58fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
68fae3551SRodney W. Grimes  *
78fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes  * are met:
108fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes  *    without specific prior written permission.
188fae3551SRodney W. Grimes  *
198fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes  * SUCH DAMAGE.
308fae3551SRodney W. Grimes  */
318fae3551SRodney W. Grimes 
32676adc04SThomas Moestl #include <sys/types.h>
338fae3551SRodney W. Grimes #include <sys/msgbuf.h>
34676adc04SThomas Moestl #include <sys/sysctl.h>
358fae3551SRodney W. Grimes 
3648697608SDavid Malone #include <ctype.h>
37b7a8c022SAlexander Langer #include <err.h>
38ccdb2370SIan Dowse #include <errno.h>
398fae3551SRodney W. Grimes #include <fcntl.h>
408fae3551SRodney W. Grimes #include <kvm.h>
41ccdb2370SIan Dowse #include <limits.h>
42301e6a17SBruce Evans #include <locale.h>
437309e024SBruce Evans #include <nlist.h>
448fae3551SRodney W. Grimes #include <stdio.h>
4511967f3cSEitan Adler #include <stdbool.h>
468fae3551SRodney W. Grimes #include <stdlib.h>
4759f256ecSIan Dowse #include <string.h>
488fae3551SRodney W. Grimes #include <unistd.h>
498fae3551SRodney W. Grimes #include <vis.h>
50f806cd42SRuslan Ermilov #include <sys/syslog.h>
518fae3551SRodney W. Grimes 
521efe3c6bSEd Schouten static struct nlist nl[] = {
538fae3551SRodney W. Grimes #define	X_MSGBUF	0
541efe3c6bSEd Schouten 	{ "_msgbufp", 0, 0, 0, 0 },
5557517b09SXin LI 	{ NULL, 0, 0, 0, 0 },
568fae3551SRodney W. Grimes };
578fae3551SRodney W. Grimes 
581fa5ae8fSWarner Losh void usage(void) __dead2;
598fae3551SRodney W. Grimes 
608fae3551SRodney W. Grimes #define	KREAD(addr, var) \
618fae3551SRodney W. Grimes 	kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
628fae3551SRodney W. Grimes 
638fae3551SRodney W. Grimes int
main(int argc,char * argv[])641fa5ae8fSWarner Losh main(int argc, char *argv[])
658fae3551SRodney W. Grimes {
668fae3551SRodney W. Grimes 	struct msgbuf *bufp, cur;
67ccdb2370SIan Dowse 	char *bp, *ep, *memf, *nextp, *nlistf, *p, *q, *visbp;
688fae3551SRodney W. Grimes 	kvm_t *kd;
69560bb4f8SDavid E. O'Brien 	size_t buflen, bufpos;
70ccdb2370SIan Dowse 	long pri;
7111967f3cSEitan Adler 	int ch, clear;
7211967f3cSEitan Adler 	bool all;
738fae3551SRodney W. Grimes 
7411967f3cSEitan Adler 	all = false;
7511967f3cSEitan Adler 	clear = false;
768dcf55a4SAndrey A. Chernov 	(void) setlocale(LC_CTYPE, "");
778fae3551SRodney W. Grimes 	memf = nlistf = NULL;
7811967f3cSEitan Adler 	while ((ch = getopt(argc, argv, "acM:N:")) != -1)
798fae3551SRodney W. Grimes 		switch(ch) {
809d133455SPoul-Henning Kamp 		case 'a':
8111967f3cSEitan Adler 			all = true;
8211967f3cSEitan Adler 			break;
8311967f3cSEitan Adler 		case 'c':
8411967f3cSEitan Adler 			clear = true;
859d133455SPoul-Henning Kamp 			break;
868fae3551SRodney W. Grimes 		case 'M':
878fae3551SRodney W. Grimes 			memf = optarg;
888fae3551SRodney W. Grimes 			break;
898fae3551SRodney W. Grimes 		case 'N':
908fae3551SRodney W. Grimes 			nlistf = optarg;
918fae3551SRodney W. Grimes 			break;
928fae3551SRodney W. Grimes 		case '?':
938fae3551SRodney W. Grimes 		default:
948fae3551SRodney W. Grimes 			usage();
958fae3551SRodney W. Grimes 		}
968fae3551SRodney W. Grimes 	argc -= optind;
97b8a2c7caSJens Schweikhardt 	if (argc != 0)
98b8a2c7caSJens Schweikhardt 		usage();
998fae3551SRodney W. Grimes 
10046fb2e1dSRuslan Ermilov 	if (memf == NULL) {
101ccdb2370SIan Dowse 		/*
10293c3ad10SIan Lepore 		 * Running kernel.  Use sysctl.  This gives an unwrapped buffer
10393c3ad10SIan Lepore 		 * as a side effect.  Remove nulterm (if present) so the value
10493c3ad10SIan Lepore 		 * returned by sysctl is formatted as the rest of the code
10593c3ad10SIan Lepore 		 * expects (the same as the value read from a core file below).
106ccdb2370SIan Dowse 		 */
107676adc04SThomas Moestl 		if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)
108676adc04SThomas Moestl 			err(1, "sysctl kern.msgbuf");
109f8ee9548SEric van Gyzen 		/* Allocate extra room for growth between the sysctl calls. */
110f8ee9548SEric van Gyzen 		buflen += buflen/8;
111f8ee9548SEric van Gyzen 		/* Allocate more than sysctl sees, for room to append \n\0. */
112ccdb2370SIan Dowse 		if ((bp = malloc(buflen + 2)) == NULL)
113676adc04SThomas Moestl 			errx(1, "malloc failed");
114676adc04SThomas Moestl 		if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
115676adc04SThomas Moestl 			err(1, "sysctl kern.msgbuf");
11693c3ad10SIan Lepore 		if (buflen > 0 && bp[buflen - 1] == '\0')
11793c3ad10SIan Lepore 			buflen--;
118e1de133cSFlorian Smeets 		if (clear)
119e1de133cSFlorian Smeets 			if (sysctlbyname("kern.msgbuf_clear", NULL, NULL, &clear, sizeof(int)))
120e1de133cSFlorian Smeets 				err(1, "sysctl kern.msgbuf_clear");
121676adc04SThomas Moestl 	} else {
122ccdb2370SIan Dowse 		/* Read in kernel message buffer and do sanity checks. */
123676adc04SThomas Moestl 		kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
124676adc04SThomas Moestl 		if (kd == NULL)
1258fae3551SRodney W. Grimes 			exit (1);
1268fae3551SRodney W. Grimes 		if (kvm_nlist(kd, nl) == -1)
1278fae3551SRodney W. Grimes 			errx(1, "kvm_nlist: %s", kvm_geterr(kd));
1288fae3551SRodney W. Grimes 		if (nl[X_MSGBUF].n_type == 0)
129676adc04SThomas Moestl 			errx(1, "%s: msgbufp not found",
130676adc04SThomas Moestl 			    nlistf ? nlistf : "namelist");
1318fae3551SRodney W. Grimes 		if (KREAD(nl[X_MSGBUF].n_value, bufp) || KREAD((long)bufp, cur))
1328fae3551SRodney W. Grimes 			errx(1, "kvm_read: %s", kvm_geterr(kd));
1338fae3551SRodney W. Grimes 		if (cur.msg_magic != MSG_MAGIC)
134676adc04SThomas Moestl 			errx(1, "kernel message buffer has different magic "
135676adc04SThomas Moestl 			    "number");
136ccdb2370SIan Dowse 		if ((bp = malloc(cur.msg_size + 2)) == NULL)
13758067a99SPoul-Henning Kamp 			errx(1, "malloc failed");
138ccdb2370SIan Dowse 
13959f256ecSIan Dowse 		/* Unwrap the circular buffer to start from the oldest data. */
14059f256ecSIan Dowse 		bufpos = MSGBUF_SEQ_TO_POS(&cur, cur.msg_wseq);
14159f256ecSIan Dowse 		if (kvm_read(kd, (long)&cur.msg_ptr[bufpos], bp,
14257517b09SXin LI 		    cur.msg_size - bufpos) != (ssize_t)(cur.msg_size - bufpos))
14359f256ecSIan Dowse 			errx(1, "kvm_read: %s", kvm_geterr(kd));
14459f256ecSIan Dowse 		if (bufpos != 0 && kvm_read(kd, (long)cur.msg_ptr,
14557517b09SXin LI 		    &bp[cur.msg_size - bufpos], bufpos) != (ssize_t)bufpos)
14658067a99SPoul-Henning Kamp 			errx(1, "kvm_read: %s", kvm_geterr(kd));
14758067a99SPoul-Henning Kamp 		kvm_close(kd);
148676adc04SThomas Moestl 		buflen = cur.msg_size;
149676adc04SThomas Moestl 	}
1508fae3551SRodney W. Grimes 
1518fae3551SRodney W. Grimes 	/*
152ccdb2370SIan Dowse 	 * Ensure that the buffer ends with a newline and a \0 to avoid
153ccdb2370SIan Dowse 	 * complications below.  We left space above.
154ccdb2370SIan Dowse 	 */
155ccdb2370SIan Dowse 	if (buflen == 0 || bp[buflen - 1] != '\n')
156ccdb2370SIan Dowse 		bp[buflen++] = '\n';
157ccdb2370SIan Dowse 	bp[buflen] = '\0';
158ccdb2370SIan Dowse 
159ccdb2370SIan Dowse 	if ((visbp = malloc(4 * buflen + 1)) == NULL)
160ccdb2370SIan Dowse 		errx(1, "malloc failed");
161ccdb2370SIan Dowse 
162ccdb2370SIan Dowse 	/*
16359f256ecSIan Dowse 	 * The message buffer is circular, but has been unwrapped so that
16459f256ecSIan Dowse 	 * the oldest data comes first.  The data will be preceded by \0's
16559f256ecSIan Dowse 	 * if the message buffer was not full.
1668fae3551SRodney W. Grimes 	 */
16758067a99SPoul-Henning Kamp 	p = bp;
16859f256ecSIan Dowse 	ep = &bp[buflen];
16959f256ecSIan Dowse 	if (*p == '\0') {
17059f256ecSIan Dowse 		/* Strip leading \0's */
171ccdb2370SIan Dowse 		while (*p == '\0')
17259f256ecSIan Dowse 			p++;
1739d133455SPoul-Henning Kamp 	}
174ccdb2370SIan Dowse 	for (; p < ep; p = nextp) {
1754c86f66fSStefan Farfeleder 		nextp = memchr(p, '\n', ep - p);
1764c86f66fSStefan Farfeleder 		nextp++;
177ccdb2370SIan Dowse 
17859f256ecSIan Dowse 		/* Skip ^<[0-9]+> syslog sequences. */
17948697608SDavid Malone 		if (*p == '<' && isdigit(*(p+1))) {
180ccdb2370SIan Dowse 			errno = 0;
181ccdb2370SIan Dowse 			pri = strtol(p + 1, &q, 10);
182ccdb2370SIan Dowse 			if (*q == '>' && pri >= 0 && pri < INT_MAX &&
183ccdb2370SIan Dowse 			    errno == 0) {
18459f256ecSIan Dowse 				if (LOG_FAC(pri) != LOG_KERN && !all)
1858fae3551SRodney W. Grimes 					continue;
18659f256ecSIan Dowse 				p = q + 1;
1878fae3551SRodney W. Grimes 			}
18859f256ecSIan Dowse 		}
189ccdb2370SIan Dowse 
190ccdb2370SIan Dowse 		(void)strvisx(visbp, p, nextp - p, 0);
191ccdb2370SIan Dowse 		(void)printf("%s", visbp);
19259f256ecSIan Dowse 	}
1938fae3551SRodney W. Grimes 	exit(0);
1948fae3551SRodney W. Grimes }
1958fae3551SRodney W. Grimes 
1968fae3551SRodney W. Grimes void
usage(void)1971fa5ae8fSWarner Losh usage(void)
1988fae3551SRodney W. Grimes {
19911967f3cSEitan Adler 	fprintf(stderr, "usage: dmesg [-ac] [-M core [-N system]]\n");
2008fae3551SRodney W. Grimes 	exit(1);
2018fae3551SRodney W. Grimes }
202