1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1986, 1988, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> 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 38 #include <sys/param.h> 39 #include <inttypes.h> 40 #include <stdarg.h> 41 #include <stddef.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include "rtld_printf.h" 45 #include "rtld_libc.h" 46 47 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 48 49 #define PRINT_METHOD_SNPRINTF 1 50 #define PRINT_METHOD_WRITE 2 51 52 struct snprintf_arg { 53 int method; 54 char *str; 55 char *buf; 56 size_t remain; 57 size_t buf_total; 58 int fd; 59 }; 60 61 static void 62 printf_out(struct snprintf_arg *info) 63 { 64 65 if (info->remain == info->buf_total) 66 return; 67 write(info->fd, info->buf, info->buf_total - info->remain); 68 info->str = info->buf; 69 info->remain = info->buf_total; 70 } 71 72 static void 73 snprintf_func(int ch, struct snprintf_arg *const info) 74 { 75 76 switch (info->method) { 77 case PRINT_METHOD_SNPRINTF: 78 if (info->remain >= 2) { 79 *info->str++ = ch; 80 info->remain--; 81 } 82 break; 83 case PRINT_METHOD_WRITE: 84 if (info->remain > 0) { 85 *info->str++ = ch; 86 info->remain--; 87 } else 88 printf_out(info); 89 break; 90 } 91 } 92 93 static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 94 static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 95 #define hex2ascii(hex) (hex2ascii_lower[hex]) 96 #define hex2ascii_upper(hex) (hex2ascii_upper[hex]) 97 98 static __inline int 99 imax(int a, int b) 100 { 101 102 return (a > b ? a : b); 103 } 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 = upper ? hex2ascii_upper(num % base) : 114 hex2ascii(num % base); 115 *++p = c; 116 } while (num /= base); 117 if (lenp) 118 *lenp = p - nbuf; 119 return (p); 120 } 121 122 static int 123 kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap) 124 { 125 #define PCHAR(c) snprintf_func((c), arg) 126 char nbuf[MAXNBUF]; 127 const char *p, *percent, *q; 128 u_char *up; 129 int ch, n; 130 uintmax_t num; 131 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 132 int cflag, hflag, jflag, tflag, zflag; 133 int dwidth, upper; 134 char padc; 135 int stop = 0, retval = 0; 136 137 num = 0; 138 139 if (fmt == NULL) 140 fmt = "(fmt null)\n"; 141 142 if (radix < 2 || radix > 36) 143 radix = 10; 144 145 for (;;) { 146 padc = ' '; 147 width = 0; 148 while ((ch = (u_char)*fmt++) != '%' || stop) { 149 if (ch == '\0') 150 return (retval); 151 PCHAR(ch); 152 } 153 percent = fmt - 1; 154 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 155 sign = 0; dot = 0; dwidth = 0; upper = 0; 156 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 157 reswitch: switch (ch = (u_char)*fmt++) { 158 case '.': 159 dot = 1; 160 goto reswitch; 161 case '#': 162 sharpflag = 1; 163 goto reswitch; 164 case '+': 165 sign = 1; 166 goto reswitch; 167 case '-': 168 ladjust = 1; 169 goto reswitch; 170 case '%': 171 PCHAR(ch); 172 break; 173 case '*': 174 if (!dot) { 175 width = va_arg(ap, int); 176 if (width < 0) { 177 ladjust = !ladjust; 178 width = -width; 179 } 180 } else { 181 dwidth = va_arg(ap, int); 182 } 183 goto reswitch; 184 case '0': 185 if (!dot) { 186 padc = '0'; 187 goto reswitch; 188 } 189 /* FALLTHROUGH */ 190 case '1': case '2': case '3': case '4': 191 case '5': case '6': case '7': case '8': case '9': 192 for (n = 0;; ++fmt) { 193 n = n * 10 + ch - '0'; 194 ch = *fmt; 195 if (ch < '0' || ch > '9') 196 break; 197 } 198 if (dot) 199 dwidth = n; 200 else 201 width = n; 202 goto reswitch; 203 case 'b': 204 num = (u_int)va_arg(ap, int); 205 p = va_arg(ap, char *); 206 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) 207 PCHAR(*q--); 208 209 if (num == 0) 210 break; 211 212 for (tmp = 0; *p;) { 213 n = *p++; 214 if (num & (1 << (n - 1))) { 215 PCHAR(tmp ? ',' : '<'); 216 for (; (n = *p) > ' '; ++p) 217 PCHAR(n); 218 tmp = 1; 219 } else 220 for (; *p > ' '; ++p) 221 continue; 222 } 223 if (tmp) 224 PCHAR('>'); 225 break; 226 case 'c': 227 PCHAR(va_arg(ap, int)); 228 break; 229 case 'D': 230 up = va_arg(ap, u_char *); 231 p = va_arg(ap, char *); 232 if (!width) 233 width = 16; 234 while(width--) { 235 PCHAR(hex2ascii(*up >> 4)); 236 PCHAR(hex2ascii(*up & 0x0f)); 237 up++; 238 if (width) 239 for (q=p;*q;q++) 240 PCHAR(*q); 241 } 242 break; 243 case 'd': 244 case 'i': 245 base = 10; 246 sign = 1; 247 goto handle_sign; 248 case 'h': 249 if (hflag) { 250 hflag = 0; 251 cflag = 1; 252 } else 253 hflag = 1; 254 goto reswitch; 255 case 'j': 256 jflag = 1; 257 goto reswitch; 258 case 'l': 259 if (lflag) { 260 lflag = 0; 261 qflag = 1; 262 } else 263 lflag = 1; 264 goto reswitch; 265 case 'n': 266 if (jflag) 267 *(va_arg(ap, intmax_t *)) = retval; 268 else if (qflag) 269 *(va_arg(ap, quad_t *)) = retval; 270 else if (lflag) 271 *(va_arg(ap, long *)) = retval; 272 else if (zflag) 273 *(va_arg(ap, size_t *)) = retval; 274 else if (hflag) 275 *(va_arg(ap, short *)) = retval; 276 else if (cflag) 277 *(va_arg(ap, char *)) = retval; 278 else 279 *(va_arg(ap, int *)) = retval; 280 break; 281 case 'o': 282 base = 8; 283 goto handle_nosign; 284 case 'p': 285 base = 16; 286 sharpflag = (width == 0); 287 sign = 0; 288 num = (uintptr_t)va_arg(ap, void *); 289 goto number; 290 case 'q': 291 qflag = 1; 292 goto reswitch; 293 case 'r': 294 base = radix; 295 if (sign) 296 goto handle_sign; 297 goto handle_nosign; 298 case 's': 299 p = va_arg(ap, char *); 300 if (p == NULL) 301 p = "(null)"; 302 if (!dot) 303 n = strlen (p); 304 else 305 for (n = 0; n < dwidth && p[n]; n++) 306 continue; 307 308 width -= n; 309 310 if (!ladjust && width > 0) 311 while (width--) 312 PCHAR(padc); 313 while (n--) 314 PCHAR(*p++); 315 if (ladjust && width > 0) 316 while (width--) 317 PCHAR(padc); 318 break; 319 case 't': 320 tflag = 1; 321 goto reswitch; 322 case 'u': 323 base = 10; 324 goto handle_nosign; 325 case 'X': 326 upper = 1; 327 /* FALLTHROUGH */ 328 case 'x': 329 base = 16; 330 goto handle_nosign; 331 case 'y': 332 base = 16; 333 sign = 1; 334 goto handle_sign; 335 case 'z': 336 zflag = 1; 337 goto reswitch; 338 handle_nosign: 339 sign = 0; 340 if (jflag) 341 num = va_arg(ap, uintmax_t); 342 else if (qflag) 343 num = va_arg(ap, u_quad_t); 344 else if (tflag) 345 num = va_arg(ap, ptrdiff_t); 346 else if (lflag) 347 num = va_arg(ap, u_long); 348 else if (zflag) 349 num = va_arg(ap, size_t); 350 else if (hflag) 351 num = (u_short)va_arg(ap, int); 352 else if (cflag) 353 num = (u_char)va_arg(ap, int); 354 else 355 num = va_arg(ap, u_int); 356 goto number; 357 handle_sign: 358 if (jflag) 359 num = va_arg(ap, intmax_t); 360 else if (qflag) 361 num = va_arg(ap, quad_t); 362 else if (tflag) 363 num = va_arg(ap, ptrdiff_t); 364 else if (lflag) 365 num = va_arg(ap, long); 366 else if (zflag) 367 num = va_arg(ap, ssize_t); 368 else if (hflag) 369 num = (short)va_arg(ap, int); 370 else if (cflag) 371 num = (char)va_arg(ap, int); 372 else 373 num = va_arg(ap, int); 374 number: 375 if (sign && (intmax_t)num < 0) { 376 neg = 1; 377 num = -(intmax_t)num; 378 } 379 p = ksprintn(nbuf, num, base, &n, upper); 380 tmp = 0; 381 if (sharpflag && num != 0) { 382 if (base == 8) 383 tmp++; 384 else if (base == 16) 385 tmp += 2; 386 } 387 if (neg) 388 tmp++; 389 390 if (!ladjust && padc == '0') 391 dwidth = width - tmp; 392 width -= tmp + imax(dwidth, n); 393 dwidth -= n; 394 if (!ladjust) 395 while (width-- > 0) 396 PCHAR(' '); 397 if (neg) 398 PCHAR('-'); 399 if (sharpflag && num != 0) { 400 if (base == 8) { 401 PCHAR('0'); 402 } else if (base == 16) { 403 PCHAR('0'); 404 PCHAR('x'); 405 } 406 } 407 while (dwidth-- > 0) 408 PCHAR('0'); 409 410 while (*p) 411 PCHAR(*p--); 412 413 if (ladjust) 414 while (width-- > 0) 415 PCHAR(' '); 416 417 break; 418 default: 419 while (percent < fmt) 420 PCHAR(*percent++); 421 /* 422 * Since we ignore an formatting argument it is no 423 * longer safe to obey the remaining formatting 424 * arguments as the arguments will no longer match 425 * the format specs. 426 */ 427 stop = 1; 428 break; 429 } 430 } 431 #undef PCHAR 432 } 433 434 int 435 rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...) 436 { 437 va_list ap; 438 int retval; 439 440 va_start(ap, fmt); 441 retval = rtld_vsnprintf(buf, bufsize, fmt, ap); 442 va_end(ap); 443 return (retval); 444 } 445 446 int 447 rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap) 448 { 449 struct snprintf_arg info; 450 int retval; 451 452 info.method = PRINT_METHOD_SNPRINTF; 453 info.buf = info.str = buf; 454 info.buf_total = info.remain = bufsize; 455 info.fd = -1; 456 retval = kvprintf(fmt, &info, 10, ap); 457 if (info.remain >= 1) 458 *info.str++ = '\0'; 459 return (retval); 460 } 461 462 int 463 rtld_vfdprintf(int fd, const char *fmt, va_list ap) 464 { 465 char buf[512]; 466 struct snprintf_arg info; 467 int retval; 468 469 info.method = PRINT_METHOD_WRITE; 470 info.buf = info.str = buf; 471 info.buf_total = info.remain = sizeof(buf); 472 info.fd = fd; 473 retval = kvprintf(fmt, &info, 10, ap); 474 printf_out(&info); 475 return (retval); 476 } 477 478 int 479 rtld_fdprintf(int fd, const char *fmt, ...) 480 { 481 va_list ap; 482 int retval; 483 484 va_start(ap, fmt); 485 retval = rtld_vfdprintf(fd, fmt, ap); 486 va_end(ap); 487 return (retval); 488 } 489 490 int 491 rtld_fdprintfx(int fd, const char *fmt, ...) 492 { 493 va_list ap; 494 int retval; 495 496 va_start(ap, fmt); 497 retval = rtld_vfdprintf(fd, fmt, ap); 498 va_end(ap); 499 return (retval); 500 } 501 502 void 503 rtld_fdputstr(int fd, const char *str) 504 { 505 506 write(fd, str, strlen(str)); 507 } 508 509 void 510 rtld_fdputchar(int fd, int c) 511 { 512 char c1; 513 514 c1 = c; 515 write(fd, &c1, 1); 516 } 517