1 1.51 rin /* $NetBSD: dmesg.c,v 1.51 2022/08/06 10:22:22 rin Exp $ */ 2 1.1 cgd /*- 3 1.6 cgd * Copyright (c) 1991, 1993 4 1.6 cgd * The Regents of the University of California. All rights reserved. 5 1.1 cgd * 6 1.1 cgd * Redistribution and use in source and binary forms, with or without 7 1.1 cgd * modification, are permitted provided that the following conditions 8 1.1 cgd * are met: 9 1.1 cgd * 1. Redistributions of source code must retain the above copyright 10 1.1 cgd * notice, this list of conditions and the following disclaimer. 11 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 cgd * notice, this list of conditions and the following disclaimer in the 13 1.1 cgd * documentation and/or other materials provided with the distribution. 14 1.22 agc * 3. Neither the name of the University nor the names of its contributors 15 1.1 cgd * may be used to endorse or promote products derived from this software 16 1.1 cgd * without specific prior written permission. 17 1.1 cgd * 18 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 cgd * SUCH DAMAGE. 29 1.1 cgd */ 30 1.1 cgd 31 1.11 lukem #include <sys/cdefs.h> 32 1.1 cgd #ifndef lint 33 1.26 lukem __COPYRIGHT("@(#) Copyright (c) 1991, 1993\ 34 1.26 lukem The Regents of the University of California. All rights reserved."); 35 1.1 cgd #endif /* not lint */ 36 1.1 cgd 37 1.1 cgd #ifndef lint 38 1.8 cgd #if 0 39 1.6 cgd static char sccsid[] = "@(#)dmesg.c 8.1 (Berkeley) 6/5/93"; 40 1.8 cgd #else 41 1.51 rin __RCSID("$NetBSD: dmesg.c,v 1.51 2022/08/06 10:22:22 rin Exp $"); 42 1.8 cgd #endif 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.17 simonb #include <sys/param.h> 46 1.1 cgd #include <sys/msgbuf.h> 47 1.17 simonb #include <sys/sysctl.h> 48 1.6 cgd 49 1.7 cgd #include <err.h> 50 1.34 christos #include <ctype.h> 51 1.6 cgd #include <fcntl.h> 52 1.28 christos #include <time.h> 53 1.6 cgd #include <kvm.h> 54 1.1 cgd #include <nlist.h> 55 1.6 cgd #include <stdio.h> 56 1.17 simonb #include <stddef.h> 57 1.1 cgd #include <stdlib.h> 58 1.5 jtc #include <unistd.h> 59 1.6 cgd #include <vis.h> 60 1.1 cgd 61 1.20 simonb #ifndef SMALL 62 1.37 christos #include <langinfo.h> 63 1.37 christos #include <locale.h> 64 1.37 christos 65 1.27 joerg static struct nlist nl[] = { 66 1.6 cgd #define X_MSGBUF 0 67 1.25 christos { .n_name = "_msgbufp" }, 68 1.25 christos { .n_name = NULL }, 69 1.1 cgd }; 70 1.1 cgd 71 1.37 christos static const char *radix; 72 1.37 christos 73 1.27 joerg __dead static void usage(void); 74 1.1 cgd 75 1.6 cgd #define KREAD(addr, var) \ 76 1.6 cgd kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var) 77 1.34 christos 78 1.34 christos static const char * 79 1.36 kre fmtydhmsf(char *b, size_t l, intmax_t t, long nsec, int ht) 80 1.34 christos { 81 1.38 kre intmax_t s, m, h; 82 1.34 christos int z; 83 1.35 kre int prec; 84 1.34 christos size_t o; 85 1.34 christos 86 1.34 christos s = t % 60; 87 1.34 christos t /= 60; 88 1.34 christos 89 1.34 christos m = t % 60; 90 1.34 christos t /= 60; 91 1.34 christos 92 1.37 christos h = t; 93 1.34 christos 94 1.34 christos z = 0; 95 1.34 christos o = 0; 96 1.34 christos 97 1.34 christos #define APPENDFMT(fmt, ...) \ 98 1.34 christos do { \ 99 1.34 christos z = snprintf(b + o, l - o, fmt, __VA_ARGS__); \ 100 1.34 christos if (z == -1) \ 101 1.34 christos return b; \ 102 1.34 christos o += (size_t)z; \ 103 1.34 christos if (o >= l) \ 104 1.34 christos return b; \ 105 1.34 christos } while (/*CONSTCOND*/0) 106 1.34 christos 107 1.34 christos #define APPEND(a) \ 108 1.34 christos do if (a) \ 109 1.40 kre APPENDFMT("%jd%c", a, toupper((unsigned char)__STRING(a)[0])); \ 110 1.34 christos while (/*CONSTCOND*/0) 111 1.35 kre #define APPENDS(a, pr, ms) \ 112 1.35 kre APPENDFMT("%jd%s%.*ld%c", a, radix, pr, ms, \ 113 1.34 christos toupper((unsigned char)__STRING(a)[0])) 114 1.34 christos 115 1.34 christos APPENDFMT("%s", "P"); 116 1.34 christos APPENDFMT("%s", "T"); 117 1.34 christos APPEND(h); 118 1.34 christos APPEND(m); 119 1.34 christos if (nsec) 120 1.35 kre nsec = (nsec + 500000) / 1000000; /* now milliseconds */ 121 1.35 kre prec = 3; 122 1.36 kre if (nsec && ht == 2) { 123 1.36 kre while (prec > 0 && (nsec % 10) == 0) 124 1.36 kre --prec, nsec /= 10; 125 1.36 kre } 126 1.36 kre if (nsec || ht > 2) 127 1.35 kre APPENDS(s, prec, nsec); 128 1.34 christos else 129 1.34 christos APPEND(s); 130 1.34 christos return b; 131 1.34 christos } 132 1.34 christos 133 1.34 christos static void 134 1.34 christos pnsec(long nsec, long fsec, int scale) 135 1.34 christos { 136 1.34 christos if (scale > 6) 137 1.34 christos printf("%6.6ld", (nsec + 499) / 1000); 138 1.34 christos else 139 1.34 christos printf("%*.*ld%.*s", scale, scale, fsec, 6 - scale, "000000"); 140 1.34 christos } 141 1.24 dsl #endif 142 1.6 cgd 143 1.6 cgd int 144 1.18 simonb main(int argc, char *argv[]) 145 1.1 cgd { 146 1.17 simonb struct kern_msgbuf cur; 147 1.28 christos int ch, newl, log, i; 148 1.50 rin size_t size; 149 1.20 simonb char *p, *bufdata; 150 1.28 christos char buf[5]; 151 1.20 simonb #ifndef SMALL 152 1.50 rin size_t tstamp; 153 1.49 rin char tbuf[64]; 154 1.20 simonb char *memf, *nlistf; 155 1.41 kre struct timespec boottime; 156 1.31 christos struct timespec lasttime; 157 1.31 christos intmax_t sec; 158 1.33 kre long nsec, fsec; 159 1.33 kre int scale; 160 1.31 christos int deltas, quiet, humantime; 161 1.44 tsutsui bool frac, postts; 162 1.40 kre 163 1.28 christos static const int bmib[] = { CTL_KERN, KERN_BOOTTIME }; 164 1.28 christos size = sizeof(boottime); 165 1.28 christos 166 1.37 christos (void)setlocale(LC_ALL, ""); 167 1.37 christos radix = nl_langinfo(RADIXCHAR); 168 1.37 christos if (radix == NULL) 169 1.37 christos radix = "."; /* could also select "," */ 170 1.37 christos 171 1.28 christos boottime.tv_sec = 0; 172 1.41 kre boottime.tv_nsec = 0; 173 1.31 christos lasttime.tv_sec = 0; 174 1.31 christos lasttime.tv_nsec = 0; 175 1.31 christos deltas = quiet = humantime = 0; 176 1.28 christos 177 1.40 kre (void)sysctl(bmib, 2, &boottime, &size, NULL, 0); 178 1.1 cgd 179 1.6 cgd memf = nlistf = NULL; 180 1.31 christos while ((ch = getopt(argc, argv, "dM:N:tT")) != -1) 181 1.1 cgd switch(ch) { 182 1.31 christos case 'd': 183 1.31 christos deltas = 1; 184 1.31 christos break; 185 1.1 cgd case 'M': 186 1.6 cgd memf = optarg; 187 1.1 cgd break; 188 1.1 cgd case 'N': 189 1.6 cgd nlistf = optarg; 190 1.1 cgd break; 191 1.31 christos case 't': 192 1.31 christos quiet = 1; 193 1.28 christos break; 194 1.31 christos case 'T': 195 1.34 christos humantime++; 196 1.28 christos break; 197 1.1 cgd case '?': 198 1.1 cgd default: 199 1.1 cgd usage(); 200 1.1 cgd } 201 1.1 cgd argc -= optind; 202 1.1 cgd argv += optind; 203 1.31 christos if (quiet && humantime) 204 1.31 christos err(EXIT_FAILURE, "-t cannot be used with -T"); 205 1.1 cgd 206 1.19 simonb if (memf == NULL) { 207 1.20 simonb #endif 208 1.28 christos static const int mmib[2] = { CTL_KERN, KERN_MSGBUF }; 209 1.17 simonb 210 1.28 christos if (sysctl(mmib, 2, NULL, &size, NULL, 0) == -1 || 211 1.24 dsl (bufdata = malloc(size)) == NULL || 212 1.28 christos sysctl(mmib, 2, bufdata, &size, NULL, 0) == -1) 213 1.17 simonb err(1, "can't get msgbuf"); 214 1.17 simonb 215 1.17 simonb /* make a dummy struct msgbuf for the display logic */ 216 1.24 dsl cur.msg_bufx = 0; 217 1.24 dsl cur.msg_bufs = size; 218 1.20 simonb #ifndef SMALL 219 1.17 simonb } else { 220 1.17 simonb kvm_t *kd; 221 1.17 simonb struct kern_msgbuf *bufp; 222 1.17 simonb 223 1.17 simonb /* 224 1.17 simonb * Read in message buffer header and data, and do sanity 225 1.17 simonb * checks. 226 1.17 simonb */ 227 1.17 simonb kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg"); 228 1.17 simonb if (kd == NULL) 229 1.17 simonb exit (1); 230 1.17 simonb if (kvm_nlist(kd, nl) == -1) 231 1.17 simonb errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 232 1.17 simonb if (nl[X_MSGBUF].n_type == 0) 233 1.17 simonb errx(1, "%s: msgbufp not found", nlistf ? nlistf : 234 1.17 simonb "namelist"); 235 1.17 simonb if (KREAD(nl[X_MSGBUF].n_value, bufp)) 236 1.17 simonb errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd), 237 1.17 simonb nl[X_MSGBUF].n_value); 238 1.17 simonb if (kvm_read(kd, (long)bufp, &cur, 239 1.17 simonb offsetof(struct kern_msgbuf, msg_bufc)) != 240 1.17 simonb offsetof(struct kern_msgbuf, msg_bufc)) 241 1.17 simonb errx(1, "kvm_read: %s (0x%lx)", kvm_geterr(kd), 242 1.17 simonb (unsigned long)bufp); 243 1.17 simonb if (cur.msg_magic != MSG_MAGIC) 244 1.17 simonb errx(1, "magic number incorrect"); 245 1.17 simonb bufdata = malloc(cur.msg_bufs); 246 1.17 simonb if (bufdata == NULL) 247 1.17 simonb errx(1, "couldn't allocate space for buffer data"); 248 1.17 simonb if (kvm_read(kd, (long)&bufp->msg_bufc, bufdata, 249 1.17 simonb cur.msg_bufs) != cur.msg_bufs) 250 1.17 simonb errx(1, "kvm_read: %s", kvm_geterr(kd)); 251 1.17 simonb kvm_close(kd); 252 1.17 simonb if (cur.msg_bufx >= cur.msg_bufs) 253 1.17 simonb cur.msg_bufx = 0; 254 1.17 simonb } 255 1.20 simonb #endif 256 1.1 cgd 257 1.1 cgd /* 258 1.14 enami * The message buffer is circular; start at the write pointer 259 1.14 enami * (which points the oldest character), and go to the write 260 1.14 enami * pointer - 1 (which points the newest character). I.e, loop 261 1.14 enami * over cur.msg_bufs times. Unused area is skipped since it 262 1.14 enami * contains nul. 263 1.1 cgd */ 264 1.33 kre #ifndef SMALL 265 1.33 kre frac = false; 266 1.44 tsutsui postts = false; 267 1.50 rin tstamp = 0; 268 1.33 kre scale = 0; 269 1.33 kre #endif 270 1.50 rin for (newl = 1, log = i = 0, p = bufdata + cur.msg_bufx; 271 1.14 enami i < cur.msg_bufs; i++, p++) { 272 1.33 kre 273 1.24 dsl #ifndef SMALL 274 1.12 leo if (p == bufdata + cur.msg_bufs) 275 1.12 leo p = bufdata; 276 1.46 rin #define ADDC(c) \ 277 1.46 rin do { \ 278 1.49 rin if (tstamp < sizeof(tbuf) - 1) \ 279 1.46 rin tbuf[tstamp++] = (c); \ 280 1.49 rin else { \ 281 1.49 rin /* Cannot be a timestamp. */ \ 282 1.49 rin tstamp = 0; \ 283 1.49 rin tbuf[sizeof(tbuf) - 1] = '\0'; \ 284 1.49 rin goto not_tstamp; \ 285 1.49 rin } \ 286 1.46 rin if (frac) \ 287 1.46 rin scale++; \ 288 1.46 rin } while (0) 289 1.47 rin #define PRTBUF() \ 290 1.47 rin for (char *_p = tbuf; *_p != '\0'; _p++) { \ 291 1.47 rin (void)vis(buf, *_p, VIS_NOSLASH, 0); \ 292 1.47 rin if (buf[1] == 0) \ 293 1.47 rin (void)putchar(buf[0]); \ 294 1.47 rin else \ 295 1.47 rin (void)printf("%s", buf); \ 296 1.47 rin } 297 1.24 dsl #endif 298 1.1 cgd ch = *p; 299 1.30 christos if (ch == '\0') 300 1.30 christos continue; 301 1.1 cgd /* Skip "\n<.*>" syslog sequences. */ 302 1.28 christos /* Gather timestamp sequences */ 303 1.28 christos if (newl) { 304 1.33 kre #ifndef SMALL 305 1.33 kre int j; 306 1.33 kre #endif 307 1.33 kre 308 1.28 christos switch (ch) { 309 1.42 kre #ifndef SMALL 310 1.28 christos case '[': 311 1.33 kre frac = false; 312 1.33 kre scale = 0; 313 1.28 christos ADDC(ch); 314 1.28 christos continue; 315 1.42 kre #endif 316 1.28 christos case '<': 317 1.28 christos log = 1; 318 1.28 christos continue; 319 1.28 christos case '>': 320 1.29 christos log = 0; 321 1.28 christos continue; 322 1.42 kre #ifndef SMALL 323 1.28 christos case ']': 324 1.49 rin if (tstamp == 0) 325 1.49 rin goto prchar; 326 1.33 kre frac = false; 327 1.28 christos ADDC(ch); 328 1.28 christos ADDC('\0'); 329 1.28 christos tstamp = 0; 330 1.33 kre sec = fsec = 0; 331 1.33 kre switch (sscanf(tbuf, "[%jd.%ld]", &sec, &fsec)){ 332 1.33 kre case 0: 333 1.49 rin not_tstamp: /* not a timestamp */ 334 1.47 rin PRTBUF(); 335 1.33 kre continue; 336 1.33 kre case 1: 337 1.47 rin fsec = 0; /* XXX PRTBUF()? */ 338 1.33 kre break; 339 1.33 kre case 2: 340 1.33 kre break; 341 1.47 rin case EOF: 342 1.33 kre default: 343 1.33 kre /* Help */ 344 1.33 kre continue; 345 1.33 kre } 346 1.51 rin postts = true; 347 1.33 kre 348 1.33 kre for (nsec = fsec, j = 9 - scale; --j >= 0; ) 349 1.33 kre nsec *= 10; 350 1.31 christos if (!quiet || deltas) 351 1.31 christos printf("["); 352 1.34 christos if (humantime == 1) { 353 1.28 christos time_t t; 354 1.28 christos struct tm tm; 355 1.33 kre 356 1.28 christos t = boottime.tv_sec + sec; 357 1.41 kre if (nsec + boottime.tv_nsec >= 358 1.41 kre ( 1L /* 1 second */ 359 1.41 kre * 1000L /* ms */ 360 1.41 kre * 1000L /* us */ 361 1.41 kre * 1000L /* ns */ )) 362 1.41 kre t++; 363 1.41 kre 364 1.28 christos if (localtime_r(&t, &tm) != NULL) { 365 1.49 rin strftime(tbuf, sizeof(tbuf), 366 1.31 christos "%a %b %e %H:%M:%S %Z %Y", 367 1.40 kre &tm); 368 1.31 christos printf("%s", tbuf); 369 1.28 christos } 370 1.34 christos } else if (humantime > 1) { 371 1.34 christos const char *fp = fmtydhmsf(tbuf, 372 1.49 rin sizeof(tbuf), sec, fsec, humantime); 373 1.34 christos if (fp) { 374 1.34 christos printf("%s", fp); 375 1.34 christos } 376 1.31 christos } else if (!quiet) { 377 1.39 kre printf(" %5jd%s", sec, radix); 378 1.34 christos pnsec(nsec, fsec, scale); 379 1.31 christos } 380 1.31 christos if (deltas) { 381 1.31 christos struct timespec nt = { sec, nsec }; 382 1.31 christos struct timespec dt; 383 1.33 kre 384 1.31 christos timespecsub(&nt, &lasttime, &dt); 385 1.31 christos if (humantime || !quiet) 386 1.31 christos printf(" "); 387 1.39 kre printf("<% 4jd%s%6.6ld>", 388 1.39 kre (intmax_t)dt.tv_sec, radix, 389 1.39 kre (dt.tv_nsec+499) / 1000); 390 1.31 christos lasttime = nt; 391 1.31 christos } 392 1.31 christos if (!quiet || deltas) 393 1.31 christos printf("] "); 394 1.42 kre continue; 395 1.28 christos #endif 396 1.28 christos case ' ': 397 1.45 kre #ifndef SMALL 398 1.44 tsutsui if (!tstamp && postts) { 399 1.44 tsutsui postts = false; 400 1.40 kre continue; 401 1.44 tsutsui } 402 1.50 rin #endif 403 1.28 christos /*FALLTHROUGH*/ 404 1.28 christos default: 405 1.42 kre #ifndef SMALL 406 1.28 christos if (tstamp) { 407 1.46 rin ADDC(ch); 408 1.46 rin if (ch == '.') 409 1.46 rin frac = true; 410 1.46 rin continue; 411 1.28 christos } 412 1.49 rin prchar: 413 1.42 kre #endif 414 1.28 christos if (log) 415 1.28 christos continue; 416 1.28 christos break; 417 1.28 christos } 418 1.1 cgd } 419 1.6 cgd newl = ch == '\n'; 420 1.21 augustss (void)vis(buf, ch, VIS_NOSLASH, 0); 421 1.24 dsl #ifndef SMALL 422 1.6 cgd if (buf[1] == 0) 423 1.6 cgd (void)putchar(buf[0]); 424 1.6 cgd else 425 1.24 dsl #endif 426 1.6 cgd (void)printf("%s", buf); 427 1.12 leo } 428 1.47 rin #ifndef SMALL 429 1.47 rin /* non-terminated [.*] */ 430 1.47 rin if (tstamp) { 431 1.47 rin ADDC('\0'); 432 1.47 rin PRTBUF(); 433 1.47 rin } 434 1.47 rin #endif 435 1.1 cgd if (!newl) 436 1.1 cgd (void)putchar('\n'); 437 1.28 christos return EXIT_SUCCESS; 438 1.1 cgd } 439 1.1 cgd 440 1.24 dsl #ifndef SMALL 441 1.27 joerg static void 442 1.18 simonb usage(void) 443 1.1 cgd { 444 1.15 enami 445 1.32 wiz (void)fprintf(stderr, "Usage: %s [-dTt] [-M core] [-N system]\n", 446 1.28 christos getprogname()); 447 1.28 christos exit(EXIT_FAILURE); 448 1.1 cgd } 449 1.24 dsl #endif 450