2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Copyright Patrick Powell 1995
31 * This code is based on code written by Patrick Powell
32 * (papowell@astart.com) It may be used for any purpose as long
33 * as this notice remains intact on all source code distributions.
35 * Adapted for Bacula -- note there were lots of bugs in
36 * the original code: %lld and %s were seriously broken, and
37 * with FP turned off %f seg faulted.
39 * Kern Sibbald, November MMV
48 #define FP_OUTPUT 1 /* Bacula uses floating point */
50 /* Define the following if you want all the features of
51 * normal printf, but with all the security problems.
52 * For Bacula we turn this off, and it silently ignores
53 * formats that could pose a security problem.
55 #undef SECURITY_PROBLEM
59 #ifdef HAVE_LONG_DOUBLE
60 #define LDOUBLE long double
62 #define LDOUBLE double
65 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args);
66 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
67 const char *value, int flags, int min, int max);
68 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
69 const wchar_t *value, int flags, int min, int max);
70 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
71 int64_t value, int base, int min, int max, int flags);
77 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
78 LDOUBLE fvalue, int min, int max, int flags);
80 #define fmtfp(b, c, m, f, min, max, fl) currlen
84 * NOTE!!!! do not use this #define with a construct such
85 * as outch(--place);. It just will NOT work, because the
86 * decrement of place is done ONLY if there is room in the
89 #define outch(c) {int len=currlen; if (currlen < maxlen) \
90 { buffer[len] = (c); currlen++; }}
92 /* format read states */
93 #define DP_S_DEFAULT 0
102 /* format flags - Bits */
103 #define DP_F_MINUS (1 << 0)
104 #define DP_F_PLUS (1 << 1)
105 #define DP_F_SPACE (1 << 2)
106 #define DP_F_NUM (1 << 3)
107 #define DP_F_ZERO (1 << 4)
108 #define DP_F_UP (1 << 5)
109 #define DP_F_UNSIGNED (1 << 6)
110 #define DP_F_DOT (1 << 7)
112 /* Conversion Flags */
115 #define DP_C_LDOUBLE 3
117 #define DP_C_WCHAR 5 /* wide characters */
118 #define DP_C_SIZE_T 6
120 #define char_to_int(p) ((p)- '0')
122 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
125 You might ask why does Bacula have it's own printf routine? Well,
126 There are two reasons: 1. Here (as opposed to library routines), we
127 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
128 disable %n for security reasons.
131 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
136 va_start(arg_ptr, fmt);
137 len = bvsnprintf(str, size, fmt, arg_ptr);
143 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
160 state = DP_S_DEFAULT;
161 currlen = flags = cflags = min = 0;
166 while (state != DP_S_DONE) {
167 if ((ch == '\0') || (currlen >= maxlen)) {
207 if (isdigit((unsigned char)ch)) {
208 min = 10 * min + char_to_int(ch);
210 } else if (ch == '*') {
211 min = va_arg(args, int);
226 if (isdigit((unsigned char)ch)) {
229 max = 10 * max + char_to_int(ch);
231 } else if (ch == '*') {
232 max = va_arg(args, int);
249 } else if (ch == 'l') { /* It's a long long */
255 cflags = DP_C_SIZE_T;
259 cflags = DP_C_LDOUBLE;
262 case 'q': /* same as long long */
275 if (cflags == DP_C_INT16) {
276 value = va_arg(args, int32_t);
277 } else if (cflags == DP_C_INT32) {
278 value = va_arg(args, int32_t);
279 } else if (cflags == DP_C_INT64) {
280 value = va_arg(args, int64_t);
281 } else if (cflags == DP_C_SIZE_T) {
282 value = va_arg(args, ssize_t);
284 value = va_arg(args, int);
286 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
294 } else if (ch == 'x') {
296 } else if (ch == 'X') {
302 flags |= DP_F_UNSIGNED;
303 if (cflags == DP_C_INT16) {
304 value = va_arg(args, uint32_t);
305 } else if (cflags == DP_C_INT32) {
306 value = va_arg(args, uint32_t);
307 } else if (cflags == DP_C_INT64) {
308 value = va_arg(args, uint64_t);
309 } else if (cflags == DP_C_SIZE_T) {
310 value = va_arg(args, size_t);
312 value = va_arg(args, unsigned int);
314 currlen = fmtint(buffer, currlen, maxlen, value, base, min, max, flags);
317 if (cflags == DP_C_LDOUBLE) {
318 fvalue = va_arg(args, LDOUBLE);
320 fvalue = va_arg(args, double);
322 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
327 if (cflags == DP_C_LDOUBLE) {
328 fvalue = va_arg(args, LDOUBLE);
330 fvalue = va_arg(args, double);
332 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
337 if (cflags == DP_C_LDOUBLE) {
338 fvalue = va_arg(args, LDOUBLE);
340 fvalue = va_arg(args, double);
342 currlen = fmtfp(buffer, currlen, maxlen, fvalue, min, max, flags);
345 ch = va_arg(args, int);
349 if (cflags != DP_C_WCHAR) {
350 strvalue = va_arg(args, char *);
352 strvalue = (char *)"<NULL>";
354 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
356 /* %ls means to edit wide characters */
357 wstrvalue = va_arg(args, wchar_t *);
359 wstrvalue = (wchar_t *)L"<NULL>";
361 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
365 flags |= DP_F_UNSIGNED;
366 if (sizeof(char *) == 4) {
367 value = va_arg(args, uint32_t);
368 } else if (sizeof(char *) == 8) {
369 value = va_arg(args, uint64_t);
371 value = 0; /* we have a problem */
373 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
376 #ifdef SECURITY_PROBLEM
378 if (cflags == DP_C_INT16) {
380 num = va_arg(args, int16_t *);
382 } else if (cflags == DP_C_INT32) {
384 num = va_arg(args, int32_t *);
385 *num = (int32_t)currlen;
386 } else if (cflags == DP_C_INT64) {
388 num = va_arg(args, int64_t *);
389 *num = (int64_t)currlen;
392 num = va_arg(args, int32_t *);
393 *num = (int32_t)currlen;
401 /* not supported yet, treat as next char */
409 state = DP_S_DEFAULT;
410 flags = cflags = min = 0;
417 break; /* some picky compilers need this */
420 if (currlen < maxlen - 1) {
421 buffer[currlen] = '\0';
423 buffer[maxlen - 1] = '\0';
428 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
429 const char *value, int flags, int min, int max)
431 int padlen, strln; /* amount to pad */
436 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
438 } else if (max < 0) {
441 strln = strlen(value);
443 strln = max; /* truncate to max */
445 padlen = min - strln;
449 if (flags & DP_F_MINUS) {
450 padlen = -padlen; /* Left Justify */
457 while (*value && (cnt < max)) {
469 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
470 const wchar_t *value, int flags, int min, int max)
472 int padlen, strln; /* amount to pad */
477 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
479 } else if (max < 0) {
482 strln = wcslen(value);
484 strln = max; /* truncate to max */
486 padlen = min - strln;
490 if (flags & DP_F_MINUS) {
491 padlen = -padlen; /* Left Justify */
498 while (*value && (cnt < max)) {
500 ch = (*value++) & 0xff;
511 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
513 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
514 int64_t value, int base, int min, int max, int flags)
520 int spadlen = 0; /* amount to space pad */
521 int zpadlen = 0; /* amount to zero pad */
523 const char *cvt_string;
531 if (!(flags & DP_F_UNSIGNED)) {
535 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
537 } else if (flags & DP_F_SPACE) {
542 if (flags & DP_F_UP) {
543 caps = 1; /* Should characters be upper case? */
546 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
548 convert[place++] = cvt_string[uvalue % (unsigned)base];
549 uvalue = (uvalue / (unsigned)base);
550 } while (uvalue && (place < (int)sizeof(convert)));
551 if (place == (int)sizeof(convert)) {
556 zpadlen = max - place;
557 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
562 if (flags & DP_F_ZERO) {
563 zpadlen = MAX(zpadlen, spadlen);
566 if (flags & DP_F_MINUS)
567 spadlen = -spadlen; /* Left Justifty */
569 #ifdef DEBUG_SNPRINTF
570 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
571 zpadlen, spadlen, min, max, place);
575 while (spadlen > 0) {
587 while (zpadlen > 0) {
593 /* Output digits backward giving correct order */
596 outch(convert[place]);
599 /* Left Justified spaces */
600 while (spadlen < 0) {
609 static LDOUBLE abs_val(LDOUBLE value)
611 LDOUBLE result = value;
619 static LDOUBLE pow10(int exp)
631 static int64_t round(LDOUBLE value)
635 intpart = (int64_t)value;
636 value = value - intpart;
643 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
644 LDOUBLE fvalue, int min, int max, int flags)
658 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
662 int padlen = 0; /* amount to pad */
670 * AIX manpage says the default is 0, but Solaris says the default
671 * is 6, and sprintf on AIX defaults to 6
676 ufvalue = abs_val(fvalue);
680 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
682 else if (flags & DP_F_SPACE)
687 caps = 1; /* Should characters be upper case? */
691 intpart = (int64_t)ufvalue;
694 * Sorry, we only support 9 digits past the decimal because of our
700 /* We "cheat" by converting the fractional part to integer by
701 * multiplying by a factor of 10
703 fracpart = round((pow10(max)) * (ufvalue - intpart));
705 if (fracpart >= pow10(max)) {
707 fracpart -= (int64_t)pow10(max);
710 #ifdef DEBUG_SNPRINTF
711 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
712 (double)fvalue, intpart, fracpart, min, max);
715 /* Convert integer part */
716 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
718 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
719 intpart = (intpart / 10);
720 } while (intpart && (iplace < (int)sizeof(iconvert)));
722 if (iplace == (int)sizeof(fconvert)) {
725 iconvert[iplace] = 0;
727 /* Convert fractional part */
728 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
730 fconvert[fplace++] = cvt_str[fracpart % 10];
731 fracpart = (fracpart / 10);
732 } while (fracpart && (fplace < (int)sizeof(fconvert)));
734 if (fplace == (int)sizeof(fconvert)) {
737 fconvert[fplace] = 0;
738 #else /* use fcvt() */
743 result = fcvtl(ufvalue, max, &dec_pt, &sig);
745 result = fcvt(ufvalue, max, &dec_pt, &sig);
753 r_length = strlen(result);
757 * Fix broken fcvt implementation returns..
766 if (r_length < dec_pt)
777 fconvert[fplace++] = result[--r_length];
780 while ((dec_pt < 0) && (fplace < max)) {
781 fconvert[fplace++] = '0';
788 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
789 iconvert[iplace] = '\0';
794 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
796 #endif /* HAVE_FCVT */
798 /* -1 for decimal point, another -1 if we are printing a sign */
799 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
800 zpadlen = max - fplace;
807 if (flags & DP_F_MINUS) {
808 padlen = -padlen; /* Left Justifty */
811 if ((flags & DP_F_ZERO) && (padlen > 0)) {
832 outch(iconvert[iplace]);
836 #ifdef DEBUG_SNPRINTF
837 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
841 * Decimal point. This should probably use locale to find the correct
848 outch(fconvert[fplace]);
852 while (zpadlen > 0) {
863 #endif /* FP_OUTPUT */
869 #define LONG_STRING 1024
872 int main(int argc, char *argv[])
874 char buf1[LONG_STRING];
875 char buf2[LONG_STRING];
878 const char *fp_fmt[] = {
894 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
895 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
898 const char *int_fmt[] = {
919 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
921 const char *ll_fmt[] = {
933 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
935 const char *s_fmt[] = {
951 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
953 const char *ls_fmt[] = {
969 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
977 printf("Testing snprintf format codes against system sprintf...\n");
980 for (x = 0; fp_fmt[x] != NULL; x++)
981 for (y = 0; fp_nums[y] != 0; y++) {
982 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
983 sprintf(buf2, fp_fmt[x], fp_nums[y]);
984 if (strcmp(buf1, buf2)) {
986 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
987 fp_fmt[x], buf1, buf2);
994 for (x = 0; int_fmt[x] != NULL; x++)
995 for (y = 0; int_nums[y] != 0; y++) {
997 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
998 printf("%s\n", buf1);
999 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
1000 if (bcount != pcount) {
1001 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1004 if (strcmp(buf1, buf2)) {
1006 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1007 int_fmt[x], buf1, buf2);
1013 for (x = 0; ll_fmt[x] != NULL; x++) {
1014 for (y = 0; ll_nums[y] != 0; y++) {
1016 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1017 printf("%s\n", buf1);
1018 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
1019 if (bcount != pcount) {
1020 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1023 if (strcmp(buf1, buf2)) {
1025 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1026 ll_fmt[x], buf1, buf2);
1033 for (x = 0; s_fmt[x] != NULL; x++) {
1034 for (y = 0; s_nums[y] != 0; y++) {
1036 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1037 printf("%s\n", buf1);
1038 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
1039 if (bcount != pcount) {
1040 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1043 if (strcmp(buf1, buf2)) {
1045 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1046 s_fmt[x], buf1, buf2);
1053 for (x = 0; ls_fmt[x] != NULL; x++) {
1054 for (y = 0; ls_nums[y] != 0; y++) {
1056 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1057 printf("%s\n", buf1);
1058 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1059 if (bcount != pcount) {
1060 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1063 if (strcmp(buf1, buf2)) {
1065 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1066 ls_fmt[x], buf1, buf2);
1075 printf("%d tests failed out of %d.\n", fail, num);
1079 #endif /* TEST_PROGRAM */
1081 #endif /* USE_BSNPRINTF */