FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_prf.c
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: releng/5.0/sys/kern/subr_prf.c 106917 2002-11-14 16:11:12Z tmm $
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
72 struct putchar_arg {
73 int flags;
74 int pri;
75 struct tty *tty;
76 };
77
78 struct snprintf_arg {
79 char *str;
80 size_t remain;
81 };
82
83 extern int log_open;
84
85 struct tty *constty; /* pointer to console "window" tty */
86
87 static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */
88 static void msglogchar(int c, int pri);
89 static void msgaddchar(int c, void *dummy);
90 static void putchar(int ch, void *arg);
91 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
92 static void snprintf_func(int ch, void *arg);
93
94 static int consintr = 1; /* Ok to handle console interrupts? */
95 static int msgbufmapped; /* Set when safe to use msgbuf */
96 int msgbuftrigger;
97
98 static int log_console_output = 1;
99 TUNABLE_INT("kern.log_console_output", &log_console_output);
100 SYSCTL_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 */
106 void
107 tablefull(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 */
118 int
119 uprintf(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 */
154 void
155 tprintf(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 */
202 int
203 ttyprintf(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 */
222 void
223 log(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
242 void
243 log_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
285 int
286 printf(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
307 int
308 vprintf(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 */
331 static void
332 putchar(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 */
355 int
356 sprintf(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 */
371 int
372 vsprintf(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 */
384 int
385 snprintf(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 */
399 int
400 vsnprintf(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
413 static void
414 snprintf_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 */
430 static char *
431 ksprintn(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, "\1\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 */
471 int
472 kvprintf(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;
511 reswitch: 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 '':
539 if (!dot) {
540 padc = '';
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 - '';
547 ch = *fmt;
548 if (ch < '' || 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;
679 handle_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;
694 handle_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);
707 number:
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('');
730 } else if (base == 16) {
731 PCHAR('');
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 */
756 static void
757 msglogchar(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 */
791 static void
792 msgaddchar(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
809 static void
810 msgbufcopy(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
822 void
823 msgbufinit(void *ptr, int 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_bufx < 0 ||
833 msgbufp->msg_bufr >= size || msgbufp->msg_bufr < 0) {
834 bzero(cp, size);
835 bzero(msgbufp, sizeof(*msgbufp));
836 msgbufp->msg_magic = MSG_MAGIC;
837 msgbufp->msg_size = (char *)msgbufp - cp;
838 }
839 msgbufp->msg_ptr = cp;
840 if (msgbufmapped && oldp != msgbufp)
841 msgbufcopy(oldp);
842 msgbufmapped = 1;
843 oldp = msgbufp;
844 }
845
846 SYSCTL_DECL(_security_bsd);
847
848 static int unprivileged_read_msgbuf = 1;
849 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
850 CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
851 "Unprivileged processes may read the kernel message buffer");
852
853 /* Sysctls for accessing/clearing the msgbuf */
854 static int
855 sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
856 {
857 int error;
858
859 if (!unprivileged_read_msgbuf) {
860 error = suser(req->td);
861 if (error)
862 return (error);
863 }
864
865 /*
866 * Unwind the buffer, so that it's linear (possibly starting with
867 * some initial nulls).
868 */
869 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
870 msgbufp->msg_size - msgbufp->msg_bufx, req);
871 if (error)
872 return (error);
873 if (msgbufp->msg_bufx > 0) {
874 error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
875 msgbufp->msg_bufx, req);
876 }
877 return (error);
878 }
879
880 SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
881 0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
882
883 static int msgbuf_clear;
884
885 static int
886 sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
887 {
888 int error;
889 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
890 if (!error && req->newptr) {
891 /* Clear the buffer and reset write pointer */
892 bzero(msgbufp->msg_ptr, msgbufp->msg_size);
893 msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
894 msgbuf_clear = 0;
895 }
896 return (error);
897 }
898
899 SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
900 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
901 sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
902
903 #include "opt_ddb.h"
904 #ifdef DDB
905 #include <ddb/ddb.h>
906
907 DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
908 {
909 int i, j;
910
911 if (!msgbufmapped) {
912 db_printf("msgbuf not mapped yet\n");
913 return;
914 }
915 db_printf("msgbufp = %p\n", msgbufp);
916 db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
917 msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
918 msgbufp->msg_bufx, msgbufp->msg_ptr);
919 for (i = 0; i < msgbufp->msg_size; i++) {
920 j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
921 db_printf("%c", msgbufp->msg_ptr[j]);
922 }
923 db_printf("\n");
924 }
925
926 #endif /* DDB */
Cache object: 8b88f26bebc6f202544f450015633633
|