1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/msgbuf.h>
34 #include <sys/sysctl.h>
35
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <kvm.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <nlist.h>
44 #include <stdio.h>
45 #include <stdbool.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <vis.h>
50 #include <sys/syslog.h>
51
52 static struct nlist nl[] = {
53 #define X_MSGBUF 0
54 { "_msgbufp", 0, 0, 0, 0 },
55 { NULL, 0, 0, 0, 0 },
56 };
57
58 void usage(void) __dead2;
59
60 #define KREAD(addr, var) \
61 kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
62
63 int
main(int argc,char * argv[])64 main(int argc, char *argv[])
65 {
66 struct msgbuf *bufp, cur;
67 char *bp, *ep, *memf, *nextp, *nlistf, *p, *q, *visbp;
68 kvm_t *kd;
69 size_t buflen, bufpos;
70 long pri;
71 int ch, clear;
72 bool all;
73
74 all = false;
75 clear = false;
76 (void) setlocale(LC_CTYPE, "");
77 memf = nlistf = NULL;
78 while ((ch = getopt(argc, argv, "acM:N:")) != -1)
79 switch(ch) {
80 case 'a':
81 all = true;
82 break;
83 case 'c':
84 clear = true;
85 break;
86 case 'M':
87 memf = optarg;
88 break;
89 case 'N':
90 nlistf = optarg;
91 break;
92 case '?':
93 default:
94 usage();
95 }
96 argc -= optind;
97 if (argc != 0)
98 usage();
99
100 if (memf == NULL) {
101 /*
102 * Running kernel. Use sysctl. This gives an unwrapped buffer
103 * as a side effect. Remove nulterm (if present) so the value
104 * returned by sysctl is formatted as the rest of the code
105 * expects (the same as the value read from a core file below).
106 */
107 if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)
108 err(1, "sysctl kern.msgbuf");
109 /* Allocate extra room for growth between the sysctl calls. */
110 buflen += buflen/8;
111 /* Allocate more than sysctl sees, for room to append \n\0. */
112 if ((bp = malloc(buflen + 2)) == NULL)
113 errx(1, "malloc failed");
114 if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
115 err(1, "sysctl kern.msgbuf");
116 if (buflen > 0 && bp[buflen - 1] == '\0')
117 buflen--;
118 if (clear)
119 if (sysctlbyname("kern.msgbuf_clear", NULL, NULL, &clear, sizeof(int)))
120 err(1, "sysctl kern.msgbuf_clear");
121 } else {
122 /* Read in kernel message buffer and do sanity checks. */
123 kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
124 if (kd == NULL)
125 exit (1);
126 if (kvm_nlist(kd, nl) == -1)
127 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
128 if (nl[X_MSGBUF].n_type == 0)
129 errx(1, "%s: msgbufp not found",
130 nlistf ? nlistf : "namelist");
131 if (KREAD(nl[X_MSGBUF].n_value, bufp) || KREAD((long)bufp, cur))
132 errx(1, "kvm_read: %s", kvm_geterr(kd));
133 if (cur.msg_magic != MSG_MAGIC)
134 errx(1, "kernel message buffer has different magic "
135 "number");
136 if ((bp = malloc(cur.msg_size + 2)) == NULL)
137 errx(1, "malloc failed");
138
139 /* Unwrap the circular buffer to start from the oldest data. */
140 bufpos = MSGBUF_SEQ_TO_POS(&cur, cur.msg_wseq);
141 if (kvm_read(kd, (long)&cur.msg_ptr[bufpos], bp,
142 cur.msg_size - bufpos) != (ssize_t)(cur.msg_size - bufpos))
143 errx(1, "kvm_read: %s", kvm_geterr(kd));
144 if (bufpos != 0 && kvm_read(kd, (long)cur.msg_ptr,
145 &bp[cur.msg_size - bufpos], bufpos) != (ssize_t)bufpos)
146 errx(1, "kvm_read: %s", kvm_geterr(kd));
147 kvm_close(kd);
148 buflen = cur.msg_size;
149 }
150
151 /*
152 * Ensure that the buffer ends with a newline and a \0 to avoid
153 * complications below. We left space above.
154 */
155 if (buflen == 0 || bp[buflen - 1] != '\n')
156 bp[buflen++] = '\n';
157 bp[buflen] = '\0';
158
159 if ((visbp = malloc(4 * buflen + 1)) == NULL)
160 errx(1, "malloc failed");
161
162 /*
163 * The message buffer is circular, but has been unwrapped so that
164 * the oldest data comes first. The data will be preceded by \0's
165 * if the message buffer was not full.
166 */
167 p = bp;
168 ep = &bp[buflen];
169 if (*p == '\0') {
170 /* Strip leading \0's */
171 while (*p == '\0')
172 p++;
173 }
174 for (; p < ep; p = nextp) {
175 nextp = memchr(p, '\n', ep - p);
176 nextp++;
177
178 /* Skip ^<[0-9]+> syslog sequences. */
179 if (*p == '<' && isdigit(*(p+1))) {
180 errno = 0;
181 pri = strtol(p + 1, &q, 10);
182 if (*q == '>' && pri >= 0 && pri < INT_MAX &&
183 errno == 0) {
184 if (LOG_FAC(pri) != LOG_KERN && !all)
185 continue;
186 p = q + 1;
187 }
188 }
189
190 (void)strvisx(visbp, p, nextp - p, 0);
191 (void)printf("%s", visbp);
192 }
193 exit(0);
194 }
195
196 void
usage(void)197 usage(void)
198 {
199 fprintf(stderr, "usage: dmesg [-ac] [-M core [-N system]]\n");
200 exit(1);
201 }
202