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 */
119 #define char_to_int(p) ((p)- '0')
121 #define MAX(p,q) (((p) >= (q)) ? (p) : (q))
124 You might ask why does Bacula have it's own printf routine? Well,
125 There are two reasons: 1. Here (as opposed to library routines), we
126 define %d and %ld to be 32 bit; %lld and %q to be 64 bit. 2. We
127 disable %n for security reasons.
130 int bsnprintf(char *str, int32_t size, const char *fmt, ...)
135 va_start(arg_ptr, fmt);
136 len = bvsnprintf(str, size, fmt, arg_ptr);
142 int bvsnprintf(char *buffer, int32_t maxlen, const char *format, va_list args)
159 state = DP_S_DEFAULT;
160 currlen = flags = cflags = min = 0;
165 while (state != DP_S_DONE) {
166 if ((ch == '\0') || (currlen >= maxlen)) {
206 if (isdigit((unsigned char)ch)) {
207 min = 10 * min + char_to_int(ch);
209 } else if (ch == '*') {
210 min = va_arg(args, int);
225 if (isdigit((unsigned char)ch)) {
228 max = 10 * max + char_to_int(ch);
230 } else if (ch == '*') {
231 max = va_arg(args, int);
248 } else if (ch == 'l') { /* It's a long long */
254 cflags = DP_C_LDOUBLE;
257 case 'q': /* same as long long */
270 if (cflags == DP_C_INT16) {
271 value = va_arg(args, int32_t);
272 } else if (cflags == DP_C_INT32) {
273 value = va_arg(args, int32_t);
274 } else if (cflags == DP_C_INT64) {
275 value = va_arg(args, int64_t);
277 value = va_arg(args, int);
279 currlen = fmtint(buffer, currlen, maxlen, value, 10, min, max, flags);
287 } else if (ch == 'x') {
289 } else if (ch == 'X') {
295 flags |= DP_F_UNSIGNED;
296 if (cflags == DP_C_INT16) {
297 value = va_arg(args, uint32_t);
298 } else if (cflags == DP_C_INT32) {
299 value = va_arg(args, uint32_t);
300 } else if (cflags == DP_C_INT64) {
301 value = va_arg(args, uint64_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 *);
342 currlen = fmtstr(buffer, currlen, maxlen, strvalue, flags, min, max);
344 /* %ls means to edit wide characters */
345 wstrvalue = va_arg(args, wchar_t *);
346 currlen = fmtwstr(buffer, currlen, maxlen, wstrvalue, flags, min, max);
350 flags |= DP_F_UNSIGNED;
351 if (sizeof(char *) == 4) {
352 value = va_arg(args, uint32_t);
353 } else if (sizeof(char *) == 8) {
354 value = va_arg(args, uint64_t);
356 value = 0; /* we have a problem */
358 currlen = fmtint(buffer, currlen, maxlen, value, 16, min, max, flags);
361 if (cflags == DP_C_INT16) {
363 num = va_arg(args, int16_t *);
364 #ifdef SECURITY_PROBLEM
367 } else if (cflags == DP_C_INT32) {
369 num = va_arg(args, int32_t *);
370 #ifdef SECURITY_PROBLEM
371 *num = (int32_t)currlen;
373 } else if (cflags == DP_C_INT64) {
375 num = va_arg(args, int64_t *);
376 #ifdef SECURITY_PROBLEM
377 *num = (int64_t)currlen;
381 num = va_arg(args, int32_t *);
382 #ifdef SECURITY_PROBLEM
383 *num = (int32_t)currlen;
391 /* not supported yet, treat as next char */
399 state = DP_S_DEFAULT;
400 flags = cflags = min = 0;
407 break; /* some picky compilers need this */
410 if (currlen < maxlen - 1) {
411 buffer[currlen] = '\0';
413 buffer[maxlen - 1] = '\0';
418 static int32_t fmtstr(char *buffer, int32_t currlen, int32_t maxlen,
419 const char *value, int flags, int min, int max)
421 int padlen, strln; /* amount to pad */
426 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
428 } else if (max < 0) {
434 strln = strlen(value);
436 strln = max; /* truncate to max */
438 padlen = min - strln;
442 if (flags & DP_F_MINUS) {
443 padlen = -padlen; /* Left Justify */
450 while (*value && (cnt < max)) {
462 static int32_t fmtwstr(char *buffer, int32_t currlen, int32_t maxlen,
463 const wchar_t *value, int flags, int min, int max)
465 int padlen, strln; /* amount to pad */
470 if (flags & DP_F_DOT && max < 0) { /* Max not specified */
472 } else if (max < 0) {
478 strln = wcslen(value);
480 strln = max; /* truncate to max */
482 padlen = min - strln;
486 if (flags & DP_F_MINUS) {
487 padlen = -padlen; /* Left Justify */
494 while (*value && (cnt < max)) {
496 ch = (*value++) & 0xff;
507 /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
509 static int32_t fmtint(char *buffer, int32_t currlen, int32_t maxlen,
510 int64_t value, int base, int min, int max, int flags)
516 int spadlen = 0; /* amount to space pad */
517 int zpadlen = 0; /* amount to zero pad */
519 const char *cvt_string;
527 if (!(flags & DP_F_UNSIGNED)) {
531 } else if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
533 } else if (flags & DP_F_SPACE) {
538 if (flags & DP_F_UP) {
539 caps = 1; /* Should characters be upper case? */
542 cvt_string = caps ? "0123456789ABCDEF" : "0123456789abcdef";
544 convert[place++] = cvt_string[uvalue % (unsigned)base];
545 uvalue = (uvalue / (unsigned)base);
546 } while (uvalue && (place < (int)sizeof(convert)));
547 if (place == (int)sizeof(convert)) {
552 zpadlen = max - place;
553 spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
558 if (flags & DP_F_ZERO) {
559 zpadlen = MAX(zpadlen, spadlen);
562 if (flags & DP_F_MINUS)
563 spadlen = -spadlen; /* Left Justifty */
565 #ifdef DEBUG_SNPRINTF
566 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
567 zpadlen, spadlen, min, max, place);
571 while (spadlen > 0) {
583 while (zpadlen > 0) {
589 /* Output digits backward giving correct order */
592 outch(convert[place]);
595 /* Left Justified spaces */
596 while (spadlen < 0) {
605 static LDOUBLE abs_val(LDOUBLE value)
607 LDOUBLE result = value;
615 static LDOUBLE pow10(int exp)
627 static int64_t round(LDOUBLE value)
631 intpart = (int64_t)value;
632 value = value - intpart;
639 static int32_t fmtfp(char *buffer, int32_t currlen, int32_t maxlen,
640 LDOUBLE fvalue, int min, int max, int flags)
654 extern char *fcvt(double value, int ndigit, int *decpt, int *sign);
658 int padlen = 0; /* amount to pad */
666 * AIX manpage says the default is 0, but Solaris says the default
667 * is 6, and sprintf on AIX defaults to 6
672 ufvalue = abs_val(fvalue);
676 else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
678 else if (flags & DP_F_SPACE)
683 caps = 1; /* Should characters be upper case? */
687 intpart = (int64_t)ufvalue;
690 * Sorry, we only support 9 digits past the decimal because of our
696 /* We "cheat" by converting the fractional part to integer by
697 * multiplying by a factor of 10
699 fracpart = round((pow10(max)) * (ufvalue - intpart));
701 if (fracpart >= pow10(max)) {
703 fracpart -= (int64_t)pow10(max);
706 #ifdef DEBUG_SNPRINTF
707 printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
708 (double)fvalue, intpart, fracpart, min, max);
711 /* Convert integer part */
712 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
714 iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
715 intpart = (intpart / 10);
716 } while (intpart && (iplace < (int)sizeof(iconvert)));
718 if (iplace == (int)sizeof(fconvert)) {
721 iconvert[iplace] = 0;
723 /* Convert fractional part */
724 cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
726 fconvert[fplace++] = cvt_str[fracpart % 10];
727 fracpart = (fracpart / 10);
728 } while (fracpart && (fplace < (int)sizeof(fconvert)));
730 if (fplace == (int)sizeof(fconvert)) {
733 fconvert[fplace] = 0;
734 #else /* use fcvt() */
739 result = fcvtl(ufvalue, max, &dec_pt, &sig);
741 result = fcvt(ufvalue, max, &dec_pt, &sig);
748 r_length = strlen(result);
752 * Fix broken fcvt implementation returns..
761 if (r_length < dec_pt)
772 fconvert[fplace++] = result[--r_length];
775 while ((dec_pt < 0) && (fplace < max)) {
776 fconvert[fplace++] = '0';
783 for (c = dec_pt; c; iconvert[iplace++] = result[--c]);
784 iconvert[iplace] = '\0';
789 for (c = (r_length - dec_pt); c; fconvert[fplace++] = result[--c]);
791 #endif /* HAVE_FCVT */
793 /* -1 for decimal point, another -1 if we are printing a sign */
794 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
795 zpadlen = max - fplace;
802 if (flags & DP_F_MINUS) {
803 padlen = -padlen; /* Left Justifty */
806 if ((flags & DP_F_ZERO) && (padlen > 0)) {
827 outch(iconvert[iplace]);
831 #ifdef DEBUG_SNPRINTF
832 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
836 * Decimal point. This should probably use locale to find the correct
843 outch(fconvert[fplace]);
847 while (zpadlen > 0) {
858 #endif /* FP_OUTPUT */
864 #define LONG_STRING 1024
867 int main(int argc, char *argv[])
869 char buf1[LONG_STRING];
870 char buf2[LONG_STRING];
873 const char *fp_fmt[] = {
889 double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
890 0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
893 const char *int_fmt[] = {
914 long int_nums[] = { -1, 134, 91340, 341, 0203, 0 };
916 const char *ll_fmt[] = {
928 int64_t ll_nums[] = { -1976, 789134567890LL, 91340, 34123, 0203, 0 };
930 const char *s_fmt[] = {
946 const char *s_nums[] = { "abc", "def", "ghi", "123", "4567", "a", "bb", "ccccccc", NULL};
948 const char *ls_fmt[] = {
964 const wchar_t *ls_nums[] = { L"abc", L"def", L"ghi", L"123", L"4567", L"a", L"bb", L"ccccccc", NULL};
972 printf("Testing snprintf format codes against system sprintf...\n");
975 for (x = 0; fp_fmt[x] != NULL; x++)
976 for (y = 0; fp_nums[y] != 0; y++) {
977 bsnprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
978 sprintf(buf2, fp_fmt[x], fp_nums[y]);
979 if (strcmp(buf1, buf2)) {
981 ("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
982 fp_fmt[x], buf1, buf2);
989 for (x = 0; int_fmt[x] != NULL; x++)
990 for (y = 0; int_nums[y] != 0; y++) {
992 bcount = bsnprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
993 printf("%s\n", buf1);
994 pcount = sprintf(buf2, int_fmt[x], int_nums[y]);
995 if (bcount != pcount) {
996 printf("bsnprintf count %d doesn't match sprintf count %d\n",
999 if (strcmp(buf1, buf2)) {
1001 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1002 int_fmt[x], buf1, buf2);
1008 for (x = 0; ll_fmt[x] != NULL; x++) {
1009 for (y = 0; ll_nums[y] != 0; y++) {
1011 bcount = bsnprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]);
1012 printf("%s\n", buf1);
1013 pcount = sprintf(buf2, ll_fmt[x], ll_nums[y]);
1014 if (bcount != pcount) {
1015 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1018 if (strcmp(buf1, buf2)) {
1020 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1021 ll_fmt[x], buf1, buf2);
1028 for (x = 0; s_fmt[x] != NULL; x++) {
1029 for (y = 0; s_nums[y] != 0; y++) {
1031 bcount = bsnprintf(buf1, sizeof(buf1), s_fmt[x], s_nums[y]);
1032 printf("%s\n", buf1);
1033 pcount = sprintf(buf2, s_fmt[x], s_nums[y]);
1034 if (bcount != pcount) {
1035 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1038 if (strcmp(buf1, buf2)) {
1040 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1041 s_fmt[x], buf1, buf2);
1048 for (x = 0; ls_fmt[x] != NULL; x++) {
1049 for (y = 0; ls_nums[y] != 0; y++) {
1051 bcount = bsnprintf(buf1, sizeof(buf1), ls_fmt[x], ls_nums[y]);
1052 printf("%s\n", buf1);
1053 pcount = sprintf(buf2, ls_fmt[x], ls_nums[y]);
1054 if (bcount != pcount) {
1055 printf("bsnprintf count %d doesn't match sprintf count %d\n",
1058 if (strcmp(buf1, buf2)) {
1060 ("bsnprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
1061 ls_fmt[x], buf1, buf2);
1070 printf("%d tests failed out of %d.\n", fail, num);
1074 #endif /* TEST_PROGRAM */
1076 #endif /* USE_BSNPRINTF */