1 /*- 2 * Copyright (c) 1986, 1988, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)subr_prf.c 7.22 (Berkeley) 05/04/91 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "buf.h" 13 #include "conf.h" 14 #include "reboot.h" 15 #include "msgbuf.h" 16 #include "proc.h" 17 #include "ioctl.h" 18 #include "vnode.h" 19 #include "file.h" 20 #include "tty.h" 21 #include "tprintf.h" 22 #include "syslog.h" 23 #include "malloc.h" 24 25 /* 26 * Note that stdarg.h and the ANSI style va_start macro is used for both 27 * ANSI and traditional C compilers. 28 */ 29 #include <machine/stdarg.h> 30 31 #ifdef KADB 32 #include "machine/kdbparam.h" 33 #endif 34 35 #define TOCONS 0x01 36 #define TOTTY 0x02 37 #define TOLOG 0x04 38 39 struct tty *constty; /* pointer to console "window" tty */ 40 41 #ifdef KADB 42 extern cngetc(); /* standard console getc */ 43 int (*v_getc)() = cngetc; /* "" getc from virtual console */ 44 extern cnpoll(); 45 int (*v_poll)() = cnpoll; /* kdb hook to enable input polling */ 46 #endif 47 extern cnputc(); /* standard console putc */ 48 int (*v_putc)() = cnputc; /* routine to putc on virtual console */ 49 50 static void logpri __P((int)); 51 static void putchar __P((int, int, struct tty *)); 52 static void kprintf __P((const char *, int, struct tty *, ...)); 53 static void kprintn __P((u_long, int)); 54 55 /* 56 * Variable panicstr contains argument to first call to panic; used 57 * as flag to indicate that the kernel has already called panic. 58 */ 59 char *panicstr; 60 61 /* 62 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 63 * and then reboots. If we are called twice, then we avoid trying to sync 64 * the disks as this often leads to recursive panics. 65 */ 66 void 67 panic(msg) 68 char *msg; 69 { 70 int bootopt = RB_AUTOBOOT | RB_DUMP; 71 int s; 72 73 if (panicstr) 74 bootopt |= RB_NOSYNC; 75 else 76 panicstr = msg; 77 printf("panic: %s\n", msg); 78 #ifdef KGDB 79 kgdb_panic(); 80 #endif 81 #ifdef KADB 82 if (boothowto & RB_KDB) { 83 s = splnet(); /* below kdb pri */ 84 setsoftkdb(); 85 splx(s); 86 } 87 #endif 88 boot(bootopt); 89 } 90 91 /* 92 * Warn that a system table is full. 93 */ 94 void 95 tablefull(tab) 96 char *tab; 97 { 98 99 log(LOG_ERR, "%s: table is full\n", tab); 100 } 101 102 /* 103 * Uprintf prints to the controlling terminal for the current process. 104 * It may block if the tty queue is overfull. No message is printed if 105 * the queue does not clear in a reasonable time. 106 */ 107 void 108 #ifdef __STDC__ 109 uprintf(const char *fmt, ...) 110 #else 111 uprintf(fmt /*, va_alist */) 112 char *fmt; 113 #endif 114 { 115 register struct proc *p = curproc; 116 va_list ap; 117 118 va_start(ap, fmt); 119 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) 120 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 121 va_end(ap); 122 } 123 124 tpr_t 125 tprintf_open(p) 126 register struct proc *p; 127 { 128 if (p->p_flag & SCTTY && p->p_session->s_ttyvp) { 129 SESSHOLD(p->p_session); 130 return ((tpr_t) p->p_session); 131 } 132 return ((tpr_t) NULL); 133 } 134 135 void 136 tprintf_close(sess) 137 tpr_t sess; 138 { 139 if (sess) 140 SESSRELE((struct session *) sess); 141 } 142 143 /* 144 * tprintf prints on the controlling terminal associated 145 * with the given session. 146 */ 147 void 148 #ifdef __STDC__ 149 tprintf(tpr_t tpr, const char *fmt, ...) 150 #else 151 tprintf(tpr, fmt /*, va_alist */) 152 tpr_t tpr; 153 char *fmt; 154 #endif 155 { 156 register struct session *sess = (struct session *)tpr; 157 struct tty *tp = NULL; 158 int flags = TOLOG; 159 va_list ap; 160 161 logpri(LOG_INFO); 162 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 163 flags |= TOTTY; 164 tp = sess->s_ttyp; 165 } 166 va_start(ap, fmt); 167 kprintf(fmt, flags, tp, ap); 168 va_end(ap); 169 logwakeup(); 170 } 171 172 /* 173 * Ttyprintf displays a message on a tty; it should be used only by 174 * the tty driver, or anything that knows the underlying tty will not 175 * be revoke(2)'d away. Other callers should use tprintf. 176 */ 177 void 178 #ifdef __STDC__ 179 ttyprintf(struct tty *tp, const char *fmt, ...) 180 #else 181 ttyprintf(tp, fmt /*, va_alist */) 182 struct tty *tp; 183 char *fmt; 184 #endif 185 { 186 va_list ap; 187 188 va_start(ap, fmt); 189 kprintf(fmt, TOTTY, tp, ap); 190 va_end(ap); 191 } 192 193 extern int log_open; 194 195 /* 196 * Log writes to the log buffer, and guarantees not to sleep (so can be 197 * called by interrupt routines). If there is no process reading the 198 * log yet, it writes to the console also. 199 */ 200 void 201 #ifdef __STDC__ 202 log(int level, const char *fmt, ...) 203 #else 204 log(level, fmt /*, va_alist */) 205 int level; 206 char *fmt; 207 #endif 208 { 209 register s = splhigh(); 210 va_list ap; 211 212 logpri(level); 213 va_start(ap, fmt); 214 kprintf(fmt, TOLOG, NULL, ap); 215 splx(s); 216 if (!log_open) 217 kprintf(fmt, TOCONS, NULL, ap); 218 va_end(ap); 219 logwakeup(); 220 } 221 222 static void 223 logpri(level) 224 int level; 225 { 226 227 putchar('<', TOLOG, NULL); 228 kprintn((u_long)level, 10, TOLOG, NULL); 229 putchar('>', TOLOG, NULL); 230 } 231 232 void 233 #ifdef __STDC__ 234 addlog(const char *fmt, ...) 235 #else 236 addlog(fmt /*, va_alist */) 237 char *fmt; 238 #endif 239 { 240 register s = splhigh(); 241 va_list ap; 242 243 va_start(ap, fmt); 244 kprintf(fmt, TOLOG, NULL, ap); 245 splx(s); 246 if (!log_open) 247 kprintf(fmt, TOCONS, NULL, ap); 248 va_end(ap); 249 logwakeup(); 250 } 251 252 int consintr = 1; /* ok to handle console interrupts? */ 253 254 void 255 #ifdef __STDC__ 256 printf(const char *fmt, ...) 257 #else 258 printf(fmt /*, va_alist */) 259 char *fmt; 260 #endif 261 { 262 register int savintr; 263 va_list ap; 264 265 savintr = consintr; /* disable interrupts */ 266 consintr = 0; 267 va_start(ap, fmt); 268 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 269 va_end(ap); 270 if (!panicstr) 271 logwakeup(); 272 consintr = savintr; /* reenable interrupts */ 273 } 274 275 /* 276 * Scaled down version of printf(3). 277 * 278 * Two additional formats: 279 * 280 * The format %b is supported to decode error registers. 281 * Its usage is: 282 * 283 * kprintf("reg=%b\n", regval, "<base><arg>*"); 284 * 285 * where <base> is the output base expressed as a control character, e.g. 286 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 287 * the first of which gives the bit number to be inspected (origin 1), and 288 * the next characters (up to a control character, i.e. a character <= 32), 289 * give the name of the register. Thus: 290 * 291 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 292 * 293 * would produce output: 294 * 295 * reg=3<BITTWO,BITONE> 296 * 297 * The format %r is supposed to pass an additional format string and argument 298 * list recursively. 299 * Its usage is: 300 * 301 * fn(otherstuff, fmt [, arg1, ... ]) 302 * char *fmt; 303 * u_int arg1, ...; 304 * 305 * kprintf("prefix: %r, other stuff\n", fmt, ap); 306 */ 307 static void 308 kprintf(fmt, flags, ttyp, ap) 309 register char *fmt; 310 int flags; 311 struct tty *ttyp; 312 va_list ap; 313 { 314 register char *p; 315 register int ch, n; 316 unsigned long ul; 317 int lflag, set; 318 319 for (;;) { 320 while ((ch = *fmt++) != '%') { 321 if (ch == '\0') 322 return; 323 putchar(ch, flags, ttyp); 324 } 325 lflag = 0; 326 reswitch: switch (ch = *fmt++) { 327 case 'l': 328 lflag = 1; 329 goto reswitch; 330 case 'b': 331 ul = va_arg(ap, int); 332 p = va_arg(ap, char *); 333 kprintn(ul, *p++); 334 335 if (!ul) 336 break; 337 338 for (set = 0; n = *p++;) { 339 if (ul & (1 << (n - 1))) { 340 putchar(set ? ',' : '<', flags, ttyp); 341 for (; (n = *p) > ' '; ++p) 342 putchar(n, flags, ttyp); 343 set = 1; 344 } else 345 for (; *p > ' '; ++p); 346 } 347 if (set) 348 putchar('>', flags, ttyp); 349 break; 350 case 'c': 351 putchar(va_arg(ap, int), flags, ttyp); 352 break; 353 case 'r': 354 p = va_arg(ap, char *); 355 kprintf(p, flags, ttyp, va_arg(ap, va_list)); 356 break; 357 case 's': 358 p = va_arg(ap, char *); 359 while (ch = *p++) 360 putchar(ch, flags, ttyp); 361 break; 362 case 'D': 363 lflag = 1; 364 /* FALLTHROUGH */ 365 case 'd': 366 ul = lflag ? 367 va_arg(ap, long) : va_arg(ap, int); 368 if ((long)ul < 0) { 369 putchar('-', flags, ttyp); 370 ul = -(long)ul; 371 } 372 kprintn(ul, 10); 373 break; 374 case 'O': 375 lflag = 1; 376 /* FALLTHROUGH */ 377 case 'o': 378 ul = lflag ? 379 va_arg(ap, u_long) : va_arg(ap, u_int); 380 kprintn(ul, 8); 381 break; 382 case 'U': 383 lflag = 1; 384 /* FALLTHROUGH */ 385 case 'u': 386 ul = lflag ? 387 va_arg(ap, u_long) : va_arg(ap, u_int); 388 kprintn(ul, 10); 389 break; 390 case 'X': 391 lflag = 1; 392 /* FALLTHROUGH */ 393 case 'x': 394 ul = lflag ? 395 va_arg(ap, u_long) : va_arg(ap, u_int); 396 kprintn(ul, 16); 397 break; 398 default: 399 putchar('%', flags, ttyp); 400 if (lflag) 401 putchar('l', flags, ttyp); 402 putchar(ch, flags, ttyp); 403 } 404 } 405 va_end(ap); 406 } 407 408 static void 409 kprintn(ul, base) 410 u_long ul; 411 int base; 412 { 413 /* hold a long in base 8 */ 414 char *p, buf[(sizeof(long) * NBBY >> 3) + 1]; 415 416 p = buf; 417 do { 418 *p++ = "0123456789abcdef"[ul % base]; 419 } while (ul /= base); 420 do { 421 putchar(*--p); 422 } while (p > buf); 423 } 424 425 /* 426 * Print a character on console or users terminal. If destination is 427 * the console then the last MSGBUFS characters are saved in msgbuf for 428 * inspection later. 429 */ 430 static void 431 putchar(c, flags, ttyp) 432 register int c; 433 int flags; 434 struct tty *ttyp; 435 { 436 extern int msgbufmapped; 437 register struct msgbuf *mbp; 438 439 if (panicstr) 440 constty = NULL; 441 if ((flags & TOCONS) && ttyp == NULL && constty) { 442 ttyp = constty; 443 flags |= TOTTY; 444 } 445 if ((flags & TOTTY) && ttyp && tputchar(c, ttyp) < 0 && 446 (flags & TOCONS) && ttyp == constty) 447 constty = NULL; 448 if ((flags & TOLOG) && 449 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 450 mbp = msgbufp; 451 if (mbp->msg_magic != MSG_MAGIC) { 452 register int i; 453 454 mbp->msg_magic = MSG_MAGIC; 455 mbp->msg_bufx = mbp->msg_bufr = 0; 456 for (i = 0; i < MSG_BSIZE; i++) 457 mbp->msg_bufc[i] = 0; 458 } 459 mbp->msg_bufc[mbp->msg_bufx++] = c; 460 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 461 mbp->msg_bufx = 0; 462 } 463 if ((flags & TOCONS) && constty == NULL && c != '\0') 464 (*v_putc)(c); 465 } 466