xref: /csrg-svn/sys/kern/subr_prf.c (revision 49953)
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*49953Sbostic  *	@(#)subr_prf.c	7.29 (Berkeley) 05/30/91
823381Smckusick  */
931Sbill 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1217094Sbloom #include "buf.h"
1317094Sbloom #include "conf.h"
1417094Sbloom #include "reboot.h"
1517094Sbloom #include "msgbuf.h"
1617094Sbloom #include "proc.h"
1717577Sbloom #include "ioctl.h"
1839560Smarc #include "vnode.h"
1939560Smarc #include "file.h"
2017094Sbloom #include "tty.h"
2144386Smarc #include "tprintf.h"
2218364Skarels #include "syslog.h"
2344386Smarc #include "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 
4140808Smarc #ifdef KADB
4240808Smarc extern	cngetc();			/* standard console getc */
4349062Sbostic int	(*v_getc)() = cngetc;		/* "" getc from virtual console */
4440808Smarc extern	cnpoll();
4540808Smarc int	(*v_poll)() = cnpoll;		/* kdb hook to enable input polling */
4640808Smarc #endif
4749062Sbostic extern	cnputc();			/* standard console putc */
48*49953Sbostic int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
4940808Smarc 
5049908Sbostic static void  logpri __P((int level));
5149908Sbostic static void  putchar __P((int ch, int flags, struct tty *tp));
5249908Sbostic static char *ksprintn __P((u_long num, int base, int *len));
5349909Sbostic void  kprintf __P((const char *fmt, int flags, struct tty *tp, va_list));
5449062Sbostic 
5531Sbill /*
5649062Sbostic  * Variable panicstr contains argument to first call to panic; used
5749062Sbostic  * as flag to indicate that the kernel has already called panic.
5831Sbill  */
5949062Sbostic char	*panicstr;
6029946Skarels 
6149062Sbostic /*
6249062Sbostic  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
6349062Sbostic  * and then reboots.  If we are called twice, then we avoid trying to sync
6449062Sbostic  * the disks as this often leads to recursive panics.
6549062Sbostic  */
6649062Sbostic void
6749062Sbostic panic(msg)
6849062Sbostic 	char *msg;
6949062Sbostic {
7049062Sbostic 	int bootopt = RB_AUTOBOOT | RB_DUMP;
7148426Skarels 
7249062Sbostic 	if (panicstr)
7349062Sbostic 		bootopt |= RB_NOSYNC;
7449062Sbostic 	else
7549062Sbostic 		panicstr = msg;
7649062Sbostic 	printf("panic: %s\n", msg);
7749062Sbostic #ifdef KGDB
7849062Sbostic 	kgdb_panic();
7949062Sbostic #endif
8049062Sbostic #ifdef KADB
8149062Sbostic 	if (boothowto & RB_KDB) {
82*49953Sbostic 		int s = splnet();	/* below kdb pri */
8349062Sbostic 		setsoftkdb();
8449062Sbostic 		splx(s);
8549062Sbostic 	}
8649062Sbostic #endif
8749062Sbostic 	boot(bootopt);
8849062Sbostic }
8949062Sbostic 
9049062Sbostic /*
9149062Sbostic  * Warn that a system table is full.
9249062Sbostic  */
9349062Sbostic void
9449062Sbostic tablefull(tab)
9549062Sbostic 	char *tab;
9631Sbill {
97285Sbill 
9849062Sbostic 	log(LOG_ERR, "%s: table is full\n", tab);
99285Sbill }
100285Sbill 
1012377Swnj /*
10239560Smarc  * Uprintf prints to the controlling terminal for the current process.
10349062Sbostic  * It may block if the tty queue is overfull.  No message is printed if
10449062Sbostic  * the queue does not clear in a reasonable time.
1052377Swnj  */
10649062Sbostic void
10749062Sbostic #ifdef __STDC__
10849062Sbostic uprintf(const char *fmt, ...)
10949062Sbostic #else
11049062Sbostic uprintf(fmt /*, va_alist */)
1112781Swnj 	char *fmt;
11249062Sbostic #endif
113285Sbill {
11447540Skarels 	register struct proc *p = curproc;
11549062Sbostic 	va_list ap;
116285Sbill 
117*49953Sbostic 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
118*49953Sbostic 		va_start(ap, fmt);
11949062Sbostic 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
120*49953Sbostic 		va_end(ap);
121*49953Sbostic 	}
122285Sbill }
123285Sbill 
12444386Smarc tpr_t
12548426Skarels tprintf_open(p)
12648426Skarels 	register struct proc *p;
12744386Smarc {
128*49953Sbostic 
12944386Smarc 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
13044386Smarc 		SESSHOLD(p->p_session);
13148426Skarels 		return ((tpr_t) p->p_session);
13249062Sbostic 	}
13349062Sbostic 	return ((tpr_t) NULL);
13444386Smarc }
13544386Smarc 
13648426Skarels void
13744386Smarc tprintf_close(sess)
13844386Smarc 	tpr_t sess;
13944386Smarc {
140*49953Sbostic 
14144386Smarc 	if (sess)
14248426Skarels 		SESSRELE((struct session *) sess);
14344386Smarc }
14444386Smarc 
14518364Skarels /*
14644386Smarc  * tprintf prints on the controlling terminal associated
14749062Sbostic  * with the given session.
14818364Skarels  */
14949062Sbostic void
15049062Sbostic #ifdef __STDC__
15149062Sbostic tprintf(tpr_t tpr, const char *fmt, ...)
15249062Sbostic #else
15349062Sbostic tprintf(tpr, fmt /*, va_alist */)
15448426Skarels 	tpr_t tpr;
15516724Sralph 	char *fmt;
15649062Sbostic #endif
15716724Sralph {
15848426Skarels 	register struct session *sess = (struct session *)tpr;
15948426Skarels 	struct tty *tp = NULL;
16044386Smarc 	int flags = TOLOG;
16149062Sbostic 	va_list ap;
16216724Sralph 
16325389Skarels 	logpri(LOG_INFO);
16448426Skarels 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
16544386Smarc 		flags |= TOTTY;
16648426Skarels 		tp = sess->s_ttyp;
16748426Skarels 	}
16849062Sbostic 	va_start(ap, fmt);
16949062Sbostic 	kprintf(fmt, flags, tp, ap);
17049062Sbostic 	va_end(ap);
17125389Skarels 	logwakeup();
17216724Sralph }
17316724Sralph 
17449062Sbostic /*
17549062Sbostic  * Ttyprintf displays a message on a tty; it should be used only by
17649062Sbostic  * the tty driver, or anything that knows the underlying tty will not
17749062Sbostic  * be revoke(2)'d away.  Other callers should use tprintf.
17849062Sbostic  */
17949062Sbostic void
18049062Sbostic #ifdef __STDC__
18149062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...)
18249062Sbostic #else
18349062Sbostic ttyprintf(tp, fmt /*, va_alist */)
18449062Sbostic 	struct tty *tp;
18549062Sbostic 	char *fmt;
18649062Sbostic #endif
18749062Sbostic {
18849062Sbostic 	va_list ap;
18949062Sbostic 
19049062Sbostic 	va_start(ap, fmt);
19149062Sbostic 	kprintf(fmt, TOTTY, tp, ap);
19249062Sbostic 	va_end(ap);
19349062Sbostic }
19449062Sbostic 
19548426Skarels extern	int log_open;
19644386Smarc 
19716724Sralph /*
19849062Sbostic  * Log writes to the log buffer, and guarantees not to sleep (so can be
19949062Sbostic  * called by interrupt routines).  If there is no process reading the
20049062Sbostic  * log yet, it writes to the console also.
20116724Sralph  */
20249062Sbostic void
20349062Sbostic #ifdef __STDC__
20449062Sbostic log(int level, const char *fmt, ...)
20549062Sbostic #else
20649062Sbostic log(level, fmt /*, va_alist */)
20749062Sbostic 	int level;
20816724Sralph 	char *fmt;
20949062Sbostic #endif
21016724Sralph {
211*49953Sbostic 	register int s = splhigh();
21249062Sbostic 	va_list ap;
21316724Sralph 
21425389Skarels 	logpri(level);
21549062Sbostic 	va_start(ap, fmt);
21649062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
21716724Sralph 	splx(s);
218*49953Sbostic 	va_end(ap);
219*49953Sbostic 	if (!log_open) {
220*49953Sbostic 		va_start(ap, fmt);
22149062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
222*49953Sbostic 		va_end(ap);
223*49953Sbostic 	}
22416724Sralph 	logwakeup();
22516724Sralph }
22616724Sralph 
22749062Sbostic static void
22825389Skarels logpri(level)
22925389Skarels 	int level;
23025389Skarels {
23149908Sbostic 	register int ch;
23249908Sbostic 	register char *p;
23325389Skarels 
23449062Sbostic 	putchar('<', TOLOG, NULL);
23549908Sbostic 	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
23649908Sbostic 		putchar(ch, TOLOG, NULL);
23749062Sbostic 	putchar('>', TOLOG, NULL);
23825389Skarels }
23925389Skarels 
24049062Sbostic void
24149062Sbostic #ifdef __STDC__
24249062Sbostic addlog(const char *fmt, ...)
24349062Sbostic #else
24449062Sbostic addlog(fmt /*, va_alist */)
24533479Skarels 	char *fmt;
24649062Sbostic #endif
24733479Skarels {
248*49953Sbostic 	register int s = splhigh();
24949062Sbostic 	va_list ap;
25033479Skarels 
25149062Sbostic 	va_start(ap, fmt);
25249062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
25333479Skarels 	splx(s);
254*49953Sbostic 	va_end(ap);
255*49953Sbostic 	if (!log_open) {
256*49953Sbostic 		va_start(ap, fmt);
25749062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
258*49953Sbostic 		va_end(ap);
259*49953Sbostic 	}
26033479Skarels 	logwakeup();
26133479Skarels }
26233479Skarels 
263*49953Sbostic #if defined(tahoe)
26449062Sbostic int	consintr = 1;			/* ok to handle console interrupts? */
265*49953Sbostic #endif
26631Sbill 
26749062Sbostic void
26849062Sbostic #ifdef __STDC__
26949062Sbostic printf(const char *fmt, ...)
27049062Sbostic #else
27149062Sbostic printf(fmt /*, va_alist */)
27249062Sbostic 	char *fmt;
27329946Skarels #endif
27449062Sbostic {
275*49953Sbostic 	va_list ap;
276*49953Sbostic #ifdef tahoe
27749062Sbostic 	register int savintr;
2782678Swnj 
27949062Sbostic 	savintr = consintr;		/* disable interrupts */
28049062Sbostic 	consintr = 0;
281*49953Sbostic #endif
28249062Sbostic 	va_start(ap, fmt);
28349062Sbostic 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
28449062Sbostic 	va_end(ap);
28549062Sbostic 	if (!panicstr)
28649062Sbostic 		logwakeup();
287*49953Sbostic #ifdef tahoe
28849062Sbostic 	consintr = savintr;		/* reenable interrupts */
289*49953Sbostic #endif
29031Sbill }
29131Sbill 
2922781Swnj /*
29349062Sbostic  * Scaled down version of printf(3).
29449062Sbostic  *
29549062Sbostic  * Two additional formats:
29649062Sbostic  *
29749062Sbostic  * The format %b is supported to decode error registers.
29849062Sbostic  * Its usage is:
29949062Sbostic  *
30049908Sbostic  *	printf("reg=%b\n", regval, "<base><arg>*");
30149062Sbostic  *
30249062Sbostic  * where <base> is the output base expressed as a control character, e.g.
30349062Sbostic  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
30449062Sbostic  * the first of which gives the bit number to be inspected (origin 1), and
30549062Sbostic  * the next characters (up to a control character, i.e. a character <= 32),
30649062Sbostic  * give the name of the register.  Thus:
30749062Sbostic  *
30849908Sbostic  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
30949062Sbostic  *
31049062Sbostic  * would produce output:
31149062Sbostic  *
31249062Sbostic  *	reg=3<BITTWO,BITONE>
31349062Sbostic  *
31449062Sbostic  * The format %r is supposed to pass an additional format string and argument
31549062Sbostic  * list recursively.
31649062Sbostic  * Its usage is:
31749062Sbostic  *
318*49953Sbostic  * fn(otherstuff, char *fmt, ...)
319*49953Sbostic  * {
320*49953Sbostic  *	va_list ap;
321*49953Sbostic  *	va_start(ap, fmt);
32249908Sbostic  *	printf("prefix: %r, other stuff\n", fmt, ap);
323*49953Sbostic  *	va_end(ap);
32449908Sbostic  *
32549908Sbostic  * Space or zero padding and a field width are supported for the numeric
32649908Sbostic  * formats only.
3272781Swnj  */
32849909Sbostic void
32949094Sbostic kprintf(fmt, flags, tp, ap)
33049094Sbostic 	register const char *fmt;
33149062Sbostic 	int flags;
33249094Sbostic 	struct tty *tp;
33349062Sbostic 	va_list ap;
33431Sbill {
33549062Sbostic 	register char *p;
33649062Sbostic 	register int ch, n;
33749908Sbostic 	u_long ul;
33849908Sbostic 	int base, lflag, tmp, width;
33949908Sbostic 	char padc;
34031Sbill 
34149062Sbostic 	for (;;) {
34249908Sbostic 		padc = ' ';
34349908Sbostic 		width = 0;
34449919Skarels 		while ((ch = *(u_char *)fmt++) != '%') {
34549062Sbostic 			if (ch == '\0')
34649062Sbostic 				return;
34749094Sbostic 			putchar(ch, flags, tp);
34829946Skarels 		}
34949062Sbostic 		lflag = 0;
35049919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
35149908Sbostic 		case '0':
35249908Sbostic 			padc = '0';
35349908Sbostic 			goto reswitch;
35449908Sbostic 		case '1': case '2': case '3': case '4':
35549908Sbostic 		case '5': case '6': case '7': case '8': case '9':
35649908Sbostic 			for (width = 0;; ++fmt) {
35749908Sbostic 				width = width * 10 + ch - '0';
35849908Sbostic 				ch = *fmt;
35949908Sbostic 				if (ch < '0' || ch > '9')
36049908Sbostic 					break;
36149908Sbostic 			}
36249908Sbostic 			goto reswitch;
36349062Sbostic 		case 'l':
36449062Sbostic 			lflag = 1;
36549062Sbostic 			goto reswitch;
36649062Sbostic 		case 'b':
36749062Sbostic 			ul = va_arg(ap, int);
36849062Sbostic 			p = va_arg(ap, char *);
36949908Sbostic 			for (p = ksprintn(ul, *p++, NULL); ch = *p--;)
37049908Sbostic 				putchar(ch, flags, tp);
37131Sbill 
37249062Sbostic 			if (!ul)
37349062Sbostic 				break;
3742377Swnj 
37549908Sbostic 			for (tmp = 0; n = *p++;) {
37649062Sbostic 				if (ul & (1 << (n - 1))) {
37749908Sbostic 					putchar(tmp ? ',' : '<', flags, tp);
37849062Sbostic 					for (; (n = *p) > ' '; ++p)
37949094Sbostic 						putchar(n, flags, tp);
38049908Sbostic 					tmp = 1;
38149062Sbostic 				} else
38249062Sbostic 					for (; *p > ' '; ++p);
38349062Sbostic 			}
38449908Sbostic 			if (tmp)
38549094Sbostic 				putchar('>', flags, tp);
38649062Sbostic 			break;
38749062Sbostic 		case 'c':
38849094Sbostic 			putchar(va_arg(ap, int), flags, tp);
38949062Sbostic 			break;
39049062Sbostic 		case 'r':
39149062Sbostic 			p = va_arg(ap, char *);
39249094Sbostic 			kprintf(p, flags, tp, va_arg(ap, va_list));
39349062Sbostic 			break;
39449062Sbostic 		case 's':
39549062Sbostic 			p = va_arg(ap, char *);
39649062Sbostic 			while (ch = *p++)
39749094Sbostic 				putchar(ch, flags, tp);
39849062Sbostic 			break;
39949062Sbostic 		case 'd':
40049908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
40149062Sbostic 			if ((long)ul < 0) {
40249094Sbostic 				putchar('-', flags, tp);
40349062Sbostic 				ul = -(long)ul;
40449062Sbostic 			}
40549908Sbostic 			base = 10;
40649908Sbostic 			goto number;
40749062Sbostic 		case 'o':
40849908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
40949908Sbostic 			base = 8;
410*49953Sbostic 			goto number;
41149062Sbostic 		case 'u':
41249908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41349908Sbostic 			base = 10;
41449908Sbostic 			goto number;
41549062Sbostic 		case 'x':
41649908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41749908Sbostic 			base = 16;
41849908Sbostic number:			p = ksprintn(ul, base, &tmp);
41949908Sbostic 			if (width && (width -= tmp) > 0)
42049908Sbostic 				while (width--)
42149908Sbostic 					putchar(padc, flags, tp);
42249908Sbostic 			while (ch = *p--)
42349908Sbostic 				putchar(ch, flags, tp);
42449062Sbostic 			break;
42549062Sbostic 		default:
42649094Sbostic 			putchar('%', flags, tp);
42749062Sbostic 			if (lflag)
42849094Sbostic 				putchar('l', flags, tp);
42949908Sbostic 			/* FALLTHROUGH */
43049908Sbostic 		case '%':
43149094Sbostic 			putchar(ch, flags, tp);
43249062Sbostic 		}
43330625Skarels 	}
43431Sbill }
43531Sbill 
4362941Swnj /*
43749062Sbostic  * Print a character on console or users terminal.  If destination is
43849062Sbostic  * the console then the last MSGBUFS characters are saved in msgbuf for
43949062Sbostic  * inspection later.
440285Sbill  */
44149062Sbostic static void
44249094Sbostic putchar(c, flags, tp)
4432377Swnj 	register int c;
44449062Sbostic 	int flags;
44549094Sbostic 	struct tty *tp;
446285Sbill {
44733479Skarels 	extern int msgbufmapped;
448*49953Sbostic 	register struct msgbuf *mbp = msgbufp;
449285Sbill 
45030549Skarels 	if (panicstr)
45149062Sbostic 		constty = NULL;
45249094Sbostic 	if ((flags & TOCONS) && tp == NULL && constty) {
45349094Sbostic 		tp = constty;
45430549Skarels 		flags |= TOTTY;
45530549Skarels 	}
45649094Sbostic 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
45749094Sbostic 	    (flags & TOCONS) && tp == constty)
45849062Sbostic 		constty = NULL;
45949062Sbostic 	if ((flags & TOLOG) &&
46049062Sbostic 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
46145733Smckusick 		if (mbp->msg_magic != MSG_MAGIC) {
462*49953Sbostic 			bzero((caddr_t)mbp, sizeof(*mbp));
46345733Smckusick 			mbp->msg_magic = MSG_MAGIC;
4642172Swnj 		}
46545733Smckusick 		mbp->msg_bufc[mbp->msg_bufx++] = c;
46645733Smckusick 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
46745733Smckusick 			mbp->msg_bufx = 0;
468285Sbill 	}
46949062Sbostic 	if ((flags & TOCONS) && constty == NULL && c != '\0')
47030549Skarels 		(*v_putc)(c);
471285Sbill }
47249908Sbostic 
47349908Sbostic /*
47449908Sbostic  * Scaled down version of sprintf(3).
47549908Sbostic  */
47649908Sbostic #ifdef __STDC__
47749919Skarels sprintf(char *buf, const char *cfmt, ...)
47849908Sbostic #else
47949919Skarels sprintf(buf, cfmt /*, va_alist */)
48049919Skarels 	char *buf, *cfmt;
48149908Sbostic #endif
48249908Sbostic {
48349919Skarels 	register const char *fmt = cfmt;
48449908Sbostic 	register char *p, *bp;
48549908Sbostic 	register int ch, base;
48649908Sbostic 	u_long ul;
48749908Sbostic 	int lflag;
48849908Sbostic 	va_list ap;
48949908Sbostic 
49049919Skarels 	va_start(ap, cfmt);
49149919Skarels 	for (bp = buf; ; ) {
49249919Skarels 		while ((ch = *(u_char *)fmt++) != '%')
49349908Sbostic 			if ((*bp++ = ch) == '\0')
49449919Skarels 				return ((bp - buf) - 1);
49549919Skarels 
49649908Sbostic 		lflag = 0;
49749919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
49849908Sbostic 		case 'l':
49949908Sbostic 			lflag = 1;
50049908Sbostic 			goto reswitch;
50149908Sbostic 		case 'c':
50249908Sbostic 			*bp++ = va_arg(ap, int);
50349908Sbostic 			break;
50449908Sbostic 		case 's':
50549908Sbostic 			p = va_arg(ap, char *);
50649919Skarels 			while (*bp++ = *p++)
50749919Skarels 				;
50849908Sbostic 			--bp;
50949908Sbostic 			break;
51049908Sbostic 		case 'd':
51149908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
51249908Sbostic 			if ((long)ul < 0) {
51349908Sbostic 				*bp++ = '-';
51449908Sbostic 				ul = -(long)ul;
51549908Sbostic 			}
51649908Sbostic 			base = 10;
51749908Sbostic 			goto number;
51849908Sbostic 			break;
51949908Sbostic 		case 'o':
52049908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
52149908Sbostic 			base = 8;
52249908Sbostic 			goto number;
52349908Sbostic 			break;
52449908Sbostic 		case 'u':
52549908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
52649908Sbostic 			base = 10;
52749908Sbostic 			goto number;
52849908Sbostic 			break;
52949908Sbostic 		case 'x':
53049908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
53149908Sbostic 			base = 16;
53249908Sbostic number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
53349908Sbostic 				*bp++ = ch;
53449908Sbostic 			break;
53549908Sbostic 		default:
53649908Sbostic 			*bp++ = '%';
53749908Sbostic 			if (lflag)
53849908Sbostic 				*bp++ = 'l';
53949908Sbostic 			/* FALLTHROUGH */
54049908Sbostic 		case '%':
54149908Sbostic 			*bp++ = ch;
54249908Sbostic 		}
54349908Sbostic 	}
54449908Sbostic 	va_end(ap);
54549908Sbostic }
54649908Sbostic 
54749908Sbostic /*
54849908Sbostic  * Put a number (base <= 16) in a buffer in reverse order; return an
54949908Sbostic  * optional length and a pointer to the NULL terminated (preceded?)
55049908Sbostic  * buffer.
55149908Sbostic  */
55249908Sbostic static char *
55349908Sbostic ksprintn(ul, base, lenp)
55449908Sbostic 	register u_long ul;
55549908Sbostic 	register int base, *lenp;
55649908Sbostic {					/* A long in base 8, plus NULL. */
55749908Sbostic 	static char buf[sizeof(long) * NBBY / 3 + 2];
55849908Sbostic 	register char *p;
55949908Sbostic 
56049908Sbostic 	p = buf;
56149908Sbostic 	do {
56249908Sbostic 		*++p = "0123456789abcdef"[ul % base];
56349908Sbostic 	} while (ul /= base);
56449908Sbostic 	if (lenp)
56549908Sbostic 		*lenp = p - buf;
56649919Skarels 	return (p);
56749908Sbostic }
568