42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/reboot.h> 45#include <sys/msgbuf.h> 46#include <sys/proc.h> 47#include <sys/vnode.h> 48#include <sys/tty.h> 49#include <sys/tprintf.h> 50#include <sys/syslog.h> 51#include <sys/malloc.h> 52#include <machine/cons.h> 53 54/* 55 * Note that stdarg.h and the ANSI style va_start macro is used for both 56 * ANSI and traditional C compilers. 57 */ 58#include <machine/stdarg.h> 59 60#ifdef KADB 61#include <machine/kdbparam.h> 62#endif 63 64 65#define TOCONS 0x01 66#define TOTTY 0x02 67#define TOLOG 0x04 68 69struct tty *constty; /* pointer to console "window" tty */ 70 71static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 72 73static void logpri __P((int level)); 74static void putchar __P((int ch, int flags, struct tty *tp)); 75static char *ksprintn __P((u_long num, int base, int *len)); 76 77static int consintr = 1; /* Ok to handle console interrupts? */ 78 79/* 80 * Variable panicstr contains argument to first call to panic; used as flag 81 * to indicate that the kernel has already called panic. 82 */ 83const char *panicstr; 84 85/* 86 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 87 * and then reboots. If we are called twice, then we avoid trying to sync 88 * the disks as this often leads to recursive panics. 89 */ 90#ifdef __GNUC__ 91__dead /* panic() does not return */ 92#endif 93void 94#ifdef __STDC__ 95panic(const char *fmt, ...) 96#else 97panic(fmt, va_alist) 98 char *fmt; 99#endif 100{ 101 int bootopt; 102 va_list ap; 103 104 bootopt = RB_AUTOBOOT | RB_DUMP; 105 if (panicstr) 106 bootopt |= RB_NOSYNC; 107 else 108 panicstr = fmt; 109 110 va_start(ap, fmt); 111 printf("panic: %r\n", fmt, ap); 112 va_end(ap); 113 114#ifdef KGDB 115 kgdb_panic(); 116#endif 117#ifdef KADB 118 if (boothowto & RB_KDB) 119 kdbpanic(); 120#endif 121#ifdef DDB 122 Debugger ("panic"); 123#endif 124 boot(bootopt); 125} 126 127/* 128 * Warn that a system table is full. 129 */ 130void 131tablefull(tab) 132 const char *tab; 133{ 134 135 log(LOG_ERR, "%s: table is full\n", tab); 136} 137 138/* 139 * Uprintf prints to the controlling terminal for the current process. 140 * It may block if the tty queue is overfull. No message is printed if 141 * the queue does not clear in a reasonable time. 142 */ 143void 144#ifdef __STDC__ 145uprintf(const char *fmt, ...) 146#else 147uprintf(fmt, va_alist) 148 char *fmt; 149#endif 150{ 151 register struct proc *p = curproc; 152 va_list ap; 153 154 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 155 va_start(ap, fmt); 156 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 157 va_end(ap); 158 } 159} 160 161tpr_t 162tprintf_open(p) 163 register struct proc *p; 164{ 165 166 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 167 SESSHOLD(p->p_session); 168 return ((tpr_t) p->p_session); 169 } 170 return ((tpr_t) NULL); 171} 172 173void 174tprintf_close(sess) 175 tpr_t sess; 176{ 177 178 if (sess) 179 SESSRELE((struct session *) sess); 180} 181 182/* 183 * tprintf prints on the controlling terminal associated 184 * with the given session. 185 */ 186void 187#ifdef __STDC__ 188tprintf(tpr_t tpr, const char *fmt, ...) 189#else 190tprintf(tpr, fmt, va_alist) 191 tpr_t tpr; 192 char *fmt; 193#endif 194{ 195 register struct session *sess = (struct session *)tpr; 196 struct tty *tp = NULL; 197 int flags = TOLOG; 198 va_list ap; 199 200 logpri(LOG_INFO); 201 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 202 flags |= TOTTY; 203 tp = sess->s_ttyp; 204 } 205 va_start(ap, fmt); 206 kprintf(fmt, flags, tp, ap); 207 va_end(ap); 208 logwakeup(); 209} 210 211/* 212 * Ttyprintf displays a message on a tty; it should be used only by 213 * the tty driver, or anything that knows the underlying tty will not 214 * be revoke(2)'d away. Other callers should use tprintf. 215 */ 216void 217#ifdef __STDC__ 218ttyprintf(struct tty *tp, const char *fmt, ...) 219#else 220ttyprintf(tp, fmt, va_alist) 221 struct tty *tp; 222 char *fmt; 223#endif 224{ 225 va_list ap; 226 227 va_start(ap, fmt); 228 kprintf(fmt, TOTTY, tp, ap); 229 va_end(ap); 230} 231 232extern int log_open; 233 234/* 235 * Log writes to the log buffer, and guarantees not to sleep (so can be 236 * called by interrupt routines). If there is no process reading the 237 * log yet, it writes to the console also. 238 */ 239void 240#ifdef __STDC__ 241log(int level, const char *fmt, ...) 242#else 243log(level, fmt, va_alist) 244 int level; 245 char *fmt; 246#endif 247{ 248 register int s; 249 va_list ap; 250 251 s = splhigh(); 252 logpri(level); 253 va_start(ap, fmt); 254 kprintf(fmt, TOLOG, NULL, ap); 255 splx(s); 256 va_end(ap); 257 if (!log_open) { 258 va_start(ap, fmt); 259 kprintf(fmt, TOCONS, NULL, ap); 260 va_end(ap); 261 } 262 logwakeup(); 263} 264 265static void 266logpri(level) 267 int level; 268{ 269 register char *p; 270 271 putchar('<', TOLOG, NULL); 272 for (p = ksprintn((u_long)level, 10, NULL); *p;) 273 putchar(*p--, TOLOG, NULL); 274 putchar('>', TOLOG, NULL); 275} 276 277void 278#ifdef __STDC__ 279addlog(const char *fmt, ...) 280#else 281addlog(fmt, va_alist) 282 char *fmt; 283#endif 284{ 285 register int s; 286 va_list ap; 287 288 s = splhigh(); 289 va_start(ap, fmt); 290 kprintf(fmt, TOLOG, NULL, ap); 291 splx(s); 292 va_end(ap); 293 if (!log_open) { 294 va_start(ap, fmt); 295 kprintf(fmt, TOCONS, NULL, ap); 296 va_end(ap); 297 } 298 logwakeup(); 299} 300 301void 302#ifdef __STDC__ 303printf(const char *fmt, ...) 304#else 305printf(fmt, va_alist) 306 char *fmt; 307#endif 308{ 309 va_list ap; 310 register int savintr; 311 312 savintr = consintr; /* disable interrupts */ 313 consintr = 0; 314 va_start(ap, fmt); 315 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 316 va_end(ap); 317 if (!panicstr) 318 logwakeup(); 319 consintr = savintr; /* reenable interrupts */ 320} 321 322/* 323 * Scaled down version of printf(3). 324 * 325 * Two additional formats: 326 * 327 * The format %b is supported to decode error registers. 328 * Its usage is: 329 * 330 * printf("reg=%b\n", regval, "<base><arg>*"); 331 * 332 * where <base> is the output base expressed as a control character, e.g. 333 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 334 * the first of which gives the bit number to be inspected (origin 1), and 335 * the next characters (up to a control character, i.e. a character <= 32), 336 * give the name of the register. Thus: 337 * 338 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 339 * 340 * would produce output: 341 * 342 * reg=3<BITTWO,BITONE> 343 * 344 * The format %r passes an additional format string and argument list 345 * recursively. Its usage is: 346 * 347 * fn(char *fmt, ...) 348 * { 349 * va_list ap; 350 * va_start(ap, fmt); 351 * printf("prefix: %r: suffix\n", fmt, ap); 352 * va_end(ap); 353 * } 354 * 355 * Space or zero padding and a field width are supported for the numeric 356 * formats only. 357 */ 358void 359kprintf(fmt, flags, tp, ap) 360 register const char *fmt; 361 int flags; 362 struct tty *tp; 363 va_list ap; 364{ 365 register char *p, *q; 366 register int ch, n; 367 u_long ul; 368 int base, lflag, tmp, width; 369 char padc; 370 371 if (fmt == NULL) 372 fmt = "(fmt null)\n"; 373 for (;;) { 374 padc = ' '; 375 width = 0; 376 while ((ch = *(u_char *)fmt++) != '%') { 377 if (ch == '\0') 378 return; 379 putchar(ch, flags, tp); 380 } 381 lflag = 0; 382reswitch: switch (ch = *(u_char *)fmt++) { 383 case '0': 384 padc = '0'; 385 goto reswitch; 386 case '1': case '2': case '3': case '4': 387 case '5': case '6': case '7': case '8': case '9': 388 for (width = 0;; ++fmt) { 389 width = width * 10 + ch - '0'; 390 ch = *fmt; 391 if (ch < '0' || ch > '9') 392 break; 393 } 394 goto reswitch; 395 case 'l': 396 lflag = 1; 397 goto reswitch; 398 case 'b': 399 ul = va_arg(ap, int); 400 p = va_arg(ap, char *); 401 for (q = ksprintn(ul, *p++, NULL); *q;) 402 putchar(*q--, flags, tp); 403 404 if (!ul) 405 break; 406 407 for (tmp = 0; *p;) { 408 n = *p++; 409 if (ul & (1 << (n - 1))) { 410 putchar(tmp ? ',' : '<', flags, tp); 411 for (; (n = *p) > ' '; ++p) 412 putchar(n, flags, tp); 413 tmp = 1; 414 } else 415 for (; *p > ' '; ++p) 416 continue; 417 } 418 if (tmp) 419 putchar('>', flags, tp); 420 break; 421 case 'c': 422 putchar(va_arg(ap, int), flags, tp); 423 break; 424 case 'r': 425 p = va_arg(ap, char *); 426 kprintf(p, flags, tp, va_arg(ap, va_list)); 427 break; 428 case 's': 429 p = va_arg(ap, char *); 430 if (p == NULL) 431 p = "(null)"; 432 while (*p) 433 putchar(*p++, flags, tp); 434 break; 435 case 'd': 436 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 437 if ((long)ul < 0) { 438 putchar('-', flags, tp); 439 ul = -(long)ul; 440 } 441 base = 10; 442 goto number; 443 case 'o': 444 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 445 base = 8; 446 goto number; 447 case 'p': 448 ul = (u_long)va_arg(ap, void *); 449 base = 16; 450 putchar('0', flags, tp); 451 putchar('x', flags, tp); 452 goto number; 453 case 'u': 454 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 455 base = 10; 456 goto number; 457 case 'x': 458 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 459 base = 16; 460number: p = ksprintn(ul, base, &tmp); 461 if (width && (width -= tmp) > 0) 462 while (width--) 463 putchar(padc, flags, tp); 464 while (*p) 465 putchar(*p--, flags, tp); 466 break; 467 default: 468 putchar('%', flags, tp); 469 if (lflag) 470 putchar('l', flags, tp); 471 /* FALLTHROUGH */ 472 case '%': 473 putchar(ch, flags, tp); 474 } 475 } 476} 477 478/* 479 * Print a character on console or users terminal. If destination is 480 * the console then the last MSGBUFS characters are saved in msgbuf for 481 * inspection later. 482 */ 483static void 484putchar(c, flags, tp) 485 register int c; 486 int flags; 487 struct tty *tp; 488{ 489 register struct msgbuf *mbp; 490 491 if (panicstr) 492 constty = NULL; 493 if ((flags & TOCONS) && tp == NULL && constty) { 494 tp = constty; 495 flags |= TOTTY; 496 } 497 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 498 (flags & TOCONS) && tp == constty) 499 constty = NULL; 500 if ((flags & TOLOG) && 501 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 502 mbp = msgbufp; 503 if (mbp->msg_magic != MSG_MAGIC || 504 mbp->msg_bufx >= MSG_BSIZE || 505 mbp->msg_bufr >= MSG_BSIZE) { 506 bzero(mbp, sizeof(struct msgbuf)); 507 mbp->msg_magic = MSG_MAGIC; 508 } 509 mbp->msg_bufc[mbp->msg_bufx++] = c; 510 if (mbp->msg_bufx >= MSG_BSIZE) 511 mbp->msg_bufx = 0; 512 /* If the buffer is full, keep the most recent data. */ 513 if (mbp->msg_bufr == mbp->msg_bufx) { 514 if (++mbp->msg_bufr >= MSG_BSIZE) 515 mbp->msg_bufr = 0; 516 } 517 } 518 if ((flags & TOCONS) && constty == NULL && c != '\0') 519 (*v_putc)(c); 520} 521 522/* 523 * Scaled down version of sprintf(3). 524 */ 525#ifdef __STDC__ 526int 527sprintf(char *buf, const char *cfmt, ...) 528#else 529int 530sprintf(buf, cfmt, va_alist) 531 char *buf, *cfmt; 532#endif 533{ 534 register const char *fmt = cfmt; 535 register char *p, *bp; 536 register int ch, base; 537 u_long ul; 538 int lflag; 539 va_list ap; 540 541 va_start(ap, cfmt); 542 for (bp = buf; ; ) { 543 while ((ch = *(u_char *)fmt++) != '%') 544 if ((*bp++ = ch) == '\0') 545 return ((bp - buf) - 1); 546 547 lflag = 0; 548reswitch: switch (ch = *(u_char *)fmt++) { 549 case 'l': 550 lflag = 1; 551 goto reswitch; 552 case 'c': 553 *bp++ = va_arg(ap, int); 554 break; 555 case 's': 556 p = va_arg(ap, char *); 557 while (*p) 558 *bp++ = *p++; 559 break; 560 case 'd': 561 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 562 if ((long)ul < 0) { 563 *bp++ = '-'; 564 ul = -(long)ul; 565 } 566 base = 10; 567 goto number; 568 break; 569 case 'o': 570 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 571 base = 8; 572 goto number; 573 break; 574 case 'p': 575 ul = (u_long)va_arg(ap, void *); 576 base = 16; 577 *bp++ = '0'; 578 *bp++ = 'x'; 579 goto number; 580 case 'u': 581 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 582 base = 10; 583 goto number; 584 break; 585 case 'x': 586 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 587 base = 16; 588number: for (p = ksprintn(ul, base, NULL); *p;) 589 *bp++ = *p--; 590 break; 591 default: 592 *bp++ = '%'; 593 if (lflag) 594 *bp++ = 'l'; 595 /* FALLTHROUGH */ 596 case '%': 597 *bp++ = ch; 598 } 599 } 600 va_end(ap); 601} 602 603/* 604 * Put a number (base <= 16) in a buffer in reverse order; return an 605 * optional length and a pointer to the NULL terminated (preceded?) 606 * buffer. 607 */ 608static char * 609ksprintn(ul, base, lenp) 610 register u_long ul; 611 register int base, *lenp; 612{ /* A long in base 8, plus NULL. */ 613 static char buf[sizeof(long) * NBBY / 3 + 2]; 614 register char *p; 615 616 p = buf; 617 do { 618 *++p = "0123456789abcdef"[ul % base]; 619 } while (ul /= base); 620 if (lenp) 621 *lenp = p - buf; 622 return (p); 623}
| 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/reboot.h> 47#include <sys/msgbuf.h> 48#include <sys/proc.h> 49#include <sys/vnode.h> 50#include <sys/tty.h> 51#include <sys/tprintf.h> 52#include <sys/syslog.h> 53#include <sys/malloc.h> 54#include <machine/cons.h> 55 56/* 57 * Note that stdarg.h and the ANSI style va_start macro is used for both 58 * ANSI and traditional C compilers. 59 */ 60#include <machine/stdarg.h> 61 62#ifdef KADB 63#include <machine/kdbparam.h> 64#endif 65 66 67#define TOCONS 0x01 68#define TOTTY 0x02 69#define TOLOG 0x04 70 71struct tty *constty; /* pointer to console "window" tty */ 72 73static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 74 75static void logpri __P((int level)); 76static void putchar __P((int ch, int flags, struct tty *tp)); 77static char *ksprintn __P((u_long num, int base, int *len)); 78 79static int consintr = 1; /* Ok to handle console interrupts? */ 80 81/* 82 * Variable panicstr contains argument to first call to panic; used as flag 83 * to indicate that the kernel has already called panic. 84 */ 85const char *panicstr; 86 87/* 88 * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 89 * and then reboots. If we are called twice, then we avoid trying to sync 90 * the disks as this often leads to recursive panics. 91 */ 92#ifdef __GNUC__ 93__dead /* panic() does not return */ 94#endif 95void 96#ifdef __STDC__ 97panic(const char *fmt, ...) 98#else 99panic(fmt, va_alist) 100 char *fmt; 101#endif 102{ 103 int bootopt; 104 va_list ap; 105 106 bootopt = RB_AUTOBOOT | RB_DUMP; 107 if (panicstr) 108 bootopt |= RB_NOSYNC; 109 else 110 panicstr = fmt; 111 112 va_start(ap, fmt); 113 printf("panic: %r\n", fmt, ap); 114 va_end(ap); 115 116#ifdef KGDB 117 kgdb_panic(); 118#endif 119#ifdef KADB 120 if (boothowto & RB_KDB) 121 kdbpanic(); 122#endif 123#ifdef DDB 124 Debugger ("panic"); 125#endif 126 boot(bootopt); 127} 128 129/* 130 * Warn that a system table is full. 131 */ 132void 133tablefull(tab) 134 const char *tab; 135{ 136 137 log(LOG_ERR, "%s: table is full\n", tab); 138} 139 140/* 141 * Uprintf prints to the controlling terminal for the current process. 142 * It may block if the tty queue is overfull. No message is printed if 143 * the queue does not clear in a reasonable time. 144 */ 145void 146#ifdef __STDC__ 147uprintf(const char *fmt, ...) 148#else 149uprintf(fmt, va_alist) 150 char *fmt; 151#endif 152{ 153 register struct proc *p = curproc; 154 va_list ap; 155 156 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 157 va_start(ap, fmt); 158 kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 159 va_end(ap); 160 } 161} 162 163tpr_t 164tprintf_open(p) 165 register struct proc *p; 166{ 167 168 if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 169 SESSHOLD(p->p_session); 170 return ((tpr_t) p->p_session); 171 } 172 return ((tpr_t) NULL); 173} 174 175void 176tprintf_close(sess) 177 tpr_t sess; 178{ 179 180 if (sess) 181 SESSRELE((struct session *) sess); 182} 183 184/* 185 * tprintf prints on the controlling terminal associated 186 * with the given session. 187 */ 188void 189#ifdef __STDC__ 190tprintf(tpr_t tpr, const char *fmt, ...) 191#else 192tprintf(tpr, fmt, va_alist) 193 tpr_t tpr; 194 char *fmt; 195#endif 196{ 197 register struct session *sess = (struct session *)tpr; 198 struct tty *tp = NULL; 199 int flags = TOLOG; 200 va_list ap; 201 202 logpri(LOG_INFO); 203 if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 204 flags |= TOTTY; 205 tp = sess->s_ttyp; 206 } 207 va_start(ap, fmt); 208 kprintf(fmt, flags, tp, ap); 209 va_end(ap); 210 logwakeup(); 211} 212 213/* 214 * Ttyprintf displays a message on a tty; it should be used only by 215 * the tty driver, or anything that knows the underlying tty will not 216 * be revoke(2)'d away. Other callers should use tprintf. 217 */ 218void 219#ifdef __STDC__ 220ttyprintf(struct tty *tp, const char *fmt, ...) 221#else 222ttyprintf(tp, fmt, va_alist) 223 struct tty *tp; 224 char *fmt; 225#endif 226{ 227 va_list ap; 228 229 va_start(ap, fmt); 230 kprintf(fmt, TOTTY, tp, ap); 231 va_end(ap); 232} 233 234extern int log_open; 235 236/* 237 * Log writes to the log buffer, and guarantees not to sleep (so can be 238 * called by interrupt routines). If there is no process reading the 239 * log yet, it writes to the console also. 240 */ 241void 242#ifdef __STDC__ 243log(int level, const char *fmt, ...) 244#else 245log(level, fmt, va_alist) 246 int level; 247 char *fmt; 248#endif 249{ 250 register int s; 251 va_list ap; 252 253 s = splhigh(); 254 logpri(level); 255 va_start(ap, fmt); 256 kprintf(fmt, TOLOG, NULL, ap); 257 splx(s); 258 va_end(ap); 259 if (!log_open) { 260 va_start(ap, fmt); 261 kprintf(fmt, TOCONS, NULL, ap); 262 va_end(ap); 263 } 264 logwakeup(); 265} 266 267static void 268logpri(level) 269 int level; 270{ 271 register char *p; 272 273 putchar('<', TOLOG, NULL); 274 for (p = ksprintn((u_long)level, 10, NULL); *p;) 275 putchar(*p--, TOLOG, NULL); 276 putchar('>', TOLOG, NULL); 277} 278 279void 280#ifdef __STDC__ 281addlog(const char *fmt, ...) 282#else 283addlog(fmt, va_alist) 284 char *fmt; 285#endif 286{ 287 register int s; 288 va_list ap; 289 290 s = splhigh(); 291 va_start(ap, fmt); 292 kprintf(fmt, TOLOG, NULL, ap); 293 splx(s); 294 va_end(ap); 295 if (!log_open) { 296 va_start(ap, fmt); 297 kprintf(fmt, TOCONS, NULL, ap); 298 va_end(ap); 299 } 300 logwakeup(); 301} 302 303void 304#ifdef __STDC__ 305printf(const char *fmt, ...) 306#else 307printf(fmt, va_alist) 308 char *fmt; 309#endif 310{ 311 va_list ap; 312 register int savintr; 313 314 savintr = consintr; /* disable interrupts */ 315 consintr = 0; 316 va_start(ap, fmt); 317 kprintf(fmt, TOCONS | TOLOG, NULL, ap); 318 va_end(ap); 319 if (!panicstr) 320 logwakeup(); 321 consintr = savintr; /* reenable interrupts */ 322} 323 324/* 325 * Scaled down version of printf(3). 326 * 327 * Two additional formats: 328 * 329 * The format %b is supported to decode error registers. 330 * Its usage is: 331 * 332 * printf("reg=%b\n", regval, "<base><arg>*"); 333 * 334 * where <base> is the output base expressed as a control character, e.g. 335 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 336 * the first of which gives the bit number to be inspected (origin 1), and 337 * the next characters (up to a control character, i.e. a character <= 32), 338 * give the name of the register. Thus: 339 * 340 * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 341 * 342 * would produce output: 343 * 344 * reg=3<BITTWO,BITONE> 345 * 346 * The format %r passes an additional format string and argument list 347 * recursively. Its usage is: 348 * 349 * fn(char *fmt, ...) 350 * { 351 * va_list ap; 352 * va_start(ap, fmt); 353 * printf("prefix: %r: suffix\n", fmt, ap); 354 * va_end(ap); 355 * } 356 * 357 * Space or zero padding and a field width are supported for the numeric 358 * formats only. 359 */ 360void 361kprintf(fmt, flags, tp, ap) 362 register const char *fmt; 363 int flags; 364 struct tty *tp; 365 va_list ap; 366{ 367 register char *p, *q; 368 register int ch, n; 369 u_long ul; 370 int base, lflag, tmp, width; 371 char padc; 372 373 if (fmt == NULL) 374 fmt = "(fmt null)\n"; 375 for (;;) { 376 padc = ' '; 377 width = 0; 378 while ((ch = *(u_char *)fmt++) != '%') { 379 if (ch == '\0') 380 return; 381 putchar(ch, flags, tp); 382 } 383 lflag = 0; 384reswitch: switch (ch = *(u_char *)fmt++) { 385 case '0': 386 padc = '0'; 387 goto reswitch; 388 case '1': case '2': case '3': case '4': 389 case '5': case '6': case '7': case '8': case '9': 390 for (width = 0;; ++fmt) { 391 width = width * 10 + ch - '0'; 392 ch = *fmt; 393 if (ch < '0' || ch > '9') 394 break; 395 } 396 goto reswitch; 397 case 'l': 398 lflag = 1; 399 goto reswitch; 400 case 'b': 401 ul = va_arg(ap, int); 402 p = va_arg(ap, char *); 403 for (q = ksprintn(ul, *p++, NULL); *q;) 404 putchar(*q--, flags, tp); 405 406 if (!ul) 407 break; 408 409 for (tmp = 0; *p;) { 410 n = *p++; 411 if (ul & (1 << (n - 1))) { 412 putchar(tmp ? ',' : '<', flags, tp); 413 for (; (n = *p) > ' '; ++p) 414 putchar(n, flags, tp); 415 tmp = 1; 416 } else 417 for (; *p > ' '; ++p) 418 continue; 419 } 420 if (tmp) 421 putchar('>', flags, tp); 422 break; 423 case 'c': 424 putchar(va_arg(ap, int), flags, tp); 425 break; 426 case 'r': 427 p = va_arg(ap, char *); 428 kprintf(p, flags, tp, va_arg(ap, va_list)); 429 break; 430 case 's': 431 p = va_arg(ap, char *); 432 if (p == NULL) 433 p = "(null)"; 434 while (*p) 435 putchar(*p++, flags, tp); 436 break; 437 case 'd': 438 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 439 if ((long)ul < 0) { 440 putchar('-', flags, tp); 441 ul = -(long)ul; 442 } 443 base = 10; 444 goto number; 445 case 'o': 446 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 447 base = 8; 448 goto number; 449 case 'p': 450 ul = (u_long)va_arg(ap, void *); 451 base = 16; 452 putchar('0', flags, tp); 453 putchar('x', flags, tp); 454 goto number; 455 case 'u': 456 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 457 base = 10; 458 goto number; 459 case 'x': 460 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 461 base = 16; 462number: p = ksprintn(ul, base, &tmp); 463 if (width && (width -= tmp) > 0) 464 while (width--) 465 putchar(padc, flags, tp); 466 while (*p) 467 putchar(*p--, flags, tp); 468 break; 469 default: 470 putchar('%', flags, tp); 471 if (lflag) 472 putchar('l', flags, tp); 473 /* FALLTHROUGH */ 474 case '%': 475 putchar(ch, flags, tp); 476 } 477 } 478} 479 480/* 481 * Print a character on console or users terminal. If destination is 482 * the console then the last MSGBUFS characters are saved in msgbuf for 483 * inspection later. 484 */ 485static void 486putchar(c, flags, tp) 487 register int c; 488 int flags; 489 struct tty *tp; 490{ 491 register struct msgbuf *mbp; 492 493 if (panicstr) 494 constty = NULL; 495 if ((flags & TOCONS) && tp == NULL && constty) { 496 tp = constty; 497 flags |= TOTTY; 498 } 499 if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 500 (flags & TOCONS) && tp == constty) 501 constty = NULL; 502 if ((flags & TOLOG) && 503 c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 504 mbp = msgbufp; 505 if (mbp->msg_magic != MSG_MAGIC || 506 mbp->msg_bufx >= MSG_BSIZE || 507 mbp->msg_bufr >= MSG_BSIZE) { 508 bzero(mbp, sizeof(struct msgbuf)); 509 mbp->msg_magic = MSG_MAGIC; 510 } 511 mbp->msg_bufc[mbp->msg_bufx++] = c; 512 if (mbp->msg_bufx >= MSG_BSIZE) 513 mbp->msg_bufx = 0; 514 /* If the buffer is full, keep the most recent data. */ 515 if (mbp->msg_bufr == mbp->msg_bufx) { 516 if (++mbp->msg_bufr >= MSG_BSIZE) 517 mbp->msg_bufr = 0; 518 } 519 } 520 if ((flags & TOCONS) && constty == NULL && c != '\0') 521 (*v_putc)(c); 522} 523 524/* 525 * Scaled down version of sprintf(3). 526 */ 527#ifdef __STDC__ 528int 529sprintf(char *buf, const char *cfmt, ...) 530#else 531int 532sprintf(buf, cfmt, va_alist) 533 char *buf, *cfmt; 534#endif 535{ 536 register const char *fmt = cfmt; 537 register char *p, *bp; 538 register int ch, base; 539 u_long ul; 540 int lflag; 541 va_list ap; 542 543 va_start(ap, cfmt); 544 for (bp = buf; ; ) { 545 while ((ch = *(u_char *)fmt++) != '%') 546 if ((*bp++ = ch) == '\0') 547 return ((bp - buf) - 1); 548 549 lflag = 0; 550reswitch: switch (ch = *(u_char *)fmt++) { 551 case 'l': 552 lflag = 1; 553 goto reswitch; 554 case 'c': 555 *bp++ = va_arg(ap, int); 556 break; 557 case 's': 558 p = va_arg(ap, char *); 559 while (*p) 560 *bp++ = *p++; 561 break; 562 case 'd': 563 ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 564 if ((long)ul < 0) { 565 *bp++ = '-'; 566 ul = -(long)ul; 567 } 568 base = 10; 569 goto number; 570 break; 571 case 'o': 572 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 573 base = 8; 574 goto number; 575 break; 576 case 'p': 577 ul = (u_long)va_arg(ap, void *); 578 base = 16; 579 *bp++ = '0'; 580 *bp++ = 'x'; 581 goto number; 582 case 'u': 583 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 584 base = 10; 585 goto number; 586 break; 587 case 'x': 588 ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 589 base = 16; 590number: for (p = ksprintn(ul, base, NULL); *p;) 591 *bp++ = *p--; 592 break; 593 default: 594 *bp++ = '%'; 595 if (lflag) 596 *bp++ = 'l'; 597 /* FALLTHROUGH */ 598 case '%': 599 *bp++ = ch; 600 } 601 } 602 va_end(ap); 603} 604 605/* 606 * Put a number (base <= 16) in a buffer in reverse order; return an 607 * optional length and a pointer to the NULL terminated (preceded?) 608 * buffer. 609 */ 610static char * 611ksprintn(ul, base, lenp) 612 register u_long ul; 613 register int base, *lenp; 614{ /* A long in base 8, plus NULL. */ 615 static char buf[sizeof(long) * NBBY / 3 + 2]; 616 register char *p; 617 618 p = buf; 619 do { 620 *++p = "0123456789abcdef"[ul % base]; 621 } while (ul /= base); 622 if (lenp) 623 *lenp = p - buf; 624 return (p); 625}
|