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*30695Skarels * @(#)subr_prf.c 7.7 (Berkeley) 03/29/87 723381Smckusick */ 831Sbill 917094Sbloom #include "param.h" 1017094Sbloom #include "systm.h" 1117094Sbloom #include "seg.h" 1217094Sbloom #include "buf.h" 1317094Sbloom #include "conf.h" 1417094Sbloom #include "reboot.h" 1517094Sbloom #include "vm.h" 1617094Sbloom #include "msgbuf.h" 1717094Sbloom #include "dir.h" 1817094Sbloom #include "user.h" 1917094Sbloom #include "proc.h" 2017577Sbloom #include "ioctl.h" 2117094Sbloom #include "tty.h" 2218364Skarels #include "syslog.h" 2331Sbill 2430625Skarels #include "../machine/mtpr.h" 2530625Skarels #ifdef KDB 2630625Skarels #include "../machine/kdbparam.h" 2730625Skarels #endif 2830625Skarels 2916724Sralph #define TOCONS 0x1 3016724Sralph #define TOTTY 0x2 3116724Sralph #define TOLOG 0x4 3216724Sralph 3331Sbill /* 3431Sbill * In case console is off, 3531Sbill * panicstr contains argument to last 3631Sbill * call to panic. 3731Sbill */ 3831Sbill char *panicstr; 3931Sbill 4030549Skarels extern cnputc(); /* standard console putc */ 4130549Skarels extern struct tty cons; /* standard console tty */ 4230549Skarels struct tty *constty; /* pointer to console "window" tty */ 4330549Skarels int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 4430549Skarels 4531Sbill /* 4631Sbill * Scaled down version of C Library printf. 472781Swnj * Used to print diagnostic information directly on console tty. 482781Swnj * Since it is not interrupt driven, all system activities are 492781Swnj * suspended. Printf should not be used for chit-chat. 502781Swnj * 512781Swnj * One additional format: %b is supported to decode error registers. 522781Swnj * Usage is: 532781Swnj * printf("reg=%b\n", regval, "<base><arg>*"); 542781Swnj * Where <base> is the output base expressed as a control character, 552781Swnj * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 562781Swnj * characters, the first of which gives the bit number to be inspected 572781Swnj * (origin 1), and the next characters (up to a control character, i.e. 582781Swnj * a character <= 32), give the name of the register. Thus 592781Swnj * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 602781Swnj * would produce output: 6117594Skarels * reg=3<BITTWO,BITONE> 6231Sbill */ 6329946Skarels #if defined(tahoe) 6429946Skarels int consintr; 6529946Skarels #endif 6629946Skarels 6731Sbill /*VARARGS1*/ 6831Sbill printf(fmt, x1) 692781Swnj char *fmt; 702781Swnj unsigned x1; 7131Sbill { 7229946Skarels #if defined(tahoe) 7329946Skarels register int savintr; 74285Sbill 7529946Skarels savintr = consintr, consintr = 0; /* disable interrupts */ 7629946Skarels #endif 7716724Sralph prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0); 7816724Sralph logwakeup(); 7929946Skarels #if defined(tahoe) 8029946Skarels consintr = savintr; /* reenable interrupts */ 8129946Skarels #endif 82285Sbill } 83285Sbill 842377Swnj /* 8525389Skarels * Uprintf prints to the current user's terminal. 8625389Skarels * It may block if the tty queue is overfull. 87*30695Skarels * No message is printed if the queue does not clear 88*30695Skarels * in a reasonable time. 8925389Skarels * Should determine whether current terminal user is related 9025389Skarels * to this process. 912377Swnj */ 922377Swnj /*VARARGS1*/ 932377Swnj uprintf(fmt, x1) 942781Swnj char *fmt; 952377Swnj unsigned x1; 96285Sbill { 9726250Skarels #ifdef notdef 9825389Skarels register struct proc *p; 9926250Skarels #endif 10025389Skarels register struct tty *tp; 101285Sbill 10225389Skarels if ((tp = u.u_ttyp) == NULL) 10325389Skarels return; 10425389Skarels #ifdef notdef 10525389Skarels if (tp->t_pgrp && (p = pfind(tp->t_pgrp))) 10626250Skarels if (p->p_uid != u.u_uid) /* doesn't account for setuid */ 10725389Skarels return; 10825389Skarels #endif 109*30695Skarels if (ttycheckoutq(tp, 1)) 110*30695Skarels prf(fmt, &x1, TOTTY, tp); 111285Sbill } 112285Sbill 11318364Skarels /* 11418364Skarels * tprintf prints on the specified terminal (console if none) 11518364Skarels * and logs the message. It is designed for error messages from 11625389Skarels * single-open devices, and may be called from interrupt level 11725389Skarels * (does not sleep). 11818364Skarels */ 11916724Sralph /*VARARGS2*/ 12025389Skarels tprintf(tp, fmt, x1) 12125389Skarels register struct tty *tp; 12216724Sralph char *fmt; 12316724Sralph unsigned x1; 12416724Sralph { 12525389Skarels int flags = TOTTY | TOLOG; 12616724Sralph 12725389Skarels logpri(LOG_INFO); 12829946Skarels if (tp == (struct tty *)NULL) 12929946Skarels tp = &cons; 13025389Skarels if (ttycheckoutq(tp, 0) == 0) 13125389Skarels flags = TOLOG; 13225389Skarels prf(fmt, &x1, flags, tp); 13325389Skarels logwakeup(); 13416724Sralph } 13516724Sralph 13616724Sralph /* 13716724Sralph * Log writes to the log buffer, 13817594Skarels * and guarantees not to sleep (so can be called by interrupt routines). 13918364Skarels * If there is no process reading the log yet, it writes to the console also. 14016724Sralph */ 14116724Sralph /*VARARGS2*/ 14216724Sralph log(level, fmt, x1) 14316724Sralph char *fmt; 14416724Sralph unsigned x1; 14516724Sralph { 14616724Sralph register s = splhigh(); 14718364Skarels extern int log_open; 14816724Sralph 14925389Skarels logpri(level); 15016724Sralph prf(fmt, &x1, TOLOG, (struct tty *)0); 15116724Sralph splx(s); 15218364Skarels if (!log_open) 15318364Skarels prf(fmt, &x1, TOCONS, (struct tty *)0); 15416724Sralph logwakeup(); 15516724Sralph } 15616724Sralph 15725389Skarels logpri(level) 15825389Skarels int level; 15925389Skarels { 16025389Skarels 16125389Skarels putchar('<', TOLOG, (struct tty *)0); 16226356Skarels printn((u_long)level, 10, TOLOG, (struct tty *)0); 16325389Skarels putchar('>', TOLOG, (struct tty *)0); 16425389Skarels } 16525389Skarels 16616724Sralph prf(fmt, adx, flags, ttyp) 1672781Swnj register char *fmt; 1682781Swnj register u_int *adx; 16916724Sralph struct tty *ttyp; 170285Sbill { 1712434Swnj register int b, c, i; 17231Sbill char *s; 1732678Swnj int any; 17431Sbill 17531Sbill loop: 1762377Swnj while ((c = *fmt++) != '%') { 17716724Sralph if (c == '\0') 17831Sbill return; 17916724Sralph putchar(c, flags, ttyp); 18031Sbill } 1812377Swnj again: 18231Sbill c = *fmt++; 18329946Skarels /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 1842377Swnj switch (c) { 1852377Swnj 1862377Swnj case 'l': 1872377Swnj goto again; 1882377Swnj case 'x': case 'X': 1892377Swnj b = 16; 1902377Swnj goto number; 1912377Swnj case 'd': case 'D': 19229946Skarels b = -10; 19329946Skarels goto number; 19429946Skarels case 'u': 1952377Swnj b = 10; 1962377Swnj goto number; 1972377Swnj case 'o': case 'O': 1982377Swnj b = 8; 1992377Swnj number: 20016724Sralph printn((u_long)*adx, b, flags, ttyp); 2012377Swnj break; 2022377Swnj case 'c': 2032434Swnj b = *adx; 20429946Skarels #if ENDIAN == LITTLE 2052434Swnj for (i = 24; i >= 0; i -= 8) 2062434Swnj if (c = (b >> i) & 0x7f) 20716724Sralph putchar(c, flags, ttyp); 20829946Skarels #endif 20929946Skarels #if ENDIAN == BIG 21029946Skarels if (c = (b & 0x7f)) 21129946Skarels putchar(c, flags, ttyp); 21229946Skarels #endif 2132377Swnj break; 2142678Swnj case 'b': 2152678Swnj b = *adx++; 2162678Swnj s = (char *)*adx; 21716724Sralph printn((u_long)b, *s++, flags, ttyp); 2182678Swnj any = 0; 2192678Swnj if (b) { 2202678Swnj while (i = *s++) { 2212678Swnj if (b & (1 << (i-1))) { 22229946Skarels putchar(any ? ',' : '<', flags, ttyp); 2232678Swnj any = 1; 2242678Swnj for (; (c = *s) > 32; s++) 22516724Sralph putchar(c, flags, ttyp); 2262678Swnj } else 2272678Swnj for (; *s > 32; s++) 2282678Swnj ; 2292678Swnj } 2303878Swnj if (any) 23116724Sralph putchar('>', flags, ttyp); 2322678Swnj } 2332678Swnj break; 2342678Swnj 2352377Swnj case 's': 23631Sbill s = (char *)*adx; 237285Sbill while (c = *s++) 23816724Sralph putchar(c, flags, ttyp); 2392377Swnj break; 2403736Sroot 2413736Sroot case '%': 24216724Sralph putchar('%', flags, ttyp); 2433736Sroot break; 24431Sbill } 24531Sbill adx++; 24631Sbill goto loop; 24731Sbill } 24831Sbill 2492781Swnj /* 2502781Swnj * Printn prints a number n in base b. 2512781Swnj * We don't use recursion to avoid deep kernel stacks. 2522781Swnj */ 25316724Sralph printn(n, b, flags, ttyp) 2543101Swnj u_long n; 25516724Sralph struct tty *ttyp; 25631Sbill { 2572434Swnj char prbuf[11]; 2582377Swnj register char *cp; 25931Sbill 26029946Skarels if (b == -10) { 26129946Skarels if ((int)n < 0) { 26229946Skarels putchar('-', flags, ttyp); 26329946Skarels n = (unsigned)(-(int)n); 26429946Skarels } 26529946Skarels b = -b; 26631Sbill } 2672434Swnj cp = prbuf; 2682377Swnj do { 2692377Swnj *cp++ = "0123456789abcdef"[n%b]; 2702377Swnj n /= b; 2712377Swnj } while (n); 2722377Swnj do 27316724Sralph putchar(*--cp, flags, ttyp); 2742434Swnj while (cp > prbuf); 27531Sbill } 27631Sbill 27731Sbill /* 2781184Sbill * Panic is called on unresolvable fatal errors. 2792781Swnj * It prints "panic: mesg", and then reboots. 2802781Swnj * If we are called twice, then we avoid trying to 2812781Swnj * sync the disks as this often leads to recursive panics. 28231Sbill */ 28331Sbill panic(s) 2842781Swnj char *s; 28531Sbill { 28630566Skarels int bootopt = RB_AUTOBOOT | RB_DUMP; 2872377Swnj 2885416Swnj if (panicstr) 2895416Swnj bootopt |= RB_NOSYNC; 2909758Ssam else { 2919758Ssam panicstr = s; 2928950Sroot } 2933285Swnj printf("panic: %s\n", s); 29430625Skarels #ifdef KDB 29530625Skarels if (boothowto & RB_KDB) { 29630625Skarels int s = splnet(); /* below kdb pri */ 29730625Skarels 29830625Skarels setsoftkdb(); 29930625Skarels splx(s); 30030625Skarels } 30130625Skarels #endif 30230566Skarels boot(bootopt); 30331Sbill } 30431Sbill 30531Sbill /* 3062941Swnj * Warn that a system table is full. 3072941Swnj */ 3082941Swnj tablefull(tab) 3092941Swnj char *tab; 3102941Swnj { 3112941Swnj 31224839Seric log(LOG_ERR, "%s: table is full\n", tab); 3132941Swnj } 3142941Swnj 3152941Swnj /* 3162781Swnj * Hard error is the preface to plaintive error messages 3172941Swnj * about failing disk transfers. 3182781Swnj */ 3192941Swnj harderr(bp, cp) 3202678Swnj struct buf *bp; 3212941Swnj char *cp; 32231Sbill { 32331Sbill 3242941Swnj printf("%s%d%c: hard error sn%d ", cp, 32524759Skarels minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno); 32631Sbill } 3272781Swnj 328285Sbill /* 3292377Swnj * Print a character on console or users terminal. 330285Sbill * If destination is console then the last MSGBUFS characters 331285Sbill * are saved in msgbuf for inspection later. 332285Sbill */ 3331785Sbill /*ARGSUSED*/ 33417594Skarels putchar(c, flags, tp) 3352377Swnj register int c; 33617594Skarels struct tty *tp; 337285Sbill { 33830549Skarels int startflags = flags; 339285Sbill 34030549Skarels if (panicstr) 34130549Skarels constty = 0; 34230549Skarels if ((flags & TOCONS) && tp == 0 && constty) { 34330549Skarels tp = constty; 34430549Skarels flags |= TOTTY; 34530549Skarels } 34616724Sralph if (flags & TOTTY) { 34725389Skarels register s = spltty(); 34825389Skarels 34925389Skarels if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == 35025389Skarels (TS_CARR_ON | TS_ISOPEN)) { 3512377Swnj if (c == '\n') 3524970Swnj (void) ttyoutput('\r', tp); 3534970Swnj (void) ttyoutput(c, tp); 3542360Skre ttstart(tp); 35530549Skarels } else if ((flags & TOCONS) && tp == constty) 35630549Skarels constty = 0; 35725389Skarels splx(s); 3582360Skre } 35929946Skarels /* 36029946Skarels * Can send to log only after memory management enabled: 36129946Skarels * this has happened by the time maxmem is set. 36229946Skarels */ 36329946Skarels if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) { 3642172Swnj if (msgbuf.msg_magic != MSG_MAGIC) { 36512494Ssam register int i; 36612494Ssam 3672172Swnj msgbuf.msg_magic = MSG_MAGIC; 36816724Sralph msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 36912494Ssam for (i=0; i < MSG_BSIZE; i++) 37012494Ssam msgbuf.msg_bufc[i] = 0; 3712172Swnj } 37226427Sbloom msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 3732172Swnj if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 3742172Swnj msgbuf.msg_bufx = 0; 375285Sbill } 37630549Skarels if ((flags & TOCONS) && constty == 0 && c != '\0') 37730549Skarels (*v_putc)(c); 378285Sbill } 379