1 /* $NetBSD: dmesg.c,v 1.43 2019/06/04 11:59:05 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.43 2019/06/04 11:59:05 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; 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 scale = 0; 266 #endif 267 for (tstamp = 0, newl = 1, log = i = 0, p = bufdata + cur.msg_bufx; 268 i < cur.msg_bufs; i++, p++) { 269 270 #ifndef SMALL 271 if (p == bufdata + cur.msg_bufs) 272 p = bufdata; 273 #define ADDC(c) \ 274 do { \ 275 if (tstamp < sizeof(tbuf) - 1) \ 276 tbuf[tstamp++] = (c); \ 277 if (frac) \ 278 scale++; \ 279 } while (/*CONSTCOND*/0) 280 #else 281 #define ADDC(c) 282 #endif 283 ch = *p; 284 if (ch == '\0') 285 continue; 286 /* Skip "\n<.*>" syslog sequences. */ 287 /* Gather timestamp sequences */ 288 if (newl) { 289 #ifndef SMALL 290 int j; 291 #endif 292 293 switch (ch) { 294 #ifndef SMALL 295 case '[': 296 frac = false; 297 scale = 0; 298 ADDC(ch); 299 continue; 300 #endif 301 case '<': 302 log = 1; 303 continue; 304 case '>': 305 log = 0; 306 continue; 307 #ifndef SMALL 308 case ']': 309 frac = false; 310 ADDC(ch); 311 ADDC('\0'); 312 tstamp = 0; 313 sec = fsec = 0; 314 switch (sscanf(tbuf, "[%jd.%ld]", &sec, &fsec)){ 315 case EOF: 316 case 0: 317 /*???*/ 318 continue; 319 case 1: 320 fsec = 0; 321 break; 322 case 2: 323 break; 324 default: 325 /* Help */ 326 continue; 327 } 328 329 for (nsec = fsec, j = 9 - scale; --j >= 0; ) 330 nsec *= 10; 331 if (!quiet || deltas) 332 printf("["); 333 if (humantime == 1) { 334 time_t t; 335 struct tm tm; 336 337 t = boottime.tv_sec + sec; 338 if (nsec + boottime.tv_nsec >= 339 ( 1L /* 1 second */ 340 * 1000L /* ms */ 341 * 1000L /* us */ 342 * 1000L /* ns */ )) 343 t++; 344 345 if (localtime_r(&t, &tm) != NULL) { 346 strftime(tbuf, sizeof(tbuf), 347 "%a %b %e %H:%M:%S %Z %Y", 348 &tm); 349 printf("%s", tbuf); 350 } 351 } else if (humantime > 1) { 352 const char *fp = fmtydhmsf(tbuf, 353 sizeof(tbuf), sec, fsec, humantime); 354 if (fp) { 355 printf("%s", fp); 356 } 357 } else if (!quiet) { 358 printf(" %5jd%s", sec, radix); 359 pnsec(nsec, fsec, scale); 360 } 361 if (deltas) { 362 struct timespec nt = { sec, nsec }; 363 struct timespec dt; 364 365 timespecsub(&nt, &lasttime, &dt); 366 if (humantime || !quiet) 367 printf(" "); 368 printf("<% 4jd%s%6.6ld>", 369 (intmax_t)dt.tv_sec, radix, 370 (dt.tv_nsec+499) / 1000); 371 lasttime = nt; 372 } 373 if (!quiet || deltas) 374 printf("] "); 375 continue; 376 #endif 377 case ' ': 378 if (!tstamp) 379 continue; 380 /*FALLTHROUGH*/ 381 default: 382 #ifndef SMALL 383 if (tstamp) { 384 ADDC(ch); 385 if (ch == '.') 386 frac = true; 387 continue; 388 } 389 #endif 390 if (log) 391 continue; 392 break; 393 } 394 } 395 newl = ch == '\n'; 396 (void)vis(buf, ch, VIS_NOSLASH, 0); 397 #ifndef SMALL 398 if (buf[1] == 0) 399 (void)putchar(buf[0]); 400 else 401 #endif 402 (void)printf("%s", buf); 403 } 404 if (!newl) 405 (void)putchar('\n'); 406 return EXIT_SUCCESS; 407 } 408 409 #ifndef SMALL 410 static void 411 usage(void) 412 { 413 414 (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n", 415 getprogname()); 416 exit(EXIT_FAILURE); 417 } 418 #endif 419