1 /*- 2 * Copyright (c) 1986, 1988, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include "opt_ddb.h" 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/lock.h> 45 #include <sys/kdb.h> 46 #include <sys/mutex.h> 47 #include <sys/sx.h> 48 #include <sys/kernel.h> 49 #include <sys/msgbuf.h> 50 #include <sys/malloc.h> 51 #include <sys/priv.h> 52 #include <sys/proc.h> 53 #include <sys/stddef.h> 54 #include <sys/sysctl.h> 55 #include <sys/tty.h> 56 #include <sys/syslog.h> 57 #include <sys/cons.h> 58 #include <sys/uio.h> 59 #include <sys/ctype.h> 60 61 #ifdef DDB 62 #include <ddb/ddb.h> 63 #endif 64 65 /* 66 * Note that stdarg.h and the ANSI style va_start macro is used for both 67 * ANSI and traditional C compilers. 68 */ 69 #include <machine/stdarg.h> 70 71 #define TOCONS 0x01 72 #define TOTTY 0x02 73 #define TOLOG 0x04 74 75 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ 76 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 77 78 struct putchar_arg { 79 int flags; 80 int pri; 81 struct tty *tty; 82 char *p_bufr; 83 size_t n_bufr; 84 char *p_next; 85 size_t remain; 86 }; 87 88 struct snprintf_arg { 89 char *str; 90 size_t remain; 91 }; 92 93 int putchar(int c); 94 int puts(const char *str); 95 96 97 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper); 98 99 /* 100 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 101 * order; return an optional length and a pointer to the last character 102 * written in the buffer (i.e., the first character of the string). 103 * The buffer pointed to by `nbuf' must have length >= MAXNBUF. 104 */ 105 static char * 106 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) 107 { 108 char *p, c; 109 110 p = nbuf; 111 *p = '\0'; 112 do { 113 c = hex2ascii(num % base); 114 *++p = upper ? toupper(c) : c; 115 } while (num /= base); 116 if (lenp) 117 *lenp = p - nbuf; 118 return (p); 119 } 120 121 static void 122 putbuf(int c, struct putchar_arg *ap) 123 { 124 /* Check if no console output buffer was provided. */ 125 if (ap->p_bufr == NULL) { 126 /* Output direct to the console. */ 127 if (ap->flags & TOCONS) 128 putchar(c); 129 130 } else { 131 /* Buffer the character: */ 132 *ap->p_next++ = c; 133 ap->remain--; 134 135 /* Always leave the buffer zero terminated. */ 136 *ap->p_next = '\0'; 137 138 /* Check if the buffer needs to be flushed. */ 139 if (ap->remain == 2 || c == '\n') { 140 141 if (ap->flags & TOCONS) { 142 puts(ap->p_bufr); 143 } 144 145 ap->p_next = ap->p_bufr; 146 ap->remain = ap->n_bufr; 147 *ap->p_next = '\0'; 148 } 149 150 /* 151 * Since we fill the buffer up one character at a time, 152 * this should not happen. We should always catch it when 153 * ap->remain == 2 (if not sooner due to a newline), flush 154 * the buffer and move on. One way this could happen is 155 * if someone sets PRINTF_BUFR_SIZE to 1 or something 156 * similarly silly. 157 */ 158 KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd", 159 ap->remain)); 160 } 161 } 162 163 /* 164 * Print a character on console or users terminal. If destination is 165 * the console then the last bunch of characters are saved in msgbuf for 166 * inspection later. 167 */ 168 static void 169 kputchar(int c, void *arg) 170 { 171 struct putchar_arg *ap = (struct putchar_arg*) arg; 172 int flags = ap->flags; 173 int putbuf_done = 0; 174 175 if (flags & TOCONS) { 176 putbuf(c, ap); 177 putbuf_done = 1; 178 } 179 180 if ((flags & TOLOG) && (putbuf_done == 0)) { 181 if (c != '\0') 182 putbuf(c, ap); 183 } 184 } 185 186 /* 187 * Scaled down version of printf(3). 188 * 189 * Two additional formats: 190 * 191 * The format %b is supported to decode error registers. 192 * Its usage is: 193 * 194 * printf("reg=%b\n", regval, "<base><arg>*"); 195 * 196 * where <base> is the output base expressed as a control character, e.g. 197 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 198 * the first of which gives the bit number to be inspected (origin 1), and 199 * the next characters (up to a control character, i.e. a character <= 32), 200 * give the name of the register. Thus: 201 * 202 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 203 * 204 * would produce output: 205 * 206 * reg=3<BITTWO,BITONE> 207 * 208 * XXX: %D -- Hexdump, takes pointer and separator string: 209 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX 210 * ("%*D", len, ptr, " " -> XX XX XX XX ... 211 */ 212 int 213 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap) 214 { 215 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } 216 char nbuf[MAXNBUF]; 217 char *d; 218 const char *p, *percent, *q; 219 u_char *up; 220 int ch, n; 221 uintmax_t num; 222 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 223 int cflag, hflag, jflag, tflag, zflag; 224 int dwidth, upper; 225 char padc; 226 int stop = 0, retval = 0; 227 228 num = 0; 229 if (!func) 230 d = (char *) arg; 231 else 232 d = NULL; 233 234 if (fmt == NULL) 235 fmt = "(fmt null)\n"; 236 237 if (radix < 2 || radix > 36) 238 radix = 10; 239 240 for (;;) { 241 padc = ' '; 242 width = 0; 243 while ((ch = (u_char)*fmt++) != '%' || stop) { 244 if (ch == '\0') 245 return (retval); 246 PCHAR(ch); 247 } 248 percent = fmt - 1; 249 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 250 sign = 0; dot = 0; dwidth = 0; upper = 0; 251 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 252 reswitch: switch (ch = (u_char)*fmt++) { 253 case '.': 254 dot = 1; 255 goto reswitch; 256 case '#': 257 sharpflag = 1; 258 goto reswitch; 259 case '+': 260 sign = 1; 261 goto reswitch; 262 case '-': 263 ladjust = 1; 264 goto reswitch; 265 case '%': 266 PCHAR(ch); 267 break; 268 case '*': 269 if (!dot) { 270 width = va_arg(ap, int); 271 if (width < 0) { 272 ladjust = !ladjust; 273 width = -width; 274 } 275 } else { 276 dwidth = va_arg(ap, int); 277 } 278 goto reswitch; 279 case '0': 280 if (!dot) { 281 padc = '0'; 282 goto reswitch; 283 } 284 case '1': case '2': case '3': case '4': 285 case '5': case '6': case '7': case '8': case '9': 286 for (n = 0;; ++fmt) { 287 n = n * 10 + ch - '0'; 288 ch = *fmt; 289 if (ch < '0' || ch > '9') 290 break; 291 } 292 if (dot) 293 dwidth = n; 294 else 295 width = n; 296 goto reswitch; 297 case 'b': 298 num = (u_int)va_arg(ap, int); 299 p = va_arg(ap, char *); 300 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 301 PCHAR(*q--); 302 303 if (num == 0) 304 break; 305 306 for (tmp = 0; *p;) { 307 n = *p++; 308 if (num & (1 << (n - 1))) { 309 PCHAR(tmp ? ',' : '<'); 310 for (; (n = *p) > ' '; ++p) 311 PCHAR(n); 312 tmp = 1; 313 } else 314 for (; *p > ' '; ++p) 315 continue; 316 } 317 if (tmp) 318 PCHAR('>'); 319 break; 320 case 'c': 321 PCHAR(va_arg(ap, int)); 322 break; 323 case 'D': 324 up = va_arg(ap, u_char *); 325 p = va_arg(ap, char *); 326 if (!width) 327 width = 16; 328 while(width--) { 329 PCHAR(hex2ascii(*up >> 4)); 330 PCHAR(hex2ascii(*up & 0x0f)); 331 up++; 332 if (width) 333 for (q=p;*q;q++) 334 PCHAR(*q); 335 } 336 break; 337 case 'd': 338 case 'i': 339 base = 10; 340 sign = 1; 341 goto handle_sign; 342 case 'h': 343 if (hflag) { 344 hflag = 0; 345 cflag = 1; 346 } else 347 hflag = 1; 348 goto reswitch; 349 case 'j': 350 jflag = 1; 351 goto reswitch; 352 case 'l': 353 if (lflag) { 354 lflag = 0; 355 qflag = 1; 356 } else 357 lflag = 1; 358 goto reswitch; 359 case 'n': 360 if (jflag) 361 *(va_arg(ap, intmax_t *)) = retval; 362 else if (qflag) 363 *(va_arg(ap, quad_t *)) = retval; 364 else if (lflag) 365 *(va_arg(ap, long *)) = retval; 366 else if (zflag) 367 *(va_arg(ap, size_t *)) = retval; 368 else if (hflag) 369 *(va_arg(ap, short *)) = retval; 370 else if (cflag) 371 *(va_arg(ap, char *)) = retval; 372 else 373 *(va_arg(ap, int *)) = retval; 374 break; 375 case 'o': 376 base = 8; 377 goto handle_nosign; 378 case 'p': 379 base = 16; 380 sharpflag = (width == 0); 381 sign = 0; 382 num = (uintptr_t)va_arg(ap, void *); 383 goto number; 384 case 'q': 385 qflag = 1; 386 goto reswitch; 387 case 'r': 388 base = radix; 389 if (sign) 390 goto handle_sign; 391 goto handle_nosign; 392 case 's': 393 p = va_arg(ap, char *); 394 if (p == NULL) 395 p = "(null)"; 396 if (!dot) 397 n = strlen (p); 398 else 399 for (n = 0; n < dwidth && p[n]; n++) 400 continue; 401 402 width -= n; 403 404 if (!ladjust && width > 0) 405 while (width--) 406 PCHAR(padc); 407 while (n--) 408 PCHAR(*p++); 409 if (ladjust && width > 0) 410 while (width--) 411 PCHAR(padc); 412 break; 413 case 't': 414 tflag = 1; 415 goto reswitch; 416 case 'u': 417 base = 10; 418 goto handle_nosign; 419 case 'X': 420 upper = 1; 421 case 'x': 422 base = 16; 423 goto handle_nosign; 424 case 'y': 425 base = 16; 426 sign = 1; 427 goto handle_sign; 428 case 'z': 429 zflag = 1; 430 goto reswitch; 431 handle_nosign: 432 sign = 0; 433 if (jflag) 434 num = va_arg(ap, uintmax_t); 435 else if (qflag) 436 num = va_arg(ap, u_quad_t); 437 else if (tflag) 438 num = va_arg(ap, ptrdiff_t); 439 else if (lflag) 440 num = va_arg(ap, u_long); 441 else if (zflag) 442 num = va_arg(ap, size_t); 443 else if (hflag) 444 num = (u_short)va_arg(ap, int); 445 else if (cflag) 446 num = (u_char)va_arg(ap, int); 447 else 448 num = va_arg(ap, u_int); 449 goto number; 450 handle_sign: 451 if (jflag) 452 num = va_arg(ap, intmax_t); 453 else if (qflag) 454 num = va_arg(ap, quad_t); 455 else if (tflag) 456 num = va_arg(ap, ptrdiff_t); 457 else if (lflag) 458 num = va_arg(ap, long); 459 else if (zflag) 460 num = va_arg(ap, ssize_t); 461 else if (hflag) 462 num = (short)va_arg(ap, int); 463 else if (cflag) 464 num = (char)va_arg(ap, int); 465 else 466 num = va_arg(ap, int); 467 number: 468 if (sign && (intmax_t)num < 0) { 469 neg = 1; 470 num = -(intmax_t)num; 471 } 472 p = ksprintn(nbuf, num, base, &n, upper); 473 tmp = 0; 474 if (sharpflag && num != 0) { 475 if (base == 8) 476 tmp++; 477 else if (base == 16) 478 tmp += 2; 479 } 480 if (neg) 481 tmp++; 482 483 if (!ladjust && padc == '0') 484 dwidth = width - tmp; 485 width -= tmp + imax(dwidth, n); 486 dwidth -= n; 487 if (!ladjust) 488 while (width-- > 0) 489 PCHAR(' '); 490 if (neg) 491 PCHAR('-'); 492 if (sharpflag && num != 0) { 493 if (base == 8) { 494 PCHAR('0'); 495 } else if (base == 16) { 496 PCHAR('0'); 497 PCHAR('x'); 498 } 499 } 500 while (dwidth-- > 0) 501 PCHAR('0'); 502 503 while (*p) 504 PCHAR(*p--); 505 506 if (ladjust) 507 while (width-- > 0) 508 PCHAR(' '); 509 510 break; 511 default: 512 while (percent < fmt) 513 PCHAR(*percent++); 514 /* 515 * Since we ignore an formatting argument it is no 516 * longer safe to obey the remaining formatting 517 * arguments as the arguments will no longer match 518 * the format specs. 519 */ 520 stop = 1; 521 break; 522 } 523 } 524 #undef PCHAR 525 } 526 527 int 528 printf(const char *fmt, ...) 529 { 530 va_list ap; 531 int retval; 532 533 va_start(ap, fmt); 534 retval = vprintf(fmt, ap); 535 va_end(ap); 536 537 return (retval); 538 } 539 540 int 541 vprintf(const char *fmt, va_list ap) 542 { 543 struct putchar_arg pca; 544 int retval; 545 #ifdef PRINTF_BUFR_SIZE 546 char bufr[PRINTF_BUFR_SIZE]; 547 #endif 548 549 pca.tty = NULL; 550 pca.flags = TOCONS | TOLOG; 551 pca.pri = -1; 552 #ifdef PRINTF_BUFR_SIZE 553 pca.p_bufr = bufr; 554 pca.p_next = pca.p_bufr; 555 pca.n_bufr = sizeof(bufr); 556 pca.remain = sizeof(bufr); 557 *pca.p_next = '\0'; 558 #else 559 /* Don't buffer console output. */ 560 pca.p_bufr = NULL; 561 #endif 562 563 retval = kvprintf(fmt, kputchar, &pca, 10, ap); 564 565 #ifdef PRINTF_BUFR_SIZE 566 /* Write any buffered console/log output: */ 567 if (*pca.p_bufr != '\0') { 568 cnputs(pca.p_bufr); 569 msglogstr(pca.p_bufr, pca.pri, /*filter_cr*/ 1); 570 } 571 #endif 572 573 return (retval); 574 } 575