hexdump.c revision 15680
1299481Sjkim/*-
2299481Sjkim * Copyright (c) 1986, 1988, 1991, 1993
3290207Sjkim *	The Regents of the University of California.  All rights reserved.
4290207Sjkim * (c) UNIX System Laboratories, Inc.
5290207Sjkim * All or some portions of this file are derived from material licensed
6290207Sjkim * to the University of California by American Telephone and Telegraph
7290207Sjkim * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8290207Sjkim * the permission of UNIX System Laboratories, Inc.
9290207Sjkim *
10290207Sjkim * Redistribution and use in source and binary forms, with or without
11299481Sjkim * modification, are permitted provided that the following conditions
12299481Sjkim * are met:
13299481Sjkim * 1. Redistributions of source code must retain the above copyright
14299481Sjkim *    notice, this list of conditions and the following disclaimer.
15299481Sjkim * 2. Redistributions in binary form must reproduce the above copyright
16299481Sjkim *    notice, this list of conditions and the following disclaimer in the
17299481Sjkim *    documentation and/or other materials provided with the distribution.
18299481Sjkim * 3. All advertising materials mentioning features or use of this software
19290207Sjkim *    must display the following acknowledgement:
20290207Sjkim *	This product includes software developed by the University of
21290207Sjkim *	California, Berkeley and its contributors.
22290207Sjkim * 4. Neither the name of the University nor the names of its contributors
23290207Sjkim *    may be used to endorse or promote products derived from this software
24290207Sjkim *    without specific prior written permission.
25290207Sjkim *
26290207Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27290207Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28290207Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29290207Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30290207Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31290207Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32290207Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33290207Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34290207Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35290207Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36290207Sjkim * SUCH DAMAGE.
37290207Sjkim *
38290207Sjkim *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
39290207Sjkim * $Id: subr_prf.c,v 1.35 1996/05/02 09:34:45 phk Exp $
40290207Sjkim */
41290207Sjkim
42290207Sjkim#include "opt_ddb.h"
43290207Sjkim
44290207Sjkim#include <sys/param.h>
45290207Sjkim#include <sys/systm.h>
46290207Sjkim#include <sys/reboot.h>
47290207Sjkim#include <sys/msgbuf.h>
48290207Sjkim#include <sys/proc.h>
49290207Sjkim#include <sys/vnode.h>
50290207Sjkim#include <sys/tty.h>
51290207Sjkim#include <sys/tprintf.h>
52290207Sjkim#include <sys/syslog.h>
53290207Sjkim#include <sys/malloc.h>
54290207Sjkim#include <sys/kernel.h>
55290207Sjkim#include <sys/sysctl.h>
56290207Sjkim#include <machine/cons.h>
57290207Sjkim
58290207Sjkim/*
59290207Sjkim * Note that stdarg.h and the ANSI style va_start macro is used for both
60290207Sjkim * ANSI and traditional C compilers.
61290207Sjkim */
62290207Sjkim#include <machine/stdarg.h>
63290207Sjkim
64290207Sjkim#if defined(DDB)
65290207Sjkim#ifdef DDB_UNATTENDED
66290207Sjkim	static int debugger_on_panic = 0;
67290207Sjkim#else
68290207Sjkim	static int debugger_on_panic = 1;
69290207Sjkim#endif
70290207Sjkim
71290207SjkimSYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW,
72290207Sjkim	&debugger_on_panic, 0, "");
73290207Sjkim#endif
74290207Sjkim
75290207Sjkim#define TOCONS	0x01
76290207Sjkim#define TOTTY	0x02
77290207Sjkim#define TOLOG	0x04
78290207Sjkim
79290207Sjkimstruct	tty *constty;			/* pointer to console "window" tty */
80290207Sjkim
81290207Sjkimstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
82290207Sjkim
83290207Sjkimstatic void  logpri __P((int level));
84290207Sjkimstatic void  msglogchar(int c, void *dummyarg);
85290207Sjkimstruct putchar_arg {int flags; struct tty *tty; };
86290207Sjkimstatic void  putchar __P((int ch, void *arg));
87290207Sjkimstatic char *ksprintn __P((u_long num, int base, int *len));
88290207Sjkim
89290207Sjkimstatic int consintr = 1;		/* Ok to handle console interrupts? */
90290207Sjkim
91290207Sjkim/*
92290207Sjkim * Variable panicstr contains argument to first call to panic; used as flag
93290207Sjkim * to indicate that the kernel has already called panic.
94290207Sjkim */
95290207Sjkimconst char *panicstr;
96290207Sjkim
97290207Sjkim/*
98290207Sjkim * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
99290207Sjkim * and then reboots.  If we are called twice, then we avoid trying to sync
100290207Sjkim * the disks as this often leads to recursive panics.
101290207Sjkim */
102290207Sjkim#ifdef __GNUC__
103290207Sjkim__dead			/* panic() does not return */
104290207Sjkim#endif
105290207Sjkimvoid
106290207Sjkimpanic(const char *fmt, ...)
107290207Sjkim{
108290207Sjkim	int bootopt;
109290207Sjkim	va_list ap;
110290207Sjkim
111290207Sjkim	bootopt = RB_AUTOBOOT | RB_DUMP;
112290207Sjkim	if (panicstr)
113290207Sjkim		bootopt |= RB_NOSYNC;
114290207Sjkim	else
115290207Sjkim		panicstr = fmt;
116290207Sjkim
117290207Sjkim	printf("panic: ");
118290207Sjkim	va_start(ap, fmt);
119290207Sjkim	vprintf(fmt, ap);
120290207Sjkim	va_end(ap);
121290207Sjkim	printf("\n");
122290207Sjkim
123290207Sjkim#if defined(DDB)
124290207Sjkim	if (debugger_on_panic)
125290207Sjkim		Debugger ("panic");
126290207Sjkim#endif
127290207Sjkim	boot(bootopt);
128290207Sjkim}
129290207Sjkim
130290207Sjkim/*
131290207Sjkim * Warn that a system table is full.
132290207Sjkim */
133290207Sjkimvoid
134290207Sjkimtablefull(tab)
135290207Sjkim	const char *tab;
136290207Sjkim{
137290207Sjkim
138290207Sjkim	log(LOG_ERR, "%s: table is full\n", tab);
139290207Sjkim}
140290207Sjkim
141290207Sjkim/*
142290207Sjkim * Uprintf prints to the controlling terminal for the current process.
143290207Sjkim * It may block if the tty queue is overfull.  No message is printed if
144290207Sjkim * the queue does not clear in a reasonable time.
145290207Sjkim */
146290207Sjkimvoid
147290207Sjkimuprintf(const char *fmt, ...)
148290207Sjkim{
149290207Sjkim	struct proc *p = curproc;
150290207Sjkim	va_list ap;
151290207Sjkim	struct putchar_arg pca;
152290207Sjkim
153290207Sjkim	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
154290207Sjkim		va_start(ap, fmt);
155290207Sjkim		pca.tty = p->p_session->s_ttyp;
156290207Sjkim		pca.flags = TOTTY;
157290207Sjkim		kvprintf(fmt, putchar, &pca, 10, ap);
158290207Sjkim		va_end(ap);
159290207Sjkim	}
160290207Sjkim}
161290207Sjkim
162290207Sjkimtpr_t
163290207Sjkimtprintf_open(p)
164290207Sjkim	register struct proc *p;
165290207Sjkim{
166290207Sjkim
167290207Sjkim	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
168290207Sjkim		SESSHOLD(p->p_session);
169290207Sjkim		return ((tpr_t) p->p_session);
170290207Sjkim	}
171290207Sjkim	return ((tpr_t) NULL);
172290207Sjkim}
173290207Sjkim
174290207Sjkimvoid
175290207Sjkimtprintf_close(sess)
176290207Sjkim	tpr_t sess;
177290207Sjkim{
178290207Sjkim
179290207Sjkim	if (sess)
180290207Sjkim		SESSRELE((struct session *) sess);
181290207Sjkim}
182290207Sjkim
183290207Sjkim/*
184290207Sjkim * tprintf prints on the controlling terminal associated
185290207Sjkim * with the given session.
186290207Sjkim */
187290207Sjkimvoid
188290207Sjkimtprintf(tpr_t tpr, const char *fmt, ...)
189290207Sjkim{
190290207Sjkim	register struct session *sess = (struct session *)tpr;
191290207Sjkim	struct tty *tp = NULL;
192290207Sjkim	int flags = TOLOG;
193290207Sjkim	va_list ap;
194290207Sjkim	struct putchar_arg pca;
195290207Sjkim
196290207Sjkim	logpri(LOG_INFO);
197290207Sjkim	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
198290207Sjkim		flags |= TOTTY;
199290207Sjkim		tp = sess->s_ttyp;
200290207Sjkim	}
201290207Sjkim	va_start(ap, fmt);
202290207Sjkim	pca.tty = tp;
203290207Sjkim	pca.flags = flags;
204290207Sjkim	kvprintf(fmt, putchar, &pca, 10, ap);
205290207Sjkim	va_end(ap);
206290207Sjkim	logwakeup();
207290207Sjkim}
208290207Sjkim
209290207Sjkim/*
210290207Sjkim * Ttyprintf displays a message on a tty; it should be used only by
211290207Sjkim * the tty driver, or anything that knows the underlying tty will not
212290207Sjkim * be revoke(2)'d away.  Other callers should use tprintf.
213290207Sjkim */
214290207Sjkimvoid
215290207Sjkimttyprintf(struct tty *tp, const char *fmt, ...)
216290207Sjkim{
217290207Sjkim	va_list ap;
218290207Sjkim	struct putchar_arg pca;
219290207Sjkim	va_start(ap, fmt);
220290207Sjkim	pca.tty = tp;
221290207Sjkim	pca.flags = TOTTY;
222290207Sjkim	kvprintf(fmt, putchar, &pca, 10, ap);
223290207Sjkim	va_end(ap);
224290207Sjkim}
225290207Sjkim
226290207Sjkimextern	int log_open;
227290207Sjkim
228290207Sjkim/*
229290207Sjkim * Log writes to the log buffer, and guarantees not to sleep (so can be
230290207Sjkim * called by interrupt routines).  If there is no process reading the
231290207Sjkim * log yet, it writes to the console also.
232290207Sjkim */
233290207Sjkimvoid
234290207Sjkimlog(int level, const char *fmt, ...)
235290207Sjkim{
236290207Sjkim	register int s;
237290207Sjkim	va_list ap;
238290207Sjkim
239290207Sjkim	s = splhigh();
240290207Sjkim	logpri(level);
241290207Sjkim	va_start(ap, fmt);
242290207Sjkim
243290207Sjkim	kvprintf(fmt, msglogchar, NULL, 10, ap);
244290207Sjkim	va_end(ap);
245290207Sjkim
246290207Sjkim	splx(s);
247290207Sjkim	if (!log_open) {
248290207Sjkim		struct putchar_arg pca;
249290207Sjkim		va_start(ap, fmt);
250290207Sjkim		pca.tty = NULL;
251290207Sjkim		pca.flags = TOCONS;
252290207Sjkim		kvprintf(fmt, putchar, &pca, 10, ap);
253290207Sjkim		va_end(ap);
254290207Sjkim	}
255290207Sjkim	logwakeup();
256290207Sjkim}
257290207Sjkim
258290207Sjkimstatic void
259290207Sjkimlogpri(level)
260290207Sjkim	int level;
261290207Sjkim{
262290207Sjkim	register char *p;
263290207Sjkim
264290207Sjkim	msglogchar('<', NULL);
265290207Sjkim	for (p = ksprintn((u_long)level, 10, NULL); *p;)
266290207Sjkim		msglogchar(*p--, NULL);
267290207Sjkim	msglogchar('>', NULL);
268290207Sjkim}
269290207Sjkim
270290207Sjkimint
271290207Sjkimaddlog(const char *fmt, ...)
272290207Sjkim{
273290207Sjkim	register int s;
274290207Sjkim	va_list ap;
275299481Sjkim	int retval;
276299481Sjkim
277299481Sjkim	s = splhigh();
278299481Sjkim	va_start(ap, fmt);
279299481Sjkim	retval = kvprintf(fmt, msglogchar, NULL, 10, ap);
280299481Sjkim	splx(s);
281299481Sjkim	va_end(ap);
282299481Sjkim	if (!log_open) {
283290207Sjkim		struct putchar_arg pca;
284290207Sjkim		va_start(ap, fmt);
285290207Sjkim		pca.tty = NULL;
286290207Sjkim		pca.flags = TOCONS;
287290207Sjkim		kvprintf(fmt, putchar, &pca, 10, ap);
288290207Sjkim		va_end(ap);
289290207Sjkim	}
290290207Sjkim	logwakeup();
291290207Sjkim	return (retval);
292290207Sjkim}
293290207Sjkim
294290207Sjkimint
295290207Sjkimprintf(const char *fmt, ...)
296290207Sjkim{
297290207Sjkim	va_list ap;
298290207Sjkim	register int savintr;
299290207Sjkim	struct putchar_arg pca;
300290207Sjkim	int retval;
301290207Sjkim
302290207Sjkim	savintr = consintr;		/* disable interrupts */
303290207Sjkim	consintr = 0;
304290207Sjkim	va_start(ap, fmt);
305290207Sjkim	pca.tty = NULL;
306290207Sjkim	pca.flags = TOCONS | TOLOG;
307290207Sjkim	retval = kvprintf(fmt, putchar, &pca, 10, ap);
308290207Sjkim	va_end(ap);
309290207Sjkim	if (!panicstr)
310290207Sjkim		logwakeup();
311290207Sjkim	consintr = savintr;		/* reenable interrupts */
312290207Sjkim	return retval;
313290207Sjkim}
314290207Sjkim
315290207Sjkimvoid
316290207Sjkimvprintf(const char *fmt, va_list ap)
317290207Sjkim{
318290207Sjkim	register int savintr;
319290207Sjkim	struct putchar_arg pca;
320290207Sjkim
321290207Sjkim	savintr = consintr;		/* disable interrupts */
322290207Sjkim	consintr = 0;
323290207Sjkim	pca.tty = NULL;
324290207Sjkim	pca.flags = TOCONS | TOLOG;
325290207Sjkim	kvprintf(fmt, putchar, &pca, 10, ap);
326290207Sjkim	if (!panicstr)
327290207Sjkim		logwakeup();
328290207Sjkim	consintr = savintr;		/* reenable interrupts */
329290207Sjkim}
330290207Sjkim
331290207Sjkim/*
332290207Sjkim * Print a character on console or users terminal.  If destination is
333290207Sjkim * the console then the last MSGBUFS characters are saved in msgbuf for
334290207Sjkim * inspection later.
335290207Sjkim */
336290207Sjkimstatic void
337290207Sjkimputchar(int c, void *arg)
338290207Sjkim{
339290207Sjkim	struct putchar_arg *ap = (struct putchar_arg*) arg;
340290207Sjkim	int flags = ap->flags;
341290207Sjkim	struct tty *tp = ap->tty;
342290207Sjkim	if (panicstr)
343290207Sjkim		constty = NULL;
344290207Sjkim	if ((flags & TOCONS) && tp == NULL && constty) {
345290207Sjkim		tp = constty;
346290207Sjkim		flags |= TOTTY;
347290207Sjkim	}
348290207Sjkim	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
349290207Sjkim	    (flags & TOCONS) && tp == constty)
350290207Sjkim		constty = NULL;
351290207Sjkim	if ((flags & TOLOG))
352290207Sjkim		msglogchar(c, NULL);
353290207Sjkim	if ((flags & TOCONS) && constty == NULL && c != '\0')
354290207Sjkim		(*v_putc)(c);
355290207Sjkim}
356290207Sjkim
357290207Sjkim/*
358290207Sjkim * Scaled down version of sprintf(3).
359290207Sjkim */
360290207Sjkimint
361290207Sjkimsprintf(char *buf, const char *cfmt, ...)
362290207Sjkim{
363290207Sjkim	int retval;
364290207Sjkim	va_list ap;
365290207Sjkim
366290207Sjkim	va_start(ap, cfmt);
367290207Sjkim	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
368290207Sjkim	buf[retval] = '\0';
369290207Sjkim	va_end(ap);
370290207Sjkim	return retval;
371290207Sjkim}
372290207Sjkim
373290207Sjkim/*
374290207Sjkim * Put a number (base <= 16) in a buffer in reverse order; return an
375290207Sjkim * optional length and a pointer to the NULL terminated (preceded?)
376290207Sjkim * buffer.
377290207Sjkim */
378290207Sjkimstatic char *
379290207Sjkimksprintn(ul, base, lenp)
380290207Sjkim	register u_long ul;
381290207Sjkim	register int base, *lenp;
382290207Sjkim{					/* A long in base 8, plus NULL. */
383290207Sjkim	static char buf[sizeof(long) * NBBY / 3 + 2];
384290207Sjkim	register char *p;
385290207Sjkim
386290207Sjkim	p = buf;
387290207Sjkim	do {
388290207Sjkim		*++p = hex2ascii(ul % base);
389290207Sjkim	} while (ul /= base);
390290207Sjkim	if (lenp)
391290207Sjkim		*lenp = p - buf;
392290207Sjkim	return (p);
393290207Sjkim}
394290207Sjkim
395290207Sjkim/*
396290207Sjkim * Scaled down version of printf(3).
397290207Sjkim *
398290207Sjkim * Two additional formats:
399290207Sjkim *
400290207Sjkim * The format %b is supported to decode error registers.
401290207Sjkim * Its usage is:
402290207Sjkim *
403290207Sjkim *	printf("reg=%b\n", regval, "<base><arg>*");
404290207Sjkim *
405290207Sjkim * where <base> is the output base expressed as a control character, e.g.
406290207Sjkim * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
407290207Sjkim * the first of which gives the bit number to be inspected (origin 1), and
408290207Sjkim * the next characters (up to a control character, i.e. a character <= 32),
409290207Sjkim * give the name of the register.  Thus:
410290207Sjkim *
411290207Sjkim *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
412290207Sjkim *
413290207Sjkim * would produce output:
414290207Sjkim *
415290207Sjkim *	reg=3<BITTWO,BITONE>
416290207Sjkim *
417290207Sjkim * XXX:  %D  -- Hexdump, takes pointer and separator string:
418290207Sjkim *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
419290207Sjkim *		("%*D", len, ptr, " " -> XX XX XX XX ...
420290207Sjkim */
421290207Sjkimint
422290207Sjkimkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
423290207Sjkim{
424290207Sjkim#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
425290207Sjkim	char *p, *q, *d;
426290207Sjkim	u_char *up;
427290207Sjkim	int ch, n;
428290207Sjkim	u_long ul;
429290207Sjkim	int base, lflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
430290207Sjkim	int dwidth;
431290207Sjkim	char padc;
432290207Sjkim	int retval = 0;
433290207Sjkim
434290207Sjkim	if (!func)
435290207Sjkim		d = (char *) arg;
436290207Sjkim	else
437290207Sjkim		d = NULL;
438290207Sjkim
439290207Sjkim	if (fmt == NULL)
440290207Sjkim		fmt = "(fmt null)\n";
441290207Sjkim
442290207Sjkim	if (radix < 2 || radix > 36)
443290207Sjkim		radix = 10;
444290207Sjkim
445290207Sjkim	for (;;) {
446290207Sjkim		padc = ' ';
447290207Sjkim		width = 0;
448290207Sjkim		while ((ch = *(u_char *)fmt++) != '%') {
449290207Sjkim			if (ch == '\0')
450290207Sjkim				return retval;
451290207Sjkim			PCHAR(ch);
452290207Sjkim		}
453290207Sjkim		lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
454290207Sjkim		sign = 0; dot = 0; dwidth = 0;
455290207Sjkimreswitch:	switch (ch = *(u_char *)fmt++) {
456290207Sjkim		case '.':
457290207Sjkim			dot = 1;
458290207Sjkim			goto reswitch;
459290207Sjkim		case '#':
460290207Sjkim			sharpflag = 1;
461290207Sjkim			goto reswitch;
462290207Sjkim		case '+':
463290207Sjkim			sign = 1;
464290207Sjkim			goto reswitch;
465290207Sjkim		case '-':
466290207Sjkim			ladjust = 1;
467290207Sjkim			goto reswitch;
468290207Sjkim		case '%':
469290207Sjkim			PCHAR(ch);
470290207Sjkim			break;
471290207Sjkim		case '*':
472290207Sjkim			if (!dot) {
473290207Sjkim				width = va_arg(ap, int);
474290207Sjkim				if (width < 0) {
475290207Sjkim					ladjust = !ladjust;
476290207Sjkim					width = -width;
477290207Sjkim				}
478290207Sjkim			} else {
479290207Sjkim				dwidth = va_arg(ap, int);
480290207Sjkim			}
481290207Sjkim			goto reswitch;
482290207Sjkim		case '0':
483290207Sjkim			if (!dot) {
484290207Sjkim				padc = '0';
485290207Sjkim				goto reswitch;
486290207Sjkim			}
487290207Sjkim		case '1': case '2': case '3': case '4':
488290207Sjkim		case '5': case '6': case '7': case '8': case '9':
489290207Sjkim				for (n = 0;; ++fmt) {
490290207Sjkim					n = n * 10 + ch - '0';
491290207Sjkim					ch = *fmt;
492290207Sjkim					if (ch < '0' || ch > '9')
493290207Sjkim						break;
494290207Sjkim				}
495290207Sjkim			if (dot)
496290207Sjkim				dwidth = n;
497290207Sjkim			else
498290207Sjkim				width = n;
499290207Sjkim			goto reswitch;
500290207Sjkim		case 'b':
501290207Sjkim			ul = va_arg(ap, int);
502290207Sjkim			p = va_arg(ap, char *);
503290207Sjkim			for (q = ksprintn(ul, *p++, NULL); *q;)
504290207Sjkim				PCHAR(*q--);
505290207Sjkim
506290207Sjkim			if (!ul)
507290207Sjkim				break;
508290207Sjkim
509290207Sjkim			for (tmp = 0; *p;) {
510290207Sjkim				n = *p++;
511290207Sjkim				if (ul & (1 << (n - 1))) {
512290207Sjkim					PCHAR(tmp ? ',' : '<');
513290207Sjkim					for (; (n = *p) > ' '; ++p)
514290207Sjkim						PCHAR(n);
515290207Sjkim					tmp = 1;
516290207Sjkim				} else
517290207Sjkim					for (; *p > ' '; ++p)
518290207Sjkim						continue;
519290207Sjkim			}
520290207Sjkim			if (tmp)
521290207Sjkim				PCHAR('>');
522290207Sjkim			break;
523290207Sjkim		case 'c':
524290207Sjkim			PCHAR(va_arg(ap, int));
525299481Sjkim			break;
526299481Sjkim		case 'D':
527299481Sjkim			up = va_arg(ap, u_char *);
528299481Sjkim			p = va_arg(ap, char *);
529299481Sjkim			if (!width)
530299481Sjkim				width = 16;
531299481Sjkim			while(width--) {
532299481Sjkim				PCHAR(hex2ascii(*up >> 4));
533299481Sjkim				PCHAR(hex2ascii(*up & 0x0f));
534299481Sjkim				up++;
535299481Sjkim				if (width)
536299481Sjkim					for (q=p;*q;q++)
537299481Sjkim						PCHAR(*q);
538299481Sjkim			}
539299481Sjkim			break;
540299481Sjkim		case 'd':
541299481Sjkim			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
542299481Sjkim			sign = 1;
543299481Sjkim			base = 10;
544299481Sjkim			goto number;
545299481Sjkim		case 'l':
546299481Sjkim			lflag = 1;
547299481Sjkim			goto reswitch;
548299481Sjkim		case 'n':
549299481Sjkim			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
550299481Sjkim			base = radix;
551299481Sjkim			goto number;
552299481Sjkim		case 'o':
553299481Sjkim			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
554299481Sjkim			base = 8;
555299481Sjkim			goto number;
556299481Sjkim		case 'p':
557299481Sjkim			ul = (u_long)va_arg(ap, void *);
558299481Sjkim			base = 16;
559299481Sjkim			PCHAR('0');
560299481Sjkim			PCHAR('x');
561299481Sjkim			goto number;
562299481Sjkim		case 's':
563299481Sjkim			p = va_arg(ap, char *);
564299481Sjkim			if (p == NULL)
565299481Sjkim				p = "(null)";
566299481Sjkim			if (!dot)
567299481Sjkim				n = strlen (p);
568299481Sjkim			else
569299481Sjkim				for (n = 0; n < dwidth && p[n]; n++)
570299481Sjkim					continue;
571299481Sjkim
572299481Sjkim			width -= n;
573299481Sjkim
574299481Sjkim			if (!ladjust && width > 0)
575299481Sjkim				while (width--)
576299481Sjkim					PCHAR(padc);
577299481Sjkim			while (n--)
578299481Sjkim				PCHAR(*p++);
579299481Sjkim			if (ladjust && width > 0)
580299481Sjkim				while (width--)
581299481Sjkim					PCHAR(padc);
582299481Sjkim			break;
583299481Sjkim		case 'u':
584299481Sjkim			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
585299481Sjkim			base = 10;
586299481Sjkim			goto number;
587299481Sjkim		case 'x':
588299481Sjkim			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
589299481Sjkim			base = 16;
590299481Sjkimnumber:			if (sign && (long)ul < 0L) {
591299481Sjkim				neg = 1;
592299481Sjkim				ul = -(long)ul;
593299481Sjkim			}
594299481Sjkim			p = ksprintn(ul, base, &tmp);
595299481Sjkim			if (sharpflag && ul != 0) {
596299481Sjkim				if (base == 8)
597299481Sjkim					tmp++;
598299481Sjkim				else if (base == 16)
599299481Sjkim					tmp += 2;
600299481Sjkim			}
601299481Sjkim			if (neg)
602299481Sjkim				tmp++;
603299481Sjkim
604299481Sjkim			if (!ladjust && width && (width -= tmp) > 0)
605299481Sjkim				while (width--)
606299481Sjkim					PCHAR(padc);
607299481Sjkim			if (neg)
608299481Sjkim				PCHAR('-');
609299481Sjkim			if (sharpflag && ul != 0) {
610299481Sjkim				if (base == 8) {
611299481Sjkim					PCHAR('0');
612299481Sjkim				} else if (base == 16) {
613299481Sjkim					PCHAR('0');
614299481Sjkim					PCHAR('x');
615299481Sjkim				}
616299481Sjkim			}
617299481Sjkim
618299481Sjkim			while (*p)
619299481Sjkim				PCHAR(*p--);
620299481Sjkim
621299481Sjkim			if (ladjust && width && (width -= tmp) > 0)
622299481Sjkim				while (width--)
623299481Sjkim					PCHAR(padc);
624299481Sjkim
625299481Sjkim			break;
626299481Sjkim		default:
627299481Sjkim			PCHAR('%');
628299481Sjkim			if (lflag)
629299481Sjkim				PCHAR('l');
630299481Sjkim			PCHAR(ch);
631299481Sjkim			break;
632299481Sjkim		}
633299481Sjkim	}
634299481Sjkim#undef PCHAR
635299481Sjkim}
636299481Sjkim
637299481Sjkim/*
638299481Sjkim * Put character in log buffer.
639299481Sjkim */
640299481Sjkimstatic void
641299481Sjkimmsglogchar(int c, void *dummyarg)
642299481Sjkim{
643299481Sjkim	struct msgbuf *mbp;
644299481Sjkim
645299481Sjkim	if (c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
646299481Sjkim		mbp = msgbufp;
647299481Sjkim		if (mbp->msg_magic != MSG_MAGIC ||
648299481Sjkim		    mbp->msg_bufx >= MSG_BSIZE ||
649299481Sjkim		    mbp->msg_bufr >= MSG_BSIZE) {
650299481Sjkim			bzero(mbp, sizeof(struct msgbuf));
651299481Sjkim			mbp->msg_magic = MSG_MAGIC;
652299481Sjkim		}
653299481Sjkim		mbp->msg_bufc[mbp->msg_bufx++] = c;
654299481Sjkim		if (mbp->msg_bufx >= MSG_BSIZE)
655299481Sjkim			mbp->msg_bufx = 0;
656299481Sjkim		/* If the buffer is full, keep the most recent data. */
657299481Sjkim		if (mbp->msg_bufr == mbp->msg_bufx) {
658299481Sjkim			if (++mbp->msg_bufr >= MSG_BSIZE)
659299481Sjkim				mbp->msg_bufr = 0;
660299481Sjkim		}
661299481Sjkim	}
662299481Sjkim}
663299481Sjkim