Deleted Added
sdiff udiff text old ( 106855 ) new ( 106917 )
full compact
1/*-
2 * Copyright (c) 1986, 1988, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
39 * $FreeBSD: head/sys/kern/subr_prf.c 106855 2002-11-13 15:15:59Z mux $
40 */
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/sx.h>
47#include <sys/kernel.h>
48#include <sys/msgbuf.h>
49#include <sys/malloc.h>
50#include <sys/proc.h>
51#include <sys/stddef.h>
52#include <sys/stdint.h>
53#include <sys/sysctl.h>
54#include <sys/tty.h>
55#include <sys/syslog.h>
56#include <sys/cons.h>
57#include <sys/uio.h>
58
59/*
60 * Note that stdarg.h and the ANSI style va_start macro is used for both
61 * ANSI and traditional C compilers.
62 */
63#include <machine/stdarg.h>
64
65#define TOCONS 0x01
66#define TOTTY 0x02
67#define TOLOG 0x04
68
69/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
70#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
71
72struct putchar_arg {
73 int flags;
74 int pri;
75 struct tty *tty;
76};
77
78struct snprintf_arg {
79 char *str;
80 size_t remain;
81};
82
83extern int log_open;
84
85struct tty *constty; /* pointer to console "window" tty */
86
87static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
88static void msglogchar(int c, int pri);
89static void msgaddchar(int c, void *dummy);
90static void putchar(int ch, void *arg);
91static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
92static void snprintf_func(int ch, void *arg);
93
94static int consintr = 1; /* Ok to handle console interrupts? */
95static int msgbufmapped; /* Set when safe to use msgbuf */
96int msgbuftrigger;
97
98static int log_console_output = 1;
99TUNABLE_INT("kern.log_console_output", &log_console_output);
100SYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW,
101 &log_console_output, 0, "");
102
103/*
104 * Warn that a system table is full.
105 */
106void
107tablefull(const char *tab)
108{
109
110 log(LOG_ERR, "%s: table is full\n", tab);
111}
112
113/*
114 * Uprintf prints to the controlling terminal for the current process.
115 * It may block if the tty queue is overfull. No message is printed if
116 * the queue does not clear in a reasonable time.
117 */
118int
119uprintf(const char *fmt, ...)
120{
121 struct thread *td = curthread;
122 struct proc *p = td->td_proc;
123 va_list ap;
124 struct putchar_arg pca;
125 int retval;
126
127 if (td == NULL || td == PCPU_GET(idlethread))
128 return (0);
129
130 p = td->td_proc;
131 PROC_LOCK(p);
132 if ((p->p_flag & P_CONTROLT) == 0) {
133 PROC_UNLOCK(p);
134 return (0);
135 }
136 SESS_LOCK(p->p_session);
137 pca.tty = p->p_session->s_ttyp;
138 SESS_UNLOCK(p->p_session);
139 PROC_UNLOCK(p);
140 if (pca.tty == NULL)
141 return (0);
142 pca.flags = TOTTY;
143 va_start(ap, fmt);
144 retval = kvprintf(fmt, putchar, &pca, 10, ap);
145 va_end(ap);
146
147 return (retval);
148}
149
150/*
151 * tprintf prints on the controlling terminal associated
152 * with the given session, possibly to the log as well.
153 */
154void
155tprintf(struct proc *p, int pri, const char *fmt, ...)
156{
157 struct tty *tp = NULL;
158 int flags = 0, shld = 0;
159 va_list ap;
160 struct putchar_arg pca;
161 int retval;
162
163 if (pri != -1)
164 flags |= TOLOG;
165 if (p != NULL) {
166 PROC_LOCK(p);
167 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
168 SESS_LOCK(p->p_session);
169 SESSHOLD(p->p_session);
170 tp = p->p_session->s_ttyp;
171 SESS_UNLOCK(p->p_session);
172 PROC_UNLOCK(p);
173 shld++;
174 if (ttycheckoutq(tp, 0))
175 flags |= TOTTY;
176 else
177 tp = NULL;
178 } else
179 PROC_UNLOCK(p);
180 }
181 pca.pri = pri;
182 pca.tty = tp;
183 pca.flags = flags;
184 va_start(ap, fmt);
185 retval = kvprintf(fmt, putchar, &pca, 10, ap);
186 va_end(ap);
187 if (shld) {
188 PROC_LOCK(p);
189 SESS_LOCK(p->p_session);
190 SESSRELE(p->p_session);
191 SESS_UNLOCK(p->p_session);
192 PROC_UNLOCK(p);
193 }
194 msgbuftrigger = 1;
195}
196
197/*
198 * Ttyprintf displays a message on a tty; it should be used only by
199 * the tty driver, or anything that knows the underlying tty will not
200 * be revoke(2)'d away. Other callers should use tprintf.
201 */
202int
203ttyprintf(struct tty *tp, const char *fmt, ...)
204{
205 va_list ap;
206 struct putchar_arg pca;
207 int retval;
208
209 va_start(ap, fmt);
210 pca.tty = tp;
211 pca.flags = TOTTY;
212 retval = kvprintf(fmt, putchar, &pca, 10, ap);
213 va_end(ap);
214 return (retval);
215}
216
217/*
218 * Log writes to the log buffer, and guarantees not to sleep (so can be
219 * called by interrupt routines). If there is no process reading the
220 * log yet, it writes to the console also.
221 */
222void
223log(int level, const char *fmt, ...)
224{
225 va_list ap;
226 int retval;
227 struct putchar_arg pca;
228
229 pca.tty = NULL;
230 pca.pri = level;
231 pca.flags = log_open ? TOLOG : TOCONS;
232
233 va_start(ap, fmt);
234 retval = kvprintf(fmt, putchar, &pca, 10, ap);
235 va_end(ap);
236
237 msgbuftrigger = 1;
238}
239
240#define CONSCHUNK 128
241
242void
243log_console(struct uio *uio)
244{
245 int c, i, error, iovlen, nl;
246 struct uio muio;
247 struct iovec *miov = NULL;
248 char *consbuffer;
249 int pri;
250
251 if (!log_console_output)
252 return;
253
254 pri = LOG_INFO | LOG_CONSOLE;
255 muio = *uio;
256 iovlen = uio->uio_iovcnt * sizeof (struct iovec);
257 MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
258 MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
259 bcopy(muio.uio_iov, miov, iovlen);
260 muio.uio_iov = miov;
261 uio = &muio;
262
263 nl = 0;
264 while (uio->uio_resid > 0) {
265 c = imin(uio->uio_resid, CONSCHUNK);
266 error = uiomove(consbuffer, c, uio);
267 if (error != 0)
268 break;
269 for (i = 0; i < c; i++) {
270 msglogchar(consbuffer[i], pri);
271 if (consbuffer[i] == '\n')
272 nl = 1;
273 else
274 nl = 0;
275 }
276 }
277 if (!nl)
278 msglogchar('\n', pri);
279 msgbuftrigger = 1;
280 FREE(miov, M_TEMP);
281 FREE(consbuffer, M_TEMP);
282 return;
283}
284
285int
286printf(const char *fmt, ...)
287{
288 va_list ap;
289 int savintr;
290 struct putchar_arg pca;
291 int retval;
292
293 savintr = consintr; /* disable interrupts */
294 consintr = 0;
295 va_start(ap, fmt);
296 pca.tty = NULL;
297 pca.flags = TOCONS | TOLOG;
298 pca.pri = -1;
299 retval = kvprintf(fmt, putchar, &pca, 10, ap);
300 va_end(ap);
301 if (!panicstr)
302 msgbuftrigger = 1;
303 consintr = savintr; /* reenable interrupts */
304 return (retval);
305}
306
307int
308vprintf(const char *fmt, va_list ap)
309{
310 int savintr;
311 struct putchar_arg pca;
312 int retval;
313
314 savintr = consintr; /* disable interrupts */
315 consintr = 0;
316 pca.tty = NULL;
317 pca.flags = TOCONS | TOLOG;
318 pca.pri = -1;
319 retval = kvprintf(fmt, putchar, &pca, 10, ap);
320 if (!panicstr)
321 msgbuftrigger = 1;
322 consintr = savintr; /* reenable interrupts */
323 return (retval);
324}
325
326/*
327 * Print a character on console or users terminal. If destination is
328 * the console then the last bunch of characters are saved in msgbuf for
329 * inspection later.
330 */
331static void
332putchar(int c, void *arg)
333{
334 struct putchar_arg *ap = (struct putchar_arg*) arg;
335 int flags = ap->flags;
336 struct tty *tp = ap->tty;
337 if (panicstr)
338 constty = NULL;
339 if ((flags & TOCONS) && tp == NULL && constty) {
340 tp = constty;
341 flags |= TOTTY;
342 }
343 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
344 (flags & TOCONS) && tp == constty)
345 constty = NULL;
346 if ((flags & TOLOG))
347 msglogchar(c, ap->pri);
348 if ((flags & TOCONS) && constty == NULL && c != '\0')
349 (*v_putc)(c);
350}
351
352/*
353 * Scaled down version of sprintf(3).
354 */
355int
356sprintf(char *buf, const char *cfmt, ...)
357{
358 int retval;
359 va_list ap;
360
361 va_start(ap, cfmt);
362 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
363 buf[retval] = '\0';
364 va_end(ap);
365 return (retval);
366}
367
368/*
369 * Scaled down version of vsprintf(3).
370 */
371int
372vsprintf(char *buf, const char *cfmt, va_list ap)
373{
374 int retval;
375
376 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
377 buf[retval] = '\0';
378 return (retval);
379}
380
381/*
382 * Scaled down version of snprintf(3).
383 */
384int
385snprintf(char *str, size_t size, const char *format, ...)
386{
387 int retval;
388 va_list ap;
389
390 va_start(ap, format);
391 retval = vsnprintf(str, size, format, ap);
392 va_end(ap);
393 return(retval);
394}
395
396/*
397 * Scaled down version of vsnprintf(3).
398 */
399int
400vsnprintf(char *str, size_t size, const char *format, va_list ap)
401{
402 struct snprintf_arg info;
403 int retval;
404
405 info.str = str;
406 info.remain = size;
407 retval = kvprintf(format, snprintf_func, &info, 10, ap);
408 if (info.remain >= 1)
409 *info.str++ = '\0';
410 return (retval);
411}
412
413static void
414snprintf_func(int ch, void *arg)
415{
416 struct snprintf_arg *const info = arg;
417
418 if (info->remain >= 2) {
419 *info->str++ = ch;
420 info->remain--;
421 }
422}
423
424/*
425 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
426 * order; return an optional length and a pointer to the last character
427 * written in the buffer (i.e., the first character of the string).
428 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
429 */
430static char *
431ksprintn(char *nbuf, uintmax_t num, int base, int *lenp)
432{
433 char *p;
434
435 p = nbuf;
436 *p = '\0';
437 do {
438 *++p = hex2ascii(num % base);
439 } while (num /= base);
440 if (lenp)
441 *lenp = p - nbuf;
442 return (p);
443}
444
445/*
446 * Scaled down version of printf(3).
447 *
448 * Two additional formats:
449 *
450 * The format %b is supported to decode error registers.
451 * Its usage is:
452 *
453 * printf("reg=%b\n", regval, "<base><arg>*");
454 *
455 * where <base> is the output base expressed as a control character, e.g.
456 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
457 * the first of which gives the bit number to be inspected (origin 1), and
458 * the next characters (up to a control character, i.e. a character <= 32),
459 * give the name of the register. Thus:
460 *
461 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
462 *
463 * would produce output:
464 *
465 * reg=3<BITTWO,BITONE>
466 *
467 * XXX: %D -- Hexdump, takes pointer and separator string:
468 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
469 * ("%*D", len, ptr, " " -> XX XX XX XX ...
470 */
471int
472kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
473{
474#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
475 char nbuf[MAXNBUF];
476 char *d;
477 const char *p, *percent, *q;
478 u_char *up;
479 int ch, n;
480 uintmax_t num;
481 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
482 int jflag, tflag, zflag;
483 int dwidth;
484 char padc;
485 int retval = 0;
486
487 num = 0;
488 if (!func)
489 d = (char *) arg;
490 else
491 d = NULL;
492
493 if (fmt == NULL)
494 fmt = "(fmt null)\n";
495
496 if (radix < 2 || radix > 36)
497 radix = 10;
498
499 for (;;) {
500 padc = ' ';
501 width = 0;
502 while ((ch = (u_char)*fmt++) != '%') {
503 if (ch == '\0')
504 return (retval);
505 PCHAR(ch);
506 }
507 percent = fmt - 1;
508 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
509 sign = 0; dot = 0; dwidth = 0;
510 jflag = 0; tflag = 0; zflag = 0;
511reswitch: switch (ch = (u_char)*fmt++) {
512 case '.':
513 dot = 1;
514 goto reswitch;
515 case '#':
516 sharpflag = 1;
517 goto reswitch;
518 case '+':
519 sign = 1;
520 goto reswitch;
521 case '-':
522 ladjust = 1;
523 goto reswitch;
524 case '%':
525 PCHAR(ch);
526 break;
527 case '*':
528 if (!dot) {
529 width = va_arg(ap, int);
530 if (width < 0) {
531 ladjust = !ladjust;
532 width = -width;
533 }
534 } else {
535 dwidth = va_arg(ap, int);
536 }
537 goto reswitch;
538 case '0':
539 if (!dot) {
540 padc = '0';
541 goto reswitch;
542 }
543 case '1': case '2': case '3': case '4':
544 case '5': case '6': case '7': case '8': case '9':
545 for (n = 0;; ++fmt) {
546 n = n * 10 + ch - '0';
547 ch = *fmt;
548 if (ch < '0' || ch > '9')
549 break;
550 }
551 if (dot)
552 dwidth = n;
553 else
554 width = n;
555 goto reswitch;
556 case 'b':
557 num = va_arg(ap, int);
558 p = va_arg(ap, char *);
559 for (q = ksprintn(nbuf, num, *p++, NULL); *q;)
560 PCHAR(*q--);
561
562 if (num == 0)
563 break;
564
565 for (tmp = 0; *p;) {
566 n = *p++;
567 if (num & (1 << (n - 1))) {
568 PCHAR(tmp ? ',' : '<');
569 for (; (n = *p) > ' '; ++p)
570 PCHAR(n);
571 tmp = 1;
572 } else
573 for (; *p > ' '; ++p)
574 continue;
575 }
576 if (tmp)
577 PCHAR('>');
578 break;
579 case 'c':
580 PCHAR(va_arg(ap, int));
581 break;
582 case 'D':
583 up = va_arg(ap, u_char *);
584 p = va_arg(ap, char *);
585 if (!width)
586 width = 16;
587 while(width--) {
588 PCHAR(hex2ascii(*up >> 4));
589 PCHAR(hex2ascii(*up & 0x0f));
590 up++;
591 if (width)
592 for (q=p;*q;q++)
593 PCHAR(*q);
594 }
595 break;
596 case 'd':
597 case 'i':
598 base = 10;
599 sign = 1;
600 goto handle_sign;
601 case 'j':
602 jflag = 1;
603 goto reswitch;
604 case 'l':
605 if (lflag) {
606 lflag = 0;
607 qflag = 1;
608 } else
609 lflag = 1;
610 goto reswitch;
611 case 'n':
612 if (jflag)
613 *(va_arg(ap, intmax_t *)) = retval;
614 else if (qflag)
615 *(va_arg(ap, quad_t *)) = retval;
616 else if (lflag)
617 *(va_arg(ap, long *)) = retval;
618 else if (zflag)
619 *(va_arg(ap, size_t *)) = retval;
620 else
621 *(va_arg(ap, int *)) = retval;
622 break;
623 case 'o':
624 base = 8;
625 goto handle_nosign;
626 case 'p':
627 base = 16;
628 sharpflag = (width == 0);
629 sign = 0;
630 num = (uintptr_t)va_arg(ap, void *);
631 goto number;
632 case 'q':
633 qflag = 1;
634 goto reswitch;
635 case 'r':
636 base = radix;
637 if (sign)
638 goto handle_sign;
639 goto handle_nosign;
640 case 's':
641 p = va_arg(ap, char *);
642 if (p == NULL)
643 p = "(null)";
644 if (!dot)
645 n = strlen (p);
646 else
647 for (n = 0; n < dwidth && p[n]; n++)
648 continue;
649
650 width -= n;
651
652 if (!ladjust && width > 0)
653 while (width--)
654 PCHAR(padc);
655 while (n--)
656 PCHAR(*p++);
657 if (ladjust && width > 0)
658 while (width--)
659 PCHAR(padc);
660 break;
661 case 't':
662 tflag = 1;
663 goto reswitch;
664 break;
665 case 'u':
666 base = 10;
667 goto handle_nosign;
668 case 'x':
669 case 'X':
670 base = 16;
671 goto handle_nosign;
672 case 'y':
673 base = 16;
674 sign = 1;
675 goto handle_sign;
676 case 'z':
677 zflag = 1;
678 goto reswitch;
679handle_nosign:
680 sign = 0;
681 if (jflag)
682 num = va_arg(ap, uintmax_t);
683 else if (qflag)
684 num = va_arg(ap, u_quad_t);
685 else if (tflag)
686 num = va_arg(ap, ptrdiff_t);
687 else if (lflag)
688 num = va_arg(ap, u_long);
689 else if (zflag)
690 num = va_arg(ap, size_t);
691 else
692 num = va_arg(ap, u_int);
693 goto number;
694handle_sign:
695 if (jflag)
696 num = va_arg(ap, intmax_t);
697 else if (qflag)
698 num = va_arg(ap, quad_t);
699 else if (tflag)
700 num = va_arg(ap, ptrdiff_t);
701 else if (lflag)
702 num = va_arg(ap, long);
703 else if (zflag)
704 num = va_arg(ap, size_t);
705 else
706 num = va_arg(ap, int);
707number:
708 if (sign && (intmax_t)num < 0) {
709 neg = 1;
710 num = -(intmax_t)num;
711 }
712 p = ksprintn(nbuf, num, base, &tmp);
713 if (sharpflag && num != 0) {
714 if (base == 8)
715 tmp++;
716 else if (base == 16)
717 tmp += 2;
718 }
719 if (neg)
720 tmp++;
721
722 if (!ladjust && width && (width -= tmp) > 0)
723 while (width--)
724 PCHAR(padc);
725 if (neg)
726 PCHAR('-');
727 if (sharpflag && num != 0) {
728 if (base == 8) {
729 PCHAR('0');
730 } else if (base == 16) {
731 PCHAR('0');
732 PCHAR('x');
733 }
734 }
735
736 while (*p)
737 PCHAR(*p--);
738
739 if (ladjust && width && (width -= tmp) > 0)
740 while (width--)
741 PCHAR(padc);
742
743 break;
744 default:
745 while (percent < fmt)
746 PCHAR(*percent++);
747 break;
748 }
749 }
750#undef PCHAR
751}
752
753/*
754 * Put character in log buffer with a particular priority.
755 */
756static void
757msglogchar(int c, int pri)
758{
759 static int lastpri = -1;
760 static int dangling;
761 char nbuf[MAXNBUF];
762 char *p;
763
764 if (!msgbufmapped)
765 return;
766 if (c == '\0' || c == '\r')
767 return;
768 if (pri != -1 && pri != lastpri) {
769 if (dangling) {
770 msgaddchar('\n', NULL);
771 dangling = 0;
772 }
773 msgaddchar('<', NULL);
774 for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
775 msgaddchar(*p--, NULL);
776 msgaddchar('>', NULL);
777 lastpri = pri;
778 }
779 msgaddchar(c, NULL);
780 if (c == '\n') {
781 dangling = 0;
782 lastpri = -1;
783 } else {
784 dangling = 1;
785 }
786}
787
788/*
789 * Put char in log buffer
790 */
791static void
792msgaddchar(int c, void *dummy)
793{
794 struct msgbuf *mbp;
795
796 if (!msgbufmapped)
797 return;
798 mbp = msgbufp;
799 mbp->msg_ptr[mbp->msg_bufx++] = c;
800 if (mbp->msg_bufx >= mbp->msg_size)
801 mbp->msg_bufx = 0;
802 /* If the buffer is full, keep the most recent data. */
803 if (mbp->msg_bufr == mbp->msg_bufx) {
804 if (++mbp->msg_bufr >= mbp->msg_size)
805 mbp->msg_bufr = 0;
806 }
807}
808
809static void
810msgbufcopy(struct msgbuf *oldp)
811{
812 int pos;
813
814 pos = oldp->msg_bufr;
815 while (pos != oldp->msg_bufx) {
816 msglogchar(oldp->msg_ptr[pos], -1);
817 if (++pos >= oldp->msg_size)
818 pos = 0;
819 }
820}
821
822void
823msgbufinit(void *ptr, size_t size)
824{
825 char *cp;
826 static struct msgbuf *oldp = NULL;
827
828 size -= sizeof(*msgbufp);
829 cp = (char *)ptr;
830 msgbufp = (struct msgbuf *) (cp + size);
831 if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
832 msgbufp->msg_bufx >= size || msgbufp->msg_bufr >= size) {
833 bzero(cp, size);
834 bzero(msgbufp, sizeof(*msgbufp));
835 msgbufp->msg_magic = MSG_MAGIC;
836 msgbufp->msg_size = (char *)msgbufp - cp;
837 }
838 msgbufp->msg_ptr = cp;
839 if (msgbufmapped && oldp != msgbufp)
840 msgbufcopy(oldp);
841 msgbufmapped = 1;
842 oldp = msgbufp;
843}
844
845SYSCTL_DECL(_security_bsd);
846
847static int unprivileged_read_msgbuf = 1;
848SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
849 CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
850 "Unprivileged processes may read the kernel message buffer");
851
852/* Sysctls for accessing/clearing the msgbuf */
853static int
854sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
855{
856 int error;
857
858 if (!unprivileged_read_msgbuf) {
859 error = suser(req->td);
860 if (error)
861 return (error);
862 }
863
864 /*
865 * Unwind the buffer, so that it's linear (possibly starting with
866 * some initial nulls).
867 */
868 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
869 msgbufp->msg_size - msgbufp->msg_bufx, req);
870 if (error)
871 return (error);
872 if (msgbufp->msg_bufx > 0) {
873 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
874 msgbufp->msg_bufx, req);
875 }
876 return (error);
877}
878
879SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
880 0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
881
882static int msgbuf_clear;
883
884static int
885sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
886{
887 int error;
888 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
889 if (!error && req->newptr) {
890 /* Clear the buffer and reset write pointer */
891 bzero(msgbufp->msg_ptr, msgbufp->msg_size);
892 msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
893 msgbuf_clear = 0;
894 }
895 return (error);
896}
897
898SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
899 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
900 sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
901
902#include "opt_ddb.h"
903#ifdef DDB
904#include <ddb/ddb.h>
905
906DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
907{
908 int i, j;
909
910 if (!msgbufmapped) {
911 db_printf("msgbuf not mapped yet\n");
912 return;
913 }
914 db_printf("msgbufp = %p\n", msgbufp);
915 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
916 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
917 msgbufp->msg_bufx, msgbufp->msg_ptr);
918 for (i = 0; i < msgbufp->msg_size; i++) {
919 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
920 db_printf("%c", msgbufp->msg_ptr[j]);
921 }
922 db_printf("\n");
923}
924
925#endif /* DDB */