123381Smckusick /* 229101Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323381Smckusick * All rights reserved. The Berkeley software License Agreement 423381Smckusick * specifies the terms and conditions for redistribution. 523381Smckusick * 6*30566Skarels * @(#)subr_prf.c 7.5 (Berkeley) 02/26/87 723381Smckusick */ 829946Skarels #include "../machine/mtpr.h" 931Sbill 1017094Sbloom #include "param.h" 1117094Sbloom #include "systm.h" 1217094Sbloom #include "seg.h" 1317094Sbloom #include "buf.h" 1417094Sbloom #include "conf.h" 1517094Sbloom #include "reboot.h" 1617094Sbloom #include "vm.h" 1717094Sbloom #include "msgbuf.h" 1817094Sbloom #include "dir.h" 1917094Sbloom #include "user.h" 2017094Sbloom #include "proc.h" 2117577Sbloom #include "ioctl.h" 2217094Sbloom #include "tty.h" 2318364Skarels #include "syslog.h" 2431Sbill 2516724Sralph #define TOCONS 0x1 2616724Sralph #define TOTTY 0x2 2716724Sralph #define TOLOG 0x4 2816724Sralph 2931Sbill /* 3031Sbill * In case console is off, 3131Sbill * panicstr contains argument to last 3231Sbill * call to panic. 3331Sbill */ 3431Sbill char *panicstr; 3531Sbill 3630549Skarels extern cnputc(); /* standard console putc */ 3730549Skarels extern struct tty cons; /* standard console tty */ 3830549Skarels struct tty *constty; /* pointer to console "window" tty */ 3930549Skarels int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 4030549Skarels 4131Sbill /* 4231Sbill * Scaled down version of C Library printf. 432781Swnj * Used to print diagnostic information directly on console tty. 442781Swnj * Since it is not interrupt driven, all system activities are 452781Swnj * suspended. Printf should not be used for chit-chat. 462781Swnj * 472781Swnj * One additional format: %b is supported to decode error registers. 482781Swnj * Usage is: 492781Swnj * printf("reg=%b\n", regval, "<base><arg>*"); 502781Swnj * Where <base> is the output base expressed as a control character, 512781Swnj * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 522781Swnj * characters, the first of which gives the bit number to be inspected 532781Swnj * (origin 1), and the next characters (up to a control character, i.e. 542781Swnj * a character <= 32), give the name of the register. Thus 552781Swnj * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 562781Swnj * would produce output: 5717594Skarels * reg=3<BITTWO,BITONE> 5831Sbill */ 5929946Skarels #if defined(tahoe) 6029946Skarels int consintr; 6129946Skarels #endif 6229946Skarels 6331Sbill /*VARARGS1*/ 6431Sbill printf(fmt, x1) 652781Swnj char *fmt; 662781Swnj unsigned x1; 6731Sbill { 6829946Skarels #if defined(tahoe) 6929946Skarels register int savintr; 70285Sbill 7129946Skarels savintr = consintr, consintr = 0; /* disable interrupts */ 7229946Skarels #endif 7316724Sralph prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0); 7416724Sralph logwakeup(); 7529946Skarels #if defined(tahoe) 7629946Skarels consintr = savintr; /* reenable interrupts */ 7729946Skarels #endif 78285Sbill } 79285Sbill 802377Swnj /* 8125389Skarels * Uprintf prints to the current user's terminal. 8225389Skarels * It may block if the tty queue is overfull. 8325389Skarels * Should determine whether current terminal user is related 8425389Skarels * to this process. 852377Swnj */ 862377Swnj /*VARARGS1*/ 872377Swnj uprintf(fmt, x1) 882781Swnj char *fmt; 892377Swnj unsigned x1; 90285Sbill { 9126250Skarels #ifdef notdef 9225389Skarels register struct proc *p; 9326250Skarels #endif 9425389Skarels register struct tty *tp; 95285Sbill 9625389Skarels if ((tp = u.u_ttyp) == NULL) 9725389Skarels return; 9825389Skarels #ifdef notdef 9925389Skarels if (tp->t_pgrp && (p = pfind(tp->t_pgrp))) 10026250Skarels if (p->p_uid != u.u_uid) /* doesn't account for setuid */ 10125389Skarels return; 10225389Skarels #endif 10325389Skarels (void)ttycheckoutq(tp, 1); 10425389Skarels prf(fmt, &x1, TOTTY, tp); 105285Sbill } 106285Sbill 10718364Skarels /* 10818364Skarels * tprintf prints on the specified terminal (console if none) 10918364Skarels * and logs the message. It is designed for error messages from 11025389Skarels * single-open devices, and may be called from interrupt level 11125389Skarels * (does not sleep). 11218364Skarels */ 11316724Sralph /*VARARGS2*/ 11425389Skarels tprintf(tp, fmt, x1) 11525389Skarels register struct tty *tp; 11616724Sralph char *fmt; 11716724Sralph unsigned x1; 11816724Sralph { 11925389Skarels int flags = TOTTY | TOLOG; 12016724Sralph 12125389Skarels logpri(LOG_INFO); 12229946Skarels if (tp == (struct tty *)NULL) 12329946Skarels tp = &cons; 12425389Skarels if (ttycheckoutq(tp, 0) == 0) 12525389Skarels flags = TOLOG; 12625389Skarels prf(fmt, &x1, flags, tp); 12725389Skarels logwakeup(); 12816724Sralph } 12916724Sralph 13016724Sralph /* 13116724Sralph * Log writes to the log buffer, 13217594Skarels * and guarantees not to sleep (so can be called by interrupt routines). 13318364Skarels * If there is no process reading the log yet, it writes to the console also. 13416724Sralph */ 13516724Sralph /*VARARGS2*/ 13616724Sralph log(level, fmt, x1) 13716724Sralph char *fmt; 13816724Sralph unsigned x1; 13916724Sralph { 14016724Sralph register s = splhigh(); 14118364Skarels extern int log_open; 14216724Sralph 14325389Skarels logpri(level); 14416724Sralph prf(fmt, &x1, TOLOG, (struct tty *)0); 14516724Sralph splx(s); 14618364Skarels if (!log_open) 14718364Skarels prf(fmt, &x1, TOCONS, (struct tty *)0); 14816724Sralph logwakeup(); 14916724Sralph } 15016724Sralph 15125389Skarels logpri(level) 15225389Skarels int level; 15325389Skarels { 15425389Skarels 15525389Skarels putchar('<', TOLOG, (struct tty *)0); 15626356Skarels printn((u_long)level, 10, TOLOG, (struct tty *)0); 15725389Skarels putchar('>', TOLOG, (struct tty *)0); 15825389Skarels } 15925389Skarels 16016724Sralph prf(fmt, adx, flags, ttyp) 1612781Swnj register char *fmt; 1622781Swnj register u_int *adx; 16316724Sralph struct tty *ttyp; 164285Sbill { 1652434Swnj register int b, c, i; 16631Sbill char *s; 1672678Swnj int any; 16831Sbill 16931Sbill loop: 1702377Swnj while ((c = *fmt++) != '%') { 17116724Sralph if (c == '\0') 17231Sbill return; 17316724Sralph putchar(c, flags, ttyp); 17431Sbill } 1752377Swnj again: 17631Sbill c = *fmt++; 17729946Skarels /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 1782377Swnj switch (c) { 1792377Swnj 1802377Swnj case 'l': 1812377Swnj goto again; 1822377Swnj case 'x': case 'X': 1832377Swnj b = 16; 1842377Swnj goto number; 1852377Swnj case 'd': case 'D': 18629946Skarels b = -10; 18729946Skarels goto number; 18829946Skarels case 'u': 1892377Swnj b = 10; 1902377Swnj goto number; 1912377Swnj case 'o': case 'O': 1922377Swnj b = 8; 1932377Swnj number: 19416724Sralph printn((u_long)*adx, b, flags, ttyp); 1952377Swnj break; 1962377Swnj case 'c': 1972434Swnj b = *adx; 19829946Skarels #if ENDIAN == LITTLE 1992434Swnj for (i = 24; i >= 0; i -= 8) 2002434Swnj if (c = (b >> i) & 0x7f) 20116724Sralph putchar(c, flags, ttyp); 20229946Skarels #endif 20329946Skarels #if ENDIAN == BIG 20429946Skarels if (c = (b & 0x7f)) 20529946Skarels putchar(c, flags, ttyp); 20629946Skarels #endif 2072377Swnj break; 2082678Swnj case 'b': 2092678Swnj b = *adx++; 2102678Swnj s = (char *)*adx; 21116724Sralph printn((u_long)b, *s++, flags, ttyp); 2122678Swnj any = 0; 2132678Swnj if (b) { 2142678Swnj while (i = *s++) { 2152678Swnj if (b & (1 << (i-1))) { 21629946Skarels putchar(any ? ',' : '<', flags, ttyp); 2172678Swnj any = 1; 2182678Swnj for (; (c = *s) > 32; s++) 21916724Sralph putchar(c, flags, ttyp); 2202678Swnj } else 2212678Swnj for (; *s > 32; s++) 2222678Swnj ; 2232678Swnj } 2243878Swnj if (any) 22516724Sralph putchar('>', flags, ttyp); 2262678Swnj } 2272678Swnj break; 2282678Swnj 2292377Swnj case 's': 23031Sbill s = (char *)*adx; 231285Sbill while (c = *s++) 23216724Sralph putchar(c, flags, ttyp); 2332377Swnj break; 2343736Sroot 2353736Sroot case '%': 23616724Sralph putchar('%', flags, ttyp); 2373736Sroot break; 23831Sbill } 23931Sbill adx++; 24031Sbill goto loop; 24131Sbill } 24231Sbill 2432781Swnj /* 2442781Swnj * Printn prints a number n in base b. 2452781Swnj * We don't use recursion to avoid deep kernel stacks. 2462781Swnj */ 24716724Sralph printn(n, b, flags, ttyp) 2483101Swnj u_long n; 24916724Sralph struct tty *ttyp; 25031Sbill { 2512434Swnj char prbuf[11]; 2522377Swnj register char *cp; 25331Sbill 25429946Skarels if (b == -10) { 25529946Skarels if ((int)n < 0) { 25629946Skarels putchar('-', flags, ttyp); 25729946Skarels n = (unsigned)(-(int)n); 25829946Skarels } 25929946Skarels b = -b; 26031Sbill } 2612434Swnj cp = prbuf; 2622377Swnj do { 2632377Swnj *cp++ = "0123456789abcdef"[n%b]; 2642377Swnj n /= b; 2652377Swnj } while (n); 2662377Swnj do 26716724Sralph putchar(*--cp, flags, ttyp); 2682434Swnj while (cp > prbuf); 26931Sbill } 27031Sbill 27131Sbill /* 2721184Sbill * Panic is called on unresolvable fatal errors. 2732781Swnj * It prints "panic: mesg", and then reboots. 2742781Swnj * If we are called twice, then we avoid trying to 2752781Swnj * sync the disks as this often leads to recursive panics. 27631Sbill */ 27731Sbill panic(s) 2782781Swnj char *s; 27931Sbill { 280*30566Skarels int bootopt = RB_AUTOBOOT | RB_DUMP; 2812377Swnj 2825416Swnj if (panicstr) 2835416Swnj bootopt |= RB_NOSYNC; 2849758Ssam else { 2859758Ssam panicstr = s; 2868950Sroot } 2873285Swnj printf("panic: %s\n", s); 288*30566Skarels boot(bootopt); 28931Sbill } 29031Sbill 29131Sbill /* 2922941Swnj * Warn that a system table is full. 2932941Swnj */ 2942941Swnj tablefull(tab) 2952941Swnj char *tab; 2962941Swnj { 2972941Swnj 29824839Seric log(LOG_ERR, "%s: table is full\n", tab); 2992941Swnj } 3002941Swnj 3012941Swnj /* 3022781Swnj * Hard error is the preface to plaintive error messages 3032941Swnj * about failing disk transfers. 3042781Swnj */ 3052941Swnj harderr(bp, cp) 3062678Swnj struct buf *bp; 3072941Swnj char *cp; 30831Sbill { 30931Sbill 3102941Swnj printf("%s%d%c: hard error sn%d ", cp, 31124759Skarels minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno); 31231Sbill } 3132781Swnj 314285Sbill /* 3152377Swnj * Print a character on console or users terminal. 316285Sbill * If destination is console then the last MSGBUFS characters 317285Sbill * are saved in msgbuf for inspection later. 318285Sbill */ 3191785Sbill /*ARGSUSED*/ 32017594Skarels putchar(c, flags, tp) 3212377Swnj register int c; 32217594Skarels struct tty *tp; 323285Sbill { 32430549Skarels int startflags = flags; 325285Sbill 32630549Skarels if (panicstr) 32730549Skarels constty = 0; 32830549Skarels if ((flags & TOCONS) && tp == 0 && constty) { 32930549Skarels tp = constty; 33030549Skarels flags |= TOTTY; 33130549Skarels } 33216724Sralph if (flags & TOTTY) { 33325389Skarels register s = spltty(); 33425389Skarels 33525389Skarels if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == 33625389Skarels (TS_CARR_ON | TS_ISOPEN)) { 3372377Swnj if (c == '\n') 3384970Swnj (void) ttyoutput('\r', tp); 3394970Swnj (void) ttyoutput(c, tp); 3402360Skre ttstart(tp); 34130549Skarels } else if ((flags & TOCONS) && tp == constty) 34230549Skarels constty = 0; 34325389Skarels splx(s); 3442360Skre } 34529946Skarels /* 34629946Skarels * Can send to log only after memory management enabled: 34729946Skarels * this has happened by the time maxmem is set. 34829946Skarels */ 34929946Skarels if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) { 3502172Swnj if (msgbuf.msg_magic != MSG_MAGIC) { 35112494Ssam register int i; 35212494Ssam 3532172Swnj msgbuf.msg_magic = MSG_MAGIC; 35416724Sralph msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 35512494Ssam for (i=0; i < MSG_BSIZE; i++) 35612494Ssam msgbuf.msg_bufc[i] = 0; 3572172Swnj } 35826427Sbloom msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 3592172Swnj if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 3602172Swnj msgbuf.msg_bufx = 0; 361285Sbill } 36230549Skarels if ((flags & TOCONS) && constty == 0 && c != '\0') 36330549Skarels (*v_putc)(c); 364285Sbill } 365