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*50268Sbostic * @(#)subr_prf.c 7.30 (Berkeley) 06/29/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 */ 4849953Sbostic int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 4940808Smarc 5049908Sbostic static 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)); 5349909Sbostic void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list)); 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; 7148426Skarels 7249062Sbostic if (panicstr) 7349062Sbostic bootopt |= RB_NOSYNC; 7449062Sbostic else 7549062Sbostic panicstr = msg; 7649062Sbostic printf("panic: %s\n", msg); 7749062Sbostic #ifdef KGDB 7849062Sbostic kgdb_panic(); 7949062Sbostic #endif 8049062Sbostic #ifdef KADB 8149062Sbostic if (boothowto & RB_KDB) { 82*50268Sbostic int s; 83*50268Sbostic 84*50268Sbostic s = splnet(); /* below kdb pri */ 8549062Sbostic setsoftkdb(); 8649062Sbostic splx(s); 8749062Sbostic } 8849062Sbostic #endif 8949062Sbostic boot(bootopt); 9049062Sbostic } 9149062Sbostic 9249062Sbostic /* 9349062Sbostic * Warn that a system table is full. 9449062Sbostic */ 9549062Sbostic void 9649062Sbostic tablefull(tab) 9749062Sbostic char *tab; 9831Sbill { 99285Sbill 10049062Sbostic log(LOG_ERR, "%s: table is full\n", tab); 101285Sbill } 102285Sbill 1032377Swnj /* 10439560Smarc * Uprintf prints to the controlling terminal for the current process. 10549062Sbostic * It may block if the tty queue is overfull. No message is printed if 10649062Sbostic * the queue does not clear in a reasonable time. 1072377Swnj */ 10849062Sbostic void 10949062Sbostic #ifdef __STDC__ 11049062Sbostic uprintf(const char *fmt, ...) 11149062Sbostic #else 11249062Sbostic uprintf(fmt /*, va_alist */) 1132781Swnj char *fmt; 11449062Sbostic #endif 115285Sbill { 11647540Skarels register struct proc *p = curproc; 11749062Sbostic va_list ap; 118285Sbill 11949953Sbostic if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 12049953Sbostic va_start(ap, fmt); 12149062Sbostic kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 12249953Sbostic va_end(ap); 12349953Sbostic } 124285Sbill } 125285Sbill 12644386Smarc tpr_t 12748426Skarels tprintf_open(p) 12848426Skarels register struct proc *p; 12944386Smarc { 13049953Sbostic 13144386Smarc if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 13244386Smarc SESSHOLD(p->p_session); 13348426Skarels return ((tpr_t) p->p_session); 13449062Sbostic } 13549062Sbostic return ((tpr_t) NULL); 13644386Smarc } 13744386Smarc 13848426Skarels void 13944386Smarc tprintf_close(sess) 14044386Smarc tpr_t sess; 14144386Smarc { 14249953Sbostic 14344386Smarc if (sess) 14448426Skarels SESSRELE((struct session *) sess); 14544386Smarc } 14644386Smarc 14718364Skarels /* 14844386Smarc * tprintf prints on the controlling terminal associated 14949062Sbostic * with the given session. 15018364Skarels */ 15149062Sbostic void 15249062Sbostic #ifdef __STDC__ 15349062Sbostic tprintf(tpr_t tpr, const char *fmt, ...) 15449062Sbostic #else 15549062Sbostic tprintf(tpr, fmt /*, va_alist */) 15648426Skarels tpr_t tpr; 15716724Sralph char *fmt; 15849062Sbostic #endif 15916724Sralph { 16048426Skarels register struct session *sess = (struct session *)tpr; 16148426Skarels struct tty *tp = NULL; 16244386Smarc int flags = TOLOG; 16349062Sbostic va_list ap; 16416724Sralph 16525389Skarels logpri(LOG_INFO); 16648426Skarels if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 16744386Smarc flags |= TOTTY; 16848426Skarels tp = sess->s_ttyp; 16948426Skarels } 17049062Sbostic va_start(ap, fmt); 17149062Sbostic kprintf(fmt, flags, tp, ap); 17249062Sbostic va_end(ap); 17325389Skarels logwakeup(); 17416724Sralph } 17516724Sralph 17649062Sbostic /* 17749062Sbostic * Ttyprintf displays a message on a tty; it should be used only by 17849062Sbostic * the tty driver, or anything that knows the underlying tty will not 17949062Sbostic * be revoke(2)'d away. Other callers should use tprintf. 18049062Sbostic */ 18149062Sbostic void 18249062Sbostic #ifdef __STDC__ 18349062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...) 18449062Sbostic #else 18549062Sbostic ttyprintf(tp, fmt /*, va_alist */) 18649062Sbostic struct tty *tp; 18749062Sbostic char *fmt; 18849062Sbostic #endif 18949062Sbostic { 19049062Sbostic va_list ap; 19149062Sbostic 19249062Sbostic va_start(ap, fmt); 19349062Sbostic kprintf(fmt, TOTTY, tp, ap); 19449062Sbostic va_end(ap); 19549062Sbostic } 19649062Sbostic 19748426Skarels extern int log_open; 19844386Smarc 19916724Sralph /* 20049062Sbostic * Log writes to the log buffer, and guarantees not to sleep (so can be 20149062Sbostic * called by interrupt routines). If there is no process reading the 20249062Sbostic * log yet, it writes to the console also. 20316724Sralph */ 20449062Sbostic void 20549062Sbostic #ifdef __STDC__ 20649062Sbostic log(int level, const char *fmt, ...) 20749062Sbostic #else 20849062Sbostic log(level, fmt /*, va_alist */) 20949062Sbostic int level; 21016724Sralph char *fmt; 21149062Sbostic #endif 21216724Sralph { 213*50268Sbostic register int s; 21449062Sbostic va_list ap; 21516724Sralph 216*50268Sbostic s = splhigh(); 21725389Skarels logpri(level); 21849062Sbostic va_start(ap, fmt); 21949062Sbostic kprintf(fmt, TOLOG, NULL, ap); 22016724Sralph splx(s); 22149953Sbostic va_end(ap); 22249953Sbostic if (!log_open) { 22349953Sbostic va_start(ap, fmt); 22449062Sbostic kprintf(fmt, TOCONS, NULL, ap); 22549953Sbostic va_end(ap); 22649953Sbostic } 22716724Sralph logwakeup(); 22816724Sralph } 22916724Sralph 23049062Sbostic static void 23125389Skarels logpri(level) 23225389Skarels int level; 23325389Skarels { 23449908Sbostic register int ch; 23549908Sbostic register char *p; 23625389Skarels 23749062Sbostic putchar('<', TOLOG, NULL); 23849908Sbostic for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;) 23949908Sbostic putchar(ch, TOLOG, NULL); 24049062Sbostic putchar('>', TOLOG, NULL); 24125389Skarels } 24225389Skarels 24349062Sbostic void 24449062Sbostic #ifdef __STDC__ 24549062Sbostic addlog(const char *fmt, ...) 24649062Sbostic #else 24749062Sbostic addlog(fmt /*, va_alist */) 24833479Skarels char *fmt; 24949062Sbostic #endif 25033479Skarels { 251*50268Sbostic register int s; 25249062Sbostic va_list ap; 25333479Skarels 254*50268Sbostic s = splhigh(); 25549062Sbostic va_start(ap, fmt); 25649062Sbostic kprintf(fmt, TOLOG, NULL, ap); 25733479Skarels splx(s); 25849953Sbostic va_end(ap); 25949953Sbostic if (!log_open) { 26049953Sbostic va_start(ap, fmt); 26149062Sbostic kprintf(fmt, TOCONS, NULL, ap); 26249953Sbostic va_end(ap); 26349953Sbostic } 26433479Skarels logwakeup(); 26533479Skarels } 26633479Skarels 26749062Sbostic int consintr = 1; /* ok to handle console interrupts? */ 26831Sbill 26949062Sbostic void 27049062Sbostic #ifdef __STDC__ 27149062Sbostic printf(const char *fmt, ...) 27249062Sbostic #else 27349062Sbostic printf(fmt /*, va_alist */) 27449062Sbostic char *fmt; 27529946Skarels #endif 27649062Sbostic { 27749953Sbostic va_list ap; 27849062Sbostic register int savintr; 2792678Swnj 28049062Sbostic savintr = consintr; /* disable interrupts */ 28149062Sbostic consintr = 0; 28249062Sbostic va_start(ap, fmt); 28349062Sbostic kprintf(fmt, TOCONS | TOLOG, NULL, ap); 28449062Sbostic va_end(ap); 28549062Sbostic if (!panicstr) 28649062Sbostic logwakeup(); 28749062Sbostic consintr = savintr; /* reenable interrupts */ 28831Sbill } 28931Sbill 2902781Swnj /* 29149062Sbostic * Scaled down version of printf(3). 29249062Sbostic * 29349062Sbostic * Two additional formats: 29449062Sbostic * 29549062Sbostic * The format %b is supported to decode error registers. 29649062Sbostic * Its usage is: 29749062Sbostic * 29849908Sbostic * printf("reg=%b\n", regval, "<base><arg>*"); 29949062Sbostic * 30049062Sbostic * where <base> is the output base expressed as a control character, e.g. 30149062Sbostic * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 30249062Sbostic * the first of which gives the bit number to be inspected (origin 1), and 30349062Sbostic * the next characters (up to a control character, i.e. a character <= 32), 30449062Sbostic * give the name of the register. Thus: 30549062Sbostic * 30649908Sbostic * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 30749062Sbostic * 30849062Sbostic * would produce output: 30949062Sbostic * 31049062Sbostic * reg=3<BITTWO,BITONE> 31149062Sbostic * 31249062Sbostic * The format %r is supposed to pass an additional format string and argument 31349062Sbostic * list recursively. 31449062Sbostic * Its usage is: 31549062Sbostic * 31649953Sbostic * fn(otherstuff, char *fmt, ...) 31749953Sbostic * { 31849953Sbostic * va_list ap; 31949953Sbostic * va_start(ap, fmt); 32049908Sbostic * printf("prefix: %r, other stuff\n", fmt, ap); 32149953Sbostic * va_end(ap); 32249908Sbostic * 32349908Sbostic * Space or zero padding and a field width are supported for the numeric 32449908Sbostic * formats only. 3252781Swnj */ 32649909Sbostic void 32749094Sbostic kprintf(fmt, flags, tp, ap) 32849094Sbostic register const char *fmt; 32949062Sbostic int flags; 33049094Sbostic struct tty *tp; 33149062Sbostic va_list ap; 33231Sbill { 33349062Sbostic register char *p; 33449062Sbostic register int ch, n; 33549908Sbostic u_long ul; 33649908Sbostic int base, lflag, tmp, width; 33749908Sbostic char padc; 33831Sbill 33949062Sbostic for (;;) { 34049908Sbostic padc = ' '; 34149908Sbostic width = 0; 34249919Skarels while ((ch = *(u_char *)fmt++) != '%') { 34349062Sbostic if (ch == '\0') 34449062Sbostic return; 34549094Sbostic putchar(ch, flags, tp); 34629946Skarels } 34749062Sbostic lflag = 0; 34849919Skarels reswitch: switch (ch = *(u_char *)fmt++) { 34949908Sbostic case '0': 35049908Sbostic padc = '0'; 35149908Sbostic goto reswitch; 35249908Sbostic case '1': case '2': case '3': case '4': 35349908Sbostic case '5': case '6': case '7': case '8': case '9': 35449908Sbostic for (width = 0;; ++fmt) { 35549908Sbostic width = width * 10 + ch - '0'; 35649908Sbostic ch = *fmt; 35749908Sbostic if (ch < '0' || ch > '9') 35849908Sbostic break; 35949908Sbostic } 36049908Sbostic goto reswitch; 36149062Sbostic case 'l': 36249062Sbostic lflag = 1; 36349062Sbostic goto reswitch; 36449062Sbostic case 'b': 36549062Sbostic ul = va_arg(ap, int); 36649062Sbostic p = va_arg(ap, char *); 36749908Sbostic for (p = ksprintn(ul, *p++, NULL); ch = *p--;) 36849908Sbostic putchar(ch, flags, tp); 36931Sbill 37049062Sbostic if (!ul) 37149062Sbostic break; 3722377Swnj 37349908Sbostic for (tmp = 0; n = *p++;) { 37449062Sbostic if (ul & (1 << (n - 1))) { 37549908Sbostic putchar(tmp ? ',' : '<', flags, tp); 37649062Sbostic for (; (n = *p) > ' '; ++p) 37749094Sbostic putchar(n, flags, tp); 37849908Sbostic tmp = 1; 37949062Sbostic } else 38049062Sbostic for (; *p > ' '; ++p); 38149062Sbostic } 38249908Sbostic if (tmp) 38349094Sbostic putchar('>', flags, tp); 38449062Sbostic break; 38549062Sbostic case 'c': 38649094Sbostic putchar(va_arg(ap, int), flags, tp); 38749062Sbostic break; 38849062Sbostic case 'r': 38949062Sbostic p = va_arg(ap, char *); 39049094Sbostic kprintf(p, flags, tp, va_arg(ap, va_list)); 39149062Sbostic break; 39249062Sbostic case 's': 39349062Sbostic p = va_arg(ap, char *); 39449062Sbostic while (ch = *p++) 39549094Sbostic putchar(ch, flags, tp); 39649062Sbostic break; 39749062Sbostic case 'd': 39849908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 39949062Sbostic if ((long)ul < 0) { 40049094Sbostic putchar('-', flags, tp); 40149062Sbostic ul = -(long)ul; 40249062Sbostic } 40349908Sbostic base = 10; 40449908Sbostic goto number; 40549062Sbostic case 'o': 40649908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 40749908Sbostic base = 8; 40849953Sbostic goto number; 40949062Sbostic case 'u': 41049908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 41149908Sbostic base = 10; 41249908Sbostic goto number; 41349062Sbostic case 'x': 41449908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 41549908Sbostic base = 16; 41649908Sbostic number: p = ksprintn(ul, base, &tmp); 41749908Sbostic if (width && (width -= tmp) > 0) 41849908Sbostic while (width--) 41949908Sbostic putchar(padc, flags, tp); 42049908Sbostic while (ch = *p--) 42149908Sbostic putchar(ch, flags, tp); 42249062Sbostic break; 42349062Sbostic default: 42449094Sbostic putchar('%', flags, tp); 42549062Sbostic if (lflag) 42649094Sbostic putchar('l', flags, tp); 42749908Sbostic /* FALLTHROUGH */ 42849908Sbostic case '%': 42949094Sbostic putchar(ch, flags, tp); 43049062Sbostic } 43130625Skarels } 43231Sbill } 43331Sbill 4342941Swnj /* 43549062Sbostic * Print a character on console or users terminal. If destination is 43649062Sbostic * the console then the last MSGBUFS characters are saved in msgbuf for 43749062Sbostic * inspection later. 438285Sbill */ 43949062Sbostic static void 44049094Sbostic putchar(c, flags, tp) 4412377Swnj register int c; 44249062Sbostic int flags; 44349094Sbostic struct tty *tp; 444285Sbill { 44533479Skarels extern int msgbufmapped; 446*50268Sbostic register struct msgbuf *mbp; 447285Sbill 44830549Skarels if (panicstr) 44949062Sbostic constty = NULL; 45049094Sbostic if ((flags & TOCONS) && tp == NULL && constty) { 45149094Sbostic tp = constty; 45230549Skarels flags |= TOTTY; 45330549Skarels } 45449094Sbostic if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 45549094Sbostic (flags & TOCONS) && tp == constty) 45649062Sbostic constty = NULL; 45749062Sbostic if ((flags & TOLOG) && 45849062Sbostic c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 459*50268Sbostic mbp = msgbufp; 46045733Smckusick if (mbp->msg_magic != MSG_MAGIC) { 46149953Sbostic bzero((caddr_t)mbp, sizeof(*mbp)); 46245733Smckusick mbp->msg_magic = MSG_MAGIC; 4632172Swnj } 46445733Smckusick mbp->msg_bufc[mbp->msg_bufx++] = c; 46545733Smckusick if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 46645733Smckusick mbp->msg_bufx = 0; 467285Sbill } 46849062Sbostic if ((flags & TOCONS) && constty == NULL && c != '\0') 46930549Skarels (*v_putc)(c); 470285Sbill } 47149908Sbostic 47249908Sbostic /* 47349908Sbostic * Scaled down version of sprintf(3). 47449908Sbostic */ 47549908Sbostic #ifdef __STDC__ 47649919Skarels sprintf(char *buf, const char *cfmt, ...) 47749908Sbostic #else 47849919Skarels sprintf(buf, cfmt /*, va_alist */) 47949919Skarels char *buf, *cfmt; 48049908Sbostic #endif 48149908Sbostic { 48249919Skarels register const char *fmt = cfmt; 48349908Sbostic register char *p, *bp; 48449908Sbostic register int ch, base; 48549908Sbostic u_long ul; 48649908Sbostic int lflag; 48749908Sbostic va_list ap; 48849908Sbostic 48949919Skarels va_start(ap, cfmt); 49049919Skarels for (bp = buf; ; ) { 49149919Skarels while ((ch = *(u_char *)fmt++) != '%') 49249908Sbostic if ((*bp++ = ch) == '\0') 49349919Skarels return ((bp - buf) - 1); 49449919Skarels 49549908Sbostic lflag = 0; 49649919Skarels reswitch: switch (ch = *(u_char *)fmt++) { 49749908Sbostic case 'l': 49849908Sbostic lflag = 1; 49949908Sbostic goto reswitch; 50049908Sbostic case 'c': 50149908Sbostic *bp++ = va_arg(ap, int); 50249908Sbostic break; 50349908Sbostic case 's': 50449908Sbostic p = va_arg(ap, char *); 50549919Skarels while (*bp++ = *p++) 50649919Skarels ; 50749908Sbostic --bp; 50849908Sbostic break; 50949908Sbostic case 'd': 51049908Sbostic ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 51149908Sbostic if ((long)ul < 0) { 51249908Sbostic *bp++ = '-'; 51349908Sbostic ul = -(long)ul; 51449908Sbostic } 51549908Sbostic base = 10; 51649908Sbostic goto number; 51749908Sbostic break; 51849908Sbostic case 'o': 51949908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 52049908Sbostic base = 8; 52149908Sbostic goto number; 52249908Sbostic break; 52349908Sbostic case 'u': 52449908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 52549908Sbostic base = 10; 52649908Sbostic goto number; 52749908Sbostic break; 52849908Sbostic case 'x': 52949908Sbostic ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 53049908Sbostic base = 16; 53149908Sbostic number: for (p = ksprintn(ul, base, NULL); ch = *p--;) 53249908Sbostic *bp++ = ch; 53349908Sbostic break; 53449908Sbostic default: 53549908Sbostic *bp++ = '%'; 53649908Sbostic if (lflag) 53749908Sbostic *bp++ = 'l'; 53849908Sbostic /* FALLTHROUGH */ 53949908Sbostic case '%': 54049908Sbostic *bp++ = ch; 54149908Sbostic } 54249908Sbostic } 54349908Sbostic va_end(ap); 54449908Sbostic } 54549908Sbostic 54649908Sbostic /* 54749908Sbostic * Put a number (base <= 16) in a buffer in reverse order; return an 54849908Sbostic * optional length and a pointer to the NULL terminated (preceded?) 54949908Sbostic * buffer. 55049908Sbostic */ 55149908Sbostic static char * 55249908Sbostic ksprintn(ul, base, lenp) 55349908Sbostic register u_long ul; 55449908Sbostic register int base, *lenp; 55549908Sbostic { /* A long in base 8, plus NULL. */ 55649908Sbostic static char buf[sizeof(long) * NBBY / 3 + 2]; 55749908Sbostic register char *p; 55849908Sbostic 55949908Sbostic p = buf; 56049908Sbostic do { 56149908Sbostic *++p = "0123456789abcdef"[ul % base]; 56249908Sbostic } while (ul /= base); 56349908Sbostic if (lenp) 56449908Sbostic *lenp = p - buf; 56549919Skarels return (p); 56649908Sbostic } 567