1 /* $NetBSD: dmesg.c,v 1.45 2020/01/01 00:24:52 kre 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.45 2020/01/01 00:24:52 kre 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 <ctype.h> 51 #include <fcntl.h> 52 #include <time.h> 53 #include <kvm.h> 54 #include <nlist.h> 55 #include <stdio.h> 56 #include <stddef.h> 57 #include <stdlib.h> 58 #include <unistd.h> 59 #include <vis.h> 60 61 #ifndef SMALL 62 #include <langinfo.h> 63 #include <locale.h> 64 65 static struct nlist nl[] = { 66 #define X_MSGBUF 0 67 { .n_name = "_msgbufp" }, 68 { .n_name = NULL }, 69 }; 70 71 static const char *radix; 72 73 __dead static void usage(void); 74 75 #define KREAD(addr, var) \ 76 kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var) 77 78 static const char * 79 fmtydhmsf(char *b, size_t l, intmax_t t, long nsec, int ht) 80 { 81 intmax_t s, m, h; 82 int z; 83 int prec; 84 size_t o; 85 86 s = t % 60; 87 t /= 60; 88 89 m = t % 60; 90 t /= 60; 91 92 h = t; 93 94 z = 0; 95 o = 0; 96 97 #define APPENDFMT(fmt, ...) \ 98 do { \ 99 z = snprintf(b + o, l - o, fmt, __VA_ARGS__); \ 100 if (z == -1) \ 101 return b; \ 102 o += (size_t)z; \ 103 if (o >= l) \ 104 return b; \ 105 } while (/*CONSTCOND*/0) 106 107 #define APPEND(a) \ 108 do if (a) \ 109 APPENDFMT("%jd%c", a, toupper((unsigned char)__STRING(a)[0])); \ 110 while (/*CONSTCOND*/0) 111 #define APPENDS(a, pr, ms) \ 112 APPENDFMT("%jd%s%.*ld%c", a, radix, pr, ms, \ 113 toupper((unsigned char)__STRING(a)[0])) 114 115 APPENDFMT("%s", "P"); 116 APPENDFMT("%s", "T"); 117 APPEND(h); 118 APPEND(m); 119 if (nsec) 120 nsec = (nsec + 500000) / 1000000; /* now milliseconds */ 121 prec = 3; 122 if (nsec && ht == 2) { 123 while (prec > 0 && (nsec % 10) == 0) 124 --prec, nsec /= 10; 125 } 126 if (nsec || ht > 2) 127 APPENDS(s, prec, nsec); 128 else 129 APPEND(s); 130 return b; 131 } 132 133 static void 134 pnsec(long nsec, long fsec, int scale) 135 { 136 if (scale > 6) 137 printf("%6.6ld", (nsec + 499) / 1000); 138 else 139 printf("%*.*ld%.*s", scale, scale, fsec, 6 - scale, "000000"); 140 } 141 #endif 142 143 int 144 main(int argc, char *argv[]) 145 { 146 struct kern_msgbuf cur; 147 int ch, newl, log, i; 148 size_t tstamp, size; 149 char *p, *bufdata; 150 char buf[5]; 151 #ifndef SMALL 152 char tbuf[64]; 153 char *memf, *nlistf; 154 struct timespec boottime; 155 struct timespec lasttime; 156 intmax_t sec; 157 long nsec, fsec; 158 int scale; 159 int deltas, quiet, humantime; 160 bool frac, postts; 161 162 static const int bmib[] = { CTL_KERN, KERN_BOOTTIME }; 163 size = sizeof(boottime); 164 165 (void)setlocale(LC_ALL, ""); 166 radix = nl_langinfo(RADIXCHAR); 167 if (radix == NULL) 168 radix = "."; /* could also select "," */ 169 170 boottime.tv_sec = 0; 171 boottime.tv_nsec = 0; 172 lasttime.tv_sec = 0; 173 lasttime.tv_nsec = 0; 174 deltas = quiet = humantime = 0; 175 176 (void)sysctl(bmib, 2, &boottime, &size, NULL, 0); 177 178 memf = nlistf = NULL; 179 while ((ch = getopt(argc, argv, "dM:N:tT")) != -1) 180 switch(ch) { 181 case 'd': 182 deltas = 1; 183 break; 184 case 'M': 185 memf = optarg; 186 break; 187 case 'N': 188 nlistf = optarg; 189 break; 190 case 't': 191 quiet = 1; 192 break; 193 case 'T': 194 humantime++; 195 break; 196 case '?': 197 default: 198 usage(); 199 } 200 argc -= optind; 201 argv += optind; 202 if (quiet && humantime) 203 err(EXIT_FAILURE, "-t cannot be used with -T"); 204 205 if (memf == NULL) { 206 #endif 207 static const int mmib[2] = { CTL_KERN, KERN_MSGBUF }; 208 209 if (sysctl(mmib, 2, NULL, &size, NULL, 0) == -1 || 210 (bufdata = malloc(size)) == NULL || 211 sysctl(mmib, 2, bufdata, &size, NULL, 0) == -1) 212 err(1, "can't get msgbuf"); 213 214 /* make a dummy struct msgbuf for the display logic */ 215 cur.msg_bufx = 0; 216 cur.msg_bufs = size; 217 #ifndef SMALL 218 } else { 219 kvm_t *kd; 220 struct kern_msgbuf *bufp; 221 222 /* 223 * Read in message buffer header and data, and do sanity 224 * checks. 225 */ 226 kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg"); 227 if (kd == NULL) 228 exit (1); 229 if (kvm_nlist(kd, nl) == -1) 230 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 231 if (nl[X_MSGBUF].n_type == 0) 232 errx(1, "%s: msgbufp not found", nlistf ? nlistf : 233 "namelist"); 234 if (KREAD(nl[X_MSGBUF].n_value, bufp)) 235 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd), 236 nl[X_MSGBUF].n_value); 237 if (kvm_read(kd, (long)bufp, &cur, 238 offsetof(struct kern_msgbuf, msg_bufc)) != 239 offsetof(struct kern_msgbuf, msg_bufc)) 240 errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd), 241 (unsigned long)bufp); 242 if (cur.msg_magic != MSG_MAGIC) 243 errx(1, "magic number incorrect"); 244 bufdata = malloc(cur.msg_bufs); 245 if (bufdata == NULL) 246 errx(1, "couldn't allocate space for buffer data"); 247 if (kvm_read(kd, (long)&bufp->msg_bufc, bufdata, 248 cur.msg_bufs) != cur.msg_bufs) 249 errx(1, "kvm_read: %s", kvm_geterr(kd)); 250 kvm_close(kd); 251 if (cur.msg_bufx >= cur.msg_bufs) 252 cur.msg_bufx = 0; 253 } 254 #endif 255 256 /* 257 * The message buffer is circular; start at the write pointer 258 * (which points the oldest character), and go to the write 259 * pointer - 1 (which points the newest character). I.e, loop 260 * over cur.msg_bufs times. Unused area is skipped since it 261 * contains nul. 262 */ 263 #ifndef SMALL 264 frac = false; 265 postts = false; 266 scale = 0; 267 #endif 268 for (tstamp = 0, newl = 1, log = i = 0, p = bufdata + cur.msg_bufx; 269 i < cur.msg_bufs; i++, p++) { 270 271 #ifndef SMALL 272 if (p == bufdata + cur.msg_bufs) 273 p = bufdata; 274 #define ADDC(c) \ 275 do { \ 276 if (tstamp < sizeof(tbuf) - 1) \ 277 tbuf[tstamp++] = (c); \ 278 if (frac) \ 279 scale++; \ 280 } while (/*CONSTCOND*/0) 281 #else 282 #define ADDC(c) 283 #endif 284 ch = *p; 285 if (ch == '\0') 286 continue; 287 /* Skip "\n<.*>" syslog sequences. */ 288 /* Gather timestamp sequences */ 289 if (newl) { 290 #ifndef SMALL 291 int j; 292 #endif 293 294 switch (ch) { 295 #ifndef SMALL 296 case '[': 297 frac = false; 298 scale = 0; 299 ADDC(ch); 300 continue; 301 #endif 302 case '<': 303 log = 1; 304 continue; 305 case '>': 306 log = 0; 307 continue; 308 #ifndef SMALL 309 case ']': 310 frac = false; 311 ADDC(ch); 312 ADDC('\0'); 313 tstamp = 0; 314 postts = true; 315 sec = fsec = 0; 316 switch (sscanf(tbuf, "[%jd.%ld]", &sec, &fsec)){ 317 case EOF: 318 case 0: 319 /*???*/ 320 continue; 321 case 1: 322 fsec = 0; 323 break; 324 case 2: 325 break; 326 default: 327 /* Help */ 328 continue; 329 } 330 331 for (nsec = fsec, j = 9 - scale; --j >= 0; ) 332 nsec *= 10; 333 if (!quiet || deltas) 334 printf("["); 335 if (humantime == 1) { 336 time_t t; 337 struct tm tm; 338 339 t = boottime.tv_sec + sec; 340 if (nsec + boottime.tv_nsec >= 341 ( 1L /* 1 second */ 342 * 1000L /* ms */ 343 * 1000L /* us */ 344 * 1000L /* ns */ )) 345 t++; 346 347 if (localtime_r(&t, &tm) != NULL) { 348 strftime(tbuf, sizeof(tbuf), 349 "%a %b %e %H:%M:%S %Z %Y", 350 &tm); 351 printf("%s", tbuf); 352 } 353 } else if (humantime > 1) { 354 const char *fp = fmtydhmsf(tbuf, 355 sizeof(tbuf), sec, fsec, humantime); 356 if (fp) { 357 printf("%s", fp); 358 } 359 } else if (!quiet) { 360 printf(" %5jd%s", sec, radix); 361 pnsec(nsec, fsec, scale); 362 } 363 if (deltas) { 364 struct timespec nt = { sec, nsec }; 365 struct timespec dt; 366 367 timespecsub(&nt, &lasttime, &dt); 368 if (humantime || !quiet) 369 printf(" "); 370 printf("<% 4jd%s%6.6ld>", 371 (intmax_t)dt.tv_sec, radix, 372 (dt.tv_nsec+499) / 1000); 373 lasttime = nt; 374 } 375 if (!quiet || deltas) 376 printf("] "); 377 continue; 378 #endif 379 case ' ': 380 #ifndef SMALL 381 if (!tstamp && postts) { 382 postts = false; 383 #else 384 if (!tstamp) { 385 #endif 386 continue; 387 } 388 /*FALLTHROUGH*/ 389 default: 390 #ifndef SMALL 391 if (tstamp) { 392 ADDC(ch); 393 if (ch == '.') 394 frac = true; 395 continue; 396 } 397 #endif 398 if (log) 399 continue; 400 break; 401 } 402 } 403 newl = ch == '\n'; 404 (void)vis(buf, ch, VIS_NOSLASH, 0); 405 #ifndef SMALL 406 if (buf[1] == 0) 407 (void)putchar(buf[0]); 408 else 409 #endif 410 (void)printf("%s", buf); 411 } 412 if (!newl) 413 (void)putchar('\n'); 414 return EXIT_SUCCESS; 415 } 416 417 #ifndef SMALL 418 static void 419 usage(void) 420 { 421 422 (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n", 423 getprogname()); 424 exit(EXIT_FAILURE); 425 } 426 #endif 427