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*30625Skarels * @(#)subr_prf.c 7.6 (Berkeley) 03/13/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 24*30625Skarels #include "../machine/mtpr.h" 25*30625Skarels #ifdef KDB 26*30625Skarels #include "../machine/kdbparam.h" 27*30625Skarels #endif 28*30625Skarels 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. 8725389Skarels * Should determine whether current terminal user is related 8825389Skarels * to this process. 892377Swnj */ 902377Swnj /*VARARGS1*/ 912377Swnj uprintf(fmt, x1) 922781Swnj char *fmt; 932377Swnj unsigned x1; 94285Sbill { 9526250Skarels #ifdef notdef 9625389Skarels register struct proc *p; 9726250Skarels #endif 9825389Skarels register struct tty *tp; 99285Sbill 10025389Skarels if ((tp = u.u_ttyp) == NULL) 10125389Skarels return; 10225389Skarels #ifdef notdef 10325389Skarels if (tp->t_pgrp && (p = pfind(tp->t_pgrp))) 10426250Skarels if (p->p_uid != u.u_uid) /* doesn't account for setuid */ 10525389Skarels return; 10625389Skarels #endif 10725389Skarels (void)ttycheckoutq(tp, 1); 10825389Skarels prf(fmt, &x1, TOTTY, tp); 109285Sbill } 110285Sbill 11118364Skarels /* 11218364Skarels * tprintf prints on the specified terminal (console if none) 11318364Skarels * and logs the message. It is designed for error messages from 11425389Skarels * single-open devices, and may be called from interrupt level 11525389Skarels * (does not sleep). 11618364Skarels */ 11716724Sralph /*VARARGS2*/ 11825389Skarels tprintf(tp, fmt, x1) 11925389Skarels register struct tty *tp; 12016724Sralph char *fmt; 12116724Sralph unsigned x1; 12216724Sralph { 12325389Skarels int flags = TOTTY | TOLOG; 12416724Sralph 12525389Skarels logpri(LOG_INFO); 12629946Skarels if (tp == (struct tty *)NULL) 12729946Skarels tp = &cons; 12825389Skarels if (ttycheckoutq(tp, 0) == 0) 12925389Skarels flags = TOLOG; 13025389Skarels prf(fmt, &x1, flags, tp); 13125389Skarels logwakeup(); 13216724Sralph } 13316724Sralph 13416724Sralph /* 13516724Sralph * Log writes to the log buffer, 13617594Skarels * and guarantees not to sleep (so can be called by interrupt routines). 13718364Skarels * If there is no process reading the log yet, it writes to the console also. 13816724Sralph */ 13916724Sralph /*VARARGS2*/ 14016724Sralph log(level, fmt, x1) 14116724Sralph char *fmt; 14216724Sralph unsigned x1; 14316724Sralph { 14416724Sralph register s = splhigh(); 14518364Skarels extern int log_open; 14616724Sralph 14725389Skarels logpri(level); 14816724Sralph prf(fmt, &x1, TOLOG, (struct tty *)0); 14916724Sralph splx(s); 15018364Skarels if (!log_open) 15118364Skarels prf(fmt, &x1, TOCONS, (struct tty *)0); 15216724Sralph logwakeup(); 15316724Sralph } 15416724Sralph 15525389Skarels logpri(level) 15625389Skarels int level; 15725389Skarels { 15825389Skarels 15925389Skarels putchar('<', TOLOG, (struct tty *)0); 16026356Skarels printn((u_long)level, 10, TOLOG, (struct tty *)0); 16125389Skarels putchar('>', TOLOG, (struct tty *)0); 16225389Skarels } 16325389Skarels 16416724Sralph prf(fmt, adx, flags, ttyp) 1652781Swnj register char *fmt; 1662781Swnj register u_int *adx; 16716724Sralph struct tty *ttyp; 168285Sbill { 1692434Swnj register int b, c, i; 17031Sbill char *s; 1712678Swnj int any; 17231Sbill 17331Sbill loop: 1742377Swnj while ((c = *fmt++) != '%') { 17516724Sralph if (c == '\0') 17631Sbill return; 17716724Sralph putchar(c, flags, ttyp); 17831Sbill } 1792377Swnj again: 18031Sbill c = *fmt++; 18129946Skarels /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 1822377Swnj switch (c) { 1832377Swnj 1842377Swnj case 'l': 1852377Swnj goto again; 1862377Swnj case 'x': case 'X': 1872377Swnj b = 16; 1882377Swnj goto number; 1892377Swnj case 'd': case 'D': 19029946Skarels b = -10; 19129946Skarels goto number; 19229946Skarels case 'u': 1932377Swnj b = 10; 1942377Swnj goto number; 1952377Swnj case 'o': case 'O': 1962377Swnj b = 8; 1972377Swnj number: 19816724Sralph printn((u_long)*adx, b, flags, ttyp); 1992377Swnj break; 2002377Swnj case 'c': 2012434Swnj b = *adx; 20229946Skarels #if ENDIAN == LITTLE 2032434Swnj for (i = 24; i >= 0; i -= 8) 2042434Swnj if (c = (b >> i) & 0x7f) 20516724Sralph putchar(c, flags, ttyp); 20629946Skarels #endif 20729946Skarels #if ENDIAN == BIG 20829946Skarels if (c = (b & 0x7f)) 20929946Skarels putchar(c, flags, ttyp); 21029946Skarels #endif 2112377Swnj break; 2122678Swnj case 'b': 2132678Swnj b = *adx++; 2142678Swnj s = (char *)*adx; 21516724Sralph printn((u_long)b, *s++, flags, ttyp); 2162678Swnj any = 0; 2172678Swnj if (b) { 2182678Swnj while (i = *s++) { 2192678Swnj if (b & (1 << (i-1))) { 22029946Skarels putchar(any ? ',' : '<', flags, ttyp); 2212678Swnj any = 1; 2222678Swnj for (; (c = *s) > 32; s++) 22316724Sralph putchar(c, flags, ttyp); 2242678Swnj } else 2252678Swnj for (; *s > 32; s++) 2262678Swnj ; 2272678Swnj } 2283878Swnj if (any) 22916724Sralph putchar('>', flags, ttyp); 2302678Swnj } 2312678Swnj break; 2322678Swnj 2332377Swnj case 's': 23431Sbill s = (char *)*adx; 235285Sbill while (c = *s++) 23616724Sralph putchar(c, flags, ttyp); 2372377Swnj break; 2383736Sroot 2393736Sroot case '%': 24016724Sralph putchar('%', flags, ttyp); 2413736Sroot break; 24231Sbill } 24331Sbill adx++; 24431Sbill goto loop; 24531Sbill } 24631Sbill 2472781Swnj /* 2482781Swnj * Printn prints a number n in base b. 2492781Swnj * We don't use recursion to avoid deep kernel stacks. 2502781Swnj */ 25116724Sralph printn(n, b, flags, ttyp) 2523101Swnj u_long n; 25316724Sralph struct tty *ttyp; 25431Sbill { 2552434Swnj char prbuf[11]; 2562377Swnj register char *cp; 25731Sbill 25829946Skarels if (b == -10) { 25929946Skarels if ((int)n < 0) { 26029946Skarels putchar('-', flags, ttyp); 26129946Skarels n = (unsigned)(-(int)n); 26229946Skarels } 26329946Skarels b = -b; 26431Sbill } 2652434Swnj cp = prbuf; 2662377Swnj do { 2672377Swnj *cp++ = "0123456789abcdef"[n%b]; 2682377Swnj n /= b; 2692377Swnj } while (n); 2702377Swnj do 27116724Sralph putchar(*--cp, flags, ttyp); 2722434Swnj while (cp > prbuf); 27331Sbill } 27431Sbill 27531Sbill /* 2761184Sbill * Panic is called on unresolvable fatal errors. 2772781Swnj * It prints "panic: mesg", and then reboots. 2782781Swnj * If we are called twice, then we avoid trying to 2792781Swnj * sync the disks as this often leads to recursive panics. 28031Sbill */ 28131Sbill panic(s) 2822781Swnj char *s; 28331Sbill { 28430566Skarels int bootopt = RB_AUTOBOOT | RB_DUMP; 2852377Swnj 2865416Swnj if (panicstr) 2875416Swnj bootopt |= RB_NOSYNC; 2889758Ssam else { 2899758Ssam panicstr = s; 2908950Sroot } 2913285Swnj printf("panic: %s\n", s); 292*30625Skarels #ifdef KDB 293*30625Skarels if (boothowto & RB_KDB) { 294*30625Skarels int s = splnet(); /* below kdb pri */ 295*30625Skarels 296*30625Skarels setsoftkdb(); 297*30625Skarels splx(s); 298*30625Skarels } 299*30625Skarels #endif 30030566Skarels boot(bootopt); 30131Sbill } 30231Sbill 30331Sbill /* 3042941Swnj * Warn that a system table is full. 3052941Swnj */ 3062941Swnj tablefull(tab) 3072941Swnj char *tab; 3082941Swnj { 3092941Swnj 31024839Seric log(LOG_ERR, "%s: table is full\n", tab); 3112941Swnj } 3122941Swnj 3132941Swnj /* 3142781Swnj * Hard error is the preface to plaintive error messages 3152941Swnj * about failing disk transfers. 3162781Swnj */ 3172941Swnj harderr(bp, cp) 3182678Swnj struct buf *bp; 3192941Swnj char *cp; 32031Sbill { 32131Sbill 3222941Swnj printf("%s%d%c: hard error sn%d ", cp, 32324759Skarels minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno); 32431Sbill } 3252781Swnj 326285Sbill /* 3272377Swnj * Print a character on console or users terminal. 328285Sbill * If destination is console then the last MSGBUFS characters 329285Sbill * are saved in msgbuf for inspection later. 330285Sbill */ 3311785Sbill /*ARGSUSED*/ 33217594Skarels putchar(c, flags, tp) 3332377Swnj register int c; 33417594Skarels struct tty *tp; 335285Sbill { 33630549Skarels int startflags = flags; 337285Sbill 33830549Skarels if (panicstr) 33930549Skarels constty = 0; 34030549Skarels if ((flags & TOCONS) && tp == 0 && constty) { 34130549Skarels tp = constty; 34230549Skarels flags |= TOTTY; 34330549Skarels } 34416724Sralph if (flags & TOTTY) { 34525389Skarels register s = spltty(); 34625389Skarels 34725389Skarels if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == 34825389Skarels (TS_CARR_ON | TS_ISOPEN)) { 3492377Swnj if (c == '\n') 3504970Swnj (void) ttyoutput('\r', tp); 3514970Swnj (void) ttyoutput(c, tp); 3522360Skre ttstart(tp); 35330549Skarels } else if ((flags & TOCONS) && tp == constty) 35430549Skarels constty = 0; 35525389Skarels splx(s); 3562360Skre } 35729946Skarels /* 35829946Skarels * Can send to log only after memory management enabled: 35929946Skarels * this has happened by the time maxmem is set. 36029946Skarels */ 36129946Skarels if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && maxmem) { 3622172Swnj if (msgbuf.msg_magic != MSG_MAGIC) { 36312494Ssam register int i; 36412494Ssam 3652172Swnj msgbuf.msg_magic = MSG_MAGIC; 36616724Sralph msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 36712494Ssam for (i=0; i < MSG_BSIZE; i++) 36812494Ssam msgbuf.msg_bufc[i] = 0; 3692172Swnj } 37026427Sbloom msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 3712172Swnj if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 3722172Swnj msgbuf.msg_bufx = 0; 373285Sbill } 37430549Skarels if ((flags & TOCONS) && constty == 0 && c != '\0') 37530549Skarels (*v_putc)(c); 376285Sbill } 377