1 /* 2 * Copyright (c) 1982 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)subr_prf.c 6.9 (Berkeley) 09/17/85 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "seg.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "reboot.h" 15 #include "vm.h" 16 #include "msgbuf.h" 17 #include "dir.h" 18 #include "user.h" 19 #include "proc.h" 20 #include "ioctl.h" 21 #include "tty.h" 22 #include "syslog.h" 23 24 #ifdef vax 25 #include "../vax/mtpr.h" 26 #endif 27 28 #define TOCONS 0x1 29 #define TOTTY 0x2 30 #define TOLOG 0x4 31 32 /* 33 * In case console is off, 34 * panicstr contains argument to last 35 * call to panic. 36 */ 37 char *panicstr; 38 39 /* 40 * Scaled down version of C Library printf. 41 * Used to print diagnostic information directly on console tty. 42 * Since it is not interrupt driven, all system activities are 43 * suspended. Printf should not be used for chit-chat. 44 * 45 * One additional format: %b is supported to decode error registers. 46 * Usage is: 47 * printf("reg=%b\n", regval, "<base><arg>*"); 48 * Where <base> is the output base expressed as a control character, 49 * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 50 * characters, the first of which gives the bit number to be inspected 51 * (origin 1), and the next characters (up to a control character, i.e. 52 * a character <= 32), give the name of the register. Thus 53 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 54 * would produce output: 55 * reg=3<BITTWO,BITONE> 56 */ 57 /*VARARGS1*/ 58 printf(fmt, x1) 59 char *fmt; 60 unsigned x1; 61 { 62 63 prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)0); 64 logwakeup(); 65 } 66 67 /* 68 * Uprintf prints to the current user's terminal 69 * and does no watermark checking - (so no verbose messages). 70 */ 71 /*VARARGS1*/ 72 uprintf(fmt, x1) 73 char *fmt; 74 unsigned x1; 75 { 76 77 prf(fmt, &x1, TOTTY, u.u_ttyp); 78 } 79 80 /* 81 * tprintf prints on the specified terminal (console if none) 82 * and logs the message. It is designed for error messages from 83 * single-open devices, and may be called from interrupt level. 84 */ 85 /*VARARGS2*/ 86 tprintf(ttyp, fmt, x1) 87 struct tty *ttyp; 88 char *fmt; 89 unsigned x1; 90 { 91 92 prf(fmt, &x1, TOTTY | TOLOG, ttyp); 93 } 94 95 /* 96 * Log writes to the log buffer, 97 * and guarantees not to sleep (so can be called by interrupt routines). 98 * If there is no process reading the log yet, it writes to the console also. 99 */ 100 /*VARARGS2*/ 101 log(level, fmt, x1) 102 char *fmt; 103 unsigned x1; 104 { 105 register s = splhigh(); 106 extern int log_open; 107 108 putchar('<', TOLOG, (struct tty *)0); 109 printn(level, 10, TOLOG, (struct tty *)0); 110 putchar('>', TOLOG, (struct tty *)0); 111 prf(fmt, &x1, TOLOG, (struct tty *)0); 112 splx(s); 113 if (!log_open) 114 prf(fmt, &x1, TOCONS, (struct tty *)0); 115 logwakeup(); 116 } 117 118 prf(fmt, adx, flags, ttyp) 119 register char *fmt; 120 register u_int *adx; 121 struct tty *ttyp; 122 { 123 register int b, c, i; 124 char *s; 125 int any; 126 127 loop: 128 while ((c = *fmt++) != '%') { 129 if (c == '\0') 130 return; 131 putchar(c, flags, ttyp); 132 } 133 again: 134 c = *fmt++; 135 /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */ 136 switch (c) { 137 138 case 'l': 139 goto again; 140 case 'x': case 'X': 141 b = 16; 142 goto number; 143 case 'd': case 'D': 144 case 'u': /* what a joke */ 145 b = 10; 146 goto number; 147 case 'o': case 'O': 148 b = 8; 149 number: 150 printn((u_long)*adx, b, flags, ttyp); 151 break; 152 case 'c': 153 b = *adx; 154 for (i = 24; i >= 0; i -= 8) 155 if (c = (b >> i) & 0x7f) 156 putchar(c, flags, ttyp); 157 break; 158 case 'b': 159 b = *adx++; 160 s = (char *)*adx; 161 printn((u_long)b, *s++, flags, ttyp); 162 any = 0; 163 if (b) { 164 while (i = *s++) { 165 if (b & (1 << (i-1))) { 166 putchar(any? ',' : '<', flags, ttyp); 167 any = 1; 168 for (; (c = *s) > 32; s++) 169 putchar(c, flags, ttyp); 170 } else 171 for (; *s > 32; s++) 172 ; 173 } 174 if (any) 175 putchar('>', flags, ttyp); 176 } 177 break; 178 179 case 's': 180 s = (char *)*adx; 181 while (c = *s++) 182 putchar(c, flags, ttyp); 183 break; 184 185 case '%': 186 putchar('%', flags, ttyp); 187 break; 188 } 189 adx++; 190 goto loop; 191 } 192 193 /* 194 * Printn prints a number n in base b. 195 * We don't use recursion to avoid deep kernel stacks. 196 */ 197 printn(n, b, flags, ttyp) 198 u_long n; 199 struct tty *ttyp; 200 { 201 char prbuf[11]; 202 register char *cp; 203 204 if (b == 10 && (int)n < 0) { 205 putchar('-', flags, ttyp); 206 n = (unsigned)(-(int)n); 207 } 208 cp = prbuf; 209 do { 210 *cp++ = "0123456789abcdef"[n%b]; 211 n /= b; 212 } while (n); 213 do 214 putchar(*--cp, flags, ttyp); 215 while (cp > prbuf); 216 } 217 218 /* 219 * Panic is called on unresolvable fatal errors. 220 * It prints "panic: mesg", and then reboots. 221 * If we are called twice, then we avoid trying to 222 * sync the disks as this often leads to recursive panics. 223 */ 224 panic(s) 225 char *s; 226 { 227 int bootopt = RB_AUTOBOOT; 228 229 if (panicstr) 230 bootopt |= RB_NOSYNC; 231 else { 232 panicstr = s; 233 } 234 printf("panic: %s\n", s); 235 boot(RB_PANIC, bootopt); 236 } 237 238 /* 239 * Warn that a system table is full. 240 */ 241 tablefull(tab) 242 char *tab; 243 { 244 245 log(LOG_ERR, "%s: table is full\n", tab); 246 } 247 248 /* 249 * Hard error is the preface to plaintive error messages 250 * about failing disk transfers. 251 */ 252 harderr(bp, cp) 253 struct buf *bp; 254 char *cp; 255 { 256 257 printf("%s%d%c: hard error sn%d ", cp, 258 minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno); 259 } 260 261 /* 262 * Print a character on console or users terminal. 263 * If destination is console then the last MSGBUFS characters 264 * are saved in msgbuf for inspection later. 265 */ 266 /*ARGSUSED*/ 267 putchar(c, flags, tp) 268 register int c; 269 struct tty *tp; 270 { 271 extern struct tty cons; 272 273 if (flags & TOTTY) { 274 if (tp == (struct tty *)NULL && (flags & TOCONS) == 0) 275 tp = &cons; 276 if (tp && (tp->t_state & TS_CARR_ON)) { 277 register s = spl6(); 278 if (c == '\n') 279 (void) ttyoutput('\r', tp); 280 (void) ttyoutput(c, tp); 281 ttstart(tp); 282 splx(s); 283 } 284 } 285 if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 286 #ifdef vax 287 && mfpr(MAPEN) 288 #endif 289 ) { 290 if (msgbuf.msg_magic != MSG_MAGIC) { 291 register int i; 292 293 msgbuf.msg_magic = MSG_MAGIC; 294 msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 295 for (i=0; i < MSG_BSIZE; i++) 296 msgbuf.msg_bufc[i] = 0; 297 } 298 if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 299 msgbuf.msg_bufx = 0; 300 msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 301 } 302 if ((flags & TOCONS) && c != '\0') 303 cnputc(c); 304 } 305