Merge branch 'collectd-4.10' into collectd-5.0
authorFlorian Forster <octo@collectd.org>
Sun, 1 Apr 2012 10:01:58 +0000 (12:01 +0200)
committerFlorian Forster <octo@collectd.org>
Sun, 1 Apr 2012 10:01:58 +0000 (12:01 +0200)
Conflicts:
ChangeLog
src/collectd.conf.pod
src/common.c
src/network.c
src/processes.c
version-gen.sh

12 files changed:
1  2 
ChangeLog
configure.in
src/Makefile.am
src/collectd.conf.pod
src/common.c
src/common.h
src/libcollectdclient/client.c
src/memcached.c
src/network.c
src/perl.c
src/processes.c
src/snmp.c

diff --combined ChangeLog
+++ b/ChangeLog
 +2012-02-19, Version 5.0.3
 +      * Build system: Fix problems when building the ipvs and iptables
 +        plugins. Thanks to Sebastian Harl for his patch. A bashism in the
 +        version-gen.sh script has been fixed. Thanks to Jo-Philipp Wich for
 +        his patch.
 +      * csv and rrdtool plugins: Print a more helpful error message when the
 +        DataDir is a symlink pointing to a non-existing location. Thanks to
 +        Jonathan Nieder for his patch.
 +      * exec plugin: Fix a problem when using select(2) to read from file
 +        handles. Thanks to Gerrie Roos for his patch.
 +      * network plugin: An incorrect error message in the handling of the
 +        "Interface" configuration option has been fixed. Thanks to Gerrie
 +        Roos for his patch.
 +      * oracle plugin: A potential endless loop in the error handling has
 +        been fixed.
 +      * python plugin: A crash bug in the configuration handling has been
 +        fixed. Thanks to Sven Trenkel for his patch.
 +      * interfaces plugin: The change which was supposed to ignore "bogus"
 +        interfaces has been reverted, since it ignored legit interfaces, such
 +        as bonding pseudo-devices as well.
 +
 +2012-01-21, Version 5.0.2
 +      * curl_xml plugin: Fix handling of file:// and other URLs (which don't
 +        follow HTTP status codes). Thanks to Fabien Wernli for his patch!
 +      * df plugin: Fix handling of negative "available" counts. This can
 +        occur with some file systems, for example UFS. Thanks to Toni Ylenius
 +        for his patch.
 +      * interface plugin: "mac" interfaces are now ignored on Solaris. These
 +        pseudo-interfaces occur multiple times, causing warnings. Also switch
 +        to 64-bit counters on Solaris, improving overflow behavior for
 +        high-speed interfaces. Thanks to Eddy Geez and Fabien Wernli for
 +        their patches.
 +      * memory plugin: Account kernel and unused memory under Solaris. Thanks
 +        to Fabien Wernli for his patch.
 +      * network plugin: A bug in the interaction between the Network plugin
 +        and filter chains has been fixed: When a filter modified a field such
 +        as the hostname, subsequent values in the same network packets could
 +        have ended up using the modified name rather than the original name.
 +        Thanks to Sebastian Harl for identifying the problem.
 +      * oracle plugin: A memory leak has been fixed in the parameter handling.
 +      * python plugin: A memory leak has been fixed. Thanks to Sven Trenkel
 +        for fixing this bug!
 +
 +2011-10-07, Version 5.0.1
 +      * collectd: A mutex leak has been fixed in the meta data code. Thanks
 +        to Rafal Lesniak for his patch.
 +      * collectd: Compatibility fixes for GCC 4.6 have been applied. Thanks
 +        to Peter Green for his patch.
 +      * csv plugin: The line buffer size has been increased. Thanks to Colin
 +        McCabe for the patch.
 +      * curl_json plugin: Don't use the "parent" node to build the type
 +        instance, if it is empty. Compatibility with libyajl 2 has been
 +        added. Thanks to "spupykin" of the Arch Linux project for the initial
 +        code. Formatting of time has been fixed in the JSON module.
 +      * exec plugin: Fix the timestamp value passed to notification scripts.
 +        Thanks to Alexander Kovalenko for fixing this.
 +      * iptables plugin: Fix linking with some versions of libiptc.
 +      * irq plugin: Fix support for interrupts under Linux. The old code
 +        assumed that interrupts have a numeric value -- this is no longer
 +        true for Linux. Thanks to Bostjan Skufca for implementing this.
 +      * notify_desktop plugin: Compatibility with libnotify 0.7 has been
 +        added. Thanks to Samuli Suominen for his patch.
 +      * processes plugin: Fix handling of regular expressions containing
 +        spaces. Thanks for Sebastian Harl for fixing this.
 +      * rrdtool, rrdcached plugins: Improve precision of the XFF parameter.
 +        Previously, values like 0.999 would have been rounded to 1.0. Thanks
 +        to Francois-Xavier Bourlet for fixing this.
 +      * varnish plugin: Fix data type handling of some metrics. Some values
 +        were submitted as gauge even though they were derives.
 +      * Various plugin: Set a multi-threading flag in libcurl. Thanks to Mike
 +        Flisher for the fix.
 +
 +2011-03-28, Version 5.0.0
 +      * collectd: The "FQDNLookup" option is now enabled by default.
 +      * collectd: The internal representation of time has been changed to
 +        allow a higher accuracy than one second.
 +      * collectdcmd: This new command line utility can send various commands
 +        to collectd using the UnixSock plugin. Thanks to Håkon Dugstad
 +        Johnsen and Sebastian Harl for their code.
 +      * collectd-nagios: The "-m" option has been implemented (treat NaNs as
 +        critical).
 +      * collectd-tg: Traffic generator creating bogus network traffic
 +        compatible to the Network plugin. This utility can be used to
 +        stress-test new write plugins and collectd in general.
 +      * libcollectdclient: Creating and sending network packets has been
 +        added to the collectd client library.
 +      * All data sets: The data source name of all data sets with exactly
 +        one data source has been changed to "value".
 +      * All plugins: All "counter" data sources have been converted to
 +        "derive" data sources. All plugins now use "derive" by default, but
 +        plugins such as the network plugin can still handle "counter", of
 +        course. The minimum value of all derive data sources is zero, the
 +        maximum value is unspecified.
 +      * amqp plugin: The new AMQP plugin can send data to and receive data
 +        from an AMQP broker. Thanks to Sebastien Pahl for his code.
 +      * apache plugin: Backwards compatibility code has been removed.
 +        Support for the IBM HTTP Server has been added. Thanks to Manuel
 +        Luis Sanmartín Rozada for his patch.
 +      * contextswitch plugin: Support for sysctlbyname(3) has been added.
 +        Thanks to Kimo Rosenbaum for his patch.
 +      * df plugin: The default behavior has been changed to be equivalent to
 +        the "ReportReserved" behavior of v4.
 +      * dns plugin: Improved RFC 1035 name parsing has been imported from
 +        "dnstop".
 +      * exec plugin: Backwards compatibility code has been removed.
 +      * GenericJMX plugin: The "InstancePrefix" option has been added to
 +        "Connection" blocks.
 +      * hddtemp plugin: The "TranslateDevicename" config option has been
 +        removed.
 +      * interface plugin: Use the "plugin instance" to store the interface
 +        value.
 +      * libvirt plugin: The "InterfaceFormat" option has been added. Thanks
 +        to Ruben Kerkhof for his patch.
 +      * lpar plugin: New plugins for "logical partitions", a virtualization
 +        technique of POWER CPUs. Thanks to Aurélien Reynaud for his code and
 +        patience.
 +      * modbus plugin: Support for libmodbus 2.9.2 has been added and the
 +        license has been changes to LGPLv2.1.
 +      * mysql plugin: Backwards compatibility code has been removed. The
 +        data sets used have been improved.
 +      * network plugin: The default buffer size has been increased to
 +        1452 bytes.
 +      * perl plugin: Backwards compatibility code has been removed.
 +      * postgresql plugin: Backwards compatibility code has been removed.
 +      * redis plugin: Plugin for collecting statistics from Redis, a key-
 +        value store, has been added. Thanks to Andres J. Diaz for his code.
 +      * swap plugin: Implement collection of physical and virtual memory
 +        statistics under Solaris. The new default is collecting physical
 +        memory. Thanks to Aurélien Reynaud for his patches.
 +      * threshold plugin: The threshold configuration has been moved into
 +        this separate plugin.
 +      * unixsock plugin: The "DeleteSocket" option has been added.
 +      * varnish plugin: The new Varnish plugin reads statistics from
 +        Varnish, a web accelerator. Thanks to Jérôme Renard and Marc
 +        Fournier for their contributions.
 +      * write_redis: New plugin for writing data to Redis, a key-value
 +        store.
 +      * zfs_arc plugin: The data sets have been replaced by more elegant
 +        alternatives.
 +      * v5upgrade target: Target for converting v4 data sets to the v5
 +        schema.
 +
+ 2012-03-23, Version 4.10.7
+       * Build system: Fix the use of a libltdl macro. Thanks to Clemens Lang
+         for fixing this. Adresses some issues with building the iptables
+         plugin under Gentoo.
+       * libcollectdclient: A memory leak in the lcc_getval() function has
+         been fixed. Thanks to Jason Schmidlapp for finding and fixing this
+         issue.
+       * bind plugin: The use of 'QType" types has been fixed.
+       * df plugin: Fixed compiler issue under Mac OS X 10.7.
+       * conntrack plugin: Support zero as legitimate value. Thanks to Louis
+         Opter for his patch.
+       * memcached plugin: Increased the size of a static buffer, which was
+         truncating status messages form memcached. Thanks to Timon for the
+         patch.
+       * network plugin: Forwarding of notifications has been disabled. This
+         was a contition not checked for before, which may retult in an
+         endless loop.
+       * processes plugin: Support for process names with spaces has been
+         added to the Linux implementation. Thanks to Darrell Bishop for his
+         patch.
+       * perl plugin: A race condition in several callbacks, including log and
+         write callbacks, has been fixed. Thanks to "Rrpv" for reporting this
+         bug.
+       * snmp plugin: A bug when casting unsigned integers to gauge values has
+         been fixed: Unsigned integers would be cast to a signed integer and
+         then to a gauge, possibly resulting in a negative value.
+       * tcpconns plugin: Compilation with newer versions of the FreeBSD
+         runtime has been fixed.
  2012-02-19, Version 4.10.6
        * Build system: Fix problems when building the ipvs and iptables
          plugins. Thanks to Sebastian Harl for his patch. A bashism in the
diff --combined configure.in
@@@ -109,13 -109,9 +109,13 @@@ AC_ARG_ENABLE(standards
  if test "x$enable_standards" = "xyes"
  then
        AC_DEFINE(_ISOC99_SOURCE,        1, [Define to enforce ISO C99 compliance.])
 -      AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Define to enforce POSIX.1-2001 compliance.])
 -      AC_DEFINE(_XOPEN_SOURCE,       600, [Define to enforce X/Open 6 (XSI) compliance.])
 +      AC_DEFINE(_POSIX_C_SOURCE, 200809L, [Define to enforce POSIX.1-2008 compliance.])
 +      AC_DEFINE(_XOPEN_SOURCE,       700, [Define to enforce X/Open 7 (XSI) compliance.])
        AC_DEFINE(_REENTRANT,            1, [Define to enable reentrancy interfaces.])
 +      if test "x$GCC" = "xyes"
 +      then
 +              CFLAGS="$CFLAGS -std=c99"
 +      fi
  fi
  AM_CONDITIONAL(BUILD_FEATURE_STANDARDS, test "x$enable_standards" = "xyes")
  
@@@ -591,27 -587,6 +591,27 @@@ socket_needs_socket="no
  AC_CHECK_FUNCS(socket, [], AC_CHECK_LIB(socket, socket, [socket_needs_socket="yes"], AC_MSG_ERROR(cannot find socket)))
  AM_CONDITIONAL(BUILD_WITH_LIBSOCKET, test "x$socket_needs_socket" = "xyes")
  
 +clock_gettime_needs_rt="no"
 +clock_gettime_needs_posix4="no"
 +have_clock_gettime="no"
 +AC_CHECK_FUNCS(clock_gettime, [have_clock_gettime="yes"])
 +if test "x$have_clock_gettime" = "xno"
 +then
 +      AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_needs_rt="yes"
 +                                       have_clock_gettime="yes"])
 +fi
 +if test "x$have_clock_gettime" = "xno"
 +then
 +      AC_CHECK_LIB(posix4, clock_gettime, [clock_gettime_needs_posix4="yes"
 +                                           have_clock_gettime="yes"])
 +fi
 +if test "x$have_clock_gettime" = "xyes"
 +then
 +      AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if the clock_gettime(2) function is available.])
 +else
 +      AC_MSG_WARN(cannot find clock_gettime)
 +fi
 +
  nanosleep_needs_rt="no"
  nanosleep_needs_posix4="no"
  AC_CHECK_FUNCS(nanosleep,
          AC_CHECK_LIB(posix4, nanosleep,
              [nanosleep_needs_posix4="yes"],
              AC_MSG_ERROR(cannot find nanosleep))))
 -AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$nanosleep_needs_rt" = "xyes")
 -AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$nanosleep_needs_posix4" = "xyes")
 +
 +AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$clock_gettime_needs_rt" = "xyes" || test "x$nanosleep_needs_rt" = "xyes")
 +AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$clock_gettime_needs_posix4" = "xyes" || test "x$nanosleep_needs_posix4" = "xyes")
  
  AC_CHECK_FUNCS(sysctl, [have_sysctl="yes"], [have_sysctl="no"])
  AC_CHECK_FUNCS(sysctlbyname, [have_sysctlbyname="yes"], [have_sysctlbyname="no"])
