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