#include <sys/types.h>
#include <sys/msgbuf.h>
#include <sys/sysctl.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vis.h>
#include <sys/syslog.h>
static struct nlist nl[] = {
#define X_MSGBUF 0
{ "_msgbufp", 0, 0, 0, 0 },
{ NULL, 0, 0, 0, 0 },
};
static void dumpbuf(char *bp, size_t bufpos, size_t buflen,
int *newl, int *skip, int *pri);
static void usage(void) __dead2;
#define KREAD(addr, var) \
kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
#define INCRBUFSIZE 65536
static int all_opt;
int
main(int argc, char **argv)
{
int newl, skip;
struct msgbuf *bufp, cur;
char *bp, *memf, *nlistf;
kvm_t *kd;
int ch;
int clear = 0;
int pri = 0;
int tailmode = 0;
int kno;
size_t buflen, bufpos;
struct stat st;
setlocale(LC_CTYPE, "");
memf = nlistf = NULL;
while ((ch = getopt(argc, argv, "acfM:N:n:")) != -1) {
switch(ch) {
case 'a':
all_opt++;
break;
case 'c':
clear = 1;
break;
case 'f':
++tailmode;
break;
case 'M':
memf = optarg;
break;
case 'N':
nlistf = optarg;
break;
case 'n':
kno = strtol(optarg, NULL, 0);
asprintf(&memf, "vmcore.%d", kno);
asprintf(&nlistf, "kern.%d", kno);
if (stat(memf, &st) || stat(nlistf, &st)) {
free(memf);
free(nlistf);
asprintf(&memf, "/var/crash/vmcore.%d", kno);
asprintf(&nlistf, "/var/crash/kern.%d", kno);
}
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
newl = 1;
skip = 0;
pri = 0;
if (memf == NULL && nlistf == NULL && tailmode == 0) {
buflen = 0;
if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)
err(1, "sysctl kern.msgbuf");
if (buflen == 0)
buflen = 1;
if ((bp = malloc(buflen)) == NULL)
errx(1, "malloc failed");
if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
err(1, "sysctl kern.msgbuf");
bufpos = 0;
dumpbuf(bp, bufpos, buflen, &newl, &skip, &pri);
} else {
u_int rindex;
u_int xindex;
u_int ri;
u_int xi;
u_int n;
kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
if (kd == NULL)
exit (1);
if (kvm_nlist(kd, nl) == -1)
errx(1, "kvm_nlist: %s", kvm_geterr(kd));
if (nl[X_MSGBUF].n_type == 0)
errx(1, "%s: msgbufp not found",
nlistf ? nlistf : "namelist");
bp = malloc(INCRBUFSIZE);
if (!bp)
errx(1, "malloc failed");
if (KREAD(nl[X_MSGBUF].n_value, bufp))
errx(1, "kvm_read: %s", kvm_geterr(kd));
if (KREAD((long)bufp, cur))
errx(1, "kvm_read: %s", kvm_geterr(kd));
if (cur.msg_magic != MSG_MAGIC && cur.msg_magic != MSG_OMAGIC)
errx(1, "kernel message buffer has different magic "
"number");
rindex = cur.msg_bufr;
for (;;) {
xindex = cur.msg_bufx;
n = xindex - rindex;
if (n > cur.msg_size - 1024) {
rindex = xindex - cur.msg_size + 2048;
n = xindex - rindex;
}
ri = rindex % cur.msg_size;
xi = xindex % cur.msg_size;
if (ri < xi)
buflen = xi - ri;
else
buflen = cur.msg_size - ri;
if (buflen > n)
buflen = n;
if (buflen > INCRBUFSIZE)
buflen = INCRBUFSIZE;
if (kvm_read(kd, (long)cur.msg_ptr + ri,
bp, buflen) != (ssize_t)buflen) {
errx(1, "kvm_read: %s", kvm_geterr(kd));
}
if (buflen)
dumpbuf(bp, 0, buflen, &newl, &skip, &pri);
ri = (ri + buflen) % cur.msg_size;
n = n - buflen;
rindex += buflen;
if ((int)n <= 0) {
if (tailmode == 0)
break;
fflush(stdout);
if (tailmode == 1)
sleep(1);
}
if (KREAD((long)bufp, cur))
errx(1, "kvm_read: %s", kvm_geterr(kd));
}
kvm_close(kd);
}
if (!newl)
putchar('\n');
if (clear) {
if (sysctlbyname("kern.msgbuf_clear", NULL, NULL,
&clear, sizeof(int)) != 0) {
err(1, "sysctl kern.msgbuf_clear");
}
}
return(0);
}
static
void
dumpbuf(char *bp, size_t bufpos, size_t buflen,
int *newl, int *skip, int *pri)
{
int ch;
char *p, *ep;
char buf[5];
p = bp + bufpos;
ep = (bufpos == 0 ? bp + buflen : p);
do {
if (p == bp + buflen)
p = bp;
ch = *p;
if (*skip) {
if (ch == '\n') {
*skip = 0;
*newl = 1;
} if (ch == '>') {
if (LOG_FAC(*pri) == LOG_KERN)
*newl = *skip = 0;
} else if (ch >= '0' && ch <= '9') {
*pri *= 10;
*pri += ch - '0';
}
continue;
}
if (*newl && ch == '<' && all_opt == 0) {
*pri = 0;
*skip = 1;
continue;
}
if (ch == '\0')
continue;
*newl = (ch == '\n');
vis(buf, ch, VIS_NOSLASH, 0);
if (buf[1] == 0)
putchar(buf[0]);
else
printf("%s", buf);
} while (++p != ep);
}
static void
usage(void)
{
fprintf(stderr, "usage: dmesg [-ac] [-M core] [-N system]\n");
exit(1);
}