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.12 (Berkeley) 02/23/86 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 * It may block if the tty queue is overfull. 70 * Should determine whether current terminal user is related 71 * to this process. 72 */ 73 /*VARARGS1*/ 74 uprintf(fmt, x1) 75 char *fmt; 76 unsigned x1; 77 { 78 #ifdef notdef 79 register struct proc *p; 80 #endif 81 register struct tty *tp; 82 83 if ((tp = u.u_ttyp) == NULL) 84 return; 85 #ifdef notdef 86 if (tp->t_pgrp && (p = pfind(tp->t_pgrp))) 87 if (p->p_uid != u.u_uid) /* doesn't account for setuid */ 88 return; 89 #endif 90 (void)ttycheckoutq(tp, 1); 91 prf(fmt, &x1, TOTTY, tp); 92 } 93 94 /* 95 * tprintf prints on the specified terminal (console if none) 96 * and logs the message. It is designed for error messages from 97 * single-open devices, and may be called from interrupt level 98 * (does not sleep). 99 */ 100 /*VARARGS2*/ 101 tprintf(tp, fmt, x1) 102 register struct tty *tp; 103 char *fmt; 104 unsigned x1; 105 { 106 int flags = TOTTY | TOLOG; 107 extern struct tty cons; 108 109 logpri(LOG_INFO); 110 if (tp == (struct tty *)NULL) 111 tp = &cons; 112 if (ttycheckoutq(tp, 0) == 0) 113 flags = TOLOG; 114 prf(fmt, &x1, flags, tp); 115 logwakeup(); 116 } 117 118 /* 119 * Log writes to the log buffer, 120 * and guarantees not to sleep (so can be called by interrupt routines). 121 * If there is no process reading the log yet, it writes to the console also. 122 */ 123 /*VARARGS2*/ 124 log(level, fmt, x1) 125 char *fmt; 126 unsigned x1; 127 { 128 register s = splhigh(); 129 extern int log_open; 130 131 logpri(level); 132 prf(fmt, &x1, TOLOG, (struct tty *)0); 133 splx(s); 134 if (!log_open) 135 prf(fmt, &x1, TOCONS, (struct tty *)0); 136 logwakeup(); 137 } 138 139 logpri(level) 140 int level; 141 { 142 143 putchar('<', TOLOG, (struct tty *)0); 144 printn((u_long)level, 10, TOLOG, (struct tty *)0); 145 putchar('>', TOLOG, (struct tty *)0); 146 } 147 148 prf(fmt, adx, flags, ttyp) 149 register char *fmt; 150 register u_int *adx; 151 struct tty *ttyp; 152 { 153 register int b, c, i; 154 char *s; 155 int any; 156 157 loop: 158 while ((c = *fmt++) != '%') { 159 if (c == '\0') 160 return; 161 putchar(c, flags, ttyp); 162 } 163 again: 164 c = *fmt++; 165 /* THIS CODE IS VAX DEPENDENT IN HANDLING %l? AND %c */ 166 switch (c) { 167 168 case 'l': 169 goto again; 170 case 'x': case 'X': 171 b = 16; 172 goto number; 173 case 'd': case 'D': 174 case 'u': /* what a joke */ 175 b = 10; 176 goto number; 177 case 'o': case 'O': 178 b = 8; 179 number: 180 printn((u_long)*adx, b, flags, ttyp); 181 break; 182 case 'c': 183 b = *adx; 184 for (i = 24; i >= 0; i -= 8) 185 if (c = (b >> i) & 0x7f) 186 putchar(c, flags, ttyp); 187 break; 188 case 'b': 189 b = *adx++; 190 s = (char *)*adx; 191 printn((u_long)b, *s++, flags, ttyp); 192 any = 0; 193 if (b) { 194 while (i = *s++) { 195 if (b & (1 << (i-1))) { 196 putchar(any? ',' : '<', flags, ttyp); 197 any = 1; 198 for (; (c = *s) > 32; s++) 199 putchar(c, flags, ttyp); 200 } else 201 for (; *s > 32; s++) 202 ; 203 } 204 if (any) 205 putchar('>', flags, ttyp); 206 } 207 break; 208 209 case 's': 210 s = (char *)*adx; 211 while (c = *s++) 212 putchar(c, flags, ttyp); 213 break; 214 215 case '%': 216 putchar('%', flags, ttyp); 217 break; 218 } 219 adx++; 220 goto loop; 221 } 222 223 /* 224 * Printn prints a number n in base b. 225 * We don't use recursion to avoid deep kernel stacks. 226 */ 227 printn(n, b, flags, ttyp) 228 u_long n; 229 struct tty *ttyp; 230 { 231 char prbuf[11]; 232 register char *cp; 233 234 if (b == 10 && (int)n < 0) { 235 putchar('-', flags, ttyp); 236 n = (unsigned)(-(int)n); 237 } 238 cp = prbuf; 239 do { 240 *cp++ = "0123456789abcdef"[n%b]; 241 n /= b; 242 } while (n); 243 do 244 putchar(*--cp, flags, ttyp); 245 while (cp > prbuf); 246 } 247 248 /* 249 * Panic is called on unresolvable fatal errors. 250 * It prints "panic: mesg", and then reboots. 251 * If we are called twice, then we avoid trying to 252 * sync the disks as this often leads to recursive panics. 253 */ 254 panic(s) 255 char *s; 256 { 257 int bootopt = RB_AUTOBOOT; 258 259 if (panicstr) 260 bootopt |= RB_NOSYNC; 261 else { 262 panicstr = s; 263 } 264 printf("panic: %s\n", s); 265 boot(RB_PANIC, bootopt); 266 } 267 268 /* 269 * Warn that a system table is full. 270 */ 271 tablefull(tab) 272 char *tab; 273 { 274 275 log(LOG_ERR, "%s: table is full\n", tab); 276 } 277 278 /* 279 * Hard error is the preface to plaintive error messages 280 * about failing disk transfers. 281 */ 282 harderr(bp, cp) 283 struct buf *bp; 284 char *cp; 285 { 286 287 printf("%s%d%c: hard error sn%d ", cp, 288 minor(bp->b_dev) >> 3, 'a'+(minor(bp->b_dev)&07), bp->b_blkno); 289 } 290 291 /* 292 * Print a character on console or users terminal. 293 * If destination is console then the last MSGBUFS characters 294 * are saved in msgbuf for inspection later. 295 */ 296 /*ARGSUSED*/ 297 putchar(c, flags, tp) 298 register int c; 299 struct tty *tp; 300 { 301 302 if (flags & TOTTY) { 303 register s = spltty(); 304 305 if (tp && (tp->t_state & (TS_CARR_ON | TS_ISOPEN)) == 306 (TS_CARR_ON | TS_ISOPEN)) { 307 if (c == '\n') 308 (void) ttyoutput('\r', tp); 309 (void) ttyoutput(c, tp); 310 ttstart(tp); 311 } 312 splx(s); 313 } 314 if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 315 #ifdef vax 316 && mfpr(MAPEN) 317 #endif 318 ) { 319 if (msgbuf.msg_magic != MSG_MAGIC) { 320 register int i; 321 322 msgbuf.msg_magic = MSG_MAGIC; 323 msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 324 for (i=0; i < MSG_BSIZE; i++) 325 msgbuf.msg_bufc[i] = 0; 326 } 327 if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 328 msgbuf.msg_bufx = 0; 329 msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 330 } 331 if ((flags & TOCONS) && c != '\0') 332 cnputc(c); 333 } 334