1 /* $NetBSD: dmesg.c,v 1.41 2018/10/30 19:40:36 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.41 2018/10/30 19:40:36 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 case '[': 295 #ifndef SMALL 296 frac = false; 297 scale = 0; 298 #endif 299 ADDC(ch); 300 continue; 301 case '<': 302 log = 1; 303 continue; 304 case '>': 305 log = 0; 306 continue; 307 case ']': 308 #ifndef SMALL 309 frac = false; 310 #endif 311 ADDC(ch); 312 ADDC('\0'); 313 tstamp = 0; 314 #ifndef SMALL 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 #endif 378 continue; 379 case ' ': 380 if (!tstamp) 381 continue; 382 /*FALLTHROUGH*/ 383 default: 384 if (tstamp) { 385 ADDC(ch); 386 #ifndef SMALL 387 if (ch == '.') 388 frac = true; 389 #endif 390 continue; 391 } 392 if (log) 393 continue; 394 break; 395 } 396 newl = 0; 397 } 398 newl = ch == '\n'; 399 (void)vis(buf, ch, VIS_NOSLASH, 0); 400 #ifndef SMALL 401 if (buf[1] == 0) 402 (void)putchar(buf[0]); 403 else 404 #endif 405 (void)printf("%s", buf); 406 } 407 if (!newl) 408 (void)putchar('\n'); 409 return EXIT_SUCCESS; 410 } 411 412 #ifndef SMALL 413 static void 414 usage(void) 415 { 416 417 (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n", 418 getprogname()); 419 exit(EXIT_FAILURE); 420 } 421 #endif 422