/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1991, 19934* The Regents of the University of California. All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the University nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*/3031#include <sys/types.h>32#include <sys/msgbuf.h>33#include <sys/sysctl.h>3435#include <ctype.h>36#include <err.h>37#include <errno.h>38#include <fcntl.h>39#include <kvm.h>40#include <limits.h>41#include <locale.h>42#include <nlist.h>43#include <stdio.h>44#include <stdbool.h>45#include <stdlib.h>46#include <string.h>47#include <unistd.h>48#include <vis.h>49#include <sys/syslog.h>5051static struct nlist nl[] = {52#define X_MSGBUF 053{ "_msgbufp", 0, 0, 0, 0 },54{ NULL, 0, 0, 0, 0 },55};5657void usage(void) __dead2;5859#define KREAD(addr, var) \60kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)6162int63main(int argc, char *argv[])64{65struct msgbuf *bufp, cur;66char *bp, *ep, *memf, *nextp, *nlistf, *p, *q, *visbp;67kvm_t *kd;68size_t buflen, bufpos;69long pri;70int ch, clear;71bool all;7273all = false;74clear = false;75(void) setlocale(LC_CTYPE, "");76memf = nlistf = NULL;77while ((ch = getopt(argc, argv, "acM:N:")) != -1)78switch(ch) {79case 'a':80all = true;81break;82case 'c':83clear = true;84break;85case 'M':86memf = optarg;87break;88case 'N':89nlistf = optarg;90break;91case '?':92default:93usage();94}95argc -= optind;96if (argc != 0)97usage();9899if (memf == NULL) {100/*101* Running kernel. Use sysctl. This gives an unwrapped buffer102* as a side effect. Remove nulterm (if present) so the value103* returned by sysctl is formatted as the rest of the code104* expects (the same as the value read from a core file below).105*/106if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)107err(1, "sysctl kern.msgbuf");108/* Allocate extra room for growth between the sysctl calls. */109buflen += buflen/8;110/* Allocate more than sysctl sees, for room to append \n\0. */111if ((bp = malloc(buflen + 2)) == NULL)112errx(1, "malloc failed");113if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)114err(1, "sysctl kern.msgbuf");115if (buflen > 0 && bp[buflen - 1] == '\0')116buflen--;117if (clear)118if (sysctlbyname("kern.msgbuf_clear", NULL, NULL, &clear, sizeof(int)))119err(1, "sysctl kern.msgbuf_clear");120} else {121/* Read in kernel message buffer and do sanity checks. */122kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");123if (kd == NULL)124exit (1);125if (kvm_nlist(kd, nl) == -1)126errx(1, "kvm_nlist: %s", kvm_geterr(kd));127if (nl[X_MSGBUF].n_type == 0)128errx(1, "%s: msgbufp not found",129nlistf ? nlistf : "namelist");130if (KREAD(nl[X_MSGBUF].n_value, bufp) || KREAD((long)bufp, cur))131errx(1, "kvm_read: %s", kvm_geterr(kd));132if (cur.msg_magic != MSG_MAGIC)133errx(1, "kernel message buffer has different magic "134"number");135if ((bp = malloc(cur.msg_size + 2)) == NULL)136errx(1, "malloc failed");137138/* Unwrap the circular buffer to start from the oldest data. */139bufpos = MSGBUF_SEQ_TO_POS(&cur, cur.msg_wseq);140if (kvm_read(kd, (long)&cur.msg_ptr[bufpos], bp,141cur.msg_size - bufpos) != (ssize_t)(cur.msg_size - bufpos))142errx(1, "kvm_read: %s", kvm_geterr(kd));143if (bufpos != 0 && kvm_read(kd, (long)cur.msg_ptr,144&bp[cur.msg_size - bufpos], bufpos) != (ssize_t)bufpos)145errx(1, "kvm_read: %s", kvm_geterr(kd));146kvm_close(kd);147buflen = cur.msg_size;148}149150/*151* Ensure that the buffer ends with a newline and a \0 to avoid152* complications below. We left space above.153*/154if (buflen == 0 || bp[buflen - 1] != '\n')155bp[buflen++] = '\n';156bp[buflen] = '\0';157158if ((visbp = malloc(4 * buflen + 1)) == NULL)159errx(1, "malloc failed");160161/*162* The message buffer is circular, but has been unwrapped so that163* the oldest data comes first. The data will be preceded by \0's164* if the message buffer was not full.165*/166p = bp;167ep = &bp[buflen];168if (*p == '\0') {169/* Strip leading \0's */170while (*p == '\0')171p++;172}173for (; p < ep; p = nextp) {174nextp = memchr(p, '\n', ep - p);175nextp++;176177/* Skip ^<[0-9]+> syslog sequences. */178if (*p == '<' && isdigit(*(p+1))) {179errno = 0;180pri = strtol(p + 1, &q, 10);181if (*q == '>' && pri >= 0 && pri < INT_MAX &&182errno == 0) {183if (LOG_FAC(pri) != LOG_KERN && !all)184continue;185p = q + 1;186}187}188189(void)strvisx(visbp, p, nextp - p, 0);190(void)printf("%s", visbp);191}192exit(0);193}194195void196usage(void)197{198fprintf(stderr, "usage: dmesg [-ac] [-M core [-N system]]\n");199exit(1);200}201202203