1 /* 2 * Copyright (c) 1982, 1986, 1988 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.18 (Berkeley) 06/28/90 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 "user.h" 18 #include "proc.h" 19 #include "ioctl.h" 20 #include "vnode.h" 21 #include "file.h" 22 #include "tty.h" 23 #include "tprintf.h" 24 #include "syslog.h" 25 #include "malloc.h" 26 27 #include "machine/mtpr.h" 28 #ifdef KADB 29 #include "machine/kdbparam.h" 30 #endif 31 32 #define TOCONS 0x1 33 #define TOTTY 0x2 34 #define TOLOG 0x4 35 36 /* 37 * In case console is off, 38 * panicstr contains argument to last 39 * call to panic. 40 */ 41 char *panicstr; 42 43 extern cnputc(); /* standard console putc */ 44 int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 45 extern struct tty cons; /* standard console tty */ 46 struct tty *constty; /* pointer to console "window" tty */ 47 48 #ifdef KADB 49 extern cngetc(); /* standard console getc */ 50 extern cnpoll(); 51 int (*v_getc)() = cngetc; /* "" getc from virtual console */ 52 int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */ 53 #endif 54 55 /* 56 * Scaled down version of C Library printf. 57 * Used to print diagnostic information directly on console tty. 58 * Since it is not interrupt driven, all system activities are 59 * suspended. Printf should not be used for chit-chat. 60 * 61 * One additional format: %b is supported to decode error registers. 62 * Usage is: 63 * printf("reg=%b\n", regval, "<base><arg>*"); 64 * Where <base> is the output base expressed as a control character, 65 * e.g. \10 gives octal; \20 gives hex. Each arg is a sequence of 66 * characters, the first of which gives the bit number to be inspected 67 * (origin 1), and the next characters (up to a control character, i.e. 68 * a character <= 32), give the name of the register. Thus 69 * printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 70 * would produce output: 71 * reg=3<BITTWO,BITONE> 72 * 73 * Another additional format: %r is used to pass an additional format string 74 * and argument list recursively. Usage is typically: 75 * 76 * fn(otherstuff, fmt [, arg1, ... ] ) 77 * char *fmt; 78 * u_int arg1, ...; 79 * 80 * printf("prefix: %r, other stuff\n", fmt, &arg1); 81 */ 82 #if defined(tahoe) 83 int consintr; 84 #endif 85 86 /*VARARGS1*/ 87 printf(fmt, x1) 88 char *fmt; 89 unsigned x1; 90 { 91 #if defined(tahoe) 92 register int savintr; 93 94 savintr = consintr, consintr = 0; /* disable interrupts */ 95 #endif 96 prf(fmt, &x1, TOCONS | TOLOG, (struct tty *)NULL); 97 if (!panicstr) 98 logwakeup(); 99 #if defined(tahoe) 100 consintr = savintr; /* reenable interrupts */ 101 #endif 102 } 103 104 /* 105 * Uprintf prints to the controlling terminal for the current process. 106 * It may block if the tty queue is overfull. 107 * No message is printed if the queue does not clear 108 * in a reasonable time. 109 */ 110 /*VARARGS1*/ 111 uprintf(fmt, x1) 112 char *fmt; 113 unsigned x1; 114 { 115 register struct proc *p = u.u_procp; 116 117 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) 118 prf(fmt, &x1, TOTTY, p->p_session->s_ttyp); 119 } 120 121 tpr_t 122 tprintf_open() 123 { 124 register struct proc *p = u.u_procp; 125 126 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 127 SESSHOLD(p->p_session); 128 return ((tpr_t)p->p_session); 129 } else 130 return ((tpr_t)NULL); 131 } 132 133 tprintf_close(sess) 134 tpr_t sess; 135 { 136 if (sess) 137 SESSRELE(sess); 138 } 139 140 /* 141 * tprintf prints on the controlling terminal associated 142 * with the given session. 143 */ 144 /*VARARGS2*/ 145 tprintf(sess, fmt, x1) 146 register tpr_t sess; 147 char *fmt; 148 unsigned x1; 149 { 150 int flags = TOLOG; 151 152 logpri(LOG_INFO); 153 154 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) 155 flags |= TOTTY; 156 prf(fmt, &x1, flags, sess->s_ttyp); 157 logwakeup(); 158 } 159 160 161 /* 162 * Log writes to the log buffer, 163 * and guarantees not to sleep (so can be called by interrupt routines). 164 * If there is no process reading the log yet, it writes to the console also. 165 */ 166 /*VARARGS2*/ 167 log(level, fmt, x1) 168 char *fmt; 169 unsigned x1; 170 { 171 register s = splhigh(); 172 extern int log_open; 173 174 logpri(level); 175 prf(fmt, &x1, TOLOG, (struct tty *)NULL); 176 splx(s); 177 if (!log_open) 178 prf(fmt, &x1, TOCONS, (struct tty *)NULL); 179 logwakeup(); 180 } 181 182 logpri(level) 183 int level; 184 { 185 186 putchar('<', TOLOG, (struct tty *)NULL); 187 printn((u_long)level, 10, TOLOG, (struct tty *)NULL); 188 putchar('>', TOLOG, (struct tty *)NULL); 189 } 190 191 /*VARARGS1*/ 192 addlog(fmt, x1) 193 char *fmt; 194 unsigned x1; 195 { 196 register s = splhigh(); 197 198 prf(fmt, &x1, TOLOG, (struct tty *)NULL); 199 splx(s); 200 if (!log_open) 201 prf(fmt, &x1, TOCONS, (struct tty *)NULL); 202 logwakeup(); 203 } 204 205 prf(fmt, adx, flags, ttyp) 206 register char *fmt; 207 register u_int *adx; 208 struct tty *ttyp; 209 { 210 register int b, c, i; 211 char *s; 212 int any; 213 214 loop: 215 while ((c = *fmt++) != '%') { 216 if (c == '\0') 217 return; 218 putchar(c, flags, ttyp); 219 } 220 again: 221 c = *fmt++; 222 /* THIS CODE IS MACHINE DEPENDENT IN HANDLING %l? AND %c */ 223 switch (c) { 224 225 case 'l': 226 goto again; 227 case 'x': case 'X': 228 b = 16; 229 goto number; 230 case 'd': case 'D': 231 b = -10; 232 goto number; 233 case 'u': 234 b = 10; 235 goto number; 236 case 'o': case 'O': 237 b = 8; 238 number: 239 printn((u_long)*adx, b, flags, ttyp); 240 break; 241 case 'c': 242 b = *adx; 243 #if BYTE_ORDER == LITTLE_ENDIAN 244 for (i = 24; i >= 0; i -= 8) 245 if (c = (b >> i) & 0x7f) 246 putchar(c, flags, ttyp); 247 #endif 248 #if BYTE_ORDER == BIG_ENDIAN 249 if (c = (b & 0x7f)) 250 putchar(c, flags, ttyp); 251 #endif 252 break; 253 case 'b': 254 b = *adx++; 255 s = (char *)*adx; 256 printn((u_long)b, *s++, flags, ttyp); 257 any = 0; 258 if (b) { 259 while (i = *s++) { 260 if (b & (1 << (i-1))) { 261 putchar(any ? ',' : '<', flags, ttyp); 262 any = 1; 263 for (; (c = *s) > 32; s++) 264 putchar(c, flags, ttyp); 265 } else 266 for (; *s > 32; s++) 267 ; 268 } 269 if (any) 270 putchar('>', flags, ttyp); 271 } 272 break; 273 274 case 's': 275 s = (char *)*adx; 276 while (c = *s++) 277 putchar(c, flags, ttyp); 278 break; 279 280 case 'r': 281 s = (char *)*adx++; 282 prf(s, (u_int *)*adx, flags, ttyp); 283 break; 284 285 case '%': 286 putchar('%', flags, ttyp); 287 break; 288 } 289 adx++; 290 goto loop; 291 } 292 293 /* 294 * Printn prints a number n in base b. 295 * We don't use recursion to avoid deep kernel stacks. 296 */ 297 printn(n, b, flags, ttyp) 298 u_long n; 299 struct tty *ttyp; 300 { 301 char prbuf[11]; 302 register char *cp; 303 304 if (b == -10) { 305 if ((int)n < 0) { 306 putchar('-', flags, ttyp); 307 n = (unsigned)(-(int)n); 308 } 309 b = -b; 310 } 311 cp = prbuf; 312 do { 313 *cp++ = "0123456789abcdef"[n%b]; 314 n /= b; 315 } while (n); 316 do 317 putchar(*--cp, flags, ttyp); 318 while (cp > prbuf); 319 } 320 321 /* 322 * Panic is called on unresolvable fatal errors. 323 * It prints "panic: mesg", and then reboots. 324 * If we are called twice, then we avoid trying to 325 * sync the disks as this often leads to recursive panics. 326 */ 327 panic(s) 328 char *s; 329 { 330 int bootopt = RB_AUTOBOOT | RB_DUMP; 331 332 if (panicstr) 333 bootopt |= RB_NOSYNC; 334 else { 335 panicstr = s; 336 } 337 printf("panic: %s\n", s); 338 #ifdef KADB 339 if (boothowto & RB_KDB) { 340 int x = splnet(); /* below kdb pri */ 341 342 setsoftkdb(); 343 splx(x); 344 } 345 #endif 346 boot(bootopt); 347 } 348 349 /* 350 * Warn that a system table is full. 351 */ 352 tablefull(tab) 353 char *tab; 354 { 355 356 log(LOG_ERR, "%s: table is full\n", tab); 357 } 358 359 /* 360 * Print a character on console or users terminal. 361 * If destination is console then the last MSGBUFS characters 362 * are saved in msgbuf for inspection later. 363 */ 364 /*ARGSUSED*/ 365 putchar(c, flags, ttyp) 366 register int c; 367 struct tty *ttyp; 368 { 369 extern int msgbufmapped; 370 371 if (panicstr) 372 constty = 0; 373 if ((flags & TOCONS) && ttyp == NULL && constty) { 374 ttyp = constty; 375 flags |= TOTTY; 376 } 377 if ((flags & TOTTY) && ttyp && tputchar(c, ttyp) < 0 && 378 (flags & TOCONS) && ttyp == constty) 379 constty = 0; 380 if ((flags & TOLOG) && c != '\0' && c != '\r' && c != 0177 && 381 msgbufmapped) { 382 if (msgbuf.msg_magic != MSG_MAGIC) { 383 register int i; 384 385 msgbuf.msg_magic = MSG_MAGIC; 386 msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 387 for (i=0; i < MSG_BSIZE; i++) 388 msgbuf.msg_bufc[i] = 0; 389 } 390 msgbuf.msg_bufc[msgbuf.msg_bufx++] = c; 391 if (msgbuf.msg_bufx < 0 || msgbuf.msg_bufx >= MSG_BSIZE) 392 msgbuf.msg_bufx = 0; 393 } 394 if ((flags & TOCONS) && constty == 0 && c != '\0') 395 (*v_putc)(c); 396 } 397