xref: /csrg-svn/sys/kern/subr_prf.c (revision 52911)
149062Sbostic /*-
249062Sbostic  * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
349062Sbostic  * All rights reserved.
423381Smckusick  *
549062Sbostic  * %sccs.include.redist.c%
649062Sbostic  *
7*52911Storek  *	@(#)subr_prf.c	7.38 (Berkeley) 03/11/92
823381Smckusick  */
931Sbill 
1051768Smarc #include <sys/param.h>
1151768Smarc #include <sys/systm.h>
1251768Smarc #include <sys/buf.h>
1351768Smarc #include <sys/conf.h>
1451768Smarc #include <sys/reboot.h>
1551768Smarc #include <sys/msgbuf.h>
1651768Smarc #include <sys/proc.h>
1751768Smarc #include <sys/ioctl.h>
1851768Smarc #include <sys/vnode.h>
1951768Smarc #include <sys/file.h>
2051768Smarc #include <sys/tty.h>
2151768Smarc #include <sys/tprintf.h>
2251768Smarc #include <sys/syslog.h>
2351768Smarc #include <sys/malloc.h>
2431Sbill 
2549062Sbostic /*
2649062Sbostic  * Note that stdarg.h and the ANSI style va_start macro is used for both
2749062Sbostic  * ANSI and traditional C compilers.
2849062Sbostic  */
2949062Sbostic #include <machine/stdarg.h>
3049062Sbostic 
3135282Skarels #ifdef KADB
3237496Smckusick #include "machine/kdbparam.h"
3330625Skarels #endif
3430625Skarels 
3549062Sbostic #define TOCONS	0x01
3649062Sbostic #define TOTTY	0x02
3749062Sbostic #define TOLOG	0x04
3816724Sralph 
3930549Skarels struct	tty *constty;			/* pointer to console "window" tty */
4030549Skarels 
4149062Sbostic extern	cnputc();			/* standard console putc */
4249953Sbostic int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
4340808Smarc 
4451768Smarc void  logpri __P((int level));
4549908Sbostic static void  putchar __P((int ch, int flags, struct tty *tp));
4649908Sbostic static char *ksprintn __P((u_long num, int base, int *len));
4752392Smarc void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
4849062Sbostic 
4951768Smarc int consintr = 1;			/* Ok to handle console interrupts? */
5051768Smarc 
5131Sbill /*
5251768Smarc  * Variable panicstr contains argument to first call to panic; used as flag
5351768Smarc  * to indicate that the kernel has already called panic.
5431Sbill  */
5551768Smarc const char *panicstr;
5629946Skarels 
5749062Sbostic /*
5849062Sbostic  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
5949062Sbostic  * and then reboots.  If we are called twice, then we avoid trying to sync
6049062Sbostic  * the disks as this often leads to recursive panics.
6149062Sbostic  */
6252392Smarc #ifdef __GNUC__
6352406Smckusick volatile void boot(int flags);	/* boot() does not return */
6452392Smarc volatile			/* panic() does not return */
6552392Smarc #endif
6649062Sbostic void
6751768Smarc #ifdef __STDC__
6851768Smarc panic(const char *fmt, ...)
6951768Smarc #else
7052782Sralph panic(fmt, va_alist)
7151768Smarc 	char *fmt;
7251768Smarc #endif
7349062Sbostic {
7452392Smarc 	int bootopt;
7551768Smarc 	va_list ap;
7648426Skarels 
7751768Smarc 	bootopt = RB_AUTOBOOT | RB_DUMP;
7849062Sbostic 	if (panicstr)
7949062Sbostic 		bootopt |= RB_NOSYNC;
8049062Sbostic 	else
8151768Smarc 		panicstr = fmt;
8251768Smarc 
8351768Smarc 	va_start(ap, fmt);
8452392Smarc 	printf("panic: %r\n", fmt, ap);
8551768Smarc 	va_end(ap);
8651768Smarc 
8749062Sbostic #ifdef KGDB
8849062Sbostic 	kgdb_panic();
8949062Sbostic #endif
9049062Sbostic #ifdef KADB
9152782Sralph 	if (boothowto & RB_KDB)
9252782Sralph 		kdbpanic();
9349062Sbostic #endif
9449062Sbostic 	boot(bootopt);
9549062Sbostic }
9649062Sbostic 
9749062Sbostic /*
9849062Sbostic  * Warn that a system table is full.
9949062Sbostic  */
10049062Sbostic void
10149062Sbostic tablefull(tab)
10252406Smckusick 	const char *tab;
10331Sbill {
104285Sbill 
10549062Sbostic 	log(LOG_ERR, "%s: table is full\n", tab);
106285Sbill }
107285Sbill 
1082377Swnj /*
10939560Smarc  * Uprintf prints to the controlling terminal for the current process.
11049062Sbostic  * It may block if the tty queue is overfull.  No message is printed if
11149062Sbostic  * the queue does not clear in a reasonable time.
1122377Swnj  */
11349062Sbostic void
11449062Sbostic #ifdef __STDC__
11549062Sbostic uprintf(const char *fmt, ...)
11649062Sbostic #else
11751767Smarc uprintf(fmt, va_alist)
1182781Swnj 	char *fmt;
11949062Sbostic #endif
120285Sbill {
12147540Skarels 	register struct proc *p = curproc;
12249062Sbostic 	va_list ap;
123285Sbill 
12449953Sbostic 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
12549953Sbostic 		va_start(ap, fmt);
12649062Sbostic 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
12749953Sbostic 		va_end(ap);
12849953Sbostic 	}
129285Sbill }
130285Sbill 
13144386Smarc tpr_t
13248426Skarels tprintf_open(p)
13348426Skarels 	register struct proc *p;
13444386Smarc {
13549953Sbostic 
13644386Smarc 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
13744386Smarc 		SESSHOLD(p->p_session);
13848426Skarels 		return ((tpr_t) p->p_session);
13949062Sbostic 	}
14049062Sbostic 	return ((tpr_t) NULL);
14144386Smarc }
14244386Smarc 
14348426Skarels void
14444386Smarc tprintf_close(sess)
14544386Smarc 	tpr_t sess;
14644386Smarc {
14749953Sbostic 
14844386Smarc 	if (sess)
14948426Skarels 		SESSRELE((struct session *) sess);
15044386Smarc }
15144386Smarc 
15218364Skarels /*
15344386Smarc  * tprintf prints on the controlling terminal associated
15449062Sbostic  * with the given session.
15518364Skarels  */
15649062Sbostic void
15749062Sbostic #ifdef __STDC__
15849062Sbostic tprintf(tpr_t tpr, const char *fmt, ...)
15949062Sbostic #else
16051767Smarc tprintf(tpr, fmt, va_alist)
16148426Skarels 	tpr_t tpr;
16216724Sralph 	char *fmt;
16349062Sbostic #endif
16416724Sralph {
16548426Skarels 	register struct session *sess = (struct session *)tpr;
16648426Skarels 	struct tty *tp = NULL;
16744386Smarc 	int flags = TOLOG;
16849062Sbostic 	va_list ap;
16916724Sralph 
17025389Skarels 	logpri(LOG_INFO);
17148426Skarels 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
17244386Smarc 		flags |= TOTTY;
17348426Skarels 		tp = sess->s_ttyp;
17448426Skarels 	}
17549062Sbostic 	va_start(ap, fmt);
17649062Sbostic 	kprintf(fmt, flags, tp, ap);
17749062Sbostic 	va_end(ap);
17825389Skarels 	logwakeup();
17916724Sralph }
18016724Sralph 
18149062Sbostic /*
18249062Sbostic  * Ttyprintf displays a message on a tty; it should be used only by
18349062Sbostic  * the tty driver, or anything that knows the underlying tty will not
18449062Sbostic  * be revoke(2)'d away.  Other callers should use tprintf.
18549062Sbostic  */
18649062Sbostic void
18749062Sbostic #ifdef __STDC__
18849062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...)
18949062Sbostic #else
19051767Smarc ttyprintf(tp, fmt, va_alist)
19149062Sbostic 	struct tty *tp;
19249062Sbostic 	char *fmt;
19349062Sbostic #endif
19449062Sbostic {
19549062Sbostic 	va_list ap;
19649062Sbostic 
19749062Sbostic 	va_start(ap, fmt);
19849062Sbostic 	kprintf(fmt, TOTTY, tp, ap);
19949062Sbostic 	va_end(ap);
20049062Sbostic }
20149062Sbostic 
20248426Skarels extern	int log_open;
20344386Smarc 
20416724Sralph /*
20549062Sbostic  * Log writes to the log buffer, and guarantees not to sleep (so can be
20649062Sbostic  * called by interrupt routines).  If there is no process reading the
20749062Sbostic  * log yet, it writes to the console also.
20816724Sralph  */
20949062Sbostic void
21049062Sbostic #ifdef __STDC__
21149062Sbostic log(int level, const char *fmt, ...)
21249062Sbostic #else
21351767Smarc log(level, fmt, va_alist)
21449062Sbostic 	int level;
21516724Sralph 	char *fmt;
21649062Sbostic #endif
21716724Sralph {
21850268Sbostic 	register int s;
21949062Sbostic 	va_list ap;
22016724Sralph 
22150268Sbostic 	s = splhigh();
22225389Skarels 	logpri(level);
22349062Sbostic 	va_start(ap, fmt);
22449062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
22516724Sralph 	splx(s);
22649953Sbostic 	va_end(ap);
22749953Sbostic 	if (!log_open) {
22849953Sbostic 		va_start(ap, fmt);
22949062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
23049953Sbostic 		va_end(ap);
23149953Sbostic 	}
23216724Sralph 	logwakeup();
23316724Sralph }
23416724Sralph 
23551768Smarc void
23625389Skarels logpri(level)
23725389Skarels 	int level;
23825389Skarels {
23949908Sbostic 	register int ch;
24049908Sbostic 	register char *p;
24125389Skarels 
24249062Sbostic 	putchar('<', TOLOG, NULL);
24349908Sbostic 	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
24449908Sbostic 		putchar(ch, TOLOG, NULL);
24549062Sbostic 	putchar('>', TOLOG, NULL);
24625389Skarels }
24725389Skarels 
24849062Sbostic void
24949062Sbostic #ifdef __STDC__
25049062Sbostic addlog(const char *fmt, ...)
25149062Sbostic #else
25251767Smarc addlog(fmt, va_alist)
25333479Skarels 	char *fmt;
25449062Sbostic #endif
25533479Skarels {
25650268Sbostic 	register int s;
25749062Sbostic 	va_list ap;
25833479Skarels 
25950268Sbostic 	s = splhigh();
26049062Sbostic 	va_start(ap, fmt);
26149062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
26233479Skarels 	splx(s);
26349953Sbostic 	va_end(ap);
26449953Sbostic 	if (!log_open) {
26549953Sbostic 		va_start(ap, fmt);
26649062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
26749953Sbostic 		va_end(ap);
26849953Sbostic 	}
26933479Skarels 	logwakeup();
27033479Skarels }
27133479Skarels 
27249062Sbostic void
27349062Sbostic #ifdef __STDC__
27449062Sbostic printf(const char *fmt, ...)
27549062Sbostic #else
27651767Smarc printf(fmt, va_alist)
27749062Sbostic 	char *fmt;
27829946Skarels #endif
27949062Sbostic {
28049953Sbostic 	va_list ap;
28149062Sbostic 	register int savintr;
2822678Swnj 
28349062Sbostic 	savintr = consintr;		/* disable interrupts */
28449062Sbostic 	consintr = 0;
28549062Sbostic 	va_start(ap, fmt);
28649062Sbostic 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
28749062Sbostic 	va_end(ap);
28849062Sbostic 	if (!panicstr)
28949062Sbostic 		logwakeup();
29049062Sbostic 	consintr = savintr;		/* reenable interrupts */
29131Sbill }
29231Sbill 
2932781Swnj /*
29449062Sbostic  * Scaled down version of printf(3).
29549062Sbostic  *
29649062Sbostic  * Two additional formats:
29749062Sbostic  *
29849062Sbostic  * The format %b is supported to decode error registers.
29949062Sbostic  * Its usage is:
30049062Sbostic  *
30152392Smarc  *	printf("reg=%b\n", regval, "<base><arg>*");
30249062Sbostic  *
30349062Sbostic  * where <base> is the output base expressed as a control character, e.g.
30449062Sbostic  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
30549062Sbostic  * the first of which gives the bit number to be inspected (origin 1), and
30649062Sbostic  * the next characters (up to a control character, i.e. a character <= 32),
30749062Sbostic  * give the name of the register.  Thus:
30849062Sbostic  *
30951768Smarc  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
31049062Sbostic  *
31149062Sbostic  * would produce output:
31249062Sbostic  *
31349062Sbostic  *	reg=3<BITTWO,BITONE>
31449062Sbostic  *
31551768Smarc  * The format %r passes an additional format string and argument list
31651768Smarc  * recursively.  Its usage is:
31749062Sbostic  *
31851768Smarc  * fn(char *fmt, ...)
31949953Sbostic  * {
32049953Sbostic  *	va_list ap;
32149953Sbostic  *	va_start(ap, fmt);
32252392Smarc  *	printf("prefix: %r: suffix\n", fmt, ap);
32349953Sbostic  *	va_end(ap);
32451768Smarc  * }
32549908Sbostic  *
32649908Sbostic  * Space or zero padding and a field width are supported for the numeric
32749908Sbostic  * formats only.
3282781Swnj  */
32949909Sbostic void
33052392Smarc kprintf(fmt, flags, tp, ap)
33149094Sbostic 	register const char *fmt;
33249062Sbostic 	int flags;
33349094Sbostic 	struct tty *tp;
33449062Sbostic 	va_list ap;
33531Sbill {
33652877Skarels 	register char *p, *q;
33749062Sbostic 	register int ch, n;
33849908Sbostic 	u_long ul;
33949908Sbostic 	int base, lflag, tmp, width;
34049908Sbostic 	char padc;
34131Sbill 
34249062Sbostic 	for (;;) {
34349908Sbostic 		padc = ' ';
34449908Sbostic 		width = 0;
34549919Skarels 		while ((ch = *(u_char *)fmt++) != '%') {
34649062Sbostic 			if (ch == '\0')
34749062Sbostic 				return;
34849094Sbostic 			putchar(ch, flags, tp);
34929946Skarels 		}
35049062Sbostic 		lflag = 0;
35149919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
35249908Sbostic 		case '0':
35349908Sbostic 			padc = '0';
35449908Sbostic 			goto reswitch;
35549908Sbostic 		case '1': case '2': case '3': case '4':
35649908Sbostic 		case '5': case '6': case '7': case '8': case '9':
35749908Sbostic 			for (width = 0;; ++fmt) {
35849908Sbostic 				width = width * 10 + ch - '0';
35949908Sbostic 				ch = *fmt;
36049908Sbostic 				if (ch < '0' || ch > '9')
36149908Sbostic 					break;
36249908Sbostic 			}
36349908Sbostic 			goto reswitch;
36449062Sbostic 		case 'l':
36549062Sbostic 			lflag = 1;
36649062Sbostic 			goto reswitch;
36749062Sbostic 		case 'b':
36849062Sbostic 			ul = va_arg(ap, int);
36949062Sbostic 			p = va_arg(ap, char *);
37052877Skarels 			for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
37149908Sbostic 				putchar(ch, flags, tp);
37231Sbill 
37349062Sbostic 			if (!ul)
37449062Sbostic 				break;
3752377Swnj 
37649908Sbostic 			for (tmp = 0; n = *p++;) {
37749062Sbostic 				if (ul & (1 << (n - 1))) {
37849908Sbostic 					putchar(tmp ? ',' : '<', flags, tp);
37949062Sbostic 					for (; (n = *p) > ' '; ++p)
38049094Sbostic 						putchar(n, flags, tp);
38149908Sbostic 					tmp = 1;
38249062Sbostic 				} else
383*52911Storek 					for (; *p > ' '; ++p)
384*52911Storek 						continue;
38549062Sbostic 			}
38649908Sbostic 			if (tmp)
38749094Sbostic 				putchar('>', flags, tp);
38849062Sbostic 			break;
38949062Sbostic 		case 'c':
39049094Sbostic 			putchar(va_arg(ap, int), flags, tp);
39149062Sbostic 			break;
39249062Sbostic 		case 'r':
39349062Sbostic 			p = va_arg(ap, char *);
39449094Sbostic 			kprintf(p, flags, tp, va_arg(ap, va_list));
39549062Sbostic 			break;
39649062Sbostic 		case 's':
39749062Sbostic 			p = va_arg(ap, char *);
39849062Sbostic 			while (ch = *p++)
39949094Sbostic 				putchar(ch, flags, tp);
40049062Sbostic 			break;
40149062Sbostic 		case 'd':
40249908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
40349062Sbostic 			if ((long)ul < 0) {
40449094Sbostic 				putchar('-', flags, tp);
40549062Sbostic 				ul = -(long)ul;
40649062Sbostic 			}
40749908Sbostic 			base = 10;
40849908Sbostic 			goto number;
40949062Sbostic 		case 'o':
41049908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41149908Sbostic 			base = 8;
41249953Sbostic 			goto number;
41349062Sbostic 		case 'u':
41449908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41549908Sbostic 			base = 10;
41649908Sbostic 			goto number;
41749062Sbostic 		case 'x':
41849908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41949908Sbostic 			base = 16;
42049908Sbostic number:			p = ksprintn(ul, base, &tmp);
42149908Sbostic 			if (width && (width -= tmp) > 0)
42249908Sbostic 				while (width--)
42349908Sbostic 					putchar(padc, flags, tp);
42449908Sbostic 			while (ch = *p--)
42549908Sbostic 				putchar(ch, flags, tp);
42649062Sbostic 			break;
42749062Sbostic 		default:
42849094Sbostic 			putchar('%', flags, tp);
42949062Sbostic 			if (lflag)
43049094Sbostic 				putchar('l', flags, tp);
43149908Sbostic 			/* FALLTHROUGH */
43249908Sbostic 		case '%':
43349094Sbostic 			putchar(ch, flags, tp);
43449062Sbostic 		}
43530625Skarels 	}
43631Sbill }
43731Sbill 
4382941Swnj /*
43949062Sbostic  * Print a character on console or users terminal.  If destination is
44049062Sbostic  * the console then the last MSGBUFS characters are saved in msgbuf for
44149062Sbostic  * inspection later.
442285Sbill  */
44349062Sbostic static void
44449094Sbostic putchar(c, flags, tp)
4452377Swnj 	register int c;
44649062Sbostic 	int flags;
44749094Sbostic 	struct tty *tp;
448285Sbill {
44933479Skarels 	extern int msgbufmapped;
45050268Sbostic 	register struct msgbuf *mbp;
451285Sbill 
45230549Skarels 	if (panicstr)
45349062Sbostic 		constty = NULL;
45449094Sbostic 	if ((flags & TOCONS) && tp == NULL && constty) {
45549094Sbostic 		tp = constty;
45630549Skarels 		flags |= TOTTY;
45730549Skarels 	}
45849094Sbostic 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
45949094Sbostic 	    (flags & TOCONS) && tp == constty)
46049062Sbostic 		constty = NULL;
46149062Sbostic 	if ((flags & TOLOG) &&
46249062Sbostic 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
46350268Sbostic 		mbp = msgbufp;
46445733Smckusick 		if (mbp->msg_magic != MSG_MAGIC) {
46549953Sbostic 			bzero((caddr_t)mbp, sizeof(*mbp));
46645733Smckusick 			mbp->msg_magic = MSG_MAGIC;
4672172Swnj 		}
46845733Smckusick 		mbp->msg_bufc[mbp->msg_bufx++] = c;
46945733Smckusick 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
47045733Smckusick 			mbp->msg_bufx = 0;
471285Sbill 	}
47249062Sbostic 	if ((flags & TOCONS) && constty == NULL && c != '\0')
47330549Skarels 		(*v_putc)(c);
474285Sbill }
47549908Sbostic 
47649908Sbostic /*
47749908Sbostic  * Scaled down version of sprintf(3).
47849908Sbostic  */
47949908Sbostic #ifdef __STDC__
48049919Skarels sprintf(char *buf, const char *cfmt, ...)
48149908Sbostic #else
48251767Smarc sprintf(buf, cfmt, va_alist)
48349919Skarels 	char *buf, *cfmt;
48449908Sbostic #endif
48549908Sbostic {
48649919Skarels 	register const char *fmt = cfmt;
48749908Sbostic 	register char *p, *bp;
48849908Sbostic 	register int ch, base;
48949908Sbostic 	u_long ul;
49049908Sbostic 	int lflag;
49149908Sbostic 	va_list ap;
49249908Sbostic 
49349919Skarels 	va_start(ap, cfmt);
49449919Skarels 	for (bp = buf; ; ) {
49549919Skarels 		while ((ch = *(u_char *)fmt++) != '%')
49649908Sbostic 			if ((*bp++ = ch) == '\0')
49749919Skarels 				return ((bp - buf) - 1);
49849919Skarels 
49949908Sbostic 		lflag = 0;
50049919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
50149908Sbostic 		case 'l':
50249908Sbostic 			lflag = 1;
50349908Sbostic 			goto reswitch;
50449908Sbostic 		case 'c':
50549908Sbostic 			*bp++ = va_arg(ap, int);
50649908Sbostic 			break;
50749908Sbostic 		case 's':
50849908Sbostic 			p = va_arg(ap, char *);
50949919Skarels 			while (*bp++ = *p++)
51052392Smarc 				continue;
51149908Sbostic 			--bp;
51249908Sbostic 			break;
51349908Sbostic 		case 'd':
51449908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
51549908Sbostic 			if ((long)ul < 0) {
51649908Sbostic 				*bp++ = '-';
51749908Sbostic 				ul = -(long)ul;
51849908Sbostic 			}
51949908Sbostic 			base = 10;
52049908Sbostic 			goto number;
52149908Sbostic 			break;
52249908Sbostic 		case 'o':
52349908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
52449908Sbostic 			base = 8;
52549908Sbostic 			goto number;
52649908Sbostic 			break;
52749908Sbostic 		case 'u':
52849908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
52949908Sbostic 			base = 10;
53049908Sbostic 			goto number;
53149908Sbostic 			break;
53249908Sbostic 		case 'x':
53349908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
53449908Sbostic 			base = 16;
53549908Sbostic number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
53649908Sbostic 				*bp++ = ch;
53749908Sbostic 			break;
53849908Sbostic 		default:
53949908Sbostic 			*bp++ = '%';
54049908Sbostic 			if (lflag)
54149908Sbostic 				*bp++ = 'l';
54249908Sbostic 			/* FALLTHROUGH */
54349908Sbostic 		case '%':
54449908Sbostic 			*bp++ = ch;
54549908Sbostic 		}
54649908Sbostic 	}
54749908Sbostic 	va_end(ap);
54849908Sbostic }
54949908Sbostic 
55049908Sbostic /*
55149908Sbostic  * Put a number (base <= 16) in a buffer in reverse order; return an
55249908Sbostic  * optional length and a pointer to the NULL terminated (preceded?)
55349908Sbostic  * buffer.
55449908Sbostic  */
55549908Sbostic static char *
55649908Sbostic ksprintn(ul, base, lenp)
55749908Sbostic 	register u_long ul;
55849908Sbostic 	register int base, *lenp;
55949908Sbostic {					/* A long in base 8, plus NULL. */
56049908Sbostic 	static char buf[sizeof(long) * NBBY / 3 + 2];
56149908Sbostic 	register char *p;
56249908Sbostic 
56349908Sbostic 	p = buf;
56449908Sbostic 	do {
56549908Sbostic 		*++p = "0123456789abcdef"[ul % base];
56649908Sbostic 	} while (ul /= base);
56749908Sbostic 	if (lenp)
56849908Sbostic 		*lenp = p - buf;
56949919Skarels 	return (p);
57049908Sbostic }
571