xref: /dragonfly/sbin/dmesg/dmesg.c (revision 1ab323cec1af8e799b2932698e89b97bfdc02f78)
1 /*-
2  * Copyright (c) 1991, 1993
3  *        The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#) Copyright (c) 1991, 1993 The Regents of the University of California.  All rights reserved.
30  * @(#)dmesg.c      8.1 (Berkeley) 6/5/93
31  * $FreeBSD: src/sbin/dmesg/dmesg.c,v 1.11.2.3 2001/08/08 22:32:15 obrien Exp $
32  */
33 
34 #include <sys/types.h>
35 #include <sys/msgbuf.h>
36 #include <sys/sysctl.h>
37 #include <sys/stat.h>
38 
39 #include <err.h>
40 #include <fcntl.h>
41 #include <kvm.h>
42 #include <locale.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <vis.h>
47 #include <sys/syslog.h>
48 
49 static struct nlist nl[] = {
50 #define   X_MSGBUF  0
51           { "_msgbufp",       0, 0, 0, 0 },
52           { NULL,             0, 0, 0, 0 },
53 };
54 
55 static void dumpbuf(char *bp, size_t bufpos, size_t buflen,
56                         int *newl, int *skip, int *pri);
57 static void usage(void) __dead2;
58 
59 #define   KREAD(addr, var) \
60           kvm_read(kd, addr, &var, sizeof(var)) != sizeof(var)
61 
62 #define INCRBUFSIZE 65536
63 
64 static int all_opt;
65 
66 int
main(int argc,char ** argv)67 main(int argc, char **argv)
68 {
69           int newl, skip;
70           struct msgbuf *bufp, cur;
71           char *bp, *memf, *nlistf;
72           kvm_t *kd;
73           int ch;
74           int clear = 0;
75           int pri = 0;
76           int tailmode = 0;
77           int kno;
78           size_t buflen, bufpos;
79           struct stat st;
80 
81           setlocale(LC_CTYPE, "");
82           memf = nlistf = NULL;
83           while ((ch = getopt(argc, argv, "acfM:N:n:")) != -1) {
84                     switch(ch) {
85                     case 'a':
86                               all_opt++;
87                               break;
88                     case 'c':
89                               clear = 1;
90                               break;
91                     case 'f':
92                               ++tailmode;
93                               break;
94                     case 'M':
95                               memf = optarg;
96                               break;
97                     case 'N':
98                               nlistf = optarg;
99                               break;
100                     case 'n':
101                               kno = strtol(optarg, NULL, 0);
102                               asprintf(&memf, "vmcore.%d", kno);
103                               asprintf(&nlistf, "kern.%d", kno);
104                               if (stat(memf, &st) || stat(nlistf, &st)) {
105                                         free(memf);
106                                         free(nlistf);
107                                         asprintf(&memf, "/var/crash/vmcore.%d", kno);
108                                         asprintf(&nlistf, "/var/crash/kern.%d", kno);
109                               }
110                               break;
111                     case '?':
112                     default:
113                               usage();
114                     }
115           }
116           argc -= optind;
117           argv += optind;
118 
119           newl = 1;
120           skip = 0;
121           pri = 0;
122 
123           if (memf == NULL && nlistf == NULL && tailmode == 0) {
124                     /* Running kernel. Use sysctl. */
125                     buflen = 0;
126                     if (sysctlbyname("kern.msgbuf", NULL, &buflen, NULL, 0) == -1)
127                               err(1, "sysctl kern.msgbuf");
128                     if (buflen == 0)    /* can happen if msgbuf was cleared */
129                               buflen = 1;
130 
131                     if ((bp = malloc(buflen)) == NULL)
132                               errx(1, "malloc failed");
133                     if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
134                               err(1, "sysctl kern.msgbuf");
135                     /* We get a dewrapped buffer using sysctl. */
136                     bufpos = 0;
137                     dumpbuf(bp, bufpos, buflen, &newl, &skip, &pri);
138           } else {
139                     u_int rindex;
140                     u_int xindex;
141                     u_int ri;
142                     u_int xi;
143                     u_int n;
144 
145                     /* Read in kernel message buffer, do sanity checks. */
146                     kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
147                     if (kd == NULL)
148                               exit (1);
149                     if (kvm_nlist(kd, nl) == -1)
150                               errx(1, "kvm_nlist: %s", kvm_geterr(kd));
151                     if (nl[X_MSGBUF].n_type == 0)
152                               errx(1, "%s: msgbufp not found",
153                                   nlistf ? nlistf : "namelist");
154                     bp = malloc(INCRBUFSIZE);
155                     if (!bp)
156                               errx(1, "malloc failed");
157                     if (KREAD(nl[X_MSGBUF].n_value, bufp))
158                               errx(1, "kvm_read: %s", kvm_geterr(kd));
159                     if (KREAD((long)bufp, cur))
160                               errx(1, "kvm_read: %s", kvm_geterr(kd));
161                     if (cur.msg_magic != MSG_MAGIC && cur.msg_magic != MSG_OMAGIC)
162                               errx(1, "kernel message buffer has different magic "
163                                   "number");
164 
165                     /*
166                      * NOTE: current algorithm is compatible with both old and
167                      *         new msgbuf structures.  The new structure doesn't
168                      *         modulo the indexes (so we do), and adds a separate
169                      *         log index which we don't access here.
170                      */
171 
172                     rindex = cur.msg_bufr;
173 
174                     for (;;) {
175                               /*
176                                * Calculate index for dump and do sanity clipping.
177                                */
178                               xindex = cur.msg_bufx;
179                               n = xindex - rindex;
180                               if (n > cur.msg_size - 1024) {
181                                         rindex = xindex - cur.msg_size + 2048;
182                                         n = xindex - rindex;
183                               }
184                               ri = rindex % cur.msg_size;
185                               xi = xindex % cur.msg_size;
186 
187                               if (ri < xi)
188                                         buflen = xi - ri;
189                               else
190                                         buflen = cur.msg_size - ri;
191                               if (buflen > n)
192                                         buflen = n;
193                               if (buflen > INCRBUFSIZE)
194                                         buflen = INCRBUFSIZE;
195 
196                               if (kvm_read(kd, (long)cur.msg_ptr + ri,
197                                              bp, buflen) != (ssize_t)buflen) {
198                                         errx(1, "kvm_read: %s", kvm_geterr(kd));
199                               }
200                               if (buflen)
201                                         dumpbuf(bp, 0, buflen, &newl, &skip, &pri);
202                               ri = (ri + buflen) % cur.msg_size;
203                               n = n - buflen;
204                               rindex += buflen;
205                               if ((int)n <= 0) {
206                                         if (tailmode == 0)
207                                                   break;
208                                         fflush(stdout);
209                                         if (tailmode == 1)
210                                                   sleep(1);
211                               }
212                               if (KREAD((long)bufp, cur))
213                                         errx(1, "kvm_read: %s", kvm_geterr(kd));
214                     }
215                     kvm_close(kd);
216           }
217           if (!newl)
218                     putchar('\n');
219           if (clear) {
220                     if (sysctlbyname("kern.msgbuf_clear", NULL, NULL,
221                                          &clear, sizeof(int)) != 0) {
222                               err(1, "sysctl kern.msgbuf_clear");
223                     }
224           }
225           return(0);
226 }
227 
228 static
229 void
dumpbuf(char * bp,size_t bufpos,size_t buflen,int * newl,int * skip,int * pri)230 dumpbuf(char *bp, size_t bufpos, size_t buflen,
231           int *newl, int *skip, int *pri)
232 {
233           int ch;
234           char *p, *ep;
235           char buf[5];
236 
237           /*
238            * The message buffer is circular.  If the buffer has wrapped, the
239            * write pointer points to the oldest data.  Otherwise, the write
240            * pointer points to \0's following the data.  Read the entire
241            * buffer starting at the write pointer and ignore nulls so that
242            * we effectively start at the oldest data.
243            */
244           p = bp + bufpos;
245           ep = (bufpos == 0 ? bp + buflen : p);
246           do {
247                     if (p == bp + buflen)
248                               p = bp;
249                     ch = *p;
250                     /* Skip "\n<.*>" syslog sequences. */
251                     if (*skip) {
252                               if (ch == '\n') {
253                                         *skip = 0;
254                                         *newl = 1;
255                               } if (ch == '>') {
256                                         if (LOG_FAC(*pri) == LOG_KERN)
257                                                   *newl = *skip = 0;
258                               } else if (ch >= '0' && ch <= '9') {
259                                         *pri *= 10;
260                                         *pri += ch - '0';
261                               }
262                               continue;
263                     }
264                     if (*newl && ch == '<' && all_opt == 0) {
265                               *pri = 0;
266                               *skip = 1;
267                               continue;
268                     }
269                     if (ch == '\0')
270                               continue;
271                     *newl = (ch == '\n');
272                     vis(buf, ch, VIS_NOSLASH, 0);
273                     if (buf[1] == 0)
274                               putchar(buf[0]);
275                     else
276                               printf("%s", buf);
277           } while (++p != ep);
278 }
279 
280 static void
usage(void)281 usage(void)
282 {
283           fprintf(stderr, "usage: dmesg [-ac] [-M core] [-N system]\n");
284           exit(1);
285 }
286