Просмотр исходного кода

Added new environment macros, asprintf support, prep for new release

Ethan Galstad 18 лет назад
Родитель
Сommit
af326a7298
8 измененных файлов с 2137 добавлено и 13 удалено
  1. 3 0
      Changelog
  2. 590 1
      configure
  3. 57 0
      configure.in
  4. 14 2
      include/config.h.in
  5. 6 6
      include/dh.h
  6. 7 4
      src/Makefile.in
  7. 8 0
      src/nrpe.c
  8. 1452 0
      src/snprintf.c

+ 3 - 0
Changelog

@@ -7,6 +7,9 @@ NRPE Changelog
 ----------------
 - Fixed bug with --with-nrpe-group configure script option (Graham Collinson)
 - Fixed bug with check_disk thresholds in sample config file (Patric Wust)
+- Added NRPE_PROGRAMVERSION and NRPE_MULTILINESUPPORT environment variables
+  for scripts that need to detect NRPE version and capabilities (Gerhard Lausser)
+- Added asprintf() support for systems that are missing it (Samba team)
 
 
 

+ 590 - 1
configure

@@ -310,7 +310,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA INSTALL build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SET_MAKE CPP EGREP OTHERLIBS SOCKETLIBS LIBWRAPLIBS HAVE_SSL nrpe_user nrpe_group NRPE_INSTALL_OPTS nrpe_port nagios_user nagios_group NAGIOS_INSTALL_OPTS PERL LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA INSTALL build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT SET_MAKE CPP EGREP SNPRINTF_O OTHERLIBS SOCKETLIBS LIBWRAPLIBS HAVE_SSL nrpe_user nrpe_group NRPE_INSTALL_OPTS nrpe_port nagios_user nagios_group NAGIOS_INSTALL_OPTS PERL LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -5279,6 +5279,594 @@ _ACEOF
 fi
 
 
