dmesg.c revision 1.32 1 /* $NetBSD: dmesg.c,v 1.32 2018/04/11 06:41:23 wiz 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.32 2018/04/11 06:41:23 wiz 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;
88 int deltas, quiet, humantime;
89
90 static const int bmib[] = { CTL_KERN, KERN_BOOTTIME };
91 size = sizeof(boottime);
92
93 boottime.tv_sec = 0;
94 boottime.tv_usec = 0;
95 lasttime.tv_sec = 0;
96 lasttime.tv_nsec = 0;
97 deltas = quiet = humantime = 0;
98
99 (void)sysctl(bmib, 2, &boottime, &size, NULL, 0);
100
101 memf = nlistf = NULL;
102 while ((ch = getopt(argc, argv, "dM:N:tT")) != -1)
103 switch(ch) {
104 case 'd':
105 deltas = 1;
106 break;
107 case 'M':
108 memf = optarg;
109 break;
110 case 'N':
111 nlistf = optarg;
112 break;
113 case 't':
114 quiet = 1;
115 break;
116 case 'T':
117 humantime = 1;
118 break;
119 case '?':
120 default:
121 usage();
122 }
123 argc -= optind;
124 argv += optind;
125 if (quiet && humantime)
126 err(EXIT_FAILURE, "-t cannot be used with -T");
127
128 if (memf == NULL) {
129 #endif
130 static const int mmib[2] = { CTL_KERN, KERN_MSGBUF };
131
132 if (sysctl(mmib, 2, NULL, &size, NULL, 0) == -1 ||
133 (bufdata = malloc(size)) == NULL ||
134 sysctl(mmib, 2, bufdata, &size, NULL, 0) == -1)
135 err(1, "can't get msgbuf");
136
137 /* make a dummy struct msgbuf for the display logic */
138 cur.msg_bufx = 0;
139 cur.msg_bufs = size;
140 #ifndef SMALL
141 } else {
142 kvm_t *kd;
143 struct kern_msgbuf *bufp;
144
145 /*
146 * Read in message buffer header and data, and do sanity
147 * checks.
148 */
149 kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
150 if (kd == NULL)
151 exit (1);
152 if (kvm_nlist(kd, nl) == -1)
153 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
154 if (nl[X_MSGBUF].n_type == 0)
155 errx(1, "%s: msgbufp not found", nlistf ? nlistf :
156 "namelist");
157 if (KREAD(nl[X_MSGBUF].n_value, bufp))
158 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
159 nl[X_MSGBUF].n_value);
160 if (kvm_read(kd, (long)bufp, &cur,
161 offsetof(struct kern_msgbuf, msg_bufc)) !=
162 offsetof(struct kern_msgbuf, msg_bufc))
163 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd),
164 (unsigned long)bufp);
165 if (cur.msg_magic != MSG_MAGIC)
166 errx(1, "magic number incorrect");
167 bufdata = malloc(cur.msg_bufs);
168 if (bufdata == NULL)
169 errx(1, "couldn't allocate space for buffer data");
170 if (kvm_read(kd, (long)&bufp->msg_bufc, bufdata,
171 cur.msg_bufs) != cur.msg_bufs)
172 errx(1, "kvm_read: %s", kvm_geterr(kd));
173 kvm_close(kd);
174 if (cur.msg_bufx >= cur.msg_bufs)
175 cur.msg_bufx = 0;
176 }
177 #endif
178
179 /*
180 * The message buffer is circular; start at the write pointer
181 * (which points the oldest character), and go to the write
182 * pointer - 1 (which points the newest character). I.e, loop
183 * over cur.msg_bufs times. Unused area is skipped since it
184 * contains nul.
185 */
186 for (tstamp = 0, newl = 1, log = i = 0, p = bufdata + cur.msg_bufx;
187 i < cur.msg_bufs; i++, p++) {
188 #ifndef SMALL
189 if (p == bufdata + cur.msg_bufs)
190 p = bufdata;
191 #define ADDC(c) \
192 do \
193 if (tstamp < sizeof(tbuf) - 1) \
194 tbuf[tstamp++] = (c); \
195 while (/*CONSTCOND*/0)
196 #else
197 #define ADDC(c)
198 #endif
199 ch = *p;
200 if (ch == '\0')
201 continue;
202 /* Skip "\n<.*>" syslog sequences. */
203 /* Gather timestamp sequences */
204 if (newl) {
205 switch (ch) {
206 case '[':
207 ADDC(ch);
208 continue;
209 case '<':
210 log = 1;
211 continue;
212 case '>':
213 log = 0;
214 continue;
215 case ']':
216 ADDC(ch);
217 ADDC('\0');
218 tstamp = 0;
219 #ifndef SMALL
220 sscanf(tbuf, "[%jd.%ld]", &sec, &nsec);
221 if (!quiet || deltas)
222 printf("[");
223 if (humantime) {
224 time_t t;
225 struct tm tm;
226 t = boottime.tv_sec + sec;
227 if (localtime_r(&t, &tm) != NULL) {
228 strftime(tbuf, sizeof(tbuf),
229 "%a %b %e %H:%M:%S %Z %Y",
230 &tm);
231 printf("%s", tbuf);
232 }
233 } else if (!quiet) {
234 printf("% 9jd.%06ld",
235 sec, nsec / 1000);
236 }
237 if (deltas) {
238 struct timespec nt = { sec, nsec };
239 struct timespec dt;
240 timespecsub(&nt, &lasttime, &dt);
241 if (humantime || !quiet)
242 printf(" ");
243 printf("<% 4jd.%06ld>", (intmax_t)
244 dt.tv_sec, dt.tv_nsec / 1000);
245 lasttime = nt;
246 }
247 if (!quiet || deltas)
248 printf("] ");
249 #endif
250 continue;
251 case ' ':
252 if (!tstamp)
253 continue;
254 /*FALLTHROUGH*/
255 default:
256 if (tstamp) {
257 ADDC(ch);
258 continue;
259 }
260 if (log)
261 continue;
262 break;
263 }
264 newl = 0;
265 }
266 newl = ch == '\n';
267 (void)vis(buf, ch, VIS_NOSLASH, 0);
268 #ifndef SMALL
269 if (buf[1] == 0)
270 (void)putchar(buf[0]);
271 else
272 #endif
273 (void)printf("%s", buf);
274 }
275 if (!newl)
276 (void)putchar('\n');
277 return EXIT_SUCCESS;
278 }
279
280 #ifndef SMALL
281 static void
282 usage(void)
283 {
284
285 (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n",
286 getprogname());
287 exit(EXIT_FAILURE);
288 }
289 #endif
290