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*51768Smarc * @(#)subr_prf.c 7.33 (Berkeley) 11/20/91 823381Smckusick */ 931Sbill 10*51768Smarc #include <sys/param.h> 11*51768Smarc #include <sys/systm.h> 12*51768Smarc #include <sys/buf.h> 13*51768Smarc #include <sys/conf.h> 14*51768Smarc #include <sys/reboot.h> 15*51768Smarc #include <sys/msgbuf.h> 16*51768Smarc #include <sys/proc.h> 17*51768Smarc #include <sys/ioctl.h> 18*51768Smarc #include <sys/vnode.h> 19*51768Smarc #include <sys/file.h> 20*51768Smarc #include <sys/tty.h> 21*51768Smarc #include <sys/tprintf.h> 22*51768Smarc #include <sys/syslog.h> 23*51768Smarc #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 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 */ 4849953Sbostic int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 4940808Smarc 50*51768Smarc 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)); 53*51768Smarc void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap, ...)); 5449062Sbostic 55*51768Smarc int consintr = 1; /* Ok to handle console interrupts? */ 56*51768Smarc 5731Sbill /* 58*51768Smarc * Variable panicstr contains argument to first call to panic; used as flag 59*51768Smarc * to indicate that the kernel has already called panic. 6031Sbill */ 61*51768Smarc const char *panicstr; 6229946Skarels 6349062Sbostic /* 6449062Sbostic * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 6549062Sbostic * and then reboots. If we are called twice, then we avoid trying to sync 6649062Sbostic * the disks as this often leads to recursive panics. 6749062Sbostic */ 6849062Sbostic void 69*51768Smarc #ifdef __STDC__ 70*51768Smarc panic(const char *fmt, ...) 71*51768Smarc #else 72*51768Smarc panic(fmt /*, va_alist */) 73*51768Smarc char *fmt; 74*51768Smarc #endif 7549062Sbostic { 76*51768Smarc int bootopt, savintr; 77*51768Smarc va_list ap; 7848426Skarels 79*51768Smarc bootopt = RB_AUTOBOOT | RB_DUMP; 8049062Sbostic if (panicstr) 8149062Sbostic bootopt |= RB_NOSYNC; 8249062Sbostic else 83*51768Smarc panicstr = fmt; 84*51768Smarc 85*51768Smarc savintr = consintr; /* disable interrupts */ 86*51768Smarc consintr = 0; 87*51768Smarc 88*51768Smarc va_start(ap, fmt); 89*51768Smarc kprintf("panic: ", TOCONS | TOLOG, NULL, ap); 90*51768Smarc kprintf(fmt, TOCONS | TOLOG, NULL, ap); 91*51768Smarc va_end(ap); 92*51768Smarc 93*51768Smarc consintr = savintr; /* reenable interrupts */ 94*51768Smarc 9549062Sbostic #ifdef KGDB 9649062Sbostic kgdb_panic(); 9749062Sbostic #endif 9849062Sbostic #ifdef KADB 9949062Sbostic if (boothowto & RB_KDB) { 10050268Sbostic int s; 10150268Sbostic 10250268Sbostic s = splnet(); /* below kdb pri */ 10349062Sbostic setsoftkdb(); 10449062Sbostic splx(s); 10549062Sbostic } 10649062Sbostic #endif 10749062Sbostic boot(bootopt); 10849062Sbostic } 10949062Sbostic 11049062Sbostic /* 11149062Sbostic * Warn that a system table is full. 11249062Sbostic */ 11349062Sbostic void 11449062Sbostic tablefull(tab) 11549062Sbostic char *tab; 11631Sbill { 117285Sbill 11849062Sbostic log(LOG_ERR, "%s: table is full\n", tab); 119285Sbill } 120285Sbill 1212377Swnj /* 12239560Smarc * Uprintf prints to the controlling terminal for the current process. 12349062Sbostic * It may block if the tty queue is overfull. No message is printed if 12449062Sbostic * the queue does not clear in a reasonable time. 1252377Swnj */ 12649062Sbostic void 12749062Sbostic #ifdef __STDC__ 12849062Sbostic uprintf(const char *fmt, ...) 12949062Sbostic #else 13051767Smarc uprintf(fmt, va_alist) 1312781Swnj char *fmt; 13249062Sbostic #endif 133285Sbill { 13447540Skarels register struct proc *p = curproc; 13549062Sbostic va_list ap; 136285Sbill 13749953Sbostic if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 13849953Sbostic va_start(ap, fmt); 13949062Sbostic kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 14049953Sbostic va_end(ap); 14149953Sbostic } 142285Sbill } 143285Sbill 14444386Smarc tpr_t 14548426Skarels tprintf_open(p) 14648426Skarels register struct proc *p; 14744386Smarc { 14849953Sbostic 14944386Smarc if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 15044386Smarc SESSHOLD(p->p_session); 15148426Skarels return ((tpr_t) p->p_session); 15249062Sbostic } 15349062Sbostic return ((tpr_t) NULL); 15444386Smarc } 15544386Smarc 15648426Skarels void 15744386Smarc tprintf_close(sess) 15844386Smarc tpr_t sess; 15944386Smarc { 16049953Sbostic 16144386Smarc if (sess) 16248426Skarels SESSRELE((struct session *) sess); 16344386Smarc } 16444386Smarc 16518364Skarels /* 16644386Smarc * tprintf prints on the controlling terminal associated 16749062Sbostic * with the given session. 16818364Skarels */ 16949062Sbostic void 17049062Sbostic #ifdef __STDC__ 17149062Sbostic tprintf(tpr_t tpr, const char *fmt, ...) 17249062Sbostic #else 17351767Smarc tprintf(tpr, fmt, va_alist) 17448426Skarels tpr_t tpr; 17516724Sralph char *fmt; 17649062Sbostic #endif 17716724Sralph { 17848426Skarels register struct session *sess = (struct session *)tpr; 17948426Skarels struct tty *tp = NULL; 18044386Smarc int flags = TOLOG; 18149062Sbostic va_list ap; 18216724Sralph 18325389Skarels logpri(LOG_INFO); 18448426Skarels if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 18544386Smarc flags |= TOTTY; 18648426Skarels tp = sess->s_ttyp; 18748426Skarels } 18849062Sbostic va_start(ap, fmt); 18949062Sbostic kprintf(fmt, flags, tp, ap); 19049062Sbostic va_end(ap); 19125389Skarels logwakeup(); 19216724Sralph } 19316724Sralph 19449062Sbostic /* 19549062Sbostic * Ttyprintf displays a message on a tty; it should be used only by 19649062Sbostic * the tty driver, or anything that knows the underlying tty will not 19749062Sbostic * be revoke(2)'d away. Other callers should use tprintf. 19849062Sbostic */ 19949062Sbostic void 20049062Sbostic #ifdef __STDC__ 20149062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...) 20249062Sbostic #else 20351767Smarc ttyprintf(tp, fmt, va_alist) 20449062Sbostic struct tty *tp; 20549062Sbostic char *fmt; 20649062Sbostic #endif 20749062Sbostic { 20849062Sbostic va_list ap; 20949062Sbostic 21049062Sbostic va_start(ap, fmt); 21149062Sbostic kprintf(fmt, TOTTY, tp, ap); 21249062Sbostic va_end(ap); 21349062Sbostic } 21449062Sbostic 21548426Skarels extern int log_open; 21644386Smarc 21716724Sralph /* 21849062Sbostic * Log writes to the log buffer, and guarantees not to sleep (so can be 21949062Sbostic * called by interrupt routines). If there is no process reading the 22049062Sbostic * log yet, it writes to the console also. 22116724Sralph */ 22249062Sbostic void 22349062Sbostic #ifdef __STDC__ 22449062Sbostic log(int level, const char *fmt, ...) 22549062Sbostic #else 22651767Smarc log(level, fmt, va_alist) 22749062Sbostic int level; 22816724Sralph char *fmt; 22949062Sbostic #endif 23016724Sralph { 23150268Sbostic register int s; 23249062Sbostic va_list ap; 23316724Sralph 23450268Sbostic s = splhigh(); 23525389Skarels logpri(level); 23649062Sbostic va_start(ap, fmt); 23749062Sbostic kprintf(fmt, TOLOG, NULL, ap); 23816724Sralph splx(s); 23949953Sbostic va_end(ap); 24049953Sbostic if (!log_open) { 24149953Sbostic va_start(ap, fmt); 24249062Sbostic kprintf(fmt, TOCONS, NULL, ap); 24349953Sbostic va_end(ap); 24449953Sbostic } 24516724Sralph logwakeup(); 24616724Sralph } 24716724Sralph 248*51768Smarc void 24925389Skarels logpri(level) 25025389Skarels int level; 25125389Skarels { 25249908Sbostic register int ch; 25349908Sbostic register char *p; 25425389Skarels 25549062Sbostic putchar('<', TOLOG, NULL); 25649908Sbostic for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 25749908Sbostic putchar(ch, TOLOG, NULL); 25849062Sbostic putchar('>', TOLOG, NULL); 25925389Skarels } 26025389Skarels 26149062Sbostic void 26249062Sbostic #ifdef __STDC__ 26349062Sbostic addlog(const char *fmt, ...) 26449062Sbostic #else 26551767Smarc addlog(fmt, va_alist) 26633479Skarels char *fmt; 26749062Sbostic #endif 26833479Skarels { 26950268Sbostic register int s; 27049062Sbostic va_list ap; 27133479Skarels 27250268Sbostic s = splhigh(); 27349062Sbostic va_start(ap, fmt); 27449062Sbostic kprintf(fmt, TOLOG, NULL, ap); 27533479Skarels splx(s); 27649953Sbostic va_end(ap); 27749953Sbostic if (!log_open) { 27849953Sbostic va_start(ap, fmt); 27949062Sbostic kprintf(fmt, TOCONS, NULL, ap); 28049953Sbostic va_end(ap); 28149953Sbostic } 28233479Skarels logwakeup(); 28333479Skarels } 28433479Skarels 28549062Sbostic void 28649062Sbostic #ifdef __STDC__ 28749062Sbostic printf(const char *fmt, ...) 28849062Sbostic #else 28951767Smarc printf(fmt, va_alist) 29049062Sbostic char *fmt; 29129946Skarels #endif 29249062Sbostic { 29349953Sbostic va_list ap; 29449062Sbostic register int savintr; 2952678Swnj 29649062Sbostic savintr = consintr; /* disable interrupts */ 29749062Sbostic consintr = 0; 29849062Sbostic va_start(ap, fmt); 29949062Sbostic kprintf(fmt, TOCONS | TOLOG, NULL, ap); 30049062Sbostic va_end(ap); 30149062Sbostic if (!panicstr) 30249062Sbostic logwakeup(); 30349062Sbostic consintr = savintr; /* reenable interrupts */ 30431Sbill } 30531Sbill 3062781Swnj /* 30749062Sbostic * Scaled down version of printf(3). 30849062Sbostic * 30949062Sbostic * Two additional formats: 31049062Sbostic * 31149062Sbostic * The format %b is supported to decode error registers. 31249062Sbostic * Its usage is: 31349062Sbostic * 314*51768Smarc * kprintf("reg=%b\n", regval, "<base><arg>*"); 31549062Sbostic * 31649062Sbostic * where <base> is the output base expressed as a control character, e.g. 31749062Sbostic * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 31849062Sbostic * the first of which gives the bit number to be inspected (origin 1), and 31949062Sbostic * the next characters (up to a control character, i.e. a character <= 32), 32049062Sbostic * give the name of the register. Thus: 32149062Sbostic * 322*51768Smarc * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 32349062Sbostic * 32449062Sbostic * would produce output: 32549062Sbostic * 32649062Sbostic * reg=3<BITTWO,BITONE> 32749062Sbostic * 328*51768Smarc * The format %r passes an additional format string and argument list 329*51768Smarc * recursively. Its usage is: 33049062Sbostic * 331*51768Smarc * fn(char *fmt, ...) 33249953Sbostic * { 33349953Sbostic * va_list ap; 33449953Sbostic * va_start(ap, fmt); 335*51768Smarc * kprintf("prefix: %r: suffix\n", flags, tp, fmt, ap); 33649953Sbostic * va_end(ap); 337*51768Smarc * } 33849908Sbostic * 33949908Sbostic * Space or zero padding and a field width are supported for the numeric 34049908Sbostic * formats only. 3412781Swnj */ 34249909Sbostic void 343*51768Smarc #ifdef __STDC__ 344*51768Smarc kprintf(const char *fmt, int flags, struct tty *tp, va_list ap, ...) 345*51768Smarc #else 346*51768Smarc kprintf(fmt, flags, tp) 34749094Sbostic register const char *fmt; 34849062Sbostic int flags; 34949094Sbostic struct tty *tp; 35049062Sbostic va_list ap; 351*51768Smarc #endif 35231Sbill { 35349062Sbostic register char *p; 35449062Sbostic register int ch, n; 35549908Sbostic u_long ul; 35649908Sbostic int base, lflag, tmp, width; 35749908Sbostic char padc; 35831Sbill 35949062Sbostic for (;;) { 36049908Sbostic padc = ' '; 36149908Sbostic width = 0; 36249919Skarels while ((ch = *(u_char *)fmt++) != '%') { 36349062Sbostic if (ch == '\0') 36449062Sbostic return; 36549094Sbostic putchar(ch, flags, tp); 36629946Skarels } 36749062Sbostic lflag = 0; 36849919Skarels reswitch: switch (ch = *(u_char *)fmt++) { 36949908Sbostic case '0': 37049908Sbostic padc = '0'; 37149908Sbostic goto reswitch; 37249908Sbostic case '1': case '2': case '3': case '4': 37349908Sbostic case '5': case '6': case '7': case '8': case '9': 37449908Sbostic for (width = 0;; ++fmt) { 37549908Sbostic width = width * 10 + ch - '0'; 37649908Sbostic ch = *fmt; 37749908Sbostic if (ch < '0' || ch > '9') 37849908Sbostic break; 37949908Sbostic } 38049908Sbostic goto reswitch; 38149062Sbostic case 'l': 38249062Sbostic lflag = 1; 38349062Sbostic goto reswitch; 38449062Sbostic case 'b': 38549062Sbostic ul = va_arg(ap, int); 38649062Sbostic p = va_arg(ap, char *); 38749908Sbostic for (p = ksprintn(ul, *p++, NULL); ch = *p--;) 38849908Sbostic putchar(ch, flags, tp); 38931Sbill 39049062Sbostic if (!ul) 39149062Sbostic break; 3922377Swnj 39349908Sbostic for (tmp = 0; n = *p++;) { 39449062Sbostic if (ul & (1 << (n - 1))) { 39549908Sbostic putchar(tmp ? ',' : '<', flags, tp); 39649062Sbostic for (; (n = *p) > ' '; ++p) 39749094Sbostic putchar(n, flags, tp); 39849908Sbostic tmp = 1; 39949062Sbostic } else 40049062Sbostic for (; *p > ' '; ++p); 40149062Sbostic } 40249908Sbostic if (tmp) 40349094Sbostic putchar('>', flags, tp); 40449062Sbostic break; 40549062Sbostic case 'c': 40649094Sbostic putchar(va_arg(ap, int), flags, tp); 40749062Sbostic break; 40849062Sbostic case 'r': 40949062Sbostic p = va_arg(ap, char *); 41049094Sbostic kprintf(p, flags, tp, va_arg(ap, va_list)); 41149062Sbostic break; 41249062Sbostic case 's': 41349062Sbostic p = va_arg(ap, char *); 41449062Sbostic while (ch = *p++) 41549094Sbostic putchar(ch, flags, tp); 41649062Sbostic break; 41749062Sbostic case 'd': 41849908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 41949062Sbostic if ((long)ul < 0) { 42049094Sbostic putchar('-', flags, tp); 42149062Sbostic ul = -(long)ul; 42249062Sbostic } 42349908Sbostic base = 10; 42449908Sbostic goto number; 42549062Sbostic case 'o': 42649908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 42749908Sbostic base = 8; 42849953Sbostic goto number; 42949062Sbostic case 'u': 43049908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 43149908Sbostic base = 10; 43249908Sbostic goto number; 43349062Sbostic case 'x': 43449908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 43549908Sbostic base = 16; 43649908Sbostic number: p = ksprintn(ul, base, &tmp); 43749908Sbostic if (width && (width -= tmp) > 0) 43849908Sbostic while (width--) 43949908Sbostic putchar(padc, flags, tp); 44049908Sbostic while (ch = *p--) 44149908Sbostic putchar(ch, flags, tp); 44249062Sbostic break; 44349062Sbostic default: 44449094Sbostic putchar('%', flags, tp); 44549062Sbostic if (lflag) 44649094Sbostic putchar('l', flags, tp); 44749908Sbostic /* FALLTHROUGH */ 44849908Sbostic case '%': 44949094Sbostic putchar(ch, flags, tp); 45049062Sbostic } 45130625Skarels } 45231Sbill } 45331Sbill 4542941Swnj /* 45549062Sbostic * Print a character on console or users terminal. If destination is 45649062Sbostic * the console then the last MSGBUFS characters are saved in msgbuf for 45749062Sbostic * inspection later. 458285Sbill */ 45949062Sbostic static void 46049094Sbostic putchar(c, flags, tp) 4612377Swnj register int c; 46249062Sbostic int flags; 46349094Sbostic struct tty *tp; 464285Sbill { 46533479Skarels extern int msgbufmapped; 46650268Sbostic register struct msgbuf *mbp; 467285Sbill 46830549Skarels if (panicstr) 46949062Sbostic constty = NULL; 47049094Sbostic if ((flags & TOCONS) && tp == NULL && constty) { 47149094Sbostic tp = constty; 47230549Skarels flags |= TOTTY; 47330549Skarels } 47449094Sbostic if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 47549094Sbostic (flags & TOCONS) && tp == constty) 47649062Sbostic constty = NULL; 47749062Sbostic if ((flags & TOLOG) && 47849062Sbostic c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 47950268Sbostic mbp = msgbufp; 48045733Smckusick if (mbp->msg_magic != MSG_MAGIC) { 48149953Sbostic bzero((caddr_t)mbp, sizeof(*mbp)); 48245733Smckusick mbp->msg_magic = MSG_MAGIC; 4832172Swnj } 48445733Smckusick mbp->msg_bufc[mbp->msg_bufx++] = c; 48545733Smckusick if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 48645733Smckusick mbp->msg_bufx = 0; 487285Sbill } 48849062Sbostic if ((flags & TOCONS) && constty == NULL && c != '\0') 48930549Skarels (*v_putc)(c); 490285Sbill } 49149908Sbostic 49249908Sbostic /* 49349908Sbostic * Scaled down version of sprintf(3). 49449908Sbostic */ 49549908Sbostic #ifdef __STDC__ 49649919Skarels sprintf(char *buf, const char *cfmt, ...) 49749908Sbostic #else 49851767Smarc sprintf(buf, cfmt, va_alist) 49949919Skarels char *buf, *cfmt; 50049908Sbostic #endif 50149908Sbostic { 50249919Skarels register const char *fmt = cfmt; 50349908Sbostic register char *p, *bp; 50449908Sbostic register int ch, base; 50549908Sbostic u_long ul; 50649908Sbostic int lflag; 50749908Sbostic va_list ap; 50849908Sbostic 50949919Skarels va_start(ap, cfmt); 51049919Skarels for (bp = buf; ; ) { 51149919Skarels while ((ch = *(u_char *)fmt++) != '%') 51249908Sbostic if ((*bp++ = ch) == '\0') 51349919Skarels return ((bp - buf) - 1); 51449919Skarels 51549908Sbostic lflag = 0; 51649919Skarels reswitch: switch (ch = *(u_char *)fmt++) { 51749908Sbostic case 'l': 51849908Sbostic lflag = 1; 51949908Sbostic goto reswitch; 52049908Sbostic case 'c': 52149908Sbostic *bp++ = va_arg(ap, int); 52249908Sbostic break; 52349908Sbostic case 's': 52449908Sbostic p = va_arg(ap, char *); 52549919Skarels while (*bp++ = *p++) 52649919Skarels ; 52749908Sbostic --bp; 52849908Sbostic break; 52949908Sbostic case 'd': 53049908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 53149908Sbostic if ((long)ul < 0) { 53249908Sbostic *bp++ = '-'; 53349908Sbostic ul = -(long)ul; 53449908Sbostic } 53549908Sbostic base = 10; 53649908Sbostic goto number; 53749908Sbostic break; 53849908Sbostic case 'o': 53949908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 54049908Sbostic base = 8; 54149908Sbostic goto number; 54249908Sbostic break; 54349908Sbostic case 'u': 54449908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 54549908Sbostic base = 10; 54649908Sbostic goto number; 54749908Sbostic break; 54849908Sbostic case 'x': 54949908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 55049908Sbostic base = 16; 55149908Sbostic number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 55249908Sbostic *bp++ = ch; 55349908Sbostic break; 55449908Sbostic default: 55549908Sbostic *bp++ = '%'; 55649908Sbostic if (lflag) 55749908Sbostic *bp++ = 'l'; 55849908Sbostic /* FALLTHROUGH */ 55949908Sbostic case '%': 56049908Sbostic *bp++ = ch; 56149908Sbostic } 56249908Sbostic } 56349908Sbostic va_end(ap); 56449908Sbostic } 56549908Sbostic 56649908Sbostic /* 56749908Sbostic * Put a number (base <= 16) in a buffer in reverse order; return an 56849908Sbostic * optional length and a pointer to the NULL terminated (preceded?) 56949908Sbostic * buffer. 57049908Sbostic */ 57149908Sbostic static char * 57249908Sbostic ksprintn(ul, base, lenp) 57349908Sbostic register u_long ul; 57449908Sbostic register int base, *lenp; 57549908Sbostic { /* A long in base 8, plus NULL. */ 57649908Sbostic static char buf[sizeof(long) * NBBY / 3 + 2]; 57749908Sbostic register char *p; 57849908Sbostic 57949908Sbostic p = buf; 58049908Sbostic do { 58149908Sbostic *++p = "0123456789abcdef"[ul % base]; 58249908Sbostic } while (ul /= base); 58349908Sbostic if (lenp) 58449908Sbostic *lenp = p - buf; 58549919Skarels return (p); 58649908Sbostic } 587