Merge branch 'collectd-5.4'
authorMarc Fournier <marc.fournier@camptocamp.com>
Wed, 7 Jan 2015 23:18:57 +0000 (00:18 +0100)
committerMarc Fournier <marc.fournier@camptocamp.com>
Wed, 7 Jan 2015 23:18:57 +0000 (00:18 +0100)
13 files changed:
1  2 
configure.ac
contrib/redhat/collectd.spec
src/collectd.conf.in
src/cpu.c
src/daemon/types_list.c
src/libcollectdclient/client.c
src/netlink.c
src/utils_cmd_flush.c
src/utils_cmd_getval.c
src/utils_cmd_listval.c
src/utils_cmd_putnotif.c
src/utils_cmd_putval.c
src/virt.c

diff --combined configure.ac
@@@ -1,6 -1,6 +1,6 @@@
  dnl Process this file with autoconf to produce a configure script.
  AC_INIT([collectd],[m4_esyscmd(./version-gen.sh)])
 -AC_CONFIG_SRCDIR(src/collectd.c)
 +AC_CONFIG_SRCDIR(src/)
  AC_CONFIG_HEADERS(src/config.h)
  AC_CONFIG_AUX_DIR([libltdl/config])
  
@@@ -70,11 -70,9 +70,11 @@@ case $host_os i
        ac_system="Solaris"
        ;;
        *darwin*)
 +      AC_DEFINE([KERNEL_DARWIN], 1, [True if program is to be compiled for a Darwin kernel])
        ac_system="Darwin"
        ;;
        *openbsd*)
 +      AC_DEFINE([KERNEL_OPENBSD], 1, [True if program is to be compiled for an OpenBSD kernel])
        ac_system="OpenBSD"
        ;;
        *aix*)
  esac
  AC_MSG_RESULT([$ac_system])
  
 +AM_CONDITIONAL([BUILD_LINUX],[test "x$x$ac_system" = "xLinux"])
 +AM_CONDITIONAL([BUILD_SOLARIS],[test "x$x$ac_system" = "xSolaris"])
 +AM_CONDITIONAL([BUILD_DARWIN],[test "x$x$ac_system" = "xDarwin"])
 +AM_CONDITIONAL([BUILD_OPENBSD],[test "x$x$ac_system" = "xOpenBSD"])
 +AM_CONDITIONAL([BUILD_AIX],[test "x$x$ac_system" = "xAIX"])
 +AM_CONDITIONAL([BUILD_FREEBSD],[test "x$x$ac_system" = "xFreeBSD"])
 +
  if test "x$ac_system" = "xLinux"
  then
        AC_ARG_VAR([KERNEL_DIR], [path to Linux kernel sources])
@@@ -527,7 -518,7 +527,7 @@@ AC_CHECK_HEADERS(linux/un.h, [], []
  #endif
  ])
  
 -AC_CHECK_HEADERS(pwd.h grp.h sys/un.h ctype.h limits.h xfs/xqm.h fs_info.h fshelp.h paths.h mntent.h mnttab.h sys/fstyp.h sys/fs_types.h sys/mntent.h sys/mnttab.h sys/statfs.h sys/statvfs.h sys/vfs.h sys/vfstab.h kvm.h wordexp.h)
 +AC_CHECK_HEADERS(pwd.h grp.h sys/un.h ctype.h limits.h xfs/xqm.h fs_info.h fshelp.h paths.h mntent.h mnttab.h sys/fstyp.h sys/fs_types.h sys/mntent.h sys/mnttab.h sys/statfs.h sys/statvfs.h sys/vfs.h sys/vfstab.h sys/vmmeter.h kvm.h wordexp.h locale.h)
  
  # For the dns plugin
  AC_CHECK_HEADERS(arpa/nameser.h)
@@@ -602,7 -593,7 +602,7 @@@ AC_HEADER_TIM
  # Checks for library functions.
  #
  AC_PROG_GCC_TRADITIONAL
 -AC_CHECK_FUNCS(gettimeofday select strdup strtol getaddrinfo getnameinfo strchr memcpy strstr strcmp strncmp strncpy strlen strncasecmp strcasecmp openlog closelog sysconf setenv if_indextoname)
 +AC_CHECK_FUNCS(gettimeofday select strdup strtol getaddrinfo getnameinfo strchr memcpy strstr strcmp strncmp strncpy strlen strncasecmp strcasecmp openlog closelog sysconf setenv if_indextoname setlocale)
  
  AC_FUNC_STRERROR_R
  
