xref: /freebsd/sys/kern/subr_prf.c (revision 5773cccf19ef7b97e56c1101aa481c43149224da)
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$
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, "\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  */
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 '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;
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('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  */
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 */
927