2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2005-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Copyright Patrick Powell 1995
23 * This code is based on code written by Patrick Powell
24 * (papowell@astart.com) It may be used for any purpose as long
25 * as this notice remains intact on all source code distributions.
27 * Adapted for Bacula -- note there were lots of bugs in
28 * the original code: %lld and %s were seriously broken, and
29 * with FP turned off %f seg faulted.
31 * Kern Sibbald, November MMV
40 #define FP_OUTPUT 1 /* Bacula uses floating point */
42 /* Define the following if you want all the features of
43 * normal printf, but with all the security problems.
44 * For Bacula we turn this off, and it silently ignores
45 * formats that could pose a security problem.
47 #undef SECURITY_PROBLEM
51 #ifdef HAVE_LONG_DOUBLE
52 #define LDOUBLE long double
54 #define LDOUBLE double
57 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
58 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
59 const char *value, int flags, int min, int max);
60 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
61 const wchar_t *value, int flags, int min, int max);
62 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
63 int64_t value, int base, int min, int max, int flags);
69 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
70 LDOUBLE fvalue, int min, int max, int flags);
72 #define fmtfp(b, c, m, f, min, max, fl) currlen
76 * NOTE!!!! do not use this #define with a construct such
77 * as outch(--place);. It just will NOT work, because the
78 * decrement of place is done ONLY if there is room in the
81 #define outch(c) {int len=currlen; if (currlen < maxlen) \
82 { buffer[len] = (c); currlen++; }}
84 /* format read states */
85 #define DP_S_DEFAULT 0
94 /* format flags - Bits */
95 #define DP_F_MINUS (1 << 0)
96 #define DP_F_PLUS (1 << 1)
97 #define DP_F_SPACE (1 << 2)
98 #define DP_F_NUM (1 << 3)
99 #define DP_F_ZERO (1 << 4)
100 #define DP_F_UP (1 << 5)
101 #define DP_F_UNSIGNED (1 << 6)
102 #define DP_F_DOT (1 << 7)
104 /* Conversion Flags */
107 #define DP_C_LDOUBLE 3
109 #define DP_C_WCHAR 5 /* wide characters */
110 #define DP_C_SIZE_T 6
112 #define char_to_int(p) ((p)- '0')
114 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
117 You might ask why does Bacula have it's own printf routine? Well,
118 There are two reasons: 1. Here (as opposed to library routines), we
119 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
120 disable %n for security reasons.
123 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
128 va_start(arg_ptr, fmt);
129 len = bvsnprintf(str, size, fmt, arg_ptr);
135 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
152 state = DP_S_DEFAULT;
153 currlen = flags = cflags = min = 0;
158 while (state != DP_S_DONE) {
159 if ((ch == '\0') || (currlen >= maxlen)) {
199 if (isdigit((unsigned char)ch)) {
200 min = 10 * min + char_to_int(ch);
202 } else if (ch == '*') {
203 min = va_arg(args, int);
218 if (isdigit((unsigned char)ch)) {
221 max = 10 * max + char_to_int(ch);
223 } else if (ch == '*') {
224 max = va_arg(args, int);
241 } else if (ch == 'l') { /* It's a long long */
247 cflags = DP_C_SIZE_T;
251 cflags = DP_C_LDOUBLE;
254 case 'q': /* same as long long */
267 if (cflags == DP_C_INT16) {
268 value = va_arg(args, int32_t);
269 } else if (cflags == DP_C_INT32) {
270 value = va_arg(args, int32_t);
271 } else if (cflags == DP_C_INT64) {
272 value = va_arg(args, int64_t);
273 } else if (cflags == DP_C_SIZE_T) {
274 value = va_arg(args, ssize_t);
276 value = va_arg(args, int);
278 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
286 } else if (ch == 'x') {
288 } else if (ch == 'X') {
294 flags |= DP_F_UNSIGNED;
295 if (cflags == DP_C_INT16) {
296 value = va_arg(args, uint32_t);
297 } else if (cflags == DP_C_INT32) {
298 value = va_arg(args, uint32_t);
299 } else if (cflags == DP_C_INT64) {
300 value = va_arg(args, uint64_t);
301 } else if (cflags == DP_C_SIZE_T) {
302 value = va_arg(args, size_t);
304 value = va_arg(args, unsigned int);
306 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
309 if (cflags == DP_C_LDOUBLE) {
310 fvalue = va_arg(args, LDOUBLE);
312 fvalue = va_arg(args, double);
314 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
319 if (cflags == DP_C_LDOUBLE) {
320 fvalue = va_arg(args, LDOUBLE);
322 fvalue = va_arg(args, double);
324 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
329 if (cflags == DP_C_LDOUBLE) {
330 fvalue = va_arg(args, LDOUBLE);
332 fvalue = va_arg(args, double);
334 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
337 ch = va_arg(args, int);
341 if (cflags != DP_C_WCHAR) {
342 strvalue = va_arg(args, char *);
344 strvalue = (char *)"<NULL>";
346 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
348 /* %ls means to edit wide characters */
349 wstrvalue = va_arg(args, wchar_t *);
351 wstrvalue = (wchar_t *)L"<NULL>";
353 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
357 flags |= DP_F_UNSIGNED;
358 if (sizeof(char *) == 4) {
359 value = va_arg(args, uint32_t);
360 } else if (sizeof(char *) == 8) {
361 value = va_arg(args, uint64_t);
363 value = 0; /* we have a problem */
365 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
368 #ifdef SECURITY_PROBLEM
370 if (cflags == DP_C_INT16) {
372 num = va_arg(args, int16_t *);
374 } else if (cflags == DP_C_INT32) {
376 num = va_arg(args, int32_t *);
377 *num = (int32_t)currlen;
378 } else if (cflags == DP_C_INT64) {
380 num = va_arg(args, int64_t *);
381 *num = (int64_t)currlen;
384 num = va_arg(args, int32_t *);
385 *num = (int32_t)currlen;
393 /* not supported yet, treat as next char */
401 state = DP_S_DEFAULT;
402 flags = cflags = min = 0;
409 break; /* some picky compilers need this */
412 if (currlen < maxlen - 1) {
413 buffer[currlen] = '\0';
415 buffer[maxlen - 1] = '\0';
420 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
421 const char *value, int flags, int min, int max)
423 int padlen, strln; /* amount to pad */
428 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
430 } else if (max < 0) {
433 strln = strlen(value);
435 strln = max; /* truncate to max */
437 padlen = min - strln;
441 if (flags & DP_F_MINUS) {
442 padlen = -padlen; /* Left Justify */
449 while (*value && (cnt < max)) {
461 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
462 const wchar_t *value, int flags, int min, int max)
464 int padlen, strln; /* amount to pad */
469 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
471 } else if (max < 0) {
474 strln = wcslen(value);
476 strln = max; /* truncate to max */
478 padlen = min - strln;
482 if (flags & DP_F_MINUS) {
483 padlen = -padlen; /* Left Justify */
490 while (*value && (cnt < max)) {
492 ch = (*value++) & 0xff;
503 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
505 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
506 int64_t value, int base, int min, int max, int flags)
512 int spadlen = 0; /* amount to space pad */
513 int zpadlen = 0; /* amount to zero pad */
515 const char *cvt_string;
523 if (!(flags & DP_F_UNSIGNED)) {
527 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
529 } else if (flags & DP_F_SPACE) {
534 if (flags & DP_F_UP) {
535 caps = 1; /* Should characters be upper case? */
538 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
540 convert[place++] = cvt_string[uvalue % (unsigned)base];
541 uvalue = (uvalue / (unsigned)base);
542 } while (uvalue && (place < (int)sizeof(convert)));
543 if (place == (int)sizeof(convert)) {
548 zpadlen = max - place;
549 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
554 if (flags & DP_F_ZERO) {
555 zpadlen = MAX(zpadlen, spadlen);
558 if (flags & DP_F_MINUS)
559 spadlen = -spadlen; /* Left Justifty */
561 #ifdef DEBUG_SNPRINTF
562 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
563 zpadlen, spadlen, min, max, place);
567 while (spadlen > 0) {
579 while (zpadlen > 0) {
585 /* Output digits backward giving correct order */
588 outch(convert[place]);
591 /* Left Justified spaces */
592 while (spadlen < 0) {
601 static LDOUBLE abs_val(LDOUBLE value)
603 LDOUBLE result = value;
611 static LDOUBLE pow10(int exp)
623 static int64_t round(LDOUBLE value)
627 intpart = (int64_t)value;
628 value = value - intpart;
635 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
636 LDOUBLE fvalue, int min, int max, int flags)
650 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
654 int padlen = 0; /* amount to pad */
661 * AIX manpage says the default is 0, but Solaris says the default
662 * is 6, and sprintf on AIX defaults to 6
667 ufvalue = abs_val(fvalue);
671 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
673 else if (flags & DP_F_SPACE)
677 intpart = (int64_t)ufvalue;
680 * Sorry, we only support 9 digits past the decimal because of our
686 /* We "cheat" by converting the fractional part to integer by
687 * multiplying by a factor of 10
689 fracpart = round((pow10(max)) * (ufvalue - intpart));
691 if (fracpart >= pow10(max)) {
693 fracpart -= (int64_t)pow10(max);
696 #ifdef DEBUG_SNPRINTF
697 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
698 (double)fvalue, intpart, fracpart, min, max);
701 /* Convert integer part */
702 cvt_str = "0123456789";
704 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
705 intpart = (intpart / 10);
706 } while (intpart && (iplace < (int)sizeof(iconvert)));
708 if (iplace == (int)sizeof(fconvert)) {
711 iconvert[iplace] = 0;
713 /* Convert fractional part */
714 cvt_str = "0123456789";
715 for (int fiter = max; fiter > 0; fiter--) {
716 fconvert[fplace++] = cvt_str[fracpart % 10];
717 fracpart = (fracpart / 10);
720 if (fplace == (int)sizeof(fconvert)) {
723 fconvert[fplace] = 0;
724 #else /* use fcvt() */
729 result = fcvtl(ufvalue, max, &dec_pt, &sig);
731 result = fcvt(ufvalue, max, &dec_pt, &sig);
739 r_length = strlen(result);
743 * Fix broken fcvt implementation returns..
752 if (r_length < dec_pt)
763 fconvert[fplace++] = result[--r_length];
766 while ((dec_pt < 0) && (fplace < max)) {
767 fconvert[fplace++] = '0';
774 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
775 iconvert[iplace] = '\0';
780 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
782 #endif /* HAVE_FCVT */
784 /* -1 for decimal point, another -1 if we are printing a sign */
785 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
786 zpadlen = max - fplace;
793 if (flags & DP_F_MINUS) {
794 padlen = -padlen; /* Left Justifty */
797 if ((flags & DP_F_ZERO) && (padlen > 0)) {
818 outch(iconvert[iplace]);
822 #ifdef DEBUG_SNPRINTF
823 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
827 * Decimal point. This should probably use locale to find the correct
834 outch(fconvert[fplace]);
838 while (zpadlen > 0) {
849 #endif /* FP_OUTPUT */
855 #define LONG_STRING 1024
858 int main(int argc, char *argv[])
860 char buf1[LONG_STRING];
861 char buf2[LONG_STRING];
864 const char *fp_fmt[] = {
881 double fp_nums[] = { 1.05, -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
882 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
885 const char *int_fmt[] = {
906 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
908 const char *ll_fmt[] = {
920 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
922 const char *s_fmt[] = {
938 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
940 const char *ls_fmt[] = {
956 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
962 printf("Testing snprintf format codes against system sprintf...\n");
965 for (x = 0; fp_fmt[x] != NULL; x++)
966 for (y = 0; fp_nums[y] != 0; y++) {
967 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
968 sprintf(buf2, fp_fmt[x], fp_nums[y]);
969 if (strcmp(buf1, buf2)) {
971 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
972 fp_fmt[x], buf1, buf2);
979 for (x = 0; int_fmt[x] != NULL; x++)
980 for (y = 0; int_nums[y] != 0; y++) {
982 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
983 printf("%s\n", buf1);
984 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
985 if (bcount != pcount) {
986 printf("bsnprintf count %d doesn't match sprintf count %d\n",
989 if (strcmp(buf1, buf2)) {
991 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
992 int_fmt[x], buf1, buf2);
998 for (x = 0; ll_fmt[x] != NULL; x++) {
999 for (y = 0; ll_nums[y] != 0; y++) {
1001 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1002 printf("%s\n", buf1);
1003 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
1004 if (bcount != pcount) {
1005 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1008 if (strcmp(buf1, buf2)) {
1010 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1011 ll_fmt[x], buf1, buf2);
1018 for (x = 0; s_fmt[x] != NULL; x++) {
1019 for (y = 0; s_nums[y] != 0; y++) {
1021 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1022 printf("%s\n", buf1);
1023 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
1024 if (bcount != pcount) {
1025 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1028 if (strcmp(buf1, buf2)) {
1030 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1031 s_fmt[x], buf1, buf2);
1038 for (x = 0; ls_fmt[x] != NULL; x++) {
1039 for (y = 0; ls_nums[y] != 0; y++) {
1041 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1042 printf("%s\n", buf1);
1043 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1044 if (bcount != pcount) {
1045 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1048 if (strcmp(buf1, buf2)) {
1050 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1051 ls_fmt[x], buf1, buf2);
1060 printf("%d tests failed out of %d.\n", fail, num);
1064 #endif /* TEST_PROGRAM */
1066 #endif /* USE_BSNPRINTF */