@@@ -809,9 -800,7 +809,9 @@@ if test "x$have_swapctl" = "xyes"; the
  #  undef _LARGEFILE64_SOURCE
  #endif
  #include <sys/stat.h>
 +#include <sys/param.h>
  #include <sys/swap.h>
 +#include <unistd.h>
  ]]],
  [[[
  int num = swapctl(0, NULL);
  #  undef _LARGEFILE64_SOURCE
  #endif
  #include <sys/stat.h>
 +#include <sys/param.h>
  #include <sys/swap.h>
 +#include <unistd.h>
  ]]],
  [[[
  int num = swapctl(0, NULL, 0);
@@@ -1006,7 -993,7 +1006,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = i0;
@@@ -1061,7 -1048,7 +1061,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = endianflip (i0);
@@@ -1110,7 -1097,7 +1110,7 @@@ if test "x$fp_layout_type" = "xunknown"
        uint8_t c[8];
        double d;
  
 -      d = 8.642135e130; 
 +      d = 8.642135e130;
        memcpy ((void *) &i0, (void *) &d, 8);
  
        i1 = intswap (i0);
    AC_MSG_ERROR([Didn't find out how doubles are stored in memory. Sorry.])
  fi; fi; fi
  
 +# --with-useragent {{{
 +AC_ARG_WITH(useragent, [AS_HELP_STRING([--with-useragent@<:@=AGENT@:>@], [User agent to use on http requests])],
 +[
 +    if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +    then
 +        AC_DEFINE_UNQUOTED(COLLECTD_USERAGENT, ["$withval"], [User agent for http requests])
 +    fi
 +])
 +
 +# }}}
 +
  have_getfsstat="no"
  AC_CHECK_FUNCS(getfsstat, [have_getfsstat="yes"])
  have_getvfsstat="no"
@@@ -1259,7 -1235,7 +1259,7 @@@ AC_CACHE_CHECK([if have htonll defined]
      )],
      [c_cv_have_htonll="yes"],
      [c_cv_have_htonll="no"]
 -       )
 +  )
  )
  if test "x$c_cv_have_htonll" = "xyes"
  then
@@@ -1315,7 -1291,7 +1315,7 @@@ AC_CHECK_MEMBERS([struct kinfo_proc.ki_
  #include <sys/user.h>
        ])
  
 -AC_CHECK_MEMBERS([struct kinfo_proc.kp_proc, struct kinfo_proc.kp_eproc],
 +AC_CHECK_MEMBERS([struct kinfo_proc.p_pid, struct kinfo_proc.p_vm_rssize],
        [
                AC_DEFINE(HAVE_STRUCT_KINFO_PROC_OPENBSD, 1,
                        [Define if struct kinfo_proc exists in the OpenBSD variant.])
  
  AC_CHECK_MEMBERS([struct udphdr.uh_dport, struct udphdr.uh_sport], [], [],
  [#define _BSD_SOURCE
 +#define _DEFAULT_SOURCE
  #if HAVE_STDINT_H
  # include <stdint.h>
  #endif
  ])
  AC_CHECK_MEMBERS([struct udphdr.dest, struct udphdr.source], [], [],
  [#define _BSD_SOURCE
 +#define _DEFAULT_SOURCE
  #if HAVE_STDINT_H
  # include <stdint.h>
  #endif
  m4_divert_once([HELP_WITH], [
  collectd additional packages:])
  
 -AM_CONDITIONAL([BUILD_FREEBSD],[test "x$x$ac_system" = "xFreeBSD"])
 -
 -AM_CONDITIONAL([BUILD_AIX],[test "x$x$ac_system" = "xAIX"]) 
 -
  if test "x$ac_system" = "xAIX"
  then
        with_perfstat="yes"
  AM_CONDITIONAL(BUILD_WITH_LIBAQUAERO5, test "x$with_libaquaero5" = "xyes")
  # }}}
  
 -# --with-libcredis {{{
 -AC_ARG_WITH(libcredis, [AS_HELP_STRING([--with-libcredis@<:@=PREFIX@:>@], [Path to libcredis.])],
 +# --with-libhiredis {{{
 +AC_ARG_WITH(libhiredis, [AS_HELP_STRING([--with-libhiredis@<:@=PREFIX@:>@],
 +      [Path to libhiredis.])],
  [
   if test "x$withval" = "xyes"
   then
 -       with_libcredis="yes"
 +       with_libhiredis="yes"
   else if test "x$withval" = "xno"
   then
 -       with_libcredis="no"
 +       with_libhiredis="no"
   else
 -       with_libcredis="yes"
 -       LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS -I$withval/include"
 -       LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS -L$withval/lib"
 +       with_libhiredis="yes"
 +       LIBHIREDIS_CPPFLAGS="$LIBHIREDIS_CPPFLAGS -I$withval/include"
 +       LIBHIREDIS_LDFLAGS="$LIBHIREDIS_LDFLAGS -L$withval/lib"
   fi; fi
  ],
 -[with_libcredis="yes"])
 +[with_libhiredis="yes"])
  
  SAVE_CPPFLAGS="$CPPFLAGS"
  SAVE_LDFLAGS="$LDFLAGS"
  
 -CPPFLAGS="$CPPFLAGS $LIBCREDIS_CPPFLAGS"
 -LDFLAGS="$LDFLAGS $LIBCREDIS_LDFLAGS"
 +CPPFLAGS="$CPPFLAGS $LIBHIREDIS_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $LIBHIREDIS_LDFLAGS"
  
 -if test "x$with_libcredis" = "xyes"
 +if test "x$with_libhiredis" = "xyes"
  then
 -      if test "x$LIBCREDIS_CPPFLAGS" != "x"
 +      if test "x$LIBHIREDIS_CPPFLAGS" != "x"
        then
 -              AC_MSG_NOTICE([libcredis CPPFLAGS: $LIBCREDIS_CPPFLAGS])
 +              AC_MSG_NOTICE([libhiredis CPPFLAGS: $LIBHIREDIS_CPPFLAGS])
        fi
 -      AC_CHECK_HEADERS(credis.h,
 -      [with_libcredis="yes"],
 -      [with_libcredis="no (credis.h not found)"])
 +      AC_CHECK_HEADERS(hiredis/hiredis.h,
 +      [with_libhiredis="yes"],
 +      [with_libhiredis="no (hiredis.h not found)"])
  fi
 -if test "x$with_libcredis" = "xyes"
 +if test "x$with_libhiredis" = "xyes"
  then
 -      if test "x$LIBCREDIS_LDFLAGS" != "x"
 +      if test "x$LIBHIREDIS_LDFLAGS" != "x"
        then
 -              AC_MSG_NOTICE([libcredis LDFLAGS: $LIBCREDIS_LDFLAGS])
 +              AC_MSG_NOTICE([libhiredis LDFLAGS: $LIBHIREDIS_LDFLAGS])
        fi
 -      AC_CHECK_LIB(credis, credis_info,
 -      [with_libcredis="yes"],
 -      [with_libcredis="no (symbol 'credis_info' not found)"])
 +      AC_CHECK_LIB(hiredis, redisCommand,
 +      [with_libhiredis="yes"],
 +      [with_libhiredis="no (symbol 'redisCommand' not found)"])
  
  fi
  
  CPPFLAGS="$SAVE_CPPFLAGS"
  LDFLAGS="$SAVE_LDFLAGS"
  
 -if test "x$with_libcredis" = "xyes"
 +if test "x$with_libhiredis" = "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)
 +      BUILD_WITH_LIBHIREDIS_CPPFLAGS="$LIBHIREDIS_CPPFLAGS"
 +      BUILD_WITH_LIBHIREDIS_LDFLAGS="$LIBHIREDIS_LDFLAGS"
 +      AC_SUBST(BUILD_WITH_LIBHIREDIS_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBHIREDIS_LDFLAGS)
  fi
 -AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes")
 +AM_CONDITIONAL(BUILD_WITH_LIBHIREDIS, test "x$with_libhiredis" = "xyes")
  # }}}
  
  # --with-libcurl {{{
                 [with_libcurl="yes"],
                 [with_libcurl="no (symbol 'curl_easy_init' not found)"],
                 [$with_curl_libs])
 +              AC_CHECK_DECL(CURLOPT_USERNAME,
 +               [have_curlopt_username="yes"],
 +               [have_curlopt_username="no"],
 +               [[#include <curl/curl.h>]])
        fi
  fi
  if test "x$with_libcurl" = "xyes"
        BUILD_WITH_LIBCURL_LIBS="$with_curl_libs"
        AC_SUBST(BUILD_WITH_LIBCURL_CFLAGS)
        AC_SUBST(BUILD_WITH_LIBCURL_LIBS)
 +
 +      if test "x$have_curlopt_username" = "xyes"
 +      then
 +              AC_DEFINE(HAVE_CURLOPT_USERNAME, 1, [Define if libcurl supports CURLOPT_USERNAME option.])
 +      fi
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBCURL, test "x$with_libcurl" = "xyes")
  # }}}
@@@ -1751,7 -1719,6 +1751,7 @@@ the
        LDFLAGS="$LDFLAGS $with_libdbi_ldflags"
  
        AC_CHECK_LIB(dbi, dbi_initialize, [with_libdbi="yes"], [with_libdbi="no (Symbol 'dbi_initialize' not found)"])
 +      AC_CHECK_LIB(dbi, dbi_driver_open_r, [with_libdbi_r="yes"], [with_libdbi_r="no"])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
        LDFLAGS="$SAVE_LDFLAGS"
        AC_SUBST(BUILD_WITH_LIBDBI_CPPFLAGS)
        AC_SUBST(BUILD_WITH_LIBDBI_LDFLAGS)
        AC_SUBST(BUILD_WITH_LIBDBI_LIBS)
 +
 +  if test "x$with_libdbi_r" = "xyes"
 +  then
 +              AC_DEFINE(HAVE_LIBDBI_R, 1, [Define if reentrant dbi facility is present and usable.])
 +  fi
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBDBI, test "x$with_libdbi" = "xyes")
  # }}}
@@@ -1964,7 -1926,7 +1964,7 @@@ the
                [with_libgcrypt="no (symbol gcry_md_hash_buffer not found)"])
  
        if test "$with_libgcrypt" != "no"; then
-               AM_PATH_LIBGCRYPT(1:1.2.0,,with_libgcrypt="no (version 1.2.0+ required)")
+               m4_ifdef([AM_PATH_LIBGCRYPT],[AM_PATH_LIBGCRYPT(1:1.2.0,,with_libgcrypt="no (version 1.2.0+ required)")])
                GCRYPT_CPPFLAGS="$LIBGCRYPT_CPPFLAGS $LIBGCRYPT_CFLAGS"
                GCRYPT_LIBS="$LIBGCRYPT_LIBS"
        fi
@@@ -1987,7 -1949,10 +1987,7 @@@ AM_CONDITIONAL(BUILD_WITH_LIBGCRYPT, te
  # --with-libiptc {{{
  AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])],
  [
 -      if test "x$withval" = "xshipped"
 -      then
 -              with_libiptc="own"
 -      else if test "x$withval" = "xyes"
 +      if test "x$withval" = "xyes"
        then
                with_libiptc="pkgconfig"
        else if test "x$withval" = "xno"
                with_libiptc="yes"
                with_libiptc_cflags="-I$withval/include"
                with_libiptc_libs="-L$withval/lib"
 -      fi; fi; fi
 +      fi; fi
  ],
  [
        if test "x$ac_system" = "xLinux"
  
  CPPFLAGS="$SAVE_CPPFLAGS"
  
 -if test "x$with_libiptc" = "xown"
 -then
 -      with_libiptc_cflags=""
 -      with_libiptc_libs=""
 -fi
 -if test "x$with_libiptc" = "xown"
 -then
 -      AC_CHECK_HEADERS(linux/netfilter_ipv4/ip_tables.h linux/netfilter_ipv6/ip6_tables.h linux/netfilter/x_tables.h, [],
 -      [
 -              with_libiptc="no (Linux iptables headers not found)"
 -      ],
 -      [
 -#include "$srcdir/src/owniptc/ipt_kernel_headers.h"
 -      ])
 -fi
 -AM_CONDITIONAL(BUILD_WITH_OWN_LIBIPTC, test "x$with_libiptc" = "xown")
 -if test "x$with_libiptc" = "xown"
 -then
 -      AC_DEFINE(OWN_LIBIPTC, 1, [Define to 1 if we use the shipped iptc library.])
 -      with_libiptc="yes"
 -fi
 -
  AM_CONDITIONAL(BUILD_WITH_LIBIPTC, test "x$with_libiptc" = "xyes")
  if test "x$with_libiptc" = "xyes"
  then
@@@ -2248,64 -2235,6 +2248,64 @@@ AC_SUBST(JAVA_LIBS
  AM_CONDITIONAL(BUILD_WITH_JAVA, test "x$with_java" = "xyes")
  # }}}
  
 +# --with-libldap {{{
 +AC_ARG_WITH(libldap, [AS_HELP_STRING([--with-libldap@<:@=PREFIX@:>@], [Path to libldap.])],
 +[
 + if test "x$withval" = "xyes"
 + then
 +       with_libldap="yes"
 + else if test "x$withval" = "xno"
 + then
 +       with_libldap="no"
 + else
 +       with_libldap="yes"
 +       LIBLDAP_CPPFLAGS="$LIBLDAP_CPPFLAGS -I$withval/include"
 +       LIBLDAP_LDFLAGS="$LIBLDAP_LDFLAGS -L$withval/lib"
 + fi; fi
 +],
 +[with_libldap="yes"])
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +CPPFLAGS="$CPPFLAGS $LIBLDAP_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $LIBLDAP_LDFLAGS"
 +
 +if test "x$with_libldap" = "xyes"
 +then
 +      if test "x$LIBLDAP_CPPFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([libldap CPPFLAGS: $LIBLDAP_CPPFLAGS])
 +      fi
 +      AC_CHECK_HEADERS(ldap.h,
 +      [with_libldap="yes"],
 +      [with_libldap="no ('ldap.h' not found)"])
 +fi
 +if test "x$with_libldap" = "xyes"
 +then
 +      if test "x$LIBLDAP_LDFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([libldap LDFLAGS: $LIBLDAP_LDFLAGS])
 +      fi
 +      AC_CHECK_LIB(ldap, ldap_initialize,
 +      [with_libldap="yes"],
 +      [with_libldap="no (symbol 'ldap_initialize' not found)"])
 +
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +if test "x$with_libldap" = "xyes"
 +then
 +      BUILD_WITH_LIBLDAP_CPPFLAGS="$LIBLDAP_CPPFLAGS"
 +      BUILD_WITH_LIBLDAP_LDFLAGS="$LIBLDAP_LDFLAGS"
 +      AC_SUBST(BUILD_WITH_LIBLDAP_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBLDAP_LDFLAGS)
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBLDAP, test "x$with_libldap" = "xyes")
 +# }}}
 +
  # --with-liblvm2app {{{
  with_liblvm2app_cppflags=""
  with_liblvm2app_ldflags=""
@@@ -2340,7 -2269,7 +2340,7 @@@ the
          CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
          LDFLAGS="$LDFLAGS $with_liblvm2app_ldflags"
  
 -        AC_CHECK_LIB(lvm2app, lvm_init, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_init' not found)"])
 +        AC_CHECK_LIB(lvm2app, lvm_lv_get_property, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_lv_get_property' not found)"])
  
          CPPFLAGS="$SAVE_CPPFLAGS"
          LDFLAGS="$SAVE_LDFLAGS"
@@@ -2742,15 -2671,6 +2742,15 @@@ return (retval)
  fi
  if test "x$with_libmnl" = "xyes"
  then
 +      AC_CHECK_MEMBERS([struct rtnl_link_stats64.tx_window_errors],
 +      [AC_DEFINE(HAVE_RTNL_LINK_STATS64, 1, [Define if struct rtnl_link_stats64 exists and is usable.])],
 +      [],
 +      [
 +      #include <linux/if_link.h>
 +      ])
 +fi
 +if test "x$with_libmnl" = "xyes"
 +then
        AC_CHECK_LIB(mnl, mnl_nlmsg_get_payload,
                     [with_libmnl="yes"],
                     [with_libmnl="no (symbol 'mnl_nlmsg_get_payload' not found)"],
@@@ -2874,7 -2794,7 +2874,7 @@@ the
        else
                SAVE_CPPFLAGS="$CPPFLAGS"
                CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
 -              
 +
                AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
  
                CPPFLAGS="$SAVE_CPPFLAGS"
@@@ -3101,7 -3021,7 +3101,7 @@@ if test "x$with_libowcapi" = "xyes
  then
        SAVE_CPPFLAGS="$CPPFLAGS"
        CPPFLAGS="$with_libowcapi_cppflags"
 -      
 +
        AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
@@@ -3112,7 -3032,7 +3112,7 @@@ the
        SAVE_CPPFLAGS="$CPPFLAGS"
        LDFLAGS="$with_libowcapi_libs"
        CPPFLAGS="$with_libowcapi_cppflags"
 -      
 +
        AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"])
  
        LDFLAGS="$SAVE_LDFLAGS"
  fi
  # }}}
  
 +# --with-librdkafka {{{
 +AC_ARG_WITH(librdkafka, [AS_HELP_STRING([--with-librdkafka@<:@=PREFIX@:>@], [Path to librdkafka.])],
 +[
 +  if test "x$withval" = "xno" && test "x$withval" != "xyes"
 +  then
 +    with_librdkafka_cppflags="-I$withval/include"
 +    with_librdkafka_ldflags="-L$withval/lib"
 +    with_librdkafka="yes"
 +  else
 +    with_librdkafka="$withval"
 +  fi
 +],
 +[
 +  with_librdkafka="yes"
 +])
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      AC_CHECK_HEADERS(librdkafka/rdkafka.h, [with_librdkafka="yes"], [with_librdkafka="no (librdkafka/rdkafka.h not found)"])
 +fi
 +
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      AC_CHECK_LIB(rdkafka, rd_kafka_new, [with_librdkafka="yes"], [with_librdkafka="no (Symbol 'rd_kafka_new' not found)"])
 +  AC_CHECK_LIB(rdkafka, rd_kafka_conf_set_log_cb, [with_librdkafka_log_cb="yes"], [with_librdkafka_log_cb="no"])
 +  AC_CHECK_LIB(rdkafka, rd_kafka_conf_set_logger, [with_librdkafka_logger="yes"], [with_librdkafka_logger="no"])
 +fi
 +if test "x$with_librdkafka" = "xyes"
 +then
 +      BUILD_WITH_LIBRDKAFKA_CPPFLAGS="$with_librdkafka_cppflags"
 +      BUILD_WITH_LIBRDKAFKA_LDFLAGS="$with_librdkafka_ldflags"
 +      BUILD_WITH_LIBRDKAFKA_LIBS="-lrdkafka"
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBRDKAFKA_LIBS)
 +      AC_DEFINE(HAVE_LIBRDKAFKA, 1, [Define if librdkafka is present and usable.])
 +  if test "x$with_librdkafka_log_cb" = "xyes"
 +  then
 +        AC_DEFINE(HAVE_LIBRDKAFKA_LOG_CB, 1, [Define if librdkafka log facility is present and usable.])
 +  fi
 +  if test "x$with_librdkafka_logger" = "xyes"
 +  then
 +        AC_DEFINE(HAVE_LIBRDKAFKA_LOGGER, 1, [Define if librdkafka log facility is present and usable.])
 +  fi
 +fi
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +AM_CONDITIONAL(BUILD_WITH_LIBRDKAFKA, test "x$with_librdkafka" = "xyes")
 +
 +# }}}
 +
  # --with-librouteros {{{
  AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
  [
    LDFLAGS="$SAVE_LDFLAGS"
  fi
  
 +if test "x$with_libstatgrab" = "xyes"
 +then
 +  SAVE_CFLAGS="$CFLAGS"
 +  SAVE_LDFLAGS="$LDFLAGS"
 +
 +  CFLAGS="$CFLAGS $with_libstatgrab_cflags"
 +  LDFLAGS="$LDFLAGS $with_libstatgrab_ldflags"
 +
 +  AC_CACHE_CHECK([if libstatgrab >= 0.90],
 +          [c_cv_have_libstatgrab_0_90],
 +          AC_LINK_IFELSE([AC_LANG_PROGRAM(
 +[[[
 +#include <stdio.h>
 +#include <statgrab.h>
 +]]],
 +[[[
 +      if (sg_init()) return 0;
 +]]]
 +    )],
 +    [c_cv_have_libstatgrab_0_90="no"],
 +    [c_cv_have_libstatgrab_0_90="yes"]
 +          )
 +  )
 +
 +  CFLAGS="$SAVE_CFLAGS"
 +  LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +
  AM_CONDITIONAL(BUILD_WITH_LIBSTATGRAB, test "x$with_libstatgrab" = "xyes")
  if test "x$with_libstatgrab" = "xyes"
  then
    BUILD_WITH_LIBSTATGRAB_LDFLAGS="$with_libstatgrab_ldflags"
    AC_SUBST(BUILD_WITH_LIBSTATGRAB_CFLAGS)
    AC_SUBST(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
 +  if test "x$c_cv_have_libstatgrab_0_90" = "xyes"
 +  then
 +        AC_DEFINE(HAVE_LIBSTATGRAB_0_90, 1, [Define to 1 if libstatgrab version >= 0.90])
 +  fi
  fi
  # }}}
  
@@@ -4241,7 -4076,7 +4241,7 @@@ CPPFLAGS="$SAVE_CPPFLAGS
  LDFLAGS="$SAVE_LDFLAGS"
  
  if test "x$with_libtokyotyrant" = "xyes"
 -then 
 +then
    BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS="$with_libtokyotyrant_cppflags"
    BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS="$with_libtokyotyrant_ldflags"
    BUILD_WITH_LIBTOKYOTYRANT_LIBS="$with_libtokyotyrant_libs"
  AM_CONDITIONAL(BUILD_WITH_LIBTOKYOTYRANT, test "x$with_libtokyotyrant" = "xyes")
  # }}}
  
 +# --with-libudev {{{
 +with_libudev_cflags=""
 +with_libudev_ldflags=""
 +AC_ARG_WITH(libudev, [AS_HELP_STRING([--with-libudev@<:@=PREFIX@:>@], [Path to libudev.])],
 +[
 +      if test "x$withval" = "xno"
 +      then
 +              with_libudev="no"
 +      else
 +              with_libudev="yes"
 +              if test "x$withval" != "xyes"
 +              then
 +                      with_libudev_cflags="-I$withval/include"
 +                      with_libudev_ldflags="-L$withval/lib"
 +                      with_libudev="yes"
 +              fi
 +      fi
 +],
 +[
 +      if test "x$ac_system" = "xLinux"
 +      then
 +              with_libudev="yes"
 +      else
 +              with_libudev="no (Linux only library)"
 +      fi
 +])
 +if test "x$with_libudev" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
 +
 +      AC_CHECK_HEADERS(libudev.h, [], [with_libudev="no (libudev.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libudev" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libudev_cflags"
 +      LDFLAGS="$LDFLAGS $with_libudev_ldflags"
 +
 +      AC_CHECK_LIB(udev, udev_new,
 +      [
 +              AC_DEFINE(HAVE_LIBUDEV, 1, [Define to 1 if you have the udev library (-ludev).])
 +      ],
 +      [with_libudev="no (libudev not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libudev" = "xyes"
 +then
 +      BUILD_WITH_LIBUDEV_CFLAGS="$with_libudev_cflags"
 +      BUILD_WITH_LIBUDEV_LDFLAGS="$with_libudev_ldflags"
 +      AC_SUBST(BUILD_WITH_LIBUDEV_CFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBUDEV_LDFLAGS)
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBUDEV, test "x$with_libudev" = "xyes")
 +# }}}
 +
  # --with-libupsclient {{{
  with_libupsclient_config=""
  with_libupsclient_cflags=""
  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_HEADERS(varnish/vsc.h,
 -        [AC_DEFINE([HAVE_VARNISH_V3], [1], [Varnish 3 API support])],
 -        [AC_DEFINE([HAVE_VARNISH_V2], [1], [Varnish 2 API support])])
 +      AC_CHECK_HEADERS(varnish/vapi/vsc.h,
 +              [AC_DEFINE([HAVE_VARNISH_V4], [1], [Varnish 4 API support])],
 +              [AC_CHECK_HEADERS(varnish/vsc.h,
 +                      [AC_DEFINE([HAVE_VARNISH_V3], [1], [Varnish 3 API support])],
 +                      [AC_CHECK_HEADERS(varnish/varnishapi.h,
 +                              [AC_DEFINE([HAVE_VARNISH_V2], [1], [Varnish 2 API support])],
 +                              [with_libvarnish="no (found none of the varnish header files)"])])])
  
        CPPFLAGS="$SAVE_CPPFLAGS"
 -      #LDFLAGS="$SAVE_LDFLAGS"
  fi
  if test "x$with_libvarnish" = "xyes"
  then
  fi
  # }}}
  
 +# --with-libatasmart {{{
 +with_libatasmart_cppflags=""
 +with_libatasmart_ldflags=""
 +AC_ARG_WITH(libatasmart, [AS_HELP_STRING([--with-libatasmart@<:@=PREFIX@:>@], [Path to libatasmart.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              with_libatasmart_cppflags="-I$withval/include"
 +              with_libatasmart_ldflags="-L$withval/lib"
 +              with_libatasmart="yes"
 +      else
 +              with_libatasmart="$withval"
 +      fi
 +],
 +[
 +      if test "x$ac_system" = "xLinux"
 +      then
 +              with_libatasmart="yes"
 +      else
 +              with_libatasmart="no (Linux only library)"
 +      fi
 +])
 +if test "x$with_libatasmart" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libatasmart_cppflags"
 +
 +      AC_CHECK_HEADERS(atasmart.h, [with_libatasmart="yes"], [with_libatasmart="no (atasmart.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libatasmart" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libatasmart_cppflags"
 +      LDFLAGS="$LDFLAGS $with_libatasmart_ldflags"
 +
 +      AC_CHECK_LIB(atasmart, sk_disk_open, [with_libatasmart="yes"], [with_libatasmart="no (Symbol 'sk_disk_open' not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libatasmart" = "xyes"
 +then
 +      BUILD_WITH_LIBATASMART_CPPFLAGS="$with_libatasmart_cppflags"
 +      BUILD_WITH_LIBATASMART_LDFLAGS="$with_libatasmart_ldflags"
 +      BUILD_WITH_LIBATASMART_LIBS="-latasmart"
 +      AC_SUBST(BUILD_WITH_LIBATASMART_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBATASMART_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBATASMART_LIBS)
 +      AC_DEFINE(HAVE_LIBATASMART, 1, [Define if libatasmart is present and usable.])
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBATASMART, test "x$with_libatasmart" = "xyes")
 +# }}}
 +
  PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
                [with_libnotify="yes"],
                [if test "x$LIBNOTIFY_PKG_ERRORS" = "x"; then
@@@ -5098,7 -4823,6 +5098,7 @@@ dependency_warning="no
  dependency_error="no"
  
  plugin_ascent="no"
 +plugin_barometer="no"
  plugin_battery="no"
  plugin_bind="no"
  plugin_cgroups="no"
@@@ -5110,7 -4834,6 +5110,7 @@@ plugin_curl_json="no
  plugin_curl_xml="no"
  plugin_df="no"
  plugin_disk="no"
 +plugin_drbd="no"
  plugin_entropy="no"
  plugin_ethstat="no"
  plugin_fscache="no"
@@@ -5118,8 -4841,8 +5118,8 @@@ plugin_interface="no
  plugin_ipmi="no"
  plugin_ipvs="no"
  plugin_irq="no"
 -plugin_libvirt="no"
  plugin_load="no"
 +plugin_log_logstash="no"
  plugin_memory="no"
  plugin_multimeter="no"
  plugin_nfs="no"
@@@ -5133,14 -4856,12 +5133,14 @@@ plugin_tape="no
  plugin_tcpconns="no"
  plugin_ted="no"
  plugin_thermal="no"
 -plugin_users="no"
  plugin_uptime="no"
 +plugin_users="no"
 +plugin_virt="no"
  plugin_vmem="no"
  plugin_vserver="no"
  plugin_wireless="no"
  plugin_zfs_arc="no"
 +plugin_zookeeper="no"
  
  # Linux
  if test "x$ac_system" = "xLinux"
@@@ -5152,7 -4873,6 +5152,7 @@@ the
        plugin_cpu="yes"
        plugin_cpufreq="yes"
        plugin_disk="yes"
 +      plugin_drbd="yes"
        plugin_entropy="yes"
        plugin_fscache="yes"
        plugin_interface="yes"
        plugin_vmem="yes"
        plugin_vserver="yes"
        plugin_wireless="yes"
 +      plugin_zfs_arc="yes"
  
        if test "x$have_linux_ip_vs_h" = "xyes" || test "x$have_net_ip_vs_h" = "xyes" || test "x$have_ip_vs_h" = "xyes"
        then
        plugin_tape="yes"
  fi
  
 +# libi2c-dev
 +with_libi2c="no"
 +if test "x$ac_system" = "xLinux"
 +then
 +AC_CHECK_DECL(i2c_smbus_read_i2c_block_data,
 +      [with_libi2c="yes"],
 +      [with_libi2c="no (symbol i2c_smbus_read_i2c_block_data not found - have you installed libi2c-dev ?)"],
 +      [[#include <stdlib.h>
 +      #include <linux/i2c-dev.h>]])
 +fi
 +
 +if test "x$with_libi2c" = "xyes"
 +then
 +      plugin_barometer="yes"
 +fi
 +
 +
  # libstatgrab
  if test "x$with_libstatgrab" = "xyes"
  then
        plugin_interface="yes"
  fi
  
 -if test "x$with_libxml2" = "xyes" && test "x$with_libvirt" = "xyes"
 +if test "x$have_getloadavg" = "xyes"
  then
 -      plugin_libvirt="yes"
 +      plugin_load="yes"
  fi
  
 -if test "x$have_getloadavg" = "xyes"
 +if test "x$with_libyajl" = "xyes"
  then
 -      plugin_load="yes"
 +      plugin_log_logstash="yes"
  fi
  
  if test "x$c_cv_have_libperl$c_cv_have_perl_ithreads" = "xyesyes"
  
  if test "x$have_termios_h" = "xyes"
  then
 -      plugin_multimeter="yes"
 +      if test "x$ac_system" != "xAIX"
 +      then
 +              plugin_multimeter="yes"
 +      fi
        plugin_ted="yes"
  fi
  
        plugin_processes="yes"
  fi
  
 +if test "x$with_kvm_getprocs" = "xyes" && test "x$have_struct_kinfo_proc_openbsd" = "xyes"
 +then
 +      plugin_processes="yes"
 +fi
 +
  if test "x$with_kvm_getswapinfo" = "xyes"
  then
        plugin_swap="yes"
        plugin_users="yes"
  fi
  
 +if test "x$with_libxml2" = "xyes" && test "x$with_libvirt" = "xyes"
 +then
 +      plugin_virt="yes"
 +fi
 +
 +
  m4_divert_once([HELP_ENABLE], [
  collectd plugins:])
  
@@@ -5463,7 -5151,6 +5463,7 @@@ AC_PLUGIN([apcups],      [yes]
  AC_PLUGIN([apple_sensors], [$with_libiokit],   [Apple's hardware sensors])
  AC_PLUGIN([aquaero],     [$with_libaquaero5],  [Aquaero's hardware sensors])
  AC_PLUGIN([ascent],      [$plugin_ascent],     [AscentEmu player statistics])
 +AC_PLUGIN([barometer],   [$plugin_barometer],  [Barometer sensor on I2C])
  AC_PLUGIN([battery],     [$plugin_battery],    [Battery statistics])
  AC_PLUGIN([bind],        [$plugin_bind],       [ISC Bind nameserver statistics])
  AC_PLUGIN([conntrack],   [$plugin_conntrack],  [nf_conntrack statistics])
@@@ -5478,7 -5165,6 +5478,7 @@@ AC_PLUGIN([cgroups],     [$plugin_cgrou
  AC_PLUGIN([dbi],         [$with_libdbi],       [General database statistics])
  AC_PLUGIN([df],          [$plugin_df],         [Filesystem usage statistics])
  AC_PLUGIN([disk],        [$plugin_disk],       [Disk usage statistics])
 +AC_PLUGIN([drbd],        [$plugin_drbd],       [DRBD statistics])
  AC_PLUGIN([dns],         [$with_libpcap],      [DNS traffic analysis])
  AC_PLUGIN([email],       [yes],                [EMail statistics])
  AC_PLUGIN([entropy],     [$plugin_entropy],    [Entropy statistics])
@@@ -5494,9 -5180,9 +5494,9 @@@ AC_PLUGIN([iptables],    [$with_libiptc
  AC_PLUGIN([ipvs],        [$plugin_ipvs],       [IPVS connection statistics])
  AC_PLUGIN([irq],         [$plugin_irq],        [IRQ statistics])
  AC_PLUGIN([java],        [$with_java],         [Embed the Java Virtual Machine])
 -AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
  AC_PLUGIN([load],        [$plugin_load],       [System load])
  AC_PLUGIN([logfile],     [yes],                [File logging plugin])
 +AC_PLUGIN([log_logstash], [$plugin_log_logstash], [Logstash json_event compatible logging])
  AC_PLUGIN([lpar],        [$with_perfstat],     [AIX logical partitions statistics])
  AC_PLUGIN([lvm],         [$with_liblvm2app],   [LVM statistics])
  AC_PLUGIN([madwifi],     [$have_linux_wireless_h], [Madwifi wireless statistics])
@@@ -5526,7 -5212,6 +5526,7 @@@ AC_PLUGIN([numa],        [$plugin_numa]
  AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
  AC_PLUGIN([olsrd],       [yes],                [olsrd statistics])
  AC_PLUGIN([onewire],     [$with_libowcapi],    [OneWire sensor statistics])
 +AC_PLUGIN([openldap],    [$with_libldap],      [OpenLDAP statistics])
  AC_PLUGIN([openvpn],     [yes],                [OpenVPN client statistics])
  AC_PLUGIN([oracle],      [$with_oracle],       [Oracle plugin])
  AC_PLUGIN([perl],        [$plugin_perl],       [Embed a Perl interpreter])
@@@ -5539,14 -5224,13 +5539,14 @@@ 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([redis],       [$with_libhiredis],    [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])
  AC_PLUGIN([sensors],     [$with_libsensors],   [lm_sensors statistics])
  AC_PLUGIN([serial],      [$plugin_serial],     [serial port traffic])
  AC_PLUGIN([sigrok],      [$with_libsigrok],    [sigrok acquisition sources])
 +AC_PLUGIN([smart],       [$with_libatasmart],  [SMART statistics])
  AC_PLUGIN([snmp],        [$with_libnetsnmp],   [SNMP querying plugin])
  AC_PLUGIN([statsd],      [yes],                [StatsD plugin])
  AC_PLUGIN([swap],        [$plugin_swap],       [Swap usage statistics])
@@@ -5571,26 -5255,21 +5571,26 @@@ AC_PLUGIN([uptime],      [$plugin_uptim
  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([virt],        [$plugin_virt],       [Virtual machine 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_graphite], [yes],             [Graphite / Carbon output plugin])
  AC_PLUGIN([write_http],  [$with_libcurl],      [HTTP output plugin])
 +AC_PLUGIN([write_kafka],  [$with_librdkafka],  [Kafka output plugin])
  AC_PLUGIN([write_mongodb], [$with_libmongoc],  [MongoDB output plugin])
 -AC_PLUGIN([write_redis], [$with_libcredis],    [Redis output plugin])
 +AC_PLUGIN([write_redis], [$with_libhiredis],    [Redis output plugin])
  AC_PLUGIN([write_riemann], [$have_protoc_c],   [Riemann output plugin])
 +AC_PLUGIN([write_tsdb],  [yes],                [TSDB output plugin])
  AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
  AC_PLUGIN([zfs_arc],     [$plugin_zfs_arc],    [ZFS ARC statistics])
 +AC_PLUGIN([zookeeper],   [yes],              [Zookeeper statistics])
  
  dnl Default configuration file
  # Load either syslog or logfile
  LOAD_PLUGIN_SYSLOG=""
  LOAD_PLUGIN_LOGFILE=""
 +LOAD_PLUGIN_LOG_LOGSTASH=""
  
  AC_MSG_CHECKING([which default log plugin to load])
  default_log_plugin="none"
  else
        LOAD_PLUGIN_LOGFILE="##"
  fi
 +
 +if test "x$enable_log_logstash" = "xyes"
 +then
 +  LOAD_PLUGIN_LOG_LOGSTASH="#"
 +else
 +  LOAD_PLUGIN_LOG_LOGSTASH="##"
 +fi
 +
 +
  AC_MSG_RESULT([$default_log_plugin])
  
  AC_SUBST(LOAD_PLUGIN_SYSLOG)
  AC_SUBST(LOAD_PLUGIN_LOGFILE)
 +AC_SUBST(LOAD_PLUGIN_LOG_LOGSTASH)
  
  DEFAULT_LOG_LEVEL="info"
  if test "x$enable_debug" = "xyes"
@@@ -5735,7 -5404,7 +5735,7 @@@ AC_SUBST(LCC_VERSION_STRING
  
  AC_CONFIG_FILES(src/libcollectdclient/collectd/lcc_features.h)
  
 -AC_CONFIG_FILES([Makefile src/Makefile src/collectd.conf src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile bindings/java/Makefile])
 +AC_CONFIG_FILES([Makefile src/Makefile src/daemon/Makefile src/collectd.conf src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile bindings/java/Makefile])
  AC_OUTPUT
  
  if test "x$with_librrd" = "xyes" \
@@@ -5768,21 -5437,17 +5768,21 @@@ Configuration
    Libraries:
      intel mic . . . . . . $with_mic
      libaquaero5 . . . . . $with_libaquaero5
 +    libatasmart . . . . . $with_libatasmart
      libcurl . . . . . . . $with_libcurl
      libdbi  . . . . . . . $with_libdbi
 -    libcredis . . . . . . $with_libcredis
 +    libhiredis  . . . . . $with_libhiredis
      libesmtp  . . . . . . $with_libesmtp
      libganglia  . . . . . $with_libganglia
      libgcrypt . . . . . . $with_libgcrypt
 +    libi2c-dev  . . . . . $with_libi2c
      libiokit  . . . . . . $with_libiokit
      libiptc . . . . . . . $with_libiptc
      libjvm  . . . . . . . $with_java
      libkstat  . . . . . . $with_kstat
      libkvm  . . . . . . . $with_libkvm
 +    libldap . . . . . . . $with_libldap
 +    liblvm2app  . . . . . $with_liblvm2app
      libmemcached  . . . . $with_libmemcached
      libmnl  . . . . . . . $with_libmnl
      libmodbus . . . . . . $with_libmodbus
      libpq . . . . . . . . $with_libpq
      libpthread  . . . . . $with_libpthread
      librabbitmq . . . . . $with_librabbitmq
 +    librdkafka  . . . . . $with_librdkafka
      librouteros . . . . . $with_librouteros
      librrd  . . . . . . . $with_librrd
      libsensors  . . . . . $with_libsensors
      libsigrok   . . . . . $with_libsigrok
      libstatgrab . . . . . $with_libstatgrab
      libtokyotyrant  . . . $with_libtokyotyrant
 +    libudev . . . . . . . $with_libudev
      libupsclient  . . . . $with_libupsclient
      libvarnish  . . . . . $with_libvarnish
      libvirt . . . . . . . $with_libvirt
      aquaero . . . . . . . $enable_aquaero
      apple_sensors . . . . $enable_apple_sensors
      ascent  . . . . . . . $enable_ascent
 +    barometer . . . . . . $enable_barometer
      battery . . . . . . . $enable_battery
      bind  . . . . . . . . $enable_bind
      conntrack . . . . . . $enable_conntrack
      df  . . . . . . . . . $enable_df
      disk  . . . . . . . . $enable_disk
      dns . . . . . . . . . $enable_dns
 +    drbd  . . . . . . . . $enable_drbd
      email . . . . . . . . $enable_email
      entropy . . . . . . . $enable_entropy
      ethstat . . . . . . . $enable_ethstat
      ipvs  . . . . . . . . $enable_ipvs
      irq . . . . . . . . . $enable_irq
      java  . . . . . . . . $enable_java
 -    libvirt . . . . . . . $enable_libvirt
      load  . . . . . . . . $enable_load
      logfile . . . . . . . $enable_logfile
      lpar  . . . . . . . . $enable_lpar
 +    log_logstash  . . . . $enable_log_logstash
      lvm . . . . . . . . . $enable_lvm
      madwifi . . . . . . . $enable_madwifi
      match_empty_counter . $enable_match_empty_counter
      nut . . . . . . . . . $enable_nut
      olsrd . . . . . . . . $enable_olsrd
      onewire . . . . . . . $enable_onewire
 +    openldap  . . . . . . $enable_openldap
      openvpn . . . . . . . $enable_openvpn
      oracle  . . . . . . . $enable_oracle
      perl  . . . . . . . . $enable_perl
      sensors . . . . . . . $enable_sensors
      serial  . . . . . . . $enable_serial
      sigrok  . . . . . . . $enable_sigrok
 +    smart . . . . . . . . $enable_smart
      snmp  . . . . . . . . $enable_snmp
      statsd  . . . . . . . $enable_statsd
      swap  . . . . . . . . $enable_swap
      users . . . . . . . . $enable_users
      uuid  . . . . . . . . $enable_uuid
      varnish . . . . . . . $enable_varnish
 +    virt  . . . . . . . . $enable_virt
      vmem  . . . . . . . . $enable_vmem
      vserver . . . . . . . $enable_vserver
      wireless  . . . . . . $enable_wireless
      write_graphite  . . . $enable_write_graphite
      write_http  . . . . . $enable_write_http
 +    write_kafka . . . . . $enable_write_kafka
      write_mongodb . . . . $enable_write_mongodb
      write_redis . . . . . $enable_write_redis
      write_riemann . . . . $enable_write_riemann
 +    write_tsdb  . . . . . $enable_write_tsdb
      xmms  . . . . . . . . $enable_xmms
      zfs_arc . . . . . . . $enable_zfs_arc
 +    zookeeper . . . . . . $enable_zookeeper
  
  EOF
  
  %{?el6:%global _has_ip_vs_h 1}
  %{?el6:%global _has_lvm2app_h 1}
  %{?el6:%global _has_libmodbus 1}
 +%{?el6:%global _has_libudev 1}
  %{?el6:%global _has_iproute 1}
 +%{?el6:%global _has_atasmart 1}
 +%{?el6:%global _has_hiredis 1}
  
  %{?el7:%global _has_libyajl 1}
  %{?el7:%global _has_recent_libpcap 1}
  %{?el7:%global _has_working_libiptc 1}
  %{?el7:%global _has_ip_vs_h 1}
  %{?el7:%global _has_lvm2app_h 1}
 +%{?el7:%global _has_libudev 1}
  %{?el7:%global _has_recent_librrd 1}
  %{?el7:%global _has_varnish4 1}
  %{?el7:%global _has_broken_libmemcached 1}
  %{?el7:%global _has_iproute 1}
 +%{?el7:%global _has_atasmart 1}
 +%{?el7:%global _has_hiredis 1}
  
  # plugins enabled by default
  %define with_aggregation 0%{!?_without_aggregation:1}
@@@ -85,7 -79,6 +85,7 @@@
  %define with_df 0%{!?_without_df:1}
  %define with_disk 0%{!?_without_disk:1}
  %define with_dns 0%{!?_without_dns:0%{?_has_recent_libpcap}}
 +%define with_drbd 0%{!?_without_drbd:1}
  %define with_email 0%{!?_without_email:1}
  %define with_entropy 0%{!?_without_entropy:1}
  %define with_ethstat 0%{!?_without_ethstat:0%{?_has_recent_sockios_h}}
  %define with_ipvs 0%{!?_without_ipvs:0%{?_has_ip_vs_h}}
  %define with_irq 0%{!?_without_irq:1}
  %define with_java 0%{!?_without_java:1}
 -%define with_libvirt 0%{!?_without_libvirt:1}
 +%define with_virt 0%{!?_without_virt:1}
  %define with_load 0%{!?_without_load:1}
  %define with_logfile 0%{!?_without_logfile:1}
 +%define with_log_logstash 0%{!?_without_log_logstash:0%{?_has_libyajl}}
  %define with_lvm 0%{!?_without_lvm:0%{?_has_lvm2app_h}}
  %define with_madwifi 0%{!?_without_madwifi:1}
  %define with_mbmon 0%{!?_without_mbmon:1}
  %define with_numa 0%{!?_without_numa:1}
  %define with_nut 0%{!?_without_nut:1}
  %define with_olsrd 0%{!?_without_olsrd:1}
 +%define with_openldap 0%{!?_without_openldap:1}
  %define with_openvpn 0%{!?_without_openvpn:1}
  %define with_perl 0%{!?_without_perl:1}
  %define with_pinba 0%{!?_without_pinba:1}
  %define with_processes 0%{!?_without_processes:1}
  %define with_protocols 0%{!?_without_protocols:1}
  %define with_python 0%{!?_without_python:1}
 +%define with_redis 0%{!?_without_redis:0%{?_has_hiredis}}
  %define with_rrdcached 0%{!?_without_rrdcached:0%{?_has_recent_librrd}}
  %define with_rrdtool 0%{!?_without_rrdtool:1}
  %define with_sensors 0%{!?_without_sensors:1}
  %define with_serial 0%{!?_without_serial:1}
 +%define with_smart 0%{!?_without_smart:0%{?_has_atasmart}}
  %define with_snmp 0%{!?_without_snmp:1}
  %define with_statsd 0%{!?_without_statsd:1}
  %define with_swap 0%{!?_without_swap:1}
  %define with_wireless 0%{!?_without_wireless:1}
  %define with_write_graphite 0%{!?_without_write_graphite:1}
  %define with_write_http 0%{!?_without_write_http:1}
 +%define with_write_redis 0%{!?_without_write_redis:0%{?_has_hiredis}}
  %define with_write_riemann 0%{!?_without_write_riemann:1}
 +%define with_write_tsdb 0%{!?_without_write_tsdb:1}
 +%define with_zfs_arc 0%{!?_without_zfs_arc:1}
 +%define with_zookeeper 0%{!?_without_zookeeper:1}
  
  # Plugins not built by default because of dependencies on libraries not
  # available in RHEL or EPEL:
  %define with_apple_sensors 0%{!?_without_apple_sensors:0}
  # plugin aquaero disabled, requires a libaquaero5
  %define with_aquaero 0%{!?_without_aquaero:0}
 +# plugin barometer disabled, requires a libi2c
 +%define with_barometer 0%{!?_without_barometer:0}
  # plugin lpar disabled, requires AIX
  %define with_lpar 0%{!?_without_lpar:0}
  # plugin mic disabled, requires Mic
  %define with_oracle 0%{!?_without_oracle:0}
  # plugin oracle disabled, requires BSD
  %define with_pf 0%{!?_without_pf:0}
 -# plugin redis disabled, requires credis
 -%define with_redis 0%{!?_without_redis:0}
  # plugin routeros disabled, requires librouteros
  %define with_routeros 0%{!?_without_routeros:0}
  # plugin sigrok disabled, requires libsigrok
  %define with_tape 0%{!?_without_tape:0}
  # plugin tokyotyrant disabled, requires tcrdb.h
  %define with_tokyotyrant 0%{!?_without_tokyotyrant:0}
 +# plugin write_kafka disabled, requires librdkafka
 +%define with_write_kafka 0%{!?_without_write_kafka:0}
  # plugin write_mongodb disabled, requires libmongoc
  %define with_write_mongodb 0%{!?_without_write_mongodb:0}
 -# plugin write_redis disabled, requires credis
 -%define with_write_redis 0%{!?_without_write_redis:0}
  # plugin xmms disabled, requires xmms
  %define with_xmms 0%{!?_without_xmms:0}
 -# plugin zfs_arc disabled, requires FreeBSD/Solaris
 -%define with_zfs_arc 0%{!?_without_zfs_arc:0}
  
  Summary:      Statistics collection daemon for filling RRD files
  Name:         collectd
@@@ -213,7 -200,7 +213,7 @@@ Source:            http://collectd.org/files/%{na
  License:      GPLv2
  Group:                System Environment/Daemons
  BuildRoot:    %{_tmppath}/%{name}-%{version}-root
- BuildRequires:        libgcrypt-devel, kernel-headers
+ BuildRequires:        libgcrypt-devel, kernel-headers, libtool-ltdl-devel
  Vendor:               collectd development team <collectd@verplant.org>
  
  Requires(post):               chkconfig
@@@ -270,15 -257,6 +270,15 @@@ open-source server software for the gam
  Entertainment.
  %endif
  
 +%if %{with_barometer}
 +%package barometer
 +Summary:       barometer plugin for collectd
 +Group:         System Environment/Daemons
 +Requires:      %{name}%{?_isa} = %{version}-%{release}
 +%description barometer
 +Collects pressure and temperature from digital barometers.
 +%endif
 +
  %if %{with_bind}
  %package bind
  Summary:      Bind plugin for collectd
@@@ -334,17 -312,6 +334,17 @@@ The DBI plugin uses libdbi, a database 
  statements on a database and read back the result.
  %endif
  
 +%if %{with_disk}
 +%package disk
 +Summary:      disk plugin for collectd
 +Group:                System Environment/Daemons
 +Requires:     %{name}%{?_isa} = %{version}-%{release}
 +%{?_has_libudev:BuildRequires:  libudev-devel}
 +%description disk
 +The "disk" plugin collects information about the usage of physical disks and
 +logical disks (partitions).
 +%endif
 +
  %if %{with_dns}
  %package dns
  Summary:      DNS plugin for collectd
@@@ -422,14 -389,14 +422,14 @@@ This plugin for collectd allows plugin
  in an embedded JVM.
  %endif
  
 -%if %{with_libvirt}
 -%package libvirt
 -Summary:      Libvirt plugin for collectd
 -Group:                System Environment/Daemons
 -Requires:     %{name}%{?_isa} = %{version}-%{release}
 -BuildRequires:        libvirt-devel
 -%description libvirt
 -This plugin collects information from virtualized guests.
 +%if %{with_log_logstash}
 +%package log_logstash
 +Summary:       log_logstash plugin for collectd
 +Group:         System Environment/Daemons
 +Requires:      %{name}%{?_isa} = %{version}-%{release}
 +BuildRequires: yajl-devel
 +%description log_logstash
 +This plugin logs in logstash JSON format
  %endif
  
  %if %{with_lvm}
@@@ -538,16 -505,6 +538,16 @@@ BuildRequires:   nut-deve
  This plugin for collectd provides Network UPS Tools support.
  %endif
  
 +%if %{with_openldap}
 +%package openldap
 +Summary:       Openldap plugin for collectd
 +Group:         System Environment/Daemons
 +Requires:      %{name}%{?_isa} = %{version}-%{release}
 +BuildRequires: openldap-devel
 +%description openldap
 +This plugin reads monitoring information from OpenLDAP's cn=Monitor subtree.
 +%endif
 +
  %if %{with_perl}
  %package perl
  Summary:      Perl plugin for collectd
@@@ -617,10 -574,10 +617,10 @@@ application programming interface (API
  Summary:      Redis plugin for collectd
  Group:                System Environment/Daemons
  Requires:     %{name}%{?_isa} = %{version}-%{release}
 -BuildRequires:        credis-devel
 +BuildRequires:        hiredis-devel
  %description redis
  The Redis plugin connects to one or more instances of Redis, a key-value store,
 -and collects usage information using the credis library.
 +and collects usage information using the hiredis library.
  %endif
  
  %if %{with_rrdcached}
@@@ -665,17 -622,6 +665,17 @@@ measurements fed to collectd. This incl
  thermometers, and much more.
  %endif
  
 +%if %{with_smart}
 +%package smart
 +Summary:       SMART plugin for collectd
 +Group:         System Environment/Daemons
 +Requires:      %{name}%{?_isa} = %{version}-%{release}
 +BuildRequires: libatasmart-devel
 +%description smart
 +Collect SMART statistics, notably load cycle count, temperature and bad
 +sectors.
 +%endif
 +
  %if %{with_snmp}
  %package snmp
  Summary:      SNMP plugin for collectd
@@@ -696,16 -642,6 +696,16 @@@ BuildRequires:   varnish-libs-deve
  The Varnish plugin collects information about Varnish, an HTTP accelerator.
  %endif
  
 +%if %{with_virt}
 +%package virt
 +Summary:      Virt plugin for collectd
 +Group:                System Environment/Daemons
 +Requires:     %{name}%{?_isa} = %{version}-%{release}
 +BuildRequires:        libvirt-devel
 +%description virt
 +This plugin collects information from virtualized guests.
 +%endif
 +
  %if %{with_write_http}
  %package write_http
  Summary:      Write-HTTP plugin for collectd
@@@ -717,22 -653,12 +717,22 @@@ The Write-HTTP plugin sends the values 
  using HTTP POST requests.
  %endif
  
 +%if %{with_write_kafka}
 +%package write_kafka
 +Summary:       Write-kafka plugin for collectd
 +Group:         System Environment/Daemons
 +Requires:      %{name}%{?_isa} = %{version}-%{release}
 +BuildRequires: rdkafka-devel
 +%description write_kafka
 +The write_kafka plugin sends values to kafka, a distributed messaging system.
 +%endif
 +
  %if %{with_write_redis}
  %package write_redis
  Summary:      Write-Redis plugin for collectd
  Group:                System Environment/Daemons
  Requires:     %{name}%{?_isa} = %{version}-%{release}
 -BuildRequires:        credis-devel
 +BuildRequires:        hiredis-devel
  %description write_redis
  The Write Redis plugin stores values in Redis, a “data structures server”.
  %endif
@@@ -836,12 -762,6 +836,12 @@@ Development files for libcollectdclien
  %define _with_ascent --disable-ascent
  %endif
  
 +%if %{with_barometer}
 +%define _with_barometer --enable-barometer
 +%else
 +%define _with_barometer --disable-barometer
 +%endif
 +
  %if %{with_battery}
  %define _with_battery --enable-battery
  %else
  %define _with_dns --disable-dns
  %endif
  
 +%if %{with_drbd}
 +%define _with_drbd --enable-drbd
 +%else
 +%define _with_drbd --disable-drbd
 +%endif
 +
  %if %{with_email}
  %define _with_email --enable-email
  %else
  %define _with_java --disable-java
  %endif
  
 -%if %{with_libvirt}
 -%define _with_libvirt --enable-libvirt
 +%if %{with_virt}
 +%define _with_virt --enable-virt
  %else
 -%define _with_libvirt --disable-libvirt
 +%define _with_virt --disable-virt
  %endif
  
  %if %{with_load}
  %define _with_logfile --disable-logfile
  %endif
  
 +%if %{with_log_logstash}
 +%define _with_log_logstash --enable-log_logstash
 +%else
 +%define _with_log_logstash --disable-log_logstash
 +%endif
 +
  %if %{with_lpar}
  %define _with_lpar --enable-lpar
  %else
  %define _with_onewire --disable-onewire
  %endif
  
 +%if %{with_openldap}
 +%define _with_openldap --enable-openldap
 +%else
 +%define _with_openldap --disable-openldap
 +%endif
 +
  %if %{with_openvpn}
  %define _with_openvpn --enable-openvpn
  %else
  %define _with_sigrok --disable-sigrok
  %endif
  
 +%if %{with_smart}
 +%define _with_smart --enable-smart
 +%else
 +%define _with_smart --disable-smart
 +%endif
 +
  %if %{with_snmp}
  %define _with_snmp --enable-snmp
  %else
  %define _with_write_http --disable-write_http
  %endif
  
 +%if %{with_write_kafka}
 +%define _with_write_kafka --enable-write_kafka
 +%else
 +%define _with_write_kafka --disable-write_kafka
 +%endif
 +
  %if %{with_write_mongodb}
  %define _with_write_mongodb --enable-write_mongodb
  %else
  %if %{with_write_redis}
  %define _with_write_redis --enable-write_redis
  %else
 -%define _with_write_redis --disable-write_redis --without-libcredis
 +%define _with_write_redis --disable-write_redis
  %endif
  
  %if %{with_write_riemann}
  %define _with_write_riemann --disable-write_riemann
  %endif
  
 +%if %{with_write_tsdb}
 +%define _with_write_tsdb --enable-write_tsdb
 +%else
 +%define _with_write_tsdb --disable-write_tsdb
 +%endif
 +
  %if %{with_xmms}
  %define _with_xmms --enable-xmms
  %else
  %define _with_zfs_arc --disable-zfs_arc
  %endif
  
 +%if %{with_zookeeper}
 +%define _with_zookeeper --enable-zookeeper
 +%else
 +%define _with_zookeeper --disable-zookeeper
 +%endif
 +
  %configure CFLAGS="%{optflags} -DLT_LAZY_OR_NOW=\"RTLD_LAZY|RTLD_GLOBAL\"" \
        --disable-static \
        --without-included-ltdl \
        %{?_with_apple_sensors} \
        %{?_with_aquaero} \
        %{?_with_ascent} \
 +      %{?_with_barometer} \
        %{?_with_battery} \
        %{?_with_bind} \
        %{?_with_cgroups} \
        %{?_with_df} \
        %{?_with_disk} \
        %{?_with_dns} \
 +      %{?_with_drbd} \
        %{?_with_email} \
        %{?_with_entropy} \
        %{?_with_ethstat} \
        %{?_with_iptables} \
        %{?_with_ipvs} \
        %{?_with_java} \
 -      %{?_with_libvirt} \
 +      %{?_with_virt} \
 +      %{?_with_log_logstash} \
        %{?_with_lpar} \
        %{?_with_lvm} \
        %{?_with_memcachec} \
        %{?_with_notify_email} \
        %{?_with_nut} \
        %{?_with_onewire} \
 +      %{?_with_openldap} \
        %{?_with_oracle} \
        %{?_with_perl} \
        %{?_with_pf} \
        %{?_with_rrdtool} \
        %{?_with_sensors} \
        %{?_with_sigrok} \
 +      %{?_with_smart} \
        %{?_with_snmp} \
        %{?_with_tape} \
        %{?_with_tokyotyrant} \
        %{?_with_varnish} \
        %{?_with_write_http} \
 +      %{?_with_write_kafka} \
        %{?_with_write_mongodb} \
        %{?_with_write_redis} \
        %{?_with_xmms} \
        %{?_with_zfs_arc} \
 +      %{?_with_zookeeper} \
        %{?_with_irq} \
        %{?_with_load} \
        %{?_with_logfile} \
        %{?_with_wireless}\
        %{?_with_write_graphite} \
        %{?_with_write_http} \
 -      %{?_with_write_riemann}
 +      %{?_with_write_riemann} \
 +      %{?_with_write_tsdb}
  
  
  %{__make} %{?_smp_mflags}
@@@ -1676,6 -1546,8 +1676,8 @@@ find %{buildroot} -type f -name .packli
  find %{buildroot} -type f -name perllocal.pod -delete
  
  %if ! %{with_java}
+ rm -f %{buildroot}%{_datadir}/collectd/java/collectd-api.jar
+ rm -f %{buildroot}%{_datadir}/collectd/java/generic-jmx.jar
  rm -f %{buildroot}%{_mandir}/man5/collectd-java.5*
  %endif
  
@@@ -1686,6 -1558,10 +1688,10 @@@ rm -fr perl-examples
  rm -fr %{buildroot}/usr/lib/perl5/
  %endif
  
+ %if ! %{with_postgresql}
+ rm -f %{buildroot}%{_datadir}/collectd/postgresql_default.conf
+ %endif
  %if ! %{with_python}
  rm -f %{buildroot}%{_mandir}/man5/collectd-python.5*
  %endif
  %{_bindir}/collectd-tg
  %{_bindir}/collectdctl
  %{_sbindir}/collectdmon
- %{_datadir}/collectd/
+ %{_datadir}/collectd/types.db
  %{_sharedstatedir}/collectd
  %{_mandir}/man1/collectd-nagios.1*
  %{_mandir}/man1/collectd.1*
  %if %{with_df}
  %{_libdir}/%{name}/df.so
  %endif
 -%if %{with_disk}
 -%{_libdir}/%{name}/disk.so
 +%if %{with_drbd}
 +%{_libdir}/%{name}/drbd.so
  %endif
  %if %{with_ethstat}
  %{_libdir}/%{name}/ethstat.so
  %if %{with_write_graphite}
  %{_libdir}/%{name}/write_graphite.so
  %endif
 -
 +%if %{with_write_tsdb}
 +%{_libdir}/%{name}/write_tsdb.so
 +%endif
 +%if %{with_zfs_arc}
 +%{_libdir}/%{name}/zfs_arc.so
 +%endif
 +%if %{with_zookeeper}
 +%{_libdir}/%{name}/zookeeper.so
 +%endif
  
  %files -n libcollectdclient-devel
  %{_includedir}/collectd/client.h
  %{_libdir}/%{name}/ascent.so
  %endif
  
 +%if %{with_barometer}
 +%files barometer
 +%{_libdir}/%{name}/barometer.so
 +%endif
 +
  %if %{with_bind}
  %files bind
  %{_libdir}/%{name}/bind.so
  %{_libdir}/%{name}/curl_xml.so
  %endif
  
 +%if %{with_disk}
 +%files disk
 +%{_libdir}/%{name}/disk.so
 +%endif
 +
  %if %{with_dns}
  %files dns
  %{_libdir}/%{name}/dns.so
  
  %if %{with_java}
  %files java
- %{_prefix}/share/collectd/java/collectd-api.jar
- %{_prefix}/share/collectd/java/generic-jmx.jar
+ %{_datadir}/collectd/java/collectd-api.jar
+ %{_datadir}/collectd/java/generic-jmx.jar
  %{_libdir}/%{name}/java.so
  %{_mandir}/man5/collectd-java.5*
  %endif
  
 -%if %{with_libvirt}
 -%files libvirt
 -%{_libdir}/%{name}/libvirt.so
 +%if %{with_virt}
 +%files virt
 +%{_libdir}/%{name}/virt.so
 +%endif
 +
 +%if %{with_log_logstash}
 +%files log_logstash
 +%{_libdir}/%{name}/log_logstash.so
  %endif
  
  %if %{with_lvm}
  %{_libdir}/%{name}/nut.so
  %endif
  
 +%if %{with_openldap}
 +%files openldap
 +%{_libdir}/%{name}/openldap.so
 +%endif
 +
  %if %{with_perl}
  %files perl
  %doc perl-examples/*
  
  %if %{with_postgresql}
  %files postgresql
- %{_prefix}/share/collectd/postgresql_default.conf
+ %{_datadir}/collectd/postgresql_default.conf
  %{_libdir}/%{name}/postgresql.so
  %endif
  
  %{_libdir}/%{name}/sigrok.so
  %endif
  
 +%if %{with_smart}
 +%files smart
 +%{_libdir}/%{name}/smart.so
 +%endif
 +
  %if %{with_snmp}
  %files snmp
  %{_mandir}/man5/collectd-snmp.5*
  %{_libdir}/%{name}/write_http.so
  %endif
  
 +%if %{with_write_kafka}
 +%files write_kafka
 +%{_libdir}/%{name}/write_kafka.so
 +%endif
 +
  %if %{with_write_redis}
  %files write_redis
  %{_libdir}/%{name}/write_redis.so
  %doc contrib/
  
  %changelog
 +# * TODO 5.5.0-1
 +# - New upstream version
 +# - New plugins enabled by default: drbd, log_logstash, write_tsdb, smart, openldap, redis, write_redis, zookeeper
 +# - New plugins disabled by default: barometer, write_kafka
 +# - Enable zfs_arc, now supported on Linux
 +# - Install disk plugin in an dedicated package, as it depends on libudev
 +
  * Mon Aug 19 2013 Marc Fournier <marc.fournier@camptocamp.com> 5.4.0-1
  - New upstream version
  - Build netlink plugin by default
  * Sat Nov 17 2012 Ruben Kerkhof <ruben@tilaa.nl> 5.1.0-2
  - Move perl stuff to perl_vendorlib
  - Replace hardcoded paths with macros
 -- Remove unneccesary Requires
 +- Remove unnecessary Requires
  - Removed .a and .la files
  - Some other small cleanups
  
  - New upstream version
  - Changes to support 5.1.0
  - Enabled all buildable plugins based on libraries available on EL6 + EPEL
 -- All plugins requiring external libraries are now shipped in seperate
 +- All plugins requiring external libraries are now shipped in separate
    packages.
  - No longer treat Java plugin as an exception, correctly set $JAVA_HOME during
    the build process + ensure build deps are installed.
diff --combined src/collectd.conf.in
  #AutoLoadPlugin false
  
  #----------------------------------------------------------------------------#
 +# When enabled, internal statistics are collected, using "collectd" as the   #
 +# plugin name.                                                               #
 +# Disabled by default.                                                       #
 +#----------------------------------------------------------------------------#
 +#CollectInternalStats false
 +
 +#----------------------------------------------------------------------------#
  # Interval at which to query values. This may be overwritten on a per-plugin #
  # base by using the 'Interval' option of the LoadPlugin block:               #
  #   <LoadPlugin foo>                                                         #
  #----------------------------------------------------------------------------#
  #Interval     10
  
 -#Timeout      2
 -#ReadThreads  5
 -#WriteThreads 5
 +#MaxReadInterval 86400
 +#Timeout         2
 +#ReadThreads     5
 +#WriteThreads    5
  
  # Limit the size of the write queue. Default is no limit. Setting up a limit is
  # recommended for servers handling a high volume of traffic.
@@@ -60,7 -52,6 +60,7 @@@
  
  @LOAD_PLUGIN_SYSLOG@LoadPlugin syslog
  @LOAD_PLUGIN_LOGFILE@LoadPlugin logfile
 +@LOAD_PLUGIN_LOG_LOGSTASH@LoadPlugin log_logstash
  
  #<Plugin logfile>
  #     LogLevel @DEFAULT_LOG_LEVEL@
  #     PrintSeverity false
  #</Plugin>
  
 +#<Plugin log_logstash>
 +#     LogLevel @DEFAULT_LOG_LEVEL@
 +#     File "@localstatedir@/log/@PACKAGE_NAME@.json.log"
 +#</Plugin>
 +
  #<Plugin syslog>
  #     LogLevel @DEFAULT_LOG_LEVEL@
  #</Plugin>
@@@ -95,7 -81,6 +95,7 @@@
  #@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
  #@BUILD_PLUGIN_AQUAERO_TRUE@LoadPlugin aquaero
  #@BUILD_PLUGIN_ASCENT_TRUE@LoadPlugin ascent
 +#@BUILD_PLUGIN_BAROMETER_TRUE@LoadPlugin barometer
  #@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
  #@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
  #@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
  #@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
  #@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
  #@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
 +#@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd
  #@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
  #@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
  #@BUILD_PLUGIN_ETHSTAT_TRUE@LoadPlugin ethstat
  #@BUILD_PLUGIN_IPVS_TRUE@LoadPlugin ipvs
  #@BUILD_PLUGIN_IRQ_TRUE@LoadPlugin irq
  #@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
 -#@BUILD_PLUGIN_LIBVIRT_TRUE@LoadPlugin libvirt
  @BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
  #@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
  #@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
  #@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
  #@BUILD_PLUGIN_OLSRD_TRUE@LoadPlugin olsrd
  #@BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
 +#@BUILD_PLUGIN_OPENLDAP_TRUE@LoadPlugin openldap
  #@BUILD_PLUGIN_OPENVPN_TRUE@LoadPlugin openvpn
  #@BUILD_PLUGIN_ORACLE_TRUE@LoadPlugin oracle
  #@BUILD_PLUGIN_PERL_TRUE@<LoadPlugin perl>
  #@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
  #@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
  #@BUILD_PLUGIN_SIGROK_TRUE@LoadPlugin sigrok
 +#@BUILD_PLUGIN_SMART_TRUE@LoadPlugin smart
  #@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
  #@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd
  #@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
  #@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
  #@BUILD_PLUGIN_VARNISH_TRUE@LoadPlugin varnish
  #@BUILD_PLUGIN_MIC_TRUE@LoadPlugin mic
 +#@BUILD_PLUGIN_VIRT_TRUE@LoadPlugin virt
  #@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
  #@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
  #@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
  #@BUILD_PLUGIN_WRITE_GRAPHITE_TRUE@LoadPlugin write_graphite
  #@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http
 +#@BUILD_PLUGIN_WRITE_KAFKA_TRUE@LoadPlugin write_kafka
  #@BUILD_PLUGIN_WRITE_MONGODB_TRUE@LoadPlugin write_mongodb
  #@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
  #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann
 +#@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
  #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
  #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
 +#@BUILD_PLUGIN_ZOOKEEPER_TRUE@LoadPlugin zookeeper
  
  ##############################################################################
  # Plugin configuration                                                       #
  # ription of those options is available in the collectd.conf(5) manual page. #
  ##############################################################################
  
 -#<Plugin "aggregation">
 +#<Plugin aggregation>
  #  <Aggregation>
  #    #Host "unspecified"
  #    Plugin "cpu"
  #  </Aggregation>
  #</Plugin>
  
 -#<Plugin "amqp">
 +#<Plugin amqp>
  #  <Publish "name">
  #    Host "localhost"
  #    Port "5672"
  #     CACert "/etc/ssl/ca.crt"
  #</Plugin>
  
 +#<Plugin "barometer">
 +#   Device            "/dev/i2c-0";
 +#   Oversampling      512
 +#   PressureOffset    0.0
 +#   TemperatureOffset 0.0
 +#   Normalization     2
 +#   Altitude          238.0
 +#   TemperatureSensor "myserver/onewire-F10FCA000800/temperature"
 +#</Plugin>
 +
 +#<Plugin "battery">
 +#  ValuesPercentage false
 +#  ReportDegraded
 +#</Plugin>
 +
  #<Plugin "bind">
  #  URL "http://localhost:8053/"
  #  ParseTime       false
  #  IgnoreSelected false
  #</Plugin>
  
 +#<Plugin cpu>
 +#  ReportByCpu true
 +#  ReportByState true
 +#  ValuesPercentage false
 +#</Plugin>
 +#
  #<Plugin csv>
  #     DataDir "@localstatedir@/lib/@PACKAGE_NAME@/csv"
  #     StoreRates false
  #    URL "http://finance.google.com/finance?q=NYSE%3AAMD"
  #    User "foo"
  #    Password "bar"
 +#    Digest false
 +#    VerifyPeer true
 +#    VerifyHost true
 +#    CACert "/path/to/ca.crt"
 +#    Header "X-Custom-Header: foobar"
 +#    Post "foo=bar"
 +#
  #    MeasureResponseTime false
 +#    MeasureResponseCode false
  #    <Match>
  #      Regex "<span +class=\"pr\"[^>]*> *([0-9]*\\.[0-9]+) *</span>"
  #      DSType "GaugeAverage"
  #  </URL>
  #</Plugin>
  
 -#<Plugin "curl_xml">
 +#<Plugin curl_xml>
  #  <URL "http://localhost/stats.xml">
  #    Host "my_host"
  #    Instance "some_instance"
  #    User "collectd"
  #    Password "thaiNg0I"
 +#    Digest false
  #    VerifyPeer true
  #    VerifyHost true
  #    CACert "/path/to/ca.crt"
 +#    Header "X-Custom-Header: foobar"
 +#    Post "foo=bar"
  #
  #    <XPath "table[@id=\"magic_level\"]/tr">
  #      Type "magic_level"
  #<Plugin disk>
  #     Disk "/^[hs]d[a-f][0-9]?$/"
  #     IgnoreSelected false
 +#     UseBSDName false
 +#     UdevNameAttr "DEVNAME"
  #</Plugin>
  
  #<Plugin dns>
  #     </Directory>
  #</Plugin>
  
 -#<Plugin "gmond">
 +#<Plugin gmond>
  #  MCReceiveFrom "239.2.11.71" "8649"
  #  <Metric "swap_total">
  #    Type "swap"
  #     IgnoreSelected true
  #</Plugin>
  
 -#<Plugin "java">
 +#<Plugin java>
  #     JVMArg "-verbose:jni"
  #     JVMArg "-Djava.class.path=@prefix@/share/collectd/java/collectd-api.jar"
  #
  #     </Plugin>
  #</Plugin>
  
 -#<Plugin libvirt>
 -#     Connection "xen:///"
 -#     RefreshInterval 60
 -#     Domain "name"
 -#     BlockDevice "name:device"
 -#     InterfaceDevice "name:device"
 -#     IgnoreSelected false
 -#     HostnameFormat name
 -#     InterfaceFormat name
 +#<Plugin load>
 +#        ReportRelative true
  #</Plugin>
  
  #<Plugin lpar>
  #     </Instance>
  #</Plugin>
  
 +#<Plugin memory>
 +#     ValuesAbsolute true
 +#     ValuesPercentage false
 +#</Plugin>
 +
  #<Plugin modbus>
  #     <Data "data_name">
  #             RegisterBase 1234
  #             RegisterType float
 +#             ModbusRegisterType holding
  #             Type gauge
  #             Instance "..."
  #     </Data>
  #             Password "secret"
  #             Database "db_name"
  #             MasterStats true
 +#             ConnectTimeout 10
 +#             InnodbStats true
  #     </Database>
  #
  #     <Database db_name2>
 +#             Alias "squeeze"
  #             Host "localhost"
  #             Socket "/var/run/mysql/mysqld.sock"
  #             SlaveStats true
  #             Username "user"
  #             Password "secret"
  #             Interface "eth0"
 +#             ResolveInterval 14400
  @LOAD_PLUGIN_NETWORK@ </Server>
- #     TimeToLive "128"
+ #     TimeToLive 128
  #
  #     # server setup:
  #     Listen "ff18::efc0:4a42" "25826"
  #     IgnoreSelected false
  #</Plugin>
  
 +#<Plugin openldap>
 +#  <Instance "localhost">
 +#    URL "ldap://localhost:389"
 +#    StartTLS false
 +#    VerifyHost true
 +#    CACert "/path/to/ca.crt"
 +#    Timeout -1
 +#    Version 3
 +#  </Instance>
 +#</Plugin>
 +
  #<Plugin openvpn>
  #     StatusFile "/etc/openvpn/openvpn-status.log"
  #     ImprovedNamingSchema false
  #  </Device>
  #</Plugin>
  
 +#<Plugin smart>
 +#  Disk "/^[hs]d[a-f][0-9]?$/"
 +#  IgnoreSelected false
 +#</Plugin>
 +
  #<Plugin snmp>
  #   <Data "powerplus_voltge_input">
  #       Type "voltage"
  #  TimerCount     false
  #</Plugin>
  
 -#<Plugin "swap">
 +#<Plugin swap>
  #     ReportByDevice false
  #     ReportBytes true
 +#     ValuesAbsolute true
 +#     ValuesPercentage false
  #</Plugin>
  
 -#<Plugin "table">
 +#<Plugin table>
  #     <Table "/proc/slabinfo">
  #             Instance "slabinfo"
  #             Separator " "
  #     </Table>
  #</Plugin>
  
 -#<Plugin "tail">
 +#<Plugin tail>
  #  <File "/var/log/exim4/mainlog">
  #    Instance "exim"
 +#    Interval 60
  #    <Match>
  #      Regex "S=([1-9][0-9]*)"
  #      DSType "CounterAdd"
  #  </File>
  #</Plugin>
  
 -#<Plugin "tail_csv">
 +#<Plugin tail_csv>
  #   <Metric "dropped">
  #       Type "percent"
  #       Instance "dropped"
  
  #<Plugin tcpconns>
  #     ListeningPorts false
 +#     AllPortsSummary false
  #     LocalPort "25"
  #     RemotePort "25"
  #</Plugin>
  #   If you prefer defining another instance you can do
  #   so by using <Instance "myinstance">
  #   <Instance>
 -#      CollectCache true
  #      CollectBackend true
 -#      CollectBan false           # Varnish 3 only
 +#      CollectBan false           # Varnish 3 and above
 +#      CollectCache true
  #      CollectConnections true
  #      CollectDirectorDNS false   # Varnish 3 only
 -#      CollectSHM true
  #      CollectESI false
  #      CollectFetch false
  #      CollectHCB false
  #      CollectObjects false
  #      CollectPurge false         # Varnish 2 only
  #      CollectSession false
 +#      CollectSHM true
  #      CollectSMA false           # Varnish 2 only
  #      CollectSMS false
  #      CollectSM false            # Varnish 2 only
  #      CollectStruct false
  #      CollectTotals false
 -#      CollectUptime false
 +#      CollectUptime false        # Varnish 3 and above
  #      CollectVCL false
 +#      CollectVSM false           # Varnish 4 only
  #      CollectWorkers false
  #   </Instance>
  #</Plugin>
  
 +#<Plugin virt>
 +#     Connection "xen:///"
 +#     RefreshInterval 60
 +#     Domain "name"
 +#     BlockDevice "name:device"
 +#     InterfaceDevice "name:device"
 +#     IgnoreSelected false
 +#     HostnameFormat name
 +#     InterfaceFormat name
 +#     PluginInstanceFormat name
 +#</Plugin>
 +
  #<Plugin vmem>
  #     Verbose false
  #</Plugin>
  #             VerifyPeer true
  #             VerifyHost true
  #             CACert "/etc/ssl/ca.crt"
 +#             CAPath "/etc/ssl/certs/"
 +#             ClientKey "/etc/ssl/client.pem"
 +#             ClientCert "/etc/ssl/client.crt"
 +#             ClientKeyPass "secret"
 +#             SSLVersion "TLSv1"
  #             Format "Command"
  #             StoreRates false
 +#             BufferSize 4096
  #     </URL>
  #</Plugin>
  
 +#<Plugin write_kafka>
 +#  Property "metadata.broker.list" "localhost:9092"
 +#  <Topic "collectd">
 +#    Format JSON
 +#  </Topic>
 +#</Plugin>
 +
  #<Plugin write_mongodb>
  #     <Node "example">
  #             Host "localhost"
  #             Host "localhost"
  #             Port 5555
  #             Protocol UDP
 +#             Batch false
 +#             BatchMaxSize 8192
  #             StoreRates true
  #             AlwaysAppendDS false
  #             TTLFactor 2.0
 +#             Notifications true
 +#             CheckThresholds false
 +#             EventServicePrefix ""
  #     </Node>
  #     Tag "foobar"
 +#     Attribute "foo" "bar"
 +#</Plugin>
 +
 +#<Plugin write_tsdb>
 +#     <Node>
 +#             Host "localhost"
 +#             Port "4242"
 +#             HostTags "status=production"
 +#             StoreRates false
 +#             AlwaysAppendDS false
 +#     </Node>
 +#</Plugin>
 +
 +#<Plugin zookeeper>
 +#    Host "localhost"
 +#    Port "2181"
  #</Plugin>
  
  ##############################################################################
  ##############################################################################
  
  #@BUILD_PLUGIN_THRESHOLD_TRUE@LoadPlugin "threshold"
 -#<Plugin "threshold">
 +#<Plugin threshold>
  #  <Type "foo">
  #    WarningMin    0.00
  #    WarningMax 1000.00
diff --combined src/cpu.c
+++ b/src/cpu.c
@@@ -1,10 -1,9 +1,10 @@@
  /**
   * collectd - src/cpu.c
 - * Copyright (C) 2005-2010  Florian octo Forster
 + * Copyright (C) 2005-2014  Florian octo Forster
   * Copyright (C) 2008       Oleg King
   * Copyright (C) 2009       Simon Kuhnle
   * Copyright (C) 2009       Manuel Sanmartin
 + * Copyright (C) 2013-2014  Pierre-Yves Ritschard
   *
   * 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
   * 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>
   *   Oleg King <king2 at kaluga.ru>
   *   Simon Kuhnle <simon at blarzwurst.de>
   *   Manuel Sanmartin
 + *   Pierre-Yves Ritschard <pyr at spootnik.org>
   **/
  
  #include "collectd.h"
  # define CAN_USE_SYSCTL 0
  #endif
  
 +#define COLLECTD_CPU_STATE_USER 0
 +#define COLLECTD_CPU_STATE_SYSTEM 1
 +#define COLLECTD_CPU_STATE_WAIT 2
 +#define COLLECTD_CPU_STATE_NICE 3
 +#define COLLECTD_CPU_STATE_SWAP 4
 +#define COLLECTD_CPU_STATE_INTERRUPT 5
 +#define COLLECTD_CPU_STATE_SOFTIRQ 6
 +#define COLLECTD_CPU_STATE_STEAL 7
 +#define COLLECTD_CPU_STATE_IDLE 8
 +#define COLLECTD_CPU_STATE_ACTIVE 9 /* sum of (!idle) */
 +#define COLLECTD_CPU_STATE_MAX 10 /* #states */
 +
  #if HAVE_STATGRAB_H
  # include <statgrab.h>
  #endif
  # error "No applicable input method."
  #endif
  
 +static const char *cpu_state_names[] = {
 +      "user",
 +      "system",
 +      "wait",
 +      "nice",
 +      "swap",
 +      "interrupt",
 +      "softirq",
 +      "steal",
 +      "idle",
 +      "active"
 +};
 +
  #ifdef PROCESSOR_CPU_LOAD_INFO
  static mach_port_t port_host;
  static processor_port_array_t cpu_list;
@@@ -166,54 -139,6 +166,54 @@@ static int numcpu
  static int pnumcpu;
  #endif /* HAVE_PERFSTAT */
  
 +#define RATE_ADD(sum, val) do { \
 +      if (isnan (sum))        \
 +      (sum) = (val);          \
 +      else if (!isnan (val))  \
 +      (sum) += (val);         \
 +} while (0)
 +
 +struct cpu_state_s
 +{
 +      value_to_rate_state_t conv;
 +      gauge_t rate;
 +      _Bool has_value;
 +};
 +typedef struct cpu_state_s cpu_state_t;
 +
 +static cpu_state_t *cpu_states = NULL;
 +static size_t cpu_states_num = 0; /* #cpu_states allocated */
 +
 +/* Highest CPU number in the current iteration. Used by the dispatch logic to
 + * determine how many CPUs there were. Reset to 0 by cpu_reset(). */
 +static size_t global_cpu_num = 0;
 +
 +static _Bool report_by_cpu = 1;
 +static _Bool report_by_state = 1;
 +static _Bool report_percent = 0;
 +
 +static const char *config_keys[] =
 +{
 +      "ReportByCpu",
 +      "ReportByState",
 +      "ValuesPercentage"
 +};
 +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 +
 +static int cpu_config (char const *key, char const *value) /* {{{ */
 +{
 +      if (strcasecmp (key, "ReportByCpu") == 0)
 +              report_by_cpu = IS_TRUE (value) ? 1 : 0;
 +      else if (strcasecmp (key, "ValuesPercentage") == 0)
 +              report_percent = IS_TRUE (value) ? 1 : 0;
 +      else if (strcasecmp (key, "ReportByState") == 0)
 +              report_by_state = IS_TRUE (value) ? 1 : 0;
 +      else
 +              return (-1);
 +
 +      return (0);
 +} /* }}} int cpu_config */
 +
  static int init (void)
  {
  #if PROCESSOR_CPU_LOAD_INFO
  
        DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
        INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
-       cpu_temp_retry_max = 86400 / CDTIME_T_TO_TIME_T (plugin_get_interval ());
  /* #endif PROCESSOR_CPU_LOAD_INFO */
  
  #elif defined(HAVE_LIBKSTAT)
        return (0);
  } /* int init */
  
 -static void submit (int cpu_num, const char *type_instance, derive_t value)
 +static void submit_value (int cpu_num, int cpu_state, const char *type, value_t value)
  {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      values[0].derive = value;
 +      memcpy(&values[0], &value, sizeof(value));
  
        vl.values = values;
        vl.values_len = 1;
 +
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
 -      ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
 -                      "%i", cpu_num);
 -      sstrncpy (vl.type, "cpu", sizeof (vl.type));
 -      sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 +      sstrncpy (vl.type, type, sizeof (vl.type));
 +      sstrncpy (vl.type_instance, cpu_state_names[cpu_state],
 +                      sizeof (vl.type_instance));
  
 +      if (cpu_num >= 0) {
 +              ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
 +                              "%i", cpu_num);
 +      }
        plugin_dispatch_values (&vl);
  }
  
 +static void submit_percent(int cpu_num, int cpu_state, gauge_t percent)
 +{
 +      value_t value;
 +
 +      /* This function is called for all known CPU states, but each read
 +       * method will only report a subset. The remaining states are left as
 +       * NAN and we ignore them here. */
 +      if (isnan (percent))
 +              return;
 +
 +      value.gauge = percent;
 +      submit_value (cpu_num, cpu_state, "percent", value);
 +}
 +
 +static void submit_derive(int cpu_num, int cpu_state, derive_t derive)
 +{
 +      value_t value;
 +
 +      value.derive = derive;
 +      submit_value (cpu_num, cpu_state, "cpu", value);
 +}
 +
 +/* Takes the zero-index number of a CPU and makes sure that the module-global
 + * cpu_states buffer is large enough. Returne ENOMEM on erorr. */
 +static int cpu_states_alloc (size_t cpu_num) /* {{{ */
 +{
 +      cpu_state_t *tmp;
 +      size_t sz;
 +
 +      sz = (((size_t) cpu_num) + 1) * COLLECTD_CPU_STATE_MAX;
 +      assert (sz > 0);
 +
 +      /* We already have enough space. */
 +      if (cpu_states_num >= sz)
 +              return 0;
 +
 +      tmp = realloc (cpu_states, sz * sizeof (*cpu_states));
 +      if (tmp == NULL)
 +      {
 +              ERROR ("cpu plugin: realloc failed.");
 +              return (ENOMEM);
 +      }
 +      cpu_states = tmp;
 +      tmp = cpu_states + cpu_states_num;
 +
 +      memset (tmp, 0, (sz - cpu_states_num) * sizeof (*cpu_states));
 +      cpu_states_num = sz;
 +      return 0;
 +} /* }}} cpu_states_alloc */
 +
 +static cpu_state_t *get_cpu_state (size_t cpu_num, size_t state) /* {{{ */
 +{
 +      size_t index = ((cpu_num * COLLECTD_CPU_STATE_MAX) + state);
 +
 +      if (index >= cpu_states_num)
 +              return (NULL);
 +
 +      return (&cpu_states[index]);
 +} /* }}} cpu_state_t *get_cpu_state */
 +
 +/* Populates the per-CPU COLLECTD_CPU_STATE_ACTIVE rate and the global rate_by_state
 + * array. */
 +static void aggregate (gauge_t *sum_by_state) /* {{{ */
 +{
 +      size_t cpu_num;
 +      size_t state;
 +
 +      for (state = 0; state < COLLECTD_CPU_STATE_MAX; state++)
 +              sum_by_state[state] = NAN;
 +
 +      for (cpu_num = 0; cpu_num < global_cpu_num; cpu_num++)
 +      {
 +              cpu_state_t *this_cpu_states = get_cpu_state (cpu_num, 0);
 +
 +              this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].rate = NAN;
 +
 +              for (state = 0; state < COLLECTD_CPU_STATE_ACTIVE; state++)
 +              {
 +                      if (!this_cpu_states[state].has_value)
 +                              continue;
 +
 +                      RATE_ADD (sum_by_state[state], this_cpu_states[state].rate);
 +                      if (state != COLLECTD_CPU_STATE_IDLE)
 +                              RATE_ADD (this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].rate, this_cpu_states[state].rate);
 +              }
 +
 +              if (!isnan (this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].rate))
 +                      this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].has_value = 1;
 +
 +              RATE_ADD (sum_by_state[COLLECTD_CPU_STATE_ACTIVE], this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].rate);
 +      }
 +} /* }}} void aggregate */
 +
 +/* Commits (dispatches) the values for one CPU or the global aggregation.
 + * cpu_num is the index of the CPU to be committed or -1 in case of the global
 + * aggregation. rates is a pointer to COLLECTD_CPU_STATE_MAX gauge_t values holding the
 + * current rate; each rate may be NAN. Calculates the percentage of each state
 + * and dispatches the metric. */
 +static void cpu_commit_one (int cpu_num, /* {{{ */
 +              gauge_t rates[static COLLECTD_CPU_STATE_MAX])
 +{
 +      size_t state;
 +      gauge_t sum;
 +
 +      sum = rates[COLLECTD_CPU_STATE_ACTIVE];
 +      RATE_ADD (sum, rates[COLLECTD_CPU_STATE_IDLE]);
 +
 +      if (!report_by_state)
 +      {
 +              gauge_t percent = 100.0 * rates[COLLECTD_CPU_STATE_ACTIVE] / sum;
 +              submit_percent (cpu_num, COLLECTD_CPU_STATE_ACTIVE, percent);
 +              return;
 +      }
 +
 +      for (state = 0; state < COLLECTD_CPU_STATE_ACTIVE; state++)
 +      {
 +              gauge_t percent = 100.0 * rates[state] / sum;
 +              submit_percent (cpu_num, state, percent);
 +      }
 +} /* }}} void cpu_commit_one */
 +
 +/* Resets the internal aggregation. This is called by the read callback after
 + * each iteration / after each call to cpu_commit(). */
 +static void cpu_reset (void) /* {{{ */
 +{
 +      size_t i;
 +
 +      for (i = 0; i < cpu_states_num; i++)
 +              cpu_states[i].has_value = 0;
 +
 +      global_cpu_num = 0;
 +} /* }}} void cpu_reset */
 +
 +/* Legacy behavior: Dispatches the raw derive values without any aggregation. */
 +static void cpu_commit_without_aggregation (void) /* {{{ */
 +{
 +      int state;
 +
 +      for (state = 0; state < COLLECTD_CPU_STATE_ACTIVE; state++)
 +      {
 +              size_t cpu_num;
 +
 +              for (cpu_num = 0; cpu_num < global_cpu_num; cpu_num++)
 +              {
 +                      cpu_state_t *s = get_cpu_state (cpu_num, state);
 +
 +                      if (!s->has_value)
 +                              continue;
 +
 +                      submit_derive ((int) cpu_num, (int) state, s->conv.last_value.derive);
 +              }
 +      }
 +} /* }}} void cpu_commit_without_aggregation */
 +
 +/* Aggregates the internal state and dispatches the metrics. */
 +static void cpu_commit (void) /* {{{ */
 +{
 +      gauge_t global_rates[COLLECTD_CPU_STATE_MAX] = {
 +              NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
 +      };
 +      size_t cpu_num;
 +
 +      if (report_by_state && report_by_cpu && !report_percent)
 +      {
 +              cpu_commit_without_aggregation ();
 +              return;
 +      }
 +
 +      aggregate (global_rates);
 +
 +      if (!report_by_cpu)
 +      {
 +              cpu_commit_one (-1, global_rates);
 +              return;
 +      }
 +
 +      for (cpu_num = 0; cpu_num < global_cpu_num; cpu_num++)
 +      {
 +              cpu_state_t *this_cpu_states = get_cpu_state (cpu_num, 0);
 +              gauge_t local_rates[COLLECTD_CPU_STATE_MAX] = {
 +                      NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN
 +              };
 +              size_t state;
 +
 +              for (state = 0; state < COLLECTD_CPU_STATE_MAX; state++)
 +                      if (this_cpu_states[state].has_value)
 +                              local_rates[state] = this_cpu_states[state].rate;
 +
 +              cpu_commit_one ((int) cpu_num, local_rates);
 +      }
 +} /* }}} void cpu_commit */
 +
 +/* Adds a derive value to the internal state. This should be used by each read
 + * function for each state. At the end of the iteration, the read function
 + * should call cpu_commit(). */
 +static int cpu_stage (size_t cpu_num, size_t state, derive_t value, cdtime_t now) /* {{{ */
 +{
 +      int status;
 +      cpu_state_t *s;
 +      value_t v;
 +
 +      if (state >= COLLECTD_CPU_STATE_ACTIVE)
 +              return (EINVAL);
 +
 +      status = cpu_states_alloc (cpu_num);
 +      if (status != 0)
 +              return (status);
 +
 +      if (global_cpu_num <= cpu_num)
 +              global_cpu_num = cpu_num + 1;
 +
 +      s = get_cpu_state (cpu_num, state);
 +
 +      v.gauge = NAN;
 +      status = value_to_rate (&v, value, &s->conv, DS_TYPE_DERIVE, now);
 +      if (status != 0)
 +              return (status);
 +
 +      s->rate = v.gauge;
 +      s->has_value = 1;
 +      return (0);
 +} /* }}} int cpu_stage */
 +
  static int cpu_read (void)
  {
 -#if PROCESSOR_CPU_LOAD_INFO
 +      cdtime_t now = cdtime ();
 +
 +#if PROCESSOR_CPU_LOAD_INFO /* {{{ */
        int cpu;
  
        kern_return_t status;
 -      
 +
        processor_cpu_load_info_data_t cpu_info;
        mach_msg_type_number_t         cpu_info_len;
  
                        continue;
                }
  
 -              if (cpu_info_len < CPU_STATE_MAX)
 +              if (cpu_info_len < COLLECTD_CPU_STATE_MAX)
                {
                        ERROR ("cpu plugin: processor_info returned only %i elements..", cpu_info_len);
                        continue;
                }
  
 -              submit (cpu, "user", (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER]);
 -              submit (cpu, "nice", (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE]);
 -              submit (cpu, "system", (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM]);
 -              submit (cpu, "idle", (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE]);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_USER,   (derive_t) cpu_info.cpu_ticks[COLLECTD_CPU_STATE_USER],   now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_NICE,   (derive_t) cpu_info.cpu_ticks[COLLECTD_CPU_STATE_NICE],   now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_SYSTEM, (derive_t) cpu_info.cpu_ticks[COLLECTD_CPU_STATE_SYSTEM], now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_IDLE,   (derive_t) cpu_info.cpu_ticks[COLLECTD_CPU_STATE_IDLE],   now);
        }
 -/* #endif PROCESSOR_CPU_LOAD_INFO */
 +/* }}} #endif PROCESSOR_CPU_LOAD_INFO */
  
 -#elif defined(KERNEL_LINUX)
 +#elif defined(KERNEL_LINUX) /* {{{ */
        int cpu;
 -      derive_t user, nice, syst, idle;
 -      derive_t wait, intr, sitr; /* sitr == soft interrupt */
        FILE *fh;
        char buf[1024];
  
                        continue;
  
                cpu = atoi (fields[0] + 3);
 -              user = atoll (fields[1]);
 -              nice = atoll (fields[2]);
 -              syst = atoll (fields[3]);
 -              idle = atoll (fields[4]);
  
 -              submit (cpu, "user", user);
 -              submit (cpu, "nice", nice);
 -              submit (cpu, "system", syst);
 -              submit (cpu, "idle", idle);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_USER,   (derive_t) atoll(fields[1]), now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_NICE,   (derive_t) atoll(fields[2]), now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_SYSTEM, (derive_t) atoll(fields[3]), now);
 +              cpu_stage (cpu, COLLECTD_CPU_STATE_IDLE,   (derive_t) atoll(fields[4]), now);
  
                if (numfields >= 8)
                {
 -                      wait = atoll (fields[5]);
 -                      intr = atoll (fields[6]);
 -                      sitr = atoll (fields[7]);
 -
 -                      submit (cpu, "wait", wait);
 -                      submit (cpu, "interrupt", intr);
 -                      submit (cpu, "softirq", sitr);
 +                      cpu_stage (cpu, COLLECTD_CPU_STATE_WAIT,      (derive_t) atoll(fields[5]), now);
 +                      cpu_stage (cpu, COLLECTD_CPU_STATE_INTERRUPT, (derive_t) atoll(fields[6]), now);
 +                      cpu_stage (cpu, COLLECTD_CPU_STATE_SOFTIRQ,   (derive_t) atoll(fields[7]), now);
  
                        if (numfields >= 9)
 -                              submit (cpu, "steal", atoll (fields[8]));
 +                              cpu_stage (cpu, COLLECTD_CPU_STATE_STEAL, (derive_t) atoll(fields[8]), now);
                }
        }
 -
        fclose (fh);
 -/* #endif defined(KERNEL_LINUX) */
 +/* }}} #endif defined(KERNEL_LINUX) */
  
 -#elif defined(HAVE_LIBKSTAT)
 +#elif defined(HAVE_LIBKSTAT) /* {{{ */
        int cpu;
 -      derive_t user, syst, idle, wait;
        static cpu_stat_t cs;
  
        if (kc == NULL)
                if (kstat_read (kc, ksp[cpu], &cs) == -1)
                        continue; /* error message? */
  
 -              idle = (derive_t) cs.cpu_sysinfo.cpu[CPU_IDLE];
 -              user = (derive_t) cs.cpu_sysinfo.cpu[CPU_USER];
 -              syst = (derive_t) cs.cpu_sysinfo.cpu[CPU_KERNEL];
 -              wait = (derive_t) cs.cpu_sysinfo.cpu[CPU_WAIT];
 -
 -              submit (ksp[cpu]->ks_instance, "user", user);
 -              submit (ksp[cpu]->ks_instance, "system", syst);
 -              submit (ksp[cpu]->ks_instance, "idle", idle);
 -              submit (ksp[cpu]->ks_instance, "wait", wait);
 +              cpu_stage (ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_IDLE,   (derive_t) cs.cpu_sysinfo.cpu[CPU_IDLE],   now);
 +              cpu_stage (ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_USER,   (derive_t) cs.cpu_sysinfo.cpu[CPU_USER],   now);
 +              cpu_stage (ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_SYSTEM, (derive_t) cs.cpu_sysinfo.cpu[CPU_KERNEL], now);
 +              cpu_stage (ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_WAIT,   (derive_t) cs.cpu_sysinfo.cpu[CPU_WAIT],   now);
        }
 -/* #endif defined(HAVE_LIBKSTAT) */
 +/* }}} #endif defined(HAVE_LIBKSTAT) */
  
 -#elif CAN_USE_SYSCTL
 +#elif CAN_USE_SYSCTL /* {{{ */
        uint64_t cpuinfo[numcpu][CPUSTATES];
        size_t cpuinfo_size;
        int status;
        }
  
        for (i = 0; i < numcpu; i++) {
 -              submit (i, "user",      cpuinfo[i][CP_USER]);
 -              submit (i, "nice",      cpuinfo[i][CP_NICE]);
 -              submit (i, "system",    cpuinfo[i][CP_SYS]);
 -              submit (i, "idle",      cpuinfo[i][CP_IDLE]);
 -              submit (i, "interrupt", cpuinfo[i][CP_INTR]);
 +              cpu_stage (i, COLLECTD_CPU_STATE_USER,      (derive_t) cpuinfo[i][CP_USER], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_NICE,      (derive_t) cpuinfo[i][CP_NICE], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_SYSTEM,    (derive_t) cpuinfo[i][CP_SYS], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_IDLE,      (derive_t) cpuinfo[i][CP_IDLE], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_INTERRUPT, (derive_t) cpuinfo[i][CP_INTR], now);
        }
 -/* #endif CAN_USE_SYSCTL */
 -#elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
 +/* }}} #endif CAN_USE_SYSCTL */
 +
 +#elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES) /* {{{ */
        long cpuinfo[maxcpu][CPUSTATES];
        size_t cpuinfo_size;
        int i;
        }
  
        for (i = 0; i < numcpu; i++) {
 -              submit (i, "user", cpuinfo[i][CP_USER]);
 -              submit (i, "nice", cpuinfo[i][CP_NICE]);
 -              submit (i, "system", cpuinfo[i][CP_SYS]);
 -              submit (i, "idle", cpuinfo[i][CP_IDLE]);
 -              submit (i, "interrupt", cpuinfo[i][CP_INTR]);
 +              cpu_stage (i, COLLECTD_CPU_STATE_USER,      (derive_t) cpuinfo[i][CP_USER], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_NICE,      (derive_t) cpuinfo[i][CP_NICE], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_SYSTEM,    (derive_t) cpuinfo[i][CP_SYS], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_IDLE,      (derive_t) cpuinfo[i][CP_IDLE], now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_INTERRUPT, (derive_t) cpuinfo[i][CP_INTR], now);
        }
 -/* #endif HAVE_SYSCTL_KERN_CP_TIMES */
 -#elif defined(HAVE_SYSCTLBYNAME)
 +/* }}} #endif HAVE_SYSCTL_KERN_CP_TIMES */
 +
 +#elif defined(HAVE_SYSCTLBYNAME) /* {{{ */
        long cpuinfo[CPUSTATES];
        size_t cpuinfo_size;
  
                return (-1);
        }
  
 -      submit (0, "user", cpuinfo[CP_USER]);
 -      submit (0, "nice", cpuinfo[CP_NICE]);
 -      submit (0, "system", cpuinfo[CP_SYS]);
 -      submit (0, "idle", cpuinfo[CP_IDLE]);
 -      submit (0, "interrupt", cpuinfo[CP_INTR]);
 -/* #endif HAVE_SYSCTLBYNAME */
 +      cpu_stage (0, COLLECTD_CPU_STATE_USER,      (derive_t) cpuinfo[CP_USER], now);
 +      cpu_stage (0, COLLECTD_CPU_STATE_NICE,      (derive_t) cpuinfo[CP_NICE], now);
 +      cpu_stage (0, COLLECTD_CPU_STATE_SYSTEM,    (derive_t) cpuinfo[CP_SYS], now);
 +      cpu_stage (0, COLLECTD_CPU_STATE_IDLE,      (derive_t) cpuinfo[CP_IDLE], now);
 +      cpu_stage (0, COLLECTD_CPU_STATE_INTERRUPT, (derive_t) cpuinfo[CP_INTR], now);
 +/* }}} #endif HAVE_SYSCTLBYNAME */
  
 -#elif defined(HAVE_LIBSTATGRAB)
 +#elif defined(HAVE_LIBSTATGRAB) /* {{{ */
        sg_cpu_stats *cs;
        cs = sg_get_cpu_stats ();
  
                return (-1);
        }
  
 -      submit (0, "idle",   (derive_t) cs->idle);
 -      submit (0, "nice",   (derive_t) cs->nice);
 -      submit (0, "swap",   (derive_t) cs->swap);
 -      submit (0, "system", (derive_t) cs->kernel);
 -      submit (0, "user",   (derive_t) cs->user);
 -      submit (0, "wait",   (derive_t) cs->iowait);
 -/* #endif HAVE_LIBSTATGRAB */
 +      cpu_state (0, COLLECTD_CPU_STATE_IDLE,   (derive_t) cs->idle);
 +      cpu_state (0, COLLECTD_CPU_STATE_NICE,   (derive_t) cs->nice);
 +      cpu_state (0, COLLECTD_CPU_STATE_SWAP,   (derive_t) cs->swap);
 +      cpu_state (0, COLLECTD_CPU_STATE_SYSTEM, (derive_t) cs->kernel);
 +      cpu_state (0, COLLECTD_CPU_STATE_USER,   (derive_t) cs->user);
 +      cpu_state (0, COLLECTD_CPU_STATE_WAIT,   (derive_t) cs->iowait);
 +/* }}} #endif HAVE_LIBSTATGRAB */
  
 -#elif defined(HAVE_PERFSTAT)
 +#elif defined(HAVE_PERFSTAT) /* {{{ */
        perfstat_id_t id;
        int i, cpus;
  
                        sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
 -      
 -      if (pnumcpu != numcpu || perfcpu == NULL) 
 +
 +      if (pnumcpu != numcpu || perfcpu == NULL)
        {
 -              if (perfcpu != NULL) 
 +              if (perfcpu != NULL)
                        free(perfcpu);
                perfcpu = malloc(numcpu * sizeof(perfstat_cpu_t));
        }
                return (-1);
        }
  
 -      for (i = 0; i < cpus; i++) 
 +      for (i = 0; i < cpus; i++)
        {
 -              submit (i, "idle",   (derive_t) perfcpu[i].idle);
 -              submit (i, "system", (derive_t) perfcpu[i].sys);
 -              submit (i, "user",   (derive_t) perfcpu[i].user);
 -              submit (i, "wait",   (derive_t) perfcpu[i].wait);
 +              cpu_stage (i, COLLECTD_CPU_STATE_IDLE,   (derive_t) perfcpu[i].idle, now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_SYSTEM, (derive_t) perfcpu[i].sys,  now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_USER,   (derive_t) perfcpu[i].user, now);
 +              cpu_stage (i, COLLECTD_CPU_STATE_WAIT,   (derive_t) perfcpu[i].wait, now);
        }
 -#endif /* HAVE_PERFSTAT */
 +#endif /* }}} HAVE_PERFSTAT */
  
 +      cpu_commit ();
 +      cpu_reset ();
        return (0);
  }
  
  void module_register (void)
  {
        plugin_register_init ("cpu", init);
 +      plugin_register_config ("cpu", cpu_config, config_keys, config_keys_num);
        plugin_register_read ("cpu", cpu_read);
  } /* void module_register */
 +
 +/* vim: set sw=8 sts=8 noet fdm=marker : */
diff --combined src/daemon/types_list.c
index b3cb8cf,0000000..c0e61c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,207 -1,0 +1,207 @@@
-         || (buf[buf_len - 1] == '\n')))
 +/**
 + * collectd - src/types_list.c
 + * Copyright (C) 2007       Florian octo Forster
 + *
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
 + *
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
 + *
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
 + *
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
 + **/
 +
 +#include "collectd.h"
 +#include "common.h"
 +
 +#include "plugin.h"
 +#include "configfile.h"
 +
 +static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
 +{
 +  char *dummy;
 +  char *saveptr;
 +  char *fields[8];
 +  int   fields_num;
 +
 +  if (buf_len < 11)
 +  {
 +    ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
 +    return (-1);
 +  }
 +
 +  if (buf[buf_len - 1] == ',')
 +  {
 +    buf_len--;
 +    buf[buf_len] = '\0';
 +  }
 +
 +  dummy = buf;
 +  saveptr = NULL;
 +
 +  fields_num = 0;
 +  while (fields_num < 8)
 +  {
 +    if ((fields[fields_num] = strtok_r (dummy, ":", &saveptr)) == NULL)
 +      break;
 +    dummy = NULL;
 +    fields_num++;
 +  }
 +
 +  if (fields_num != 4)
 +  {
 +    ERROR ("parse_ds: (fields_num = %i) != 4", fields_num);
 +    return (-1);
 +  }
 +
 +  sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
 +
 +  if (strcasecmp (fields[1], "GAUGE") == 0)
 +    dsrc->type = DS_TYPE_GAUGE;
 +  else if (strcasecmp (fields[1], "COUNTER") == 0)
 +    dsrc->type = DS_TYPE_COUNTER;
 +  else if (strcasecmp (fields[1], "DERIVE") == 0)
 +    dsrc->type = DS_TYPE_DERIVE;
 +  else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
 +    dsrc->type = DS_TYPE_ABSOLUTE;
 +  else
 +  {
 +    ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
 +    return (-1);
 +  }
 +
 +  if (strcasecmp (fields[2], "U") == 0)
 +    dsrc->min = NAN;
 +  else
 +    dsrc->min = atof (fields[2]);
 +
 +  if (strcasecmp (fields[3], "U") == 0)
 +    dsrc->max = NAN;
 +  else
 +    dsrc->max = atof (fields[3]);
 +
 +  return (0);
 +} /* int parse_ds */
 +
 +static void parse_line (char *buf)
 +{
 +  char  *fields[64];
 +  size_t fields_num;
 +  data_set_t *ds;
 +  int i;
 +
 +  fields_num = strsplit (buf, fields, 64);
 +  if (fields_num < 2)
 +    return;
 +
 +  /* Ignore lines which begin with a hash sign. */
 +  if (fields[0][0] == '#')
 +    return;
 +
 +  ds = (data_set_t *) malloc (sizeof (data_set_t));
 +  if (ds == NULL)
 +    return;
 +
 +  memset (ds, '\0', sizeof (data_set_t));
 +
 +  sstrncpy (ds->type, fields[0], sizeof (ds->type));
 +
 +  ds->ds_num = fields_num - 1;
 +  ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
 +  if (ds->ds == NULL)
 +    return;
 +
 +  for (i = 0; i < ds->ds_num; i++)
 +    if (parse_ds (ds->ds + i, fields[i + 1], strlen (fields[i + 1])) != 0)
 +    {
 +      sfree (ds->ds);
 +      ERROR ("types_list: parse_line: Cannot parse data source #%i "
 +        "of data set %s", i, ds->type);
 +      return;
 +    }
 +
 +  plugin_register_data_set (ds);
 +
 +  sfree (ds->ds);
 +  sfree (ds);
 +} /* void parse_line */
 +
 +static void parse_file (FILE *fh)
 +{
 +  char buf[4096];
 +  size_t buf_len;
 +
 +  while (fgets (buf, sizeof (buf), fh) != NULL)
 +  {
 +    buf_len = strlen (buf);
 +
 +    if (buf_len >= 4095)
 +    {
 +      NOTICE ("Skipping line with more than 4095 characters.");
 +      do
 +      {
 +      if (fgets (buf, sizeof (buf), fh) == NULL)
 +        break;
 +      buf_len = strlen (buf);
 +      } while (buf_len >= 4095);
 +      continue;
 +    } /* if (buf_len >= 4095) */
 +
 +    if ((buf_len == 0) || (buf[0] == '#'))
 +      continue;
 +
 +    while ((buf_len > 0) && ((buf[buf_len - 1] == '\n')
++        || (buf[buf_len - 1] == '\r')))
 +      buf[--buf_len] = '\0';
 +
 +    if (buf_len == 0)
 +      continue;
 +
 +    parse_line (buf);
 +  } /* while (fgets) */
 +} /* void parse_file */
 +
 +int read_types_list (const char *file)
 +{
 +  FILE *fh;
 +
 +  if (file == NULL)
 +    return (-1);
 +
 +  fh = fopen (file, "r");
 +  if (fh == NULL)
 +  {
 +    char errbuf[1024];
 +    fprintf (stderr, "Failed to open types database `%s': %s.\n",
 +      file, sstrerror (errno, errbuf, sizeof (errbuf)));
 +    ERROR ("Failed to open types database `%s': %s",
 +      file, sstrerror (errno, errbuf, sizeof (errbuf)));
 +    return (-1);
 +  }
 +
 +  parse_file (fh);
 +
 +  fclose (fh);
 +  fh = NULL;
 +
 +  DEBUG ("Done parsing `%s'", file);
 +
 +  return (0);
 +} /* int read_types_list */
 +
 +/*
 + * vim: shiftwidth=2:softtabstop=2:tabstop=8
 + */
@@@ -84,7 -84,7 +84,7 @@@
      _b[sizeof (_b) - 1] = 0; \
      SSTRCAT ((d), _b); \
    } while (0)
 -    
 +
  
  #define LCC_SET_ERRSTR(c, ...) do { \
    snprintf ((c)->errbuf, sizeof ((c)->errbuf), __VA_ARGS__); \
@@@ -258,6 -258,7 +258,7 @@@ static int lcc_send (lcc_connection_t *
      lcc_set_errno (c, errno);
      return (-1);
    }
+   fflush(c->fh);
  
    return (0);
  } /* }}} int lcc_send */
diff --combined src/netlink.c
  
  #include <libmnl/libmnl.h>
  
 +struct ir_link_stats_storage_s {
 +
 +  uint64_t rx_packets;
 +  uint64_t tx_packets;
 +  uint64_t rx_bytes;
 +  uint64_t tx_bytes;
 +  uint64_t rx_errors;
 +  uint64_t tx_errors;
 +
 +  uint64_t rx_dropped;
 +  uint64_t tx_dropped;
 +  uint64_t multicast;
 +  uint64_t collisions;
 +
 +  uint64_t rx_length_errors;
 +  uint64_t rx_over_errors;
 +  uint64_t rx_crc_errors;
 +  uint64_t rx_frame_errors;
 +  uint64_t rx_fifo_errors;
 +  uint64_t rx_missed_errors;
 +
 +  uint64_t tx_aborted_errors;
 +  uint64_t tx_carrier_errors;
 +  uint64_t tx_fifo_errors;
 +  uint64_t tx_heartbeat_errors;
 +  uint64_t tx_window_errors;
 +};
 +
 +union ir_link_stats_u {
 +  struct rtnl_link_stats *stats32;
 +#ifdef HAVE_RTNL_LINK_STATS64
 +  struct rtnl_link_stats64 *stats64;
 +#endif
 +};
 +
  typedef struct ir_ignorelist_s
  {
    char *device;
@@@ -270,7 -235,7 +270,7 @@@ static int update_iflist (struct ifinfo
  } /* int update_iflist */
  
  static void check_ignorelist_and_submit (const char *dev,
 -    struct rtnl_link_stats *stats)
 +    struct ir_link_stats_storage_s *stats)
  {
  
    if (check_ignorelist (dev, "interface", NULL) == 0)
  
  } /* void check_ignorelist_and_submit */
  
 +#define COPY_RTNL_LINK_VALUE(dst_stats, src_stats, value_name) \
 +  (dst_stats)->value_name = (src_stats)->value_name
 +
 +#define COPY_RTNL_LINK_STATS(dst_stats, src_stats) \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_packets); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_packets); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_bytes); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_bytes); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_dropped); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_dropped); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, multicast); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, collisions); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_length_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_over_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_crc_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_frame_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_fifo_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_missed_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_aborted_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_carrier_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_fifo_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_heartbeat_errors); \
 +  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_window_errors)
 +
 +#ifdef HAVE_RTNL_LINK_STATS64
 +static void check_ignorelist_and_submit64 (const char *dev,
 +    struct rtnl_link_stats64 *stats)
 +{
 +  struct ir_link_stats_storage_s s;
 +
 +  COPY_RTNL_LINK_STATS (&s, stats);
 +
 +  check_ignorelist_and_submit (dev, &s);
 +}
 +#endif
 +
 +static void check_ignorelist_and_submit32 (const char *dev,
 +    struct rtnl_link_stats *stats)
 +{
 +  struct ir_link_stats_storage_s s;
 +
 +  COPY_RTNL_LINK_STATS(&s, stats);
 +
 +  check_ignorelist_and_submit (dev, &s);
 +}
 +
  static int link_filter_cb (const struct nlmsghdr *nlh,
      void *args __attribute__((unused)))
  {
    struct ifinfomsg *ifm = mnl_nlmsg_get_payload (nlh);
    struct nlattr *attr;
 -  struct rtnl_link_stats *stats = NULL;
    const char *dev = NULL;
 +  union ir_link_stats_u stats;
  
    if (nlh->nlmsg_type != RTM_NEWLINK)
    {
      ERROR ("netlink plugin: link_filter_cb: dev == NULL");
      return MNL_CB_ERROR;
    }
 +#ifdef HAVE_RTNL_LINK_STATS64
 +  mnl_attr_for_each (attr, nlh, sizeof (*ifm))
 +  {
 +    if (mnl_attr_get_type (attr) != IFLA_STATS64)
 +      continue;
 +
 +    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats64)) < 0)
 +    {
 +      ERROR ("netlink plugin: link_filter_cb: IFLA_STATS64 mnl_attr_validate2 failed.");
 +      return MNL_CB_ERROR;
 +    }
 +    stats.stats64 = mnl_attr_get_payload (attr);
 +
 +    check_ignorelist_and_submit64 (dev, stats.stats64);
  
 +    return MNL_CB_OK;
 +  }
 +#endif
    mnl_attr_for_each (attr, nlh, sizeof (*ifm))
    {
      if (mnl_attr_get_type (attr) != IFLA_STATS)
        continue;
  
 -    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats)) < 0)
 +    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats32)) < 0)
      {
        ERROR ("netlink plugin: link_filter_cb: IFLA_STATS mnl_attr_validate2 failed.");
        return MNL_CB_ERROR;
      }
 -    stats = mnl_attr_get_payload (attr);
 +    stats.stats32 = mnl_attr_get_payload (attr);
  
 -    check_ignorelist_and_submit (dev, stats);
 -    break;
 -  }
 +    check_ignorelist_and_submit32 (dev, stats.stats32);
  
 -  if (stats == NULL)
 -  {
 -    DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev);
      return MNL_CB_OK;
    }
  
 +  DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev);
    return MNL_CB_OK;
 +
  } /* int link_filter_cb */
  
  #if HAVE_TCA_STATS2
