hexdump.c revision 98998
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1986, 1988, 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes * (c) UNIX System Laboratories, Inc.
51556Srgrimes * All or some portions of this file are derived from material licensed
61556Srgrimes * to the University of California by American Telephone and Telegraph
71556Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81556Srgrimes * the permission of UNIX System Laboratories, Inc.
91556Srgrimes *
101556Srgrimes * Redistribution and use in source and binary forms, with or without
111556Srgrimes * modification, are permitted provided that the following conditions
121556Srgrimes * are met:
131556Srgrimes * 1. Redistributions of source code must retain the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer.
151556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161556Srgrimes *    notice, this list of conditions and the following disclaimer in the
171556Srgrimes *    documentation and/or other materials provided with the distribution.
181556Srgrimes * 3. All advertising materials mentioning features or use of this software
191556Srgrimes *    must display the following acknowledgement:
201556Srgrimes *	This product includes software developed by the University of
211556Srgrimes *	California, Berkeley and its contributors.
221556Srgrimes * 4. Neither the name of the University nor the names of its contributors
231556Srgrimes *    may be used to endorse or promote products derived from this software
241556Srgrimes *    without specific prior written permission.
251556Srgrimes *
261556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361556Srgrimes * SUCH DAMAGE.
371556Srgrimes *
3850471Speter *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
391556Srgrimes * $FreeBSD: head/sys/kern/subr_prf.c 98998 2002-06-29 00:29:12Z alfred $
401556Srgrimes */
411556Srgrimes
421556Srgrimes#include <sys/param.h>
431556Srgrimes#include <sys/systm.h>
441556Srgrimes#include <sys/lock.h>
451556Srgrimes#include <sys/mutex.h>
461556Srgrimes#include <sys/sx.h>
471556Srgrimes#include <sys/kernel.h>
481556Srgrimes#include <sys/msgbuf.h>
491556Srgrimes#include <sys/malloc.h>
501556Srgrimes#include <sys/proc.h>
511556Srgrimes#include <sys/stdint.h>
521556Srgrimes#include <sys/sysctl.h>
531556Srgrimes#include <sys/tty.h>
541556Srgrimes#include <sys/syslog.h>
551556Srgrimes#include <sys/cons.h>
561556Srgrimes#include <sys/uio.h>
571556Srgrimes
581556Srgrimes/*
591556Srgrimes * Note that stdarg.h and the ANSI style va_start macro is used for both
601556Srgrimes * ANSI and traditional C compilers.
611556Srgrimes */
621556Srgrimes#include <machine/stdarg.h>
631556Srgrimes
641556Srgrimes#define TOCONS	0x01
651556Srgrimes#define TOTTY	0x02
661556Srgrimes#define TOLOG	0x04
671556Srgrimes
681556Srgrimes/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
691556Srgrimes#define MAXNBUF	(sizeof(intmax_t) * NBBY + 1)
701556Srgrimes
711556Srgrimesstruct putchar_arg {
721556Srgrimes	int	flags;
731556Srgrimes	int	pri;
741556Srgrimes	struct	tty *tty;
751556Srgrimes};
761556Srgrimes
771556Srgrimesstruct snprintf_arg {
781556Srgrimes	char	*str;
791556Srgrimes	size_t	remain;
801556Srgrimes};
811556Srgrimes
821556Srgrimesextern	int log_open;
8346684Skris
841556Srgrimesstruct	tty *constty;			/* pointer to console "window" tty */
851556Srgrimes
861556Srgrimesstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
871556Srgrimesstatic void  msglogchar(int c, int pri);
881556Srgrimesstatic void  msgaddchar(int c, void *dummy);
891556Srgrimesstatic void  putchar(int ch, void *arg);
901556Srgrimesstatic char *ksprintn(char *nbuf, uintmax_t num, int base, int *len);
911556Srgrimesstatic void  snprintf_func(int ch, void *arg);
921556Srgrimes
931556Srgrimesstatic int consintr = 1;		/* Ok to handle console interrupts? */
941556Srgrimesstatic int msgbufmapped;		/* Set when safe to use msgbuf */
951556Srgrimesint msgbuftrigger;
961556Srgrimes
971556Srgrimesstatic int      log_console_output = 1;
981556SrgrimesSYSCTL_INT(_kern, OID_AUTO, log_console_output, CTLFLAG_RW,
991556Srgrimes    &log_console_output, 0, "");
1001556Srgrimes
1011556Srgrimes/*
1021556Srgrimes * Warn that a system table is full.
1031556Srgrimes */
1041556Srgrimesvoid
1051556Srgrimestablefull(const char *tab)
1061556Srgrimes{
1071556Srgrimes
1081556Srgrimes	log(LOG_ERR, "%s: table is full\n", tab);
1098855Srgrimes}
1101556Srgrimes
1111556Srgrimes/*
1121556Srgrimes * Uprintf prints to the controlling terminal for the current process.
1131556Srgrimes * It may block if the tty queue is overfull.  No message is printed if
1141556Srgrimes * the queue does not clear in a reasonable time.
1151556Srgrimes */
1161556Srgrimesint
1171556Srgrimesuprintf(const char *fmt, ...)
1181556Srgrimes{
1191556Srgrimes	struct thread *td = curthread;
1201556Srgrimes	struct proc *p = td->td_proc;
1211556Srgrimes	va_list ap;
1221556Srgrimes	struct putchar_arg pca;
1231556Srgrimes	int retval;
1241556Srgrimes
1251556Srgrimes	if (td == NULL || td == PCPU_GET(idlethread))
1261556Srgrimes		return (0);
1271556Srgrimes
1281556Srgrimes	p = td->td_proc;
1291556Srgrimes	PROC_LOCK(p);
1301556Srgrimes	if ((p->p_flag & P_CONTROLT) == 0) {
1311556Srgrimes		PROC_UNLOCK(p);
1321556Srgrimes		return (0);
1331556Srgrimes	}
1341556Srgrimes	SESS_LOCK(p->p_session);
1351556Srgrimes	pca.tty = p->p_session->s_ttyp;
1361556Srgrimes	SESS_UNLOCK(p->p_session);
1371556Srgrimes	PROC_UNLOCK(p);
1381556Srgrimes	if (pca.tty == NULL)
1391556Srgrimes		return (0);
1401556Srgrimes	pca.flags = TOTTY;
1411556Srgrimes	va_start(ap, fmt);
1421556Srgrimes	retval = kvprintf(fmt, putchar, &pca, 10, ap);
1431556Srgrimes	va_end(ap);
1441556Srgrimes
1451556Srgrimes	return (retval);
1461556Srgrimes}
1471556Srgrimes
1481556Srgrimes/*
1491556Srgrimes * tprintf prints on the controlling terminal associated
1501556Srgrimes * with the given session, possibly to the log as well.
1511556Srgrimes */
1521556Srgrimesvoid
1531556Srgrimestprintf(struct proc *p, int pri, const char *fmt, ...)
1541556Srgrimes{
1551556Srgrimes	struct tty *tp = NULL;
1561556Srgrimes	int flags = 0, shld = 0;
1571556Srgrimes	va_list ap;
1581556Srgrimes	struct putchar_arg pca;
1591556Srgrimes	int retval;
1601556Srgrimes
1611556Srgrimes	if (pri != -1)
1621556Srgrimes		flags |= TOLOG;
1631556Srgrimes	if (p != NULL) {
1641556Srgrimes		PROC_LOCK(p);
1651556Srgrimes		if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
1661556Srgrimes			SESS_LOCK(p->p_session);
1671556Srgrimes			SESSHOLD(p->p_session);
1681556Srgrimes			tp = p->p_session->s_ttyp;
1691556Srgrimes			SESS_UNLOCK(p->p_session);
1701556Srgrimes			PROC_UNLOCK(p);
1711556Srgrimes			shld++;
1721556Srgrimes			if (ttycheckoutq(tp, 0))
1731556Srgrimes				flags |= TOTTY;
174			else
175				tp = NULL;
176		} else
177			PROC_UNLOCK(p);
178	}
179	pca.pri = pri;
180	pca.tty = tp;
181	pca.flags = flags;
182	va_start(ap, fmt);
183	retval = kvprintf(fmt, putchar, &pca, 10, ap);
184	va_end(ap);
185	if (shld) {
186		PROC_LOCK(p);
187		SESS_LOCK(p->p_session);
188		SESSRELE(p->p_session);
189		SESS_UNLOCK(p->p_session);
190		PROC_UNLOCK(p);
191	}
192	msgbuftrigger = 1;
193}
194
195/*
196 * Ttyprintf displays a message on a tty; it should be used only by
197 * the tty driver, or anything that knows the underlying tty will not
198 * be revoke(2)'d away.  Other callers should use tprintf.
199 */
200int
201ttyprintf(struct tty *tp, const char *fmt, ...)
202{
203	va_list ap;
204	struct putchar_arg pca;
205	int retval;
206
207	va_start(ap, fmt);
208	pca.tty = tp;
209	pca.flags = TOTTY;
210	retval = kvprintf(fmt, putchar, &pca, 10, ap);
211	va_end(ap);
212	return (retval);
213}
214
215/*
216 * Log writes to the log buffer, and guarantees not to sleep (so can be
217 * called by interrupt routines).  If there is no process reading the
218 * log yet, it writes to the console also.
219 */
220void
221log(int level, const char *fmt, ...)
222{
223	va_list ap;
224	int retval;
225	struct putchar_arg pca;
226
227	pca.tty = NULL;
228	pca.pri = level;
229	pca.flags = log_open ? TOLOG : TOCONS;
230
231	va_start(ap, fmt);
232	retval = kvprintf(fmt, putchar, &pca, 10, ap);
233	va_end(ap);
234
235	msgbuftrigger = 1;
236}
237
238#define CONSCHUNK 128
239
240void
241log_console(struct uio *uio)
242{
243	int c, i, error, iovlen, nl;
244	struct uio muio;
245	struct iovec *miov = NULL;
246	char *consbuffer;
247	int pri;
248
249	if (!log_console_output)
250		return;
251
252	pri = LOG_INFO | LOG_CONSOLE;
253	muio = *uio;
254	iovlen = uio->uio_iovcnt * sizeof (struct iovec);
255	MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
256	MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
257	bcopy(muio.uio_iov, miov, iovlen);
258	muio.uio_iov = miov;
259	uio = &muio;
260
261	nl = 0;
262	while (uio->uio_resid > 0) {
263		c = imin(uio->uio_resid, CONSCHUNK);
264		error = uiomove(consbuffer, c, uio);
265		if (error != 0)
266			return;
267		for (i = 0; i < c; i++) {
268			msglogchar(consbuffer[i], pri);
269			if (consbuffer[i] == '\n')
270				nl = 1;
271			else
272				nl = 0;
273		}
274	}
275	if (!nl)
276		msglogchar('\n', pri);
277	msgbuftrigger = 1;
278	FREE(miov, M_TEMP);
279	FREE(consbuffer, M_TEMP);
280	return;
281}
282
283int
284printf(const char *fmt, ...)
285{
286	va_list ap;
287	int savintr;
288	struct putchar_arg pca;
289	int retval;
290
291	savintr = consintr;		/* disable interrupts */
292	consintr = 0;
293	va_start(ap, fmt);
294	pca.tty = NULL;
295	pca.flags = TOCONS | TOLOG;
296	pca.pri = -1;
297	retval = kvprintf(fmt, putchar, &pca, 10, ap);
298	va_end(ap);
299	if (!panicstr)
300		msgbuftrigger = 1;
301	consintr = savintr;		/* reenable interrupts */
302	return (retval);
303}
304
305int
306vprintf(const char *fmt, va_list ap)
307{
308	int savintr;
309	struct putchar_arg pca;
310	int retval;
311
312	savintr = consintr;		/* disable interrupts */
313	consintr = 0;
314	pca.tty = NULL;
315	pca.flags = TOCONS | TOLOG;
316	pca.pri = -1;
317	retval = kvprintf(fmt, putchar, &pca, 10, ap);
318	if (!panicstr)
319		msgbuftrigger = 1;
320	consintr = savintr;		/* reenable interrupts */
321	return (retval);
322}
323
324/*
325 * Print a character on console or users terminal.  If destination is
326 * the console then the last bunch of characters are saved in msgbuf for
327 * inspection later.
328 */
329static void
330putchar(int c, void *arg)
331{
332	struct putchar_arg *ap = (struct putchar_arg*) arg;
333	int flags = ap->flags;
334	struct tty *tp = ap->tty;
335	if (panicstr)
336		constty = NULL;
337	if ((flags & TOCONS) && tp == NULL && constty) {
338		tp = constty;
339		flags |= TOTTY;
340	}
341	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
342	    (flags & TOCONS) && tp == constty)
343		constty = NULL;
344	if ((flags & TOLOG))
345		msglogchar(c, ap->pri);
346	if ((flags & TOCONS) && constty == NULL && c != '\0')
347		(*v_putc)(c);
348}
349
350/*
351 * Scaled down version of sprintf(3).
352 */
353int
354sprintf(char *buf, const char *cfmt, ...)
355{
356	int retval;
357	va_list ap;
358
359	va_start(ap, cfmt);
360	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
361	buf[retval] = '\0';
362	va_end(ap);
363	return (retval);
364}
365
366/*
367 * Scaled down version of vsprintf(3).
368 */
369int
370vsprintf(char *buf, const char *cfmt, va_list ap)
371{
372	int retval;
373
374	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
375	buf[retval] = '\0';
376	return (retval);
377}
378
379/*
380 * Scaled down version of snprintf(3).
381 */
382int
383snprintf(char *str, size_t size, const char *format, ...)
384{
385	int retval;
386	va_list ap;
387
388	va_start(ap, format);
389	retval = vsnprintf(str, size, format, ap);
390	va_end(ap);
391	return(retval);
392}
393
394/*
395 * Scaled down version of vsnprintf(3).
396 */
397int
398vsnprintf(char *str, size_t size, const char *format, va_list ap)
399{
400	struct snprintf_arg info;
401	int retval;
402
403	info.str = str;
404	info.remain = size;
405	retval = kvprintf(format, snprintf_func, &info, 10, ap);
406	if (info.remain >= 1)
407		*info.str++ = '\0';
408	return (retval);
409}
410
411static void
412snprintf_func(int ch, void *arg)
413{
414	struct snprintf_arg *const info = arg;
415
416	if (info->remain >= 2) {
417		*info->str++ = ch;
418		info->remain--;
419	}
420}
421
422/*
423 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
424 * order; return an optional length and a pointer to the last character
425 * written in the buffer (i.e., the first character of the string).
426 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
427 */
428static char *
429ksprintn(char *nbuf, uintmax_t num, int base, int *lenp)
430{
431	char *p;
432
433	p = nbuf;
434	*p = '\0';
435	do {
436		*++p = hex2ascii(num % base);
437	} while (num /= base);
438	if (lenp)
439		*lenp = p - nbuf;
440	return (p);
441}
442
443/*
444 * Scaled down version of printf(3).
445 *
446 * Two additional formats:
447 *
448 * The format %b is supported to decode error registers.
449 * Its usage is:
450 *
451 *	printf("reg=%b\n", regval, "<base><arg>*");
452 *
453 * where <base> is the output base expressed as a control character, e.g.
454 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
455 * the first of which gives the bit number to be inspected (origin 1), and
456 * the next characters (up to a control character, i.e. a character <= 32),
457 * give the name of the register.  Thus:
458 *
459 *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
460 *
461 * would produce output:
462 *
463 *	reg=3<BITTWO,BITONE>
464 *
465 * XXX:  %D  -- Hexdump, takes pointer and separator string:
466 *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
467 *		("%*D", len, ptr, " " -> XX XX XX XX ...
468 */
469int
470kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
471{
472#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
473	char nbuf[MAXNBUF];
474	char *d;
475	const char *p, *percent, *q;
476	u_char *up;
477	int ch, n;
478	uintmax_t num;
479	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
480	int jflag;
481	int dwidth;
482	char padc;
483	int retval = 0;
484
485	num = 0;
486	if (!func)
487		d = (char *) arg;
488	else
489		d = NULL;
490
491	if (fmt == NULL)
492		fmt = "(fmt null)\n";
493
494	if (radix < 2 || radix > 36)
495		radix = 10;
496
497	for (;;) {
498		padc = ' ';
499		width = 0;
500		while ((ch = (u_char)*fmt++) != '%') {
501			if (ch == '\0')
502				return (retval);
503			PCHAR(ch);
504		}
505		percent = fmt - 1;
506		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
507		sign = 0; dot = 0; dwidth = 0;
508		jflag = 0;
509reswitch:	switch (ch = (u_char)*fmt++) {
510		case '.':
511			dot = 1;
512			goto reswitch;
513		case '#':
514			sharpflag = 1;
515			goto reswitch;
516		case '+':
517			sign = 1;
518			goto reswitch;
519		case '-':
520			ladjust = 1;
521			goto reswitch;
522		case '%':
523			PCHAR(ch);
524			break;
525		case '*':
526			if (!dot) {
527				width = va_arg(ap, int);
528				if (width < 0) {
529					ladjust = !ladjust;
530					width = -width;
531				}
532			} else {
533				dwidth = va_arg(ap, int);
534			}
535			goto reswitch;
536		case '0':
537			if (!dot) {
538				padc = '0';
539				goto reswitch;
540			}
541		case '1': case '2': case '3': case '4':
542		case '5': case '6': case '7': case '8': case '9':
543				for (n = 0;; ++fmt) {
544					n = n * 10 + ch - '0';
545					ch = *fmt;
546					if (ch < '0' || ch > '9')
547						break;
548				}
549			if (dot)
550				dwidth = n;
551			else
552				width = n;
553			goto reswitch;
554		case 'b':
555			num = va_arg(ap, int);
556			p = va_arg(ap, char *);
557			for (q = ksprintn(nbuf, num, *p++, NULL); *q;)
558				PCHAR(*q--);
559
560			if (num == 0)
561				break;
562
563			for (tmp = 0; *p;) {
564				n = *p++;
565				if (num & (1 << (n - 1))) {
566					PCHAR(tmp ? ',' : '<');
567					for (; (n = *p) > ' '; ++p)
568						PCHAR(n);
569					tmp = 1;
570				} else
571					for (; *p > ' '; ++p)
572						continue;
573			}
574			if (tmp)
575				PCHAR('>');
576			break;
577		case 'c':
578			PCHAR(va_arg(ap, int));
579			break;
580		case 'D':
581			up = va_arg(ap, u_char *);
582			p = va_arg(ap, char *);
583			if (!width)
584				width = 16;
585			while(width--) {
586				PCHAR(hex2ascii(*up >> 4));
587				PCHAR(hex2ascii(*up & 0x0f));
588				up++;
589				if (width)
590					for (q=p;*q;q++)
591						PCHAR(*q);
592			}
593			break;
594		case 'd':
595			base = 10;
596			sign = 1;
597			goto handle_sign;
598		case 'j':
599			jflag = 1;
600			goto reswitch;
601		case 'l':
602			if (lflag) {
603				lflag = 0;
604				qflag = 1;
605			} else
606				lflag = 1;
607			goto reswitch;
608		case 'n':
609			if (jflag)
610				*(va_arg(ap, intmax_t *)) = retval;
611			else if (qflag)
612				*(va_arg(ap, quad_t *)) = retval;
613			else if (lflag)
614				*(va_arg(ap, long *)) = retval;
615			else
616				*(va_arg(ap, int *)) = retval;
617			break;
618		case 'o':
619			base = 8;
620			goto handle_nosign;
621		case 'p':
622			base = 16;
623			sharpflag = (width == 0);
624			sign = 0;
625			num = (uintptr_t)va_arg(ap, void *);
626			goto number;
627		case 'q':
628			qflag = 1;
629			goto reswitch;
630		case 'r':
631			base = radix;
632			if (sign)
633				goto handle_sign;
634			goto handle_nosign;
635		case 's':
636			p = va_arg(ap, char *);
637			if (p == NULL)
638				p = "(null)";
639			if (!dot)
640				n = strlen (p);
641			else
642				for (n = 0; n < dwidth && p[n]; n++)
643					continue;
644
645			width -= n;
646
647			if (!ladjust && width > 0)
648				while (width--)
649					PCHAR(padc);
650			while (n--)
651				PCHAR(*p++);
652			if (ladjust && width > 0)
653				while (width--)
654					PCHAR(padc);
655			break;
656		case 'u':
657			base = 10;
658			goto handle_nosign;
659		case 'x':
660		case 'X':
661			base = 16;
662			goto handle_nosign;
663		case 'z':
664			base = 16;
665			if (sign)
666				goto handle_sign;
667handle_nosign:
668			sign = 0;
669			if (jflag)
670				num = va_arg(ap, uintmax_t);
671			else if (qflag)
672				num = va_arg(ap, u_quad_t);
673			else if (lflag)
674				num = va_arg(ap, u_long);
675			else
676				num = va_arg(ap, u_int);
677			goto number;
678handle_sign:
679			if (jflag)
680				num = va_arg(ap, intmax_t);
681			else if (qflag)
682				num = va_arg(ap, quad_t);
683			else if (lflag)
684				num = va_arg(ap, long);
685			else
686				num = va_arg(ap, int);
687number:
688			if (sign && (intmax_t)num < 0) {
689				neg = 1;
690				num = -(intmax_t)num;
691			}
692			p = ksprintn(nbuf, num, base, &tmp);
693			if (sharpflag && num != 0) {
694				if (base == 8)
695					tmp++;
696				else if (base == 16)
697					tmp += 2;
698			}
699			if (neg)
700				tmp++;
701
702			if (!ladjust && width && (width -= tmp) > 0)
703				while (width--)
704					PCHAR(padc);
705			if (neg)
706				PCHAR('-');
707			if (sharpflag && num != 0) {
708				if (base == 8) {
709					PCHAR('0');
710				} else if (base == 16) {
711					PCHAR('0');
712					PCHAR('x');
713				}
714			}
715
716			while (*p)
717				PCHAR(*p--);
718
719			if (ladjust && width && (width -= tmp) > 0)
720				while (width--)
721					PCHAR(padc);
722
723			break;
724		default:
725			while (percent < fmt)
726				PCHAR(*percent++);
727			break;
728		}
729	}
730#undef PCHAR
731}
732
733/*
734 * Put character in log buffer with a particular priority.
735 */
736static void
737msglogchar(int c, int pri)
738{
739	static int lastpri = -1;
740	static int dangling;
741	char nbuf[MAXNBUF];
742	char *p;
743
744	if (!msgbufmapped)
745		return;
746	if (c == '\0' || c == '\r')
747		return;
748	if (pri != -1 && pri != lastpri) {
749		if (dangling) {
750			msgaddchar('\n', NULL);
751			dangling = 0;
752		}
753		msgaddchar('<', NULL);
754		for (p = ksprintn(nbuf, (uintmax_t)pri, 10, NULL); *p;)
755			msgaddchar(*p--, NULL);
756		msgaddchar('>', NULL);
757		lastpri = pri;
758	}
759	msgaddchar(c, NULL);
760	if (c == '\n') {
761		dangling = 0;
762		lastpri = -1;
763	} else {
764		dangling = 1;
765	}
766}
767
768/*
769 * Put char in log buffer
770 */
771static void
772msgaddchar(int c, void *dummy)
773{
774	struct msgbuf *mbp;
775
776	if (!msgbufmapped)
777		return;
778	mbp = msgbufp;
779	mbp->msg_ptr[mbp->msg_bufx++] = c;
780	if (mbp->msg_bufx >= mbp->msg_size)
781		mbp->msg_bufx = 0;
782	/* If the buffer is full, keep the most recent data. */
783	if (mbp->msg_bufr == mbp->msg_bufx) {
784		if (++mbp->msg_bufr >= mbp->msg_size)
785			mbp->msg_bufr = 0;
786	}
787}
788
789static void
790msgbufcopy(struct msgbuf *oldp)
791{
792	int pos;
793
794	pos = oldp->msg_bufr;
795	while (pos != oldp->msg_bufx) {
796		msglogchar(oldp->msg_ptr[pos], -1);
797		if (++pos >= oldp->msg_size)
798			pos = 0;
799	}
800}
801
802void
803msgbufinit(void *ptr, size_t size)
804{
805	char *cp;
806	static struct msgbuf *oldp = NULL;
807
808	size -= sizeof(*msgbufp);
809	cp = (char *)ptr;
810	msgbufp = (struct msgbuf *) (cp + size);
811	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size ||
812	    msgbufp->msg_bufx >= size || msgbufp->msg_bufr >= size) {
813		bzero(cp, size);
814		bzero(msgbufp, sizeof(*msgbufp));
815		msgbufp->msg_magic = MSG_MAGIC;
816		msgbufp->msg_size = (char *)msgbufp - cp;
817	}
818	msgbufp->msg_ptr = cp;
819	if (msgbufmapped && oldp != msgbufp)
820		msgbufcopy(oldp);
821	msgbufmapped = 1;
822	oldp = msgbufp;
823}
824
825SYSCTL_DECL(_security_bsd);
826
827static int unprivileged_read_msgbuf = 1;
828SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf,
829    CTLFLAG_RW, &unprivileged_read_msgbuf, 0,
830    "Unprivileged processes may read the kernel message buffer");
831
832/* Sysctls for accessing/clearing the msgbuf */
833static int
834sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
835{
836	int error;
837
838	if (!unprivileged_read_msgbuf) {
839		error = suser(req->td);
840		if (error)
841			return (error);
842	}
843
844	/*
845	 * Unwind the buffer, so that it's linear (possibly starting with
846	 * some initial nulls).
847	 */
848	error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr + msgbufp->msg_bufx,
849	    msgbufp->msg_size - msgbufp->msg_bufx, req);
850	if (error)
851		return (error);
852	if (msgbufp->msg_bufx > 0) {
853		error = sysctl_handle_opaque(oidp, msgbufp->msg_ptr,
854		    msgbufp->msg_bufx, req);
855	}
856	return (error);
857}
858
859SYSCTL_PROC(_kern, OID_AUTO, msgbuf, CTLTYPE_STRING | CTLFLAG_RD,
860    0, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
861
862static int msgbuf_clear;
863
864static int
865sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS)
866{
867	int error;
868	error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
869	if (!error && req->newptr) {
870		/* Clear the buffer and reset write pointer */
871		bzero(msgbufp->msg_ptr, msgbufp->msg_size);
872		msgbufp->msg_bufr = msgbufp->msg_bufx = 0;
873		msgbuf_clear = 0;
874	}
875	return (error);
876}
877
878SYSCTL_PROC(_kern, OID_AUTO, msgbuf_clear,
879    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE, &msgbuf_clear, 0,
880    sysctl_kern_msgbuf_clear, "I", "Clear kernel message buffer");
881
882#include "opt_ddb.h"
883#ifdef DDB
884#include <ddb/ddb.h>
885
886DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
887{
888	int i, j;
889
890	if (!msgbufmapped) {
891		db_printf("msgbuf not mapped yet\n");
892		return;
893	}
894	db_printf("msgbufp = %p\n", msgbufp);
895	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
896	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
897	    msgbufp->msg_bufx, msgbufp->msg_ptr);
898	for (i = 0; i < msgbufp->msg_size; i++) {
899		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
900		db_printf("%c", msgbufp->msg_ptr[j]);
901	}
902	db_printf("\n");
903}
904
905#endif /* DDB */
906