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