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