Annotation of sys/kern/subr_prf.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: subr_prf.c,v 1.70 2007/04/26 20:28:25 deraadt Exp $ */
! 2: /* $NetBSD: subr_prf.c,v 1.45 1997/10/24 18:14:25 chuck Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1986, 1988, 1991, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: * (c) UNIX System Laboratories, Inc.
! 8: * All or some portions of this file are derived from material licensed
! 9: * to the University of California by American Telephone and Telegraph
! 10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 11: * the permission of UNIX System Laboratories, Inc.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/buf.h>
! 43: #include <sys/conf.h>
! 44: #include <sys/reboot.h>
! 45: #include <sys/msgbuf.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/ioctl.h>
! 48: #include <sys/vnode.h>
! 49: #include <sys/file.h>
! 50: #include <sys/tty.h>
! 51: #include <sys/tprintf.h>
! 52: #include <sys/syslog.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/pool.h>
! 55: #include <sys/mutex.h>
! 56:
! 57: #include <dev/cons.h>
! 58:
! 59: /*
! 60: * note that stdarg.h and the ansi style va_start macro is used for both
! 61: * ansi and traditional c compilers.
! 62: */
! 63: #include <sys/stdarg.h>
! 64:
! 65: #ifdef KGDB
! 66: #include <sys/kgdb.h>
! 67: #include <machine/cpu.h>
! 68: #endif
! 69: #ifdef DDB
! 70: #include <ddb/db_output.h> /* db_printf, db_putchar prototypes */
! 71: #include <ddb/db_var.h> /* db_log, db_radix */
! 72: #endif
! 73: #if defined(UVM_SWAP_ENCRYPT)
! 74: extern int uvm_doswapencrypt;
! 75: #endif
! 76:
! 77:
! 78: /*
! 79: * defines
! 80: */
! 81:
! 82: /* flags for kprintf */
! 83: #define TOCONS 0x01 /* to the console */
! 84: #define TOTTY 0x02 /* to the process' tty */
! 85: #define TOLOG 0x04 /* to the kernel message buffer */
! 86: #define TOBUFONLY 0x08 /* to the buffer (only) [for snprintf] */
! 87: #define TODDB 0x10 /* to ddb console */
! 88: #define TOCOUNT 0x20 /* act like [v]snprintf */
! 89:
! 90: /* max size buffer kprintf needs to print quad_t [size in base 8 + \0] */
! 91: #define KPRINTF_BUFSIZE (sizeof(quad_t) * NBBY / 3 + 2)
! 92:
! 93:
! 94: /*
! 95: * local prototypes
! 96: */
! 97:
! 98: int kprintf(const char *, int, void *, char *, va_list);
! 99: void kputchar(int, int, struct tty *);
! 100:
! 101: struct mutex kprintf_mutex = MUTEX_INITIALIZER(IPL_HIGH);
! 102:
! 103: /*
! 104: * globals
! 105: */
! 106:
! 107: extern struct tty *constty; /* pointer to console "window" tty */
! 108: int consintr = 1; /* ok to handle console interrupts? */
! 109: extern int log_open; /* subr_log: is /dev/klog open? */
! 110: const char *panicstr; /* arg to first call to panic (used as a flag
! 111: to indicate that panic has already been called). */
! 112: #ifdef DDB
! 113: /*
! 114: * Enter ddb on panic.
! 115: */
! 116: int db_panic = 1;
! 117:
! 118: /*
! 119: * db_console controls if we can be able to enter ddb by a special key
! 120: * combination (machine dependent).
! 121: * If DDB_SAFE_CONSOLE is defined in the kernel configuration it allows
! 122: * to break into console during boot. It's _really_ useful when debugging
! 123: * some things in the kernel that can cause init(8) to crash.
! 124: */
! 125: #ifdef DDB_SAFE_CONSOLE
! 126: int db_console = 1;
! 127: #else
! 128: int db_console = 0;
! 129: #endif
! 130: #endif
! 131:
! 132: /*
! 133: * panic on spl assertion failure?
! 134: */
! 135: int splassert_ctl = 1;
! 136:
! 137: /*
! 138: * v_putc: routine to putc on virtual console
! 139: *
! 140: * the v_putc pointer can be used to redirect the console cnputc elsewhere
! 141: * [e.g. to a "virtual console"].
! 142: */
! 143:
! 144: void (*v_putc)(int) = cnputc; /* start with cnputc (normal cons) */
! 145:
! 146:
! 147: /*
! 148: * functions
! 149: */
! 150:
! 151: /*
! 152: * Partial support (the failure case) of the assertion facility
! 153: * commonly found in userland.
! 154: */
! 155: void
! 156: __assert(const char *t, const char *f, int l, const char *e)
! 157: {
! 158:
! 159: panic("kernel %sassertion \"%s\" failed: file \"%s\", line %d",
! 160: t, e, f, l);
! 161: }
! 162:
! 163: /*
! 164: * tablefull: warn that a system table is full
! 165: */
! 166:
! 167: void
! 168: tablefull(const char *tab)
! 169: {
! 170: log(LOG_ERR, "%s: table is full\n", tab);
! 171: }
! 172:
! 173: /*
! 174: * panic: handle an unresolvable fatal error
! 175: *
! 176: * prints "panic: <message>" and reboots. if called twice (i.e. recursive
! 177: * call) we avoid trying to sync the disk and just reboot (to avoid
! 178: * recursive panics).
! 179: */
! 180:
! 181: void
! 182: panic(const char *fmt, ...)
! 183: {
! 184: static char panicbuf[512];
! 185: int bootopt;
! 186: va_list ap;
! 187:
! 188: bootopt = RB_AUTOBOOT | RB_DUMP;
! 189: #if defined(UVM_SWAP_ENCRYPT)
! 190: if (uvm_doswapencrypt)
! 191: bootopt &= ~RB_DUMP;
! 192: #endif
! 193: va_start(ap, fmt);
! 194: if (panicstr)
! 195: bootopt |= RB_NOSYNC;
! 196: else {
! 197: vsnprintf(panicbuf, sizeof panicbuf, fmt, ap);
! 198: panicstr = panicbuf;
! 199: }
! 200: va_end(ap);
! 201:
! 202: printf("panic: ");
! 203: va_start(ap, fmt);
! 204: vprintf(fmt, ap);
! 205: printf("\n");
! 206: va_end(ap);
! 207:
! 208: #ifdef KGDB
! 209: kgdb_panic();
! 210: #endif
! 211: #ifdef KADB
! 212: if (boothowto & RB_KDB)
! 213: kdbpanic();
! 214: #endif
! 215: #ifdef DDB
! 216: if (db_panic)
! 217: Debugger();
! 218: else
! 219: db_stack_dump();
! 220: #endif
! 221: boot(bootopt);
! 222: }
! 223:
! 224: /*
! 225: * We print only the function name. The file name is usually very long and
! 226: * would eat tons of space in the kernel.
! 227: */
! 228: void
! 229: splassert_fail(int wantipl, int haveipl, const char *func)
! 230: {
! 231:
! 232: printf("splassert: %s: want %d have %d\n", func, wantipl, haveipl);
! 233: switch (splassert_ctl) {
! 234: case 1:
! 235: break;
! 236: case 2:
! 237: #ifdef DDB
! 238: db_stack_dump();
! 239: #endif
! 240: break;
! 241: case 3:
! 242: #ifdef DDB
! 243: db_stack_dump();
! 244: Debugger();
! 245: #endif
! 246: break;
! 247: default:
! 248: panic("spl assertion failure in %s", func);
! 249: }
! 250: }
! 251:
! 252: /*
! 253: * kernel logging functions: log, logpri, addlog
! 254: */
! 255:
! 256: /*
! 257: * log: write to the log buffer
! 258: *
! 259: * => will not sleep [so safe to call from interrupt]
! 260: * => will log to console if /dev/klog isn't open
! 261: */
! 262:
! 263: void
! 264: log(int level, const char *fmt, ...)
! 265: {
! 266: int s;
! 267: va_list ap;
! 268:
! 269: s = splhigh();
! 270: logpri(level); /* log the level first */
! 271: va_start(ap, fmt);
! 272: kprintf(fmt, TOLOG, NULL, NULL, ap);
! 273: va_end(ap);
! 274: splx(s);
! 275: if (!log_open) {
! 276: va_start(ap, fmt);
! 277: kprintf(fmt, TOCONS, NULL, NULL, ap);
! 278: va_end(ap);
! 279: }
! 280: logwakeup(); /* wake up anyone waiting for log msgs */
! 281: }
! 282:
! 283: /*
! 284: * logpri: log the priority level to the klog
! 285: */
! 286:
! 287: void
! 288: logpri(int level)
! 289: {
! 290: char *p;
! 291: char snbuf[KPRINTF_BUFSIZE];
! 292:
! 293: kputchar('<', TOLOG, NULL);
! 294: snprintf(snbuf, sizeof snbuf, "%d", level);
! 295: for (p = snbuf ; *p ; p++)
! 296: kputchar(*p, TOLOG, NULL);
! 297: kputchar('>', TOLOG, NULL);
! 298: }
! 299:
! 300: /*
! 301: * addlog: add info to previous log message
! 302: */
! 303:
! 304: int
! 305: addlog(const char *fmt, ...)
! 306: {
! 307: int s;
! 308: va_list ap;
! 309:
! 310: s = splhigh();
! 311: va_start(ap, fmt);
! 312: kprintf(fmt, TOLOG, NULL, NULL, ap);
! 313: va_end(ap);
! 314: splx(s);
! 315: if (!log_open) {
! 316: va_start(ap, fmt);
! 317: kprintf(fmt, TOCONS, NULL, NULL, ap);
! 318: va_end(ap);
! 319: }
! 320: logwakeup();
! 321: return(0);
! 322: }
! 323:
! 324:
! 325: /*
! 326: * kputchar: print a single character on console or user terminal.
! 327: *
! 328: * => if console, then the last MSGBUFS chars are saved in msgbuf
! 329: * for inspection later (e.g. dmesg/syslog)
! 330: */
! 331: void
! 332: kputchar(int c, int flags, struct tty *tp)
! 333: {
! 334: extern int msgbufmapped;
! 335:
! 336: if (panicstr)
! 337: constty = NULL;
! 338: if ((flags & TOCONS) && tp == NULL && constty) {
! 339: tp = constty;
! 340: flags |= TOTTY;
! 341: }
! 342: if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
! 343: (flags & TOCONS) && tp == constty)
! 344: constty = NULL;
! 345: if ((flags & TOLOG) &&
! 346: c != '\0' && c != '\r' && c != 0177 && msgbufmapped)
! 347: msgbuf_putchar(c);
! 348: if ((flags & TOCONS) && constty == NULL && c != '\0')
! 349: (*v_putc)(c);
! 350: #ifdef DDB
! 351: if (flags & TODDB)
! 352: db_putchar(c);
! 353: #endif
! 354: }
! 355:
! 356:
! 357: /*
! 358: * uprintf: print to the controlling tty of the current process
! 359: *
! 360: * => we may block if the tty queue is full
! 361: * => no message is printed if the queue doesn't clear in a reasonable
! 362: * time
! 363: */
! 364:
! 365: void
! 366: uprintf(const char *fmt, ...)
! 367: {
! 368: struct proc *p = curproc;
! 369: va_list ap;
! 370:
! 371: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
! 372: va_start(ap, fmt);
! 373: kprintf(fmt, TOTTY, p->p_session->s_ttyp, NULL, ap);
! 374: va_end(ap);
! 375: }
! 376: }
! 377:
! 378: #if defined(NFSSERVER) || defined(NFSCLIENT)
! 379:
! 380: /*
! 381: * tprintf functions: used to send messages to a specific process
! 382: *
! 383: * usage:
! 384: * get a tpr_t handle on a process "p" by using "tprintf_open(p)"
! 385: * use the handle when calling "tprintf"
! 386: * when done, do a "tprintf_close" to drop the handle
! 387: */
! 388:
! 389: /*
! 390: * tprintf_open: get a tprintf handle on a process "p"
! 391: *
! 392: * => returns NULL if process can't be printed to
! 393: */
! 394:
! 395: tpr_t
! 396: tprintf_open(struct proc *p)
! 397: {
! 398:
! 399: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
! 400: SESSHOLD(p->p_session);
! 401: return ((tpr_t) p->p_session);
! 402: }
! 403: return ((tpr_t) NULL);
! 404: }
! 405:
! 406: /*
! 407: * tprintf_close: dispose of a tprintf handle obtained with tprintf_open
! 408: */
! 409:
! 410: void
! 411: tprintf_close(tpr_t sess)
! 412: {
! 413:
! 414: if (sess)
! 415: SESSRELE((struct session *) sess);
! 416: }
! 417:
! 418: /*
! 419: * tprintf: given tprintf handle to a process [obtained with tprintf_open],
! 420: * send a message to the controlling tty for that process.
! 421: *
! 422: * => also sends message to /dev/klog
! 423: */
! 424: void
! 425: tprintf(tpr_t tpr, const char *fmt, ...)
! 426: {
! 427: struct session *sess = (struct session *)tpr;
! 428: struct tty *tp = NULL;
! 429: int flags = TOLOG;
! 430: va_list ap;
! 431:
! 432: logpri(LOG_INFO);
! 433: if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
! 434: flags |= TOTTY;
! 435: tp = sess->s_ttyp;
! 436: }
! 437: va_start(ap, fmt);
! 438: kprintf(fmt, flags, tp, NULL, ap);
! 439: va_end(ap);
! 440: logwakeup();
! 441: }
! 442:
! 443: #endif /* NFSSERVER || NFSCLIENT */
! 444:
! 445:
! 446: /*
! 447: * ttyprintf: send a message to a specific tty
! 448: *
! 449: * => should be used only by tty driver or anything that knows the
! 450: * underlying tty will not be revoked(2)'d away. [otherwise,
! 451: * use tprintf]
! 452: */
! 453: void
! 454: ttyprintf(struct tty *tp, const char *fmt, ...)
! 455: {
! 456: va_list ap;
! 457:
! 458: va_start(ap, fmt);
! 459: kprintf(fmt, TOTTY, tp, NULL, ap);
! 460: va_end(ap);
! 461: }
! 462:
! 463: #ifdef DDB
! 464:
! 465: /*
! 466: * db_printf: printf for DDB (via db_putchar)
! 467: */
! 468:
! 469: int
! 470: db_printf(const char *fmt, ...)
! 471: {
! 472: va_list ap;
! 473: int flags, retval;
! 474:
! 475: flags = TODDB;
! 476: if (db_log)
! 477: flags |= TOLOG;
! 478: va_start(ap, fmt);
! 479: retval = kprintf(fmt, flags, NULL, NULL, ap);
! 480: va_end(ap);
! 481: return(retval);
! 482: }
! 483:
! 484: #endif /* DDB */
! 485:
! 486:
! 487: /*
! 488: * normal kernel printf functions: printf, vprintf, snprintf
! 489: */
! 490:
! 491: /*
! 492: * printf: print a message to the console and the log
! 493: */
! 494: int
! 495: printf(const char *fmt, ...)
! 496: {
! 497: va_list ap;
! 498: int savintr, retval;
! 499:
! 500: mtx_enter(&kprintf_mutex);
! 501:
! 502: savintr = consintr; /* disable interrupts */
! 503: consintr = 0;
! 504: va_start(ap, fmt);
! 505: retval = kprintf(fmt, TOCONS | TOLOG, NULL, NULL, ap);
! 506: va_end(ap);
! 507: if (!panicstr)
! 508: logwakeup();
! 509: consintr = savintr; /* reenable interrupts */
! 510:
! 511: mtx_leave(&kprintf_mutex);
! 512:
! 513: return(retval);
! 514: }
! 515:
! 516: /*
! 517: * vprintf: print a message to the console and the log [already have a
! 518: * va_list]
! 519: */
! 520:
! 521: int
! 522: vprintf(const char *fmt, va_list ap)
! 523: {
! 524: int savintr, retval;
! 525:
! 526: mtx_enter(&kprintf_mutex);
! 527:
! 528: savintr = consintr; /* disable interrupts */
! 529: consintr = 0;
! 530: retval = kprintf(fmt, TOCONS | TOLOG, NULL, NULL, ap);
! 531: if (!panicstr)
! 532: logwakeup();
! 533: consintr = savintr; /* reenable interrupts */
! 534:
! 535: mtx_leave(&kprintf_mutex);
! 536:
! 537: return (retval);
! 538: }
! 539:
! 540: /*
! 541: * snprintf: print a message to a buffer
! 542: */
! 543: int
! 544: snprintf(char *buf, size_t size, const char *fmt, ...)
! 545: {
! 546: int retval;
! 547: va_list ap;
! 548: char *p;
! 549:
! 550: p = buf + size - 1;
! 551: if (size < 1)
! 552: p = buf;
! 553: va_start(ap, fmt);
! 554: retval = kprintf(fmt, TOBUFONLY | TOCOUNT, &p, buf, ap);
! 555: va_end(ap);
! 556: if (size > 0)
! 557: *(p) = 0; /* null terminate */
! 558: return(retval);
! 559: }
! 560:
! 561: /*
! 562: * vsnprintf: print a message to a buffer [already have va_alist]
! 563: */
! 564: int
! 565: vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
! 566: {
! 567: int retval;
! 568: char *p;
! 569:
! 570: p = buf + size - 1;
! 571: if (size < 1)
! 572: p = buf;
! 573: retval = kprintf(fmt, TOBUFONLY | TOCOUNT, &p, buf, ap);
! 574: if (size > 0)
! 575: *(p) = 0; /* null terminate */
! 576: return(retval);
! 577: }
! 578:
! 579: /*
! 580: * kprintf: scaled down version of printf(3).
! 581: *
! 582: * this version based on vfprintf() from libc which was derived from
! 583: * software contributed to Berkeley by Chris Torek.
! 584: *
! 585: * Two additional formats:
! 586: *
! 587: * The format %b is supported to decode error registers.
! 588: * Its usage is:
! 589: *
! 590: * printf("reg=%b\n", regval, "<base><arg>*");
! 591: *
! 592: * where <base> is the output base expressed as a control character, e.g.
! 593: * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
! 594: * the first of which gives the bit number to be inspected (origin 1), and
! 595: * the next characters (up to a control character, i.e. a character <= 32),
! 596: * give the name of the register. Thus:
! 597: *
! 598: * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
! 599: *
! 600: * would produce output:
! 601: *
! 602: * reg=3<BITTWO,BITONE>
! 603: *
! 604: * To support larger integers (> 32 bits), %b formatting will also accept
! 605: * control characters in the region 0x80 - 0xff. 0x80 refers to bit 0,
! 606: * 0x81 refers to bit 1, and so on. The equivalent string to the above is:
! 607: *
! 608: * kprintf("reg=%b\n", 3, "\10\201BITTWO\200BITONE\n");
! 609: *
! 610: * and would produce the same output.
! 611: *
! 612: * Like the rest of printf, %b can be prefixed to handle various size
! 613: * modifiers, eg. %b is for "int", %lb is for "long", and %llb supports
! 614: * "long long".
! 615: *
! 616: * This code is large and complicated...
! 617: */
! 618:
! 619: /*
! 620: * macros for converting digits to letters and vice versa
! 621: */
! 622: #define to_digit(c) ((c) - '0')
! 623: #define is_digit(c) ((unsigned)to_digit(c) <= 9)
! 624: #define to_char(n) ((n) + '0')
! 625:
! 626: /*
! 627: * flags used during conversion.
! 628: */
! 629: #define ALT 0x001 /* alternate form */
! 630: #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
! 631: #define LADJUST 0x004 /* left adjustment */
! 632: #define LONGDBL 0x008 /* long double; unimplemented */
! 633: #define LONGINT 0x010 /* long integer */
! 634: #define QUADINT 0x020 /* quad integer */
! 635: #define SHORTINT 0x040 /* short integer */
! 636: #define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
! 637: #define FPT 0x100 /* Floating point number */
! 638:
! 639: /*
! 640: * To extend shorts properly, we need both signed and unsigned
! 641: * argument extraction methods.
! 642: */
! 643: #define SARG() \
! 644: (flags&QUADINT ? va_arg(ap, quad_t) : \
! 645: flags&LONGINT ? va_arg(ap, long) : \
! 646: flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
! 647: (long)va_arg(ap, int))
! 648: #define UARG() \
! 649: (flags&QUADINT ? va_arg(ap, u_quad_t) : \
! 650: flags&LONGINT ? va_arg(ap, u_long) : \
! 651: flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
! 652: (u_long)va_arg(ap, u_int))
! 653:
! 654: #define KPRINTF_PUTCHAR(C) do { \
! 655: int chr = (C); \
! 656: ret += 1; \
! 657: if (oflags & TOBUFONLY) { \
! 658: if ((vp != NULL) && (sbuf == tailp)) { \
! 659: if (!(oflags & TOCOUNT)) \
! 660: goto overflow; \
! 661: } else \
! 662: *sbuf++ = chr; \
! 663: } else { \
! 664: kputchar(chr, oflags, (struct tty *)vp); \
! 665: } \
! 666: } while(0)
! 667:
! 668: int
! 669: kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap)
! 670: {
! 671: char *fmt; /* format string */
! 672: int ch; /* character from fmt */
! 673: int n; /* handy integer (short term usage) */
! 674: char *cp = NULL; /* handy char pointer (short term usage) */
! 675: int flags; /* flags as above */
! 676: int ret; /* return value accumulator */
! 677: int width; /* width from format (%8d), or 0 */
! 678: int prec; /* precision from format (%.3d), or -1 */
! 679: char sign; /* sign prefix (' ', '+', '-', or \0) */
! 680:
! 681: u_quad_t _uquad; /* integer arguments %[diouxX] */
! 682: enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
! 683: int dprec; /* a copy of prec if [diouxX], 0 otherwise */
! 684: int realsz; /* field size expanded by dprec */
! 685: int size = 0; /* size of converted field or string */
! 686: char *xdigs = NULL; /* digits for [xX] conversion */
! 687: char buf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */
! 688: char *tailp = NULL; /* tail pointer for snprintf */
! 689:
! 690: if ((oflags & TOBUFONLY) && (vp != NULL))
! 691: tailp = *(char **)vp;
! 692:
! 693: fmt = (char *)fmt0;
! 694: ret = 0;
! 695:
! 696: /*
! 697: * Scan the format for conversions (`%' character).
! 698: */
! 699: for (;;) {
! 700: while (*fmt != '%' && *fmt) {
! 701: KPRINTF_PUTCHAR(*fmt++);
! 702: }
! 703: if (*fmt == 0)
! 704: goto done;
! 705:
! 706: fmt++; /* skip over '%' */
! 707:
! 708: flags = 0;
! 709: dprec = 0;
! 710: width = 0;
! 711: prec = -1;
! 712: sign = '\0';
! 713:
! 714: rflag: ch = *fmt++;
! 715: reswitch: switch (ch) {
! 716: /* XXX: non-standard '%b' format */
! 717: case 'b': {
! 718: char *b, *z;
! 719: int tmp;
! 720: _uquad = UARG();
! 721: b = va_arg(ap, char *);
! 722: if (*b == 8)
! 723: snprintf(buf, sizeof buf, "%llo", _uquad);
! 724: else if (*b == 10)
! 725: snprintf(buf, sizeof buf, "%lld", _uquad);
! 726: else if (*b == 16)
! 727: snprintf(buf, sizeof buf, "%llx", _uquad);
! 728: else
! 729: break;
! 730: b++;
! 731:
! 732: z = buf;
! 733: while (*z) {
! 734: KPRINTF_PUTCHAR(*z++);
! 735: }
! 736:
! 737: if (_uquad) {
! 738: tmp = 0;
! 739: while ((n = *b++) != 0) {
! 740: if (n & 0x80)
! 741: n &= 0x7f;
! 742: else if (n <= ' ')
! 743: n = n - 1;
! 744: if (_uquad & (1LL << n)) {
! 745: KPRINTF_PUTCHAR(tmp ? ',':'<');
! 746: while (*b > ' ' &&
! 747: (*b & 0x80) == 0) {
! 748: KPRINTF_PUTCHAR(*b);
! 749: b++;
! 750: }
! 751: tmp = 1;
! 752: } else {
! 753: while (*b > ' ' &&
! 754: (*b & 0x80) == 0)
! 755: b++;
! 756: }
! 757: }
! 758: if (tmp) {
! 759: KPRINTF_PUTCHAR('>');
! 760: }
! 761: }
! 762: continue; /* no output */
! 763: }
! 764:
! 765: #ifdef DDB
! 766: /* XXX: non-standard '%r' format (print int in db_radix) */
! 767: case 'r':
! 768: if ((oflags & TODDB) == 0)
! 769: goto default_case;
! 770:
! 771: if (db_radix == 16)
! 772: goto case_z; /* signed hex */
! 773: _uquad = SARG();
! 774: if ((quad_t)_uquad < 0) {
! 775: _uquad = -_uquad;
! 776: sign = '-';
! 777: }
! 778: base = (db_radix == 8) ? OCT : DEC;
! 779: goto number;
! 780:
! 781:
! 782: /* XXX: non-standard '%z' format ("signed hex", a "hex %i")*/
! 783: case 'z':
! 784: case_z:
! 785: if ((oflags & TODDB) == 0)
! 786: goto default_case;
! 787:
! 788: xdigs = "0123456789abcdef";
! 789: ch = 'x'; /* the 'x' in '0x' (below) */
! 790: _uquad = SARG();
! 791: base = HEX;
! 792: /* leading 0x/X only if non-zero */
! 793: if (flags & ALT && _uquad != 0)
! 794: flags |= HEXPREFIX;
! 795: if ((quad_t)_uquad < 0) {
! 796: _uquad = -_uquad;
! 797: sign = '-';
! 798: }
! 799: goto number;
! 800: #endif
! 801:
! 802: case ' ':
! 803: /*
! 804: * ``If the space and + flags both appear, the space
! 805: * flag will be ignored.''
! 806: * -- ANSI X3J11
! 807: */
! 808: if (!sign)
! 809: sign = ' ';
! 810: goto rflag;
! 811: case '#':
! 812: flags |= ALT;
! 813: goto rflag;
! 814: case '*':
! 815: /*
! 816: * ``A negative field width argument is taken as a
! 817: * - flag followed by a positive field width.''
! 818: * -- ANSI X3J11
! 819: * They don't exclude field widths read from args.
! 820: */
! 821: if ((width = va_arg(ap, int)) >= 0)
! 822: goto rflag;
! 823: width = -width;
! 824: /* FALLTHROUGH */
! 825: case '-':
! 826: flags |= LADJUST;
! 827: goto rflag;
! 828: case '+':
! 829: sign = '+';
! 830: goto rflag;
! 831: case '.':
! 832: if ((ch = *fmt++) == '*') {
! 833: n = va_arg(ap, int);
! 834: prec = n < 0 ? -1 : n;
! 835: goto rflag;
! 836: }
! 837: n = 0;
! 838: while (is_digit(ch)) {
! 839: n = 10 * n + to_digit(ch);
! 840: ch = *fmt++;
! 841: }
! 842: prec = n < 0 ? -1 : n;
! 843: goto reswitch;
! 844: case '0':
! 845: /*
! 846: * ``Note that 0 is taken as a flag, not as the
! 847: * beginning of a field width.''
! 848: * -- ANSI X3J11
! 849: */
! 850: flags |= ZEROPAD;
! 851: goto rflag;
! 852: case '1': case '2': case '3': case '4':
! 853: case '5': case '6': case '7': case '8': case '9':
! 854: n = 0;
! 855: do {
! 856: n = 10 * n + to_digit(ch);
! 857: ch = *fmt++;
! 858: } while (is_digit(ch));
! 859: width = n;
! 860: goto reswitch;
! 861: case 'h':
! 862: flags |= SHORTINT;
! 863: goto rflag;
! 864: case 'l':
! 865: if (*fmt == 'l') {
! 866: fmt++;
! 867: flags |= QUADINT;
! 868: } else {
! 869: flags |= LONGINT;
! 870: }
! 871: goto rflag;
! 872: case 'q':
! 873: flags |= QUADINT;
! 874: goto rflag;
! 875: case 'c':
! 876: *(cp = buf) = va_arg(ap, int);
! 877: size = 1;
! 878: sign = '\0';
! 879: break;
! 880: case 'D':
! 881: flags |= LONGINT;
! 882: /*FALLTHROUGH*/
! 883: case 'd':
! 884: case 'i':
! 885: _uquad = SARG();
! 886: if ((quad_t)_uquad < 0) {
! 887: _uquad = -_uquad;
! 888: sign = '-';
! 889: }
! 890: base = DEC;
! 891: goto number;
! 892: case 'n':
! 893: #ifdef DDB
! 894: /* XXX: non-standard '%n' format */
! 895: /*
! 896: * XXX: HACK! DDB wants '%n' to be a '%u' printed
! 897: * in db_radix format. this should die since '%n'
! 898: * is already defined in standard printf to write
! 899: * the number of chars printed so far to the arg (which
! 900: * should be a pointer.
! 901: */
! 902: if (oflags & TODDB) {
! 903: if (db_radix == 16)
! 904: ch = 'x'; /* convert to %x */
! 905: else if (db_radix == 8)
! 906: ch = 'o'; /* convert to %o */
! 907: else
! 908: ch = 'u'; /* convert to %u */
! 909:
! 910: /* ... and start again */
! 911: goto reswitch;
! 912: }
! 913:
! 914: #endif
! 915: if (flags & QUADINT)
! 916: *va_arg(ap, quad_t *) = ret;
! 917: else if (flags & LONGINT)
! 918: *va_arg(ap, long *) = ret;
! 919: else if (flags & SHORTINT)
! 920: *va_arg(ap, short *) = ret;
! 921: else
! 922: *va_arg(ap, int *) = ret;
! 923: continue; /* no output */
! 924: case 'O':
! 925: flags |= LONGINT;
! 926: /*FALLTHROUGH*/
! 927: case 'o':
! 928: _uquad = UARG();
! 929: base = OCT;
! 930: goto nosign;
! 931: case 'p':
! 932: /*
! 933: * ``The argument shall be a pointer to void. The
! 934: * value of the pointer is converted to a sequence
! 935: * of printable characters, in an implementation-
! 936: * defined manner.''
! 937: * -- ANSI X3J11
! 938: */
! 939: /* NOSTRICT */
! 940: _uquad = (u_long)va_arg(ap, void *);
! 941: base = HEX;
! 942: xdigs = "0123456789abcdef";
! 943: flags |= HEXPREFIX;
! 944: ch = 'x';
! 945: goto nosign;
! 946: case 's':
! 947: if ((cp = va_arg(ap, char *)) == NULL)
! 948: cp = "(null)";
! 949: if (prec >= 0) {
! 950: /*
! 951: * can't use strlen; can only look for the
! 952: * NUL in the first `prec' characters, and
! 953: * strlen() will go further.
! 954: */
! 955: char *p = memchr(cp, 0, prec);
! 956:
! 957: if (p != NULL) {
! 958: size = p - cp;
! 959: if (size > prec)
! 960: size = prec;
! 961: } else
! 962: size = prec;
! 963: } else
! 964: size = strlen(cp);
! 965: sign = '\0';
! 966: break;
! 967: case 'U':
! 968: flags |= LONGINT;
! 969: /*FALLTHROUGH*/
! 970: case 'u':
! 971: _uquad = UARG();
! 972: base = DEC;
! 973: goto nosign;
! 974: case 'X':
! 975: xdigs = "0123456789ABCDEF";
! 976: goto hex;
! 977: case 'x':
! 978: xdigs = "0123456789abcdef";
! 979: hex: _uquad = UARG();
! 980: base = HEX;
! 981: /* leading 0x/X only if non-zero */
! 982: if (flags & ALT && _uquad != 0)
! 983: flags |= HEXPREFIX;
! 984:
! 985: /* unsigned conversions */
! 986: nosign: sign = '\0';
! 987: /*
! 988: * ``... diouXx conversions ... if a precision is
! 989: * specified, the 0 flag will be ignored.''
! 990: * -- ANSI X3J11
! 991: */
! 992: number: if ((dprec = prec) >= 0)
! 993: flags &= ~ZEROPAD;
! 994:
! 995: /*
! 996: * ``The result of converting a zero value with an
! 997: * explicit precision of zero is no characters.''
! 998: * -- ANSI X3J11
! 999: */
! 1000: cp = buf + KPRINTF_BUFSIZE;
! 1001: if (_uquad != 0 || prec != 0) {
! 1002: /*
! 1003: * Unsigned mod is hard, and unsigned mod
! 1004: * by a constant is easier than that by
! 1005: * a variable; hence this switch.
! 1006: */
! 1007: switch (base) {
! 1008: case OCT:
! 1009: do {
! 1010: *--cp = to_char(_uquad & 7);
! 1011: _uquad >>= 3;
! 1012: } while (_uquad);
! 1013: /* handle octal leading 0 */
! 1014: if (flags & ALT && *cp != '0')
! 1015: *--cp = '0';
! 1016: break;
! 1017:
! 1018: case DEC:
! 1019: /* many numbers are 1 digit */
! 1020: while (_uquad >= 10) {
! 1021: *--cp = to_char(_uquad % 10);
! 1022: _uquad /= 10;
! 1023: }
! 1024: *--cp = to_char(_uquad);
! 1025: break;
! 1026:
! 1027: case HEX:
! 1028: do {
! 1029: *--cp = xdigs[_uquad & 15];
! 1030: _uquad >>= 4;
! 1031: } while (_uquad);
! 1032: break;
! 1033:
! 1034: default:
! 1035: cp = "bug in kprintf: bad base";
! 1036: size = strlen(cp);
! 1037: goto skipsize;
! 1038: }
! 1039: }
! 1040: size = buf + KPRINTF_BUFSIZE - cp;
! 1041: skipsize:
! 1042: break;
! 1043: default: /* "%?" prints ?, unless ? is NUL */
! 1044: #ifdef DDB
! 1045: default_case: /* DDB */
! 1046: #endif
! 1047: if (ch == '\0')
! 1048: goto done;
! 1049: /* pretend it was %c with argument ch */
! 1050: cp = buf;
! 1051: *cp = ch;
! 1052: size = 1;
! 1053: sign = '\0';
! 1054: break;
! 1055: }
! 1056:
! 1057: /*
! 1058: * All reasonable formats wind up here. At this point, `cp'
! 1059: * points to a string which (if not flags&LADJUST) should be
! 1060: * padded out to `width' places. If flags&ZEROPAD, it should
! 1061: * first be prefixed by any sign or other prefix; otherwise,
! 1062: * it should be blank padded before the prefix is emitted.
! 1063: * After any left-hand padding and prefixing, emit zeroes
! 1064: * required by a decimal [diouxX] precision, then print the
! 1065: * string proper, then emit zeroes required by any leftover
! 1066: * floating precision; finally, if LADJUST, pad with blanks.
! 1067: *
! 1068: * Compute actual size, so we know how much to pad.
! 1069: * size excludes decimal prec; realsz includes it.
! 1070: */
! 1071: realsz = dprec > size ? dprec : size;
! 1072: if (sign)
! 1073: realsz++;
! 1074: else if (flags & HEXPREFIX)
! 1075: realsz+= 2;
! 1076:
! 1077: /* right-adjusting blank padding */
! 1078: if ((flags & (LADJUST|ZEROPAD)) == 0) {
! 1079: n = width - realsz;
! 1080: while (n-- > 0)
! 1081: KPRINTF_PUTCHAR(' ');
! 1082: }
! 1083:
! 1084: /* prefix */
! 1085: if (sign) {
! 1086: KPRINTF_PUTCHAR(sign);
! 1087: } else if (flags & HEXPREFIX) {
! 1088: KPRINTF_PUTCHAR('0');
! 1089: KPRINTF_PUTCHAR(ch);
! 1090: }
! 1091:
! 1092: /* right-adjusting zero padding */
! 1093: if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
! 1094: n = width - realsz;
! 1095: while (n-- > 0)
! 1096: KPRINTF_PUTCHAR('0');
! 1097: }
! 1098:
! 1099: /* leading zeroes from decimal precision */
! 1100: n = dprec - size;
! 1101: while (n-- > 0)
! 1102: KPRINTF_PUTCHAR('0');
! 1103:
! 1104: /* the string or number proper */
! 1105: while (size--)
! 1106: KPRINTF_PUTCHAR(*cp++);
! 1107: /* left-adjusting padding (always blank) */
! 1108: if (flags & LADJUST) {
! 1109: n = width - realsz;
! 1110: while (n-- > 0)
! 1111: KPRINTF_PUTCHAR(' ');
! 1112: }
! 1113: }
! 1114:
! 1115: done:
! 1116: if ((oflags & TOBUFONLY) && (vp != NULL))
! 1117: *(char **)vp = sbuf;
! 1118: overflow:
! 1119: return (ret);
! 1120: /* NOTREACHED */
! 1121: }
! 1122:
! 1123: #if __GNUC_PREREQ__(2,96)
! 1124: /*
! 1125: * XXX - these functions shouldn't be in the kernel, but gcc 3.X feels like
! 1126: * translating some printf calls to puts and since it doesn't seem
! 1127: * possible to just turn off parts of those optimizations (some of
! 1128: * them are really useful), we have to provide a dummy puts and putchar
! 1129: * that are wrappers around printf.
! 1130: */
! 1131: int puts(const char *);
! 1132: int putchar(int c);
! 1133:
! 1134: int
! 1135: puts(const char *str)
! 1136: {
! 1137: printf("%s\n", str);
! 1138:
! 1139: return (0);
! 1140: }
! 1141:
! 1142: int
! 1143: putchar(int c)
! 1144: {
! 1145: printf("%c", c);
! 1146:
! 1147: return (c);
! 1148: }
! 1149:
! 1150:
! 1151: #endif
CVSweb