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