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