+echo "$as_me:$LINENO: checking for va_copy" >&5
+echo $ECHO_N "checking for va_copy... $ECHO_C" >&6
+if test "${ac_cv_HAVE_VA_COPY+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+va_list ap1,ap2;
+int
+main ()
+{
+va_copy(ap1,ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_HAVE_VA_COPY=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_HAVE_VA_COPY=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_HAVE_VA_COPY" >&5
+echo "${ECHO_T}$ac_cv_HAVE_VA_COPY" >&6
+if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_VA_COPY 1
+_ACEOF
+
+else
+    echo "$as_me:$LINENO: checking for __va_copy" >&5
+echo $ECHO_N "checking for __va_copy... $ECHO_C" >&6
+if test "${ac_cv_HAVE___VA_COPY+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+    va_list ap1,ap2;
+int
+main ()
+{
+__va_copy(ap1,ap2);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_HAVE___VA_COPY=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_HAVE___VA_COPY=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_HAVE___VA_COPY" >&5
+echo "${ECHO_T}$ac_cv_HAVE___VA_COPY" >&6
+    if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___VA_COPY 1
+_ACEOF
+
+    fi
+fi
+
+echo "$as_me:$LINENO: checking for vsnprintf" >&5
+echo $ECHO_N "checking for vsnprintf... $ECHO_C" >&6
+if test "${ac_cv_func_vsnprintf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define vsnprintf to an innocuous variant, in case <limits.h> declares vsnprintf.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define vsnprintf innocuous_vsnprintf
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vsnprintf (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef vsnprintf
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char vsnprintf ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vsnprintf) || defined (__stub___vsnprintf)
+choke me
+#else
+char (*f) () = vsnprintf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != vsnprintf;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_vsnprintf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_vsnprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_vsnprintf" >&5
+echo "${ECHO_T}$ac_cv_func_vsnprintf" >&6
+if test $ac_cv_func_vsnprintf = yes; then
+  :
+else
+  SNPRINTF_O=./snprintf.o
+fi
+
+echo "$as_me:$LINENO: checking for snprintf" >&5
+echo $ECHO_N "checking for snprintf... $ECHO_C" >&6
+if test "${ac_cv_func_snprintf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define snprintf to an innocuous variant, in case <limits.h> declares snprintf.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define snprintf innocuous_snprintf
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char snprintf (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef snprintf
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char snprintf ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_snprintf) || defined (__stub___snprintf)
+choke me
+#else
+char (*f) () = snprintf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != snprintf;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_snprintf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_snprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_snprintf" >&5
+echo "${ECHO_T}$ac_cv_func_snprintf" >&6
+if test $ac_cv_func_snprintf = yes; then
+  :
+else
+  SNPRINTF_O=./snprintf.o
+fi
+
+echo "$as_me:$LINENO: checking for asprintf" >&5
+echo $ECHO_N "checking for asprintf... $ECHO_C" >&6
+if test "${ac_cv_func_asprintf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define asprintf to an innocuous variant, in case <limits.h> declares asprintf.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define asprintf innocuous_asprintf
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char asprintf (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef asprintf
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char asprintf ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_asprintf) || defined (__stub___asprintf)
+choke me
+#else
+char (*f) () = asprintf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != asprintf;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_asprintf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_asprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_asprintf" >&5
+echo "${ECHO_T}$ac_cv_func_asprintf" >&6
+if test $ac_cv_func_asprintf = yes; then
+  :
+else
+  SNPRINTF_O=./snprintf.o
+fi
+
+echo "$as_me:$LINENO: checking for vasprintf" >&5
+echo $ECHO_N "checking for vasprintf... $ECHO_C" >&6
+if test "${ac_cv_func_vasprintf+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define vasprintf to an innocuous variant, in case <limits.h> declares vasprintf.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define vasprintf innocuous_vasprintf
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vasprintf (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef vasprintf
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char vasprintf ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vasprintf) || defined (__stub___vasprintf)
+choke me
+#else
+char (*f) () = vasprintf;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != vasprintf;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_vasprintf=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_vasprintf=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_vasprintf" >&5
+echo "${ECHO_T}$ac_cv_func_vasprintf" >&6
+if test $ac_cv_func_vasprintf = yes; then
+  :
+else
+  SNPRINTF_O=./snprintf.o
+fi
+
+
+echo "$as_me:$LINENO: checking for C99 vsnprintf" >&5
+echo $ECHO_N "checking for C99 vsnprintf... $ECHO_C" >&6
+if test "${ac_cv_HAVE_C99_VSNPRINTF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test "$cross_compiling" = yes; then
+  ac_cv_HAVE_C99_VSNPRINTF=cross
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <stdarg.h>
+void foo(const char *format, ...) {
+       va_list ap;
+       int len;
+       char buf[5];
+
+       va_start(ap, format);
+       len = vsnprintf(buf, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       va_start(ap, format);
+       len = vsnprintf(0, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
+
+       exit(0);
+}
+main() { foo("hello"); }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_HAVE_C99_VSNPRINTF=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_HAVE_C99_VSNPRINTF=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_HAVE_C99_VSNPRINTF" >&5
+echo "${ECHO_T}$ac_cv_HAVE_C99_VSNPRINTF" >&6
+if test x"$ac_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_C99_VSNPRINTF 1
+_ACEOF
+
+fi
+
+
+
 
 for ac_func in getopt_long
 do
@@ -6796,6 +7384,7 @@ s,@OBJEXT@,$OBJEXT,;t t
 s,@SET_MAKE@,$SET_MAKE,;t t
 s,@CPP@,$CPP,;t t
 s,@EGREP@,$EGREP,;t t
+s,@SNPRINTF_O@,$SNPRINTF_O,;t t
 s,@OTHERLIBS@,$OTHERLIBS,;t t
 s,@SOCKETLIBS@,$SOCKETLIBS,;t t
 s,@LIBWRAPLIBS@,$LIBWRAPLIBS,;t t

+ 57 - 0
configure.in

@@ -82,6 +82,63 @@ if test "$ac_cv_type_int32_t" = no ; then
 fi
 
 
+dnl Check for asprintf() and friends...
+AC_CACHE_CHECK([for va_copy],ac_cv_HAVE_VA_COPY,[
+AC_TRY_LINK([#include <stdarg.h>
+va_list ap1,ap2;], [va_copy(ap1,ap2);],
+ac_cv_HAVE_VA_COPY=yes,
+ac_cv_HAVE_VA_COPY=no)])
+if test x"$ac_cv_HAVE_VA_COPY" = x"yes"; then
+    AC_DEFINE(HAVE_VA_COPY,1,[Whether va_copy() is available])
+else    
+    AC_CACHE_CHECK([for __va_copy],ac_cv_HAVE___VA_COPY,[
+    AC_TRY_LINK([#include <stdarg.h>
+    va_list ap1,ap2;], [__va_copy(ap1,ap2);],
+    ac_cv_HAVE___VA_COPY=yes,
+    ac_cv_HAVE___VA_COPY=no)])
+    if test x"$ac_cv_HAVE___VA_COPY" = x"yes"; then
+        AC_DEFINE(HAVE___VA_COPY,1,[Whether __va_copy() is available])
+    fi
+fi
+
+AC_CHECK_FUNC(vsnprintf,,SNPRINTF_O=./snprintf.o)
+AC_CHECK_FUNC(snprintf,,SNPRINTF_O=./snprintf.o)
+AC_CHECK_FUNC(asprintf,,SNPRINTF_O=./snprintf.o)
+AC_CHECK_FUNC(vasprintf,,SNPRINTF_O=./snprintf.o)
+
+AC_CACHE_CHECK([for C99 vsnprintf],ac_cv_HAVE_C99_VSNPRINTF,[
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <stdarg.h>
+void foo(const char *format, ...) { 
+       va_list ap;
+       int len;
+       char buf[5];
+
+       va_start(ap, format);
+       len = vsnprintf(buf, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       va_start(ap, format);
+       len = vsnprintf(0, 0, format, ap);
+       va_end(ap);
+       if (len != 5) exit(1);
+
+       if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1);
+
+       exit(0);
+}
+main() { foo("hello"); }
+],
+ac_cv_HAVE_C99_VSNPRINTF=yes,ac_cv_HAVE_C99_VSNPRINTF=no,ac_cv_HAVE_C99_VSNPRINTF=cross)])
+if test x"$ac_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
+    AC_DEFINE(HAVE_C99_VSNPRINTF,1,[Define if system has C99 compatible vsnprintf])
+fi
+
+dnl AC_CHECK_FUNC(snprintf,AC_DEFINE(HAVE_SNPRINTF),SNPRINTF_O=./snprintf.o)
+AC_SUBST(SNPRINTF_O)
+
 dnl Check for getopt_long (Solaris)
 AC_CHECK_FUNCS([getopt_long],,AC_CHECK_LIB([iberty],[getopt_long],OTHERLIBS="$OTHERLIBS -liberty"))
 AC_SUBST(OTHERLIBS)

+ 14 - 2
include/config.h.in

@@ -1,8 +1,8 @@
 /************************************************************************
  *
  * NRPE Common Header File
- * Copyright (c) 1999-2006 Ethan Galstad (nagios@nagios.org)
- * Last Modified: 12-11-2006
+ * Copyright (c) 1999-2007 Ethan Galstad (nagios@nagios.org)
+ * Last Modified: 08-13-2007
  *
  * License:
  *
@@ -84,6 +84,18 @@ typedef int int32_t;
 #endif
 
 
+/***** ASPRINTF() AND FRIENDS *****/
+
+#undef HAVE_VSNPRINTF
+#undef HAVE_SNPRINTF
+#undef HAVE_ASPRINTF
+#undef HAVE_VASPRINTF
+#undef HAVE_C99_VSNPRINTF
+#undef HAVE_VA_COPY
+#undef HAVE___VA_COPY
+
+
+
 #define SOCKET_SIZE_TYPE ""
 #define GETGROUPS_T ""
 #define RETSIGTYPE ""

+ 6 - 6
include/dh.h

@@ -4,12 +4,12 @@
 DH *get_dh512()
 	{
 	static unsigned char dh512_p[]={
-		0xA3,0x3E,0x3A,0xED,0x7B,0xCB,0x7D,0x95,0x34,0xAF,0x60,0xC8,
-		0x0D,0x95,0x65,0xC8,0x1B,0x92,0x01,0x78,0x4B,0xDA,0xB9,0x3C,
-		0x62,0xD4,0x0E,0x92,0x22,0x48,0xE6,0x9F,0x4E,0xBC,0x27,0x8A,
-		0x00,0x2A,0x67,0x80,0xC7,0xDE,0xCA,0x79,0x78,0x89,0x5A,0xE8,
-		0x06,0x70,0xD7,0xF1,0x14,0x53,0x3B,0x4E,0x40,0x51,0xD8,0x56,
-		0x4E,0xA6,0x2F,0x53,
+		0xBD,0x3F,0xF2,0xBB,0x91,0x8A,0x6D,0x31,0xF8,0xD2,0xBE,0xA1,
+		0x43,0x40,0x5D,0xAD,0x66,0xC6,0x83,0x16,0xC7,0x7F,0xD3,0x13,
+		0xC6,0x15,0xB0,0x4B,0x98,0x8E,0xF1,0x65,0x4E,0x30,0x24,0x27,
+		0x6D,0xCA,0x0D,0x23,0x52,0x19,0x2E,0x56,0xFA,0x3F,0x53,0x6A,
+		0x58,0x08,0xB8,0x6A,0x30,0x14,0xF2,0x65,0x12,0x4F,0xD8,0x74,
+		0x1E,0x82,0x4F,0x3B,
 		};
 	static unsigned char dh512_g[]={
 		0x02,

+ 7 - 4
src/Makefile.in

@@ -1,7 +1,7 @@
 ###############################
 # Makefile for NRPE
 #
-# Last Modified: 05-10-2007
+# Last Modified: 08-13-2007
 ###############################
 
 
@@ -27,11 +27,14 @@ INSTALL=@INSTALL@
 NAGIOS_INSTALL_OPTS=@NAGIOS_INSTALL_OPTS@
 NRPE_INSTALL_OPTS=@NRPE_INSTALL_OPTS@
 
+# Generated automatically from configure script
+SNPRINTF_O=@SNPRINTF_O@
+
 
 all: nrpe check_nrpe
 
-nrpe: nrpe.c utils.c $(SRC_INCLUDE)/nrpe.h $(SRC_INCLUDE)/utils.h $(SRC_INCLUDE)/common.h $(SRC_INCLUDE)/config.h
-	$(CC) $(CFLAGS) -o $@ nrpe.c utils.c $(LDFLAGS) $(SOCKETLIBS) $(LIBWRAPLIBS) $(OTHERLIBS)
+nrpe: nrpe.c utils.c $(SRC_INCLUDE)/nrpe.h $(SRC_INCLUDE)/utils.h $(SRC_INCLUDE)/common.h $(SRC_INCLUDE)/config.h $(SNPRINTF_O)
+	$(CC) $(CFLAGS) -o $@ nrpe.c utils.c $(LDFLAGS) $(SOCKETLIBS) $(LIBWRAPLIBS) $(SNPRINTF_O) $(OTHERLIBS)
 
 check_nrpe: check_nrpe.c utils.c $(SRC_INCLUDE)/utils.h $(SRC_INCLUDE)/common.h $(SRC_INCLUDE)/config.h
 	$(CC) $(CFLAGS) -o $@ check_nrpe.c utils.c $(LDFLAGS) $(SOCKETLIBS) $(OTHERLIBS)
@@ -49,7 +52,7 @@ install-daemon:
 	$(INSTALL) -m 775 $(NRPE_INSTALL_OPTS) nrpe $(DESTDIR)$(BINDIR)
 
 clean:
-	rm -f core nrpe check_nrpe
+	rm -f core nrpe check_nrpe $(SNPRINTF_O)
 	rm -f *~ */*~
 
 distclean: clean

+ 8 - 0
src/nrpe.c

@@ -85,12 +85,20 @@ int main(int argc, char **argv){
 	int result=OK;
 	int x;
 	char buffer[MAX_INPUT_BUFFER];
+	char *env_string=NULL;
 #ifdef HAVE_SSL
 	DH *dh;
 	char seedfile[FILENAME_MAX];
 	int i,c;
 #endif
 
+	/* set some environment variables */
+	asprintf(&env_string,"NRPE_MULTILINESUPPORT=1");
+	putenv(env_string);
+	asprintf(&env_string,"NRPE_PROGRAMVERSION=%s",PROGRAM_VERSION);
+	putenv(env_string);
+
+	/* process command-line args */
 	result=process_arguments(argc,argv);
 
         if(result!=OK || show_help==TRUE || show_license==TRUE || show_version==TRUE){

+ 1452 - 0
src/snprintf.c

@@ -0,0 +1,1452 @@
+/*
+ * NOTE: If you change this file, please merge it into rsync, samba, etc.
+ */
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh.  This sort of thing is always nasty do deal with.  Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length.  This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
+ *  This was ugly.  It is still ugly.  I opted out of floating point
+ *  numbers, but the formatter understands just about everything
+ *  from the normal C string format, at least as far as I can tell from
+ *  the Solaris 2.5 printf(3S) man page.
+ *
+ *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
+ *    Ok, added some minimal floating point support, which means this
+ *    probably requires libm on most operating systems.  Don't yet
+ *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
+ *    was pretty badly broken, it just wasn't being exercised in ways
+ *    which showed it, so that's been fixed.  Also, formated the code
+ *    to mutt conventions, and removed dead code left over from the
+ *    original.  Also, there is now a builtin-test, just compile with:
+ *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ *    and run snprintf for results.
+ * 
+ *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ *    The original code assumed that both snprintf() and vsnprintf() were
+ *    missing.  Some systems only have snprintf() but not vsnprintf(), so
+ *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ *  Andrew Tridgell (tridge@samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
+ * actually print args for %g and %e
+ * 
+ * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally.  Fixes AIX and Solaris builds.
+ * 
+ * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ * 
+ * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
+ * Fix usage of va_list passed as an arg.  Use __va_copy before using it
+ * when it exists.
+ * 
+ * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ *    Remove NO_CONFIG_H so that the test case can be built within a source
+ *    tree with less trouble.
+ *    Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ *    if the C library has some snprintf functions already.
+ *
+ * Darren Tucker (dtucker@zip.com.au) 2005
+ *    Fix bug allowing read overruns of the source string with "%.*s"
+ *    Usually harmless unless the read runs outside the process' allocation
+ *    (eg if your malloc does guard pages) in which case it will segfault.
+ *    From OpenSSH.  Also added test for same.
+ *
+ * Simo Sorce (idra@samba.org) Jan 2006
+ * 
+ *    Add support for position independent parameters 
+ *    fix fmtstr now it conforms to sprintf wrt min.max
+ *
+ **************************************************************/
+
+#ifndef NO_CONFIG_H
+/* 08/13/2007 EG changed path to config.h to match NRPE distro */
+#include "../include/config.h"
+#else
+#define NULL 0
+#endif 
+
+#ifdef TEST_SNPRINTF /* need math library headers for testing */
+
+/* In test mode, we pretend that this system doesn't have any snprintf
+ * functions, regardless of what config.h says. */
+#  undef HAVE_SNPRINTF
+#  undef HAVE_VSNPRINTF
+#  undef HAVE_C99_VSNPRINTF
+#  undef HAVE_ASPRINTF
+#  undef HAVE_VASPRINTF
+#  include <math.h>
+#endif /* TEST_SNPRINTF */
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#include <sys/types.h>
+#include <stdarg.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF)
+/* only include stdio.h if we are not re-defining snprintf or vsnprintf */
+#include <stdio.h>
+ /* make the compiler happy with an empty file */
+ void dummy_snprintf(void);
+ void dummy_snprintf(void) {} 
+#endif /* HAVE_SNPRINTF, etc */
+
+#ifdef HAVE_LONG_DOUBLE
+#define LDOUBLE long double
+#else
+#define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+#define LLONG long long
+#else
+#define LLONG long
+#endif
+
+#ifndef VA_COPY
+#ifdef HAVE_VA_COPY
+#define VA_COPY(dest, src) va_copy(dest, src)
+#else
+#ifdef HAVE___VA_COPY
+#define VA_COPY(dest, src) __va_copy(dest, src)
+#else
+#define VA_COPY(dest, src) (dest) = (src)
+#endif
+#endif
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_CHAR    1
+#define DP_C_SHORT   2
+#define DP_C_LONG    3
+#define DP_C_LDOUBLE 4
+#define DP_C_LLONG   5
+
+/* Chunk types */
+#define CNK_FMT_STR 0
+#define CNK_INT     1
+#define CNK_OCTAL   2
+#define CNK_UINT    3
+#define CNK_HEX     4
+#define CNK_FLOAT   5
+#define CNK_CHAR    6
+#define CNK_STRING  7
+#define CNK_PTR     8
+#define CNK_NUM     9
+#define CNK_PRCNT   10
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+#define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+/* yes this really must be a ||. Don't muck with this (tridge) */
+#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+
+struct pr_chunk {
+	int type; /* chunk type */
+	int num; /* parameter number */
+	int min; 
+	int max;
+	int flags;
+	int cflags;
+	int start;
+	int len;
+	LLONG value;
+	LDOUBLE fvalue;
+	char *strvalue;
+	void *pnum;
+	struct pr_chunk *min_star;
+	struct pr_chunk *max_star;
+	struct pr_chunk *next;
+};
+
+struct pr_chunk_x {
+	struct pr_chunk **chunks;
+	int num;
+};
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format, 
+		   va_list args_in);
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max);
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags);
+static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags);
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+static struct pr_chunk *new_chunk(void);
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+				int max_num, struct pr_chunk *chunk);
+
+static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+	char ch;
+	int state;
+	int pflag;
+	int pnum;
+	int pfirst;
+	size_t currlen;
+	va_list args;
+	const char *base;
+	struct pr_chunk *chunks = NULL;
+	struct pr_chunk *cnk = NULL;
+	struct pr_chunk_x *clist = NULL;
+	int max_pos;
+	size_t ret = -1;
+
+	VA_COPY(args, args_in);
+
+	state = DP_S_DEFAULT;
+	pfirst = 1;
+	pflag = 0;
+	pnum = 0;
+
+	max_pos = 0;
+	base = format;
+	ch = *format++;
+	
+	/* retrieve the string structure as chunks */
+	while (state != DP_S_DONE) {
+		if (ch == '\0') 
+			state = DP_S_DONE;
+
+		switch(state) {
+		case DP_S_DEFAULT:
+			
+			if (cnk) {
+				cnk->next = new_chunk();
+				cnk = cnk->next;
+			} else {
+				cnk = new_chunk();
+			}
+			if (!cnk) goto done;
+			if (!chunks) chunks = cnk;
+			
+			if (ch == '%') {
+				state = DP_S_FLAGS;
+				ch = *format++;
+			} else {
+				cnk->type = CNK_FMT_STR;
+				cnk->start = format - base -1;
+				while ((ch != '\0') && (ch != '%')) ch = *format++;
+				cnk->len = format - base - cnk->start -1;
+			}
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				cnk->flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				cnk->flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				cnk->flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				cnk->flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				cnk->flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			case 'I':
+				/* internationalization not supported yet */
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char)ch)) {
+				cnk->min = 10 * cnk->min + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '$') {
+				if (!pfirst && !pflag) {
+					/* parameters must be all positioned or none */
+					goto done;
+				}
+				if (pfirst) {
+					pfirst = 0;
+					pflag = 1;
+				}
+				if (cnk->min == 0) /* what ?? */
+					goto done;
+				cnk->num = cnk->min;
+				cnk->min = 0;
+				ch = *format++;
+			} else if (ch == '*') {
+				if (pfirst) pfirst = 0;
+				cnk->min_star = new_chunk();
+				if (!cnk->min_star) /* out of memory :-( */
+					goto done;
+				cnk->min_star->type = CNK_INT;
+				if (pflag) {
+					int num;
+					ch = *format++;
+					if (!isdigit((unsigned char)ch)) {
+						/* parameters must be all positioned or none */
+						goto done;
+					}
+					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+						num = 10 * num + char_to_int(ch);
+					}
+					cnk->min_star->num = num;
+					if (ch != '$') /* what ?? */
+						goto done;
+				} else {
+					cnk->min_star->num = ++pnum;
+				}
+				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star);
+				if (max_pos == 0) /* out of memory :-( */
+					goto done;
+				ch = *format++;
+				state = DP_S_DOT;
+			} else {
+				if (pfirst) pfirst = 0;
+				state = DP_S_DOT;
+			}
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else { 
+				state = DP_S_MOD;
+			}
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char)ch)) {
+				if (cnk->max < 0)
+					cnk->max = 0;
+				cnk->max = 10 * cnk->max + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '$') {
+				if (!pfirst && !pflag) {
+					/* parameters must be all positioned or none */
+					goto done;
+				}
+				if (cnk->max <= 0) /* what ?? */
+					goto done;
+				cnk->num = cnk->max;
+				cnk->max = -1;
+				ch = *format++;
+			} else if (ch == '*') {
+				cnk->max_star = new_chunk();
+				if (!cnk->max_star) /* out of memory :-( */
+					goto done;
+				cnk->max_star->type = CNK_INT;
+				if (pflag) {
+					int num;
+					ch = *format++;
+					if (!isdigit((unsigned char)ch)) {
+						/* parameters must be all positioned or none */
+						goto done;
+					}
+					for (num = 0; isdigit((unsigned char)ch); ch = *format++) {
+						num = 10 * num + char_to_int(ch);
+					}
+					cnk->max_star->num = num;
+					if (ch != '$') /* what ?? */
+						goto done;
+				} else {
+					cnk->max_star->num = ++pnum;
+				}
+				max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star);
+				if (max_pos == 0) /* out of memory :-( */
+					goto done;
+
+				ch = *format++;
+				state = DP_S_MOD;
+			} else {
+				state = DP_S_MOD;
+			}
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cnk->cflags = DP_C_SHORT;
+				ch = *format++;
+				if (ch == 'h') {
+					cnk->cflags = DP_C_CHAR;
+					ch = *format++;
+				}
+				break;
+			case 'l':
+				cnk->cflags = DP_C_LONG;
+				ch = *format++;
+				if (ch == 'l') {	/* It's a long long */
+					cnk->cflags = DP_C_LLONG;
+					ch = *format++;
+				}
+				break;
+			case 'L':
+				cnk->cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			if (cnk->num == 0) cnk->num = ++pnum;
+			max_pos = add_cnk_list_entry(&clist, max_pos, cnk);
+			if (max_pos == 0) /* out of memory :-( */
+				goto done;
+			
+			switch (ch) {
+			case 'd':
+			case 'i':
+				cnk->type = CNK_INT;
+				break;
+			case 'o':
+				cnk->type = CNK_OCTAL;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'u':
+				cnk->type = CNK_UINT;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'X':
+				cnk->flags |= DP_F_UP;
+			case 'x':
+				cnk->type = CNK_HEX;
+				cnk->flags |= DP_F_UNSIGNED;
+				break;
+			case 'A':
+				/* hex float not supported yet */
+			case 'E':
+			case 'G':
+			case 'F':
+				cnk->flags |= DP_F_UP;
+			case 'a':
+				/* hex float not supported yet */
+			case 'e':
+			case 'f':
+			case 'g':
+				cnk->type = CNK_FLOAT;
+				break;
+			case 'c':
+				cnk->type = CNK_CHAR;
+				break;
+			case 's':
+				cnk->type = CNK_STRING;
+				break;
+			case 'p':
+				cnk->type = CNK_PTR;
+				break;
+			case 'n':
+				cnk->type = CNK_NUM;
+				break;
+			case '%':
+				cnk->type = CNK_PRCNT;
+				break;
+			default:
+				/* Unknown, bail out*/
+				goto done;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			break;
+		case DP_S_DONE:
+			break;
+		default:
+			/* hmm? */
+			break; /* some picky compilers need this */
+		}
+	}
+
+	/* retieve the format arguments */
+	for (pnum = 0; pnum < max_pos; pnum++) {
+		int i;
+
+		if (clist[pnum].num == 0) {
+			/* ignoring a parameter should not be permitted
+			 * all parameters must be matched at least once
+			 * BUT seem some system ignore this rule ...
+			 * at least my glibc based system does --SSS
+			 */
+#ifdef DEBUG_SNPRINTF
+			printf("parameter at position %d not used\n", pnum+1);
+#endif
+			/* eat the parameter */
+			va_arg (args, int);
+			continue;
+		}
+		for (i = 1; i < clist[pnum].num; i++) {
+			if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) {
+				/* nooo noo no!
+				 * all the references to a parameter
+				 * must be of the same type
+				 */
+				goto done;
+			}
+		}
+		cnk = clist[pnum].chunks[0];
+		switch (cnk->type) {
+		case CNK_INT:
+			if (cnk->cflags == DP_C_SHORT) 
+				cnk->value = va_arg (args, int);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->value = va_arg (args, long int);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->value = va_arg (args, LLONG);
+			else
+				cnk->value = va_arg (args, int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_OCTAL:
+		case CNK_UINT:
+		case CNK_HEX:
+			if (cnk->cflags == DP_C_SHORT)
+				cnk->value = va_arg (args, unsigned int);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->value = (long)va_arg (args, unsigned long int);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->value = (LLONG)va_arg (args, unsigned LLONG);
+			else
+				cnk->value = (long)va_arg (args, unsigned int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_FLOAT:
+			if (cnk->cflags == DP_C_LDOUBLE)
+				cnk->fvalue = va_arg (args, LDOUBLE);
+			else
+				cnk->fvalue = va_arg (args, double);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->fvalue = cnk->fvalue;
+			}
+			break;
+
+		case CNK_CHAR:
+			cnk->value = va_arg (args, int);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->value = cnk->value;
+			}
+			break;
+
+		case CNK_STRING:
+			cnk->strvalue = va_arg (args, char *);
+			if (!cnk->strvalue) cnk->strvalue = "(NULL)";
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+			}
+			break;
+
+		case CNK_PTR:
+			cnk->strvalue = va_arg (args, void *);
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->strvalue = cnk->strvalue;
+			}
+			break;
+
+		case CNK_NUM:
+			if (cnk->cflags == DP_C_CHAR)
+				cnk->pnum = va_arg (args, char *);
+			else if (cnk->cflags == DP_C_SHORT)
+				cnk->pnum = va_arg (args, short int *);
+			else if (cnk->cflags == DP_C_LONG)
+				cnk->pnum = va_arg (args, long int *);
+			else if (cnk->cflags == DP_C_LLONG)
+				cnk->pnum = va_arg (args, LLONG *);
+			else
+				cnk->pnum = va_arg (args, int *);
+
+			for (i = 1; i < clist[pnum].num; i++) {
+				clist[pnum].chunks[i]->pnum = cnk->pnum;
+			}
+			break;
+
+		case CNK_PRCNT:
+			break;
+
+		default:
+			/* what ?? */
+			goto done;
+		}
+	}
+	/* print out the actual string from chunks */
+	currlen = 0;
+	cnk = chunks;
+	while (cnk) {
+		int len, min, max;
+
+		if (cnk->min_star) min = cnk->min_star->value;
+		else min = cnk->min;
+		if (cnk->max_star) max = cnk->max_star->value;
+		else max = cnk->max;
+
+		switch (cnk->type) {
+
+		case CNK_FMT_STR:
+			if (maxlen != 0 && maxlen > currlen) {
+				if (maxlen > (currlen + cnk->len)) len = cnk->len;
+				else len = maxlen - currlen;
+
+				memcpy(&(buffer[currlen]), &(base[cnk->start]), len);
+			}
+			currlen += cnk->len;
+				
+			break;
+
+		case CNK_INT:
+		case CNK_UINT:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags);
+			break;
+
+		case CNK_OCTAL:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags);
+			break;
+
+		case CNK_HEX:
+			fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags);
+			break;
+
+		case CNK_FLOAT:
+			fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags);
+			break;
+
+		case CNK_CHAR:
+			dopr_outch (buffer, &currlen, maxlen, cnk->value);
+			break;
+
+		case CNK_STRING:
+			if (max == -1) {
+				max = strlen(cnk->strvalue);
+			}
+			fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max);
+			break;
+
+		case CNK_PTR:
+			fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags);
+			break;
+
+		case CNK_NUM:
+			if (cnk->cflags == DP_C_CHAR)
+				*((char *)(cnk->pnum)) = (char)currlen;
+			else if (cnk->cflags == DP_C_SHORT)
+				*((short int *)(cnk->pnum)) = (short int)currlen;
+			else if (cnk->cflags == DP_C_LONG)
+				*((long int *)(cnk->pnum)) = (long int)currlen;
+			else if (cnk->cflags == DP_C_LLONG)
+				*((LLONG *)(cnk->pnum)) = (LLONG)currlen;
+			else
+				*((int *)(cnk->pnum)) = (int)currlen;
+			break;
+
+		case CNK_PRCNT:
+			dopr_outch (buffer, &currlen, maxlen, '%');
+			break;
+
+		default:
+			/* what ?? */
+			goto done;
+		}
+		cnk = cnk->next;
+	}
+	if (maxlen != 0) {
+		if (currlen < maxlen - 1) 
+			buffer[currlen] = '\0';
+		else if (maxlen > 0) 
+			buffer[maxlen - 1] = '\0';
+	}
+	ret = currlen;
+
+done:
+	while (chunks) {
+		cnk = chunks->next;
+		free(chunks);
+		chunks = cnk;
+	}
+	if (clist) {
+		for (pnum = 0; pnum < max_pos; pnum++) {
+			if (clist[pnum].chunks) free(clist[pnum].chunks);
+		}
+		free(clist);
+	}
+	return ret;
+}
+
+static void fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+		    char *value, int flags, int min, int max)
+{
+	int padlen, strln;     /* amount to pad */
+	int cnt = 0;
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+	if (value == 0) {
+		value = "<NULL>";
+	}
+
+	for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */
+	padlen = min - strln;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justify */
+	
+	while (padlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch (buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while (padlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
+		    long value, int base, int min, int max, int flags)
+{
+	int signvalue = 0;
+	unsigned long uvalue;
+	char convert[20];
+	int place = 0;
+	int spadlen = 0; /* amount to space pad */
+	int zpadlen = 0; /* amount to zero pad */
+	int caps = 0;
+	
+	if (max < 0)
+		max = 0;
+	
+	uvalue = value;
+	
+	if(!(flags & DP_F_UNSIGNED)) {
+		if( value < 0 ) {
+			signvalue = '-';
+			uvalue = -value;
+		} else {
+			if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+				signvalue = '+';
+			else if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
+	}
+  
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+
+	do {
+		convert[place++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")
+			[uvalue % (unsigned)base  ];
+		uvalue = (uvalue / (unsigned)base );
+	} while(uvalue && (place < 20));
+	if (place == 20) place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0) zpadlen = 0;
+	if (spadlen < 0) spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = MAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS) 
+		spadlen = -spadlen; /* Left Justifty */
+
+#ifdef DEBUG_SNPRINTF
+	printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+	       zpadlen, spadlen, min, max, place);
+#endif
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue) 
+		dopr_outch (buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+
+	/* Digits */
+	while (place > 0) 
+		dopr_outch (buffer, currlen, maxlen, convert[--place]);
+  
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+	LDOUBLE result = value;
+
+	if (value < 0)
+		result = -value;
+	
+	return result;
+}
+
+static LDOUBLE POW10(int exp)
+{
+	LDOUBLE result = 1;
+	
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+  
+	return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+	LLONG intpart;
+
+	intpart = (LLONG)value;
+	value = value - intpart;
+	if (value >= 0.5) intpart++;
+	
+	return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+	int i;
+	long l;
+	double x = x0;
+	double f = 1.0;
+
+	for (i=0;i<100;i++) {
+		l = (long)x;
+		if (l <= (x+1) && l >= (x-1)) break;
+		x *= 0.1;
+		f *= 10.0;
+	}
+
+	if (i == 100) {
+		/* yikes! the number is beyond what we can handle. What do we do? */
+		(*iptr) = 0;
+		return 0;
+	}
+
+	if (i != 0) {
+		double i2;
+		double ret;
+
+		ret = my_modf(x0-l*f, &i2);
+		(*iptr) = l*f + i2;
+		return ret;
+	} 
+
+	(*iptr) = l;
+	return x - (*iptr);
+}
+
+
+static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+		   LDOUBLE fvalue, int min, int max, int flags)
+{
+	int signvalue = 0;
+	double ufvalue;
+	char iconvert[311];
+	char fconvert[311];
+	int iplace = 0;
+	int fplace = 0;
+	int padlen = 0; /* amount to pad */
+	int zpadlen = 0; 
+	int caps = 0;
+	int idx;
+	double intpart;
+	double fracpart;
+	double temp;
+  
+	/* 
+	 * AIX manpage says the default is 0, but Solaris says the default
+	 * is 6, and sprintf on AIX defaults to 6
+	 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val (fvalue);
+
+	if (fvalue < 0) {
+		signvalue = '-';
+	} else {
+		if (flags & DP_F_PLUS) { /* Do a sign (+/i) */
+			signvalue = '+';
+		} else {
+			if (flags & DP_F_SPACE)
+				signvalue = ' ';
+		}
+	}
+
+#if 0
+	if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+	 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+	/* 
+	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * conversion method
+	 */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10
+	 */
+
+	temp = ufvalue;
+	my_modf(temp, &intpart);
+
+	fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+	
+	if (fracpart >= POW10(max)) {
+		intpart++;
+		fracpart -= POW10(max);
+	}
+
+
+	/* Convert integer part */
+	do {
+		temp = intpart*0.1;
+		my_modf(temp, &intpart);
+		idx = (int) ((temp -intpart +0.05)* 10.0);
+		/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+		/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+		iconvert[iplace++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+	} while (intpart && (iplace < 311));
+	if (iplace == 311) iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	if (fracpart)
+	{
+		do {
+			temp = fracpart*0.1;
+			my_modf(temp, &fracpart);
+			idx = (int) ((temp -fracpart +0.05)* 10.0);
+			/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+			/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+			fconvert[fplace++] =
+			(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+		} while(fracpart && (fplace < 311));
+		if (fplace == 311) fplace--;
+	}
+	fconvert[fplace] = 0;
+  
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+	zpadlen = max - fplace;
+	if (zpadlen < 0) zpadlen = 0;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justifty */
+	
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch (buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue) 
+		dopr_outch (buffer, currlen, maxlen, signvalue);
+	
+	while (iplace > 0) 
+		dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
+
+#ifdef DEBUG_SNPRINTF
+	printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+	/*
+	 * Decimal point.  This should probably use locale to find the correct
+	 * char to print out.
+	 */
+	if (max > 0) {
+		dopr_outch (buffer, currlen, maxlen, '.');
+		
+		while (zpadlen > 0) {
+			dopr_outch (buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+
+		while (fplace > 0) 
+			dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
+	}
+
+	while (padlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+	if (*currlen < maxlen) {
+		buffer[(*currlen)] = c;
+	}
+	(*currlen)++;
+}
+
+static struct pr_chunk *new_chunk(void) {
+	struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk));
+
+	if ( !new_c ) 
+		return NULL;
+
+	new_c->type = 0;
+	new_c->num = 0;
+	new_c->min = 0;
+	new_c->min_star = NULL;
+	new_c->max = -1;
+	new_c->max_star = NULL;
+	new_c->flags = 0;
+	new_c->cflags = 0;
+	new_c->start = 0;
+	new_c->len = 0;
+	new_c->value = 0;
+	new_c->fvalue = 0;
+	new_c->strvalue = NULL;
+	new_c->pnum = NULL;
+	new_c->next = NULL;
+
+	return new_c;
+}
+
+static int add_cnk_list_entry(struct pr_chunk_x **list,
+				int max_num, struct pr_chunk *chunk) {
+	struct pr_chunk_x *l;
+	struct pr_chunk **c;
+	int max;
+	int cnum;
+	int i, pos;
+
+	if (chunk->num > max_num) {
+		max = chunk->num;
+	
+		if (*list == NULL) {
+			l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max);
+			pos = 0;
+		} else {
+			l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max);
+			pos = max_num;
+		}
+		if (l == NULL) {
+			for (i = 0; i < max; i++) {
+				if ((*list)[i].chunks) free((*list)[i].chunks);
+			}
+			return 0;
+		}
+		for (i = pos; i < max; i++) {
+			l[i].chunks = NULL;
+			l[i].num = 0;
+		}
+	} else {
+		l = *list;
+		max = max_num;
+	}
+
+	i = chunk->num - 1;
+	cnum = l[i].num + 1;
+	if (l[i].chunks == NULL) {
+		c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); 
+	} else {
+		c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum);
+	}
+	if (c == NULL) {
+		for (i = 0; i < max; i++) {
+			if (l[i].chunks) free(l[i].chunks);
+		}
+		return 0;
+	}
+	c[l[i].num] = chunk;
+	l[i].chunks = c;
+	l[i].num = cnum;
+
+	*list = l;
+	return max;
+}
+
+ int smb_vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+	return dopr(str, count, fmt, args);
+}
+#define vsnprintf smb_vsnprintf
+#endif
+
+/* yes this really must be a ||. Don't muck with this (tridge)
+ *
+ * The logic for these two is that we need our own definition if the
+ * OS *either* has no definition of *sprintf, or if it does have one
+ * that doesn't work properly according to the autoconf test.
+ */
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF)
+int smb_snprintf(char *str,size_t count,const char *fmt,...)
+{
+	size_t ret;
+	va_list ap;
+    
+	va_start(ap, fmt);
+	ret = vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+	return ret;
+}
+#define snprintf smb_snprintf
+#endif
+
+#endif 
+
+#ifndef HAVE_VASPRINTF
+ int vasprintf(char **ptr, const char *format, va_list ap)
+{
+	int ret;
+	va_list ap2;
+
+	VA_COPY(ap2, ap);
+	
+	ret = vsnprintf(NULL, 0, format, ap2);
+	if (ret <= 0) return ret;
+
+	(*ptr) = (char *)malloc(ret+1);
+	if (!*ptr) return -1;
+
+	VA_COPY(ap2, ap);
+
+	ret = vsnprintf(*ptr, ret+1, format, ap2);
+
+	return ret;
+}
+#endif
+
+
+#ifndef HAVE_ASPRINTF
+ int asprintf(char **ptr, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+	
+	*ptr = NULL;
+	va_start(ap, format);
+	ret = vasprintf(ptr, format, ap);
+	va_end(ap);
+
+	return ret;
+}
+#endif
+
+#ifdef TEST_SNPRINTF
+
+ int sprintf(char *str,const char *fmt,...);
+
+ int main (void)
+{
+	char buf1[1024];
+	char buf2[1024];
+	char *buf3;
+	char *fp_fmt[] = {
+		"%1.1f",
+		"%-1.5f",
+		"%1.5f",
+		"%123.9f",
+		"%10.5f",
+		"% 10.5f",
+		"%+22.9f",
+		"%+4.9f",
+		"%01.3f",
+		"%4f",
+		"%3.1f",
+		"%3.2f",
+		"%.0f",
+		"%f",
+		"%-8.8f",
+		"%-9.9f",
+		NULL
+	};
+	double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, 
+			     0.9996, 1.996, 4.136, 5.030201, 0.00205,
+			     /* END LIST */ 0};
+	char *int_fmt[] = {
+		"%-1.5d",
+		"%1.5d",
+		"%123.9d",
+		"%5.5d",
+		"%10.5d",
+		"% 10.5d",
+		"%+22.33d",
+		"%01.3d",
+		"%4d",
+		"%d",
+		NULL
+	};
+	long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 1234567890};
+	char *str_fmt[] = {
+		"%10.5s",
+		"%-10.5s",
+		"%5.10s",
+		"%-5.10s",
+		"%10.1s",
+		"%0.10s",
+		"%10.0s",
+		"%1.10s",
+		"%s",
+		"%.1s",
+		"%.10s",
+		"%10s",
+		NULL
+	};
+	char *str_vals[] = {"hello", "a", "", "a longer string", NULL};
+	int x, y;
+	int fail = 0;
+	int num = 0;
+	int l1, l2;
+
+	printf ("Testing snprintf format codes against system sprintf...\n");
+
+	for (x = 0; fp_fmt[x] ; x++) {
+		for (y = 0; fp_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]);
+			l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
+			sprintf (buf2, fp_fmt[x], fp_nums[y]);
+			buf1[1023] = buf1[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       fp_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+	for (x = 0; int_fmt[x] ; x++) {
+		for (y = 0; int_nums[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]);
+			l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
+			sprintf (buf2, int_fmt[x], int_nums[y]);
+			buf1[1023] = buf1[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       int_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+	for (x = 0; str_fmt[x] ; x++) {
+		for (y = 0; str_vals[y] != 0 ; y++) {
+			buf1[0] = buf2[0] = '\0';
+			l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]);
+			l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]);
+			sprintf (buf2, str_fmt[x], str_vals[y]);
+			buf1[1023] = buf1[1023] = '\0';
+			if (strcmp (buf1, buf2) || (l1 != l2)) {
+				printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", 
+				       str_fmt[x], l1, buf1, l2, buf2);
+				fail++;
+			}
+			num++;
+		}
+	}
+
+#define BUFSZ 2048
+
+	buf1[0] = buf2[0] = '\0';
+	if ((buf3 = malloc(BUFSZ)) == NULL) {
+		fail++;
+	} else {
+		num++;
+		memset(buf3, 'a', BUFSZ);
+		snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3);
+		buf1[1023] = '\0';
+		if (strcmp(buf1, "a") != 0) {
+			printf("length limit buf1 '%s' expected 'a'\n", buf1);
+			fail++;
+		}
+        }
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+	l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9);
+	buf1[1023] = buf1[1023] = '\0';
+	if (strcmp(buf1, buf2) || (l1 != l2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+		fail++;
+	}
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+	l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9);
+	buf1[1023] = buf1[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2);
+		fail++;
+	}
+#if 0
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890);
+	l2 = sprintf(buf2, "%lld", (LLONG)1234567890);
+	buf1[1023] = buf1[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%lld", l1, buf1, l2, buf2);
+		fail++;
+	}
+
+	buf1[0] = buf2[0] = '\0';
+	l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123);
+	l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123);
+	buf1[1023] = buf1[1023] = '\0';
+	if (strcmp(buf1, buf2)) {
+		printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n",
+				"%Lf", l1, buf1, l2, buf2);
+		fail++;
+	}
+#endif
+	printf ("%d tests failed out of %d.\n", fail, num);
+
+	printf("seeing how many digits we support\n");
+	{
+		double v0 = 0.12345678901234567890123456789012345678901;
+		for (x=0; x<100; x++) {
+			double p = pow(10, x); 
+			double r = v0*p;
+			snprintf(buf1, sizeof(buf1), "%1.1f", r);
+			sprintf(buf2,                "%1.1f", r);
+			if (strcmp(buf1, buf2)) {
+				printf("we seem to support %d digits\n", x-1);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* TEST_SNPRINTF */