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