2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Copyright Patrick Powell 1995
22 * This code is based on code written by Patrick Powell
23 * (papowell@astart.com) It may be used for any purpose as long
24 * as this notice remains intact on all source code distributions.
26 * Adapted for Bacula -- note there were lots of bugs in
27 * the original code: %lld and %s were seriously broken, and
28 * with FP turned off %f seg faulted.
30 * Kern Sibbald, November MMV
39 #define FP_OUTPUT 1 /* Bacula uses floating point */
41 /* Define the following if you want all the features of
42 * normal printf, but with all the security problems.
43 * For Bacula we turn this off, and it silently ignores
44 * formats that could pose a security problem.
46 #undef SECURITY_PROBLEM
50 #ifdef HAVE_LONG_DOUBLE
51 #define LDOUBLE long double
53 #define LDOUBLE double
56 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
57 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
58 const char *value, int flags, int min, int max);
59 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
60 const wchar_t *value, int flags, int min, int max);
61 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
62 int64_t value, int base, int min, int max, int flags);
68 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
69 LDOUBLE fvalue, int min, int max, int flags);
71 #define fmtfp(b, c, m, f, min, max, fl) currlen
75 * NOTE!!!! do not use this #define with a construct such
76 * as outch(--place);. It just will NOT work, because the
77 * decrement of place is done ONLY if there is room in the
80 #define outch(c) {int len=currlen; if (currlen < maxlen) \
81 { buffer[len] = (c); currlen++; }}
83 /* format read states */
84 #define DP_S_DEFAULT 0
93 /* format flags - Bits */
94 #define DP_F_MINUS (1 << 0)
95 #define DP_F_PLUS (1 << 1)
96 #define DP_F_SPACE (1 << 2)
97 #define DP_F_NUM (1 << 3)
98 #define DP_F_ZERO (1 << 4)
99 #define DP_F_UP (1 << 5)
100 #define DP_F_UNSIGNED (1 << 6)
101 #define DP_F_DOT (1 << 7)
103 /* Conversion Flags */
106 #define DP_C_LDOUBLE 3
108 #define DP_C_WCHAR 5 /* wide characters */
109 #define DP_C_SIZE_T 6
111 #define char_to_int(p) ((p)- '0')
113 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
116 You might ask why does Bacula have it's own printf routine? Well,
117 There are two reasons: 1. Here (as opposed to library routines), we
118 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
119 disable %n for security reasons.
122 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
127 va_start(arg_ptr, fmt);
128 len = bvsnprintf(str, size, fmt, arg_ptr);
134 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
151 state = DP_S_DEFAULT;
152 currlen = flags = cflags = min = 0;
157 while (state != DP_S_DONE) {
158 if ((ch == '\0') || (currlen >= maxlen)) {
198 if (isdigit((unsigned char)ch)) {
199 min = 10 * min + char_to_int(ch);
201 } else if (ch == '*') {
202 min = va_arg(args, int);
217 if (isdigit((unsigned char)ch)) {
220 max = 10 * max + char_to_int(ch);
222 } else if (ch == '*') {
223 max = va_arg(args, int);
240 } else if (ch == 'l') { /* It's a long long */
246 cflags = DP_C_SIZE_T;
250 cflags = DP_C_LDOUBLE;
253 case 'q': /* same as long long */
266 if (cflags == DP_C_INT16) {
267 value = va_arg(args, int32_t);
268 } else if (cflags == DP_C_INT32) {
269 value = va_arg(args, int32_t);
270 } else if (cflags == DP_C_INT64) {
271 value = va_arg(args, int64_t);
272 } else if (cflags == DP_C_SIZE_T) {
273 value = va_arg(args, ssize_t);
275 value = va_arg(args, int);
277 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
285 } else if (ch == 'x') {
287 } else if (ch == 'X') {
293 flags |= DP_F_UNSIGNED;
294 if (cflags == DP_C_INT16) {
295 value = va_arg(args, uint32_t);
296 } else if (cflags == DP_C_INT32) {
297 value = va_arg(args, uint32_t);
298 } else if (cflags == DP_C_INT64) {
299 value = va_arg(args, uint64_t);
300 } else if (cflags == DP_C_SIZE_T) {
301 value = va_arg(args, size_t);
303 value = va_arg(args, unsigned int);
305 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
308 if (cflags == DP_C_LDOUBLE) {
309 fvalue = va_arg(args, LDOUBLE);
311 fvalue = va_arg(args, double);
313 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
318 if (cflags == DP_C_LDOUBLE) {
319 fvalue = va_arg(args, LDOUBLE);
321 fvalue = va_arg(args, double);
323 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
328 if (cflags == DP_C_LDOUBLE) {
329 fvalue = va_arg(args, LDOUBLE);
331 fvalue = va_arg(args, double);
333 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
336 ch = va_arg(args, int);
340 if (cflags != DP_C_WCHAR) {
341 strvalue = va_arg(args, char *);
343 strvalue = (char *)"<NULL>";
345 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
347 /* %ls means to edit wide characters */
348 wstrvalue = va_arg(args, wchar_t *);
350 wstrvalue = (wchar_t *)L"<NULL>";
352 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
356 flags |= DP_F_UNSIGNED;
357 if (sizeof(char *) == 4) {
358 value = va_arg(args, uint32_t);
359 } else if (sizeof(char *) == 8) {
360 value = va_arg(args, uint64_t);
362 value = 0; /* we have a problem */
364 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
367 #ifdef SECURITY_PROBLEM
369 if (cflags == DP_C_INT16) {
371 num = va_arg(args, int16_t *);
373 } else if (cflags == DP_C_INT32) {
375 num = va_arg(args, int32_t *);
376 *num = (int32_t)currlen;
377 } else if (cflags == DP_C_INT64) {
379 num = va_arg(args, int64_t *);
380 *num = (int64_t)currlen;
383 num = va_arg(args, int32_t *);
384 *num = (int32_t)currlen;
392 /* not supported yet, treat as next char */
400 state = DP_S_DEFAULT;
401 flags = cflags = min = 0;
408 break; /* some picky compilers need this */
411 if (currlen < maxlen - 1) {
412 buffer[currlen] = '\0';
414 buffer[maxlen - 1] = '\0';
419 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
420 const char *value, int flags, int min, int max)
422 int padlen, strln; /* amount to pad */
427 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
429 } else if (max < 0) {
432 strln = strlen(value);
434 strln = max; /* truncate to max */
436 padlen = min - strln;
440 if (flags & DP_F_MINUS) {
441 padlen = -padlen; /* Left Justify */
448 while (*value && (cnt < max)) {
460 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
461 const wchar_t *value, int flags, int min, int max)
463 int padlen, strln; /* amount to pad */
468 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
470 } else if (max < 0) {
473 strln = wcslen(value);
475 strln = max; /* truncate to max */
477 padlen = min - strln;
481 if (flags & DP_F_MINUS) {
482 padlen = -padlen; /* Left Justify */
489 while (*value && (cnt < max)) {
491 ch = (*value++) & 0xff;
502 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
504 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
505 int64_t value, int base, int min, int max, int flags)
511 int spadlen = 0; /* amount to space pad */
512 int zpadlen = 0; /* amount to zero pad */
514 const char *cvt_string;
522 if (!(flags & DP_F_UNSIGNED)) {
526 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
528 } else if (flags & DP_F_SPACE) {
533 if (flags & DP_F_UP) {
534 caps = 1; /* Should characters be upper case? */
537 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
539 convert[place++] = cvt_string[uvalue % (unsigned)base];
540 uvalue = (uvalue / (unsigned)base);
541 } while (uvalue && (place < (int)sizeof(convert)));
542 if (place == (int)sizeof(convert)) {
547 zpadlen = max - place;
548 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
553 if (flags & DP_F_ZERO) {
554 zpadlen = MAX(zpadlen, spadlen);
557 if (flags & DP_F_MINUS)
558 spadlen = -spadlen; /* Left Justifty */
560 #ifdef DEBUG_SNPRINTF
561 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
562 zpadlen, spadlen, min, max, place);
566 while (spadlen > 0) {
578 while (zpadlen > 0) {
584 /* Output digits backward giving correct order */
587 outch(convert[place]);
590 /* Left Justified spaces */
591 while (spadlen < 0) {
600 static LDOUBLE abs_val(LDOUBLE value)
602 LDOUBLE result = value;
610 static LDOUBLE pow10(int exp)
622 static int64_t round(LDOUBLE value)
626 intpart = (int64_t)value;
627 value = value - intpart;
634 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
635 LDOUBLE fvalue, int min, int max, int flags)
649 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
653 int padlen = 0; /* amount to pad */
660 * AIX manpage says the default is 0, but Solaris says the default
661 * is 6, and sprintf on AIX defaults to 6
666 ufvalue = abs_val(fvalue);
670 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
672 else if (flags & DP_F_SPACE)
676 intpart = (int64_t)ufvalue;
679 * Sorry, we only support 9 digits past the decimal because of our
685 /* We "cheat" by converting the fractional part to integer by
686 * multiplying by a factor of 10
688 fracpart = round((pow10(max)) * (ufvalue - intpart));
690 if (fracpart >= pow10(max)) {
692 fracpart -= (int64_t)pow10(max);
695 #ifdef DEBUG_SNPRINTF
696 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
697 (double)fvalue, intpart, fracpart, min, max);
700 /* Convert integer part */
701 cvt_str = "0123456789";
703 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
704 intpart = (intpart / 10);
705 } while (intpart && (iplace < (int)sizeof(iconvert)));
707 if (iplace == (int)sizeof(fconvert)) {
710 iconvert[iplace] = 0;
712 /* Convert fractional part */
713 cvt_str = "0123456789";
714 for (int fiter = max; fiter > 0; fiter--) {
715 fconvert[fplace++] = cvt_str[fracpart % 10];
716 fracpart = (fracpart / 10);
719 if (fplace == (int)sizeof(fconvert)) {
722 fconvert[fplace] = 0;
723 #else /* use fcvt() */
728 result = fcvtl(ufvalue, max, &dec_pt, &sig);
730 result = fcvt(ufvalue, max, &dec_pt, &sig);
738 r_length = strlen(result);
742 * Fix broken fcvt implementation returns..
751 if (r_length < dec_pt)
762 fconvert[fplace++] = result[--r_length];
765 while ((dec_pt < 0) && (fplace < max)) {
766 fconvert[fplace++] = '0';
773 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
774 iconvert[iplace] = '\0';
779 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
781 #endif /* HAVE_FCVT */
783 /* -1 for decimal point, another -1 if we are printing a sign */
784 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
785 zpadlen = max - fplace;
792 if (flags & DP_F_MINUS) {
793 padlen = -padlen; /* Left Justifty */
796 if ((flags & DP_F_ZERO) && (padlen > 0)) {
817 outch(iconvert[iplace]);
821 #ifdef DEBUG_SNPRINTF
822 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
826 * Decimal point. This should probably use locale to find the correct
833 outch(fconvert[fplace]);
837 while (zpadlen > 0) {
848 #endif /* FP_OUTPUT */
854 #define LONG_STRING 1024
857 int main(int argc, char *argv[])
859 char buf1[LONG_STRING];
860 char buf2[LONG_STRING];
863 const char *fp_fmt[] = {
880 double fp_nums[] = { 1.05, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
881 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
884 const char *int_fmt[] = {
905 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
907 const char *ll_fmt[] = {
919 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
921 const char *s_fmt[] = {
937 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
939 const char *ls_fmt[] = {
955 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
961 printf("Testing snprintf format codes against system sprintf...\n");
964 for (x = 0; fp_fmt[x] != NULL; x++)
965 for (y = 0; fp_nums[y] != 0; y++) {
966 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
967 sprintf(buf2, fp_fmt[x], fp_nums[y]);
968 if (strcmp(buf1, buf2)) {
970 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
971 fp_fmt[x], buf1, buf2);
978 for (x = 0; int_fmt[x] != NULL; x++)
979 for (y = 0; int_nums[y] != 0; y++) {
981 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
982 printf("%s\n", buf1);
983 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
984 if (bcount != pcount) {
985 printf("bsnprintf count %d doesn't match sprintf count %d\n",
988 if (strcmp(buf1, buf2)) {
990 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
991 int_fmt[x], buf1, buf2);
997 for (x = 0; ll_fmt[x] != NULL; x++) {
998 for (y = 0; ll_nums[y] != 0; y++) {
1000 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1001 printf("%s\n", buf1);
1002 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
1003 if (bcount != pcount) {
1004 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1007 if (strcmp(buf1, buf2)) {
1009 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1010 ll_fmt[x], buf1, buf2);
1017 for (x = 0; s_fmt[x] != NULL; x++) {
1018 for (y = 0; s_nums[y] != 0; y++) {
1020 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1021 printf("%s\n", buf1);
1022 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
1023 if (bcount != pcount) {
1024 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1027 if (strcmp(buf1, buf2)) {
1029 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1030 s_fmt[x], buf1, buf2);
1037 for (x = 0; ls_fmt[x] != NULL; x++) {
1038 for (y = 0; ls_nums[y] != 0; y++) {
1040 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1041 printf("%s\n", buf1);
1042 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1043 if (bcount != pcount) {
1044 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1047 if (strcmp(buf1, buf2)) {
1049 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1050 ls_fmt[x], buf1, buf2);
1059 printf("%d tests failed out of %d.\n", fail, num);
1063 #endif /* TEST_PROGRAM */
1065 #endif /* USE_BSNPRINTF */