149062Sbostic /*-
263176Sbostic * Copyright (c) 1986, 1988, 1991, 1993
363176Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923381Smckusick *
1049062Sbostic * %sccs.include.redist.c%
1149062Sbostic *
12*69241Smckusick * @(#)subr_prf.c 8.4 (Berkeley) 05/04/95
1323381Smckusick */
1431Sbill
1551768Smarc #include <sys/param.h>
1651768Smarc #include <sys/systm.h>
1751768Smarc #include <sys/buf.h>
1851768Smarc #include <sys/conf.h>
1951768Smarc #include <sys/reboot.h>
2051768Smarc #include <sys/msgbuf.h>
2151768Smarc #include <sys/proc.h>
2251768Smarc #include <sys/ioctl.h>
2351768Smarc #include <sys/vnode.h>
2451768Smarc #include <sys/file.h>
2551768Smarc #include <sys/tty.h>
2651768Smarc #include <sys/tprintf.h>
2751768Smarc #include <sys/syslog.h>
2851768Smarc #include <sys/malloc.h>
2931Sbill
3049062Sbostic /*
3149062Sbostic * Note that stdarg.h and the ANSI style va_start macro is used for both
3249062Sbostic * ANSI and traditional C compilers.
3349062Sbostic */
3449062Sbostic #include <machine/stdarg.h>
3549062Sbostic
3635282Skarels #ifdef KADB
3756517Sbostic #include <machine/kdbparam.h>
3830625Skarels #endif
3930625Skarels
4049062Sbostic #define TOCONS 0x01
4149062Sbostic #define TOTTY 0x02
4249062Sbostic #define TOLOG 0x04
4316724Sralph
4430549Skarels struct tty *constty; /* pointer to console "window" tty */
4530549Skarels
4649062Sbostic extern cnputc(); /* standard console putc */
4749953Sbostic int (*v_putc)() = cnputc; /* routine to putc on virtual console */
4840808Smarc
4951768Smarc void logpri __P((int level));
5049908Sbostic static void putchar __P((int ch, int flags, struct tty *tp));
5149908Sbostic static char *ksprintn __P((u_long num, int base, int *len));
5252392Smarc void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap));
5349062Sbostic
5451768Smarc int consintr = 1; /* Ok to handle console interrupts? */
5551768Smarc
5631Sbill /*
5751768Smarc * Variable panicstr contains argument to first call to panic; used as flag
5851768Smarc * to indicate that the kernel has already called panic.
5931Sbill */
6051768Smarc const char *panicstr;
6129946Skarels
6249062Sbostic /*
6349062Sbostic * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
6449062Sbostic * and then reboots. If we are called twice, then we avoid trying to sync
6549062Sbostic * the disks as this often leads to recursive panics.
6649062Sbostic */
6752392Smarc #ifdef __GNUC__
6852406Smckusick volatile void boot(int flags); /* boot() does not return */
6952392Smarc volatile /* panic() does not return */
7052392Smarc #endif
7149062Sbostic void
7251768Smarc #ifdef __STDC__
panic(const char * fmt,...)7351768Smarc panic(const char *fmt, ...)
7451768Smarc #else
7552782Sralph panic(fmt, va_alist)
7651768Smarc char *fmt;
7751768Smarc #endif
7849062Sbostic {
7952392Smarc int bootopt;
8051768Smarc va_list ap;
8148426Skarels
8251768Smarc bootopt = RB_AUTOBOOT | RB_DUMP;
8349062Sbostic if (panicstr)
8449062Sbostic bootopt |= RB_NOSYNC;
8549062Sbostic else
8651768Smarc panicstr = fmt;
8751768Smarc
8851768Smarc va_start(ap, fmt);
8952392Smarc printf("panic: %r\n", fmt, ap);
9051768Smarc va_end(ap);
9151768Smarc
9249062Sbostic #ifdef KGDB
9349062Sbostic kgdb_panic();
9449062Sbostic #endif
9549062Sbostic #ifdef KADB
9652782Sralph if (boothowto & RB_KDB)
9752782Sralph kdbpanic();
9849062Sbostic #endif
9949062Sbostic boot(bootopt);
10049062Sbostic }
10149062Sbostic
10249062Sbostic /*
10349062Sbostic * Warn that a system table is full.
10449062Sbostic */
10549062Sbostic void
tablefull(tab)10649062Sbostic tablefull(tab)
10752406Smckusick const char *tab;
10831Sbill {
109285Sbill
11049062Sbostic log(LOG_ERR, "%s: table is full\n", tab);
111285Sbill }
112285Sbill
1132377Swnj /*
11439560Smarc * Uprintf prints to the controlling terminal for the current process.
11549062Sbostic * It may block if the tty queue is overfull. No message is printed if
11649062Sbostic * the queue does not clear in a reasonable time.
1172377Swnj */
11849062Sbostic void
11949062Sbostic #ifdef __STDC__
uprintf(const char * fmt,...)12049062Sbostic uprintf(const char *fmt, ...)
12149062Sbostic #else
12251767Smarc uprintf(fmt, va_alist)
1232781Swnj char *fmt;
12449062Sbostic #endif
125285Sbill {
12647540Skarels register struct proc *p = curproc;
12749062Sbostic va_list ap;
128285Sbill
12964584Sbostic if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
13049953Sbostic va_start(ap, fmt);
13149062Sbostic kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
13249953Sbostic va_end(ap);
13349953Sbostic }
134285Sbill }
135285Sbill
13644386Smarc tpr_t
tprintf_open(p)13748426Skarels tprintf_open(p)
13848426Skarels register struct proc *p;
13944386Smarc {
14049953Sbostic
14164584Sbostic if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
14244386Smarc SESSHOLD(p->p_session);
14348426Skarels return ((tpr_t) p->p_session);
14449062Sbostic }
14549062Sbostic return ((tpr_t) NULL);
14644386Smarc }
14744386Smarc
14848426Skarels void
tprintf_close(sess)14944386Smarc tprintf_close(sess)
15044386Smarc tpr_t sess;
15144386Smarc {
15249953Sbostic
15344386Smarc if (sess)
15448426Skarels SESSRELE((struct session *) sess);
15544386Smarc }
15644386Smarc
15718364Skarels /*
15844386Smarc * tprintf prints on the controlling terminal associated
15949062Sbostic * with the given session.
16018364Skarels */
16149062Sbostic void
16249062Sbostic #ifdef __STDC__
tprintf(tpr_t tpr,const char * fmt,...)16349062Sbostic tprintf(tpr_t tpr, const char *fmt, ...)
16449062Sbostic #else
16551767Smarc tprintf(tpr, fmt, va_alist)
16648426Skarels tpr_t tpr;
16716724Sralph char *fmt;
16849062Sbostic #endif
16916724Sralph {
17048426Skarels register struct session *sess = (struct session *)tpr;
17148426Skarels struct tty *tp = NULL;
17244386Smarc int flags = TOLOG;
17349062Sbostic va_list ap;
17416724Sralph
17525389Skarels logpri(LOG_INFO);
17648426Skarels if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
17744386Smarc flags |= TOTTY;
17848426Skarels tp = sess->s_ttyp;
17948426Skarels }
18049062Sbostic va_start(ap, fmt);
18149062Sbostic kprintf(fmt, flags, tp, ap);
18249062Sbostic va_end(ap);
18325389Skarels logwakeup();
18416724Sralph }
18516724Sralph
18649062Sbostic /*
18749062Sbostic * Ttyprintf displays a message on a tty; it should be used only by
18849062Sbostic * the tty driver, or anything that knows the underlying tty will not
18949062Sbostic * be revoke(2)'d away. Other callers should use tprintf.
19049062Sbostic */
19149062Sbostic void
19249062Sbostic #ifdef __STDC__
ttyprintf(struct tty * tp,const char * fmt,...)19349062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...)
19449062Sbostic #else
19551767Smarc ttyprintf(tp, fmt, va_alist)
19649062Sbostic struct tty *tp;
19749062Sbostic char *fmt;
19849062Sbostic #endif
19949062Sbostic {
20049062Sbostic va_list ap;
20149062Sbostic
20249062Sbostic va_start(ap, fmt);
20349062Sbostic kprintf(fmt, TOTTY, tp, ap);
20449062Sbostic va_end(ap);
20549062Sbostic }
20649062Sbostic
20748426Skarels extern int log_open;
20844386Smarc
20916724Sralph /*
21049062Sbostic * Log writes to the log buffer, and guarantees not to sleep (so can be
21149062Sbostic * called by interrupt routines). If there is no process reading the
21249062Sbostic * log yet, it writes to the console also.
21316724Sralph */
21449062Sbostic void
21549062Sbostic #ifdef __STDC__
log(int level,const char * fmt,...)21649062Sbostic log(int level, const char *fmt, ...)
21749062Sbostic #else
21851767Smarc log(level, fmt, va_alist)
21949062Sbostic int level;
22016724Sralph char *fmt;
22149062Sbostic #endif
22216724Sralph {
22350268Sbostic register int s;
22449062Sbostic va_list ap;
22516724Sralph
22650268Sbostic s = splhigh();
22725389Skarels logpri(level);
22849062Sbostic va_start(ap, fmt);
22949062Sbostic kprintf(fmt, TOLOG, NULL, ap);
23016724Sralph splx(s);
23149953Sbostic va_end(ap);
23249953Sbostic if (!log_open) {
23349953Sbostic va_start(ap, fmt);
23449062Sbostic kprintf(fmt, TOCONS, NULL, ap);
23549953Sbostic va_end(ap);
23649953Sbostic }
23716724Sralph logwakeup();
23816724Sralph }
23916724Sralph
24051768Smarc void
logpri(level)24125389Skarels logpri(level)
24225389Skarels int level;
24325389Skarels {
24449908Sbostic register int ch;
24549908Sbostic register char *p;
24625389Skarels
24749062Sbostic putchar('<', TOLOG, NULL);
24849908Sbostic for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
24949908Sbostic putchar(ch, TOLOG, NULL);
25049062Sbostic putchar('>', TOLOG, NULL);
25125389Skarels }
25225389Skarels
25349062Sbostic void
25449062Sbostic #ifdef __STDC__
addlog(const char * fmt,...)25549062Sbostic addlog(const char *fmt, ...)
25649062Sbostic #else
25751767Smarc addlog(fmt, va_alist)
25833479Skarels char *fmt;
25949062Sbostic #endif
26033479Skarels {
26150268Sbostic register int s;
26249062Sbostic va_list ap;
26333479Skarels
26450268Sbostic s = splhigh();
26549062Sbostic va_start(ap, fmt);
26649062Sbostic kprintf(fmt, TOLOG, NULL, ap);
26733479Skarels splx(s);
26849953Sbostic va_end(ap);
26949953Sbostic if (!log_open) {
27049953Sbostic va_start(ap, fmt);
27149062Sbostic kprintf(fmt, TOCONS, NULL, ap);
27249953Sbostic va_end(ap);
27349953Sbostic }
27433479Skarels logwakeup();
27533479Skarels }
27633479Skarels
27749062Sbostic void
27849062Sbostic #ifdef __STDC__
printf(const char * fmt,...)27949062Sbostic printf(const char *fmt, ...)
28049062Sbostic #else
28151767Smarc printf(fmt, va_alist)
28249062Sbostic char *fmt;
28329946Skarels #endif
28449062Sbostic {
28549953Sbostic va_list ap;
28649062Sbostic register int savintr;
2872678Swnj
28849062Sbostic savintr = consintr; /* disable interrupts */
28949062Sbostic consintr = 0;
29049062Sbostic va_start(ap, fmt);
29149062Sbostic kprintf(fmt, TOCONS | TOLOG, NULL, ap);
29249062Sbostic va_end(ap);
29349062Sbostic if (!panicstr)
29449062Sbostic logwakeup();
29549062Sbostic consintr = savintr; /* reenable interrupts */
29631Sbill }
29731Sbill
2982781Swnj /*
29949062Sbostic * Scaled down version of printf(3).
30049062Sbostic *
30149062Sbostic * Two additional formats:
30249062Sbostic *
30349062Sbostic * The format %b is supported to decode error registers.
30449062Sbostic * Its usage is:
30549062Sbostic *
30652392Smarc * printf("reg=%b\n", regval, "<base><arg>*");
30749062Sbostic *
30849062Sbostic * where <base> is the output base expressed as a control character, e.g.
30949062Sbostic * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
31049062Sbostic * the first of which gives the bit number to be inspected (origin 1), and
31149062Sbostic * the next characters (up to a control character, i.e. a character <= 32),
31249062Sbostic * give the name of the register. Thus:
31349062Sbostic *
31451768Smarc * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
31549062Sbostic *
31649062Sbostic * would produce output:
31749062Sbostic *
31849062Sbostic * reg=3<BITTWO,BITONE>
31949062Sbostic *
32051768Smarc * The format %r passes an additional format string and argument list
32151768Smarc * recursively. Its usage is:
32249062Sbostic *
32351768Smarc * fn(char *fmt, ...)
32449953Sbostic * {
32549953Sbostic * va_list ap;
32649953Sbostic * va_start(ap, fmt);
32752392Smarc * printf("prefix: %r: suffix\n", fmt, ap);
32849953Sbostic * va_end(ap);
32951768Smarc * }
33049908Sbostic *
33149908Sbostic * Space or zero padding and a field width are supported for the numeric
33249908Sbostic * formats only.
3332781Swnj */
33449909Sbostic void
kprintf(fmt,flags,tp,ap)33552392Smarc kprintf(fmt, flags, tp, ap)
33649094Sbostic register const char *fmt;
33749062Sbostic int flags;
33849094Sbostic struct tty *tp;
33949062Sbostic va_list ap;
34031Sbill {
34152877Skarels register char *p, *q;
34249062Sbostic register int ch, n;
34349908Sbostic u_long ul;
34449908Sbostic int base, lflag, tmp, width;
34549908Sbostic char padc;
34631Sbill
34749062Sbostic for (;;) {
34849908Sbostic padc = ' ';
34949908Sbostic width = 0;
35049919Skarels while ((ch = *(u_char *)fmt++) != '%') {
35149062Sbostic if (ch == '\0')
35249062Sbostic return;
35349094Sbostic putchar(ch, flags, tp);
35429946Skarels }
35549062Sbostic lflag = 0;
35649919Skarels reswitch: switch (ch = *(u_char *)fmt++) {
35749908Sbostic case '0':
35849908Sbostic padc = '0';
35949908Sbostic goto reswitch;
36049908Sbostic case '1': case '2': case '3': case '4':
36149908Sbostic case '5': case '6': case '7': case '8': case '9':
36249908Sbostic for (width = 0;; ++fmt) {
36349908Sbostic width = width * 10 + ch - '0';
36449908Sbostic ch = *fmt;
36549908Sbostic if (ch < '0' || ch > '9')
36649908Sbostic break;
36749908Sbostic }
36849908Sbostic goto reswitch;
36949062Sbostic case 'l':
37049062Sbostic lflag = 1;
37149062Sbostic goto reswitch;
37249062Sbostic case 'b':
37349062Sbostic ul = va_arg(ap, int);
37449062Sbostic p = va_arg(ap, char *);
37552877Skarels for (q = ksprintn(ul, *p++, NULL); ch = *q--;)
37649908Sbostic putchar(ch, flags, tp);
37731Sbill
37849062Sbostic if (!ul)
37949062Sbostic break;
3802377Swnj
38149908Sbostic for (tmp = 0; n = *p++;) {
38249062Sbostic if (ul & (1 << (n - 1))) {
38349908Sbostic putchar(tmp ? ',' : '<', flags, tp);
38449062Sbostic for (; (n = *p) > ' '; ++p)
38549094Sbostic putchar(n, flags, tp);
38649908Sbostic tmp = 1;
38749062Sbostic } else
38852911Storek for (; *p > ' '; ++p)
38952911Storek continue;
39049062Sbostic }
39149908Sbostic if (tmp)
39249094Sbostic putchar('>', flags, tp);
39349062Sbostic break;
39449062Sbostic case 'c':
39549094Sbostic putchar(va_arg(ap, int), flags, tp);
39649062Sbostic break;
39749062Sbostic case 'r':
39849062Sbostic p = va_arg(ap, char *);
39949094Sbostic kprintf(p, flags, tp, va_arg(ap, va_list));
40049062Sbostic break;
40149062Sbostic case 's':
40249062Sbostic p = va_arg(ap, char *);
40349062Sbostic while (ch = *p++)
40449094Sbostic putchar(ch, flags, tp);
40549062Sbostic break;
40649062Sbostic case 'd':
40749908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
40849062Sbostic if ((long)ul < 0) {
40949094Sbostic putchar('-', flags, tp);
41049062Sbostic ul = -(long)ul;
41149062Sbostic }
41249908Sbostic base = 10;
41349908Sbostic goto number;
41449062Sbostic case 'o':
41549908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
41649908Sbostic base = 8;
41749953Sbostic goto number;
41849062Sbostic case 'u':
41949908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
42049908Sbostic base = 10;
42149908Sbostic goto number;
42249062Sbostic case 'x':
42349908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
42449908Sbostic base = 16;
42549908Sbostic number: p = ksprintn(ul, base, &tmp);
42649908Sbostic if (width && (width -= tmp) > 0)
42749908Sbostic while (width--)
42849908Sbostic putchar(padc, flags, tp);
42949908Sbostic while (ch = *p--)
43049908Sbostic putchar(ch, flags, tp);
43149062Sbostic break;
43249062Sbostic default:
43349094Sbostic putchar('%', flags, tp);
43449062Sbostic if (lflag)
43549094Sbostic putchar('l', flags, tp);
43649908Sbostic /* FALLTHROUGH */
43749908Sbostic case '%':
43849094Sbostic putchar(ch, flags, tp);
43949062Sbostic }
44030625Skarels }
44131Sbill }
44231Sbill
4432941Swnj /*
44449062Sbostic * Print a character on console or users terminal. If destination is
44549062Sbostic * the console then the last MSGBUFS characters are saved in msgbuf for
44649062Sbostic * inspection later.
447285Sbill */
44849062Sbostic static void
putchar(c,flags,tp)44949094Sbostic putchar(c, flags, tp)
4502377Swnj register int c;
45149062Sbostic int flags;
45249094Sbostic struct tty *tp;
453285Sbill {
45433479Skarels extern int msgbufmapped;
45550268Sbostic register struct msgbuf *mbp;
456285Sbill
45730549Skarels if (panicstr)
45849062Sbostic constty = NULL;
45949094Sbostic if ((flags & TOCONS) && tp == NULL && constty) {
46049094Sbostic tp = constty;
46130549Skarels flags |= TOTTY;
46230549Skarels }
46349094Sbostic if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
46449094Sbostic (flags & TOCONS) && tp == constty)
46549062Sbostic constty = NULL;
46649062Sbostic if ((flags & TOLOG) &&
46749062Sbostic c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
46850268Sbostic mbp = msgbufp;
46945733Smckusick if (mbp->msg_magic != MSG_MAGIC) {
47049953Sbostic bzero((caddr_t)mbp, sizeof(*mbp));
47145733Smckusick mbp->msg_magic = MSG_MAGIC;
4722172Swnj }
47345733Smckusick mbp->msg_bufc[mbp->msg_bufx++] = c;
47445733Smckusick if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
47545733Smckusick mbp->msg_bufx = 0;
476*69241Smckusick /* If the buffer is full, keep the most recent data. */
477*69241Smckusick if (mbp->msg_bufr == mbp->msg_bufx) {
478*69241Smckusick if (++mbp->msg_bufr >= MSG_BSIZE)
479*69241Smckusick mbp->msg_bufr = 0;
480*69241Smckusick }
481285Sbill }
48249062Sbostic if ((flags & TOCONS) && constty == NULL && c != '\0')
48330549Skarels (*v_putc)(c);
484285Sbill }
48549908Sbostic
48649908Sbostic /*
48749908Sbostic * Scaled down version of sprintf(3).
48849908Sbostic */
48949908Sbostic #ifdef __STDC__
sprintf(char * buf,const char * cfmt,...)49049919Skarels sprintf(char *buf, const char *cfmt, ...)
49149908Sbostic #else
49251767Smarc sprintf(buf, cfmt, va_alist)
49349919Skarels char *buf, *cfmt;
49449908Sbostic #endif
49549908Sbostic {
49649919Skarels register const char *fmt = cfmt;
49749908Sbostic register char *p, *bp;
49849908Sbostic register int ch, base;
49949908Sbostic u_long ul;
50049908Sbostic int lflag;
50149908Sbostic va_list ap;
50249908Sbostic
50349919Skarels va_start(ap, cfmt);
50449919Skarels for (bp = buf; ; ) {
50549919Skarels while ((ch = *(u_char *)fmt++) != '%')
50649908Sbostic if ((*bp++ = ch) == '\0')
50749919Skarels return ((bp - buf) - 1);
50849919Skarels
50949908Sbostic lflag = 0;
51049919Skarels reswitch: switch (ch = *(u_char *)fmt++) {
51149908Sbostic case 'l':
51249908Sbostic lflag = 1;
51349908Sbostic goto reswitch;
51449908Sbostic case 'c':
51549908Sbostic *bp++ = va_arg(ap, int);
51649908Sbostic break;
51749908Sbostic case 's':
51849908Sbostic p = va_arg(ap, char *);
51949919Skarels while (*bp++ = *p++)
52052392Smarc continue;
52149908Sbostic --bp;
52249908Sbostic break;
52349908Sbostic case 'd':
52449908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
52549908Sbostic if ((long)ul < 0) {
52649908Sbostic *bp++ = '-';
52749908Sbostic ul = -(long)ul;
52849908Sbostic }
52949908Sbostic base = 10;
53049908Sbostic goto number;
53149908Sbostic break;
53249908Sbostic case 'o':
53349908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
53449908Sbostic base = 8;
53549908Sbostic goto number;
53649908Sbostic break;
53749908Sbostic case 'u':
53849908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
53949908Sbostic base = 10;
54049908Sbostic goto number;
54149908Sbostic break;
54249908Sbostic case 'x':
54349908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
54449908Sbostic base = 16;
54549908Sbostic number: for (p = ksprintn(ul, base, NULL); ch = *p--;)
54649908Sbostic *bp++ = ch;
54749908Sbostic break;
54849908Sbostic default:
54949908Sbostic *bp++ = '%';
55049908Sbostic if (lflag)
55149908Sbostic *bp++ = 'l';
55249908Sbostic /* FALLTHROUGH */
55349908Sbostic case '%':
55449908Sbostic *bp++ = ch;
55549908Sbostic }
55649908Sbostic }
55749908Sbostic va_end(ap);
55849908Sbostic }
55949908Sbostic
56049908Sbostic /*
56149908Sbostic * Put a number (base <= 16) in a buffer in reverse order; return an
56249908Sbostic * optional length and a pointer to the NULL terminated (preceded?)
56349908Sbostic * buffer.
56449908Sbostic */
56549908Sbostic static char *
ksprintn(ul,base,lenp)56649908Sbostic ksprintn(ul, base, lenp)
56749908Sbostic register u_long ul;
56849908Sbostic register int base, *lenp;
56949908Sbostic { /* A long in base 8, plus NULL. */
57049908Sbostic static char buf[sizeof(long) * NBBY / 3 + 2];
57149908Sbostic register char *p;
57249908Sbostic
57349908Sbostic p = buf;
57449908Sbostic do {
57549908Sbostic *++p = "0123456789abcdef"[ul % base];
57649908Sbostic } while (ul /= base);
57749908Sbostic if (lenp)
57849908Sbostic *lenp = p - buf;
57949919Skarels return (p);
58049908Sbostic }
581