@@@ -780,7 -683,7 +780,7 @@@ static int ir_read (void
          continue;
        }
  
-       DEBUG ("netlink plugin: ir_read: querying %s from %s (%lu).",
+       DEBUG ("netlink plugin: ir_read: querying %s from %s (%zu).",
            type_name[type_index], iflist[ifindex], ifindex);
  
        nlh = mnl_nlmsg_put_header (buf);
diff --combined src/utils_cmd_flush.c
@@@ -1,29 -1,24 +1,29 @@@
  /**
   * collectd - src/utils_cmd_flush.c
 - * Copyright (C) 2008  Sebastian Harl
 - * Copyright (C) 2008  Florian Forster
 + * Copyright (C) 2008       Sebastian Harl
 + * Copyright (C) 2008       Florian 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
 - * Free Software Foundation; only version 2 of the License is applicable.
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
   *
 - * This program is distributed in the hope that it will be useful, but
 - * WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * General Public License for more details.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * You should have received a copy of the GNU General Public License along
 - * with this program; if not, write to the Free Software Foundation, Inc.,
 - * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
   *
   * Authors:
   *   Sebastian "tokkee" Harl <sh at tokkee.org>
 - *   Florian "octo" Forster <octo at verplant.org>
 + *   Florian "octo" Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #include "utils_parse_option.h"
  
  #define print_to_socket(fh, ...) \
-       if (fprintf (fh, __VA_ARGS__) < 0) { \
-               char errbuf[1024]; \
-               WARNING ("handle_flush: failed to write to socket #%i: %s", \
-                               fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-               return -1; \
-       }
+       do { \
+               if (fprintf (fh, __VA_ARGS__) < 0) { \
+                       char errbuf[1024]; \
+                       WARNING ("handle_flush: failed to write to socket #%i: %s", \
+                                       fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+                       return -1; \
+               } \
+               fflush(fh); \
+       } while (0)
  
  static int add_to_array (char ***array, int *array_num, char *value)
  {
@@@ -173,7 -171,7 +176,7 @@@ int handle_flush (FILE *fh, char *buffe
        }
        else
        {
 -              plugin_flush (NULL, timeout, NULL);
 +              plugin_flush (NULL, DOUBLE_TO_CDTIME_T (timeout), NULL);
                print_to_socket (fh, "0 Done\n");
        }
  
diff --combined src/utils_cmd_getval.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_getval.c
 - * Copyright (C) 2008  Florian octo Forster
 + * collectd - src/utils_cmd_getval.c
 + * Copyright (C) 2008       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
 - * Free Software Foundation; only version 2 of the License is applicable.
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
   *
 - * This program is distributed in the hope that it will be useful, but
 - * WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * General Public License for more details.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * You should have received a copy of the GNU General Public License along
 - * with this program; if not, write to the Free Software Foundation, Inc.,
 - * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #include "utils_parse_option.h"
  
  #define print_to_socket(fh, ...) \
-   if (fprintf (fh, __VA_ARGS__) < 0) { \
-     char errbuf[1024]; \
-     WARNING ("handle_getval: failed to write to socket #%i: %s", \
-       fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-     return -1; \
-   }
+   do { \
+     if (fprintf (fh, __VA_ARGS__) < 0) { \
+       char errbuf[1024]; \
+       WARNING ("handle_getval: failed to write to socket #%i: %s", \
+           fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+       return -1; \
+     } \
+     fflush(fh); \
+   } while (0)
  
  int handle_getval (FILE *fh, char *buffer)
  {
diff --combined src/utils_cmd_listval.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_listval.c
 - * Copyright (C) 2008  Florian octo Forster
 + * collectd - src/utils_cmd_listval.c
 + * Copyright (C) 2008       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
 - * Free Software Foundation; only version 2 of the License is applicable.
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
   *
 - * This program is distributed in the hope that it will be useful, but
 - * WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * General Public License for more details.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * You should have received a copy of the GNU General Public License along
 - * with this program; if not, write to the Free Software Foundation, Inc.,
 - * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
    } while (0)
  
  #define print_to_socket(fh, ...) \
-   if (fprintf (fh, __VA_ARGS__) < 0) { \
-     char errbuf[1024]; \
-     WARNING ("handle_listval: failed to write to socket #%i: %s", \
-       fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-     free_everything_and_return (-1); \
-   }
+   do { \
+     if (fprintf (fh, __VA_ARGS__) < 0) { \
+       char errbuf[1024]; \
+       WARNING ("handle_listval: failed to write to socket #%i: %s", \
+           fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+       free_everything_and_return (-1); \
+     } \
+     fflush(fh); \
+   } while (0)
  
  int handle_listval (FILE *fh, char *buffer)
  {
diff --combined src/utils_cmd_putnotif.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_putnotif.c
 - * Copyright (C) 2008  Florian octo Forster
 + * collectd - src/utils_cmd_putnotif.c
 + * Copyright (C) 2008       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
 - * Free Software Foundation; only version 2 of the License is applicable.
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
   *
 - * This program is distributed in the hope that it will be useful, but
 - * WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * General Public License for more details.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * You should have received a copy of the GNU General Public License along
 - * with this program; if not, write to the Free Software Foundation, Inc.,
 - * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #include "utils_parse_option.h"
  
  #define print_to_socket(fh, ...) \
-   if (fprintf (fh, __VA_ARGS__) < 0) { \
-     char errbuf[1024]; \
-     WARNING ("handle_putnotif: failed to write to socket #%i: %s", \
-       fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-     return -1; \
-   }
+   do { \
+     if (fprintf (fh, __VA_ARGS__) < 0) { \
+       char errbuf[1024]; \
+       WARNING ("handle_putnotif: failed to write to socket #%i: %s", \
+           fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+       return -1; \
+     } \
+     fflush(fh); \
+   } while (0)
  
  static int set_option_severity (notification_t *n, const char *value)
  {
@@@ -78,18 -76,6 +81,18 @@@ static int set_option (notification_t *
    DEBUG ("utils_cmd_putnotif: set_option (option = %s, value = %s);",
        option, value);
  
 +  /* Add a meta option in the form: <type>:<key> */
 +  if (option[0] != '\0' && option[1] == ':') {
 +    /* Refuse empty key */
 +    if (option[2] == '\0')
 +      return (1);
 +
 +    if (option[0] == 's')
 +      return plugin_notification_meta_add_string (n, option + 2, value);
 +    else
 +      return (1);
 +  }
 +
    if (strcasecmp ("severity", option) == 0)
      return (set_option_severity (n, value));
    else if (strcasecmp ("time", option) == 0)
diff --combined src/utils_cmd_putval.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_putval.c
 + * collectd - src/utils_cmd_putval.c
   * Copyright (C) 2007-2009  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
 - * Free Software Foundation; only version 2 of the License is applicable.
 + * Permission is hereby granted, free of charge, to any person obtaining a
 + * copy of this software and associated documentation files (the "Software"),
 + * to deal in the Software without restriction, including without limitation
 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 + * and/or sell copies of the Software, and to permit persons to whom the
 + * Software is furnished to do so, subject to the following conditions:
   *
 - * This program is distributed in the hope that it will be useful, but
 - * WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * General Public License for more details.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * You should have received a copy of the GNU General Public License along
 - * with this program; if not, write to the Free Software Foundation, Inc.,
 - * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 + * DEALINGS IN THE SOFTWARE.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #include "utils_parse_option.h"
  
  #define print_to_socket(fh, ...) \
-       if (fprintf (fh, __VA_ARGS__) < 0) { \
-               char errbuf[1024]; \
-               WARNING ("handle_putval: failed to write to socket #%i: %s", \
-                               fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-               return -1; \
-       }
+     do { \
+         if (fprintf (fh, __VA_ARGS__) < 0) { \
+             char errbuf[1024]; \
+             WARNING ("handle_putval: failed to write to socket #%i: %s", \
+                     fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+             return -1; \
+         } \
+         fflush(fh); \
+     } while (0)
  
  static int dispatch_values (const data_set_t *ds, value_list_t *vl,
                FILE *fh, char *buffer)
diff --combined src/virt.c
index 5f87625,0000000..b6fedf5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1004 -1,0 +1,1010 @@@
 +/**
 + * collectd - src/virt.c
 + * Copyright (C) 2006-2008  Red Hat Inc.
 + *
 + * 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
 + * Free Software Foundation; only version 2 of the license is applicable.
 + *
 + * This program is distributed in the hope that it will be useful, but
 + * WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 + *
 + * Authors:
 + *   Richard W.M. Jones <rjones@redhat.com>
 + **/
 +
 +#include "collectd.h"
 +#include "common.h"
 +#include "plugin.h"
 +#include "configfile.h"
 +#include "utils_ignorelist.h"
 +#include "utils_complain.h"
 +
 +#include <libvirt/libvirt.h>
 +#include <libvirt/virterror.h>
 +#include <libxml/parser.h>
 +#include <libxml/tree.h>
 +#include <libxml/xpath.h>
 +
 +/* Plugin name */
 +#define PLUGIN_NAME "virt"
 +
 +static const char *config_keys[] = {
 +    "Connection",
 +
 +    "RefreshInterval",
 +
 +    "Domain",
 +    "BlockDevice",
 +    "InterfaceDevice",
 +    "IgnoreSelected",
 +
 +    "HostnameFormat",
 +    "InterfaceFormat",
 +
 +    "PluginInstanceFormat",
 +
 +    NULL
 +};
 +#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
 +
 +/* Connection. */
 +static virConnectPtr conn = 0;
 +static char *conn_string = NULL;
 +static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
 +
 +/* Seconds between list refreshes, 0 disables completely. */
 +static int interval = 60;
 +
 +/* List of domains, if specified. */
 +static ignorelist_t *il_domains = NULL;
 +/* List of block devices, if specified. */
 +static ignorelist_t *il_block_devices = NULL;
 +/* List of network interface devices, if specified. */
 +static ignorelist_t *il_interface_devices = NULL;
 +
 +static int ignore_device_match (ignorelist_t *,
 +                                const char *domname, const char *devpath);
 +
 +/* Actual list of domains found on last refresh. */
 +static virDomainPtr *domains = NULL;
 +static int nr_domains = 0;
 +
 +static void free_domains (void);
 +static int add_domain (virDomainPtr dom);
 +
 +/* Actual list of block devices found on last refresh. */
 +struct block_device {
 +    virDomainPtr dom;           /* domain */
 +    char *path;                 /* name of block device */
 +};
 +
 +static struct block_device *block_devices = NULL;
 +static int nr_block_devices = 0;
 +
 +static void free_block_devices (void);
 +static int add_block_device (virDomainPtr dom, const char *path);
 +
 +/* Actual list of network interfaces found on last refresh. */
 +struct interface_device {
 +    virDomainPtr dom;           /* domain */
 +    char *path;                 /* name of interface device */
 +    char *address;              /* mac address of interface device */
 +    char *number;               /* interface device number */
 +};
 +
 +static struct interface_device *interface_devices = NULL;
 +static int nr_interface_devices = 0;
 +
 +static void free_interface_devices (void);
 +static int add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number);
 +
 +/* HostnameFormat. */
 +#define HF_MAX_FIELDS 3
 +
 +enum hf_field {
 +    hf_none = 0,
 +    hf_hostname,
 +    hf_name,
 +    hf_uuid
 +};
 +
 +static enum hf_field hostname_format[HF_MAX_FIELDS] =
 +    { hf_name };
 +
 +/* PluginInstanceFormat */
 +#define PLGINST_MAX_FIELDS 2
 +
 +enum plginst_field {
 +    plginst_none = 0,
 +    plginst_name,
 +    plginst_uuid
 +};
 +
 +static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] =
 +    { plginst_name };
 +
 +/* InterfaceFormat. */
 +enum if_field {
 +    if_address,
 +    if_name,
 +    if_number
 +};
 +
 +static enum if_field interface_format = if_name;
 +
 +/* Time that we last refreshed. */
 +static time_t last_refresh = (time_t) 0;
 +
 +static int refresh_lists (void);
 +
 +/* ERROR(...) macro for virterrors. */
 +#define VIRT_ERROR(conn,s) do {                 \
 +        virErrorPtr err;                        \
 +        err = (conn) ? virConnGetLastError ((conn)) : virGetLastError (); \
 +        if (err) ERROR ("%s: %s", (s), err->message);                   \
 +    } while(0)
 +
 +static void
 +init_value_list (value_list_t *vl, virDomainPtr dom)
 +{
 +    int i, n;
 +    const char *name;
 +    char uuid[VIR_UUID_STRING_BUFLEN];
 +
 +    sstrncpy (vl->plugin, PLUGIN_NAME, sizeof (vl->plugin));
 +
 +    vl->host[0] = '\0';
 +
 +    /* Construct the hostname field according to HostnameFormat. */
 +    for (i = 0; i < HF_MAX_FIELDS; ++i) {
 +        if (hostname_format[i] == hf_none)
 +            continue;
 +
 +        n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
 +
 +        if (i > 0 && n >= 1) {
 +            strncat (vl->host, ":", 1);
 +            n--;
 +        }
 +
 +        switch (hostname_format[i]) {
 +        case hf_none: break;
 +        case hf_hostname:
 +            strncat (vl->host, hostname_g, n);
 +            break;
 +        case hf_name:
 +            name = virDomainGetName (dom);
 +            if (name)
 +                strncat (vl->host, name, n);
 +            break;
 +        case hf_uuid:
 +            if (virDomainGetUUIDString (dom, uuid) == 0)
 +                strncat (vl->host, uuid, n);
 +            break;
 +        }
 +    }
 +
 +    vl->host[sizeof (vl->host) - 1] = '\0';
 +
 +    /* Construct the plugin instance field according to PluginInstanceFormat. */
 +    for (i = 0; i < PLGINST_MAX_FIELDS; ++i) {
 +        if (plugin_instance_format[i] == plginst_none)
 +            continue;
 +
 +        n = sizeof(vl->plugin_instance) - strlen (vl->plugin_instance) - 2;
 +
 +        if (i > 0 && n >= 1) {
 +            strncat (vl->plugin_instance, ":", 1);
 +            n--;
 +        }
 +
 +        switch (plugin_instance_format[i]) {
 +        case plginst_none: break;
 +        case plginst_name:
 +            name = virDomainGetName (dom);
 +            if (name)
 +                strncat (vl->plugin_instance, name, n);
 +            break;
 +        case plginst_uuid:
 +            if (virDomainGetUUIDString (dom, uuid) == 0)
 +                strncat (vl->plugin_instance, uuid, n);
 +            break;
 +        }
 +    }
 +
 +    vl->plugin_instance[sizeof (vl->plugin_instance) - 1] = '\0';
 +
 +} /* void init_value_list */
 +
 +static void
 +memory_submit (gauge_t memory, virDomainPtr dom)
 +{
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].gauge = memory;
 +
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, "memory", sizeof (vl.type));
 +    sstrncpy (vl.type_instance, "total", sizeof (vl.type_instance));
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +memory_stats_submit (gauge_t memory, virDomainPtr dom, int tag_index)
 +{
 +    static const char *tags[] = { "swap_in", "swap_out", "major_fault", "minor_fault",
 +                                    "unused", "available", "actual_balloon", "rss"};
 +
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].gauge = memory;
 +
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, "memory", sizeof (vl.type));
 +    sstrncpy (vl.type_instance, tags[tag_index], sizeof (vl.type_instance));
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +cpu_submit (unsigned long long cpu_time,
 +            virDomainPtr dom, const char *type)
 +{
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = cpu_time;
 +
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +vcpu_submit (derive_t cpu_time,
 +             virDomainPtr dom, int vcpu_nr, const char *type)
 +{
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = cpu_time;
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +submit_derive2 (const char *type, derive_t v0, derive_t v1,
 +             virDomainPtr dom, const char *devname)
 +{
 +    value_t values[2];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = v0;
 +    values[1].derive = v1;
 +    vl.values = values;
 +    vl.values_len = 2;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
 +
 +    plugin_dispatch_values (&vl);
 +} /* void submit_derive2 */
 +
 +static int
 +lv_init (void)
 +{
 +    if (virInitialize () != 0)
 +        return -1;
 +
 +      return 0;
 +}
 +
 +static int
 +lv_config (const char *key, const char *value)
 +{
 +    if (virInitialize () != 0)
 +        return 1;
 +
 +    if (il_domains == NULL)
 +        il_domains = ignorelist_create (1);
 +    if (il_block_devices == NULL)
 +        il_block_devices = ignorelist_create (1);
 +    if (il_interface_devices == NULL)
 +        il_interface_devices = ignorelist_create (1);
 +
 +    if (strcasecmp (key, "Connection") == 0) {
 +        char *tmp = strdup (value);
 +        if (tmp == NULL) {
 +            ERROR (PLUGIN_NAME " plugin: Connection strdup failed.");
 +            return 1;
 +        }
 +        sfree (conn_string);
 +        conn_string = tmp;
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "RefreshInterval") == 0) {
 +        char *eptr = NULL;
 +        interval = strtol (value, &eptr, 10);
 +        if (eptr == NULL || *eptr != '\0') return 1;
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "Domain") == 0) {
 +        if (ignorelist_add (il_domains, value)) return 1;
 +        return 0;
 +    }
 +    if (strcasecmp (key, "BlockDevice") == 0) {
 +        if (ignorelist_add (il_block_devices, value)) return 1;
 +        return 0;
 +    }
 +    if (strcasecmp (key, "InterfaceDevice") == 0) {
 +        if (ignorelist_add (il_interface_devices, value)) return 1;
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "IgnoreSelected") == 0) {
 +        if (IS_TRUE (value))
 +        {
 +            ignorelist_set_invert (il_domains, 0);
 +            ignorelist_set_invert (il_block_devices, 0);
 +            ignorelist_set_invert (il_interface_devices, 0);
 +        }
 +        else
 +        {
 +            ignorelist_set_invert (il_domains, 1);
 +            ignorelist_set_invert (il_block_devices, 1);
 +            ignorelist_set_invert (il_interface_devices, 1);
 +        }
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "HostnameFormat") == 0) {
 +        char *value_copy;
 +        char *fields[HF_MAX_FIELDS];
 +        int i, n;
 +
 +        value_copy = strdup (value);
 +        if (value_copy == NULL) {
 +            ERROR (PLUGIN_NAME " plugin: strdup failed.");
 +            return -1;
 +        }
 +
 +        n = strsplit (value_copy, fields, HF_MAX_FIELDS);
 +        if (n < 1) {
 +            sfree (value_copy);
 +            ERROR (PLUGIN_NAME " plugin: HostnameFormat: no fields");
 +            return -1;
 +        }
 +
 +        for (i = 0; i < n; ++i) {
 +            if (strcasecmp (fields[i], "hostname") == 0)
 +                hostname_format[i] = hf_hostname;
 +            else if (strcasecmp (fields[i], "name") == 0)
 +                hostname_format[i] = hf_name;
 +            else if (strcasecmp (fields[i], "uuid") == 0)
 +                hostname_format[i] = hf_uuid;
 +            else {
 +                sfree (value_copy);
 +                ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
 +                return -1;
 +            }
 +        }
 +        sfree (value_copy);
 +
 +        for (i = n; i < HF_MAX_FIELDS; ++i)
 +            hostname_format[i] = hf_none;
 +
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "PluginInstanceFormat") == 0) {
 +        char *value_copy;
 +        char *fields[PLGINST_MAX_FIELDS];
 +        int i, n;
 +
 +        value_copy = strdup (value);
 +        if (value_copy == NULL) {
 +            ERROR (PLUGIN_NAME " plugin: strdup failed.");
 +            return -1;
 +        }
 +
 +        n = strsplit (value_copy, fields, PLGINST_MAX_FIELDS);
 +        if (n < 1) {
 +            sfree (value_copy);
 +            ERROR (PLUGIN_NAME " plugin: PluginInstanceFormat: no fields");
 +            return -1;
 +        }
 +
 +        for (i = 0; i < n; ++i) {
 +            if (strcasecmp (fields[i], "name") == 0)
 +                plugin_instance_format[i] = plginst_name;
 +            else if (strcasecmp (fields[i], "uuid") == 0)
 +                plugin_instance_format[i] = plginst_uuid;
 +            else {
 +                sfree (value_copy);
 +                ERROR (PLUGIN_NAME " plugin: unknown HostnameFormat field: %s", fields[i]);
 +                return -1;
 +            }
 +        }
 +        sfree (value_copy);
 +
 +        for (i = n; i < PLGINST_MAX_FIELDS; ++i)
 +            plugin_instance_format[i] = plginst_none;
 +
 +        return 0;
 +    }
 +
 +    if (strcasecmp (key, "InterfaceFormat") == 0) {
 +        if (strcasecmp (value, "name") == 0)
 +            interface_format = if_name;
 +        else if (strcasecmp (value, "address") == 0)
 +            interface_format = if_address;
 +        else if (strcasecmp (value, "number") == 0)
 +            interface_format = if_number;
 +        else {
 +            ERROR (PLUGIN_NAME " plugin: unknown InterfaceFormat: %s", value);
 +            return -1;
 +        }
 +        return 0;
 +    }
 +
 +    /* Unrecognised option. */
 +    return -1;
 +}
 +
 +static int
 +lv_read (void)
 +{
 +    time_t t;
 +    int i;
 +
 +    if (conn == NULL) {
 +        /* `conn_string == NULL' is acceptable. */
 +        conn = virConnectOpenReadOnly (conn_string);
 +        if (conn == NULL) {
 +            c_complain (LOG_ERR, &conn_complain,
 +                    PLUGIN_NAME " plugin: Unable to connect: "
 +                    "virConnectOpenReadOnly failed.");
 +            return -1;
 +        }
 +    }
 +    c_release (LOG_NOTICE, &conn_complain,
 +            PLUGIN_NAME " plugin: Connection established.");
 +
 +    time (&t);
 +
 +    /* Need to refresh domain or device lists? */
 +    if ((last_refresh == (time_t) 0) ||
 +            ((interval > 0) && ((last_refresh + interval) <= t))) {
 +        if (refresh_lists () != 0) {
 +            if (conn != NULL)
 +                virConnectClose (conn);
 +            conn = NULL;
 +            return -1;
 +        }
 +        last_refresh = t;
 +    }
 +
 +#if 0
 +    for (i = 0; i < nr_domains; ++i)
 +        fprintf (stderr, "domain %s\n", virDomainGetName (domains[i]));
 +    for (i = 0; i < nr_block_devices; ++i)
 +        fprintf  (stderr, "block device %d %s:%s\n",
 +                  i, virDomainGetName (block_devices[i].dom),
 +                  block_devices[i].path);
 +    for (i = 0; i < nr_interface_devices; ++i)
 +        fprintf (stderr, "interface device %d %s:%s\n",
 +                 i, virDomainGetName (interface_devices[i].dom),
 +                 interface_devices[i].path);
 +#endif
 +
 +    /* Get CPU usage, memory, VCPU usage for each domain. */
 +    for (i = 0; i < nr_domains; ++i) {
 +        virDomainInfo info;
 +        virVcpuInfoPtr vinfo = NULL;
 +        virDomainMemoryStatPtr minfo = NULL;
 +        int status;
 +        int j;
 +
 +        status = virDomainGetInfo (domains[i], &info);
 +        if (status != 0)
 +        {
 +            ERROR (PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
 +                    status);
 +            continue;
 +        }
 +
++        if (info.state != VIR_DOMAIN_RUNNING)
++        {
++            /* only gather stats for running domains */
++            continue;
++        }
++
 +        cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
 +        memory_submit ((gauge_t) info.memory * 1024, domains[i]);
 +
 +        vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
 +        if (vinfo == NULL) {
 +            ERROR (PLUGIN_NAME " plugin: malloc failed.");
 +            continue;
 +        }
 +
 +        status = virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
 +                /* cpu map = */ NULL, /* cpu map length = */ 0);
 +        if (status < 0)
 +        {
 +            ERROR (PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
 +                    status);
 +            sfree (vinfo);
 +            continue;
 +        }
 +
 +        for (j = 0; j < info.nrVirtCpu; ++j)
 +            vcpu_submit (vinfo[j].cpuTime,
 +                    domains[i], vinfo[j].number, "virt_vcpu");
 +
 +        sfree (vinfo);
 +
 +        minfo = malloc (VIR_DOMAIN_MEMORY_STAT_NR * sizeof (virDomainMemoryStatStruct));
 +        if (minfo == NULL) {
 +            ERROR ("virt plugin: malloc failed.");
 +            continue;
 +        }
 +
 +        status =  virDomainMemoryStats (domains[i], minfo, VIR_DOMAIN_MEMORY_STAT_NR, 0);
 +
 +        if (status < 0) {
 +            ERROR ("virt plugin: virDomainMemoryStats failed with status %i.",
 +                    status);
 +            sfree (minfo);
 +            continue;
 +        }
 +
 +        for (j = 0; j < status; j++) {
 +            memory_stats_submit ((gauge_t) minfo[j].val * 1024, domains[i], minfo[j].tag);
 +        }
 +
 +        sfree (minfo);
 +    }
 +
 +
 +    /* Get block device stats for each domain. */
 +    for (i = 0; i < nr_block_devices; ++i) {
 +        struct _virDomainBlockStats stats;
 +
 +        if (virDomainBlockStats (block_devices[i].dom, block_devices[i].path,
 +                    &stats, sizeof stats) != 0)
 +            continue;
 +
 +        if ((stats.rd_req != -1) && (stats.wr_req != -1))
 +            submit_derive2 ("disk_ops",
 +                    (derive_t) stats.rd_req, (derive_t) stats.wr_req,
 +                    block_devices[i].dom, block_devices[i].path);
 +
 +        if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
 +            submit_derive2 ("disk_octets",
 +                    (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
 +                    block_devices[i].dom, block_devices[i].path);
 +    } /* for (nr_block_devices) */
 +
 +    /* Get interface stats for each domain. */
 +    for (i = 0; i < nr_interface_devices; ++i) {
 +        struct _virDomainInterfaceStats stats;
 +        char *display_name = NULL;
 +
 +
 +        switch (interface_format) {
 +            case if_address:
 +                display_name = interface_devices[i].address;
 +                break;
 +            case if_number:
 +                display_name = interface_devices[i].number;
 +                break;
 +            case if_name:
 +            default:
 +                display_name = interface_devices[i].path;
 +        }
 +
 +        if (virDomainInterfaceStats (interface_devices[i].dom,
 +                    interface_devices[i].path,
 +                    &stats, sizeof stats) != 0)
 +            continue;
 +
 +      if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
 +          submit_derive2 ("if_octets",
 +                  (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
 +                  interface_devices[i].dom, display_name);
 +
 +      if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
 +          submit_derive2 ("if_packets",
 +                  (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
 +                  interface_devices[i].dom, display_name);
 +
 +      if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
 +          submit_derive2 ("if_errors",
 +                  (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
 +                  interface_devices[i].dom, display_name);
 +
 +      if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
 +          submit_derive2 ("if_dropped",
 +                  (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
 +                  interface_devices[i].dom, display_name);
 +    } /* for (nr_interface_devices) */
 +
 +    return 0;
 +}
 +
 +static int
 +refresh_lists (void)
 +{
 +    int n;
 +
 +    n = virConnectNumOfDomains (conn);
 +    if (n < 0) {
 +        VIRT_ERROR (conn, "reading number of domains");
 +        return -1;
 +    }
 +
 +    if (n > 0) {
 +        int i;
 +        int *domids;
 +
 +        /* Get list of domains. */
 +        domids = malloc (sizeof (int) * n);
 +        if (domids == 0) {
 +            ERROR (PLUGIN_NAME " plugin: malloc failed.");
 +            return -1;
 +        }
 +
 +        n = virConnectListDomains (conn, domids, n);
 +        if (n < 0) {
 +            VIRT_ERROR (conn, "reading list of domains");
 +            sfree (domids);
 +            return -1;
 +        }
 +
 +        free_block_devices ();
 +        free_interface_devices ();
 +        free_domains ();
 +
 +        /* Fetch each domain and add it to the list, unless ignore. */
 +        for (i = 0; i < n; ++i) {
 +            virDomainPtr dom = NULL;
 +            const char *name;
 +            char *xml = NULL;
 +            xmlDocPtr xml_doc = NULL;
 +            xmlXPathContextPtr xpath_ctx = NULL;
 +            xmlXPathObjectPtr xpath_obj = NULL;
 +            int j;
 +
 +            dom = virDomainLookupByID (conn, domids[i]);
 +            if (dom == NULL) {
 +                VIRT_ERROR (conn, "virDomainLookupByID");
 +                /* Could be that the domain went away -- ignore it anyway. */
 +                continue;
 +            }
 +
 +            name = virDomainGetName (dom);
 +            if (name == NULL) {
 +                VIRT_ERROR (conn, "virDomainGetName");
 +                goto cont;
 +            }
 +
 +            if (il_domains && ignorelist_match (il_domains, name) != 0)
 +                goto cont;
 +
 +            if (add_domain (dom) < 0) {
 +                ERROR (PLUGIN_NAME " plugin: malloc failed.");
 +                goto cont;
 +            }
 +
 +            /* Get a list of devices for this domain. */
 +            xml = virDomainGetXMLDesc (dom, 0);
 +            if (!xml) {
 +                VIRT_ERROR (conn, "virDomainGetXMLDesc");
 +                goto cont;
 +            }
 +
 +            /* Yuck, XML.  Parse out the devices. */
 +            xml_doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, XML_PARSE_NONET);
 +            if (xml_doc == NULL) {
 +                VIRT_ERROR (conn, "xmlReadDoc");
 +                goto cont;
 +            }
 +
 +            xpath_ctx = xmlXPathNewContext (xml_doc);
 +
 +            /* Block devices. */
 +            xpath_obj = xmlXPathEval
 +                ((xmlChar *) "/domain/devices/disk/target[@dev]",
 +                 xpath_ctx);
 +            if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
 +                xpath_obj->nodesetval == NULL)
 +                goto cont;
 +
 +            for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
 +                xmlNodePtr node;
 +                char *path = NULL;
 +
 +                node = xpath_obj->nodesetval->nodeTab[j];
 +                if (!node) continue;
 +                path = (char *) xmlGetProp (node, (xmlChar *) "dev");
 +                if (!path) continue;
 +
 +                if (il_block_devices &&
 +                    ignore_device_match (il_block_devices, name, path) != 0)
 +                    goto cont2;
 +
 +                add_block_device (dom, path);
 +            cont2:
 +                if (path) xmlFree (path);
 +            }
 +            xmlXPathFreeObject (xpath_obj);
 +
 +            /* Network interfaces. */
 +            xpath_obj = xmlXPathEval
 +                ((xmlChar *) "/domain/devices/interface[target[@dev]]",
 +                 xpath_ctx);
 +            if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
 +                xpath_obj->nodesetval == NULL)
 +                goto cont;
 +
 +            xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
 +
 +            for (j = 0; j < xml_interfaces->nodeNr; ++j) {
 +                char *path = NULL;
 +                char *address = NULL;
 +                xmlNodePtr xml_interface;
 +
 +                xml_interface = xml_interfaces->nodeTab[j];
 +                if (!xml_interface) continue;
 +                xmlNodePtr child = NULL;
 +
 +                for (child = xml_interface->children; child; child = child->next) {
 +                    if (child->type != XML_ELEMENT_NODE) continue;
 +
 +                    if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
 +                        path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
 +                        if (!path) continue;
 +                    } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
 +                        address = (char *) xmlGetProp (child, (const xmlChar *) "address");
 +                        if (!address) continue;
 +                    }
 +                }
 +
 +                if (il_interface_devices &&
 +                    (ignore_device_match (il_interface_devices, name, path) != 0 ||
 +                     ignore_device_match (il_interface_devices, name, address) != 0))
 +                    goto cont3;
 +
 +                add_interface_device (dom, path, address, j+1);
 +                cont3:
 +                    if (path) xmlFree (path);
 +                    if (address) xmlFree (address);
 +            }
 +
 +        cont:
 +            if (xpath_obj) xmlXPathFreeObject (xpath_obj);
 +            if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
 +            if (xml_doc) xmlFreeDoc (xml_doc);
 +            sfree (xml);
 +        }
 +
 +        sfree (domids);
 +    }
 +
 +    return 0;
 +}
 +
 +static void
 +free_domains ()
 +{
 +    int i;
 +
 +    if (domains) {
 +        for (i = 0; i < nr_domains; ++i)
 +            virDomainFree (domains[i]);
 +        sfree (domains);
 +    }
 +    domains = NULL;
 +    nr_domains = 0;
 +}
 +
 +static int
 +add_domain (virDomainPtr dom)
 +{
 +    virDomainPtr *new_ptr;
 +    int new_size = sizeof (domains[0]) * (nr_domains+1);
 +
 +    if (domains)
 +        new_ptr = realloc (domains, new_size);
 +    else
 +        new_ptr = malloc (new_size);
 +
 +    if (new_ptr == NULL)
 +        return -1;
 +
 +    domains = new_ptr;
 +    domains[nr_domains] = dom;
 +    return nr_domains++;
 +}
 +
 +static void
 +free_block_devices ()
 +{
 +    int i;
 +
 +    if (block_devices) {
 +        for (i = 0; i < nr_block_devices; ++i)
 +            sfree (block_devices[i].path);
 +        sfree (block_devices);
 +    }
 +    block_devices = NULL;
 +    nr_block_devices = 0;
 +}
 +
 +static int
 +add_block_device (virDomainPtr dom, const char *path)
 +{
 +    struct block_device *new_ptr;
 +    int new_size = sizeof (block_devices[0]) * (nr_block_devices+1);
 +    char *path_copy;
 +
 +    path_copy = strdup (path);
 +    if (!path_copy)
 +        return -1;
 +
 +    if (block_devices)
 +        new_ptr = realloc (block_devices, new_size);
 +    else
 +        new_ptr = malloc (new_size);
 +
 +    if (new_ptr == NULL) {
 +        sfree (path_copy);
 +        return -1;
 +    }
 +    block_devices = new_ptr;
 +    block_devices[nr_block_devices].dom = dom;
 +    block_devices[nr_block_devices].path = path_copy;
 +    return nr_block_devices++;
 +}
 +
 +static void
 +free_interface_devices ()
 +{
 +    int i;
 +
 +    if (interface_devices) {
 +        for (i = 0; i < nr_interface_devices; ++i) {
 +            sfree (interface_devices[i].path);
 +            sfree (interface_devices[i].address);
 +            sfree (interface_devices[i].number);
 +        }
 +        sfree (interface_devices);
 +    }
 +    interface_devices = NULL;
 +    nr_interface_devices = 0;
 +}
 +
 +static int
 +add_interface_device (virDomainPtr dom, const char *path, const char *address, unsigned int number)
 +{
 +    struct interface_device *new_ptr;
 +    int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
 +    char *path_copy, *address_copy, number_string[15];
 +
 +    path_copy = strdup (path);
 +    if (!path_copy) return -1;
 +
 +    address_copy = strdup (address);
 +    if (!address_copy) {
 +        sfree(path_copy);
 +        return -1;
 +    }
 +
 +    snprintf(number_string, sizeof (number_string), "interface-%u", number);
 +
 +    if (interface_devices)
 +        new_ptr = realloc (interface_devices, new_size);
 +    else
 +        new_ptr = malloc (new_size);
 +
 +    if (new_ptr == NULL) {
 +        sfree (path_copy);
 +        sfree (address_copy);
 +        return -1;
 +    }
 +    interface_devices = new_ptr;
 +    interface_devices[nr_interface_devices].dom = dom;
 +    interface_devices[nr_interface_devices].path = path_copy;
 +    interface_devices[nr_interface_devices].address = address_copy;
 +    interface_devices[nr_interface_devices].number = strdup(number_string);
 +    return nr_interface_devices++;
 +}
 +
 +static int
 +ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
 +{
 +    char *name;
 +    int n, r;
 +
 +    n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
 +    name = malloc (n);
 +    if (name == NULL) {
 +        ERROR (PLUGIN_NAME " plugin: malloc failed.");
 +        return 0;
 +    }
 +    ssnprintf (name, n, "%s:%s", domname, devpath);
 +    r = ignorelist_match (il, name);
 +    sfree (name);
 +    return r;
 +}
 +
 +static int
 +lv_shutdown (void)
 +{
 +    free_block_devices ();
 +    free_interface_devices ();
 +    free_domains ();
 +
 +    if (conn != NULL)
 +        virConnectClose (conn);
 +    conn = NULL;
 +
 +    ignorelist_free (il_domains);
 +    il_domains = NULL;
 +    ignorelist_free (il_block_devices);
 +    il_block_devices = NULL;
 +    ignorelist_free (il_interface_devices);
 +    il_interface_devices = NULL;
 +
 +    return 0;
 +}
 +
 +void
 +module_register (void)
 +{
 +    plugin_register_config (PLUGIN_NAME,
 +    lv_config,
 +    config_keys, NR_CONFIG_KEYS);
 +    plugin_register_init (PLUGIN_NAME, lv_init);
 +    plugin_register_read (PLUGIN_NAME, lv_read);
 +    plugin_register_shutdown (PLUGIN_NAME, lv_shutdown);
 +}
 +
 +/*
 + * vim: shiftwidth=4 tabstop=8 softtabstop=4 expandtab fdm=marker
 + */