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*52406Smckusick * @(#)subr_prf.c 7.35 (Berkeley) 02/05/92 823381Smckusick */ 931Sbill 1051768Smarc #include <sys/param.h> 1151768Smarc #include <sys/systm.h> 1251768Smarc #include <sys/buf.h> 1351768Smarc #include <sys/conf.h> 1451768Smarc #include <sys/reboot.h> 1551768Smarc #include <sys/msgbuf.h> 1651768Smarc #include <sys/proc.h> 1751768Smarc #include <sys/ioctl.h> 1851768Smarc #include <sys/vnode.h> 1951768Smarc #include <sys/file.h> 2051768Smarc #include <sys/tty.h> 2151768Smarc #include <sys/tprintf.h> 2251768Smarc #include <sys/syslog.h> 2351768Smarc #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 5051768Smarc 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)); 5352392Smarc void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap)); 5449062Sbostic 5551768Smarc int consintr = 1; /* Ok to handle console interrupts? */ 5651768Smarc 5731Sbill /* 5851768Smarc * Variable panicstr contains argument to first call to panic; used as flag 5951768Smarc * to indicate that the kernel has already called panic. 6031Sbill */ 6151768Smarc 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 */ 6852392Smarc #ifdef __GNUC__ 69*52406Smckusick volatile void boot(int flags); /* boot() does not return */ 7052392Smarc volatile /* panic() does not return */ 7152392Smarc #endif 7249062Sbostic void 7351768Smarc #ifdef __STDC__ 7451768Smarc panic(const char *fmt, ...) 7551768Smarc #else 7651768Smarc panic(fmt /*, va_alist */) 7751768Smarc char *fmt; 7851768Smarc #endif 7949062Sbostic { 8052392Smarc int bootopt; 8151768Smarc va_list ap; 8248426Skarels 8351768Smarc bootopt = RB_AUTOBOOT | RB_DUMP; 8449062Sbostic if (panicstr) 8549062Sbostic bootopt |= RB_NOSYNC; 8649062Sbostic else 8751768Smarc panicstr = fmt; 8851768Smarc 8951768Smarc va_start(ap, fmt); 9052392Smarc printf("panic: %r\n", fmt, ap); 9151768Smarc va_end(ap); 9251768Smarc 9349062Sbostic #ifdef KGDB 9449062Sbostic kgdb_panic(); 9549062Sbostic #endif 9649062Sbostic #ifdef KADB 9749062Sbostic if (boothowto & RB_KDB) { 9850268Sbostic int s; 9950268Sbostic 10050268Sbostic s = splnet(); /* below kdb pri */ 10149062Sbostic setsoftkdb(); 10249062Sbostic splx(s); 10349062Sbostic } 10449062Sbostic #endif 10549062Sbostic boot(bootopt); 10649062Sbostic } 10749062Sbostic 10849062Sbostic /* 10949062Sbostic * Warn that a system table is full. 11049062Sbostic */ 11149062Sbostic void 11249062Sbostic tablefull(tab) 113*52406Smckusick const char *tab; 11431Sbill { 115285Sbill 11649062Sbostic log(LOG_ERR, "%s: table is full\n", tab); 117285Sbill } 118285Sbill 1192377Swnj /* 12039560Smarc * Uprintf prints to the controlling terminal for the current process. 12149062Sbostic * It may block if the tty queue is overfull. No message is printed if 12249062Sbostic * the queue does not clear in a reasonable time. 1232377Swnj */ 12449062Sbostic void 12549062Sbostic #ifdef __STDC__ 12649062Sbostic uprintf(const char *fmt, ...) 12749062Sbostic #else 12851767Smarc uprintf(fmt, va_alist) 1292781Swnj char *fmt; 13049062Sbostic #endif 131285Sbill { 13247540Skarels register struct proc *p = curproc; 13349062Sbostic va_list ap; 134285Sbill 13549953Sbostic if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 13649953Sbostic va_start(ap, fmt); 13749062Sbostic kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 13849953Sbostic va_end(ap); 13949953Sbostic } 140285Sbill } 141285Sbill 14244386Smarc tpr_t 14348426Skarels tprintf_open(p) 14448426Skarels register struct proc *p; 14544386Smarc { 14649953Sbostic 14744386Smarc if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 14844386Smarc SESSHOLD(p->p_session); 14948426Skarels return ((tpr_t) p->p_session); 15049062Sbostic } 15149062Sbostic return ((tpr_t) NULL); 15244386Smarc } 15344386Smarc 15448426Skarels void 15544386Smarc tprintf_close(sess) 15644386Smarc tpr_t sess; 15744386Smarc { 15849953Sbostic 15944386Smarc if (sess) 16048426Skarels SESSRELE((struct session *) sess); 16144386Smarc } 16244386Smarc 16318364Skarels /* 16444386Smarc * tprintf prints on the controlling terminal associated 16549062Sbostic * with the given session. 16618364Skarels */ 16749062Sbostic void 16849062Sbostic #ifdef __STDC__ 16949062Sbostic tprintf(tpr_t tpr, const char *fmt, ...) 17049062Sbostic #else 17151767Smarc tprintf(tpr, fmt, va_alist) 17248426Skarels tpr_t tpr; 17316724Sralph char *fmt; 17449062Sbostic #endif 17516724Sralph { 17648426Skarels register struct session *sess = (struct session *)tpr; 17748426Skarels struct tty *tp = NULL; 17844386Smarc int flags = TOLOG; 17949062Sbostic va_list ap; 18016724Sralph 18125389Skarels logpri(LOG_INFO); 18248426Skarels if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 18344386Smarc flags |= TOTTY; 18448426Skarels tp = sess->s_ttyp; 18548426Skarels } 18649062Sbostic va_start(ap, fmt); 18749062Sbostic kprintf(fmt, flags, tp, ap); 18849062Sbostic va_end(ap); 18925389Skarels logwakeup(); 19016724Sralph } 19116724Sralph 19249062Sbostic /* 19349062Sbostic * Ttyprintf displays a message on a tty; it should be used only by 19449062Sbostic * the tty driver, or anything that knows the underlying tty will not 19549062Sbostic * be revoke(2)'d away. Other callers should use tprintf. 19649062Sbostic */ 19749062Sbostic void 19849062Sbostic #ifdef __STDC__ 19949062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...) 20049062Sbostic #else 20151767Smarc ttyprintf(tp, fmt, va_alist) 20249062Sbostic struct tty *tp; 20349062Sbostic char *fmt; 20449062Sbostic #endif 20549062Sbostic { 20649062Sbostic va_list ap; 20749062Sbostic 20849062Sbostic va_start(ap, fmt); 20949062Sbostic kprintf(fmt, TOTTY, tp, ap); 21049062Sbostic va_end(ap); 21149062Sbostic } 21249062Sbostic 21348426Skarels extern int log_open; 21444386Smarc 21516724Sralph /* 21649062Sbostic * Log writes to the log buffer, and guarantees not to sleep (so can be 21749062Sbostic * called by interrupt routines). If there is no process reading the 21849062Sbostic * log yet, it writes to the console also. 21916724Sralph */ 22049062Sbostic void 22149062Sbostic #ifdef __STDC__ 22249062Sbostic log(int level, const char *fmt, ...) 22349062Sbostic #else 22451767Smarc log(level, fmt, va_alist) 22549062Sbostic int level; 22616724Sralph char *fmt; 22749062Sbostic #endif 22816724Sralph { 22950268Sbostic register int s; 23049062Sbostic va_list ap; 23116724Sralph 23250268Sbostic s = splhigh(); 23325389Skarels logpri(level); 23449062Sbostic va_start(ap, fmt); 23549062Sbostic kprintf(fmt, TOLOG, NULL, ap); 23616724Sralph splx(s); 23749953Sbostic va_end(ap); 23849953Sbostic if (!log_open) { 23949953Sbostic va_start(ap, fmt); 24049062Sbostic kprintf(fmt, TOCONS, NULL, ap); 24149953Sbostic va_end(ap); 24249953Sbostic } 24316724Sralph logwakeup(); 24416724Sralph } 24516724Sralph 24651768Smarc void 24725389Skarels logpri(level) 24825389Skarels int level; 24925389Skarels { 25049908Sbostic register int ch; 25149908Sbostic register char *p; 25225389Skarels 25349062Sbostic putchar('<', TOLOG, NULL); 25449908Sbostic for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 25549908Sbostic putchar(ch, TOLOG, NULL); 25649062Sbostic putchar('>', TOLOG, NULL); 25725389Skarels } 25825389Skarels 25949062Sbostic void 26049062Sbostic #ifdef __STDC__ 26149062Sbostic addlog(const char *fmt, ...) 26249062Sbostic #else 26351767Smarc addlog(fmt, va_alist) 26433479Skarels char *fmt; 26549062Sbostic #endif 26633479Skarels { 26750268Sbostic register int s; 26849062Sbostic va_list ap; 26933479Skarels 27050268Sbostic s = splhigh(); 27149062Sbostic va_start(ap, fmt); 27249062Sbostic kprintf(fmt, TOLOG, NULL, ap); 27333479Skarels splx(s); 27449953Sbostic va_end(ap); 27549953Sbostic if (!log_open) { 27649953Sbostic va_start(ap, fmt); 27749062Sbostic kprintf(fmt, TOCONS, NULL, ap); 27849953Sbostic va_end(ap); 27949953Sbostic } 28033479Skarels logwakeup(); 28133479Skarels } 28233479Skarels 28349062Sbostic void 28449062Sbostic #ifdef __STDC__ 28549062Sbostic printf(const char *fmt, ...) 28649062Sbostic #else 28751767Smarc printf(fmt, va_alist) 28849062Sbostic char *fmt; 28929946Skarels #endif 29049062Sbostic { 29149953Sbostic va_list ap; 29249062Sbostic register int savintr; 2932678Swnj 29449062Sbostic savintr = consintr; /* disable interrupts */ 29549062Sbostic consintr = 0; 29649062Sbostic va_start(ap, fmt); 29749062Sbostic kprintf(fmt, TOCONS | TOLOG, NULL, ap); 29849062Sbostic va_end(ap); 29949062Sbostic if (!panicstr) 30049062Sbostic logwakeup(); 30149062Sbostic consintr = savintr; /* reenable interrupts */ 30231Sbill } 30331Sbill 3042781Swnj /* 30549062Sbostic * Scaled down version of printf(3). 30649062Sbostic * 30749062Sbostic * Two additional formats: 30849062Sbostic * 30949062Sbostic * The format %b is supported to decode error registers. 31049062Sbostic * Its usage is: 31149062Sbostic * 31252392Smarc * printf("reg=%b\n", regval, "<base><arg>*"); 31349062Sbostic * 31449062Sbostic * where <base> is the output base expressed as a control character, e.g. 31549062Sbostic * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 31649062Sbostic * the first of which gives the bit number to be inspected (origin 1), and 31749062Sbostic * the next characters (up to a control character, i.e. a character <= 32), 31849062Sbostic * give the name of the register. Thus: 31949062Sbostic * 32051768Smarc * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 32149062Sbostic * 32249062Sbostic * would produce output: 32349062Sbostic * 32449062Sbostic * reg=3<BITTWO,BITONE> 32549062Sbostic * 32651768Smarc * The format %r passes an additional format string and argument list 32751768Smarc * recursively. Its usage is: 32849062Sbostic * 32951768Smarc * fn(char *fmt, ...) 33049953Sbostic * { 33149953Sbostic * va_list ap; 33249953Sbostic * va_start(ap, fmt); 33352392Smarc * printf("prefix: %r: suffix\n", fmt, ap); 33449953Sbostic * va_end(ap); 33551768Smarc * } 33649908Sbostic * 33749908Sbostic * Space or zero padding and a field width are supported for the numeric 33849908Sbostic * formats only. 3392781Swnj */ 34049909Sbostic void 34152392Smarc kprintf(fmt, flags, tp, ap) 34249094Sbostic register const char *fmt; 34349062Sbostic int flags; 34449094Sbostic struct tty *tp; 34549062Sbostic va_list ap; 34631Sbill { 34749062Sbostic register char *p; 34849062Sbostic register int ch, n; 34949908Sbostic u_long ul; 35049908Sbostic int base, lflag, tmp, width; 35149908Sbostic char padc; 35231Sbill 35349062Sbostic for (;;) { 35449908Sbostic padc = ' '; 35549908Sbostic width = 0; 35649919Skarels while ((ch = *(u_char *)fmt++) != '%') { 35749062Sbostic if (ch == '\0') 35849062Sbostic return; 35949094Sbostic putchar(ch, flags, tp); 36029946Skarels } 36149062Sbostic lflag = 0; 36249919Skarels reswitch: switch (ch = *(u_char *)fmt++) { 36349908Sbostic case '0': 36449908Sbostic padc = '0'; 36549908Sbostic goto reswitch; 36649908Sbostic case '1': case '2': case '3': case '4': 36749908Sbostic case '5': case '6': case '7': case '8': case '9': 36849908Sbostic for (width = 0;; ++fmt) { 36949908Sbostic width = width * 10 + ch - '0'; 37049908Sbostic ch = *fmt; 37149908Sbostic if (ch < '0' || ch > '9') 37249908Sbostic break; 37349908Sbostic } 37449908Sbostic goto reswitch; 37549062Sbostic case 'l': 37649062Sbostic lflag = 1; 37749062Sbostic goto reswitch; 37849062Sbostic case 'b': 37949062Sbostic ul = va_arg(ap, int); 38049062Sbostic p = va_arg(ap, char *); 38149908Sbostic for (p = ksprintn(ul, *p++, NULL); ch = *p--;) 38249908Sbostic putchar(ch, flags, tp); 38331Sbill 38449062Sbostic if (!ul) 38549062Sbostic break; 3862377Swnj 38749908Sbostic for (tmp = 0; n = *p++;) { 38849062Sbostic if (ul & (1 << (n - 1))) { 38949908Sbostic putchar(tmp ? ',' : '<', flags, tp); 39049062Sbostic for (; (n = *p) > ' '; ++p) 39149094Sbostic putchar(n, flags, tp); 39249908Sbostic tmp = 1; 39349062Sbostic } else 39449062Sbostic for (; *p > ' '; ++p); 39549062Sbostic } 39649908Sbostic if (tmp) 39749094Sbostic putchar('>', flags, tp); 39849062Sbostic break; 39949062Sbostic case 'c': 40049094Sbostic putchar(va_arg(ap, int), flags, tp); 40149062Sbostic break; 40249062Sbostic case 'r': 40349062Sbostic p = va_arg(ap, char *); 40449094Sbostic kprintf(p, flags, tp, va_arg(ap, va_list)); 40549062Sbostic break; 40649062Sbostic case 's': 40749062Sbostic p = va_arg(ap, char *); 40849062Sbostic while (ch = *p++) 40949094Sbostic putchar(ch, flags, tp); 41049062Sbostic break; 41149062Sbostic case 'd': 41249908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 41349062Sbostic if ((long)ul < 0) { 41449094Sbostic putchar('-', flags, tp); 41549062Sbostic ul = -(long)ul; 41649062Sbostic } 41749908Sbostic base = 10; 41849908Sbostic goto number; 41949062Sbostic case 'o': 42049908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 42149908Sbostic base = 8; 42249953Sbostic goto number; 42349062Sbostic case 'u': 42449908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 42549908Sbostic base = 10; 42649908Sbostic goto number; 42749062Sbostic case 'x': 42849908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 42949908Sbostic base = 16; 43049908Sbostic number: p = ksprintn(ul, base, &tmp); 43149908Sbostic if (width && (width -= tmp) > 0) 43249908Sbostic while (width--) 43349908Sbostic putchar(padc, flags, tp); 43449908Sbostic while (ch = *p--) 43549908Sbostic putchar(ch, flags, tp); 43649062Sbostic break; 43749062Sbostic default: 43849094Sbostic putchar('%', flags, tp); 43949062Sbostic if (lflag) 44049094Sbostic putchar('l', flags, tp); 44149908Sbostic /* FALLTHROUGH */ 44249908Sbostic case '%': 44349094Sbostic putchar(ch, flags, tp); 44449062Sbostic } 44530625Skarels } 44631Sbill } 44731Sbill 4482941Swnj /* 44949062Sbostic * Print a character on console or users terminal. If destination is 45049062Sbostic * the console then the last MSGBUFS characters are saved in msgbuf for 45149062Sbostic * inspection later. 452285Sbill */ 45349062Sbostic static void 45449094Sbostic putchar(c, flags, tp) 4552377Swnj register int c; 45649062Sbostic int flags; 45749094Sbostic struct tty *tp; 458285Sbill { 45933479Skarels extern int msgbufmapped; 46050268Sbostic register struct msgbuf *mbp; 461285Sbill 46230549Skarels if (panicstr) 46349062Sbostic constty = NULL; 46449094Sbostic if ((flags & TOCONS) && tp == NULL && constty) { 46549094Sbostic tp = constty; 46630549Skarels flags |= TOTTY; 46730549Skarels } 46849094Sbostic if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 46949094Sbostic (flags & TOCONS) && tp == constty) 47049062Sbostic constty = NULL; 47149062Sbostic if ((flags & TOLOG) && 47249062Sbostic c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 47350268Sbostic mbp = msgbufp; 47445733Smckusick if (mbp->msg_magic != MSG_MAGIC) { 47549953Sbostic bzero((caddr_t)mbp, sizeof(*mbp)); 47645733Smckusick mbp->msg_magic = MSG_MAGIC; 4772172Swnj } 47845733Smckusick mbp->msg_bufc[mbp->msg_bufx++] = c; 47945733Smckusick if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 48045733Smckusick mbp->msg_bufx = 0; 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__ 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 * 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