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 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 if (cflags == DP_C_INT16) {
378 num = va_arg(args, int16_t *);
379 #ifdef SECURITY_PROBLEM
382 } else if (cflags == DP_C_INT32) {
384 num = va_arg(args, int32_t *);
385 #ifdef SECURITY_PROBLEM
386 *num = (int32_t)currlen;
388 } else if (cflags == DP_C_INT64) {
390 num = va_arg(args, int64_t *);
391 #ifdef SECURITY_PROBLEM
392 *num = (int64_t)currlen;
396 num = va_arg(args, int32_t *);
397 #ifdef SECURITY_PROBLEM
398 *num = (int32_t)currlen;
406 /* not supported yet, treat as next char */
414 state = DP_S_DEFAULT;
415 flags = cflags = min = 0;
422 break; /* some picky compilers need this */
425 if (currlen < maxlen - 1) {
426 buffer[currlen] = '\0';
428 buffer[maxlen - 1] = '\0';
433 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
434 const char *value, int flags, int min, int max)
436 int padlen, strln; /* amount to pad */
441 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
443 } else if (max < 0) {
446 strln = strlen(value);
448 strln = max; /* truncate to max */
450 padlen = min - strln;
454 if (flags & DP_F_MINUS) {
455 padlen = -padlen; /* Left Justify */
462 while (*value && (cnt < max)) {
474 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
475 const wchar_t *value, int flags, int min, int max)
477 int padlen, strln; /* amount to pad */
482 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
484 } 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);
758 r_length = strlen(result);
762 * Fix broken fcvt implementation returns..
771 if (r_length < dec_pt)
782 fconvert[fplace++] = result[--r_length];
785 while ((dec_pt < 0) && (fplace < max)) {
786 fconvert[fplace++] = '0';
793 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
794 iconvert[iplace] = '\0';
799 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
801 #endif /* HAVE_FCVT */
803 /* -1 for decimal point, another -1 if we are printing a sign */
804 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
805 zpadlen = max - fplace;
812 if (flags & DP_F_MINUS) {
813 padlen = -padlen; /* Left Justifty */
816 if ((flags & DP_F_ZERO) && (padlen > 0)) {
837 outch(iconvert[iplace]);
841 #ifdef DEBUG_SNPRINTF
842 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
846 * Decimal point. This should probably use locale to find the correct
853 outch(fconvert[fplace]);
857 while (zpadlen > 0) {
868 #endif /* FP_OUTPUT */
874 #define LONG_STRING 1024
877 int main(int argc, char *argv[])
879 char buf1[LONG_STRING];
880 char buf2[LONG_STRING];
883 const char *fp_fmt[] = {
899 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
900 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
903 const char *int_fmt[] = {
924 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
926 const char *ll_fmt[] = {
938 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
940 const char *s_fmt[] = {
956 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
958 const char *ls_fmt[] = {
974 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
982 printf("Testing snprintf format codes against system sprintf...\n");
985 for (x = 0; fp_fmt[x] != NULL; x++)
986 for (y = 0; fp_nums[y] != 0; y++) {
987 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
988 sprintf(buf2, fp_fmt[x], fp_nums[y]);
989 if (strcmp(buf1, buf2)) {
991 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
992 fp_fmt[x], buf1, buf2);
999 for (x = 0; int_fmt[x] != NULL; x++)
1000 for (y = 0; int_nums[y] != 0; y++) {
1002 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
1003 printf("%s\n", buf1);
1004 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
1005 if (bcount != pcount) {
1006 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1009 if (strcmp(buf1, buf2)) {
1011 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1012 int_fmt[x], buf1, buf2);
1018 for (x = 0; ll_fmt[x] != NULL; x++) {
1019 for (y = 0; ll_nums[y] != 0; y++) {
1021 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1022 printf("%s\n", buf1);
1023 pcount = sprintf(buf2, ll_fmt[x], ll_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 ll_fmt[x], buf1, buf2);
1038 for (x = 0; s_fmt[x] != NULL; x++) {
1039 for (y = 0; s_nums[y] != 0; y++) {
1041 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1042 printf("%s\n", buf1);
1043 pcount = sprintf(buf2, s_fmt[x], s_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 s_fmt[x], buf1, buf2);
1058 for (x = 0; ls_fmt[x] != NULL; x++) {
1059 for (y = 0; ls_nums[y] != 0; y++) {
1061 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1062 printf("%s\n", buf1);
1063 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1064 if (bcount != pcount) {
1065 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1068 if (strcmp(buf1, buf2)) {
1070 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1071 ls_fmt[x], buf1, buf2);
1080 printf("%d tests failed out of %d.\n", fail, num);
1084 #endif /* TEST_PROGRAM */
1086 #endif /* USE_BSNPRINTF */