@@@ -633,127 -607,13 +633,127 @@@ AC_CHECK_FUNCS(thread_info, [have_threa
  AC_CHECK_FUNCS(statfs, [have_statfs="yes"], [have_statfs="no"])
  AC_CHECK_FUNCS(statvfs, [have_statvfs="yes"], [have_statvfs="no"])
  AC_CHECK_FUNCS(getifaddrs, [have_getifaddrs="yes"], [have_getifaddrs="no"])
 +AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
  AC_CHECK_FUNCS(syslog, [have_syslog="yes"], [have_syslog="no"])
  AC_CHECK_FUNCS(getutent, [have_getutent="yes"], [have_getutent="no"])
  AC_CHECK_FUNCS(getutxent, [have_getutxent="yes"], [have_getutxent="no"])
 -AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"])
  
 -# For load module
 -AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
 +# Check for strptime {{{
 +if test "x$GCC" = "xyes"
 +then
 +      SAVE_CFLAGS="$CFLAGS"
 +      CFLAGS="$CFLAGS -Wall -Wextra -Werror"
 +fi
 +
 +AC_CHECK_FUNCS(strptime, [have_strptime="yes"], [have_strptime="no"])
 +if test "x$have_strptime" = "xyes"
 +then
 +      AC_CACHE_CHECK([whether strptime is exported by default],
 +                     [c_cv_have_strptime_default],
 +                     AC_COMPILE_IFELSE(
 +AC_LANG_PROGRAM(
 +[[
 +AC_INCLUDES_DEFAULT
 +#include <time.h>
 +]],
 +[[
 + struct tm stm;
 + (void) strptime ("2010-12-30%13:42:42", "%Y-%m-%dT%T", &stm);
 +]]),
 +                     [c_cv_have_strptime_default="yes"],
 +                     [c_cv_have_strptime_default="no"]))
 +fi
 +if test "x$have_strptime" = "xyes" && test "x$c_cv_have_strptime_default" = "xno"
 +then
 +      AC_CACHE_CHECK([whether strptime needs standards mode],
 +                     [c_cv_have_strptime_standards],
 +                     AC_COMPILE_IFELSE(
 +AC_LANG_PROGRAM(
 +[[
 +#ifndef _ISOC99_SOURCE
 +# define _ISOC99_SOURCE 1
 +#endif
 +#ifndef _POSIX_C_SOURCE
 +# define _POSIX_C_SOURCE 200112L
 +#endif
 +#ifndef _XOPEN_SOURCE
 +# define _XOPEN_SOURCE 500
 +#endif
 +AC_INCLUDES_DEFAULT
 +#include <time.h>
 +]],
 +[[
 + struct tm stm;
 + (void) strptime ("2010-12-30%13:42:42", "%Y-%m-%dT%T", &stm);
 +]]),
 +                     [c_cv_have_strptime_standards="yes"],
 +                     [c_cv_have_strptime_standards="no"]))
 +
 +      if test "x$c_cv_have_strptime_standards" = "xyes"
 +      then
 +              AC_DEFINE([STRPTIME_NEEDS_STANDARDS], 1, [Set to true if strptime is only exported in X/Open mode (GNU libc).])
 +      else
 +              have_strptime="no"
 +      fi
 +fi
 +
 +if test "x$GCC" = "xyes"
 +then
 +      CFLAGS="$SAVE_CFLAGS"
 +fi
 +
 +# }}} Check for strptime
 +
 +AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"])
 +if test "x$have_swapctl" = "xyes"; then
 +        AC_CACHE_CHECK([whether swapctl takes two arguments],
 +                [c_cv_have_swapctl_two_args],
 +                AC_COMPILE_IFELSE(
 +                        AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
 +#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
 +#  undef _FILE_OFFSET_BITS
 +#  undef _LARGEFILE64_SOURCE
 +#endif
 +#include <sys/stat.h>
 +#include <sys/swap.h>]],
 +                                [[
 +                                int num = swapctl(0, NULL);
 +                                ]]
 +                        ),
 +                        [c_cv_have_swapctl_two_args="yes"],
 +                        [c_cv_have_swapctl_two_args="no"]
 +                )
 +        )
 +        AC_CACHE_CHECK([whether swapctl takes three arguments],
 +                [c_cv_have_swapctl_three_args],
 +                AC_COMPILE_IFELSE(
 +                        AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
 +#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
 +#  undef _FILE_OFFSET_BITS
 +#  undef _LARGEFILE64_SOURCE
 +#endif
 +#include <sys/stat.h>
 +#include <sys/swap.h>]],
 +                                [[
 +                                int num = swapctl(0, NULL,0);
 +                                ]]
 +                        ),
 +                        [c_cv_have_swapctl_three_args="yes"],
 +                        [c_cv_have_swapctl_three_args="no"]
 +                )
 +        )
 +fi
 +# Check for different versions of `swapctl' here..
 +if test "x$have_swapctl" = "xyes"; then
 +        if test "x$c_cv_have_swapctl_two_args" = "xyes"; then
 +                AC_DEFINE(HAVE_SWAPCTL_TWO_ARGS, 1,
 +                          [Define if the function swapctl exists and takes two arguments.])
 +        fi
 +        if test "x$c_cv_have_swapctl_three_args" = "xyes"; then
 +                AC_DEFINE(HAVE_SWAPCTL_THREE_ARGS, 1,
 +                          [Define if the function swapctl exists and takes three arguments.])
 +        fi
 +fi
  
  # Check for NAN
  AC_ARG_WITH(nan-emulation, [AS_HELP_STRING([--with-nan-emulation], [use emulated NAN. For crosscompiling only.])],
@@@ -775,7 -635,7 +775,7 @@@ if test "x$nan_type" = "xnone"; the
        [[
  #include <stdlib.h>
  #include <math.h>
 -static float foo = NAN;
 +static double foo = NAN;
        ]],
        [[
         if (isnan (foo))
@@@ -801,7 -661,7 +801,7 @@@ if test "x$nan_type" = "xnone"; the
  #include <stdlib.h>
  #define __USE_ISOC99 1
  #include <math.h>
 -static float foo = NAN;
 +static double foo = NAN;
        ]],
        [[
         if (isnan (foo))
@@@ -835,7 -695,7 +835,7 @@@ if test "x$nan_type" = "xnone"; the
  #ifndef isnan
  # define isnan(f) ((f) != (f))
  #endif
 -static float foo = NAN;
 +static double foo = NAN;
        ]],
        [[
         if (isnan (foo))
  if test "x$with_perfstat" = "xyes"
  then
         AC_DEFINE(HAVE_PERFSTAT, 1, [Define to 1 if you have the 'perfstat' library (-lperfstat)])
 +       # struct members pertaining to donation have been added to libperfstat somewhere between AIX5.3ML5 and AIX5.3ML9
 +       AC_CHECK_MEMBER([perfstat_partition_type_t.b.donate_enabled], [], [], [[#include <libperfstat.h]])
 +       if test "x$av_cv_member_perfstat_partition_type_t_b_donate_enabled" = "xyes"
 +       then
 +              AC_DEFINE(PERFSTAT_SUPPORTS_DONATION, 1, [Define to 1 if your version of the 'perfstat' library supports donation])
 +       fi
  fi
  AM_CONDITIONAL(BUILD_WITH_PERFSTAT, test "x$with_perfstat" = "xyes")
  
@@@ -1380,6 -1234,7 +1380,7 @@@ AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWA
  AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"])
  if test "x$with_kvm_nlist" = "xyes"
  then
+       AC_CHECK_HEADERS(bsd/nlist.h nlist.h)
        AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
                  [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)])
        with_libkvm="yes"
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
  
 +# --with-libcredis {{{
 +AC_ARG_WITH(libcredis, [AS_HELP_STRING([--with-libcredis@<:@=PREFIX@:>@], [Path to libcredis.])],
 +[
 + if test "x$withval" = "xyes"
 + then
 +       with_libcredis="yes"
 + else if test "x$withval" = "xno"
 + then
 +       with_libcredis="no"
 + else
 +       with_libcredis="yes"
 +       LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS -I$withval/include"
 +       LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS -L$withval/lib"
 + fi; fi
 +],
 +[with_libcredis="yes"])
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +CPPFLAGS="$CPPFLAGS $LIBCREDIS_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $LIBCREDIS_LDFLAGS"
 +
 +if test "x$with_libcredis" = "xyes"
 +then
 +      if test "x$LIBCREDIS_CPPFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([libcredis CPPFLAGS: $LIBCREDIS_CPPFLAGS])
 +      fi
 +      AC_CHECK_HEADERS(credis.h,
 +      [with_libcredis="yes"],
 +      [with_libcredis="no (credis.h not found)"])
 +fi
 +if test "x$with_libcredis" = "xyes"
 +then
 +      if test "x$LIBCREDIS_LDFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([libcredis LDFLAGS: $LIBCREDIS_LDFLAGS])
 +      fi
 +      AC_CHECK_LIB(credis, credis_info,
 +      [with_libcredis="yes"],
 +      [with_libcredis="no (symbol 'credis_info' not found)"])
 +
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +if test "x$with_libcredis" = "xyes"
 +then
 +      BUILD_WITH_LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS"
 +      BUILD_WITH_LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS"
 +      AC_SUBST(BUILD_WITH_LIBCREDIS_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBCREDIS_LDFLAGS)
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes")
 +# }}}
 +
  # --with-libcurl {{{
  with_curl_config="curl-config"
  with_curl_cflags=""
        AC_CHECK_TYPES([iptc_handle_t, ip6tc_handle_t], [], [])
  fi
  # Check for the iptc_init symbol in the library.
+ # This could be in iptc or ip4tc
  if test "x$with_libiptc" = "xpkgconfig"
  then
-       AC_CHECK_LIB(iptc, iptc_init,
+       AC_SEARCH_LIBS(iptc_init, [iptc ip4tc],
                        [with_libiptc="pkgconfig"],
                        [with_libiptc="no"],
                        [$with_libiptc_libs])
@@@ -2155,7 -1953,7 +2157,7 @@@ the
        $PKG_CONFIG --exists 'modbus' 2>/dev/null
        if test $? -ne 0
        then
 -              with_libmodbus="no (pkg-config doesn't know library)"
 +              with_libmodbus="no (pkg-config doesn't know modbus)"
        fi
  fi
  if test "x$with_libmodbus" = "xuse_pkgconfig"
@@@ -2195,9 -1993,9 +2197,9 @@@ the
        CPPFLAGS="$CPPFLAGS $with_libmodbus_cflags"
        LDFLAGS="$LDFLAGS $with_libmodbus_libs"
  
 -      AC_CHECK_LIB(modbus, modbus_init_tcp,
 +      AC_CHECK_LIB(modbus, modbus_connect,
                     [with_libmodbus="yes"],
 -                   [with_libmodbus="no (symbol modbus_init_tcp not found)"])
 +                   [with_libmodbus="no (symbol modbus_connect not found)"])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
        LDFLAGS="$SAVE_LDFLAGS"
@@@ -2620,7 -2418,7 +2622,7 @@@ the
        fi
        AC_CHECK_HEADERS(oping.h,
        [with_liboping="yes"],
 -      [with_liboping="no ('oping.h' not found)"])
 +      [with_liboping="no (oping.h not found)"])
  fi
  if test "x$with_liboping" = "xyes"
  then
@@@ -2791,8 -2589,7 +2793,8 @@@ the
  fi
  if test "x$with_libpcap" = "xyes"
  then
 -      AC_CHECK_HEADERS(pcap-bpf.h)
 +      AC_CHECK_HEADERS(pcap-bpf.h,,
 +                       [with_libpcap="no (pcap-bpf.h not found)"])
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBPCAP, test "x$with_libpcap" = "xyes")
  # }}}
  fi
  # }}} --with-python
  
 +# --with-librabbitmq {{{
 +with_librabbitmq_cppflags=""
 +with_librabbitmq_ldflags=""
 +AC_ARG_WITH(librabbitmq, [AS_HELP_STRING([--with-librabbitmq@<:@=PREFIX@:>@], [Path to librabbitmq.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              with_librabbitmq_cppflags="-I$withval/include"
 +              with_librabbitmq_ldflags="-L$withval/lib"
 +              with_librabbitmq="yes"
 +      else
 +              with_librabbitmq="$withval"
 +      fi
 +],
 +[
 +      with_librabbitmq="yes"
 +])
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
 +LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
 +if test "x$with_librabbitmq" = "xyes"
 +then
 +      AC_CHECK_HEADERS(amqp.h, [with_librabbitmq="yes"], [with_librabbitmq="no (amqp.h not found)"])
 +fi
 +if test "x$with_librabbitmq" = "xyes"
 +then
 +      # librabbitmq up to version 0.9.1 provides "library_errno", later
 +      # versions use "library_error". The library does not provide a version
 +      # macro :( Use "AC_CHECK_MEMBERS" (plural) for automatic defines.
 +      AC_CHECK_MEMBERS([amqp_rpc_reply_t.library_errno],,,
 +                       [
 +#if HAVE_STDLIB_H
 +# include <stdlib.h>
 +#endif
 +#if HAVE_STDIO_H
 +# include <stdio.h>
 +#endif
 +#if HAVE_STDINT_H
 +# include <stdint.h>
 +#endif
 +#if HAVE_INTTYPES_H
 +# include <inttypes.h>
 +#endif
 +#include <amqp.h>
 +                         ])
 +fi
 +if test "x$with_librabbitmq" = "xyes"
 +then
 +      AC_CHECK_LIB(rabbitmq, amqp_basic_publish, [with_librabbitmq="yes"], [with_librabbitmq="no (Symbol 'amqp_basic_publish' not found)"])
 +fi
 +if test "x$with_librabbitmq" = "xyes"
 +then
 +      BUILD_WITH_LIBRABBITMQ_CPPFLAGS="$with_librabbitmq_cppflags"
 +      BUILD_WITH_LIBRABBITMQ_LDFLAGS="$with_librabbitmq_ldflags"
 +      BUILD_WITH_LIBRABBITMQ_LIBS="-lrabbitmq"
 +      AC_SUBST(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRABBITMQ_LIBS)
 +      AC_DEFINE(HAVE_LIBRABBITMQ, 1, [Define if librabbitmq is present and usable.])
 +fi
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +AM_CONDITIONAL(BUILD_WITH_LIBRABBITMQ, test "x$with_librabbitmq" = "xyes")
 +# }}}
 +
  # --with-librouteros {{{
  AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
  [
@@@ -3324,7 -3055,7 +3326,7 @@@ the
        fi
        AC_CHECK_HEADERS(routeros_api.h,
        [with_librouteros="yes"],
 -      [with_librouteros="no ('routeros_api.h' not found)"])
 +      [with_librouteros="no (routeros_api.h not found)"])
  fi
  if test "x$with_librouteros" = "xyes"
  then
@@@ -3523,7 -3254,7 +3525,7 @@@ the
      if test "$?" != "0"
      then
        with_libstatgrab_pkg_config="no"
 -      with_libstatgrab="no ($PKG_CONFIG doesn't know libstatgrab)"
 +      with_libstatgrab="no (pkg-config doesn't know libstatgrab)"
        temp_result="not found"
      fi
      AC_MSG_RESULT([$temp_result])
@@@ -3743,7 -3474,7 +3745,7 @@@ the
        $PKG_CONFIG --exists 'libupsclient' 2>/dev/null
        if test $? -ne 0
        then
 -              with_libupsclient="no (pkg-config doesn't know library)"
 +              with_libupsclient="no (pkg-config doesn't know libupsclient)"
        fi
  fi
  if test "x$with_libupsclient" = "xuse_pkgconfig"
  AM_CONDITIONAL(BUILD_WITH_LIBYAJL, test "x$with_libyajl" = "xyes")
  # }}}
  
 +# --with-libvarnish {{{
 +with_libvarnish_cppflags=""
 +with_libvarnish_cflags=""
 +with_libvarnish_libs=""
 +AC_ARG_WITH(libvarnish, [AS_HELP_STRING([--with-libvarnish@<:@=PREFIX@:>@], [Path to libvarnish.])],
 +[
 +      if test "x$withval" = "xno"
 +      then
 +              with_libvarnish="no"
 +      else if test "x$withval" = "xyes"
 +      then
 +              with_libvarnish="use_pkgconfig"
 +      else if test -d "$with_libvarnish/lib"
 +      then
 +              AC_MSG_NOTICE([Not checking for libvarnish: Manually configured])
 +              with_libvarnish_cflags="-I$withval/include"
 +              with_libvarnish_libs="-L$withval/lib -lvarnish -lvarnishcompat -lvarnishapi"
 +              with_libvarnish="yes"
 +      fi; fi; fi
 +],
 +[with_libvarnish="use_pkgconfig"])
 +
 +# configure using pkg-config
 +if test "x$with_libvarnish" = "xuse_pkgconfig"
 +then
 +      if test "x$PKG_CONFIG" = "x"
 +      then
 +              with_libvarnish="no (Don't have pkg-config)"
 +      fi
 +fi
 +if test "x$with_libvarnish" = "xuse_pkgconfig"
 +then
 +      AC_MSG_NOTICE([Checking for varnishapi using $PKG_CONFIG])
 +      $PKG_CONFIG --exists 'varnishapi' 2>/dev/null
 +      if test $? -ne 0
 +      then
 +              with_libvarnish="no (pkg-config doesn't know varnishapi)"
 +      fi
 +fi
 +if test "x$with_libvarnish" = "xuse_pkgconfig"
 +then
 +      with_libvarnish_cflags="`$PKG_CONFIG --cflags 'varnishapi'`"
 +      if test $? -ne 0
 +      then
 +              with_libvarnish="no ($PKG_CONFIG failed)"
 +      fi
 +      with_libvarnish_libs="`$PKG_CONFIG --libs 'varnishapi'`"
 +      if test $? -ne 0
 +      then
 +              with_libvarnish="no ($PKG_CONFIG failed)"
 +      fi
 +fi
 +if test "x$with_libvarnish" = "xuse_pkgconfig"
 +then
 +      with_libvarnish="yes"
 +fi
 +
 +# with_libvarnish_cflags and with_libvarnish_libs are set up now, let's do
 +# the actual checks.
 +if test "x$with_libvarnish" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
 +      AC_CHECK_HEADERS(varnish/varnishapi.h, [], [with_libvarnish="no (varnish/varnishapi.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libvarnish" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      #SAVE_LDFLAGS="$LDFLAGS"
 +
 +      CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
 +      #LDFLAGS="$LDFLAGS $with_libvarnish_libs"
 +
 +      AC_CHECK_LIB(varnishapi, VSL_OpenStats,
 +                   [with_libvarnish="yes"],
 +                   [with_libvarnish="no (symbol VSL_OpenStats not found)"],
 +                   [$with_libvarnish_libs])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      #LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libvarnish" = "xyes"
 +then
 +      BUILD_WITH_LIBVARNISH_CFLAGS="$with_libvarnish_cflags"
 +      BUILD_WITH_LIBVARNISH_LIBS="$with_libvarnish_libs"
 +      AC_SUBST(BUILD_WITH_LIBVARNISH_CFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBVARNISH_LIBS)
 +fi
 +# }}}
 +
  # pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
  with_libxml2="no (pkg-config isn't available)"
  with_libxml2_cflags=""
@@@ -4039,7 -3678,7 +4041,7 @@@ the
        then
                with_libxml2="yes"
        else
 -              with_libxml2="no (pkg-config doesn't know library)"
 +              with_libxml2="no (pkg-config doesn't know libxml-2.0)"
        fi
  
        pkg-config --exists libvirt 2>/dev/null
        then
                with_libvirt="yes"
        else
 -              with_libvirt="no (pkg-config doesn't know library)"
 +              with_libvirt="no (pkg-config doesn't know libvirt)"
        fi
  fi
  if test "x$with_libxml2" = "xyes"
@@@ -4164,7 -3803,7 +4166,7 @@@ the
        $PKG_CONFIG --exists OpenIPMIpthread 2>/dev/null
        if test "$?" != "0"
        then
 -              with_libopenipmipthread="no ($PKG_CONFIG doesn't know OpenIPMIpthread)"
 +              with_libopenipmipthread="no (pkg-config doesn't know OpenIPMIpthread)"
        fi
        AC_MSG_RESULT([$with_libopenipmipthread])
  fi
  
  PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
                [with_libnotify="yes"],
 -              [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
 +              [if test "x$LIBNOTIFY_PKG_ERRORS" = "x"; then
 +                       with_libnotify="no"
 +               else
 +                       with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"
 +               fi])
  
  # Check for enabled/disabled features
  #
@@@ -4472,6 -4107,11 +4474,6 @@@ the
        plugin_tape="yes"
  fi
  
 -if test "x$have_sys_swap_h$with_kstat$ac_system" = "xyesyesSolaris"
 -then
 -      plugin_swap="yes"
 -fi
 -
  # libstatgrab
  if test "x$with_libstatgrab" = "xyes"
  then
  if test "x$with_libcurl" = "xyes" && test "x$with_libxml2" = "xyes"
  then
        plugin_ascent="yes"
 -      plugin_bind="yes"
 +      if test "x$have_strptime" = "xyes"
 +      then
 +              plugin_bind="yes"
 +      fi
  fi
  
  if test "x$with_libopenipmipthread" = "xyes"
@@@ -4516,15 -4153,11 +4518,15 @@@ if test "x$have_sysctl" = "xyes
  then
        plugin_cpu="yes"
        plugin_memory="yes"
 -      plugin_swap="yes"
        plugin_uptime="yes"
 +      if test "x$ac_system" = "xDarwin"
 +      then
 +              plugin_swap="yes"
 +      fi
  fi
  if test "x$have_sysctlbyname" = "xyes"
  then
 +      plugin_contextswitch="yes"
        plugin_cpu="yes"
        plugin_memory="yes"
        plugin_tcpconns="yes"
@@@ -4612,7 -4245,7 +4614,7 @@@ the
        plugin_swap="yes"
  fi
  
 -if test "x$have_swapctl" = "xyes"
 +if test "x$have_swapctl" = "xyes" && test "x$c_cv_have_swapctl_two_args" = "xyes"
  then
        plugin_swap="yes"
  fi
@@@ -4652,7 -4285,6 +4654,7 @@@ AC_ARG_ENABLE([all-plugins]
  
  m4_divert_once([HELP_ENABLE], [])
  
 +AC_PLUGIN([amqp],        [$with_librabbitmq],  [AMQP output plugin])
  AC_PLUGIN([apache],      [$with_libcurl],      [Apache httpd statistics])
  AC_PLUGIN([apcups],      [yes],                [Statistics of UPSes by APC])
  AC_PLUGIN([apple_sensors], [$with_libiokit],   [Apple's hardware sensors])
@@@ -4687,7 -4319,6 +4689,7 @@@ AC_PLUGIN([java],        [$with_java]
  AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
  AC_PLUGIN([load],        [$plugin_load],       [System load])
  AC_PLUGIN([logfile],     [yes],                [File logging plugin])
 +AC_PLUGIN([lpar],        [$with_perfstat],     [AIX logical partitions statistics])
  AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
  AC_PLUGIN([match_empty_counter], [yes],        [The empty counter match])
  AC_PLUGIN([match_hashed], [yes],               [The hashed match])
@@@ -4723,7 -4354,6 +4725,7 @@@ AC_PLUGIN([powerdns],    [yes]
  AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
  AC_PLUGIN([protocols],   [$plugin_protocols],  [Protocol (IP, TCP, ...) statistics])
  AC_PLUGIN([python],      [$with_python],       [Embed a Python interpreter])
 +AC_PLUGIN([redis],       [$with_libcredis],    [Redis plugin])
  AC_PLUGIN([routeros],    [$with_librouteros],  [RouterOS plugin])
  AC_PLUGIN([rrdcached],   [$librrd_rrdc_update], [RRDTool output plugin])
  AC_PLUGIN([rrdtool],     [$with_librrd],       [RRDTool output plugin])
@@@ -4739,23 -4369,19 +4741,23 @@@ AC_PLUGIN([target_notification], [yes]
  AC_PLUGIN([target_replace], [yes],             [The replace target])
  AC_PLUGIN([target_scale],[yes],                [The scale target])
  AC_PLUGIN([target_set],  [yes],                [The set target])
 +AC_PLUGIN([target_v5upgrade], [yes],           [The v5upgrade target])
  AC_PLUGIN([tcpconns],    [$plugin_tcpconns],   [TCP connection statistics])
  AC_PLUGIN([teamspeak2],  [yes],                [TeamSpeak2 server statistics])
  AC_PLUGIN([ted],         [$plugin_ted],        [Read The Energy Detective values])
  AC_PLUGIN([thermal],     [$plugin_thermal],    [Linux ACPI thermal zone statistics])
 +AC_PLUGIN([threshold],   [yes],                [Threshold checking plugin])
  AC_PLUGIN([tokyotyrant], [$with_libtokyotyrant],  [TokyoTyrant database statistics])
  AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
  AC_PLUGIN([uptime],      [$plugin_uptime],     [Uptime statistics])
  AC_PLUGIN([users],       [$plugin_users],      [User statistics])
  AC_PLUGIN([uuid],        [yes],                [UUID as hostname plugin])
 +AC_PLUGIN([varnish],     [$with_libvarnish],   [Varnish cache statistics])
  AC_PLUGIN([vmem],        [$plugin_vmem],       [Virtual memory statistics])
  AC_PLUGIN([vserver],     [$plugin_vserver],    [Linux VServer statistics])
  AC_PLUGIN([wireless],    [$plugin_wireless],   [Wireless statistics])
  AC_PLUGIN([write_http],  [$with_libcurl],      [HTTP output plugin])
 +AC_PLUGIN([write_redis], [$with_libcredis],    [Redis output plugin])
  AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
  AC_PLUGIN([zfs_arc],     [$plugin_zfs_arc],    [ZFS ARC statistics])
  
@@@ -4930,7 -4556,6 +4932,7 @@@ Configuration
    Libraries:
      libcurl . . . . . . . $with_libcurl
      libdbi  . . . . . . . $with_libdbi
 +    libcredis . . . . . . $with_libcredis
      libesmtp  . . . . . . $with_libesmtp
      libganglia  . . . . . $with_libganglia
      libgcrypt . . . . . . $with_libgcrypt
      libperl . . . . . . . $with_libperl
      libpq . . . . . . . . $with_libpq
      libpthread  . . . . . $with_libpthread
 +    librabbitmq . . . . . $with_librabbitmq
      librouteros . . . . . $with_librouteros
      librrd  . . . . . . . $with_librrd
      libsensors  . . . . . $with_libsensors
      libstatgrab . . . . . $with_libstatgrab
      libtokyotyrant  . . . $with_libtokyotyrant
      libupsclient  . . . . $with_libupsclient
 +    libvarnish  . . . . . $with_libvarnish
      libvirt . . . . . . . $with_libvirt
      libxml2 . . . . . . . $with_libxml2
      libxmms . . . . . . . $with_libxmms
      perl  . . . . . . . . $with_perl_bindings
  
    Modules:
 +    amqp    . . . . . . . $enable_amqp
      apache  . . . . . . . $enable_apache
      apcups  . . . . . . . $enable_apcups
      apple_sensors . . . . $enable_apple_sensors
      libvirt . . . . . . . $enable_libvirt
      load  . . . . . . . . $enable_load
      logfile . . . . . . . $enable_logfile
 +    lpar... . . . . . . . $enable_lpar
      madwifi . . . . . . . $enable_madwifi
      match_empty_counter . $enable_match_empty_counter
      match_hashed  . . . . $enable_match_hashed
      processes . . . . . . $enable_processes
      protocols . . . . . . $enable_protocols
      python  . . . . . . . $enable_python
 +    redis . . . . . . . . $enable_redis
      routeros  . . . . . . $enable_routeros
      rrdcached . . . . . . $enable_rrdcached
      rrdtool . . . . . . . $enable_rrdtool
      target_replace  . . . $enable_target_replace
      target_scale  . . . . $enable_target_scale
      target_set  . . . . . $enable_target_set
 +    target_v5upgrade  . . $enable_target_v5upgrade
      tcpconns  . . . . . . $enable_tcpconns
      teamspeak2  . . . . . $enable_teamspeak2
      ted . . . . . . . . . $enable_ted
      thermal . . . . . . . $enable_thermal
 +    threshold . . . . . . $enable_threshold
      tokyotyrant . . . . . $enable_tokyotyrant
      unixsock  . . . . . . $enable_unixsock
      uptime  . . . . . . . $enable_uptime
      users . . . . . . . . $enable_users
      uuid  . . . . . . . . $enable_uuid
 +    varnish . . . . . . . $enable_varnish
      vmem  . . . . . . . . $enable_vmem
      vserver . . . . . . . $enable_vserver
      wireless  . . . . . . $enable_wireless
      write_http  . . . . . $enable_write_http
 +    write_redis . . . . . $enable_write_redis
      xmms  . . . . . . . . $enable_xmms
      zfs_arc . . . . . . . $enable_zfs_arc
  
diff --combined src/Makefile.am
@@@ -21,7 -21,7 +21,7 @@@ AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdi
  AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
  
  sbin_PROGRAMS = collectd collectdmon
 -bin_PROGRAMS = collectd-nagios
 +bin_PROGRAMS = collectd-nagios collectdctl
  
  collectd_SOURCES = collectd.c collectd.h \
                   common.c common.h \
@@@ -40,7 -40,7 +40,7 @@@
                   utils_match.c utils_match.h \
                   utils_subst.c utils_subst.h \
                   utils_tail.c utils_tail.h \
 -                 utils_threshold.c utils_threshold.h \
 +                 utils_time.c utils_time.h \
                   types_list.c types_list.h
  
  collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
@@@ -85,7 -85,7 +85,7 @@@ endi
  
  if BUILD_WITH_OWN_LIBOCONFIG
  collectd_LDADD += $(LIBLTDL) liboconfig/liboconfig.la
- collectd_DEPENDENCIES += $(LIBLTDL) liboconfig/liboconfig.la
+ collectd_DEPENDENCIES += liboconfig/liboconfig.la
  else
  collectd_LDADD += -loconfig
  endif
@@@ -105,36 -105,11 +105,36 @@@ endi
  collectd_nagios_LDADD += libcollectdclient/libcollectdclient.la
  collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
  
 +
 +collectdctl_SOURCES = collectdctl.c
 +collectdctl_LDADD =
 +if BUILD_WITH_LIBSOCKET
 +collectdctl_LDADD += -lsocket
 +endif
 +if BUILD_AIX
 +collectdctl_LDADD += -lm
 +endif
 +collectdctl_LDADD += libcollectdclient/libcollectdclient.la
 +collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
 +
 +
  pkglib_LTLIBRARIES = 
  
  BUILT_SOURCES = 
  CLEANFILES = 
  
 +if BUILD_PLUGIN_AMQP
 +pkglib_LTLIBRARIES += amqp.la
 +amqp_la_SOURCES = amqp.c \
 +                utils_cmd_putval.c utils_cmd_putval.h \
 +                utils_format_json.c utils_format_json.h
 +amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
 +amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
 +amqp_la_LIBADD = $(BUILD_WITH_LIBRABBITMQ_LIBS)
 +collectd_LDADD += "-dlopen" amqp.la
 +collectd_DEPENDENCIES += amqp.la
 +endif
 +
  if BUILD_PLUGIN_APACHE
  pkglib_LTLIBRARIES += apache.la
  apache_la_SOURCES = apache.c
@@@ -526,15 -501,6 +526,15 @@@ collectd_LDADD += "-dlopen" logfile.l
  collectd_DEPENDENCIES += logfile.la
  endif
  
 +if BUILD_PLUGIN_LPAR
 +pkglib_LTLIBRARIES += lpar.la
 +lpar_la_SOURCES = lpar.c
 +lpar_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" lpar.la
 +collectd_DEPENDENCIES += lpar.la
 +lpar_la_LIBADD = -lperfstat
 +endif
 +
  if BUILD_PLUGIN_MADWIFI
  pkglib_LTLIBRARIES += madwifi.la
  madwifi_la_SOURCES = madwifi.c madwifi.h
@@@ -921,16 -887,6 +921,16 @@@ collectd_LDADD += "-dlopen" protocols.l
  collectd_DEPENDENCIES += protocols.la
  endif
  
 +if BUILD_PLUGIN_REDIS
 +pkglib_LTLIBRARIES += redis.la
 +redis_la_SOURCES = redis.c
 +redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
 +redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
 +redis_la_LIBADD = -lcredis
 +collectd_LDADD += "-dlopen" redis.la
 +collectd_DEPENDENCIES += redis.la
 +endif
 +
  if BUILD_PLUGIN_ROUTEROS
  pkglib_LTLIBRARIES += routeros.la
  routeros_la_SOURCES = routeros.c
@@@ -1088,14 -1044,6 +1088,14 @@@ collectd_LDADD += "-dlopen" target_set.
  collectd_DEPENDENCIES += target_set.la
  endif
  
 +if BUILD_PLUGIN_TARGET_V5UPGRADE
 +pkglib_LTLIBRARIES += target_v5upgrade.la
 +target_v5upgrade_la_SOURCES = target_v5upgrade.c
 +target_v5upgrade_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" target_v5upgrade.la
 +collectd_DEPENDENCIES += target_v5upgrade.la
 +endif
 +
  if BUILD_PLUGIN_TCPCONNS
  pkglib_LTLIBRARIES += tcpconns.la
  tcpconns_la_SOURCES = tcpconns.c
@@@ -1132,14 -1080,6 +1132,14 @@@ collectd_LDADD += "-dlopen" thermal.l
  collectd_DEPENDENCIES += thermal.la
  endif
  
 +if BUILD_PLUGIN_THRESHOLD
 +pkglib_LTLIBRARIES += threshold.la
 +threshold_la_SOURCES = threshold.c
 +threshold_la_LDFLAGS = -module -avoid-version
 +collectd_LDADD += "-dlopen" threshold.la
 +collectd_DEPENDENCIES += threshold.la
 +endif
 +
  if BUILD_PLUGIN_TOKYOTYRANT
  pkglib_LTLIBRARIES += tokyotyrant.la
  tokyotyrant_la_SOURCES = tokyotyrant.c
@@@ -1158,6 -1098,7 +1158,6 @@@ pkglib_LTLIBRARIES += unixsock.l
  unixsock_la_SOURCES = unixsock.c \
                      utils_cmd_flush.h utils_cmd_flush.c \
                      utils_cmd_getval.h utils_cmd_getval.c \
 -                    utils_cmd_getthreshold.h utils_cmd_getthreshold.c \
                      utils_cmd_listval.h utils_cmd_listval.c \
                      utils_cmd_putval.h utils_cmd_putval.c \
                      utils_cmd_putnotif.h utils_cmd_putnotif.c
@@@ -1204,16 -1145,6 +1204,16 @@@ collectd_LDADD += "-dlopen" uuid.l
  collectd_DEPENDENCIES += uuid.la
  endif
  
 +if BUILD_PLUGIN_VARNISH
 +pkglib_LTLIBRARIES += varnish.la
 +varnish_la_SOURCES = varnish.c
 +varnish_la_LDFLAGS = -module -avoid-version
 +varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
 +varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
 +collectd_LDADD += "-dlopen" varnish.la
 +collectd_DEPENDENCIES += varnish.la
 +endif
 +
  if BUILD_PLUGIN_VMEM
  pkglib_LTLIBRARIES += vmem.la
  vmem_la_SOURCES = vmem.c
@@@ -1253,16 -1184,6 +1253,16 @@@ endi
  collectd_DEPENDENCIES += write_http.la
  endif
  
 +if BUILD_PLUGIN_WRITE_REDIS
 +pkglib_LTLIBRARIES += write_redis.la
 +write_redis_la_SOURCES = write_redis.c
 +write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
 +write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
 +write_redis_la_LIBADD = -lcredis
 +collectd_LDADD += "-dlopen" write_redis.la
 +collectd_DEPENDENCIES += write_redis.la
 +endif
 +
  if BUILD_PLUGIN_XMMS
  pkglib_LTLIBRARIES += xmms.la
  xmms_la_SOURCES = xmms.c
@@@ -1287,14 -1208,12 +1287,14 @@@ dist_man_MANS = collectd.1 
                collectd.conf.5 \
                collectd-email.5 \
                collectd-exec.5 \
 +              collectdctl.1 \
                collectd-java.5 \
                collectdmon.1 \
                collectd-nagios.1 \
                collectd-perl.5 \
                collectd-python.5 \
                collectd-snmp.5 \
 +              collectd-threshold.5 \
                collectd-unixsock.5 \
                types.db.5
  
@@@ -1305,7 -1224,6 +1305,7 @@@ EXTRA_DIST = types.db pinba.prot
  EXTRA_DIST +=   collectd.conf.pod \
                collectd-email.pod \
                collectd-exec.pod \
 +              collectdctl.pod \
                collectd-java.pod \
                collectdmon.pod \
                collectd-nagios.pod \
                collectd-python.pod \
                collectd.pod \
                collectd-snmp.pod \
 +              collectd-threshold.pod \
                collectd-unixsock.pod \
                postgresql_default.conf \
                types.db.pod
diff --combined src/collectd.conf.pod
@@@ -72,19 -72,15 +72,19 @@@ options are allowed inside a B<LoadPlug
  If enabled, collectd will export all global symbols of the plugin (and of all
  libraries loaded as dependencies of the plugin) and, thus, makes those symbols
  available for resolving unresolved symbols in subsequently loaded plugins if
 -that is supported by your system. By default, this is disabled.
 +that is supported by your system.
  
 -This is useful (or possibly even required), e.E<nbsp>g., when loading a plugin
 -that embeds some scripting language into the daemon (e.E<nbsp>g. the C<perl>
 -or C<python> plugins). Scripting languages usually provide means to load
 +This is useful (or possibly even required), e.g., when loading a plugin that
 +embeds some scripting language into the daemon (e.g. the I<Perl> and
 +I<Python plugins>). Scripting languages usually provide means to load
  extensions written in C. Those extensions require symbols provided by the
 -interpreter, which is loaded as a dependency of the respective collectd
 -plugin. See the documentation of those plugins (e.E<nbsp>g.,
 -L<collectd-perl(5)> or L<collectd-python(5)>) for details.
 +interpreter, which is loaded as a dependency of the respective collectd plugin.
 +See the documentation of those plugins (e.g., L<collectd-perl(5)> or
 +L<collectd-python(5)>) for details.
 +
 +By default, this is disabled. As a special exception, if the plugin name is
 +either C<perl> or C<python>, the default is changed to enabled in order to keep
 +the average user from ever having to deal with this low level linking stuff.
  
  =back
  
@@@ -145,7 -141,7 +145,7 @@@ missing when no update has been receive
  this setting uses iterations, the maximum allowed time without update depends
  on the I<Interval> information contained in each value list. This is used in
  the I<Threshold> configuration to dispatch notifications about missing values,
 -see L<"THRESHOLD CONFIGURATION"> below.
 +see L<collectd-threshold(5)> for details.
  
  =item B<ReadThreads> I<Num>
  
@@@ -163,8 -159,13 +163,8 @@@ hostname will be determined using the L
  
  If B<Hostname> is determined automatically this setting controls whether or not
  the daemon should try to figure out the "fully qualified domain name", FQDN.
 -This is done using a lookup of the name returned by C<gethostname>.
 -
 -Using this feature (i.E<nbsp>e. setting this option to B<true>) is recommended.
 -However, to preserve backwards compatibility the default is set to B<false>.
 -The sample config file that is installed with C<makeE<nbsp>install> includes a
 -line which sets this option, though, so that default installations will have
 -this setting enabled.
 +This is done using a lookup of the name returned by C<gethostname>. This option
 +is enabled by default.
  
  =item B<PreCacheChain> I<ChainName>
  
@@@ -189,143 -190,6 +189,143 @@@ A list of all plugins and a short summa
  F<README> file shipped with the sourcecode and hopefully binary packets as
  well.
  
 +=head2 Plugin C<amqp>
 +
 +The I<AMQMP plugin> can be used to communicate with other instances of
 +I<collectd> or third party applications using an AMQP message broker. Values
 +are sent to or received from the broker, which handles routing, queueing and
 +possibly filtering or messages.
 +
 + <Plugin "amqp">
 +   # Send values to an AMQP broker
 +   <Publish "some_name">
 +     Host "localhost"
 +     Port "5672"
 +     VHost "/"
 +     User "guest"
 +     Password "guest"
 +     Exchange "amq.fanout"
 + #   ExchangeType "fanout"
 + #   RoutingKey "collectd"
 + #   Persistent false
 + #   Format "command"
 + #   StoreRates false
 +   </Publish>
 +   
 +   # Receive values from an AMQP broker
 +   <Subscribe "some_name">
 +     Host "localhost"
 +     Port "5672"
 +     VHost "/"
 +     User "guest"
 +     Password "guest"
 +     Exchange "amq.fanout"
 + #   ExchangeType "fanout"
 + #   Queue "queue_name"
 + #   RoutingKey "collectd.#"
 +   </Subscribe>
 + </Plugin>
 +
 +The plugin's configuration consists of a number of I<Publish> and I<Subscribe>
 +blocks, which configure sending and receiving of values respectively. The two
 +blocks are very similar, so unless otherwise noted, an option can be used in
 +either block. The name given in the blocks starting tag is only used for
 +reporting messages, but may be used to support I<flushing> of certain
 +I<Publish> blocks in the future.
 +
 +=over 4
 +
 +=item B<Host> I<Host>
 +
 +Hostname or IP-address of the AMQP broker. Defaults to the default behavior of
 +the underlying communications library, I<rabbitmq-c>, which is "localhost".
 +
 +=item B<Port> I<Port>
 +
 +Service name or port number on which the AMQP broker accepts connections. This
 +argument must be a string, even if the numeric form is used. Defaults to
 +"5672".
 +
 +=item B<VHost> I<VHost>
 +
 +Name of the I<virtual host> on the AMQP broker to use. Defaults to "/".
 +
 +=item B<User> I<User>
 +
 +=item B<Password> I<Password>
 +
 +Credentials used to authenticate to the AMQP broker. By default "guest"/"guest"
 +is used.
 +
 +=item B<Exchange> I<Exchange>
 +
 +In I<Publish> blocks, this option specifies the I<exchange> to send values to.
 +By default, "amq.fanout" will be used.
 +
 +In I<Subscribe> blocks this option is optional. If given, a I<binding> between
 +the given exchange and the I<queue> is created, using the I<routing key> if
 +configured. See the B<Queue> and B<RoutingKey> options below.
 +
 +=item B<ExchangeType> I<Type>
 +
 +If given, the plugin will try to create the configured I<exchange> with this
 +I<type> after connecting. When in a I<Subscribe> block, the I<queue> will then
 +be bound to this exchange.
 +
 +=item B<Queue> I<Queue> (Subscribe only)
 +
 +Configures the I<queue> name to subscribe to. If no queue name was configures
 +explicitly, a unique queue name will be created by the broker.
 +
 +=item B<RoutingKey> I<Key>
 +
 +In I<Publish> blocks, this configures the routing key to set on all outgoing
 +messages. If not given, the routing key will be computed from the I<identifier>
 +of the value. The host, plugin, type and the two instances are concatenated
 +together using dots as the separator and all containing dots replaced with
 +slashes. For example "collectd.host/example/com.cpu.0.cpu.user". This makes it
 +possible to receive only specific values using a "topic" exchange.
 +
 +In I<Subscribe> blocks, configures the I<routing key> used when creating a
 +I<binding> between an I<exchange> and the I<queue>. The usual wildcards can be
 +used to filter messages when using a "topic" exchange. If you're only
 +interested in CPU statistics, you could use the routing key "collectd.*.cpu.#"
 +for example.
 +
 +=item B<Persistent> B<true>|B<false> (Publish only)
 +
 +Selects the I<delivery method> to use. If set to B<true>, the I<persistent>
 +mode will be used, i.e. delivery is guaranteed. If set to B<false> (the
 +default), the I<transient> delivery mode will be used, i.e. messages may be
 +lost due to high load, overflowing queues or similar issues.
 +
 +=item B<Format> B<Command>|B<JSON> (Publish only)
 +
 +Selects the format in which messages are sent to the broker. If set to
 +B<Command> (the default), values are sent as C<PUTVAL> commands which are
 +identical to the syntax used by the I<Exec> and I<UnixSock plugins>. In this
 +case, the C<Content-Type> header field will be set to C<text/collectd>.
 +
 +If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
 +an easy and straight forward exchange format. The C<Content-Type> header field
 +will be set to C<application/json>.
 +
 +A subscribing client I<should> use the C<Content-Type> header field to
 +determine how to decode the values. Currently, the I<AMQP plugin> itself can
 +only decode the B<Command> format.
 +
 +=item B<StoreRates> B<true>|B<false> (Publish only)
 +
 +Determines whether or not C<COUNTER>, C<DERIVE> and C<ABSOLUTE> data sources
 +are converted to a I<rate> (i.e. a C<GAUGE> value). If set to B<false> (the
 +default), no conversion is performed. Otherwise the conversion is performed
 +using the internal value cache.
 +
 +Please note that currently this option is only used if the B<Format> option has
 +been set to B<JSON>.
 +
 +=back
 +
  =head2 Plugin C<apache>
  
  To configure the C<apache>-plugin you first need to configure the Apache
@@@ -344,25 -208,7 +344,25 @@@ Since its C<mod_status> module is very 
  also supported. It introduces a new field, called C<BusyServers>, to count the
  number of currently connected clients. This field is also supported.
  
 -The following options are accepted by the C<apache>-plugin:
 +The configuration of the I<Apache> plugin consists of one or more
 +C<E<lt>InstanceE<nbsp>/E<gt>> blocks. Each block requires one string argument
 +as the instance name. For example:
 +
 + <Plugin "apache">
 +   <Instance "www1">
 +     URL "http://www1.example.com/mod_status?auto"
 +   </Instance>
 +   <Instance "www2">
 +     URL "http://www2.example.com/mod_status?auto"
 +   </Instance>
 + </Plugin>
 +
 +The instance name will be used as the I<plugin instance>. To emulate the old
 +(versionE<nbsp>4) behavior, you can use an empty string (""). In order for the
 +plugin to work correctly, each instance name must be unique. This is not
 +enforced by the plugin and it is your responsibility to ensure it.
 +
 +The following options are accepted within each I<Instance> block:
  
  =over 4
  
  
  Sets the URL of the C<mod_status> output. This needs to be the output generated
  by C<ExtendedStatus on> and it needs to be the machine readable output
 -generated by appending the C<?auto> argument.
 +generated by appending the C<?auto> argument. This option is I<mandatory>.
  
  =item B<User> I<Username>
  
@@@ -739,6 -585,22 +739,6 @@@ runtime statistics module of CouchD
      </URL>
    </Plugin>
  
 -Another CouchDB example:
 -The following example will collect the status values from each database:
 -
 -  <URL "http://localhost:5984/_all_dbs">
 -    Instance "dbs"
 -    <Key "*/doc_count">
 -      Type "gauge"
 -    </Key>
 -    <Key "*/doc_del_count">
 -      Type "counter"
 -    </Key>
 -    <Key "*/disk_size">
 -      Type "bytes"
 -    </Key>
 -  </URL>
 -
  In the B<Plugin> block, there may be one or more B<URL> blocks, each defining
  a URL to be fetched via HTTP (using libcurl) and one or more B<Key> blocks.
  The B<Key> string argument must be in a path format, which is used to collect a
@@@ -1168,6 -1030,22 +1168,6 @@@ Report using the device name rather tha
  (the default), it will report a disk as "root", but with it I<true>, it will be
  "sda1" (or whichever).
  
 -=item B<ReportReserved> B<true>|B<false>
 -
 -When enabled, the blocks reserved for root are reported separately. When
 -disabled (the default for backwards compatibility reasons) the reserved space
 -will be included in the "free" space.
 -
 -When disabled, the "df" type will be used to store "free" and "used" space. The
 -mount point or disk name (see option B<ReportByDevice>) is used as type
 -instance in this case (again: backwards compatibility).
 -
 -When enabled, the type "df_complex" is used and three files are created. The
 -mount point or disk name is used as plugin instance and the type instance is
 -set to "free", "reserved" and "used" as appropriate.
 -
 -Enabling this option is recommended.
 -
  =item B<ReportInodes> B<true>|B<false>
  
  Enables or disables reporting of free, reserved and used inodes. Defaults to
@@@ -1487,6 -1365,13 +1487,6 @@@ Hostname to connect to. Defaults to B<1
  
  TCP-Port to connect to. Defaults to B<7634>.
  
 -=item B<TranslateDevicename> I<true>|I<false>
 -
 -If enabled, translate the disk names to major/minor device numbers
 -(e.E<nbsp>g. "8-0" for /dev/sda). For backwards compatibility this defaults to
 -I<true> but it's recommended to disable it as it will probably be removed in
 -the next major version.
 -
  =back
  
  =head2 Plugin C<interface>
@@@ -1714,16 -1599,6 +1714,16 @@@ You can also specify combinations of th
  means to concatenate the guest name and UUID (with a literal colon character
  between, thus I<"foo:1234-1234-1234-1234">).
  
 +=item B<InterfaceFormat> B<name>|B<address>
 +
 +When the libvirt plugin logs interface data, it sets the name of the collected
 +data according to this setting. The default is to use the path as provided by
 +the hypervisor (the "dev" property of the target node), which is equal to
 +setting B<name>.
 +
 +B<address> means use the interface's mac address. This is useful since the
 +interface path might change between reboots of a guest or across migrations.
 +
  =back
  
  =head2 Plugin C<logfile>
@@@ -1742,8 -1617,8 +1742,8 @@@ debugging support
  
  Sets the file to write log messages to. The special strings B<stdout> and
  B<stderr> can be used to write to the standard output and standard error
 -channels, respectively. This, of course, only makes much sense when collectd is
 -running in foreground- or non-daemon-mode.
 +channels, respectively. This, of course, only makes much sense when I<collectd>
 +is running in foreground- or non-daemon-mode.
  
  =item B<Timestamp> B<true>|B<false>
  
@@@ -1760,33 -1635,6 +1760,33 @@@ B<Note>: There is no need to notify th
  log file (e.E<nbsp>g. when rotating the logs). The plugin reopens the file
  for each line it writes.
  
 +=head2 Plugin C<lpar>
 +
 +The I<LPAR plugin> reads CPU statistics of I<Logical Partitions>, a
 +virtualization technique for IBM POWER processors. It takes into account CPU
 +time stolen from or donated to a partition, in addition to the usual user,
 +system, I/O statistics.
 +
 +The following configuration options are available:
 +
 +=over 4
 +
 +=item B<CpuPoolStats> B<false>|B<true>
 +
 +When enabled, statistics about the processor pool are read, too. The partition
 +needs to have pool authority in order to be able to acquire this information.
 +Defaults to false.
 +
 +=item B<ReportBySerial> B<false>|B<true>
 +
 +If enabled, the serial of the physical machine the partition is currently
 +running on is reported as I<hostname> and the logical hostname of the machine
 +is reported in the I<plugin instance>. Otherwise, the logical hostname will be
 +used (just like other plugins) and the I<plugin instance> will be empty.
 +Defaults to false.
 +
 +=back
 +
  =head2 Plugin C<mbmon>
  
  The C<mbmon plugin> uses mbmon to retrieve temperature, voltage, etc.
@@@ -2012,7 -1860,7 +2012,7 @@@ B<Collect> option is mandatory
  The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
  one or more databases when started and keeps the connection up as long as
  possible. When the connection is interrupted for whatever reason it will try
 -to re-connect. The plugin will complaint loudly in case anything goes wrong.
 +to re-connect. The plugin will complain loudly in case anything goes wrong.
  
  This plugin issues the MySQL C<SHOW STATUS> / C<SHOW GLOBAL STATUS> command
  and collects information about MySQL network traffic, executed statements,
@@@ -2654,10 -2502,18 +2654,18 @@@ The default IPv6 multicast group is C<f
  multicast group is C<239.192.74.66>. The default I<UDP> port is B<25826>.
  
  Both, B<Server> and B<Listen> can be used as single option or as block. When
- used as block, given options are valid for this socket only. For example:
+ used as block, given options are valid for this socket only. The following
+ example will export the metrics twice: Once to an "internal" server (without
+ encryption and signing) and one to an external server (with cryptographic
+ signature):
  
   <Plugin "network">
+    # Export to an internal server
+    # (demonstrates usage without additional options)
     Server "collectd.internal.tld"
+    
+    # Export to an external server
+    # (demonstrates usage with signature options)
     <Server "collectd.external.tld">
       SecurityLevel "sign"
       Username "myhostname"
@@@ -2786,18 -2642,7 +2794,18 @@@ operating systems
  =item B<MaxPacketSize> I<1024-65535>
  
  Set the maximum size for datagrams received over the network. Packets larger
 -than this will be truncated.
 +than this will be truncated. Defaults to 1452E<nbsp>bytes, which is the maximum
 +payload size that can be transmitted in one Ethernet frame using IPv6E<nbsp>/
 +UDP.
 +
 +On the server side, this limit should be set to the largest value used on
 +I<any> client. Likewise, the value on the client must not be larger than the
 +value on the server, or data will be lost.
 +
 +B<Compatibility:> Versions prior to I<versionE<nbsp>4.8> used a fixed sized
 +buffer of 1024E<nbsp>bytes. Versions I<4.8>, I<4.9> and I<4.10> used a default
 +value of 1024E<nbsp>bytes to avoid problems when sending data to an older
 +server.
  
  =item B<Forward> I<true|false>
  
@@@ -2808,6 -2653,16 +2816,6 @@@ the same multicast group. While this re
  necessary it's not a huge problem since the plugin has a duplicate detection,
  so the values will not loop.
  
 -=item B<CacheFlush> I<Seconds>
 -
 -For each host/plugin/type combination the C<network plugin> caches the time of
 -the last value being sent or received. Every I<Seconds> seconds the plugin
 -searches and removes all entries that are older than I<Seconds> seconds, thus
 -freeing the unused memory again. Since this process is somewhat expensive and
 -normally doesn't do much, this value should not be too small. The default is
 -1800 seconds, but setting this to 86400 seconds (one day) will not do much harm
 -either.
 -
  =item B<ReportStats> B<true>|B<false>
  
  The network plugin cannot only receive and send statistics, it can also create
@@@ -3442,6 -3297,11 +3450,6 @@@ allowed as long as a single non-empty c
  
  The returned lines will be handled separately one after another.
  
 -=item B<Query> I<sql query statement>
 -
 -This is a deprecated synonym for B<Statement>. It will be removed in version 5
 -of collectd.
 -
  =item B<Param> I<hostname>|I<database>|I<username>|I<interval>
  
  Specify the parameters which should be passed to the SQL query. The parameters
@@@ -3517,6 -3377,21 +3525,6 @@@ This option is required inside a B<Resu
  times. If multiple B<ValuesFrom> options are specified, the columns are read
  in the given order.
  
 -=item B<Column> I<type> [I<type instance>]
 -
 -This is a deprecated alternative to a B<Result> block. It will be removed in
 -version 5 of collectd. It is equivalent to the following B<Result> block:
 -
 -  <Result>
 -    Type I<type>
 -    InstancePrefix I<type instance>
 -    ValuesFrom I<name of the x. column>
 -  </Result>
 -
 -The order of the B<Column> options defines which columns of the query result
 -should be used. The first option specifies the data found in the first column,
 -the second option that of the second column, and so on.
 -
  =item B<MinVersion> I<version>
  
  =item B<MaxVersion> I<version>
@@@ -3531,6 -3406,13 +3539,6 @@@ The I<version> has to be specified as t
  and patch-level versions, each represented as two-decimal-digit numbers. For
  example, version 8.2.3 will become 80203.
  
 -=item B<MinPGVersion> I<version>
 -
 -=item B<MaxPGVersion> I<version>
 -
 -These are deprecated synonyms for B<MinVersion> and B<MaxVersion>
 -respectively. They will be removed in version 5 of collectd.
 -
  =back
  
  The following predefined queries are available (the definitions can be found
@@@ -3941,52 -3823,6 +3949,52 @@@ Defaults to B<false>
  
  =back
  
 +=head2 Plugin C<redis>
 +
 +The I<Redis plugin> connects to one or more Redis servers and gathers
 +information about each server's state. For each server there is a I<Node> block
 +which configures the connection parameters for this node.
 +
 +  <Plugin redis>
 +    <Node "example">
 +        Host "localhost"
 +        Port "6379"
 +        Timeout 2000
 +    </Node>
 +  </Plugin>
 +
 +The information shown in the synopsis above is the I<default configuration>
 +which is used by the plugin if no configuration is present.
 +
 +=over 4
 +
 +=item B<Node> I<Nodename>
 +
 +The B<Node> block identifies a new Redis node, that is a new Redis instance
 +running in an specified host and port. The name for node is a canonical
 +identifier which is used as I<plugin instance>. It is limited to
 +64E<nbsp>characters in length.
 +
 +=item B<Host> I<Hostname>
 +
 +The B<Host> option is the hostname or IP-address where the Redis instance is
 +running on.
 +
 +=item B<Port> I<Port>
 +
 +The B<Port> option is the TCP port on which the Redis instance accepts
 +connections. Either a service name of a port number may be given. Please note
 +that numerical port numbers must be given as a string, too.
 +
 +=item B<Timeout> I<Timeout in miliseconds>
 +
 +The B<Timeout> option set the socket timeout for node response. Since the Redis
 +read function is blocking, you should keep this value as low as possible. Keep
 +in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
 +than B<Interval> defined globally.
 +
 +=back
 +
  =head2 Plugin C<rrdcached>
  
  The C<rrdcached> plugin uses the RRDtool accelerator daemon, L<rrdcached(1)>,
@@@ -4150,7 -3986,7 +4158,7 @@@ because all values were added to the in
  
  =head2 Plugin C<sensors>
  
 -The C<sensors plugin> uses B<lm_sensors> to retrieve sensor-values. This means
 +The I<Sensors plugin> uses B<lm_sensors> to retrieve sensor-values. This means
  that all the needed modules have to be loaded and lm_sensors has to be
  configured (most likely by editing F</etc/sensors.conf>. Read
  L<sensors.conf(5)> for details.
@@@ -4185,25 -4021,6 +4193,25 @@@ Since the configuration of the C<snmp p
  other plugins, its documentation has been moved to an own manpage,
  L<collectd-snmp(5)>. Please see there for details.
  
 +=head2 Plugin C<swap>
 +
 +The I<Swap plugin> collects information about used and available swap space. On
 +I<Solaris>, the following options are available:
 +
 +=over 4
 +
 +=item B<ReportByDevice> B<false>|B<true>
 +
 +Configures how to report physical swap devices. If set to B<false> is used (the
 +default), the summary over all swap devices is reported only, i.e. the globally
 +used and available space over all devices. If B<true> is configured, the used
 +and available space of each device will be reported separately.
 +
 +This option is only available if the I<Swap plugin> can use the L<swapctl(2)>
 +mechanism under I<Solaris>.
 +
 +=back
 +
  =head2 Plugin C<syslog>
  
  =over 4
@@@ -4553,7 -4370,7 +4561,7 @@@ port in numeric form
  
  =item B<ForceUseProcfs> I<true>|I<false>
  
 -By default, the C<thermal> plugin tries to read the statistics from the Linux
 +By default, the I<Thermal plugin> tries to read the statistics from the Linux
  C<sysfs> interface. If that is not available, the plugin falls back to the
  C<procfs> interface. By setting this option to I<true>, you can force the
  plugin to use the latter. This option defaults to I<false>.
@@@ -4573,18 -4390,9 +4581,18 @@@ selection is configured at all, B<all> 
  
  =back
  
 +=head2 Plugin C<threshold>
 +
 +The I<Threshold plugin> checks values collected or received by I<collectd>
 +against a configurable I<threshold> and issues I<notifications> if values are
 +out of bounds.
 +
 +Documentation for this plugin is available in the L<collectd-threshold(5)>
 +manual page.
 +
  =head2 Plugin C<tokyotyrant>
  
 -The C<tokyotyrant plugin> connects to a TokyoTyrant server and collects a
 +The I<TokyoTyrant plugin> connects to a TokyoTyrant server and collects a
  couple metrics: number of records, and database size on disk.
  
  =over 4
@@@ -4621,13 -4429,6 +4629,13 @@@ Change the file permissions of the UNIX
  permissions must be given as a numeric, octal value as you would pass to
  L<chmod(1)>. Defaults to B<0770>.
  
 +=item B<DeleteSocket> B<false>|B<true>
 +
 +If set to B<true>, delete the socket file before calling L<bind(2)>, if a file
 +with the given name already exists. If I<collectd> crashes a socket file may be
 +left over, preventing the daemon from opening a new socket when restarted.
 +Since this is potentially dangerous, this defaults to B<false>.
 +
  =back
  
  =head2 Plugin C<uuid>
@@@ -4671,68 -4472,6 +4679,68 @@@ Take the UUID from the given file (defa
  
  =back
  
 +=head2 Plugin C<varnish>
 +
 +The Varnish plugin collects information about Varnish, an HTTP accelerator.
 +
 +=over 4
 +
 +=item B<CollectCache> B<true>|B<false>
 +
 +Cache hits and misses. True by default.
 +
 +=item B<CollectConnections> B<true>|B<false>
 +
 +Number of client connections received, accepted and dropped. True by default.
 +
 +=item B<CollectBackend> B<true>|B<false>
 +
 +Back-end connection statistics, such as successful, reused,
 +and closed connections. True by default.
 +
 +=item B<CollectSHM> B<true>|B<false>
 +
 +Statistics about the shared memory log, a memory region to store
 +log messages which is flushed to disk when full. True by default.
 +
 +=item B<CollectESI> B<true>|B<false>
 +
 +Edge Side Includes (ESI) parse statistics. False by default.
 +
 +=item B<CollectFetch> B<true>|B<false>
 +
 +Statistics about fetches (HTTP requests sent to the backend). False by default.
 +
 +=item B<CollectHCB> B<true>|B<false>
 +
 +Inserts and look-ups in the crit bit tree based hash. Look-ups are
 +divided into locked and unlocked look-ups. False by default.
 +
 +=item B<CollectSMA> B<true>|B<false>
 +
 +malloc or umem (umem_alloc(3MALLOC) based) storage statistics.
 +The umem storage component is Solaris specific. False by default.
 +
 +=item B<CollectSMS> B<true>|B<false>
 +
 +synth (synthetic content) storage statistics. This storage
 +component is used internally only. False by default.
 +
 +=item B<CollectSM> B<true>|B<false>
 +
 +file (memory mapped file) storage statistics. False by default.
 +
 +=item B<CollectTotals> B<true>|B<false>
 +
 +Collects overview counters, such as the number of sessions created,
 +the number of requests and bytes transferred. False by default.
 +
 +=item B<CollectWorkers> B<true>|B<false>
 +
 +Collect statistics about worker threads. False by default.
 +
 +=back
 +
  =head2 Plugin C<vmem>
  
  The C<vmem> plugin collects information about the usage of virtual memory.
@@@ -4831,6 -4570,170 +4839,170 @@@ number
  
  =back
  
+ =head1 THRESHOLD CONFIGURATION
+ Starting with version C<4.3.0> collectd has support for B<monitoring>. By that
+ we mean that the values are not only stored or sent somewhere, but that they
+ are judged and, if a problem is recognized, acted upon. The only action
+ collectd takes itself is to generate and dispatch a "notification". Plugins can
+ register to receive notifications and perform appropriate further actions.
+ Since systems and what you expect them to do differ a lot, you can configure
+ B<thresholds> for your values freely. This gives you a lot of flexibility but
+ also a lot of responsibility.
+ Every time a value is out of range a notification is dispatched. This means
+ that the idle percentage of your CPU needs to be less then the configured
+ threshold only once for a notification to be generated. There's no such thing
+ as a moving average or similar - at least not now.
+ Also, all values that match a threshold are considered to be relevant or
+ "interesting". As a consequence collectd will issue a notification if they are
+ not received for B<Timeout> iterations. The B<Timeout> configuration option is
+ explained in section L<"GLOBAL OPTIONS">. If, for example, B<Timeout> is set to
+ "2" (the default) and some hosts sends it's CPU statistics to the server every
+ 60 seconds, a notification will be dispatched after about 120 seconds. It may
+ take a little longer because the timeout is checked only once each B<Interval>
+ on the server.
+ When a value comes within range again or is received after it was missing, an
+ "OKAY-notification" is dispatched.
+ Here is a configuration example to get you started. Read below for more
+ information.
+  <Threshold>
+    <Type "foo">
+      WarningMin    0.00
+      WarningMax 1000.00
+      FailureMin    0.00
+      FailureMax 1200.00
+      Invert false
+      Instance "bar"
+    </Type>
+    <Plugin "interface">
+      Instance "eth0"
+      <Type "if_octets">
+        FailureMax 10000000
+        DataSource "rx"
+      </Type>
+    </Plugin>
+    <Host "hostname">
+      <Type "cpu">
+        Instance "idle"
+        FailureMin 10
+      </Type>
+      <Plugin "memory">
+        <Type "memory">
+          Instance "cached"
+          WarningMin 100000000
+        </Type>
+      </Plugin>
+    </Host>
+  </Threshold>
+ There are basically two types of configuration statements: The C<Host>,
+ C<Plugin>, and C<Type> blocks select the value for which a threshold should be
+ configured. The C<Plugin> and C<Type> blocks may be specified further using the
+ C<Instance> option. You can combine the block by nesting the blocks, though
+ they must be nested in the above order, i.E<nbsp>e. C<Host> may contain either
+ C<Plugin> and C<Type> blocks, C<Plugin> may only contain C<Type> blocks and
+ C<Type> may not contain other blocks. If multiple blocks apply to the same
+ value the most specific block is used.
+ The other statements specify the threshold to configure. They B<must> be
+ included in a C<Type> block. Currently the following statements are recognized:
+ =over 4
+ =item B<FailureMax> I<Value>
+ =item B<WarningMax> I<Value>
+ Sets the upper bound of acceptable values. If unset defaults to positive
+ infinity. If a value is greater than B<FailureMax> a B<FAILURE> notification
+ will be created. If the value is greater than B<WarningMax> but less than (or
+ equal to) B<FailureMax> a B<WARNING> notification will be created.
+ =item B<FailureMin> I<Value>
+ =item B<WarningMin> I<Value>
+ Sets the lower bound of acceptable values. If unset defaults to negative
+ infinity. If a value is less than B<FailureMin> a B<FAILURE> notification will
+ be created. If the value is less than B<WarningMin> but greater than (or equal
+ to) B<FailureMin> a B<WARNING> notification will be created.
+ =item B<DataSource> I<DSName>
+ Some data sets have more than one "data source". Interesting examples are the
+ C<if_octets> data set, which has received (C<rx>) and sent (C<tx>) bytes and
+ the C<disk_ops> data set, which holds C<read> and C<write> operations. The
+ system load data set, C<load>, even has three data sources: C<shortterm>,
+ C<midterm>, and C<longterm>.
+ Normally, all data sources are checked against a configured threshold. If this
+ is undesirable, or if you want to specify different limits for each data
+ source, you can use the B<DataSource> option to have a threshold apply only to
+ one data source.
+ =item B<Invert> B<true>|B<false>
+ If set to B<true> the range of acceptable values is inverted, i.E<nbsp>e.
+ values between B<FailureMin> and B<FailureMax> (B<WarningMin> and
+ B<WarningMax>) are not okay. Defaults to B<false>.
+ =item B<Persist> B<true>|B<false>
+ Sets how often notifications are generated. If set to B<true> one notification
+ will be generated for each value that is out of the acceptable range. If set to
+ B<false> (the default) then a notification is only generated if a value is out
+ of range but the previous value was okay.
+ This applies to missing values, too: If set to B<true> a notification about a
+ missing value is generated once every B<Interval> seconds. If set to B<false>
+ only one such notification is generated until the value appears again.
+ =item B<Percentage> B<true>|B<false>
+ If set to B<true>, the minimum and maximum values given are interpreted as
+ percentage value, relative to the other data sources. This is helpful for
+ example for the "df" type, where you may want to issue a warning when less than
+ 5E<nbsp>% of the total space is available. Defaults to B<false>.
+ =item B<Hits> I<Number>
+ Delay creating the notification until the threshold has been passed I<Number>
+ times. When a notification has been generated, or when a subsequent value is
+ inside the threshold, the counter is reset. If, for example, a value is
+ collected once every 10E<nbsp>seconds and B<Hits> is set to 3, a notification
+ will be dispatched at most once every 30E<nbsp>seconds.
+ This is useful when short bursts are not a problem. If, for example, 100% CPU
+ usage for up to a minute is normal (and data is collected every
+ 10E<nbsp>seconds), you could set B<Hits> to B<6> to account for this.
+ =item B<Hysteresis> I<Number>
+ When set to non-zero, a hysteresis value is applied when checking minimum and
+ maximum bounds. This is useful for values that increase slowly and fluctuate a
+ bit while doing so. When these values come close to the threshold, they may
+ "flap", i.e. switch between failure / warning case and okay case repeatedly.
+ If, for example, the threshold is configures as
+   WarningMax 100.0
+   Hysteresis 1.0
+ then a I<Warning> notification is created when the value exceeds I<101> and the
+ corresponding I<Okay> notification is only created once the value falls below
+ I<99>, thus avoiding the "flapping".
+ =back
  =head1 FILTER CONFIGURATION
  
  Starting with collectd 4.6 there is a powerful filtering infrastructure
diff --combined src/common.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/common.c
 - * Copyright (C) 2005-2009  Florian octo Forster
 + * Copyright (C) 2005-2010  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -16,7 -16,7 +16,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Niki W. Waibel <niki.waibel@gmx.net>
   *   Sebastian Harl <sh at tokkee.org>
   *   Michał Mirosław <mirq-linux at rere.qmqm.pl>
@@@ -29,7 -29,6 +29,7 @@@
  #include "collectd.h"
  #include "common.h"
  #include "plugin.h"
 +#include "utils_cache.h"
  
  #if HAVE_PTHREAD_H
  # include <pthread.h>
  # include <math.h>
  #endif
  
 -/* for ntohl and htonl */
 -#if HAVE_ARPA_INET_H
 -# include <arpa/inet.h>
 -#endif
 -
  /* for getaddrinfo */
  #include <sys/types.h>
  #include <sys/socket.h>
  # include <netinet/in.h>
  #endif
  
 +/* for ntohl and htonl */
 +#if HAVE_ARPA_INET_H
 +# include <arpa/inet.h>
 +#endif
 +
  #ifdef HAVE_LIBKSTAT
  extern kstat_ctl_t *kc;
  #endif
@@@ -804,75 -803,6 +804,75 @@@ int format_name (char *ret, int ret_len
        return (0);
  } /* int format_name */
  
 +int format_values (char *ret, size_t ret_len, /* {{{ */
 +              const data_set_t *ds, const value_list_t *vl,
 +              _Bool store_rates)
 +{
 +        size_t offset = 0;
 +        int status;
 +        int i;
 +        gauge_t *rates = NULL;
 +
 +        assert (0 == strcmp (ds->type, vl->type));
 +
 +        memset (ret, 0, ret_len);
 +
 +#define BUFFER_ADD(...) do { \
 +        status = ssnprintf (ret + offset, ret_len - offset, \
 +                        __VA_ARGS__); \
 +        if (status < 1) \
 +        { \
 +                sfree (rates); \
 +                return (-1); \
 +        } \
 +        else if (((size_t) status) >= (ret_len - offset)) \
 +        { \
 +                sfree (rates); \
 +                return (-1); \
 +        } \
 +        else \
 +                offset += ((size_t) status); \
 +} while (0)
 +
 +        BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
 +
 +        for (i = 0; i < ds->ds_num; i++)
 +        {
 +                if (ds->ds[i].type == DS_TYPE_GAUGE)
 +                        BUFFER_ADD (":%f", vl->values[i].gauge);
 +                else if (store_rates)
 +                {
 +                        if (rates == NULL)
 +                                rates = uc_get_rate (ds, vl);
 +                        if (rates == NULL)
 +                        {
 +                                WARNING ("format_values: "
 +                                              "uc_get_rate failed.");
 +                                return (-1);
 +                        }
 +                        BUFFER_ADD (":%g", rates[i]);
 +                }
 +                else if (ds->ds[i].type == DS_TYPE_COUNTER)
 +                        BUFFER_ADD (":%llu", vl->values[i].counter);
 +                else if (ds->ds[i].type == DS_TYPE_DERIVE)
 +                        BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
 +                else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
 +                        BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
 +                else
 +                {
 +                        ERROR ("format_values plugin: Unknown data source type: %i",
 +                                        ds->ds[i].type);
 +                        sfree (rates);
 +                        return (-1);
 +                }
 +        } /* for ds->ds_num */
 +
 +#undef BUFFER_ADD
 +
 +        sfree (rates);
 +        return (0);
 +} /* }}} int format_values */
 +
  int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
                char **ret_type, char **ret_type_instance)
        return (0);
  } /* int parse_identifier */
  
- int parse_value (const char *value, value_t *ret_value, int ds_type)
 +int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
 +{
 +      char str_copy[6 * DATA_MAX_NAME_LEN];
 +      char *host = NULL;
 +      char *plugin = NULL;
 +      char *plugin_instance = NULL;
 +      char *type = NULL;
 +      char *type_instance = NULL;
 +      int status;
 +
 +      if ((str == NULL) || (vl == NULL))
 +              return (EINVAL);
 +
 +      sstrncpy (str_copy, str, sizeof (str_copy));
 +
 +      status = parse_identifier (str_copy, &host,
 +                      &plugin, &plugin_instance,
 +                      &type, &type_instance);
 +      if (status != 0)
 +              return (status);
 +
 +      sstrncpy (vl->host, host, sizeof (vl->host));
 +      sstrncpy (vl->plugin, plugin, sizeof (vl->plugin));
 +      sstrncpy (vl->plugin_instance,
 +                      (plugin_instance != NULL) ? plugin_instance : "",
 +                      sizeof (vl->plugin_instance));
 +      sstrncpy (vl->type, type, sizeof (vl->type));
 +      sstrncpy (vl->type_instance,
 +                      (type_instance != NULL) ? type_instance : "",
 +                      sizeof (vl->type_instance));
 +
 +      return (0);
 +} /* }}} int parse_identifier_vl */
 +
+ int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
  {
+   char *value;
    char *endptr = NULL;
+   size_t value_len;
+   if (value_orig == NULL)
+     return (EINVAL);
+   value = strdup (value_orig);
+   if (value == NULL)
+     return (ENOMEM);
+   value_len = strlen (value);
+   while ((value_len > 0) && isspace ((int) value[value_len - 1]))
+   {
+     value[value_len - 1] = 0;
+     value_len--;
+   }
  
    switch (ds_type)
    {
        break;
  
      default:
+       sfree (value);
        ERROR ("parse_value: Invalid data source type: %i.", ds_type);
        return -1;
    }
  
    if (value == endptr) {
+     sfree (value);
      ERROR ("parse_value: Failed to parse string as %s: %s.",
          DS_TYPE_TO_STRING (ds_type), value);
      return -1;
    else if ((NULL != endptr) && ('\0' != *endptr))
      INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
          "Input string was \"%s\".",
-         endptr, DS_TYPE_TO_STRING (ds_type), value);
+         endptr, DS_TYPE_TO_STRING (ds_type), value_orig);
  
+   sfree (value);
    return 0;
  } /* int parse_value */
  
@@@ -1017,22 -932,9 +1036,22 @@@ int parse_values (char *buffer, value_l
                if (i == -1)
                {
                        if (strcmp ("N", ptr) == 0)
 -                              vl->time = time (NULL);
 +                              vl->time = cdtime ();
                        else
 -                              vl->time = (time_t) atoi (ptr);
 +                      {
 +                              char *endptr = NULL;
 +                              double tmp;
 +
 +                              errno = 0;
 +                              tmp = strtod (ptr, &endptr);
 +                              if ((errno != 0)                    /* Overflow */
 +                                              || (endptr == ptr)  /* Invalid string */
 +                                              || (endptr == NULL) /* This should not happen */
 +                                              || (*endptr != 0))  /* Trailing chars */
 +                                      return (-1);
 +
 +                              vl->time = DOUBLE_TO_CDTIME_T (tmp);
 +                      }
                }
                else
                {
diff --combined src/common.h
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/common.h
 - * Copyright (C) 2005-2009  Florian octo Forster
 + * Copyright (C) 2005-2010  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -16,7 -16,7 +16,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Niki W. Waibel <niki.waibel@gmx.net>
  **/
  
@@@ -258,14 -258,10 +258,14 @@@ int format_name (char *ret, int ret_len
  #define FORMAT_VL(ret, ret_len, vl) \
        format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
                        (vl)->type, (vl)->type_instance)
 +int format_values (char *ret, size_t ret_len,
 +              const data_set_t *ds, const value_list_t *vl,
 +              _Bool store_rates);
  
  int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
                char **ret_type, char **ret_type_instance);
 +int parse_identifier_vl (const char *str, value_list_t *vl);
  int parse_value (const char *value, value_t *ret_value, int ds_type);
  int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
  
@@@ -278,15 -274,16 +278,16 @@@ int notification_init (notification_t *
                const char *host,
                const char *plugin, const char *plugin_instance,
                const char *type, const char *type_instance);
 -#define NOTIFICATION_INIT_VL(n, vl, ds) \
 +#define NOTIFICATION_INIT_VL(n, vl) \
        notification_init (n, NOTIF_FAILURE, NULL, \
                        (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
 -                      (ds)->type, (vl)->type_instance)
 +                      (vl)->type, (vl)->type_instance)
  
  typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
                void *user_data);
  int walk_directory (const char *dir, dirwalk_callback_f callback,
                void *user_data, int hidden);
+ /* Returns the number of bytes read or negative on error. */
  int read_file_contents (const char *filename, char *buf, int bufsize);
  
  counter_t counter_diff (counter_t old_value, counter_t new_value);
@@@ -164,14 -164,27 +164,14 @@@ static int lcc_set_errno (lcc_connectio
    return (0);
  } /* }}} int lcc_set_errno */
  
 -/* lcc_strdup: Since `strdup' is an XSI extension, we provide our own version
 - * here. */
 -__attribute__((malloc, nonnull (1)))
 -static char *lcc_strdup (const char *str) /* {{{ */
 -{
 -  size_t strsize;
 -  char *ret;
 -
 -  strsize = strlen (str) + 1;
 -  ret = (char *) malloc (strsize);
 -  if (ret != NULL)
 -    memcpy (ret, str, strsize);
 -  return (ret);
 -} /* }}} char *lcc_strdup */
 -
 -__attribute__((nonnull (1, 2)))
  static char *lcc_strescape (char *dest, const char *src, size_t dest_size) /* {{{ */
  {
    size_t dest_pos;
    size_t src_pos;
  
 +  if ((dest == NULL) || (src == NULL))
 +    return (NULL);
 +
    dest_pos = 0;
    src_pos = 0;
  
@@@ -325,7 -338,7 +325,7 @@@ static int lcc_receive (lcc_connection_
      lcc_chomp (buffer);
      LCC_DEBUG ("receive: <-- %s\n", buffer);
  
 -    res.lines[i] = lcc_strdup (buffer);
 +    res.lines[i] = strdup (buffer);
      if (res.lines[i] == NULL)
      {
        lcc_set_errno (c, ENOMEM);
@@@ -720,7 -733,7 +720,7 @@@ int lcc_getval (lcc_connection_t *c, lc
  
      if (values_names != NULL)
      {
 -      values_names[i] = lcc_strdup (key);
 +      values_names[i] = strdup (key);
        if (values_names[i] == NULL)
          BAIL_OUT (ENOMEM);
      }
    if (ret_values_names != NULL)
      *ret_values_names = values_names;
  
+   lcc_response_free (&res);
    return (0);
  } /* }}} int lcc_getval */
  
@@@ -775,7 -790,7 +777,7 @@@ int lcc_putval (lcc_connection_t *c, co
      else if (vl->values_types[i] == LCC_TYPE_GAUGE)
      {
        if (isnan (vl->values[i].gauge))
 -        SSTRCPY (command, ":U");
 +        SSTRCATF (command, ":U");
        else
          SSTRCATF (command, ":%g", vl->values[i].gauge);
      }
@@@ -1000,7 -1015,7 +1002,7 @@@ int lcc_string_to_identifier (lcc_conne
    char *type;
    char *type_instance;
  
 -  string_copy = lcc_strdup (string);
 +  string_copy = strdup (string);
    if (string_copy == NULL)
    {
      lcc_set_errno (c, ENOMEM);
diff --combined src/memcached.c
@@@ -1,7 -1,7 +1,7 @@@
  /**
   * collectd - src/memcached.c, based on src/hddtemp.c
   * Copyright (C) 2007       Antony Dovgal
 - * Copyright (C) 2007-2009  Florian Forster
 + * Copyright (C) 2007-2010  Florian Forster
   * Copyright (C) 2009       Doug MacEachern
   * Copyright (C) 2009       Franck Lombardi
   *
@@@ -21,7 -21,7 +21,7 @@@
   *
   * Authors:
   *   Antony Dovgal <tony at daylessday dot org>
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Doug MacEachern <dougm at hyperic.com>
   *   Franck Lombardi
   **/
@@@ -176,14 -176,12 +176,14 @@@ static int memcached_query_daemon (cha
                p.events = POLLIN | POLLERR | POLLHUP;
                p.revents = 0;
  
 -              status = poll (&p, /* nfds = */ 1, /* timeout = */ 1000 * interval_g);
 +              status = poll (&p, /* nfds = */ 1,
 +                              /* timeout = */ CDTIME_T_TO_MS (interval_g));
                if (status <= 0)
                {
                        if (status == 0)
                        {
 -                              ERROR ("memcached: poll(2) timed out after %i seconds.", interval_g);
 +                              ERROR ("memcached: poll(2) timed out after %.3f seconds.",
 +                                              CDTIME_T_TO_DOUBLE (interval_g));
                        }
                        else
                        {
@@@ -273,13 -271,13 +273,13 @@@ static int memcached_config (const cha
  }
  /* }}} */
  
 -static void submit_counter (const char *type, const char *type_inst,
 -              counter_t value) /* {{{ */
 +static void submit_derive (const char *type, const char *type_inst,
 +              derive_t value) /* {{{ */
  {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      values[0].counter = value;
 +      values[0].derive = value;
  
        vl.values = values;
        vl.values_len = 1;
  } /* void memcached_submit_cmd */
  /* }}} */
  
 -static void submit_counter2 (const char *type, const char *type_inst,
 -              counter_t value0, counter_t value1) /* {{{ */
 +static void submit_derive2 (const char *type, const char *type_inst,
 +              derive_t value0, derive_t value1) /* {{{ */
  {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      values[0].counter = value0;
 -      values[1].counter = value1;
 +      values[0].derive = value0;
 +      values[1].derive = value1;
  
        vl.values = values;
        vl.values_len = 2;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@@ -324,6 -323,7 +324,6 @@@ static void submit_gauge (const char *t
  
        vl.values = values;
        vl.values_len = 1;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@@ -345,6 -345,7 +345,6 @@@ static void submit_gauge2 (const char *
  
        vl.values = values;
        vl.values_len = 2;
 -      vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
  
  static int memcached_read (void) /* {{{ */
  {
-       char buf[1024];
+       char buf[4096];
        char *fields[3];
        char *ptr;
        char *line;
        gauge_t bytes_total = NAN;
        gauge_t hits = NAN;
        gauge_t gets = NAN;
 -      counter_t rusage_user = 0;
 -      counter_t rusage_syst = 0;
 -      counter_t octets_rx = 0;
 -      counter_t octets_tx = 0;
 +      derive_t rusage_user = 0;
 +      derive_t rusage_syst = 0;
 +      derive_t octets_rx = 0;
 +      derive_t octets_tx = 0;
  
        /* get data from daemon */
        if (memcached_query_daemon (buf, sizeof (buf)) < 0) {
                else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
                {
                        const char *name = fields[1] + 4;
 -                      submit_counter ("memcached_command", name, atoll (fields[2]));
 +                      submit_derive ("memcached_command", name, atoll (fields[2]));
                        if (strcmp (name, "get") == 0)
                                gets = atof (fields[2]);
                }
                 */
                else if (FIELD_IS ("get_hits"))
                {
 -                      submit_counter ("memcached_ops", "hits", atoll (fields[2]));
 +                      submit_derive ("memcached_ops", "hits", atoll (fields[2]));
                        hits = atof (fields[2]);
                }
                else if (FIELD_IS ("get_misses"))
                {
 -                      submit_counter ("memcached_ops", "misses", atoll (fields[2]));
 +                      submit_derive ("memcached_ops", "misses", atoll (fields[2]));
                }
                else if (FIELD_IS ("evictions"))
                {
 -                      submit_counter ("memcached_ops", "evictions", atoll (fields[2]));
 +                      submit_derive ("memcached_ops", "evictions", atoll (fields[2]));
                }
  
                /*
                submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used);
  
        if ((rusage_user != 0) || (rusage_syst != 0))
 -              submit_counter2 ("ps_cputime", NULL, rusage_user, rusage_syst);
 +              submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst);
  
        if ((octets_rx != 0) || (octets_tx != 0))
 -              submit_counter2 ("memcached_octets", NULL, octets_rx, octets_tx);
 +              submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx);
  
        if (!isnan (gets) && !isnan (hits))
        {
diff --combined src/network.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/network.c
 - * Copyright (C) 2005-2009  Florian octo Forster
 + * Copyright (C) 2005-2010  Florian octo Forster
   * Copyright (C) 2009       Aman Gupta
   *
   * This program is free software; you can redistribute it and/or modify it
@@@ -259,8 -259,7 +259,8 @@@ typedef struct receive_list_entry_s rec
   * Private variables
   */
  static int network_config_ttl = 0;
 -static size_t network_config_packet_size = 1024;
 +/* Ethernet - (IPv6 + UDP) = 1500 - (40 + 8) = 1452 */
 +static size_t network_config_packet_size = 1452;
  static int network_config_forward = 0;
  static int network_config_stats = 0;
  
@@@ -297,14 -296,14 +297,14 @@@ static pthread_mutex_t  send_buffer_loc
   * example). Only if neither is true, the stats_lock is acquired. The counters
   * are always read without holding a lock in the hope that writing 8 bytes to
   * memory is an atomic operation. */
 -static uint64_t stats_octets_rx  = 0;
 -static uint64_t stats_octets_tx  = 0;
 -static uint64_t stats_packets_rx = 0;
 -static uint64_t stats_packets_tx = 0;
 -static uint64_t stats_values_dispatched = 0;
 -static uint64_t stats_values_not_dispatched = 0;
 -static uint64_t stats_values_sent = 0;
 -static uint64_t stats_values_not_sent = 0;
 +static derive_t stats_octets_rx  = 0;
 +static derive_t stats_octets_tx  = 0;
 +static derive_t stats_packets_rx = 0;
 +static derive_t stats_packets_tx = 0;
 +static derive_t stats_values_dispatched = 0;
 +static derive_t stats_values_not_dispatched = 0;
 +static derive_t stats_values_sent = 0;
 +static derive_t stats_values_not_sent = 0;
  static pthread_mutex_t stats_lock = PTHREAD_MUTEX_INITIALIZER;
  
  /*
@@@ -321,30 -320,30 +321,30 @@@ static _Bool check_receive_okay (const 
    /* This is a value we already sent. Don't allow it to be received again in
     * order to avoid looping. */
    if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
 -    return (false);
 +    return (0);
  
 -  return (true);
 +  return (1);
  } /* }}} _Bool check_receive_okay */
  
  static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
  {
 -  _Bool received = false;
 +  _Bool received = 0;
    int status;
  
    if (network_config_forward != 0)
 -    return (true);
 +    return (1);
  
    if (vl->meta == NULL)
 -    return (true);
 +    return (1);
  
    status = meta_data_get_boolean (vl->meta, "network:received", &received);
    if (status == -ENOENT)
 -    return (true);
 +    return (1);
    else if (status != 0)
    {
      ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
        "with status %i.", status);
 -    return (true);
 +    return (1);
    }
  
    /* By default, only *send* value lists that were not *received* by the
    return (!received);
  } /* }}} _Bool check_send_okay */
  
+ static _Bool check_notify_received (const notification_t *n) /* {{{ */
+ {
+   notification_meta_t *ptr;
+   for (ptr = n->meta; ptr != NULL; ptr = ptr->next)
+     if ((strcmp ("network:received", ptr->name) == 0)
+         && (ptr->type == NM_TYPE_BOOLEAN))
+       return ((_Bool) ptr->nm_value.nm_boolean);
+   return (0);
+ } /* }}} _Bool check_notify_received */
+ static _Bool check_send_notify_okay (const notification_t *n) /* {{{ */
+ {
+   static c_complain_t complain_forwarding = C_COMPLAIN_INIT_STATIC;
+   _Bool received = 0;
+   if (n->meta == NULL)
+     return (1);
+   received = check_notify_received (n);
+   if (network_config_forward && received)
+   {
+     c_complain_once (LOG_ERR, &complain_forwarding,
+         "network plugin: A notification has been received via the network "
+         "forwarding if enabled. Forwarding of notifications is currently "
+         "not supported, because there is not loop-deteciton available. "
+         "Please contact the collectd mailing list if you need this "
+         "feature.");
+   }
+   /* By default, only *send* value lists that were not *received* by the
+    * network plugin. */
+   return (!received);
+ } /* }}} _Bool check_send_notify_okay */
  static int network_dispatch_values (value_list_t *vl, /* {{{ */
      const char *username)
  {
      return (-ENOMEM);
    }
  
 -  status = meta_data_add_boolean (vl->meta, "network:received", true);
 +  status = meta_data_add_boolean (vl->meta, "network:received", 1);
    if (status != 0)
    {
      ERROR ("network plugin: meta_data_add_boolean failed.");
    return (0);
  } /* }}} int network_dispatch_values */
  
+ static int network_dispatch_notification (notification_t *n) /* {{{ */
+ {
+   int status;
+   assert (n->meta == NULL);
+   status = plugin_notification_meta_add_boolean (n, "network:received", 1);
+   if (status != 0)
+   {
+     ERROR ("network plugin: plugin_notification_meta_add_boolean failed.");
+     plugin_notification_meta_free (n->meta);
+     n->meta = NULL;
+     return (status);
+   }
+   status = plugin_dispatch_notification (n);
+   plugin_notification_meta_free (n->meta);
+   n->meta = NULL;
+   return (status);
+ } /* }}} int network_dispatch_notification */
  #if HAVE_LIBGCRYPT
  static gcry_cipher_hd_t network_get_aes256_cypher (sockent_t *se, /* {{{ */
      const void *iv, size_t iv_size, const char *username)
@@@ -705,7 -764,7 +765,7 @@@ static int parse_part_values (void **re
  
        exp_size = 3 * sizeof (uint16_t)
                + pkg_numval * (sizeof (uint8_t) + sizeof (value_t));
-       if ((buffer_len < 0) || (buffer_len < exp_size))
+       if (buffer_len < exp_size)
        {
                WARNING ("network plugin: parse_part_values: "
                                "Packet too short: "
@@@ -790,7 -849,7 +850,7 @@@ static int parse_part_number (void **re
  
        uint16_t pkg_length;
  
-       if ((buffer_len < 0) || ((size_t) buffer_len < exp_size))
+       if (buffer_len < exp_size)
        {
                WARNING ("network plugin: parse_part_number: "
                                "Packet too short: "
@@@ -829,7 -888,7 +889,7 @@@ static int parse_part_string (void **re
  
        uint16_t pkg_length;
  
-       if ((buffer_len < 0) || (buffer_len < header_size))
+       if (buffer_len < header_size)
        {
                WARNING ("network plugin: parse_part_string: "
                                "Packet too short: "
@@@ -1380,19 -1439,8 +1440,19 @@@ static int parse_packet (sockent_t *se
                                        &tmp);
                        if (status == 0)
                        {
 -                              vl.time = (time_t) tmp;
 -                              n.time = (time_t) tmp;
 +                              vl.time = TIME_T_TO_CDTIME_T (tmp);
 +                              n.time  = TIME_T_TO_CDTIME_T (tmp);
 +                      }
 +              }
 +              else if (pkg_type == TYPE_TIME_HR)
 +              {
 +                      uint64_t tmp = 0;
 +                      status = parse_part_number (&buffer, &buffer_size,
 +                                      &tmp);
 +                      if (status == 0)
 +                      {
 +                              vl.time = (cdtime_t) tmp;
 +                              n.time  = (cdtime_t) tmp;
                        }
                }
                else if (pkg_type == TYPE_INTERVAL)
                        status = parse_part_number (&buffer, &buffer_size,
                                        &tmp);
                        if (status == 0)
 -                              vl.interval = (int) tmp;
 +                              vl.interval = TIME_T_TO_CDTIME_T (tmp);
 +              }
 +              else if (pkg_type == TYPE_INTERVAL_HR)
 +              {
 +                      uint64_t tmp = 0;
 +                      status = parse_part_number (&buffer, &buffer_size,
 +                                      &tmp);
 +                      if (status == 0)
 +                              vl.interval = (cdtime_t) tmp;
                }
                else if (pkg_type == TYPE_HOST)
                {
                        }
                        else
                        {
-                               plugin_dispatch_notification (&n);
+                               network_dispatch_notification (&n);
                        }
                }
                else if (pkg_type == TYPE_SEVERITY)
@@@ -2606,7 -2646,7 +2666,7 @@@ static int add_to_buffer (char *buffer
  
        if (vl_def->time != vl->time)
        {
 -              if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
 +              if (write_part_number (&buffer, &buffer_size, TYPE_TIME_HR,
                                        (uint64_t) vl->time))
                        return (-1);
                vl_def->time = vl->time;
  
        if (vl_def->interval != vl->interval)
        {
 -              if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
 +              if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL_HR,
                                        (uint64_t) vl->interval))
                        return (-1);
                vl_def->interval = vl->interval;
@@@ -3076,6 -3116,8 +3136,6 @@@ static int network_config (oconfig_item
        network_config_set_boolean (child, &network_config_forward);
      else if (strcasecmp ("ReportStats", child->key) == 0)
        network_config_set_boolean (child, &network_config_stats);
 -    else if (strcasecmp ("CacheFlush", child->key) == 0)
 -      /* no op for backwards compatibility only */;
      else
      {
        WARNING ("network plugin: Option `%s' is not allowed here.",
  } /* }}} int network_config */
  
  static int network_notification (const notification_t *n,
-               user_data_t __attribute__((unused)) *user_data)
+     user_data_t __attribute__((unused)) *user_data)
  {
    char  buffer[network_config_packet_size];
    char *buffer_ptr = buffer;
    int   buffer_free = sizeof (buffer);
    int   status;
  
-   memset (buffer, '\0', sizeof (buffer));
+   if (!check_send_notify_okay (n))
+     return (0);
+   memset (buffer, 0, sizeof (buffer));
  
 -  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
 +  status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR,
        (uint64_t) n->time);
    if (status != 0)
      return (-1);
    if (strlen (n->host) > 0)
    {
      status = write_part_string (&buffer_ptr, &buffer_free, TYPE_HOST,
-       n->host, strlen (n->host));
+         n->host, strlen (n->host));
      if (status != 0)
        return (-1);
    }
    if (strlen (n->plugin) > 0)
    {
      status = write_part_string (&buffer_ptr, &buffer_free, TYPE_PLUGIN,
-       n->plugin, strlen (n->plugin));
+         n->plugin, strlen (n->plugin));
      if (status != 0)
        return (-1);
    }
    if (strlen (n->plugin_instance) > 0)
    {
      status = write_part_string (&buffer_ptr, &buffer_free,
-       TYPE_PLUGIN_INSTANCE,
-       n->plugin_instance, strlen (n->plugin_instance));
+         TYPE_PLUGIN_INSTANCE,
+         n->plugin_instance, strlen (n->plugin_instance));
      if (status != 0)
        return (-1);
    }
    if (strlen (n->type) > 0)
    {
      status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE,
-       n->type, strlen (n->type));
+         n->type, strlen (n->type));
      if (status != 0)
        return (-1);
    }
    if (strlen (n->type_instance) > 0)
    {
      status = write_part_string (&buffer_ptr, &buffer_free, TYPE_TYPE_INSTANCE,
-       n->type_instance, strlen (n->type_instance));
+         n->type_instance, strlen (n->type_instance));
      if (status != 0)
        return (-1);
    }
@@@ -3201,15 -3246,15 +3264,15 @@@ static int network_shutdown (void
  
  static int network_stats_read (void) /* {{{ */
  {
 -      uint64_t copy_octets_rx;
 -      uint64_t copy_octets_tx;
 -      uint64_t copy_packets_rx;
 -      uint64_t copy_packets_tx;
 -      uint64_t copy_values_dispatched;
 -      uint64_t copy_values_not_dispatched;
 -      uint64_t copy_values_sent;
 -      uint64_t copy_values_not_sent;
 -      uint64_t copy_receive_list_length;
 +      derive_t copy_octets_rx;
 +      derive_t copy_octets_tx;
 +      derive_t copy_packets_rx;
 +      derive_t copy_packets_tx;
 +      derive_t copy_values_dispatched;
 +      derive_t copy_values_not_dispatched;
 +      derive_t copy_values_sent;
 +      derive_t copy_values_not_sent;
 +      derive_t copy_receive_list_length;
        value_list_t vl = VALUE_LIST_INIT;
        value_t values[2];
  
        sstrncpy (vl.plugin, "network", sizeof (vl.plugin));
  
        /* Octets received / sent */
 -      vl.values[0].counter = (counter_t) copy_octets_rx;
 -      vl.values[1].counter = (counter_t) copy_octets_tx;
 +      vl.values[0].derive = (derive_t) copy_octets_rx;
 +      vl.values[1].derive = (derive_t) copy_octets_tx;
        sstrncpy (vl.type, "if_octets", sizeof (vl.type));
        plugin_dispatch_values_secure (&vl);
  
        /* Packets received / send */
 -      vl.values[0].counter = (counter_t) copy_packets_rx;
 -      vl.values[1].counter = (counter_t) copy_packets_tx;
 +      vl.values[0].derive = (derive_t) copy_packets_rx;
 +      vl.values[1].derive = (derive_t) copy_packets_tx;
        sstrncpy (vl.type, "if_packets", sizeof (vl.type));
        plugin_dispatch_values_secure (&vl);
  
  
  static int network_init (void)
  {
 -      static _Bool have_init = false;
 +      static _Bool have_init = 0;
  
        /* Check if we were already initialized. If so, just return - there's
         * nothing more to do (for now, that is). */
        if (have_init)
                return (0);
 -      have_init = true;
 +      have_init = 1;
  
  #if HAVE_LIBGCRYPT
        gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
   * just send the buffer if `flush'  is called - if the requested value was in
   * there, good. If not, well, then there is nothing to flush.. -octo
   */
 -static int network_flush (int timeout,
 -              const char __attribute__((unused)) *identifier,
 -              user_data_t __attribute__((unused)) *user_data)
 +static int network_flush (__attribute__((unused)) cdtime_t timeout,
 +              __attribute__((unused)) const char *identifier,
 +              __attribute__((unused)) user_data_t *user_data)
  {
        pthread_mutex_lock (&send_buffer_lock);
  
diff --combined src/perl.c
  
  #include "configfile.h"
  
 +#if HAVE_STDBOOL_H
 +# include <stdbool.h>
 +#endif
 +
  #include <EXTERN.h>
  #include <perl.h>
  
@@@ -235,6 -231,15 +235,6 @@@ struct 
        { "", NULL }
  };
  
 -struct {
 -      char  name[64];
 -      int  *var;
 -} g_integers[] =
 -{
 -      { "Collectd::interval_g", &interval_g },
 -      { "", NULL }
 -};
 -
  /*
   * Helper functions for data type conversion.
   */
@@@ -388,16 -393,10 +388,16 @@@ static int hv2value_list (pTHX_ HV *has
        }
  
        if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
 -              vl->time = (time_t)SvIV (*tmp);
 +      {
 +              double t = SvNV (*tmp);
 +              vl->time = DOUBLE_TO_CDTIME_T (t);
 +      }
  
        if (NULL != (tmp = hv_fetch (hash, "interval", 8, 0)))
 -              vl->interval = SvIV (*tmp);
 +      {
 +              double t = SvNV (*tmp);
 +              vl->interval = DOUBLE_TO_CDTIME_T (t);
 +      }
  
        if (NULL != (tmp = hv_fetch (hash, "host", 4, 0)))
                sstrncpy (vl->host, SvPV_nolen (*tmp), sizeof (vl->host));
@@@ -549,12 -548,9 +549,12 @@@ static int hv2notification (pTHX_ HV *h
                n->severity = NOTIF_FAILURE;
  
        if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
 -              n->time = (time_t)SvIV (*tmp);
 +      {
 +              double t = SvNV (*tmp);
 +              n->time = DOUBLE_TO_CDTIME_T (t);
 +      }
        else
 -              n->time = time (NULL);
 +              n->time = cdtime ();
  
        if (NULL != (tmp = hv_fetch (hash, "message", 7, 0)))
                sstrncpy (n->message, SvPV_nolen (*tmp), sizeof (n->message));
@@@ -672,17 -668,11 +672,17 @@@ static int value_list2hv (pTHX_ value_l
                return -1;
  
        if (0 != vl->time)
 -              if (NULL == hv_store (hash, "time", 4, newSViv (vl->time), 0))
 +      {
 +              double t = CDTIME_T_TO_DOUBLE (vl->time);
 +              if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
                        return -1;
 +      }
  
 -      if (NULL == hv_store (hash, "interval", 8, newSViv (vl->interval), 0))
 -              return -1;
 +      {
 +              double t = CDTIME_T_TO_DOUBLE (vl->interval);
 +              if (NULL == hv_store (hash, "interval", 8, newSVnv (t), 0))
 +                      return -1;
 +      }
  
        if ('\0' != vl->host[0])
                if (NULL == hv_store (hash, "host", 4, newSVpv (vl->host, 0), 0))
@@@ -760,11 -750,8 +760,11 @@@ static int notification2hv (pTHX_ notif
                return -1;
  
        if (0 != n->time)
 -              if (NULL == hv_store (hash, "time", 4, newSViv (n->time), 0))
 +      {
 +              double t = CDTIME_T_TO_DOUBLE (n->time);
 +              if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
                        return -1;
 +      }
  
        if ('\0' != *n->message)
                if (NULL == hv_store (hash, "message", 7, newSVpv (n->message, 0), 0))
@@@ -1115,15 -1102,11 +1115,15 @@@ static int pplugin_call_all (pTHX_ int 
                XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
        }
        else if (PLUGIN_FLUSH == type) {
 +              cdtime_t timeout;
 +
                /*
                 * $_[0] = $timeout;
                 * $_[1] = $identifier;
                 */
 -              XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
 +              timeout = va_arg (ap, cdtime_t);
 +
 +              XPUSHs (sv_2mortal (newSVnv (CDTIME_T_TO_DOUBLE (timeout))));
                XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
        }
  
@@@ -1627,29 -1610,40 +1627,29 @@@ static XS (Collectd_plugin_unregister_d
  static XS (Collectd_plugin_dispatch_values)
  {
        SV *values     = NULL;
 -      int values_idx = 0;
  
        int ret = 0;
  
        dXSARGS;
  
 -      if (2 == items) {
 -              log_warn ("Collectd::plugin_dispatch_values with two arguments "
 -                              "is deprecated - pass the type through values->{type}.");
 -              values_idx = 1;
 -      }
 -      else if (1 != items) {
 +      if (1 != items) {
                log_err ("Usage: Collectd::plugin_dispatch_values(values)");
                XSRETURN_EMPTY;
        }
  
        log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
 -                      SvPV_nolen (ST (values_idx)));
 +                      SvPV_nolen (ST (/* stack index = */ 0)));
  
 -      values = ST (values_idx);
 +      values = ST (/* stack index = */ 0);
  
 +      /* Make sure the argument is a hash reference. */
        if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
                log_err ("Collectd::plugin_dispatch_values: Invalid values.");
                XSRETURN_EMPTY;
        }
  
 -      if (((2 == items) && (NULL == ST (0))) || (NULL == values))
 -              XSRETURN_EMPTY;
 -
 -      if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
 -                      newSVsv (ST (0)), 0))) {
 -              log_err ("Collectd::plugin_dispatch_values: Could not store type.");
 +      if (NULL == values)
                XSRETURN_EMPTY;
 -      }
  
        ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
  
@@@ -1929,6 -1923,11 +1929,11 @@@ static int perl_read (void
                aTHX = t->interp;
        }
  
+       /* Assert that we're not running as the base thread. Otherwise, we might
+        * run into concurrency issues with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       assert (aTHX != perl_threads->head->interp);
        log_debug ("perl_read: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
        return pplugin_call_all (aTHX_ PLUGIN_READ);
  static int perl_write (const data_set_t *ds, const value_list_t *vl,
                user_data_t __attribute__((unused)) *user_data)
  {
+       int status;
        dTHX;
  
        if (NULL == perl_threads)
                aTHX = t->interp;
        }
  
+       /* Lock the base thread if this is not called from one of the read threads
+        * to avoid race conditions with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_lock (&perl_threads->mutex);
        log_debug ("perl_write: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
-       return pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl);
+       status = pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl);
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_unlock (&perl_threads->mutex);
+       return status;
  } /* static int perl_write (const data_set_t *, const value_list_t *) */
  
  static void perl_log (int level, const char *msg,
                aTHX = t->interp;
        }
  
+       /* Lock the base thread if this is not called from one of the read threads
+        * to avoid race conditions with c_ithread_create(). See
+        * https://github.com/collectd/collectd/issues/9 for details. */
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_lock (&perl_threads->mutex);
        pplugin_call_all (aTHX_ PLUGIN_LOG, level, msg);
+       if (aTHX == perl_threads->head->interp)
+               pthread_mutex_unlock (&perl_threads->mutex);
        return;
  } /* static void perl_log (int, const char *) */
  
@@@ -1999,7 -2020,7 +2026,7 @@@ static int perl_notify (const notificat
        return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
  } /* static int perl_notify (const notification_t *) */
  
 -static int perl_flush (int timeout, const char *identifier,
 +static int perl_flush (cdtime_t timeout, const char *identifier,
                user_data_t __attribute__((unused)) *user_data)
  {
        dTHX;
@@@ -2101,27 -2122,19 +2128,27 @@@ static int g_pv_set (pTHX_ SV *var, MAG
        return 0;
  } /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
  
 -static int g_iv_get (pTHX_ SV *var, MAGIC *mg)
 +static int g_interval_get (pTHX_ SV *var, MAGIC *mg)
  {
 -      int *iv = (int *)mg->mg_ptr;
 -      sv_setiv (var, *iv);
 +      cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
 +      double nv;
 +
 +      nv = CDTIME_T_TO_DOUBLE (*interval);
 +
 +      sv_setnv (var, nv);
        return 0;
 -} /* static int g_iv_get (pTHX_ SV *, MAGIC *) */
 +} /* static int g_interval_get (pTHX_ SV *, MAGIC *) */
  
 -static int g_iv_set (pTHX_ SV *var, MAGIC *mg)
 +static int g_interval_set (pTHX_ SV *var, MAGIC *mg)
  {
 -      int *iv = (int *)mg->mg_ptr;
 -      *iv = (int)SvIV (var);
 +      cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
 +      double nv;
 +
 +      nv = (double)SvNV (var);
 +
 +      *interval = DOUBLE_TO_CDTIME_T (nv);
        return 0;
 -} /* static int g_iv_set (pTHX_ SV *, MAGIC *) */
 +} /* static int g_interval_set (pTHX_ SV *, MAGIC *) */
  
  static MGVTBL g_pv_vtbl = {
        g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL
                , NULL
  #endif
  };
 -static MGVTBL g_iv_vtbl = {
 -      g_iv_get, g_iv_set, NULL, NULL, NULL, NULL, NULL
 +static MGVTBL g_interval_vtbl = {
 +      g_interval_get, g_interval_set, NULL, NULL, NULL, NULL, NULL
  #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL
                , NULL
  #endif
@@@ -2172,11 -2185,12 +2199,11 @@@ static void xs_init (pTHX
                                g_strings[i].var, 0);
        }
  
 -      /* global integers */
 -      for (i = 0; '\0' != g_integers[i].name[0]; ++i) {
 -              tmp = get_sv (g_integers[i].name, 1);
 -              sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_iv_vtbl,
 -                              (char *)g_integers[i].var, 0);
 -      }
 +      tmp = get_sv ("Collectd::interval_g", /* create = */ 1);
 +      sv_magicext (tmp, NULL, /* how = */ PERL_MAGIC_ext,
 +                      /* vtbl = */ &g_interval_vtbl,
 +                      /* name = */ (char *) &interval_g, /* namelen = */ 0);
 +
        return;
  } /* static void xs_init (pTHX) */
  
diff --combined src/processes.c
@@@ -1,7 -1,7 +1,7 @@@
  /**
   * collectd - src/processes.c
   * Copyright (C) 2005       Lyonel Vincent
 - * Copyright (C) 2006-2008  Florian octo Forster
 + * Copyright (C) 2006-2010  Florian octo Forster
   * Copyright (C) 2008       Oleg King
   * Copyright (C) 2009       Sebastian Harl
   * Copyright (C) 2009       Andrés J. Díaz
@@@ -136,13 -136,13 +136,13 @@@ typedef struct procstat_entry_
  
        unsigned long vmem_minflt;
        unsigned long vmem_majflt;
 -      unsigned long vmem_minflt_counter;
 -      unsigned long vmem_majflt_counter;
 +      derive_t      vmem_minflt_counter;
 +      derive_t      vmem_majflt_counter;
  
        unsigned long cpu_user;
        unsigned long cpu_system;
 -      unsigned long cpu_user_counter;
 -      unsigned long cpu_system_counter;
 +      derive_t      cpu_user_counter;
 +      derive_t      cpu_system_counter;
  
        /* io data */
        derive_t io_rchar;
@@@ -169,11 -169,11 +169,11 @@@ typedef struct procsta
        unsigned long vmem_code;
        unsigned long stack_size;
  
 -      unsigned long vmem_minflt_counter;
 -      unsigned long vmem_majflt_counter;
 +      derive_t vmem_minflt_counter;
 +      derive_t vmem_majflt_counter;
  
 -      unsigned long cpu_user_counter;
 -      unsigned long cpu_system_counter;
 +      derive_t cpu_user_counter;
 +      derive_t cpu_system_counter;
  
        /* io data */
        derive_t io_rchar;
@@@ -676,8 -676,8 +676,8 @@@ static void ps_submit_proc_list (procst
        plugin_dispatch_values (&vl);
  
        sstrncpy (vl.type, "ps_cputime", sizeof (vl.type));
 -      vl.values[0].counter = ps->cpu_user_counter;
 -      vl.values[1].counter = ps->cpu_system_counter;
 +      vl.values[0].derive = ps->cpu_user_counter;
 +      vl.values[1].derive = ps->cpu_system_counter;
        vl.values_len = 2;
        plugin_dispatch_values (&vl);
  
        plugin_dispatch_values (&vl);
  
        sstrncpy (vl.type, "ps_pagefaults", sizeof (vl.type));
 -      vl.values[0].counter = ps->vmem_minflt_counter;
 -      vl.values[1].counter = ps->vmem_majflt_counter;
 +      vl.values[0].derive = ps->vmem_minflt_counter;
 +      vl.values[1].derive = ps->vmem_majflt_counter;
        vl.values_len = 2;
        plugin_dispatch_values (&vl);
  
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
                          "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
 -                      "vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; "
 -                      "cpu_user_counter = %lu; cpu_system_counter = %lu; "
 +                      "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
 +                      "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
                        "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; "
                        "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";",
                        ps->name, ps->num_proc, ps->num_lwp,
@@@ -881,12 -881,15 +881,15 @@@ int ps_read_process (int pid, procstat_
        char *fields[64];
        char  fields_len;
  
-       int   i;
+       int   buffer_len;
  
-       int   name_len;
+       char *buffer_ptr;
+       size_t name_start_pos;
+       size_t name_end_pos;
+       size_t name_len;
  
 -      long long unsigned cpu_user_counter;
 -      long long unsigned cpu_system_counter;
 +      derive_t cpu_user_counter;
 +      derive_t cpu_system_counter;
        long long unsigned vmem_size;
        long long unsigned vmem_rss;
        long long unsigned stack_size;
  
        ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
  
-       i = read_file_contents (filename, buffer, sizeof(buffer) - 1);
-       if (i <= 0)
+       buffer_len = read_file_contents (filename,
+                       buffer, sizeof(buffer) - 1);
+       if (buffer_len <= 0)
                return (-1);
-       buffer[i] = 0;
-       fields_len = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
-       if (fields_len < 24)
+       buffer[buffer_len] = 0;
+       /* The name of the process is enclosed in parens. Since the name can
+        * contain parens itself, spaces, numbers and pretty much everything
+        * else, use these to determine the process name. We don't use
+        * strchr(3) and strrchr(3) to avoid pointer arithmetic which would
+        * otherwise be required to determine name_len. */
+       name_start_pos = 0;
+       while ((buffer[name_start_pos] != '(')
+                       && (name_start_pos < buffer_len))
+               name_start_pos++;
+       name_end_pos = buffer_len;
+       while ((buffer[name_end_pos] != ')')
+                       && (name_end_pos > 0))
+               name_end_pos--;
+       /* Either '(' or ')' is not found or they are in the wrong order.
+        * Anyway, something weird that shouldn't happen ever. */
+       if (name_start_pos >= name_end_pos)
        {
-               DEBUG ("processes plugin: ps_read_process (pid = %i):"
-                               " `%s' has only %i fields..",
-                               (int) pid, filename, fields_len);
+               ERROR ("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
+                               name_start_pos, name_end_pos);
                return (-1);
        }
  
-       /* copy the name, strip brackets in the process */
-       name_len = strlen (fields[1]) - 2;
-       if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')'))
+       name_len = (name_end_pos - name_start_pos) - 1;
+       if (name_len >= sizeof (ps->name))
+               name_len = sizeof (ps->name) - 1;
+       sstrncpy (ps->name, &buffer[name_start_pos + 1], name_len + 1);
+       if ((buffer_len - name_end_pos) < 2)
+               return (-1);
+       buffer_ptr = &buffer[name_end_pos + 2];
+       fields_len = strsplit (buffer_ptr, fields, STATIC_ARRAY_SIZE (fields));
+       if (fields_len < 22)
        {
-               DEBUG ("No brackets found in process name: `%s'", fields[1]);
+               DEBUG ("processes plugin: ps_read_process (pid = %i):"
+                               " `%s' has only %i fields..",
+                               (int) pid, filename, fields_len);
                return (-1);
        }
-       fields[1] = fields[1] + 1;
-       fields[1][name_len] = '\0';
-       strncpy (ps->name, fields[1], PROCSTAT_NAME_LEN);
  
-       *state = fields[2][0];
+       *state = fields[0][0];
  
        if (*state == 'Z')
        {
                return (0);
        }
  
-       cpu_user_counter   = atoll (fields[13]);
-       cpu_system_counter = atoll (fields[14]);
-       vmem_size          = atoll (fields[22]);
-       vmem_rss           = atoll (fields[23]);
-       ps->vmem_minflt_counter = atoll (fields[9]);
-       ps->vmem_majflt_counter = atoll (fields[11]);
+       cpu_user_counter   = atoll (fields[11]);
+       cpu_system_counter = atoll (fields[12]);
+       vmem_size          = atoll (fields[20]);
+       vmem_rss           = atoll (fields[21]);
+       ps->vmem_minflt_counter = atol (fields[7]);
+       ps->vmem_majflt_counter = atol (fields[9]);
  
        {
-               unsigned long long stack_start = atoll (fields[27]);
-               unsigned long long stack_ptr   = atoll (fields[28]);
+               unsigned long long stack_start = atoll (fields[25]);
+               unsigned long long stack_ptr   = atoll (fields[26]);
  
                stack_size = (stack_start > stack_ptr)
                        ? stack_start - stack_ptr
                DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
        }
  
 -      ps->cpu_user_counter = (unsigned long) cpu_user_counter;
 -      ps->cpu_system_counter = (unsigned long) cpu_system_counter;
 +      ps->cpu_user_counter = cpu_user_counter;
 +      ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
        ps->vmem_rss = (unsigned long) vmem_rss;
        ps->stack_size = (unsigned long) stack_size;
diff --combined src/snmp.c
@@@ -69,7 -69,7 +69,7 @@@ struct host_definition_
    int version;
    void *sess_handle;
    c_complain_t complaint;
 -  uint32_t interval;
 +  cdtime_t interval;
    data_definition_t **data_list;
    int data_list_len;
  };
@@@ -159,6 -159,7 +159,6 @@@ static void csnmp_host_definition_destr
   *      +-> csnmp_config_add_host_community
   *      +-> csnmp_config_add_host_version
   *      +-> csnmp_config_add_host_collect
 - *      +-> csnmp_config_add_host_interval
   */
  static void call_snmp_init_once (void)
  {
@@@ -542,6 -543,22 +542,6 @@@ static int csnmp_config_add_host_collec
    return (0);
  } /* int csnmp_config_add_host_collect */
  
 -static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
 -{
 -  if ((ci->values_num != 1)
 -      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 -  {
 -    WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
 -    return (-1);
 -  }
 -
 -  hd->interval = ci->values[0].value.number >= 0
 -    ? (uint32_t) ci->values[0].value.number
 -    : 0;
 -
 -  return (0);
 -} /* int csnmp_config_add_host_interval */
 -
  static int csnmp_config_add_host (oconfig_item_t *ci)
  {
    host_definition_t *hd;
      else if (strcasecmp ("Collect", option->key) == 0)
        csnmp_config_add_host_collect (hd, option);
      else if (strcasecmp ("Interval", option->key) == 0)
 -      csnmp_config_add_host_interval (hd, option);
 +      cf_util_get_cdtime (option, &hd->interval);
      else
      {
        WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
    cb_data.data = hd;
    cb_data.free_func = csnmp_host_definition_destroy;
  
 -  memset (&cb_interval, 0, sizeof (cb_interval));
 -  if (hd->interval != 0)
 -    cb_interval.tv_sec = (time_t) hd->interval;
 +  CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
  
    status = plugin_register_complex_read (/* group = */ NULL, cb_name,
        csnmp_read_host, /* interval = */ &cb_interval,
@@@ -708,7 -727,9 +708,9 @@@ static value_t csnmp_value_list_to_valu
    value_t ret;
    uint64_t tmp_unsigned = 0;
    int64_t tmp_signed = 0;
-   int defined = 1;
+   _Bool defined = 1;
+   /* Set to true when the original SNMP type appears to have been signed. */
+   _Bool prefer_signed = 0;
  
    if ((vl->type == ASN_INTEGER)
        || (vl->type == ASN_UINTEGER)
    {
      tmp_unsigned = (uint32_t) *vl->val.integer;
      tmp_signed = (int32_t) *vl->val.integer;
-     DEBUG ("snmp plugin: Parsed int32 value is %"PRIi64".", tmp_signed);
+     if ((vl->type == ASN_INTEGER)
+         || (vl->type == ASN_GAUGE))
+       prefer_signed = 1;
+     DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", tmp_unsigned);
    }
    else if (vl->type == ASN_COUNTER64)
    {
    }
    else if (type == DS_TYPE_GAUGE)
    {
-     ret.gauge = NAN;
-     if (defined != 0)
+     if (!defined)
+       ret.gauge = NAN;
+     else if (prefer_signed)
        ret.gauge = (scale * tmp_signed) + shift;
+     else
+       ret.gauge = (scale * tmp_unsigned) + shift;
    }
    else if (type == DS_TYPE_DERIVE)
-     ret.derive = (derive_t) tmp_signed;
+   {
+     if (prefer_signed)
+       ret.derive = (derive_t) tmp_signed;
+     else
+       ret.derive = (derive_t) tmp_unsigned;
+   }
    else if (type == DS_TYPE_ABSOLUTE)
+   {
      ret.absolute = (absolute_t) tmp_unsigned;
+   }
    else
    {
      ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
@@@ -1510,8 -1546,8 +1527,8 @@@ static int csnmp_read_value (host_defin
  static int csnmp_read_host (user_data_t *ud)
  {
    host_definition_t *host;
 -  time_t time_start;
 -  time_t time_end;
 +  cdtime_t time_start;
 +  cdtime_t time_end;
    int status;
    int success;
    int i;
    if (host->interval == 0)
      host->interval = interval_g;
  
 -  time_start = time (NULL);
 -  DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name,
 -      (unsigned int) time_start);
 +  time_start = cdtime ();
  
    if (host->sess_handle == NULL)
      csnmp_host_open_session (host);
        success++;
    }
  
 -  time_end = time (NULL);
 -  DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
 -      (unsigned int) time_end);
 -  if ((uint32_t) (time_end - time_start) > host->interval)
 +  time_end = cdtime ();
 +  if ((time_end - time_start) > host->interval)
    {
 -    WARNING ("snmp plugin: Host `%s' should be queried every %"PRIu32
 -      " seconds, but reading all values takes %u seconds.",
 -      host->name, host->interval, (unsigned int) (time_end - time_start));
 +    WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
 +      "seconds, but reading all values takes %.3f seconds.",
 +      host->name,
 +      CDTIME_T_TO_DOUBLE (host->interval),
 +      CDTIME_T_TO_DOUBLE (time_end - time_start));
    }
  
    if (success == 0)