2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2010 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 two of the GNU 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 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 *);
351 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
353 /* %ls means to edit wide characters */
354 wstrvalue = va_arg(args, wchar_t *);
355 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
359 flags |= DP_F_UNSIGNED;
360 if (sizeof(char *) == 4) {
361 value = va_arg(args, uint32_t);
362 } else if (sizeof(char *) == 8) {
363 value = va_arg(args, uint64_t);
365 value = 0; /* we have a problem */
367 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
370 if (cflags == DP_C_INT16) {
372 num = va_arg(args, int16_t *);
373 #ifdef SECURITY_PROBLEM
376 } else if (cflags == DP_C_INT32) {
378 num = va_arg(args, int32_t *);
379 #ifdef SECURITY_PROBLEM
380 *num = (int32_t)currlen;
382 } else if (cflags == DP_C_INT64) {
384 num = va_arg(args, int64_t *);
385 #ifdef SECURITY_PROBLEM
386 *num = (int64_t)currlen;
390 num = va_arg(args, int32_t *);
391 #ifdef SECURITY_PROBLEM
392 *num = (int32_t)currlen;
400 /* not supported yet, treat as next char */
408 state = DP_S_DEFAULT;
409 flags = cflags = min = 0;
416 break; /* some picky compilers need this */
419 if (currlen < maxlen - 1) {
420 buffer[currlen] = '\0';
422 buffer[maxlen - 1] = '\0';
427 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
428 const char *value, int flags, int min, int max)
430 int padlen, strln; /* amount to pad */
435 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
437 } else if (max < 0) {
443 strln = strlen(value);
445 strln = max; /* truncate to max */
447 padlen = min - strln;
451 if (flags & DP_F_MINUS) {
452 padlen = -padlen; /* Left Justify */
459 while (*value && (cnt < max)) {
471 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
472 const wchar_t *value, int flags, int min, int max)
474 int padlen, strln; /* amount to pad */
479 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
481 } else if (max < 0) {
487 strln = wcslen(value);
489 strln = max; /* truncate to max */
491 padlen = min - strln;
495 if (flags & DP_F_MINUS) {
496 padlen = -padlen; /* Left Justify */
503 while (*value && (cnt < max)) {
505 ch = (*value++) & 0xff;
516 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
518 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
519 int64_t value, int base, int min, int max, int flags)
525 int spadlen = 0; /* amount to space pad */
526 int zpadlen = 0; /* amount to zero pad */
528 const char *cvt_string;
536 if (!(flags & DP_F_UNSIGNED)) {
540 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
542 } else if (flags & DP_F_SPACE) {
547 if (flags & DP_F_UP) {
548 caps = 1; /* Should characters be upper case? */
551 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
553 convert[place++] = cvt_string[uvalue % (unsigned)base];
554 uvalue = (uvalue / (unsigned)base);
555 } while (uvalue && (place < (int)sizeof(convert)));
556 if (place == (int)sizeof(convert)) {
561 zpadlen = max - place;
562 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
567 if (flags & DP_F_ZERO) {
568 zpadlen = MAX(zpadlen, spadlen);
571 if (flags & DP_F_MINUS)
572 spadlen = -spadlen; /* Left Justifty */
574 #ifdef DEBUG_SNPRINTF
575 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
576 zpadlen, spadlen, min, max, place);
580 while (spadlen > 0) {
592 while (zpadlen > 0) {
598 /* Output digits backward giving correct order */
601 outch(convert[place]);
604 /* Left Justified spaces */
605 while (spadlen < 0) {
614 static LDOUBLE abs_val(LDOUBLE value)
616 LDOUBLE result = value;
624 static LDOUBLE pow10(int exp)
636 static int64_t round(LDOUBLE value)
640 intpart = (int64_t)value;
641 value = value - intpart;
648 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
649 LDOUBLE fvalue, int min, int max, int flags)
663 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
667 int padlen = 0; /* amount to pad */
675 * AIX manpage says the default is 0, but Solaris says the default
676 * is 6, and sprintf on AIX defaults to 6
681 ufvalue = abs_val(fvalue);
685 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
687 else if (flags & DP_F_SPACE)
692 caps = 1; /* Should characters be upper case? */
696 intpart = (int64_t)ufvalue;
699 * Sorry, we only support 9 digits past the decimal because of our
705 /* We "cheat" by converting the fractional part to integer by
706 * multiplying by a factor of 10
708 fracpart = round((pow10(max)) * (ufvalue - intpart));
710 if (fracpart >= pow10(max)) {
712 fracpart -= (int64_t)pow10(max);
715 #ifdef DEBUG_SNPRINTF
716 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
717 (double)fvalue, intpart, fracpart, min, max);
720 /* Convert integer part */
721 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
723 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
724 intpart = (intpart / 10);
725 } while (intpart && (iplace < (int)sizeof(iconvert)));
727 if (iplace == (int)sizeof(fconvert)) {
730 iconvert[iplace] = 0;
732 /* Convert fractional part */
733 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
735 fconvert[fplace++] = cvt_str[fracpart % 10];
736 fracpart = (fracpart / 10);
737 } while (fracpart && (fplace < (int)sizeof(fconvert)));
739 if (fplace == (int)sizeof(fconvert)) {
742 fconvert[fplace] = 0;
743 #else /* use fcvt() */
748 result = fcvtl(ufvalue, max, &dec_pt, &sig);
750 result = fcvt(ufvalue, max, &dec_pt, &sig);
757 r_length = strlen(result);
761 * Fix broken fcvt implementation returns..
770 if (r_length < dec_pt)
781 fconvert[fplace++] = result[--r_length];
784 while ((dec_pt < 0) && (fplace < max)) {
785 fconvert[fplace++] = '0';
792 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
793 iconvert[iplace] = '\0';
798 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
800 #endif /* HAVE_FCVT */
802 /* -1 for decimal point, another -1 if we are printing a sign */
803 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
804 zpadlen = max - fplace;
811 if (flags & DP_F_MINUS) {
812 padlen = -padlen; /* Left Justifty */
815 if ((flags & DP_F_ZERO) && (padlen > 0)) {
836 outch(iconvert[iplace]);
840 #ifdef DEBUG_SNPRINTF
841 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
845 * Decimal point. This should probably use locale to find the correct
852 outch(fconvert[fplace]);
856 while (zpadlen > 0) {
867 #endif /* FP_OUTPUT */
873 #define LONG_STRING 1024
876 int main(int argc, char *argv[])
878 char buf1[LONG_STRING];
879 char buf2[LONG_STRING];
882 const char *fp_fmt[] = {
898 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
899 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
902 const char *int_fmt[] = {
923 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
925 const char *ll_fmt[] = {
937 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
939 const char *s_fmt[] = {
955 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
957 const char *ls_fmt[] = {
973 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
981 printf("Testing snprintf format codes against system sprintf...\n");
984 for (x = 0; fp_fmt[x] != NULL; x++)
985 for (y = 0; fp_nums[y] != 0; y++) {
986 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
987 sprintf(buf2, fp_fmt[x], fp_nums[y]);
988 if (strcmp(buf1, buf2)) {
990 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
991 fp_fmt[x], buf1, buf2);
998 for (x = 0; int_fmt[x] != NULL; x++)
999 for (y = 0; int_nums[y] != 0; y++) {
1001 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
1002 printf("%s\n", buf1);
1003 pcount = sprintf(buf2, int_fmt[x], int_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 int_fmt[x], buf1, buf2);
1017 for (x = 0; ll_fmt[x] != NULL; x++) {
1018 for (y = 0; ll_nums[y] != 0; y++) {
1020 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1021 printf("%s\n", buf1);
1022 pcount = sprintf(buf2, ll_fmt[x], ll_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 ll_fmt[x], buf1, buf2);
1037 for (x = 0; s_fmt[x] != NULL; x++) {
1038 for (y = 0; s_nums[y] != 0; y++) {
1040 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1041 printf("%s\n", buf1);
1042 pcount = sprintf(buf2, s_fmt[x], s_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 s_fmt[x], buf1, buf2);
1057 for (x = 0; ls_fmt[x] != NULL; x++) {
1058 for (y = 0; ls_nums[y] != 0; y++) {
1060 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1061 printf("%s\n", buf1);
1062 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1063 if (bcount != pcount) {
1064 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1067 if (strcmp(buf1, buf2)) {
1069 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1070 ls_fmt[x], buf1, buf2);
1079 printf("%d tests failed out of %d.\n", fail, num);
1083 #endif /* TEST_PROGRAM */
1085 #endif /* USE_BSNPRINTF */