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