subr_log.c revision 1.54 1 /* $NetBSD: subr_log.c,v 1.54 2015/05/20 11:17:24 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)subr_log.c 8.3 (Berkeley) 2/14/95
61 */
62
63 /*
64 * Error log buffer for kernel printf's.
65 */
66
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: subr_log.c,v 1.54 2015/05/20 11:17:24 pooka Exp $");
69
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/kernel.h>
73 #include <sys/proc.h>
74 #include <sys/vnode.h>
75 #include <sys/ioctl.h>
76 #include <sys/msgbuf.h>
77 #include <sys/file.h>
78 #include <sys/syslog.h>
79 #include <sys/conf.h>
80 #include <sys/select.h>
81 #include <sys/poll.h>
82 #include <sys/intr.h>
83 #include <sys/sysctl.h>
84 #include <sys/ktrace.h>
85
86 static int sysctl_msgbuf(SYSCTLFN_PROTO);
87
88 static void logsoftintr(void *);
89
90 static bool log_async;
91 static struct selinfo log_selp; /* process waiting on select call */
92 static pid_t log_pgid; /* process/group for async I/O */
93 static kcondvar_t log_cv;
94 static void *log_sih;
95
96 kmutex_t log_lock;
97 int log_open; /* also used in log() */
98 int msgbufmapped; /* is the message buffer mapped */
99 int msgbufenabled; /* is logging to the buffer enabled */
100 struct kern_msgbuf *msgbufp; /* the mapped buffer, itself. */
101
102 void
103 initmsgbuf(void *bf, size_t bufsize)
104 {
105 struct kern_msgbuf *mbp;
106 long new_bufs;
107
108 /* Sanity-check the given size. */
109 if (bufsize < sizeof(struct kern_msgbuf))
110 return;
111
112 mbp = msgbufp = (struct kern_msgbuf *)bf;
113
114 new_bufs = bufsize - offsetof(struct kern_msgbuf, msg_bufc);
115 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) ||
116 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) ||
117 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) {
118 /*
119 * If the buffer magic number is wrong, has changed
120 * size (which shouldn't happen often), or is
121 * internally inconsistent, initialize it.
122 */
123
124 memset(bf, 0, bufsize);
125 mbp->msg_magic = MSG_MAGIC;
126 mbp->msg_bufs = new_bufs;
127 }
128
129 /* mark it as ready for use. */
130 msgbufmapped = msgbufenabled = 1;
131 }
132
133 void
134 loginit(void)
135 {
136 struct sysctllog *log = NULL;
137
138 mutex_init(&log_lock, MUTEX_DEFAULT, IPL_VM);
139 selinit(&log_selp);
140 cv_init(&log_cv, "klog");
141 log_sih = softint_establish(SOFTINT_CLOCK | SOFTINT_MPSAFE,
142 logsoftintr, NULL);
143
144 sysctl_createv(&log, 0, NULL, NULL,
145 CTLFLAG_PERMANENT,
146 CTLTYPE_INT, "msgbufsize",
147 SYSCTL_DESCR("Size of the kernel message buffer"),
148 sysctl_msgbuf, 0, NULL, 0,
149 CTL_KERN, KERN_MSGBUFSIZE, CTL_EOL);
150 sysctl_createv(&log, 0, NULL, NULL,
151 CTLFLAG_PERMANENT,
152 CTLTYPE_INT, "msgbuf",
153 SYSCTL_DESCR("Kernel message buffer"),
154 sysctl_msgbuf, 0, NULL, 0,
155 CTL_KERN, KERN_MSGBUF, CTL_EOL);
156 }
157
158 /*ARGSUSED*/
159 static int
160 logopen(dev_t dev, int flags, int mode, struct lwp *l)
161 {
162 struct kern_msgbuf *mbp = msgbufp;
163 int error = 0;
164
165 mutex_spin_enter(&log_lock);
166 if (log_open) {
167 error = EBUSY;
168 } else {
169 log_open = 1;
170 log_pgid = l->l_proc->p_pid; /* signal process only */
171 /*
172 * The message buffer is initialized during system
173 * configuration. If it's been clobbered, note that
174 * and return an error. (This allows a user to read
175 * the buffer via /dev/kmem, and try to figure out
176 * what clobbered it.
177 */
178 if (mbp->msg_magic != MSG_MAGIC) {
179 msgbufenabled = 0;
180 error = ENXIO;
181 }
182 }
183 mutex_spin_exit(&log_lock);
184
185 return error;
186 }
187
188 /*ARGSUSED*/
189 static int
190 logclose(dev_t dev, int flag, int mode, struct lwp *l)
191 {
192
193 mutex_spin_enter(&log_lock);
194 log_pgid = 0;
195 log_open = 0;
196 log_async = 0;
197 mutex_spin_exit(&log_lock);
198
199 return 0;
200 }
201
202 /*ARGSUSED*/
203 static int
204 logread(dev_t dev, struct uio *uio, int flag)
205 {
206 struct kern_msgbuf *mbp = msgbufp;
207 long l;
208 int error = 0;
209
210 mutex_spin_enter(&log_lock);
211 while (mbp->msg_bufr == mbp->msg_bufx) {
212 if (flag & IO_NDELAY) {
213 mutex_spin_exit(&log_lock);
214 return EWOULDBLOCK;
215 }
216 error = cv_wait_sig(&log_cv, &log_lock);
217 if (error) {
218 mutex_spin_exit(&log_lock);
219 return error;
220 }
221 }
222 while (uio->uio_resid > 0) {
223 l = mbp->msg_bufx - mbp->msg_bufr;
224 if (l < 0)
225 l = mbp->msg_bufs - mbp->msg_bufr;
226 l = min(l, uio->uio_resid);
227 if (l == 0)
228 break;
229 mutex_spin_exit(&log_lock);
230 error = uiomove(&mbp->msg_bufc[mbp->msg_bufr], (int)l, uio);
231 mutex_spin_enter(&log_lock);
232 if (error)
233 break;
234 mbp->msg_bufr += l;
235 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs)
236 mbp->msg_bufr = 0;
237 }
238 mutex_spin_exit(&log_lock);
239
240 return error;
241 }
242
243 /*ARGSUSED*/
244 static int
245 logpoll(dev_t dev, int events, struct lwp *l)
246 {
247 int revents = 0;
248
249 if (events & (POLLIN | POLLRDNORM)) {
250 mutex_spin_enter(&log_lock);
251 if (msgbufp->msg_bufr != msgbufp->msg_bufx)
252 revents |= events & (POLLIN | POLLRDNORM);
253 else
254 selrecord(l, &log_selp);
255 mutex_spin_exit(&log_lock);
256 }
257
258 return revents;
259 }
260
261 static void
262 filt_logrdetach(struct knote *kn)
263 {
264
265 mutex_spin_enter(&log_lock);
266 SLIST_REMOVE(&log_selp.sel_klist, kn, knote, kn_selnext);
267 mutex_spin_exit(&log_lock);
268 }
269
270 static int
271 filt_logread(struct knote *kn, long hint)
272 {
273 int rv;
274
275 if ((hint & NOTE_SUBMIT) == 0)
276 mutex_spin_enter(&log_lock);
277 if (msgbufp->msg_bufr == msgbufp->msg_bufx) {
278 rv = 0;
279 } else if (msgbufp->msg_bufr < msgbufp->msg_bufx) {
280 kn->kn_data = msgbufp->msg_bufx - msgbufp->msg_bufr;
281 rv = 1;
282 } else {
283 kn->kn_data = (msgbufp->msg_bufs - msgbufp->msg_bufr) +
284 msgbufp->msg_bufx;
285 rv = 1;
286 }
287 if ((hint & NOTE_SUBMIT) == 0)
288 mutex_spin_exit(&log_lock);
289
290 return rv;
291 }
292
293 static const struct filterops logread_filtops =
294 { 1, NULL, filt_logrdetach, filt_logread };
295
296 static int
297 logkqfilter(dev_t dev, struct knote *kn)
298 {
299 struct klist *klist;
300
301 switch (kn->kn_filter) {
302 case EVFILT_READ:
303 klist = &log_selp.sel_klist;
304 kn->kn_fop = &logread_filtops;
305 break;
306
307 default:
308 return (EINVAL);
309 }
310
311 mutex_spin_enter(&log_lock);
312 kn->kn_hook = NULL;
313 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
314 mutex_spin_exit(&log_lock);
315
316 return (0);
317 }
318
319 void
320 logwakeup(void)
321 {
322
323 if (!cold && log_open) {
324 mutex_spin_enter(&log_lock);
325 selnotify(&log_selp, 0, NOTE_SUBMIT);
326 if (log_async)
327 softint_schedule(log_sih);
328 cv_broadcast(&log_cv);
329 mutex_spin_exit(&log_lock);
330 }
331 }
332
333 static void
334 logsoftintr(void *cookie)
335 {
336 pid_t pid;
337
338 if ((pid = log_pgid) != 0)
339 fownsignal(pid, SIGIO, 0, 0, NULL);
340 }
341
342 /*ARGSUSED*/
343 static int
344 logioctl(dev_t dev, u_long com, void *data, int flag, struct lwp *lwp)
345 {
346 long l;
347
348 switch (com) {
349
350 /* return number of characters immediately available */
351 case FIONREAD:
352 mutex_spin_enter(&log_lock);
353 l = msgbufp->msg_bufx - msgbufp->msg_bufr;
354 if (l < 0)
355 l += msgbufp->msg_bufs;
356 mutex_spin_exit(&log_lock);
357 *(int *)data = l;
358 break;
359
360 case FIONBIO:
361 break;
362
363 case FIOASYNC:
364 /* No locking needed, 'thread private'. */
365 log_async = (*((int *)data) != 0);
366 break;
367
368 case TIOCSPGRP:
369 case FIOSETOWN:
370 return fsetown(&log_pgid, com, data);
371
372 case TIOCGPGRP:
373 case FIOGETOWN:
374 return fgetown(log_pgid, com, data);
375
376 default:
377 return (EPASSTHROUGH);
378 }
379 return (0);
380 }
381
382 void
383 logputchar(int c)
384 {
385 struct kern_msgbuf *mbp;
386
387 if (!cold)
388 mutex_spin_enter(&log_lock);
389 if (msgbufenabled) {
390 mbp = msgbufp;
391 if (mbp->msg_magic != MSG_MAGIC) {
392 /*
393 * Arguably should panic or somehow notify the
394 * user... but how? Panic may be too drastic,
395 * and would obliterate the message being kicked
396 * out (maybe a panic itself), and printf
397 * would invoke us recursively. Silently punt
398 * for now. If syslog is running, it should
399 * notice.
400 */
401 msgbufenabled = 0;
402 } else {
403 mbp->msg_bufc[mbp->msg_bufx++] = c;
404 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs)
405 mbp->msg_bufx = 0;
406 /* If the buffer is full, keep the most recent data. */
407 if (mbp->msg_bufr == mbp->msg_bufx) {
408 char c0;
409 int i;
410
411 /*
412 * Move forward read pointer to the next line
413 * in the buffer. Note that the buffer is
414 * a ring buffer so we should reset msg_bufr
415 * to 0 when msg_bufr exceeds msg_bufs.
416 *
417 * To prevent to loop forever, give up if we
418 * cannot find a newline in mbp->msg_bufs
419 * characters (the max size of the buffer).
420 */
421 for (i = 0; i < mbp->msg_bufs; i++) {
422 c0 = mbp->msg_bufc[mbp->msg_bufr];
423 if (++mbp->msg_bufr >= mbp->msg_bufs)
424 mbp->msg_bufr = 0;
425 if (c0 == '\n')
426 break;
427 }
428 }
429 }
430 }
431 if (!cold)
432 mutex_spin_exit(&log_lock);
433 }
434
435 /*
436 * sysctl helper routine for kern.msgbufsize and kern.msgbuf. For the
437 * former it merely checks the message buffer is set up. For the latter,
438 * it also copies out the data if necessary.
439 */
440 static int
441 sysctl_msgbuf(SYSCTLFN_ARGS)
442 {
443 char *where = oldp;
444 size_t len, maxlen;
445 long beg, end;
446 extern kmutex_t log_lock;
447 int error;
448
449 if (!msgbufenabled || msgbufp->msg_magic != MSG_MAGIC) {
450 msgbufenabled = 0;
451 return (ENXIO);
452 }
453
454 switch (rnode->sysctl_num) {
455 case KERN_MSGBUFSIZE: {
456 struct sysctlnode node = *rnode;
457 int msg_bufs = (int)msgbufp->msg_bufs;
458 node.sysctl_data = &msg_bufs;
459 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
460 }
461 case KERN_MSGBUF:
462 break;
463 default:
464 return (EOPNOTSUPP);
465 }
466
467 if (newp != NULL)
468 return (EPERM);
469
470 if (oldp == NULL) {
471 /* always return full buffer size */
472 *oldlenp = msgbufp->msg_bufs;
473 return (0);
474 }
475
476 sysctl_unlock();
477
478 /*
479 * First, copy from the write pointer to the end of
480 * message buffer.
481 */
482 error = 0;
483 mutex_spin_enter(&log_lock);
484 maxlen = MIN(msgbufp->msg_bufs, *oldlenp);
485 beg = msgbufp->msg_bufx;
486 end = msgbufp->msg_bufs;
487 mutex_spin_exit(&log_lock);
488
489 while (maxlen > 0) {
490 len = MIN(end - beg, maxlen);
491 if (len == 0)
492 break;
493 /* XXX unlocked, but hardly matters. */
494 error = copyout(&msgbufp->msg_bufc[beg], where, len);
495 ktrmibio(-1, UIO_READ, where, len, error);
496 if (error)
497 break;
498 where += len;
499 maxlen -= len;
500
501 /*
502 * ... then, copy from the beginning of message buffer to
503 * the write pointer.
504 */
505 beg = 0;
506 end = msgbufp->msg_bufx;
507 }
508
509 sysctl_relock();
510 return (error);
511 }
512
513 const struct cdevsw log_cdevsw = {
514 .d_open = logopen,
515 .d_close = logclose,
516 .d_read = logread,
517 .d_write = nowrite,
518 .d_ioctl = logioctl,
519 .d_stop = nostop,
520 .d_tty = notty,
521 .d_poll = logpoll,
522 .d_mmap = nommap,
523 .d_kqfilter = logkqfilter,
524 .d_discard = nodiscard,
525 .d_flag = D_OTHER | D_MPSAFE
526 };
527