xref: /netbsd-src/sys/kern/subr_prf.c (revision a5a68ff5f29de57339ca14f6c671c0a87714f1f8)
1 /*	$NetBSD: subr_prf.c,v 1.44 1997/09/19 13:56:41 leo Exp $	*/
2 
3 /*-
4  * Copyright (c) 1986, 1988, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/buf.h>
46 #include <sys/conf.h>
47 #include <sys/reboot.h>
48 #include <sys/msgbuf.h>
49 #include <sys/proc.h>
50 #include <sys/ioctl.h>
51 #include <sys/vnode.h>
52 #include <sys/file.h>
53 #include <sys/tty.h>
54 #include <sys/tprintf.h>
55 #include <sys/syslog.h>
56 #include <sys/malloc.h>
57 
58 #include <dev/cons.h>
59 
60 /*
61  * Note that stdarg.h and the ANSI style va_start macro is used for both
62  * ANSI and traditional C compilers.
63  * XXX: This requires that stdarg.h defines: va_alist, va_dcl
64  */
65 #include <machine/stdarg.h>
66 
67 #include "ipkdb.h"
68 
69 #ifdef KADB
70 #include <machine/kdbparam.h>
71 #endif
72 #ifdef KGDB
73 #include <sys/kgdb.h>
74 #include <machine/cpu.h>
75 #endif
76 
77 #define TOCONS	0x01
78 #define TOTTY	0x02
79 #define TOLOG	0x04
80 
81 /*
82  * This is the size of the buffer that should be passed to ksnprintn().
83  * It's the length of a long in base 8, plus NULL.
84  */
85 #define KSNPRINTN_BUFSIZE	(sizeof(quad_t) * NBBY / 3 + 2)
86 
87 struct	tty *constty;			/* pointer to console "window" tty */
88 
89 void	(*v_putc) __P((int)) = cnputc;	/* routine to putc on virtual console */
90 
91 static void putchar __P((int, int, struct tty *));
92 static char *ksnprintn __P((u_quad_t, int, int *, char *, size_t));
93 void kprintf __P((const char *, int, struct tty *, va_list));
94 
95 int consintr = 1;			/* Ok to handle console interrupts? */
96 
97 /*
98  * Variable panicstr contains argument to first call to panic; used as flag
99  * to indicate that the kernel has already called panic.
100  */
101 const char *panicstr;
102 
103 /*
104  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
105  * and then reboots.  If we are called twice, then we avoid trying to sync
106  * the disks as this often leads to recursive panics.
107  */
108 void
109 #ifdef __STDC__
110 panic(const char *fmt, ...)
111 #else
112 panic(fmt, va_alist)
113 	char *fmt;
114 	va_dcl
115 #endif
116 {
117 	int bootopt;
118 	va_list ap;
119 
120 	bootopt = RB_AUTOBOOT | RB_DUMP;
121 	if (panicstr)
122 		bootopt |= RB_NOSYNC;
123 	else
124 		panicstr = fmt;
125 
126 	va_start(ap, fmt);
127 #ifdef __powerpc__				/* XXX */
128 	printf("panic: ");			/* XXX */
129 	vprintf(fmt, ap);			/* XXX */
130 	printf("\n");				/* XXX */
131 #else						/* XXX */
132 	printf("panic: %:\n", fmt, ap);		/* XXX */
133 #endif						/* XXX */
134 	va_end(ap);
135 
136 #if NIPKDB > 0
137 	ipkdb_panic();
138 #endif
139 #ifdef KGDB
140 	kgdb_panic();
141 #endif
142 #ifdef KADB
143 	if (boothowto & RB_KDB)
144 		kdbpanic();
145 #endif
146 #ifdef DDB
147 	if (db_onpanic)
148 		Debugger();
149 #endif
150 	cpu_reboot(bootopt, NULL);
151 }
152 
153 /*
154  * Warn that a system table is full.
155  */
156 void
157 tablefull(tab)
158 	const char *tab;
159 {
160 
161 	log(LOG_ERR, "%s: table is full\n", tab);
162 }
163 
164 /*
165  * Uprintf prints to the controlling terminal for the current process.
166  * It may block if the tty queue is overfull.  No message is printed if
167  * the queue does not clear in a reasonable time.
168  */
169 void
170 #ifdef __STDC__
171 uprintf(const char *fmt, ...)
172 #else
173 uprintf(fmt, va_alist)
174 	char *fmt;
175 	va_dcl
176 #endif
177 {
178 	register struct proc *p = curproc;
179 	va_list ap;
180 
181 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
182 		va_start(ap, fmt);
183 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
184 		va_end(ap);
185 	}
186 }
187 
188 tpr_t
189 tprintf_open(p)
190 	register struct proc *p;
191 {
192 
193 	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
194 		SESSHOLD(p->p_session);
195 		return ((tpr_t) p->p_session);
196 	}
197 	return ((tpr_t) NULL);
198 }
199 
200 void
201 tprintf_close(sess)
202 	tpr_t sess;
203 {
204 
205 	if (sess)
206 		SESSRELE((struct session *) sess);
207 }
208 
209 /*
210  * tprintf prints on the controlling terminal associated
211  * with the given session.
212  */
213 void
214 #ifdef __STDC__
215 tprintf(tpr_t tpr, const char *fmt, ...)
216 #else
217 tprintf(tpr, fmt, va_alist)
218 	tpr_t tpr;
219 	char *fmt;
220 	va_dcl
221 #endif
222 {
223 	register struct session *sess = (struct session *)tpr;
224 	struct tty *tp = NULL;
225 	int flags = TOLOG;
226 	va_list ap;
227 
228 	logpri(LOG_INFO);
229 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
230 		flags |= TOTTY;
231 		tp = sess->s_ttyp;
232 	}
233 	va_start(ap, fmt);
234 	kprintf(fmt, flags, tp, ap);
235 	va_end(ap);
236 	logwakeup();
237 }
238 
239 /*
240  * Ttyprintf displays a message on a tty; it should be used only by
241  * the tty driver, or anything that knows the underlying tty will not
242  * be revoke(2)'d away.  Other callers should use tprintf.
243  */
244 void
245 #ifdef __STDC__
246 ttyprintf(struct tty *tp, const char *fmt, ...)
247 #else
248 ttyprintf(tp, fmt, va_alist)
249 	struct tty *tp;
250 	char *fmt;
251 	va_dcl
252 #endif
253 {
254 	va_list ap;
255 
256 	va_start(ap, fmt);
257 	kprintf(fmt, TOTTY, tp, ap);
258 	va_end(ap);
259 }
260 
261 extern	int log_open;
262 
263 /*
264  * Log writes to the log buffer, and guarantees not to sleep (so can be
265  * called by interrupt routines).  If there is no process reading the
266  * log yet, it writes to the console also.
267  */
268 void
269 #ifdef __STDC__
270 log(int level, const char *fmt, ...)
271 #else
272 log(level, fmt, va_alist)
273 	int level;
274 	char *fmt;
275 	va_dcl
276 #endif
277 {
278 	register int s;
279 	va_list ap;
280 
281 	s = splhigh();
282 	logpri(level);
283 	va_start(ap, fmt);
284 	kprintf(fmt, TOLOG, NULL, ap);
285 	splx(s);
286 	va_end(ap);
287 	if (!log_open) {
288 		va_start(ap, fmt);
289 		kprintf(fmt, TOCONS, NULL, ap);
290 		va_end(ap);
291 	}
292 	logwakeup();
293 }
294 
295 void
296 logpri(level)
297 	int level;
298 {
299 	register int ch;
300 	register char *p;
301 	char snbuf[KSNPRINTN_BUFSIZE];
302 
303 	putchar('<', TOLOG, NULL);
304 	for (p = ksnprintn((u_long)level, 10, NULL, snbuf, sizeof(snbuf));
305 	    (ch = *p--) != 0;)
306 		putchar(ch, TOLOG, NULL);
307 	putchar('>', TOLOG, NULL);
308 }
309 
310 void
311 #ifdef __STDC__
312 addlog(const char *fmt, ...)
313 #else
314 addlog(fmt, va_alist)
315 	char *fmt;
316 	va_dcl
317 #endif
318 {
319 	register int s;
320 	va_list ap;
321 
322 	s = splhigh();
323 	va_start(ap, fmt);
324 	kprintf(fmt, TOLOG, NULL, ap);
325 	splx(s);
326 	va_end(ap);
327 	if (!log_open) {
328 		va_start(ap, fmt);
329 		kprintf(fmt, TOCONS, NULL, ap);
330 		va_end(ap);
331 	}
332 	logwakeup();
333 }
334 
335 void
336 #ifdef __STDC__
337 printf(const char *fmt, ...)
338 #else
339 printf(fmt, va_alist)
340 	char *fmt;
341 	va_dcl
342 #endif
343 {
344 	va_list ap;
345 	register int savintr;
346 
347 	savintr = consintr;		/* disable interrupts */
348 	consintr = 0;
349 	va_start(ap, fmt);
350 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
351 	va_end(ap);
352 	if (!panicstr)
353 		logwakeup();
354 	consintr = savintr;		/* reenable interrupts */
355 }
356 
357 #ifdef __powerpc__			/* XXX XXX XXX */
358 void
359 vprintf(fmt, ap)
360 	const char *fmt;
361 	va_list ap;
362 {
363 	register int savintr;
364 
365 	savintr = consintr;		/* disable interrupts */
366 	consintr = 0;
367 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
368 	if (!panicstr)
369 		logwakeup();
370 	consintr = savintr;		/* reenable interrupts */
371 }
372 #endif /* __powerpc__ */		/* XXX XXX XXX */
373 
374 /*
375  * Scaled down version of printf(3).
376  *
377  * Two additional formats:
378  *
379  * The format %b is supported to decode error registers.
380  * Its usage is:
381  *
382  *	printf("reg=%b\n", regval, "<base><arg>*");
383  *
384  * where <base> is the output base expressed as a control character, e.g.
385  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
386  * the first of which gives the bit number to be inspected (origin 1), and
387  * the next characters (up to a control character, i.e. a character <= 32),
388  * give the name of the register.  Thus:
389  *
390  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
391  *
392  * would produce output:
393  *
394  *	reg=3<BITTWO,BITONE>
395  *
396  * The format %: passes an additional format string and argument list
397  * recursively.  Its usage is:
398  *
399  * fn(char *fmt, ...)
400  * {
401  *	va_list ap;
402  *	va_start(ap, fmt);
403  *	printf("prefix: %: suffix\n", fmt, ap);
404  *	va_end(ap);
405  * }
406  *
407  * Space or zero padding and a field width are supported for the numeric
408  * formats only.
409  */
410 #define	LONGINT		0x010		/* long integer */
411 #define	QUADINT		0x020		/* quad integer */
412 #define	SARG() \
413 	(flags&QUADINT ? va_arg(ap, quad_t) : \
414 	    flags&LONGINT ? va_arg(ap, long) : \
415 	    (long)va_arg(ap, int))
416 #define	UARG() \
417 	(flags&QUADINT ? va_arg(ap, u_quad_t) : \
418 	    flags&LONGINT ? va_arg(ap, u_long) : \
419 	    (u_long)va_arg(ap, u_int))
420 void
421 kprintf(fmt, oflags, tp, ap)
422 	register const char *fmt;
423 	int oflags;
424 	struct tty *tp;
425 	va_list ap;
426 {
427 	register char *p, *q;
428 	register int ch, n;
429 	u_quad_t ul;
430 	int base, flags, tmp, width;
431 	char padc, snbuf[KSNPRINTN_BUFSIZE];
432 
433 	for (;;) {
434 		padc = ' ';
435 		width = 0;
436 		while ((ch = *(const u_char *)fmt++) != '%') {
437 			if (ch == '\0')
438 				return;
439 			putchar(ch, oflags, tp);
440 		}
441 		flags = 0;
442 reswitch:	switch (ch = *(const u_char *)fmt++) {
443 		case '\0':
444 			/* XXX Print the last format character? */
445 			return;
446 		case '0':
447 		case '.':
448 			padc = '0';
449 			goto reswitch;
450 		case '1': case '2': case '3': case '4':
451 		case '5': case '6': case '7': case '8': case '9':
452 			for (width = 0;; ++fmt) {
453 				width = width * 10 + ch - '0';
454 				ch = *fmt;
455 				if (ch < '0' || ch > '9')
456 					break;
457 			}
458 			goto reswitch;
459 		case 'l':
460 			flags |= LONGINT;
461 			goto reswitch;
462 		case 'q':
463 			flags |= QUADINT;
464 			goto reswitch;
465 		case 'b':
466 			ul = va_arg(ap, int);
467 			p = va_arg(ap, char *);
468 			for (q = ksnprintn(ul, *p++, NULL, snbuf,
469 			    sizeof(snbuf)); (ch = *q--) != 0;)
470 				putchar(ch, oflags, tp);
471 
472 			if (!ul)
473 				break;
474 
475 			for (tmp = 0; (n = *p++) != 0;) {
476 				if (ul & (1 << (n - 1))) {
477 					putchar(tmp ? ',' : '<', oflags, tp);
478 					for (; (n = *p) > ' '; ++p)
479 						putchar(n, oflags, tp);
480 					tmp = 1;
481 				} else
482 					for (; *p > ' '; ++p)
483 						continue;
484 			}
485 			if (tmp)
486 				putchar('>', oflags, tp);
487 			break;
488 		case 'c':
489 			putchar(va_arg(ap, int), oflags, tp);
490 			break;
491 #ifndef __powerpc__			/* XXX XXX XXX */
492 		case ':':
493 			p = va_arg(ap, char *);
494 			kprintf(p, oflags, tp, va_arg(ap, va_list));
495 			break;
496 #endif /* __powerpc__ */		/* XXX XXX XXX */
497 		case 's':
498 			if ((p = va_arg(ap, char *)) == NULL)
499 				p = "(null)";
500 			while ((ch = *p++) != 0)
501 				putchar(ch, oflags, tp);
502 			break;
503 		case 'd':
504 		        ul = SARG();
505 			if ((quad_t)ul < 0) {
506 				putchar('-', oflags, tp);
507 				ul = -ul;
508 			}
509 			base = 10;
510 			goto number;
511 		case 'o':
512 			ul = UARG();
513 			base = 8;
514 			goto number;
515 		case 'u':
516 			ul = UARG();
517 			base = 10;
518 			goto number;
519 		case 'p':
520 			putchar('0', oflags, tp);
521 			putchar('x', oflags, tp);
522 			ul = (u_long)va_arg(ap, void *);
523 			base = 16;
524 			goto number;
525 		case 'x':
526 			ul = UARG();
527 			base = 16;
528 number:			p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
529 			if (width && (width -= tmp) > 0)
530 				while (width--)
531 					putchar(padc, oflags, tp);
532 			while ((ch = *p--) != 0)
533 				putchar(ch, oflags, tp);
534 			break;
535 		default:
536 			putchar('%', oflags, tp);
537 		        /* flags??? */
538 			/* FALLTHROUGH */
539 		case '%':
540 			putchar(ch, oflags, tp);
541 		}
542 	}
543 }
544 
545 /*
546  * Print a character on console or users terminal.  If destination is
547  * the console then the last MSGBUFS characters are saved in msgbuf for
548  * inspection later.
549  */
550 static void
551 putchar(c, flags, tp)
552 	register int c;
553 	int flags;
554 	struct tty *tp;
555 {
556 	register struct kern_msgbuf *mbp;
557 
558 	if (panicstr)
559 		constty = NULL;
560 	if ((flags & TOCONS) && tp == NULL && constty) {
561 		tp = constty;
562 		flags |= TOTTY;
563 	}
564 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
565 	    (flags & TOCONS) && tp == constty)
566 		constty = NULL;
567 	if ((flags & TOLOG) &&
568 	    c != '\0' && c != '\r' && c != 0177 && msgbufenabled) {
569 		mbp = msgbufp;
570 		if (mbp->msg_magic != MSG_MAGIC) {
571 			/*
572 			 * Arguably should panic or somehow notify the
573 			 * user...  but how?  Panic may be too drastic,
574 			 * and would obliterate the message being kicked
575 			 * out (maybe a panic itself), and printf
576 			 * would invoke us recursively.  Silently punt
577 			 * for now.  If syslog is running, it should
578 			 * notice.
579 			 */
580 			msgbufenabled = 0;
581 		} else {
582 			mbp->msg_bufc[mbp->msg_bufx++] = c;
583 			if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs)
584 				mbp->msg_bufx = 0;
585 		}
586 	}
587 	if ((flags & TOCONS) && constty == NULL && c != '\0')
588 		(*v_putc)(c);
589 }
590 
591 /*
592  * Scaled down version of sprintf(3).
593  */
594 int
595 #ifdef __STDC__
596 sprintf(char *buf, const char *cfmt, ...)
597 #else
598 sprintf(buf, cfmt, va_alist)
599 	char *buf;
600 	const char *cfmt;
601 	va_dcl
602 #endif
603 {
604 	register const char *fmt = cfmt;
605 	register char *p, *bp;
606 	register int ch, base;
607 	u_quad_t ul;
608 	int flags, tmp, width;
609 	va_list ap;
610 	char padc, snbuf[KSNPRINTN_BUFSIZE];
611 
612 	va_start(ap, cfmt);
613 	for (bp = buf; ; ) {
614 		padc = ' ';
615 		width = 0;
616 		while ((ch = *(const u_char *)fmt++) != '%')
617 			if ((*bp++ = ch) == '\0')
618 				return ((bp - buf) - 1);
619 
620 		flags = 0;
621 reswitch:	switch (ch = *(const u_char *)fmt++) {
622 		case '\0':
623 			/* XXX Store the last format character? */
624 			*bp++ = '\0';
625 			return ((bp - buf) - 1);
626 		case '0':
627 			padc = '0';
628 			goto reswitch;
629 		case '1': case '2': case '3': case '4':
630 		case '5': case '6': case '7': case '8': case '9':
631 			for (width = 0;; ++fmt) {
632 				width = width * 10 + ch - '0';
633 				ch = *fmt;
634 				if (ch < '0' || ch > '9')
635 					break;
636 			}
637 			goto reswitch;
638 		case 'l':
639 			flags |= LONGINT;
640 			goto reswitch;
641 		case 'q':
642 			flags |= QUADINT;
643 			goto reswitch;
644 		/* case 'b': ... break; XXX */
645 		case 'c':
646 			*bp++ = va_arg(ap, int);
647 			break;
648 		/* case 'r': ... break; XXX */
649 		case 's':
650 			p = va_arg(ap, char *);
651 			while ((*bp++ = *p++) != 0)
652 				continue;
653 			--bp;
654 			break;
655 		case 'd':
656 		        ul = SARG();
657 			if ((quad_t)ul < 0) {
658 				*bp++ = '-';
659 				ul = -ul;
660 			}
661 			base = 10;
662 			goto number;
663 		case 'o':
664 			ul = UARG();
665 			base = 8;
666 			goto number;
667 		case 'u':
668 			ul = UARG();
669 			base = 10;
670 			goto number;
671 		case 'p':
672 			*bp++ = '0';
673 			*bp++ = 'x';
674 			ul = (u_long)va_arg(ap, void *);
675 			base = 16;
676 			goto number;
677 		case 'x':
678 			ul = UARG();
679 			base = 16;
680 number:			p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
681 			if (width && (width -= tmp) > 0)
682 				while (width--)
683 					*bp++ = padc;
684 			while ((ch = *p--) != 0)
685 				*bp++ = ch;
686 			break;
687 		default:
688 			*bp++ = '%';
689 		        /* flags??? */
690 			/* FALLTHROUGH */
691 		case '%':
692 			*bp++ = ch;
693 		}
694 	}
695 	va_end(ap);
696 }
697 
698 /*
699  * Put a number (base <= 16) in a buffer in reverse order; return an
700  * optional length and a pointer to the NULL terminated (preceded?)
701  * buffer.
702  */
703 static char *
704 ksnprintn(ul, base, lenp, buf, buflen)
705 	register u_quad_t ul;
706 	register int base, *lenp;
707 	char *buf;
708 	size_t buflen;
709 {
710 	register char *p;
711 
712 	p = buf;
713 	*p = '\0';			/* ensure NULL `termination' */
714 
715 	/*
716 	 * Don't even bother of the buffer's not big enough.  No
717 	 * value at all is better than a wrong value, and we
718 	 * have a lot of control over the buffer that's passed
719 	 * to this function, since it's not exported.
720 	 */
721 	if (buflen < KSNPRINTN_BUFSIZE)
722 		return (p);
723 
724 	do {
725 		*++p = "0123456789abcdef"[ul % base];
726 	} while (ul /= base);
727 	if (lenp)
728 		*lenp = p - buf;
729 	return (p);
730 }
731 
732 /*
733  * Print a bitmask into the provided buffer, and return a pointer
734  * to that buffer.
735  */
736 char *
737 bitmask_snprintf(ul, p, buf, buflen)
738 	u_long ul;
739 	const char *p;
740 	char *buf;
741 	size_t buflen;
742 {
743 	char *bp, *q;
744 	size_t left;
745 	register int n;
746 	int ch, tmp;
747 	char snbuf[KSNPRINTN_BUFSIZE];
748 
749 	bp = buf;
750 	bzero(buf, buflen);
751 
752 	/*
753 	 * Always leave room for the trailing NULL.
754 	 */
755 	left = buflen - 1;
756 
757 	/*
758 	 * Print the value into the buffer.  Abort if there's not
759 	 * enough room.
760 	 */
761 	if (buflen < KSNPRINTN_BUFSIZE)
762 		return (buf);
763 
764 	for (q = ksnprintn(ul, *p++, NULL, snbuf, sizeof(snbuf));
765 	    (ch = *q--) != 0;) {
766 		*bp++ = ch;
767 		left--;
768 	}
769 
770 	/*
771 	 * If the value we printed was 0, or if we don't have room for
772 	 * "<x>", we're done.
773 	 */
774 	if (ul == 0 || left < 3)
775 		return (buf);
776 
777 #define PUTBYTE(b, c, l)	\
778 	*(b)++ = (c);		\
779 	if (--(l) == 0)		\
780 		goto out;
781 
782 	for (tmp = 0; (n = *p++) != 0;) {
783 		if (ul & (1 << (n - 1))) {
784 			PUTBYTE(bp, tmp ? ',' : '<', left);
785 				for (; (n = *p) > ' '; ++p) {
786 					PUTBYTE(bp, n, left);
787 				}
788 				tmp = 1;
789 		} else
790 			for (; *p > ' '; ++p)
791 				continue;
792 	}
793 	if (tmp)
794 		*bp = '>';
795 
796 #undef PUTBYTE
797 
798  out:
799 	return (buf);
800 }
801