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 #include <sys/sbuf.h>
61
62 #ifdef DDB
63 #include <ddb/ddb.h>
64 #endif
65
66 /*
67 * Note that stdarg.h and the ANSI style va_start macro is used for both
68 * ANSI and traditional C compilers.
69 */
70 #include <machine/stdarg.h>
71
72 #define TOCONS 0x01
73 #define TOTTY 0x02
74 #define TOLOG 0x04
75
76 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
77 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
78
79 struct putchar_arg {
80 int flags;
81 int pri;
82 struct tty *tty;
83 char *p_bufr;
84 size_t n_bufr;
85 char *p_next;
86 size_t remain;
87 };
88
89 struct snprintf_arg {
90 char *str;
91 size_t remain;
92 };
93
94 int putchar(int c);
95 int puts(const char *str);
96
97
98 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
99
100 /*
101 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
102 * order; return an optional length and a pointer to the last character
103 * written in the buffer (i.e., the first character of the string).
104 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
105 */
106 static char *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)107 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
108 {
109 char *p, c;
110
111 p = nbuf;
112 *p = '\0';
113 do {
114 c = hex2ascii(num % base);
115 *++p = upper ? toupper(c) : c;
116 } while (num /= base);
117 if (lenp)
118 *lenp = p - nbuf;
119 return (p);
120 }
121
122 static void
putbuf(int c,struct putchar_arg * ap)123 putbuf(int c, struct putchar_arg *ap)
124 {
125 /* Check if no console output buffer was provided. */
126 if (ap->p_bufr == NULL) {
127 /* Output direct to the console. */
128 if (ap->flags & TOCONS)
129 putchar(c);
130
131 } else {
132 /* Buffer the character: */
133 *ap->p_next++ = c;
134 ap->remain--;
135
136 /* Always leave the buffer zero terminated. */
137 *ap->p_next = '\0';
138
139 /* Check if the buffer needs to be flushed. */
140 if (ap->remain == 2 || c == '\n') {
141
142 if (ap->flags & TOCONS) {
143 puts(ap->p_bufr);
144 }
145
146 ap->p_next = ap->p_bufr;
147 ap->remain = ap->n_bufr;
148 *ap->p_next = '\0';
149 }
150
151 /*
152 * Since we fill the buffer up one character at a time,
153 * this should not happen. We should always catch it when
154 * ap->remain == 2 (if not sooner due to a newline), flush
155 * the buffer and move on. One way this could happen is
156 * if someone sets PRINTF_BUFR_SIZE to 1 or something
157 * similarly silly.
158 */
159 KASSERT(ap->remain > 2, ("Bad buffer logic, remain = %zd",
160 ap->remain));
161 }
162 }
163
164 /*
165 * Print a character on console or users terminal. If destination is
166 * the console then the last bunch of characters are saved in msgbuf for
167 * inspection later.
168 */
169 static void
kputchar(int c,void * arg)170 kputchar(int c, void *arg)
171 {
172 struct putchar_arg *ap = (struct putchar_arg*) arg;
173 int flags = ap->flags;
174 int putbuf_done = 0;
175
176 if (flags & TOCONS) {
177 putbuf(c, ap);
178 putbuf_done = 1;
179 }
180
181 if ((flags & TOLOG) && (putbuf_done == 0)) {
182 if (c != '\0')
183 putbuf(c, ap);
184 }
185 }
186
187 /*
188 * Scaled down version of printf(3).
189 *
190 * Two additional formats:
191 *
192 * The format %b is supported to decode error registers.
193 * Its usage is:
194 *
195 * printf("reg=%b\n", regval, "<base><arg>*");
196 *
197 * where <base> is the output base expressed as a control character, e.g.
198 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
199 * the first of which gives the bit number to be inspected (origin 1), and
200 * the next characters (up to a control character, i.e. a character <= 32),
201 * give the name of the register. Thus:
202 *
203 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
204 *
205 * would produce output:
206 *
207 * reg=3<BITTWO,BITONE>
208 *
209 * XXX: %D -- Hexdump, takes pointer and separator string:
210 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
211 * ("%*D", len, ptr, " " -> XX XX XX XX ...
212 */
213 int
kvprintf(char const * fmt,void (* func)(int,void *),void * arg,int radix,va_list ap)214 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
215 {
216 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
217 char nbuf[MAXNBUF];
218 char *d;
219 const char *p, *percent, *q;
220 u_char *up;
221 int ch, n;
222 uintmax_t num;
223 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
224 int cflag, hflag, jflag, tflag, zflag;
225 int dwidth, upper;
226 char padc;
227 int stop = 0, retval = 0;
228
229 num = 0;
230 if (!func)
231 d = (char *) arg;
232 else
233 d = NULL;
234
235 if (fmt == NULL)
236 fmt = "(fmt null)\n";
237
238 if (radix < 2 || radix > 36)
239 radix = 10;
240
241 for (;;) {
242 padc = ' ';
243 width = 0;
244 while ((ch = (u_char)*fmt++) != '%' || stop) {
245 if (ch == '\0')
246 return (retval);
247 PCHAR(ch);
248 }
249 percent = fmt - 1;
250 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
251 sign = 0; dot = 0; dwidth = 0; upper = 0;
252 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
253 reswitch: switch (ch = (u_char)*fmt++) {
254 case '.':
255 dot = 1;
256 goto reswitch;
257 case '#':
258 sharpflag = 1;
259 goto reswitch;
260 case '+':
261 sign = 1;
262 goto reswitch;
263 case '-':
264 ladjust = 1;
265 goto reswitch;
266 case '%':
267 PCHAR(ch);
268 break;
269 case '*':
270 if (!dot) {
271 width = va_arg(ap, int);
272 if (width < 0) {
273 ladjust = !ladjust;
274 width = -width;
275 }
276 } else {
277 dwidth = va_arg(ap, int);
278 }
279 goto reswitch;
280 case '0':
281 if (!dot) {
282 padc = '0';
283 goto reswitch;
284 }
285 case '1': case '2': case '3': case '4':
286 case '5': case '6': case '7': case '8': case '9':
287 for (n = 0;; ++fmt) {
288 n = n * 10 + ch - '0';
289 ch = *fmt;
290 if (ch < '0' || ch > '9')
291 break;
292 }
293 if (dot)
294 dwidth = n;
295 else
296 width = n;
297 goto reswitch;
298 case 'b':
299 num = (u_int)va_arg(ap, int);
300 p = va_arg(ap, char *);
301 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
302 PCHAR(*q--);
303
304 if (num == 0)
305 break;
306
307 for (tmp = 0; *p;) {
308 n = *p++;
309 if (num & (1 << (n - 1))) {
310 PCHAR(tmp ? ',' : '<');
311 for (; (n = *p) > ' '; ++p)
312 PCHAR(n);
313 tmp = 1;
314 } else
315 for (; *p > ' '; ++p)
316 continue;
317 }
318 if (tmp)
319 PCHAR('>');
320 break;
321 case 'c':
322 PCHAR(va_arg(ap, int));
323 break;
324 case 'D':
325 up = va_arg(ap, u_char *);
326 p = va_arg(ap, char *);
327 if (!width)
328 width = 16;
329 while(width--) {
330 PCHAR(hex2ascii(*up >> 4));
331 PCHAR(hex2ascii(*up & 0x0f));
332 up++;
333 if (width)
334 for (q=p;*q;q++)
335 PCHAR(*q);
336 }
337 break;
338 case 'd':
339 case 'i':
340 base = 10;
341 sign = 1;
342 goto handle_sign;
343 case 'h':
344 if (hflag) {
345 hflag = 0;
346 cflag = 1;
347 } else
348 hflag = 1;
349 goto reswitch;
350 case 'j':
351 jflag = 1;
352 goto reswitch;
353 case 'l':
354 if (lflag) {
355 lflag = 0;
356 qflag = 1;
357 } else
358 lflag = 1;
359 goto reswitch;
360 case 'n':
361 if (jflag)
362 *(va_arg(ap, intmax_t *)) = retval;
363 else if (qflag)
364 *(va_arg(ap, quad_t *)) = retval;
365 else if (lflag)
366 *(va_arg(ap, long *)) = retval;
367 else if (zflag)
368 *(va_arg(ap, size_t *)) = retval;
369 else if (hflag)
370 *(va_arg(ap, short *)) = retval;
371 else if (cflag)
372 *(va_arg(ap, char *)) = retval;
373 else
374 *(va_arg(ap, int *)) = retval;
375 break;
376 case 'o':
377 base = 8;
378 goto handle_nosign;
379 case 'p':
380 base = 16;
381 sharpflag = (width == 0);
382 sign = 0;
383 num = (uintptr_t)va_arg(ap, void *);
384 goto number;
385 case 'q':
386 qflag = 1;
387 goto reswitch;
388 case 'r':
389 base = radix;
390 if (sign)
391 goto handle_sign;
392 goto handle_nosign;
393 case 's':
394 p = va_arg(ap, char *);
395 if (p == NULL)
396 p = "(null)";
397 if (!dot)
398 n = strlen (p);
399 else
400 for (n = 0; n < dwidth && p[n]; n++)
401 continue;
402
403 width -= n;
404
405 if (!ladjust && width > 0)
406 while (width--)
407 PCHAR(padc);
408 while (n--)
409 PCHAR(*p++);
410 if (ladjust && width > 0)
411 while (width--)
412 PCHAR(padc);
413 break;
414 case 't':
415 tflag = 1;
416 goto reswitch;
417 case 'u':
418 base = 10;
419 goto handle_nosign;
420 case 'X':
421 upper = 1;
422 case 'x':
423 base = 16;
424 goto handle_nosign;
425 case 'y':
426 base = 16;
427 sign = 1;
428 goto handle_sign;
429 case 'z':
430 zflag = 1;
431 goto reswitch;
432 handle_nosign:
433 sign = 0;
434 if (jflag)
435 num = va_arg(ap, uintmax_t);
436 else if (qflag)
437 num = va_arg(ap, u_quad_t);
438 else if (tflag)
439 num = va_arg(ap, ptrdiff_t);
440 else if (lflag)
441 num = va_arg(ap, u_long);
442 else if (zflag)
443 num = va_arg(ap, size_t);
444 else if (hflag)
445 num = (u_short)va_arg(ap, int);
446 else if (cflag)
447 num = (u_char)va_arg(ap, int);
448 else
449 num = va_arg(ap, u_int);
450 goto number;
451 handle_sign:
452 if (jflag)
453 num = va_arg(ap, intmax_t);
454 else if (qflag)
455 num = va_arg(ap, quad_t);
456 else if (tflag)
457 num = va_arg(ap, ptrdiff_t);
458 else if (lflag)
459 num = va_arg(ap, long);
460 else if (zflag)
461 num = va_arg(ap, ssize_t);
462 else if (hflag)
463 num = (short)va_arg(ap, int);
464 else if (cflag)
465 num = (char)va_arg(ap, int);
466 else
467 num = va_arg(ap, int);
468 number:
469 if (sign && (intmax_t)num < 0) {
470 neg = 1;
471 num = -(intmax_t)num;
472 }
473 p = ksprintn(nbuf, num, base, &n, upper);
474 tmp = 0;
475 if (sharpflag && num != 0) {
476 if (base == 8)
477 tmp++;
478 else if (base == 16)
479 tmp += 2;
480 }
481 if (neg)
482 tmp++;
483
484 if (!ladjust && padc == '0')
485 dwidth = width - tmp;
486 width -= tmp + imax(dwidth, n);
487 dwidth -= n;
488 if (!ladjust)
489 while (width-- > 0)
490 PCHAR(' ');
491 if (neg)
492 PCHAR('-');
493 if (sharpflag && num != 0) {
494 if (base == 8) {
495 PCHAR('0');
496 } else if (base == 16) {
497 PCHAR('0');
498 PCHAR('x');
499 }
500 }
501 while (dwidth-- > 0)
502 PCHAR('0');
503
504 while (*p)
505 PCHAR(*p--);
506
507 if (ladjust)
508 while (width-- > 0)
509 PCHAR(' ');
510
511 break;
512 default:
513 while (percent < fmt)
514 PCHAR(*percent++);
515 /*
516 * Since we ignore an formatting argument it is no
517 * longer safe to obey the remaining formatting
518 * arguments as the arguments will no longer match
519 * the format specs.
520 */
521 stop = 1;
522 break;
523 }
524 }
525 #undef PCHAR
526 }
527
528 int
printf(const char * fmt,...)529 printf(const char *fmt, ...)
530 {
531 va_list ap;
532 int retval;
533
534 va_start(ap, fmt);
535 retval = vprintf(fmt, ap);
536 va_end(ap);
537
538 return (retval);
539 }
540
541 int
vprintf(const char * fmt,va_list ap)542 vprintf(const char *fmt, va_list ap)
543 {
544 struct putchar_arg pca;
545 int retval;
546 #ifdef PRINTF_BUFR_SIZE
547 char bufr[PRINTF_BUFR_SIZE];
548 #endif
549
550 pca.tty = NULL;
551 pca.flags = TOCONS | TOLOG;
552 pca.pri = -1;
553 #ifdef PRINTF_BUFR_SIZE
554 pca.p_bufr = bufr;
555 pca.p_next = pca.p_bufr;
556 pca.n_bufr = sizeof(bufr);
557 pca.remain = sizeof(bufr);
558 *pca.p_next = '\0';
559 #else
560 /* Don't buffer console output. */
561 pca.p_bufr = NULL;
562 #endif
563
564 retval = kvprintf(fmt, kputchar, &pca, 10, ap);
565
566 #ifdef PRINTF_BUFR_SIZE
567 /* Write any buffered console/log output: */
568 if (*pca.p_bufr != '\0') {
569 cnputs(pca.p_bufr);
570 msglogstr(pca.p_bufr, pca.pri, /*filter_cr*/ 1);
571 }
572 #endif
573
574 return (retval);
575 }
576
577 void
vlog(int level,const char * fmt,va_list ap)578 vlog(int level, const char *fmt, va_list ap)
579 {
580 (void)vprintf(fmt, ap);
581 }
582
583 int
sbuf_printf_drain(void * arg,const char * data,int len)584 sbuf_printf_drain(void *arg, const char *data, int len)
585 {
586 return 0;
587 }
588
589