xref: /csrg-svn/sys/kern/subr_prf.c (revision 49908)
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*49908Sbostic  *	@(#)subr_prf.c	7.26 (Berkeley) 05/28/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 */
4849062Sbostic int	(*v_putc)() = cnputc;          	/* routine to putc on virtual console */
4940808Smarc 
50*49908Sbostic static void  logpri __P((int level));
51*49908Sbostic static void  putchar __P((int ch, int flags, struct tty *tp));
52*49908Sbostic static void  kprintf __P((const char *fmt, int flags, struct tty *tp, va_list));
53*49908Sbostic static char *ksprintn __P((u_long num, int base, int *len));
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;
7149062Sbostic 	int s;
7248426Skarels 
7349062Sbostic 	if (panicstr)
7449062Sbostic 		bootopt |= RB_NOSYNC;
7549062Sbostic 	else
7649062Sbostic 		panicstr = msg;
7749062Sbostic 	printf("panic: %s\n", msg);
7849062Sbostic #ifdef KGDB
7949062Sbostic 	kgdb_panic();
8049062Sbostic #endif
8149062Sbostic #ifdef KADB
8249062Sbostic 	if (boothowto & RB_KDB) {
8349062Sbostic 		s = splnet();		/* below kdb pri */
8449062Sbostic 		setsoftkdb();
8549062Sbostic 		splx(s);
8649062Sbostic 	}
8749062Sbostic #endif
8849062Sbostic 	boot(bootopt);
8949062Sbostic }
9049062Sbostic 
9149062Sbostic /*
9249062Sbostic  * Warn that a system table is full.
9349062Sbostic  */
9449062Sbostic void
9549062Sbostic tablefull(tab)
9649062Sbostic 	char *tab;
9731Sbill {
98285Sbill 
9949062Sbostic 	log(LOG_ERR, "%s: table is full\n", tab);
100285Sbill }
101285Sbill 
1022377Swnj /*
10339560Smarc  * Uprintf prints to the controlling terminal for the current process.
10449062Sbostic  * It may block if the tty queue is overfull.  No message is printed if
10549062Sbostic  * the queue does not clear in a reasonable time.
1062377Swnj  */
10749062Sbostic void
10849062Sbostic #ifdef __STDC__
10949062Sbostic uprintf(const char *fmt, ...)
11049062Sbostic #else
11149062Sbostic uprintf(fmt /*, va_alist */)
1122781Swnj 	char *fmt;
11349062Sbostic #endif
114285Sbill {
11547540Skarels 	register struct proc *p = curproc;
11649062Sbostic 	va_list ap;
117285Sbill 
11849062Sbostic 	va_start(ap, fmt);
11944386Smarc 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp)
12049062Sbostic 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
12149062Sbostic 	va_end(ap);
122285Sbill }
123285Sbill 
12444386Smarc tpr_t
12548426Skarels tprintf_open(p)
12648426Skarels 	register struct proc *p;
12744386Smarc {
12844386Smarc 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
12944386Smarc 		SESSHOLD(p->p_session);
13048426Skarels 		return ((tpr_t) p->p_session);
13149062Sbostic 	}
13249062Sbostic 	return ((tpr_t) NULL);
13344386Smarc }
13444386Smarc 
13548426Skarels void
13644386Smarc tprintf_close(sess)
13744386Smarc 	tpr_t sess;
13844386Smarc {
13944386Smarc 	if (sess)
14048426Skarels 		SESSRELE((struct session *) sess);
14144386Smarc }
14244386Smarc 
14318364Skarels /*
14444386Smarc  * tprintf prints on the controlling terminal associated
14549062Sbostic  * with the given session.
14618364Skarels  */
14749062Sbostic void
14849062Sbostic #ifdef __STDC__
14949062Sbostic tprintf(tpr_t tpr, const char *fmt, ...)
15049062Sbostic #else
15149062Sbostic tprintf(tpr, fmt /*, va_alist */)
15248426Skarels 	tpr_t tpr;
15316724Sralph 	char *fmt;
15449062Sbostic #endif
15516724Sralph {
15648426Skarels 	register struct session *sess = (struct session *)tpr;
15748426Skarels 	struct tty *tp = NULL;
15844386Smarc 	int flags = TOLOG;
15949062Sbostic 	va_list ap;
16016724Sralph 
16125389Skarels 	logpri(LOG_INFO);
16248426Skarels 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
16344386Smarc 		flags |= TOTTY;
16448426Skarels 		tp = sess->s_ttyp;
16548426Skarels 	}
16649062Sbostic 	va_start(ap, fmt);
16749062Sbostic 	kprintf(fmt, flags, tp, ap);
16849062Sbostic 	va_end(ap);
16925389Skarels 	logwakeup();
17016724Sralph }
17116724Sralph 
17249062Sbostic /*
17349062Sbostic  * Ttyprintf displays a message on a tty; it should be used only by
17449062Sbostic  * the tty driver, or anything that knows the underlying tty will not
17549062Sbostic  * be revoke(2)'d away.  Other callers should use tprintf.
17649062Sbostic  */
17749062Sbostic void
17849062Sbostic #ifdef __STDC__
17949062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...)
18049062Sbostic #else
18149062Sbostic ttyprintf(tp, fmt /*, va_alist */)
18249062Sbostic 	struct tty *tp;
18349062Sbostic 	char *fmt;
18449062Sbostic #endif
18549062Sbostic {
18649062Sbostic 	va_list ap;
18749062Sbostic 
18849062Sbostic 	va_start(ap, fmt);
18949062Sbostic 	kprintf(fmt, TOTTY, tp, ap);
19049062Sbostic 	va_end(ap);
19149062Sbostic }
19249062Sbostic 
19348426Skarels extern	int log_open;
19444386Smarc 
19516724Sralph /*
19649062Sbostic  * Log writes to the log buffer, and guarantees not to sleep (so can be
19749062Sbostic  * called by interrupt routines).  If there is no process reading the
19849062Sbostic  * log yet, it writes to the console also.
19916724Sralph  */
20049062Sbostic void
20149062Sbostic #ifdef __STDC__
20249062Sbostic log(int level, const char *fmt, ...)
20349062Sbostic #else
20449062Sbostic log(level, fmt /*, va_alist */)
20549062Sbostic 	int level;
20616724Sralph 	char *fmt;
20749062Sbostic #endif
20816724Sralph {
20916724Sralph 	register s = splhigh();
21049062Sbostic 	va_list ap;
21116724Sralph 
21225389Skarels 	logpri(level);
21349062Sbostic 	va_start(ap, fmt);
21449062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
21516724Sralph 	splx(s);
21618364Skarels 	if (!log_open)
21749062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
21849062Sbostic 	va_end(ap);
21916724Sralph 	logwakeup();
22016724Sralph }
22116724Sralph 
22249062Sbostic static void
22325389Skarels logpri(level)
22425389Skarels 	int level;
22525389Skarels {
226*49908Sbostic 	register int ch;
227*49908Sbostic 	register char *p;
22825389Skarels 
22949062Sbostic 	putchar('<', TOLOG, NULL);
230*49908Sbostic 	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
231*49908Sbostic 		putchar(ch, TOLOG, NULL);
23249062Sbostic 	putchar('>', TOLOG, NULL);
23325389Skarels }
23425389Skarels 
23549062Sbostic void
23649062Sbostic #ifdef __STDC__
23749062Sbostic addlog(const char *fmt, ...)
23849062Sbostic #else
23949062Sbostic addlog(fmt /*, va_alist */)
24033479Skarels 	char *fmt;
24149062Sbostic #endif
24233479Skarels {
24333479Skarels 	register s = splhigh();
24449062Sbostic 	va_list ap;
24533479Skarels 
24649062Sbostic 	va_start(ap, fmt);
24749062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
24833479Skarels 	splx(s);
24933479Skarels 	if (!log_open)
25049062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
25149062Sbostic 	va_end(ap);
25233479Skarels 	logwakeup();
25333479Skarels }
25433479Skarels 
25549062Sbostic int	consintr = 1;			/* ok to handle console interrupts? */
25631Sbill 
25749062Sbostic void
25849062Sbostic #ifdef __STDC__
25949062Sbostic printf(const char *fmt, ...)
26049062Sbostic #else
26149062Sbostic printf(fmt /*, va_alist */)
26249062Sbostic 	char *fmt;
26329946Skarels #endif
26449062Sbostic {
26549062Sbostic 	register int savintr;
26649062Sbostic 	va_list ap;
2672678Swnj 
26849062Sbostic 	savintr = consintr;		/* disable interrupts */
26949062Sbostic 	consintr = 0;
27049062Sbostic 	va_start(ap, fmt);
27149062Sbostic 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
27249062Sbostic 	va_end(ap);
27349062Sbostic 	if (!panicstr)
27449062Sbostic 		logwakeup();
27549062Sbostic 	consintr = savintr;		/* reenable interrupts */
27631Sbill }
27731Sbill 
2782781Swnj /*
27949062Sbostic  * Scaled down version of printf(3).
28049062Sbostic  *
28149062Sbostic  * Two additional formats:
28249062Sbostic  *
28349062Sbostic  * The format %b is supported to decode error registers.
28449062Sbostic  * Its usage is:
28549062Sbostic  *
286*49908Sbostic  *	printf("reg=%b\n", regval, "<base><arg>*");
28749062Sbostic  *
28849062Sbostic  * where <base> is the output base expressed as a control character, e.g.
28949062Sbostic  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
29049062Sbostic  * the first of which gives the bit number to be inspected (origin 1), and
29149062Sbostic  * the next characters (up to a control character, i.e. a character <= 32),
29249062Sbostic  * give the name of the register.  Thus:
29349062Sbostic  *
294*49908Sbostic  *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
29549062Sbostic  *
29649062Sbostic  * would produce output:
29749062Sbostic  *
29849062Sbostic  *	reg=3<BITTWO,BITONE>
29949062Sbostic  *
30049062Sbostic  * The format %r is supposed to pass an additional format string and argument
30149062Sbostic  * list recursively.
30249062Sbostic  * Its usage is:
30349062Sbostic  *
30449062Sbostic  * fn(otherstuff, fmt [, arg1, ... ])
30549062Sbostic  *	char *fmt;
30649062Sbostic  *	u_int arg1, ...;
30749062Sbostic  *
308*49908Sbostic  *	printf("prefix: %r, other stuff\n", fmt, ap);
309*49908Sbostic  *
310*49908Sbostic  * Space or zero padding and a field width are supported for the numeric
311*49908Sbostic  * formats only.
3122781Swnj  */
313*49908Sbostic static void
31449094Sbostic kprintf(fmt, flags, tp, ap)
31549094Sbostic 	register const char *fmt;
31649062Sbostic 	int flags;
31749094Sbostic 	struct tty *tp;
31849062Sbostic 	va_list ap;
31931Sbill {
32049062Sbostic 	register char *p;
32149062Sbostic 	register int ch, n;
322*49908Sbostic 	u_long ul;
323*49908Sbostic 	int base, lflag, tmp, width;
324*49908Sbostic 	char padc;
32531Sbill 
32649062Sbostic 	for (;;) {
327*49908Sbostic 		padc = ' ';
328*49908Sbostic 		width = 0;
32949062Sbostic 		while ((ch = *fmt++) != '%') {
33049062Sbostic 			if (ch == '\0')
33149062Sbostic 				return;
33249094Sbostic 			putchar(ch, flags, tp);
33329946Skarels 		}
33449062Sbostic 		lflag = 0;
33549062Sbostic reswitch:	switch (ch = *fmt++) {
336*49908Sbostic 		case '0':
337*49908Sbostic 			padc = '0';
338*49908Sbostic 			goto reswitch;
339*49908Sbostic 		case '1': case '2': case '3': case '4':
340*49908Sbostic 		case '5': case '6': case '7': case '8': case '9':
341*49908Sbostic 			for (width = 0;; ++fmt) {
342*49908Sbostic 				width = width * 10 + ch - '0';
343*49908Sbostic 				ch = *fmt;
344*49908Sbostic 				if (ch < '0' || ch > '9')
345*49908Sbostic 					break;
346*49908Sbostic 			}
347*49908Sbostic 			goto reswitch;
34849062Sbostic 		case 'l':
34949062Sbostic 			lflag = 1;
35049062Sbostic 			goto reswitch;
35149062Sbostic 		case 'b':
35249062Sbostic 			ul = va_arg(ap, int);
35349062Sbostic 			p = va_arg(ap, char *);
354*49908Sbostic 			for (p = ksprintn(ul, *p++, NULL); ch = *p--;)
355*49908Sbostic 				putchar(ch, flags, tp);
35631Sbill 
35749062Sbostic 			if (!ul)
35849062Sbostic 				break;
3592377Swnj 
360*49908Sbostic 			for (tmp = 0; n = *p++;) {
36149062Sbostic 				if (ul & (1 << (n - 1))) {
362*49908Sbostic 					putchar(tmp ? ',' : '<', flags, tp);
36349062Sbostic 					for (; (n = *p) > ' '; ++p)
36449094Sbostic 						putchar(n, flags, tp);
365*49908Sbostic 					tmp = 1;
36649062Sbostic 				} else
36749062Sbostic 					for (; *p > ' '; ++p);
36849062Sbostic 			}
369*49908Sbostic 			if (tmp)
37049094Sbostic 				putchar('>', flags, tp);
37149062Sbostic 			break;
37249062Sbostic 		case 'c':
37349094Sbostic 			putchar(va_arg(ap, int), flags, tp);
37449062Sbostic 			break;
37549062Sbostic 		case 'r':
37649062Sbostic 			p = va_arg(ap, char *);
37749094Sbostic 			kprintf(p, flags, tp, va_arg(ap, va_list));
37849062Sbostic 			break;
37949062Sbostic 		case 's':
38049062Sbostic 			p = va_arg(ap, char *);
38149062Sbostic 			while (ch = *p++)
38249094Sbostic 				putchar(ch, flags, tp);
38349062Sbostic 			break;
38449062Sbostic 		case 'd':
385*49908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
38649062Sbostic 			if ((long)ul < 0) {
38749094Sbostic 				putchar('-', flags, tp);
38849062Sbostic 				ul = -(long)ul;
38949062Sbostic 			}
390*49908Sbostic 			base = 10;
391*49908Sbostic 			goto number;
39249062Sbostic 		case 'o':
393*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
394*49908Sbostic 			base = 8;
395*49908Sbostic 			goto number;;
39649062Sbostic 		case 'u':
397*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
398*49908Sbostic 			base = 10;
399*49908Sbostic 			goto number;
40049062Sbostic 		case 'x':
401*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
402*49908Sbostic 			base = 16;
403*49908Sbostic number:			p = ksprintn(ul, base, &tmp);
404*49908Sbostic 			if (width && (width -= tmp) > 0)
405*49908Sbostic 				while (width--)
406*49908Sbostic 					putchar(padc, flags, tp);
407*49908Sbostic 			while (ch = *p--)
408*49908Sbostic 				putchar(ch, flags, tp);
40949062Sbostic 			break;
41049062Sbostic 		default:
41149094Sbostic 			putchar('%', flags, tp);
41249062Sbostic 			if (lflag)
41349094Sbostic 				putchar('l', flags, tp);
414*49908Sbostic 			/* FALLTHROUGH */
415*49908Sbostic 		case '%':
41649094Sbostic 			putchar(ch, flags, tp);
41749062Sbostic 		}
41830625Skarels 	}
41931Sbill }
42031Sbill 
4212941Swnj /*
42249062Sbostic  * Print a character on console or users terminal.  If destination is
42349062Sbostic  * the console then the last MSGBUFS characters are saved in msgbuf for
42449062Sbostic  * inspection later.
425285Sbill  */
42649062Sbostic static void
42749094Sbostic putchar(c, flags, tp)
4282377Swnj 	register int c;
42949062Sbostic 	int flags;
43049094Sbostic 	struct tty *tp;
431285Sbill {
43233479Skarels 	extern int msgbufmapped;
43349062Sbostic 	register struct msgbuf *mbp;
434285Sbill 
43530549Skarels 	if (panicstr)
43649062Sbostic 		constty = NULL;
43749094Sbostic 	if ((flags & TOCONS) && tp == NULL && constty) {
43849094Sbostic 		tp = constty;
43930549Skarels 		flags |= TOTTY;
44030549Skarels 	}
44149094Sbostic 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
44249094Sbostic 	    (flags & TOCONS) && tp == constty)
44349062Sbostic 		constty = NULL;
44449062Sbostic 	if ((flags & TOLOG) &&
44549062Sbostic 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
44649062Sbostic  		mbp = msgbufp;
44745733Smckusick 		if (mbp->msg_magic != MSG_MAGIC) {
44812494Ssam 			register int i;
44912494Ssam 
45045733Smckusick 			mbp->msg_magic = MSG_MAGIC;
45145733Smckusick 			mbp->msg_bufx = mbp->msg_bufr = 0;
45249062Sbostic 			for (i = 0; i < MSG_BSIZE; i++)
45345733Smckusick 				mbp->msg_bufc[i] = 0;
4542172Swnj 		}
45545733Smckusick 		mbp->msg_bufc[mbp->msg_bufx++] = c;
45645733Smckusick 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
45745733Smckusick 			mbp->msg_bufx = 0;
458285Sbill 	}
45949062Sbostic 	if ((flags & TOCONS) && constty == NULL && c != '\0')
46030549Skarels 		(*v_putc)(c);
461285Sbill }
462*49908Sbostic 
463*49908Sbostic /*
464*49908Sbostic  * Scaled down version of sprintf(3).
465*49908Sbostic  */
466*49908Sbostic #ifdef __STDC__
467*49908Sbostic sprintf(char *buf, const char *fmt, ...)
468*49908Sbostic #else
469*49908Sbostic sprintf(buf, fmt /*, va_alist */)
470*49908Sbostic 	char *buf, *fmt;
471*49908Sbostic #endif
472*49908Sbostic {
473*49908Sbostic 	register char *p, *bp;
474*49908Sbostic 	register int ch, base;
475*49908Sbostic 	u_long ul;
476*49908Sbostic 	int lflag;
477*49908Sbostic 	va_list ap;
478*49908Sbostic 
479*49908Sbostic 	va_start(ap, fmt);
480*49908Sbostic 	for (bp = buf;;) {
481*49908Sbostic 		while ((ch = *fmt++) != '%')
482*49908Sbostic 			if ((*bp++ = ch) == '\0')
483*49908Sbostic 				return((bp - buf) - 1);
484*49908Sbostic 		lflag = 0;
485*49908Sbostic reswitch:	switch (ch = *fmt++) {
486*49908Sbostic 		case 'l':
487*49908Sbostic 			lflag = 1;
488*49908Sbostic 			goto reswitch;
489*49908Sbostic 		case 'c':
490*49908Sbostic 			*bp++ = va_arg(ap, int);
491*49908Sbostic 			break;
492*49908Sbostic 		case 's':
493*49908Sbostic 			p = va_arg(ap, char *);
494*49908Sbostic 			while (*bp++ = *p++);
495*49908Sbostic 			--bp;
496*49908Sbostic 			break;
497*49908Sbostic 		case 'd':
498*49908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
499*49908Sbostic 			if ((long)ul < 0) {
500*49908Sbostic 				*bp++ = '-';
501*49908Sbostic 				ul = -(long)ul;
502*49908Sbostic 			}
503*49908Sbostic 			base = 10;
504*49908Sbostic 			goto number;
505*49908Sbostic 			break;
506*49908Sbostic 		case 'o':
507*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
508*49908Sbostic 			base = 8;
509*49908Sbostic 			goto number;
510*49908Sbostic 			break;
511*49908Sbostic 		case 'u':
512*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
513*49908Sbostic 			base = 10;
514*49908Sbostic 			goto number;
515*49908Sbostic 			break;
516*49908Sbostic 		case 'x':
517*49908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
518*49908Sbostic 			base = 16;
519*49908Sbostic number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
520*49908Sbostic 				*bp++ = ch;
521*49908Sbostic 			break;
522*49908Sbostic 		default:
523*49908Sbostic 			*bp++ = '%';
524*49908Sbostic 			if (lflag)
525*49908Sbostic 				*bp++ = 'l';
526*49908Sbostic 			/* FALLTHROUGH */
527*49908Sbostic 		case '%':
528*49908Sbostic 			*bp++ = ch;
529*49908Sbostic 		}
530*49908Sbostic 	}
531*49908Sbostic 	va_end(ap);
532*49908Sbostic }
533*49908Sbostic 
534*49908Sbostic /*
535*49908Sbostic  * Put a number (base <= 16) in a buffer in reverse order; return an
536*49908Sbostic  * optional length and a pointer to the NULL terminated (preceded?)
537*49908Sbostic  * buffer.
538*49908Sbostic  */
539*49908Sbostic static char *
540*49908Sbostic ksprintn(ul, base, lenp)
541*49908Sbostic 	register u_long ul;
542*49908Sbostic 	register int base, *lenp;
543*49908Sbostic {					/* A long in base 8, plus NULL. */
544*49908Sbostic 	static char buf[sizeof(long) * NBBY / 3 + 2];
545*49908Sbostic 	register char *p;
546*49908Sbostic 
547*49908Sbostic 	p = buf;
548*49908Sbostic 	do {
549*49908Sbostic 		*++p = "0123456789abcdef"[ul % base];
550*49908Sbostic 	} while (ul /= base);
551*49908Sbostic 	if (lenp)
552*49908Sbostic 		*lenp = p - buf;
553*49908Sbostic 	return(p);
554*49908Sbostic }
555