Merge branch 'collectd-5.8' into master
authorPavel Rochnyack <pavel2000@ngs.ru>
Fri, 26 Oct 2018 17:29:52 +0000 (00:29 +0700)
committerPavel Rochnyack <pavel2000@ngs.ru>
Fri, 26 Oct 2018 17:29:52 +0000 (00:29 +0700)
Conflicts:
src/disk.c
src/virt.c

1  2 
configure.ac
src/disk.c
src/exec.c
src/ntpd.c
src/powerdns.c
src/utils_mount.c
src/virt.c
src/zfs_arc.c

diff --combined configure.ac
@@@ -99,10 -99,6 +99,10 @@@ case $host_os i
      AC_DEFINE([KERNEL_SOLARIS], [1], [True if program is to be compiled for a Solaris kernel])
      ac_system="Solaris"
      ;;
 +  *mingw32*)
 +    AC_DEFINE([KERNEL_WIN32], [1], [True if program is to be compiled for a Windows kernel])
 +    ac_system="Windows"
 +    ;;
    *)
      ac_system="unknown"
      ;;
@@@ -115,7 -111,6 +115,7 @@@ AM_CONDITIONAL([BUILD_FREEBSD], [test "
  AM_CONDITIONAL([BUILD_LINUX], [test "x$ac_system" = "xLinux"])
  AM_CONDITIONAL([BUILD_OPENBSD], [test "x$ac_system" = "xOpenBSD"])
  AM_CONDITIONAL([BUILD_SOLARIS], [test "x$ac_system" = "xSolaris"])
 +AM_CONDITIONAL([BUILD_WIN32], [test "x$ac_system" = "xWindows"])
  
  if test "x$ac_system" = "xSolaris"; then
    AC_DEFINE([_POSIX_PTHREAD_SEMANTICS], [1], [Define to enforce POSIX thread semantics under Solaris.])
@@@ -555,12 -550,6 +555,12 @@@ if test "x$ac_system" = "xLinux"; the
      AC_DEFINE([HAVE_CAPABILITY], [1], [Define to 1 if you have cap_get_proc() (-lcap).])
    fi
  
 +  # For pcie_errors plugin
 +  AC_CHECK_HEADERS([linux/pci_regs.h],
 +    [have_pci_regs_h="yes"],
 +    [have_pci_regs_h="no (linux/pci_regs.h not found)"]
 +  )
 +
  else
    have_linux_raid_md_u_h="no"
    have_linux_wireless_h="no"
@@@ -756,7 -745,6 +756,7 @@@ AC_CHECK_FUNCS_ONCE([ 
      getaddrinfo \
      getgrnam_r \
      getnameinfo \
 +    getpwnam \
      getpwnam_r \
      gettimeofday \
      if_indextoname \
  AC_FUNC_STRERROR_R
  
  SAVE_CFLAGS="$CFLAGS"
 -# Emulate behavior of src/Makefile.am
 -if test "x$GCC" = "xyes"; then
 -  CFLAGS="$CFLAGS -Wall -Werror"
 +CFLAGS="-Wall -Werror"
 +SAVE_LDFLAGS="$LDFLAGS"
 +LDFLAGS=""
 +if test "x$ac_system" = "xWindows"; then
 +  # This is exported from build.sh
 +  LDFLAGS="$LDFLAGS -L${GNULIB_DIR}"
  fi
  
  AC_CACHE_CHECK([for strtok_r],
@@@ -857,7 -842,6 +857,7 @@@ if test "x$c_cv_have_strtok_r_default" 
  fi
  
  CFLAGS="$SAVE_CFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
  if test "x$c_cv_have_strtok_r_reentrant" = "xyes"; then
    CFLAGS="$CFLAGS -D_REENTRANT=1"
  fi
@@@ -867,17 -851,11 +867,17 @@@ AC_CHECK_FUNCS([socket]
    [
      AC_CHECK_LIB([socket], [socket],
        [socket_needs_socket="yes"],
 -      [AC_MSG_ERROR([cannot find socket() in libsocket])]
 +      [
 +        AC_CHECK_LIB([gnu], [rpl_socket],
 +          [socket_needs_gnulib="yes"],
 +          [AC_MSG_ERROR([cannot find socket() in libsocket])]
 +        )
 +      ]
      )
    ]
  )
  AM_CONDITIONAL([BUILD_WITH_LIBSOCKET], [test "x$socket_needs_socket" = "xyes"])
 +AM_CONDITIONAL([BUILD_WITH_GNULIB], [test "x$socket_needs_gnulib" = "xyes"])
  
  clock_gettime_needs_posix4="no"
  AC_CHECK_FUNCS([clock_gettime],
@@@ -1589,7 -1567,7 +1589,7 @@@ if test "x$have_getmntent" = "xlibc"; t
                struct mntent *me;
                fh = setmntent ("/etc/mtab", "r");
                me = getmntent (fh);
 -              return(me->mnt_passno);
 +              return me->mnt_passno;
              ]]
            )
          ],
                int status;
                fh = fopen ("/etc/mnttab", "r");
                status = getmntent (fh, &mt);
 -              return(status);
 +              return status;
              ]]
            )
          ],
  
  # libi2c-dev
  if test "x$ac_system" = "xLinux"; then
 +  with_libi2c_libs=""
 +  AC_CHECK_HEADERS([i2c/smbus.h],
 +    [with_libi2c_libs="-li2c"]
 +  )
    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>
 +      #if HAVE_I2C_SMBUS_H
 +      # include <i2c/smbus.h>
 +      #endif
      ]]
    )
 +  BUILD_WITH_LIBI2C_LIBS="$with_libi2c_libs"
 +  AC_SUBST([BUILD_WITH_LIBI2C_LIBS])
  else
    with_libi2c="no (Linux only)"
  fi
  
  AC_SUBST(BUILD_WITH_LIBCURL_CFLAGS)
  AC_SUBST(BUILD_WITH_LIBCURL_LIBS)
 +
 +AM_CONDITIONAL([BUILD_WITH_LIBCURL], [test "x$with_libcurl" = "xyes"])
  # }}}
  
  # --with-libdbi {{{
@@@ -2668,7 -2635,6 +2668,7 @@@ AC_ARG_WITH([libgrpc++]
      if test "x$withval" != "xno" && test "x$withval" != "xyes"; then
        with_libgrpcpp_cppflags="-I$withval/include"
        with_libgrpcpp_ldflags="-L$withval/lib"
 +      with_libgrpcpp_bin="$withval/bin"
        with_libgrpcpp="yes"
      fi
      if test "x$withval" = "xno"; then
@@@ -2748,11 -2714,7 +2748,11 @@@ AC_SUBST([BUILD_WITH_LIBGRPCPP_LIBS]
  # }}}
  
  AC_ARG_VAR([GRPC_CPP_PLUGIN], [path to the grpc_cpp_plugin binary])
 -AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin])
 +if test "x$with_libgrpcpp_bin" = "x"; then
 +  AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin])
 +else
 +  AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin], [], "$with_libgrpcpp_bin:$PATH")
 +fi
  AM_CONDITIONAL([HAVE_GRPC_CPP], [test "x$GRPC_CPP_PLUGIN" != "x"])
  
  # --with-libiptc {{{
            PKG_CHECK_MODULES([LUA], [lua5.3],
              [with_liblua="yes"],
              [
 -              PKG_CHECK_MODULES([LUA], [lua-5.2],
 +              PKG_CHECK_MODULES([LUA], [lua53],
                  [with_liblua="yes"],
                  [
 -                  PKG_CHECK_MODULES([LUA], [lua5.2],
 +                  PKG_CHECK_MODULES([LUA], [lua-5.2],
                      [with_liblua="yes"],
                      [
 -                      PKG_CHECK_MODULES([LUA], [lua-5.1],
 +                      PKG_CHECK_MODULES([LUA], [lua5.2],
                          [with_liblua="yes"],
                          [
 -                          PKG_CHECK_MODULES([LUA], [lua5.1],
 +                          PKG_CHECK_MODULES([LUA], [lua52],
                              [with_liblua="yes"],
 -                            [with_liblua="no (pkg-config cannot find liblua)"]
 +                            [
 +                              PKG_CHECK_MODULES([LUA], [lua-5.1],
 +                                [with_liblua="yes"],
 +                                [
 +                                  PKG_CHECK_MODULES([LUA], [lua5.1],
 +                                    [with_liblua="yes"],
 +                                    [
 +                                      PKG_CHECK_MODULES([LUA], [lua51],
 +                                        [with_liblua="yes"],
 +                                        [with_liblua="no (pkg-config cannot find liblua)"]
 +                                      )
 +                                    ]
 +                                  )
 +                                ]
 +                              )
 +                            ]
                            )
                          ]
                        )
@@@ -3708,18 -3655,6 +3708,18 @@@ if test "x$with_libmnl" = "xyes"; the
      [[#include <linux/if_link.h>]]
    )
  
 +  AC_CHECK_MEMBERS([struct rtnl_link_stats.rx_nohandler],
 +    [],
 +    [],
 +    [[#include <linux/if_link.h>]]
 +  )
 +
 +  AC_CHECK_MEMBERS([struct rtnl_link_stats64.rx_nohandler],
 +    [],
 +    [],
 +    [[#include <linux/if_link.h>]]
 +  )
 +
    AC_CHECK_LIB([mnl], [mnl_nlmsg_get_payload],
      [with_libmnl="yes"],
      [with_libmnl="no (symbol 'mnl_nlmsg_get_payload' not found)"],
@@@ -3733,7 -3668,6 +3733,7 @@@ if test "x$with_libmnl" = "xyes"; the
  fi
  AC_SUBST([BUILD_WITH_LIBMNL_CFLAGS])
  AC_SUBST([BUILD_WITH_LIBMNL_LIBS])
 +AM_CONDITIONAL([HAVE_LIBMNL], [test "x$with_libmnl" = "xyes"])
  # }}}
  
  # --with-libnetapp {{{
@@@ -3841,7 -3775,7 +3841,7 @@@ if test "x$with_libnetsnmp" = "xyes"; t
    LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
  
    AC_CHECK_LIB([netsnmp], [init_snmp],
 -    [with_libnetsmp="yes"],
 +    [with_libnetsnmp="yes"],
      [with_libnetsnmp="no (libnetsnmp not found)"]
    )
  
  fi
  
  if test "x$with_libnetsnmp" = "xyes"; then
 +  SAVE_LDFLAGS="$LDFLAGS"
 +  LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
 +
 +  AC_CHECK_LIB([netsnmp], [netsnmp_get_version],
 +    [with_libnetsnmp="yes"],
 +    [with_libnetsnmp="no (couldn't get libnetsnmp version)"]
 +  )
 +
 +  LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +
 +if test "x$with_libnetsnmp" = "xyes"; then
 +  SAVE_CPPFLAGS="$CPPFLAGS"
 +  SAVE_LDFLAGS="$LDFLAGS"
 +  SAVE_LIBS="$LIBS"
 +  CPPFLAGS="$CPPFLAGS $with_libnetsnmp_cppflags -Wall -Werror"
 +  LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
 +  LIBS="$LIBS -lnetsnmp"
 +
 +  AC_CACHE_CHECK([whether netsnmp library has old API],
 +    [c_cv_have_netsnmp_old_api],
 +    [
 +      AC_LINK_IFELSE(
 +        [
 +          AC_LANG_PROGRAM(
 +            [[
 +              #include <net-snmp/net-snmp-config.h>
 +              #include <net-snmp/net-snmp-includes.h>
 +            ]],
 +            [[
 +              netsnmp_variable_list *key = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);;
 +              int val;
 +              u_char type = ASN_INTEGER;
 +              snmp_set_var_value(key, &val, sizeof(val));
 +              snmp_set_var_typed_value(key, type, &val, sizeof(val));
 +              return 0;
 +            ]]
 +          )
 +        ],
 +        [c_cv_have_netsnmp_old_api="no"],
 +        [c_cv_have_netsnmp_old_api="yes"]
 +      )
 +    ]
 +  )
 +
 +  if test "x$c_cv_have_netsnmp_old_api" = "xyes"; then
 +    AC_DEFINE([HAVE_NETSNMP_OLD_API], [1],
 +              ["Define 1 if you have old netsnmp API]")
 +  fi
 +
 +  CPPFLAGS="$SAVE_CPPFLAGS"
 +  LDFLAGS="$SAVE_LDFLAGS"
 +  LIBS="$SAVE_LIBS"
 +fi
 +
 +if test "x$with_libnetsnmp" = "xyes"; then
    BUILD_WITH_LIBNETSNMP_CPPFLAGS="$with_libnetsnmp_cppflags"
    BUILD_WITH_LIBNETSNMP_LDFLAGS="$with_libnetsnmp_ldflags"
    BUILD_WITH_LIBNETSNMP_LIBS="-lnetsnmp"
@@@ -3915,7 -3793,7 +3915,7 @@@ AC_SUBST([BUILD_WITH_LIBNETSNMP_LDFLAGS
  AC_SUBST([BUILD_WITH_LIBNETSNMP_LIBS])
  # }}}
  
 -# --with-libnetsmpagent {{{
 +# --with-libnetsnmpagent {{{
  AC_ARG_WITH([libnetsnmpagent],
    [AS_HELP_STRING([--with-libnetsnmpagent@<:@=PREFIX@:>@], [Path to libnetsnmpagent.])],
    [
@@@ -4197,7 -4075,7 +4197,7 @@@ if test "x$with_libpcap" = "xyes"; the
              [[#include <pcap.h>]],
              [[
                int val = PCAP_ERROR_IFACE_NOT_UP;
 -              return(val);
 +              return val;
              ]]
            )
          ],
@@@ -4802,56 -4680,6 +4802,56 @@@ if test "$with_libpython" != "xno"; the
  fi
  # }}} --with-libpython
  
 +# --with-libqpid_proton {{{
 +AC_ARG_WITH([libqpid_proton],
 +  [AS_HELP_STRING([--with-libqpid_proton@<:@=PREFIX@:>@], [Path to libqpid_proton.])],
 +  [
 +    if test "x$withval" != "xno" && test "x$withval" != "xyes"; then
 +      with_libqpid_proton_cppflags="-I$withval/include"
 +      with_libqpid_proton_ldflags="-L$withval/lib"
 +      with_libqpid_proton="yes"
 +    else
 +      with_libqpid_proton="$withval"
 +    fi
 +  ],
 +  [with_libqpid_proton="yes"]
 +)
 +
 +if test "x$with_libqpid_proton" = "xyes"; then
 +  SAVE_CPPFLAGS="$CPPFLAGS"
 +  CPPFLAGS="$CPPFLAGS $with_libqpid_proton_cppflags"
 +
 +  AC_CHECK_HEADERS([proton/proactor.h],
 +    [with_libqpid_proton="yes"],
 +    [with_libqpid_proton="no (proton/proactor.h not found)"]
 +  )
 +
 +  CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +
 +if test "x$with_libqpid_proton" = "xyes"; then
 +  SAVE_LDFLAGS="$LDFLAGS"
 +  LDFLAGS="$LDFLAGS $with_libqpid_proton_ldflags"
 +
 +  AC_CHECK_LIB([qpid-proton], [pn_connection],
 +    [with_libqpid_proton="yes"],
 +    [with_libqpid_proton="no (Symbol 'pn_connection' not found)"])
 +
 +  LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +
 +if test "x$with_libqpid_proton" = "xyes"; then
 +  BUILD_WITH_LIBQPIDPROTON_CPPFLAGS="$with_libqpid_proton_cppflags"
 +  BUILD_WITH_LIBQPIDPROTON_LDFLAGS="$with_libqpid_proton_ldflags"
 +  BUILD_WITH_LIBQPIDPROTON_LIBS="-lqpid-proton"
 +fi
 +
 +AC_SUBST(BUILD_WITH_LIBQPIDPROTON_CPPFLAGS)
 +AC_SUBST(BUILD_WITH_LIBQPIDPROTON_LDFLAGS)
 +AC_SUBST(BUILD_WITH_LIBQPIDPROTON_LIBS)
 +
 +# }}}
 +
  # --with-librabbitmq {{{
  AC_ARG_WITH([librabbitmq],
    [AS_HELP_STRING([--with-librabbitmq@<:@=PREFIX@:>@], [Path to librabbitmq.])],
@@@ -5236,55 -5064,6 +5236,55 @@@ PKG_CHECK_MODULES([LIBSIGROK], [libsigr
  )
  # }}}
  
 +# --with-libssl {{{
 +with_libssl_cflags=""
 +with_libssl_ldflags=""
 +AC_ARG_WITH([libssl], [AS_HELP_STRING([--with-libssl@<:@=PREFIX@:>@], [Path to libssl.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"; then
 +              with_libssl_cppflags="-I$withval/include"
 +              with_libssl_ldflags="-L$withval/lib"
 +              with_libssl="yes"
 +      else
 +              with_libssl="$withval"
 +      fi
 +],
 +[
 +      with_libssl="yes"
 +])
 +if test "x$with_libssl" = "xyes"; then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libssl_cppflags"
 +
 +  AC_CHECK_HEADERS([openssl/sha.h openssl/blowfish.h openssl/rand.h],
 +    [with_libssl="yes"],
 +    [with_libssl="no (ssl header not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libssl" = "xyes"; then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libssl_cppflags"
 +      LDFLAGS="$LDFLAGS $with_libssl_ldflags"
 +
 +      AC_CHECK_LIB([ssl], [OPENSSL_init_ssl], [with_libssl="yes"], [with_libssl="no (Symbol 'SSL_library_init' not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libssl" = "xyes"; then
 +      BUILD_WITH_LIBSSL_CFLAGS="$with_libssl_cflags"
 +      BUILD_WITH_LIBSSL_LDFLAGS="$with_libssl_ldflags"
 +      BUILD_WITH_LIBSSL_LIBS="-lssl -lcrypto"
 +      AC_SUBST([BUILD_WITH_LIBSSL_CFLAGS])
 +      AC_SUBST([BUILD_WITH_LIBSSL_LDFLAGS])
 +      AC_SUBST([BUILD_WITH_LIBSSL_LIBS])
 +      AC_DEFINE([HAVE_LIBSSL], [1], [Define if libssl is present and usable.])
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBSSL, test "x$with_libssl" = "xyes")
 +# }}}
 +
  # --with-libstatgrab {{{
  AC_ARG_WITH([libstatgrab],
    [AS_HELP_STRING([--with-libstatgrab@<:@=PREFIX@:>@], [Path to libstatgrab.])],
@@@ -5745,15 -5524,15 +5745,15 @@@ if test "x$with_libxmms" = "xyes"; the
  fi
  
  if test "x$with_libxmms" = "xyes"; then
-   SAVE_CFLAGS="$CFLAGS"
-   CFLAGS="$with_xmms_cflags"
+   SAVE_CPPFLAGS="$CFLAGS"
+   CPPFLAGS="$with_xmms_cflags"
  
    AC_CHECK_HEADER([xmmsctrl.h],
      [with_libxmms="yes"],
      [with_libxmms="no"],
    )
  
-   CFLAGS="$SAVE_CFLAGS"
+   CPPFLAGS="$SAVE_CPPFLAGS"
  fi
  
  if test "x$with_libxmms" = "xyes"; then
@@@ -5840,7 -5619,6 +5840,7 @@@ AC_SUBST([BUILD_WITH_LIBYAJL_LDFLAGS]
  AC_SUBST([BUILD_WITH_LIBYAJL_LIBS])
  
  AM_CONDITIONAL([BUILD_WITH_LIBYAJL], [test "x$with_libyajl" = "xyes"])
 +AM_CONDITIONAL([BUILD_WITH_LIBYAJL2], [test "x$with_libyajl$with_libyajl2" = "xyesyes"])
  # }}}
  
  # --with-mic {{{
@@@ -5972,41 -5750,32 +5972,41 @@@ AC_SUBST([BUILD_WITH_LIBVARNISH_CFLAGS]
  AC_SUBST([BUILD_WITH_LIBVARNISH_LIBS])
  # }}}
  
 -# pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
 -$PKG_CONFIG --exists 'libxml-2.0' 2>/dev/null
 -if test $? -eq 0; then
 -  with_libxml2="yes"
 -else
 -  with_libxml2="no (pkg-config doesn't know libxml-2.0)"
 -fi
 -
 -$PKG_CONFIG --exists libvirt 2>/dev/null
 -if test $? = 0; then
 -  with_libvirt="yes"
 -else
 -  with_libvirt="no (pkg-config doesn't know libvirt)"
 -fi
 -
 -if test "x$with_libxml2" = "xyes"; then
 -  with_libxml2_cflags="`$PKG_CONFIG --cflags libxml-2.0`"
 -  if test $? -ne 0; then
 -    with_libxml2="no"
 -  fi
 -
 -  with_libxml2_ldflags="`$PKG_CONFIG --libs libxml-2.0`"
 -  if test $? -ne 0; then
 -    with_libxml2="no"
 -  fi
 -fi
 +# --with-libxml2 {{{
 +AC_ARG_WITH(libxml2,
 +  [AS_HELP_STRING([--with-libxml2@<:@=PREFIX@:>@], [Path to libxml2.])],
 +  [
 +    if test "x$withval" = "xno"; then
 +      with_libxml2="no"
 +    else if test "x$withval" = "xyes"; then
 +      $PKG_CONFIG --exists 'libxml-2.0' 2>/dev/null
 +      if test $? -eq 0; then
 +        with_libxml2="yes"
 +        with_libxml2_cflags="`$PKG_CONFIG --cflags libxml-2.0`"
 +        with_libxml2_ldflags="`$PKG_CONFIG --libs libxml-2.0`"
 +      else
 +        with_libxml2="no (pkg-config doesn't know libxml-2.0)"
 +      fi
 +    else
 +      with_libxml2="yes"
 +      with_libxml2_cflags="-I$withval/include"
 +      with_libxml2_ldflags="-L$withval/lib"
 +    fi; fi
 +  ],
 +  dnl  if no argument --with-libxml2 was passed, find the library locations
 +  dnl  with pkg-config just like above, when --with-libxml2=yes.
 +  [
 +    with_libxml2="yes"
 +    $PKG_CONFIG --exists 'libxml-2.0' 2>/dev/null
 +    if test $? -eq 0; then
 +      with_libxml2="yes"
 +      with_libxml2_cflags="`$PKG_CONFIG --cflags libxml-2.0`"
 +      with_libxml2_ldflags="`$PKG_CONFIG --libs libxml-2.0`"
 +    else
 +      with_libxml2="no (pkg-config doesn't know libxml-2.0)"
 +    fi
 +  ]
 +)
  
  if test "x$with_libxml2" = "xyes"; then
    SAVE_CPPFLAGS="$CPPFLAGS"
  
  AC_SUBST([BUILD_WITH_LIBXML2_CFLAGS])
  AC_SUBST([BUILD_WITH_LIBXML2_LIBS])
 +# }}}
 +
 +# pkg-config --exists libvirt {{{
 +$PKG_CONFIG --exists libvirt 2>/dev/null
 +if test $? = 0; then
 +  with_libvirt="yes"
 +else
 +  with_libvirt="no (pkg-config doesn't know libvirt)"
 +fi
  
  if test "x$with_libvirt" = "xyes"; then
    with_libvirt_cflags="`$PKG_CONFIG --cflags libvirt`"
@@@ -6380,7 -6140,6 +6380,7 @@@ plugin_nfs="no
  plugin_numa="no"
  plugin_ovs_events="no"
  plugin_ovs_stats="no"
 +plugin_pcie_errors="no"
  plugin_perl="no"
  plugin_pinba="no"
  plugin_processes="no"
@@@ -6402,7 -6161,6 +6402,7 @@@ plugin_vmem="no
  plugin_vserver="no"
  plugin_wireless="no"
  plugin_write_prometheus="no"
 +plugin_write_stackdriver="no"
  plugin_xencpu="no"
  plugin_zfs_arc="no"
  plugin_zone="no"
@@@ -6460,10 -6218,6 +6460,10 @@@ if test "x$ac_system" = "xLinux"; the
      plugin_ovs_events="yes"
      plugin_ovs_stats="yes"
    fi
 +
 +  if test "x$have_pci_regs_h" = "xyes"; then
 +    plugin_pcie_errors="yes"
 +  fi
  fi
  
  if test "x$ac_system" = "xOpenBSD"; then
@@@ -6561,10 -6315,6 +6561,10 @@@ if test "x$with_libcurl" = "xyes" && te
    plugin_curl_json="yes"
  fi
  
 +if test "x$with_libcurl" = "xyes" && test "x$with_libssl" = "xyes" && test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then
 +  plugin_write_stackdriver="yes"
 +fi
 +
  if test "x$with_libcurl" = "xyes" && test "x$with_libxml2" = "xyes"; then
    plugin_curl_xml="yes"
  fi
@@@ -6628,18 -6378,8 +6628,18 @@@ if test "x$with_libgps" = "xyes"; the
    plugin_gps="yes"
  fi
  
 -if test "x$with_libgrpcpp" = "xyes" && test "x$with_libprotobuf" = "xyes" && test "x$have_protoc3" = "xyes" && test "x$GRPC_CPP_PLUGIN" != "x"; then
 -  plugin_grpc="yes"
 +plugin_grpc="yes"
 +if test "x$GRPC_CPP_PLUGIN" = "x"; then
 +  plugin_grpc="no (grpc_cpp_plugin not found)"
 +fi
 +if test "x$have_protoc3" != "xyes"; then
 +  plugin_grpc="no (protoc3 not found)"
 +fi
 +if test "x$with_libprotobuf" != "xyes"; then
 +  plugin_grpc="no (libprotobuf not found)"
 +fi
 +if test "x$with_libgrpcpp" != "xyes"; then
 +  plugin_grpc="no (libgrpc++ not found)"
  fi
  
  if test "x$have_getifaddrs" = "xyes"; then
@@@ -6753,164 -6493,161 +6753,164 @@@ AC_ARG_ENABLE([all-plugins]
  
  m4_divert_once([HELP_ENABLE], [])
  
 -AC_PLUGIN([aggregation],         [yes],                     [Aggregation plugin])
 -AC_PLUGIN([amqp],                [$with_librabbitmq],       [AMQP output plugin])
 -AC_PLUGIN([apache],              [$with_libcurl],           [Apache httpd statistics])
 -AC_PLUGIN([apcups],              [yes],                     [Statistics of UPSes by APC])
 -AC_PLUGIN([apple_sensors],       [$with_libiokit],          [Apple hardware sensors])
 -AC_PLUGIN([aquaero],             [$with_libaquaero5],       [Aquaero 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([ceph],                [$plugin_ceph],            [Ceph daemon statistics])
 -AC_PLUGIN([cgroups],             [$plugin_cgroups],         [CGroups CPU usage accounting])
 -AC_PLUGIN([chrony],              [yes],                     [Chrony statistics])
 -AC_PLUGIN([conntrack],           [$plugin_conntrack],       [nf_conntrack statistics])
 -AC_PLUGIN([contextswitch],       [$plugin_contextswitch],   [context switch statistics])
 -AC_PLUGIN([cpu],                 [$plugin_cpu],             [CPU usage statistics])
 -AC_PLUGIN([cpufreq],             [$plugin_cpufreq],         [CPU frequency statistics])
 -AC_PLUGIN([cpusleep],            [$plugin_cpusleep],        [CPU sleep statistics])
 -AC_PLUGIN([csv],                 [yes],                     [CSV output plugin])
 -AC_PLUGIN([curl],                [$with_libcurl],           [CURL generic web statistics])
 -AC_PLUGIN([curl_json],           [$plugin_curl_json],       [CouchDB statistics])
 -AC_PLUGIN([curl_xml],            [$plugin_curl_xml],        [CURL generic xml statistics])
 -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([dns],                 [$with_libpcap],           [DNS traffic analysis])
 -AC_PLUGIN([dpdkevents],          [$plugin_dpdkevents],      [Events from DPDK])
 -AC_PLUGIN([dpdkstat],            [$plugin_dpdkstat],        [Stats from DPDK])
 -AC_PLUGIN([drbd],                [$plugin_drbd],            [DRBD statistics])
 -AC_PLUGIN([email],               [yes],                     [EMail statistics])
 -AC_PLUGIN([entropy],             [$plugin_entropy],         [Entropy statistics])
 -AC_PLUGIN([ethstat],             [$plugin_ethstat],         [Stats from NIC driver])
 -AC_PLUGIN([exec],                [yes],                     [Execution of external programs])
 -AC_PLUGIN([fhcount],             [$plugin_fhcount],         [File handles statistics])
 -AC_PLUGIN([filecount],           [yes],                     [Count files in directories])
 -AC_PLUGIN([fscache],             [$plugin_fscache],         [fscache statistics])
 -AC_PLUGIN([gmond],               [$with_libganglia],        [Ganglia plugin])
 -AC_PLUGIN([gps],                 [$plugin_gps],             [GPS plugin])
 -AC_PLUGIN([grpc],                [$plugin_grpc],            [gRPC plugin])
 -AC_PLUGIN([hddtemp],             [yes],                     [Query hddtempd])
 -AC_PLUGIN([hugepages],           [$plugin_hugepages],       [Hugepages statistics])
 -AC_PLUGIN([intel_pmu],           [$with_libjevents],        [Intel performance monitor plugin])
 -AC_PLUGIN([intel_rdt],           [$with_libpqos],           [Intel RDT monitor plugin])
 -AC_PLUGIN([interface],           [$plugin_interface],       [Interface traffic statistics])
 -AC_PLUGIN([ipc],                 [$plugin_ipc],             [IPC statistics])
 -AC_PLUGIN([ipmi],                [$plugin_ipmi],            [IPMI sensor statistics])
 -AC_PLUGIN([iptables],            [$with_libiptc],           [IPTables rule counters])
 -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([load],                [$plugin_load],            [System load])
 -AC_PLUGIN([log_logstash],        [$plugin_log_logstash],    [Logstash json_event compatible logging])
 -AC_PLUGIN([logfile],             [yes],                     [File logging plugin])
 -AC_PLUGIN([lpar],                [$with_perfstat],          [AIX logical partitions statistics])
 -AC_PLUGIN([lua],                 [$with_liblua],            [Lua plugin])
 -AC_PLUGIN([lvm],                 [$with_liblvm2app],        [LVM statistics])
 -AC_PLUGIN([madwifi],             [$have_linux_wireless_h],  [Madwifi wireless statistics])
 -AC_PLUGIN([match_empty_counter], [yes],                     [The empty counter match])
 -AC_PLUGIN([match_hashed],        [yes],                     [The hashed match])
 -AC_PLUGIN([match_regex],         [yes],                     [The regex match])
 -AC_PLUGIN([match_timediff],      [yes],                     [The timediff match])
 -AC_PLUGIN([match_value],         [yes],                     [The value match])
 -AC_PLUGIN([mbmon],               [yes],                     [Query mbmond])
 -AC_PLUGIN([mcelog],              [$plugin_mcelog],          [Machine Check Exceptions notifications])
 -AC_PLUGIN([md],                  [$have_linux_raid_md_u_h], [md (Linux software RAID) devices])
 -AC_PLUGIN([memcachec],           [$with_libmemcached],      [memcachec statistics])
 -AC_PLUGIN([memcached],           [yes],                     [memcached statistics])
 -AC_PLUGIN([memory],              [$plugin_memory],          [Memory usage])
 -AC_PLUGIN([mic],                 [$with_mic],               [Intel Many Integrated Core stats])
 -AC_PLUGIN([modbus],              [$with_libmodbus],         [Modbus plugin])
 -AC_PLUGIN([mqtt],                [$with_libmosquitto],      [MQTT output plugin])
 -AC_PLUGIN([multimeter],          [$plugin_multimeter],      [Read multimeter values])
 -AC_PLUGIN([mysql],               [$with_libmysql],          [MySQL statistics])
 -AC_PLUGIN([netapp],              [$with_libnetapp],         [NetApp plugin])
 -AC_PLUGIN([netlink],             [$with_libmnl],            [Enhanced Linux network statistics])
 -AC_PLUGIN([network],             [yes],                     [Network communication plugin])
 -AC_PLUGIN([nfs],                 [$plugin_nfs],             [NFS statistics])
 -AC_PLUGIN([nginx],               [$with_libcurl],           [nginx statistics])
 -AC_PLUGIN([notify_desktop],      [$with_libnotify],         [Desktop notifications])
 -AC_PLUGIN([notify_email],        [$with_libesmtp],          [Email notifier])
 -AC_PLUGIN([notify_nagios],       [yes],                     [Nagios notification plugin])
 -AC_PLUGIN([ntpd],                [yes],                     [NTPd statistics])
 -AC_PLUGIN([numa],                [$plugin_numa],            [NUMA virtual memory statistics])
 -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([ovs_events],          [$plugin_ovs_events],      [OVS events plugin])
 -AC_PLUGIN([ovs_stats],           [$plugin_ovs_stats],       [OVS statistics plugin])
 -AC_PLUGIN([perl],                [$plugin_perl],            [Embed a Perl interpreter])
 -AC_PLUGIN([pf],                  [$have_net_pfvar_h],       [BSD packet filter (PF) statistics])
 +AC_PLUGIN([aggregation],         [yes],                       [Aggregation plugin])
 +AC_PLUGIN([amqp],                [$with_librabbitmq],         [AMQP output plugin])
 +AC_PLUGIN([amqp1],               [$with_libqpid_proton],      [AMQP 1.0 output plugin])
 +AC_PLUGIN([apache],              [$with_libcurl],             [Apache httpd statistics])
 +AC_PLUGIN([apcups],              [yes],                       [Statistics of UPSes by APC])
 +AC_PLUGIN([apple_sensors],       [$with_libiokit],            [Apple hardware sensors])
 +AC_PLUGIN([aquaero],             [$with_libaquaero5],         [Aquaero 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([ceph],                [$plugin_ceph],              [Ceph daemon statistics])
 +AC_PLUGIN([cgroups],             [$plugin_cgroups],           [CGroups CPU usage accounting])
 +AC_PLUGIN([chrony],              [yes],                       [Chrony statistics])
 +AC_PLUGIN([conntrack],           [$plugin_conntrack],         [nf_conntrack statistics])
 +AC_PLUGIN([contextswitch],       [$plugin_contextswitch],     [context switch statistics])
 +AC_PLUGIN([cpu],                 [$plugin_cpu],               [CPU usage statistics])
 +AC_PLUGIN([cpufreq],             [$plugin_cpufreq],           [CPU frequency statistics])
 +AC_PLUGIN([cpusleep],            [$plugin_cpusleep],          [CPU sleep statistics])
 +AC_PLUGIN([csv],                 [yes],                       [CSV output plugin])
 +AC_PLUGIN([curl],                [$with_libcurl],             [CURL generic web statistics])
 +AC_PLUGIN([curl_json],           [$plugin_curl_json],         [CouchDB statistics])
 +AC_PLUGIN([curl_xml],            [$plugin_curl_xml],          [CURL generic xml statistics])
 +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([dns],                 [$with_libpcap],             [DNS traffic analysis])
 +AC_PLUGIN([dpdkevents],          [$plugin_dpdkevents],        [Events from DPDK])
 +AC_PLUGIN([dpdkstat],            [$plugin_dpdkstat],          [Stats from DPDK])
 +AC_PLUGIN([drbd],                [$plugin_drbd],              [DRBD statistics])
 +AC_PLUGIN([email],               [yes],                       [EMail statistics])
 +AC_PLUGIN([entropy],             [$plugin_entropy],           [Entropy statistics])
 +AC_PLUGIN([ethstat],             [$plugin_ethstat],           [Stats from NIC driver])
 +AC_PLUGIN([exec],                [yes],                       [Execution of external programs])
 +AC_PLUGIN([fhcount],             [$plugin_fhcount],           [File handles statistics])
 +AC_PLUGIN([filecount],           [yes],                       [Count files in directories])
 +AC_PLUGIN([fscache],             [$plugin_fscache],           [fscache statistics])
 +AC_PLUGIN([gmond],               [$with_libganglia],          [Ganglia plugin])
 +AC_PLUGIN([gps],                 [$plugin_gps],               [GPS plugin])
 +AC_PLUGIN([grpc],                [$plugin_grpc],              [gRPC plugin])
 +AC_PLUGIN([hddtemp],             [yes],                       [Query hddtempd])
 +AC_PLUGIN([hugepages],           [$plugin_hugepages],         [Hugepages statistics])
 +AC_PLUGIN([intel_pmu],           [$with_libjevents],          [Intel performance monitor plugin])
 +AC_PLUGIN([intel_rdt],           [$with_libpqos],             [Intel RDT monitor plugin])
 +AC_PLUGIN([interface],           [$plugin_interface],         [Interface traffic statistics])
 +AC_PLUGIN([ipc],                 [$plugin_ipc],               [IPC statistics])
 +AC_PLUGIN([ipmi],                [$plugin_ipmi],              [IPMI sensor statistics])
 +AC_PLUGIN([iptables],            [$with_libiptc],             [IPTables rule counters])
 +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([load],                [$plugin_load],              [System load])
 +AC_PLUGIN([log_logstash],        [$plugin_log_logstash],      [Logstash json_event compatible logging])
 +AC_PLUGIN([logfile],             [yes],                       [File logging plugin])
 +AC_PLUGIN([lpar],                [$with_perfstat],            [AIX logical partitions statistics])
 +AC_PLUGIN([lua],                 [$with_liblua],              [Lua plugin])
 +AC_PLUGIN([lvm],                 [$with_liblvm2app],          [LVM statistics])
 +AC_PLUGIN([madwifi],             [$have_linux_wireless_h],    [Madwifi wireless statistics])
 +AC_PLUGIN([match_empty_counter], [yes],                       [The empty counter match])
 +AC_PLUGIN([match_hashed],        [yes],                       [The hashed match])
 +AC_PLUGIN([match_regex],         [yes],                       [The regex match])
 +AC_PLUGIN([match_timediff],      [yes],                       [The timediff match])
 +AC_PLUGIN([match_value],         [yes],                       [The value match])
 +AC_PLUGIN([mbmon],               [yes],                       [Query mbmond])
 +AC_PLUGIN([mcelog],              [$plugin_mcelog],            [Machine Check Exceptions notifications])
 +AC_PLUGIN([md],                  [$have_linux_raid_md_u_h],   [md (Linux software RAID) devices])
 +AC_PLUGIN([memcachec],           [$with_libmemcached],        [memcachec statistics])
 +AC_PLUGIN([memcached],           [yes],                       [memcached statistics])
 +AC_PLUGIN([memory],              [$plugin_memory],            [Memory usage])
 +AC_PLUGIN([mic],                 [$with_mic],                 [Intel Many Integrated Core stats])
 +AC_PLUGIN([modbus],              [$with_libmodbus],           [Modbus plugin])
 +AC_PLUGIN([mqtt],                [$with_libmosquitto],        [MQTT output plugin])
 +AC_PLUGIN([multimeter],          [$plugin_multimeter],        [Read multimeter values])
 +AC_PLUGIN([mysql],               [$with_libmysql],            [MySQL statistics])
 +AC_PLUGIN([netapp],              [$with_libnetapp],           [NetApp plugin])
 +AC_PLUGIN([netlink],             [$with_libmnl],              [Enhanced Linux network statistics])
 +AC_PLUGIN([network],             [yes],                       [Network communication plugin])
 +AC_PLUGIN([nfs],                 [$plugin_nfs],               [NFS statistics])
 +AC_PLUGIN([nginx],               [$with_libcurl],             [nginx statistics])
 +AC_PLUGIN([notify_desktop],      [$with_libnotify],           [Desktop notifications])
 +AC_PLUGIN([notify_email],        [$with_libesmtp],            [Email notifier])
 +AC_PLUGIN([notify_nagios],       [yes],                       [Nagios notification plugin])
 +AC_PLUGIN([ntpd],                [yes],                       [NTPd statistics])
 +AC_PLUGIN([numa],                [$plugin_numa],              [NUMA virtual memory statistics])
 +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([ovs_events],          [$plugin_ovs_events],        [OVS events plugin])
 +AC_PLUGIN([ovs_stats],           [$plugin_ovs_stats],         [OVS statistics plugin])
 +AC_PLUGIN([pcie_errors],         [$plugin_pcie_errors],       [PCIe errors plugin])
 +AC_PLUGIN([perl],                [$plugin_perl],              [Embed a Perl interpreter])
 +AC_PLUGIN([pf],                  [$have_net_pfvar_h],         [BSD packet filter (PF) statistics])
  # FIXME: Check for libevent, too.
 -AC_PLUGIN([pinba],               [$plugin_pinba],           [Pinba statistics])
 -AC_PLUGIN([ping],                [$with_liboping],          [Network latency statistics])
 -AC_PLUGIN([postgresql],          [$with_libpq],             [PostgreSQL database statistics])
 -AC_PLUGIN([powerdns],            [yes],                     [PowerDNS statistics])
 -AC_PLUGIN([processes],           [$plugin_processes],       [Process statistics])
 -AC_PLUGIN([protocols],           [$plugin_protocols],       [Protocol (IP, TCP, ...) statistics])
 -AC_PLUGIN([python],              [$plugin_python],          [Embed a Python interpreter])
 -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],               [$plugin_smart],           [SMART statistics])
 -AC_PLUGIN([snmp],                [$with_libnetsnmp],        [SNMP querying plugin])
 -AC_PLUGIN([snmp_agent],          [$with_libnetsnmpagent],   [SNMP agent plugin])
 -AC_PLUGIN([statsd],              [yes],                     [StatsD plugin])
 -AC_PLUGIN([swap],                [$plugin_swap],            [Swap usage statistics])
 -AC_PLUGIN([synproxy],            [$plugin_synproxy],        [Synproxy stats plugin])
 -AC_PLUGIN([syslog],              [$have_syslog],            [Syslog logging plugin])
 -AC_PLUGIN([table],               [yes],                     [Parsing of tabular data])
 -AC_PLUGIN([tail],                [yes],                     [Parsing of logfiles])
 -AC_PLUGIN([tail_csv],            [yes],                     [Parsing of CSV files])
 -AC_PLUGIN([tape],                [$plugin_tape],            [Tape drive statistics])
 -AC_PLUGIN([target_notification], [yes],                     [The notification target])
 -AC_PLUGIN([target_replace],      [yes],                     [The replace target])
 -AC_PLUGIN([target_scale],        [yes],                     [The scale target])
 -AC_PLUGIN([target_set],          [yes],                     [The set target])
 -AC_PLUGIN([target_v5upgrade],    [yes],                     [The v5upgrade target])
 -AC_PLUGIN([tcpconns],            [$plugin_tcpconns],        [TCP connection statistics])
 -AC_PLUGIN([teamspeak2],          [yes],                     [TeamSpeak2 server statistics])
 -AC_PLUGIN([ted],                 [$plugin_ted],             [Read The Energy Detective values])
 -AC_PLUGIN([thermal],             [$plugin_thermal],         [Linux ACPI thermal zone statistics])
 -AC_PLUGIN([threshold],           [yes],                     [Threshold checking plugin])
 -AC_PLUGIN([tokyotyrant],         [$with_libtokyotyrant],    [TokyoTyrant database statistics])
 -AC_PLUGIN([turbostat],           [$plugin_turbostat],       [Advanced statistic on Intel cpu states])
 -AC_PLUGIN([unixsock],            [yes],                     [Unixsock communication plugin])
 -AC_PLUGIN([uptime],              [$plugin_uptime],          [Uptime statistics])
 -AC_PLUGIN([users],               [$plugin_users],           [User statistics])
 -AC_PLUGIN([uuid],                [yes],                     [UUID as hostname plugin])
 -AC_PLUGIN([varnish],             [$with_libvarnish],        [Varnish cache statistics])
 -AC_PLUGIN([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_log],           [yes],                     [Log output plugin])
 -AC_PLUGIN([write_mongodb],       [$with_libmongoc],         [MongoDB output plugin])
 -AC_PLUGIN([write_prometheus],    [$plugin_write_prometheus], [Prometheus write plugin])
 -AC_PLUGIN([write_redis],         [$with_libhiredis],        [Redis output plugin])
 -AC_PLUGIN([write_riemann],       [$with_libriemann_client], [Riemann output plugin])
 -AC_PLUGIN([write_sensu],         [yes],                     [Sensu output plugin])
 -AC_PLUGIN([write_tsdb],          [yes],                     [TSDB output plugin])
 -AC_PLUGIN([xencpu],              [$plugin_xencpu],          [Xen Host CPU usage])
 -AC_PLUGIN([xmms],                [$with_libxmms],           [XMMS statistics])
 -AC_PLUGIN([zfs_arc],             [$plugin_zfs_arc],         [ZFS ARC statistics])
 -AC_PLUGIN([zone],                [$plugin_zone],            [Solaris container statistics])
 -AC_PLUGIN([zookeeper],           [yes],                     [Zookeeper statistics])
 +AC_PLUGIN([pinba],               [$plugin_pinba],             [Pinba statistics])
 +AC_PLUGIN([ping],                [$with_liboping],            [Network latency statistics])
 +AC_PLUGIN([postgresql],          [$with_libpq],               [PostgreSQL database statistics])
 +AC_PLUGIN([powerdns],            [yes],                       [PowerDNS statistics])
 +AC_PLUGIN([processes],           [$plugin_processes],         [Process statistics])
 +AC_PLUGIN([protocols],           [$plugin_protocols],         [Protocol (IP, TCP, ...) statistics])
 +AC_PLUGIN([python],              [$plugin_python],            [Embed a Python interpreter])
 +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],               [$plugin_smart],             [SMART statistics])
 +AC_PLUGIN([snmp],                [$with_libnetsnmp],          [SNMP querying plugin])
 +AC_PLUGIN([snmp_agent],          [$with_libnetsnmpagent],     [SNMP agent plugin])
 +AC_PLUGIN([statsd],              [yes],                       [StatsD plugin])
 +AC_PLUGIN([swap],                [$plugin_swap],              [Swap usage statistics])
 +AC_PLUGIN([synproxy],            [$plugin_synproxy],          [Synproxy stats plugin])
 +AC_PLUGIN([syslog],              [$have_syslog],              [Syslog logging plugin])
 +AC_PLUGIN([table],               [yes],                       [Parsing of tabular data])
 +AC_PLUGIN([tail],                [yes],                       [Parsing of logfiles])
 +AC_PLUGIN([tail_csv],            [yes],                       [Parsing of CSV files])
 +AC_PLUGIN([tape],                [$plugin_tape],              [Tape drive statistics])
 +AC_PLUGIN([target_notification], [yes],                       [The notification target])
 +AC_PLUGIN([target_replace],      [yes],                       [The replace target])
 +AC_PLUGIN([target_scale],        [yes],                       [The scale target])
 +AC_PLUGIN([target_set],          [yes],                       [The set target])
 +AC_PLUGIN([target_v5upgrade],    [yes],                       [The v5upgrade target])
 +AC_PLUGIN([tcpconns],            [$plugin_tcpconns],          [TCP connection statistics])
 +AC_PLUGIN([teamspeak2],          [yes],                       [TeamSpeak2 server statistics])
 +AC_PLUGIN([ted],                 [$plugin_ted],               [Read The Energy Detective values])
 +AC_PLUGIN([thermal],             [$plugin_thermal],           [Linux ACPI thermal zone statistics])
 +AC_PLUGIN([threshold],           [yes],                       [Threshold checking plugin])
 +AC_PLUGIN([tokyotyrant],         [$with_libtokyotyrant],      [TokyoTyrant database statistics])
 +AC_PLUGIN([turbostat],           [$plugin_turbostat],         [Advanced statistic on Intel cpu states])
 +AC_PLUGIN([unixsock],            [yes],                       [Unixsock communication plugin])
 +AC_PLUGIN([uptime],              [$plugin_uptime],            [Uptime statistics])
 +AC_PLUGIN([users],               [$plugin_users],             [User statistics])
 +AC_PLUGIN([uuid],                [yes],                       [UUID as hostname plugin])
 +AC_PLUGIN([varnish],             [$with_libvarnish],          [Varnish cache statistics])
 +AC_PLUGIN([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_stackdriver],   [$plugin_write_stackdriver], [Google Stackdriver Monitoring output plugin])
 +AC_PLUGIN([write_kafka],         [$with_librdkafka],          [Kafka output plugin])
 +AC_PLUGIN([write_log],           [yes],                       [Log output plugin])
 +AC_PLUGIN([write_mongodb],       [$with_libmongoc],           [MongoDB output plugin])
 +AC_PLUGIN([write_prometheus],    [$plugin_write_prometheus],  [Prometheus write plugin])
 +AC_PLUGIN([write_redis],         [$with_libhiredis],          [Redis output plugin])
 +AC_PLUGIN([write_riemann],       [$with_libriemann_client],   [Riemann output plugin])
 +AC_PLUGIN([write_sensu],         [yes],                       [Sensu output plugin])
 +AC_PLUGIN([write_tsdb],          [yes],                       [TSDB output plugin])
 +AC_PLUGIN([xencpu],              [$plugin_xencpu],            [Xen Host CPU usage])
 +AC_PLUGIN([xmms],                [$with_libxmms],             [XMMS statistics])
 +AC_PLUGIN([zfs_arc],             [$plugin_zfs_arc],           [ZFS ARC statistics])
 +AC_PLUGIN([zone],                [$plugin_zone],              [Solaris container statistics])
 +AC_PLUGIN([zookeeper],           [yes],                       [Zookeeper statistics])
  
  dnl Default configuration file
  # Load either syslog or logfile
@@@ -7146,7 -6883,6 +7146,7 @@@ AC_MSG_RESULT([    libpqos . . . . . . 
  AC_MSG_RESULT([    libprotobuf . . . . . $with_libprotobuf])
  AC_MSG_RESULT([    libprotobuf-c . . . . $with_libprotobuf_c])
  AC_MSG_RESULT([    libpython . . . . . . $with_libpython])
 +AC_MSG_RESULT([    libqpid-proton .  . . $with_libqpid_proton])
  AC_MSG_RESULT([    librabbitmq . . . . . $with_librabbitmq])
  AC_MSG_RESULT([    libriemann-client . . $with_libriemann_client])
  AC_MSG_RESULT([    librdkafka  . . . . . $with_librdkafka])
@@@ -7154,7 -6890,6 +7154,7 @@@ AC_MSG_RESULT([    librouteros . . . . 
  AC_MSG_RESULT([    librrd  . . . . . . . $with_librrd])
  AC_MSG_RESULT([    libsensors  . . . . . $with_libsensors])
  AC_MSG_RESULT([    libsigrok   . . . . . $with_libsigrok])
 +AC_MSG_RESULT([    libssl  . . . . . . . $with_libssl])
  AC_MSG_RESULT([    libstatgrab . . . . . $with_libstatgrab])
  AC_MSG_RESULT([    libtokyotyrant  . . . $with_libtokyotyrant])
  AC_MSG_RESULT([    libudev . . . . . . . $with_libudev])
@@@ -7179,7 -6914,6 +7179,7 @@@ AC_MSG_RESULT(
  AC_MSG_RESULT([  Modules:])
  AC_MSG_RESULT([    aggregation . . . . . $enable_aggregation])
  AC_MSG_RESULT([    amqp    . . . . . . . $enable_amqp])
 +AC_MSG_RESULT([    amqp1   . . . . . . . $enable_amqp1])
  AC_MSG_RESULT([    apache  . . . . . . . $enable_apache])
  AC_MSG_RESULT([    apcups  . . . . . . . $enable_apcups])
  AC_MSG_RESULT([    apple_sensors . . . . $enable_apple_sensors])
@@@ -7269,7 -7003,6 +7269,7 @@@ AC_MSG_RESULT([    openvpn . . . . . . 
  AC_MSG_RESULT([    oracle  . . . . . . . $enable_oracle])
  AC_MSG_RESULT([    ovs_events  . . . . . $enable_ovs_events])
  AC_MSG_RESULT([    ovs_stats . . . . . . $enable_ovs_stats])
 +AC_MSG_RESULT([    pcie_errors . . . . . $enable_pcie_errors])
  AC_MSG_RESULT([    perl  . . . . . . . . $enable_perl])
  AC_MSG_RESULT([    pf  . . . . . . . . . $enable_pf])
  AC_MSG_RESULT([    pinba . . . . . . . . $enable_pinba])
@@@ -7327,7 -7060,6 +7327,7 @@@ AC_MSG_RESULT([    write_prometheus. . 
  AC_MSG_RESULT([    write_redis . . . . . $enable_write_redis])
  AC_MSG_RESULT([    write_riemann . . . . $enable_write_riemann])
  AC_MSG_RESULT([    write_sensu . . . . . $enable_write_sensu])
 +AC_MSG_RESULT([    write_stackdriver . . $enable_write_stackdriver])
  AC_MSG_RESULT([    write_tsdb  . . . . . $enable_write_tsdb])
  AC_MSG_RESULT([    xencpu  . . . . . . . $enable_xencpu])
  AC_MSG_RESULT([    xmms  . . . . . . . . $enable_xmms])
@@@ -7345,4 -7077,3 +7345,4 @@@ if test "x$dependency_warning" = "xyes"
  fi
  
  # vim: set fdm=marker sw=2 sts=2 ts=2 et :
 +
diff --combined src/disk.c
@@@ -82,7 -82,7 +82,7 @@@
  static mach_port_t io_master_port = MACH_PORT_NULL;
  /* This defaults to false for backwards compatibility. Please fix in the next
   * major version. */
 -static _Bool use_bsd_name = 0;
 +static bool use_bsd_name;
  /* #endif HAVE_IOKIT_IOKITLIB_H */
  
  #elif KERNEL_LINUX
@@@ -106,9 -106,9 +106,9 @@@ typedef struct diskstats 
    derive_t avg_read_time;
    derive_t avg_write_time;
  
 -  _Bool has_merged;
 -  _Bool has_in_progress;
 -  _Bool has_io_time;
 +  bool has_merged;
 +  bool has_in_progress;
 +  bool has_io_time;
  
    struct diskstats *next;
  } diskstats_t;
@@@ -126,7 -126,7 +126,7 @@@ static struct gmesh geom_tree
  #define MAX_NUMDISK 1024
  extern kstat_ctl_t *kc;
  static kstat_t *ksp[MAX_NUMDISK];
 -static int numdisk = 0;
 +static int numdisk;
  /* #endif HAVE_LIBKSTAT */
  
  #elif defined(HAVE_LIBSTATGRAB)
@@@ -145,7 -145,7 +145,7 @@@ static int pnumdisk
  #if HAVE_LIBUDEV_H
  #include <libudev.h>
  
 -static char *conf_udev_name_attr = NULL;
 +static char *conf_udev_name_attr;
  static struct udev *handle_udev;
  #endif
  
@@@ -153,7 -153,7 +153,7 @@@ static const char *config_keys[] = {"Di
                                      "UdevNameAttr"};
  static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
  
 -static ignorelist_t *ignorelist = NULL;
 +static ignorelist_t *ignorelist;
  
  static int disk_config(const char *key, const char *value) {
    if (ignorelist == NULL)
      ignorelist_set_invert(ignorelist, invert);
    } else if (strcasecmp("UseBSDName", key) == 0) {
  #if HAVE_IOKIT_IOKITLIB_H
 -    use_bsd_name = IS_TRUE(value) ? 1 : 0;
 +    use_bsd_name = IS_TRUE(value);
  #else
      WARNING("disk plugin: The \"UseBSDName\" option is only supported "
              "on Mach / Mac OS X and will be ignored.");
@@@ -303,7 -303,9 +303,7 @@@ static void submit_io_time(char const *
  
    plugin_dispatch_values(&vl);
  } /* void submit_io_time */
 -#endif /* KERNEL_FREEBSD || KERNEL_LINUX */
  
 -#if KERNEL_LINUX
  static void submit_in_progress(char const *disk_name, gauge_t in_progress) {
    value_list_t vl = VALUE_LIST_INIT;
  
  
    plugin_dispatch_values(&vl);
  }
 +#endif /* KERNEL_FREEBSD || KERNEL_LINUX */
  
 +#if KERNEL_LINUX
  static counter_t disk_calc_time_incr(counter_t delta_time,
                                       counter_t delta_ops) {
    double interval = CDTIME_T_TO_DOUBLE(plugin_get_interval());
@@@ -544,7 -544,6 +544,7 @@@ static int disk_read(void) 
  
    const char *disk_name;
    long double read_time, write_time, busy_time, total_duration;
 +  uint64_t queue_length;
  
    for (retry = 0, dirty = 1; retry < 5 && dirty == 1; retry++) {
      if (snap != NULL)
      }
      if (devstat_compute_statistics(snap_iter, NULL, 1.0, DSM_TOTAL_BUSY_TIME,
                                     &busy_time, DSM_TOTAL_DURATION,
 -                                   &total_duration, DSM_NONE) != 0) {
 +                                   &total_duration, DSM_QUEUE_LENGTH,
 +                                   &queue_length, DSM_NONE) != 0) {
        WARNING("%s", devstat_errbuf);
      } else {
        submit_io_time(disk_name, busy_time, total_duration);
 +      submit_in_progress(disk_name, (gauge_t)queue_length);
      }
    }
    geom_stats_snapshot_free(snap);
  
    char *fields[32];
    int numfields;
 -  int fieldshift = 0;
  
    int minor = 0;
  
    diskstats_t *ds, *pre_ds;
  
    if ((fh = fopen("/proc/diskstats", "r")) == NULL) {
 -    fh = fopen("/proc/partitions", "r");
 -    if (fh == NULL) {
 -      ERROR("disk plugin: fopen (/proc/{diskstats,partitions}) failed.");
 -      return -1;
 -    }
 -
 -    /* Kernel is 2.4.* */
 -    fieldshift = 1;
 +    ERROR("disk plugin: fopen(\"/proc/diskstats\"): %s", STRERRNO);
 +    return -1;
    }
  
    while (fgets(buffer, sizeof(buffer), fh) != NULL) {
      char *output_name;
  
      numfields = strsplit(buffer, fields, 32);
-     if ((numfields != 14) && (numfields != 7))
 -    /* need either 7 fields (partition)
 -     * or at least 14 fields (15 on Linux 2.4) */
 -    if ((numfields != 7) && (numfields < (14 + fieldshift)))
++    /* need either 7 fields (partition) or at least 14 fields */
++    if ((numfields != 7) && (numfields < 14))
        continue;
  
      minor = atoll(fields[1]);
  
 -    disk_name = fields[2 + fieldshift];
 +    disk_name = fields[2];
  
      for (ds = disklist, pre_ds = disklist; ds != NULL;
           pre_ds = ds, ds = ds->next)
        read_sectors = atoll(fields[4]);
        write_ops = atoll(fields[5]);
        write_sectors = atoll(fields[6]);
-     } else if (numfields == 14) {
+     } else {
 -      assert(numfields >= (14 + fieldshift));
 -      read_ops = atoll(fields[3 + fieldshift]);
 -      write_ops = atoll(fields[7 + fieldshift]);
++      assert(numfields >= 14);
 +      read_ops = atoll(fields[3]);
 +      write_ops = atoll(fields[7]);
  
 -      read_sectors = atoll(fields[5 + fieldshift]);
 -      write_sectors = atoll(fields[9 + fieldshift]);
 +      read_sectors = atoll(fields[5]);
 +      write_sectors = atoll(fields[9]);
  
 -      if ((fieldshift == 0) || (minor == 0)) {
 +      if (minor == 0) {
          is_disk = 1;
 -        read_merged = atoll(fields[4 + fieldshift]);
 -        read_time = atoll(fields[6 + fieldshift]);
 -        write_merged = atoll(fields[8 + fieldshift]);
 -        write_time = atoll(fields[10 + fieldshift]);
 +        read_merged = atoll(fields[4]);
 +        read_time = atoll(fields[6]);
 +        write_merged = atoll(fields[8]);
 +        write_time = atoll(fields[10]);
  
 -        in_progress = atof(fields[11 + fieldshift]);
 +        in_progress = atof(fields[11]);
  
 -        io_time = atof(fields[12 + fieldshift]);
 -        weighted_time = atof(fields[13 + fieldshift]);
 +        io_time = atof(fields[12]);
 +        weighted_time = atof(fields[13]);
        }
-     } else {
-       DEBUG("numfields = %i; => unknown file format.", numfields);
-       continue;
      }
  
      {
        ds->write_time = write_time;
  
        if (read_merged || write_merged)
 -        ds->has_merged = 1;
 +        ds->has_merged = true;
  
        if (in_progress)
 -        ds->has_in_progress = 1;
 +        ds->has_in_progress = true;
  
        if (io_time)
 -        ds->has_io_time = 1;
 +        ds->has_io_time = true;
  
      } /* if (is_disk) */
  
    int rnumdisk;
  
    if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0) {
 -    char errbuf[1024];
 -    WARNING("disk plugin: perfstat_disk: %s",
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +    WARNING("disk plugin: perfstat_disk: %s", STRERRNO);
      return -1;
    }
  
    firstpath.name[0] = '\0';
    if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t),
                                  numdisk)) < 0) {
 -    char errbuf[1024];
 -    WARNING("disk plugin: perfstat_disk : %s",
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +    WARNING("disk plugin: perfstat_disk : %s", STRERRNO);
      return -1;
    }
  
diff --combined src/exec.c
@@@ -85,7 -85,7 +85,7 @@@ const long int MAX_GRBUF_SIZE = 65536
  /*
   * Private variables
   */
 -static program_list_t *pl_head = NULL;
 +static program_list_t *pl_head;
  static pthread_mutex_t pl_lock = PTHREAD_MUTEX_INITIALIZER;
  
  /*
@@@ -245,11 -245,17 +245,17 @@@ static int exec_config(oconfig_item_t *
    return 0;
  } /* int exec_config }}} */
  
+ #if !defined(HAVE_SETENV)
+ static char env_interval[64];
+ // max hostname len is 255, so this should be enough
+ static char env_hostname[300];
+ #endif
  static void set_environment(void) /* {{{ */
  {
+ #ifdef HAVE_SETENV
    char buffer[1024];
  
- #ifdef HAVE_SETENV
    snprintf(buffer, sizeof(buffer), "%.3f",
             CDTIME_T_TO_DOUBLE(plugin_get_interval()));
    setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
    sstrncpy(buffer, hostname_g, sizeof(buffer));
    setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
  #else
-   snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f",
+   snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL=%.3f",
             CDTIME_T_TO_DOUBLE(plugin_get_interval()));
-   putenv(buffer);
+   putenv(env_interval);
  
-   snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
-   putenv(buffer);
+   snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME=%s",
+            hostname_g);
+   putenv(env_hostname);
  #endif
  } /* }}} void set_environment */
  
+ static void unset_environment(void) /* {{{ */
+ {
+ #ifdef HAVE_SETENV
+   unsetenv("COLLECTD_INTERVAL");
+   unsetenv("COLLECTD_HOSTNAME");
+ #else
+   snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL");
+   putenv(env_interval);
+   snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME");
+   putenv(env_hostname);
+ #endif
+ } /* }}} void unset_environment */
  __attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid,
                                                   int gid, int egid) /* {{{ */
  {
    int status;
 -  char errbuf[1024];
  
  #if HAVE_SETGROUPS
    if (getuid() == 0) {
  
    status = setgid(gid);
    if (status != 0) {
 -    ERROR("exec plugin: setgid (%i) failed: %s", gid,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("exec plugin: setgid (%i) failed: %s", gid, STRERRNO);
      exit(-1);
    }
  
    if (egid != -1) {
      status = setegid(egid);
      if (status != 0) {
 -      ERROR("exec plugin: setegid (%i) failed: %s", egid,
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +      ERROR("exec plugin: setegid (%i) failed: %s", egid, STRERRNO);
        exit(-1);
      }
    }
  
    status = setuid(uid);
    if (status != 0) {
 -    ERROR("exec plugin: setuid (%i) failed: %s", uid,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("exec plugin: setuid (%i) failed: %s", uid, STRERRNO);
      exit(-1);
    }
  
    execvp(pl->exec, pl->argv);
  
 -  ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec,
 -        sstrerror(errno, errbuf, sizeof(errbuf)));
 +  ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, STRERRNO);
    exit(-1);
  } /* void exec_child }}} */
  
@@@ -324,11 -349,13 +344,11 @@@ static void reset_signal_mask(void) /* 
  
  static int create_pipe(int fd_pipe[2]) /* {{{ */
  {
 -  char errbuf[1024];
    int status;
  
    status = pipe(fd_pipe);
    if (status != 0) {
 -    ERROR("exec plugin: pipe failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("exec plugin: pipe failed: %s", STRERRNO);
      return -1;
    }
  
@@@ -393,7 -420,9 +413,7 @@@ static int getegr_id(program_list_t *pl
      } else if (errno == ERANGE) {
        grbuf_size += grbuf_size; // increment buffer size and try again
      } else {
 -      char errbuf[1024];
 -      ERROR("exec plugin: getegr_id failed %s",
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +      ERROR("exec plugin: getegr_id failed %s", STRERRNO);
        sfree(grbuf);
        return -2;
      }
    ERROR("exec plugin: getegr_id Max grbuf size reached  for %s", pl->group);
    sfree(grbuf);
    return -2;
 -} /* }}} */
 +}
  
  /*
   * Creates three pipes (one for reading, one for writing and one for errors),
@@@ -415,6 -444,7 +435,6 @@@ static int fork_child(program_list_t *p
    int fd_pipe_in[2] = {-1, -1};
    int fd_pipe_out[2] = {-1, -1};
    int fd_pipe_err[2] = {-1, -1};
 -  char errbuf[1024];
    int status;
    int pid;
  
    status = getpwnam_r(pl->user, &sp, nambuf, sizeof(nambuf), &sp_ptr);
    if (status != 0) {
      ERROR("exec plugin: Failed to get user information for user ``%s'': %s",
 -          pl->user, sstrerror(status, errbuf, sizeof(errbuf)));
 +          pl->user, STRERROR(status));
      goto failed;
    }
  
      goto failed;
    }
  
 +  /* The group configured in the configfile is set as effective group, because
 +   * this way the forked process can (re-)gain the user's primary group. */
    egid = getegr_id(pl, gid);
    if (egid == -2) {
      goto failed;
    }
  
+   set_environment();
    pid = fork();
    if (pid < 0) {
 -    ERROR("exec plugin: fork failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("exec plugin: fork failed: %s", STRERRNO);
      goto failed;
    } else if (pid == 0) {
      int fd_num;
        close(fd_pipe_err[1]);
      }
  
-     set_environment();
      /* Unblock all signals */
      reset_signal_mask();
  
      /* does not return */
    }
  
+   unset_environment();
    close(fd_pipe_in[0]);
    close(fd_pipe_out[1]);
    close(fd_pipe_err[1]);
    return pid;
  
  failed:
+   unset_environment();
    close_pipe(fd_pipe_in);
    close_pipe(fd_pipe_out);
    close_pipe(fd_pipe_err);
@@@ -717,7 -750,9 +741,7 @@@ static void *exec_notification_one(voi
  
    fh = fdopen(fd, "w");
    if (fh == NULL) {
 -    char errbuf[1024];
 -    ERROR("exec plugin: fdopen (%i) failed: %s", fd,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("exec plugin: fdopen (%i) failed: %s", fd, STRERRNO);
      kill(pid, SIGTERM);
      close(fd);
      sfree(arg);
diff --combined src/ntpd.c
@@@ -56,17 -56,17 +56,17 @@@ static const char *config_keys[] = {"Ho
                                      "IncludeUnitID"};
  static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
  
 -static _Bool do_reverse_lookups = 1;
 +static bool do_reverse_lookups = true;
  
  /* This option only exists for backward compatibility. If it is false and two
   * ntpd peers use the same refclock driver, the plugin will try to write
   * simultaneous measurements from both to the same type instance. */
 -static _Bool include_unit_id = 0;
 +static bool include_unit_id;
  
  #define NTPD_DEFAULT_HOST "localhost"
  #define NTPD_DEFAULT_PORT "123"
  static int sock_descr = -1;
 -static char *ntpd_host = NULL;
 +static char *ntpd_host;
  static char ntpd_port[16];
  
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@@ -251,7 -251,7 +251,7 @@@ static const char *refclock_names[] = 
      "CHRONOLOG",  "DUMBCLOCK",    "ULINK_M320", "PCF",         /* 32-35 */
      "WWV_AUDIO",  "GPS_FG",       "HOPF_S",     "HOPF_P",      /* 36-39 */
      "JJY",        "TT_IRIG",      "GPS_ZYFER",  "GPS_RIPENCC", /* 40-43 */
 -    "NEOCLK4X"                                                 /* 44    */
 +    "NEOCLK4X",   "PCI_TSYNC",    "GPSD_JSON"                  /* 44-46 */
  };
  static size_t refclock_names_num = STATIC_ARRAY_SIZE(refclock_names);
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@@ -272,14 -272,14 +272,14 @@@ static int ntpd_config(const char *key
        sstrncpy(ntpd_port, value, sizeof(ntpd_port));
    } else if (strcasecmp(key, "ReverseLookups") == 0) {
      if (IS_TRUE(value))
 -      do_reverse_lookups = 1;
 +      do_reverse_lookups = true;
      else
 -      do_reverse_lookups = 0;
 +      do_reverse_lookups = false;
    } else if (strcasecmp(key, "IncludeUnitID") == 0) {
      if (IS_TRUE(value))
 -      include_unit_id = 1;
 +      include_unit_id = true;
      else
 -      include_unit_id = 0;
 +      include_unit_id = false;
    } else {
      return -1;
    }
@@@ -337,8 -337,10 +337,8 @@@ static int ntpd_connect(void) 
                                .ai_socktype = SOCK_DGRAM};
  
    if ((status = getaddrinfo(host, port, &ai_hints, &ai_list)) != 0) {
 -    char errbuf[1024];
      ERROR("ntpd plugin: getaddrinfo (%s, %s): %s", host, port,
 -          (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
 -                                 : gai_strerror(status));
 +          (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
      return -1;
    }
  
@@@ -407,7 -409,9 +407,7 @@@ static int ntpd_receive_response(int *r
    *res_data = NULL;
  
    if (gettimeofday(&time_end, NULL) < 0) {
 -    char errbuf[1024];
 -    ERROR("ntpd plugin: gettimeofday failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("ntpd plugin: gettimeofday failed: %s", STRERRNO);
      return -1;
    }
    time_end.tv_sec++; /* wait for a most one second */
      struct timeval time_left;
  
      if (gettimeofday(&time_now, NULL) < 0) {
 -      char errbuf[1024];
 -      ERROR("ntpd plugin: gettimeofday failed: %s",
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +      ERROR("ntpd plugin: gettimeofday failed: %s", STRERRNO);
        return -1;
      }
  
        continue;
  
      if (status < 0) {
 -      char errbuf[1024];
 -      ERROR("ntpd plugin: poll failed: %s",
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +      ERROR("ntpd plugin: poll failed: %s", STRERRNO);
        return -1;
      }
  
        continue;
  
      if (status < 0) {
 -      char errbuf[1024];
 -      INFO("recv(2) failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
 +      INFO("recv(2) failed: %s", STRERRNO);
        DEBUG("Closing socket #%i", sd);
        close(sd);
        sock_descr = sd = -1;
       * Enough with the checks. Copy the data now.
       * We start by allocating some more memory.
       */
 -    DEBUG("realloc (%p, %zu)", (void *)*res_data,
 +    DEBUG("realloc (%p, %" PRIsz ")", (void *)*res_data,
            (items_num + pkt_item_num) * res_item_size);
      items = realloc(*res_data, (items_num + pkt_item_num) * res_item_size);
      if (items == NULL) {
@@@ -717,7 -726,7 +717,7 @@@ ntpd_get_refclock_id(struct info_peer_s
  
  static int ntpd_get_name_from_address(char *buffer, size_t buffer_size,
                                        struct info_peer_summary const *peer_info,
 -                                      _Bool do_reverse_lookup) {
 +                                      bool do_reverse_lookup) {
    struct sockaddr_storage sa = {0};
    socklen_t sa_len;
    int flags = 0;
                         buffer_size, NULL, 0, /* No port name */
                         flags);
    if (status != 0) {
 -    char errbuf[1024];
      ERROR("ntpd plugin: getnameinfo failed: %s",
 -          (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
 -                                 : gai_strerror(status));
 +          (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
      return -1;
    }
  
@@@ -779,6 -790,17 +779,6 @@@ static int ntpd_get_name_refclock(char 
    return 0;
  } /* int ntpd_get_name_refclock */
  
 -static int ntpd_get_name(char *buffer, size_t buffer_size,
 -                         struct info_peer_summary const *peer_info) {
 -  uint32_t addr = ntohl(peer_info->srcadr);
 -
 -  if (!peer_info->v6_flag && ((addr & REFCLOCK_MASK) == REFCLOCK_ADDR))
 -    return ntpd_get_name_refclock(buffer, buffer_size, peer_info);
 -  else
 -    return ntpd_get_name_from_address(buffer, buffer_size, peer_info,
 -                                      do_reverse_lookups);
 -} /* int ntpd_addr_to_name */
 -
  static int ntpd_read(void) {
    struct info_kernel *ik;
    int ik_num;
    if (status != 0) {
      ERROR("ntpd plugin: ntpd_do_query (REQ_GET_KERNEL) failed with status %i",
            status);
+     free(ik);
      return status;
    } else if ((ik == NULL) || (ik_num == 0) || (ik_size == 0)) {
      ERROR("ntpd plugin: ntpd_do_query returned unexpected data. "
            "(ik = %p; ik_num = %i; ik_size = %i)",
            (void *)ik, ik_num, ik_size);
+     free(ik);
      return -1;
    }
  
      ERROR(
          "ntpd plugin: ntpd_do_query (REQ_PEER_LIST_SUM) failed with status %i",
          status);
+     free(ps);
      return status;
    } else if ((ps == NULL) || (ps_num == 0) || (ps_size == 0)) {
      ERROR("ntpd plugin: ntpd_do_query returned unexpected data. "
            "(ps = %p; ps_num = %i; ps_size = %i)",
            (void *)ps, ps_num, ps_size);
+     free(ps);
      return -1;
    }
  
  
      ptr = ps + i;
  
 -    status = ntpd_get_name(peername, sizeof(peername), ptr);
 +    int is_refclock = !ptr->v6_flag &&
 +                      ((ntohl(ptr->srcadr) & REFCLOCK_MASK) == REFCLOCK_ADDR);
 +
 +    if (is_refclock)
 +      status = ntpd_get_name_refclock(peername, sizeof(peername), ptr);
 +    else
 +      status = ntpd_get_name_from_address(peername, sizeof(peername), ptr,
 +                                          do_reverse_lookups);
 +
      if (status != 0) {
        ERROR("ntpd plugin: Determining name of peer failed.");
        continue;
      }
  
 +    // `0.0.0.0` hosts are caused by POOL servers
 +    // see https://github.com/collectd/collectd/issues/2358
 +    if (strcmp(peername, "0.0.0.0") == 0) {
 +      continue;
 +    }
 +
      refclock_id = ntpd_get_refclock_id(ptr);
  
      /* Convert the `long floating point' offset value to double */
      M_LFPTOD(ntohl(ptr->offset_int), ntohl(ptr->offset_frc), offset);
  
      DEBUG("peer %i:\n"
 +          "  is_refclock= %d\n"
 +          "  refclock_id= %d\n"
            "  peername   = %s\n"
            "  srcadr     = 0x%08x\n"
            "  reach      = 0%03o\n"
            "  offset_frc = %i\n"
            "  offset     = %f\n"
            "  dispersion = %f\n",
 -          i, peername, ntohl(ptr->srcadr), ptr->reach, ntpd_read_fp(ptr->delay),
 +          i, is_refclock, (is_refclock > 0) ? refclock_id : 0, peername,
 +          ntohl(ptr->srcadr), ptr->reach, ntpd_read_fp(ptr->delay),
            ntohl(ptr->offset_int), ntohl(ptr->offset_frc), offset,
            ntpd_read_fp(ptr->dispersion));
  
 -    if (refclock_id !=
 -        1) /* not the system clock (offset will always be zero.. */
 -      ntpd_submit_reach("time_offset", peername, ptr->reach, offset);
      ntpd_submit_reach("time_dispersion", peername, ptr->reach,
                        ntpd_read_fp(ptr->dispersion));
 -    if (refclock_id == 0) /* not a reference clock */
 +
 +    /* not the system clock (offset will always be zero) */
 +    if (!(is_refclock && refclock_id == 1))
 +      ntpd_submit_reach("time_offset", peername, ptr->reach, offset);
 +
 +    if (!is_refclock) /* not a reference clock */
        ntpd_submit_reach("delay", peername, ptr->reach,
                          ntpd_read_fp(ptr->delay));
    }
diff --combined src/powerdns.c
  #endif
  #define FUNC_ERROR(func)                                                       \
    do {                                                                         \
 -    char errbuf[1024];                                                         \
 -    ERROR("powerdns plugin: %s failed: %s", func,                              \
 -          sstrerror(errno, errbuf, sizeof(errbuf)));                           \
 +    ERROR("powerdns plugin: %s failed: %s", func, STRERRNO);                   \
    } while (0)
  #define SOCK_ERROR(func, sockpath)                                             \
    do {                                                                         \
 -    char errbuf[1024];                                                         \
      ERROR("powerdns plugin: Socket `%s` %s failed: %s", sockpath, func,        \
 -          sstrerror(errno, errbuf, sizeof(errbuf)));                           \
 +          STRERRNO);                                                           \
    } while (0)
  
  #define SERVER_SOCKET LOCALSTATEDIR "/run/pdns.controlsocket"
@@@ -279,7 -282,7 +279,7 @@@ static statname_lookup_t lookup_table[
          {"ipv6-questions", "dns_question", "incoming-ipv6"},
          {"malloc-bytes", "gauge", "malloc_bytes"},
          {"max-mthread-stack", "gauge", "max_mthread_stack"},
-         {"no-packet-error", "gauge", "no_packet_error"},
+         {"no-packet-error", "errors", "no_packet_error"},
          {"noedns-outqueries", "dns_question", "outgoing-noedns"},
          {"noping-outqueries", "dns_question", "outgoing-noping"},
          {"over-capacity-drops", "dns_question", "incoming-over_capacity"},
          {"uptime", "uptime", NULL}}; /* }}} */
  static int lookup_table_length = STATIC_ARRAY_SIZE(lookup_table);
  
 -static llist_t *list = NULL;
 +static llist_t *list;
  
  #define PDNS_LOCAL_SOCKPATH LOCALSTATEDIR "/run/" PACKAGE_NAME "-powerdns"
 -static char *local_sockpath = NULL;
 +static char *local_sockpath;
  
  /* TODO: Do this before 4.4:
   * - Update the collectd.conf(5) manpage.
@@@ -352,13 -355,16 +352,13 @@@ static void submit(const char *plugin_i
    }
  
    if (ds->ds_num != 1) {
 -    ERROR("powerdns plugin: type `%s' has %zu data sources, "
 +    ERROR("powerdns plugin: type `%s' has %" PRIsz " data sources, "
            "but I can only handle one.",
            type, ds->ds_num);
      return;
    }
  
    if (0 != parse_value(value_str, &value, ds->ds[0].type)) {
 -    ERROR("powerdns plugin: Cannot convert `%s' "
 -          "to a number.",
 -          value_str);
      return;
    }
  
diff --combined src/utils_mount.c
@@@ -361,7 -361,9 +361,7 @@@ static cu_mount_t *cu_mount_listmntent(
    struct tabmntent *mntlist;
    if (listmntent(&mntlist, COLLECTD_MNTTAB, NULL, NULL) < 0) {
  #if COLLECT_DEBUG
 -    char errbuf[1024];
 -    DEBUG("utils_mount: calling listmntent() failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    DEBUG("utils_mount: calling listmntent() failed: %s", STRERRNO);
  #endif /* COLLECT_DEBUG */
    }
  
@@@ -429,7 -431,9 +429,7 @@@ static cu_mount_t *cu_mount_getfsstat(v
    /* Get the number of mounted file systems */
    if ((bufsize = CMD_STATFS(NULL, 0, FLAGS_STATFS)) < 1) {
  #if COLLECT_DEBUG
 -    char errbuf[1024];
 -    DEBUG("utils_mount: getv?fsstat failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    DEBUG("utils_mount: getv?fsstat failed: %s", STRERRNO);
  #endif /* COLLECT_DEBUG */
      return NULL;
    }
    if ((num = CMD_STATFS(buf, bufsize * sizeof(STRUCT_STATFS), FLAGS_STATFS)) <
        1) {
  #if COLLECT_DEBUG
 -    char errbuf[1024];
 -    DEBUG("utils_mount: getv?fsstat failed: %s",
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    DEBUG("utils_mount: getv?fsstat failed: %s", STRERRNO);
  #endif /* COLLECT_DEBUG */
      free(buf);
      return NULL;
@@@ -489,7 -495,9 +489,7 @@@ static cu_mount_t *cu_mount_gen_getmnte
    DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
  
    if ((fp = fopen(COLLECTD_MNTTAB, "r")) == NULL) {
 -    char errbuf[1024];
 -    ERROR("fopen (%s): %s", COLLECTD_MNTTAB,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("fopen (%s): %s", COLLECTD_MNTTAB, STRERRNO);
      return NULL;
    }
  
  
    return first;
  } /* static cu_mount_t *cu_mount_gen_getmntent (void) */
 -  /* #endif HAVE_TWO_GETMNTENT || HAVE_GEN_GETMNTENT || HAVE_SUN_GETMNTENT */
  
  #elif HAVE_SEQ_GETMNTENT
  #warn "This version of `getmntent' hat not yet been implemented!"
@@@ -537,7 -546,9 +537,7 @@@ static cu_mount_t *cu_mount_getmntent(v
    DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
  
    if ((fp = setmntent(COLLECTD_MNTTAB, "r")) == NULL) {
 -    char errbuf[1024];
 -    ERROR("setmntent (%s): %s", COLLECTD_MNTTAB,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("setmntent (%s): %s", COLLECTD_MNTTAB, STRERRNO);
      return NULL;
    }
  
@@@ -586,7 -597,9 +586,7 @@@ static cu_mount_t *cu_mount_getmntent(v
    DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
  
    if ((fp = setmntent(COLLECTD_MNTTAB, "r")) == NULL) {
 -    char errbuf[1024];
 -    ERROR("setmntent (%s): %s", COLLECTD_MNTTAB,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    ERROR("setmntent (%s): %s", COLLECTD_MNTTAB, STRERRNO);
      return NULL;
    }
  
@@@ -651,6 -664,8 +651,8 @@@ cu_mount_t *cu_mount_getlist(cu_mount_
    new = cu_mount_gen_getmntent();
  #elif HAVE_SEQ_GETMNTENT
  #error "This version of `getmntent' hat not yet been implemented!"
+ #elif HAVE_GETMNTENT_R
+   new = cu_mount_getmntent();
  #elif HAVE_ONE_GETMNTENT
    new = cu_mount_getmntent();
  #else
@@@ -688,7 -703,7 +690,7 @@@ void cu_mount_freelist(cu_mount_t *list
  
  char *cu_mount_checkoption(char *line, const char *keyword, int full) {
    char *line2, *l2, *p1, *p2;
 -  int l;
 +  size_t l;
  
    if (line == NULL || keyword == NULL) {
      return NULL;
diff --combined src/virt.c
  #include <libxml/tree.h>
  #include <libxml/xpath.h>
  #include <libxml/xpathInternals.h>
 +#include <stdbool.h>
  
  /* Plugin name */
  #define PLUGIN_NAME "virt"
  
 +/* Secure strcat macro assuring null termination. Parameter (n) is the size of
 +   buffer (d), allowing this macro to be safe for static and dynamic buffers */
 +#define SSTRNCAT(d, s, n)                                                      \
 +  do {                                                                         \
 +    size_t _l = strlen(d);                                                     \
 +    sstrncpy((d) + _l, (s), (n)-_l);                                           \
 +  } while (0)
 +
  #ifdef LIBVIR_CHECK_VERSION
  
  #if LIBVIR_CHECK_VERSION(0, 9, 2)
  #define HAVE_DOM_REASON_RUNNING_WAKEUP 1
  #endif
  
 +/*
 +  virConnectListAllDomains() appeared in 0.10.2
 +  Note that LIBVIR_CHECK_VERSION appeared a year later, so
 +  in some systems which actually have virConnectListAllDomains()
 +  we can't detect this.
 + */
 +#if LIBVIR_CHECK_VERSION(0, 10, 2)
 +#define HAVE_LIST_ALL_DOMAINS 1
 +#endif
 +
  #if LIBVIR_CHECK_VERSION(1, 0, 1)
  #define HAVE_DOM_REASON_PAUSED_SNAPSHOT 1
  #endif
  
  #endif /* LIBVIR_CHECK_VERSION */
  
 +/* structure used for aggregating notification-thread data*/
 +typedef struct virt_notif_thread_s {
 +  pthread_t event_loop_tid;
 +  int domain_event_cb_id;
 +  pthread_mutex_t active_mutex; /* protects 'is_active' member access*/
 +  bool is_active;
 +} virt_notif_thread_t;
 +
  static const char *config_keys[] = {"Connection",
  
                                      "RefreshInterval",
  
                                      "Instances",
                                      "ExtraStats",
 +                                    "PersistentNotification",
                                      NULL};
  
 +/* PersistentNotification is false by default */
 +static bool persistent_notification = false;
 +
 +/* Thread used for handling libvirt notifications events */
 +static virt_notif_thread_t notif_thread;
 +
  const char *domain_states[] = {
          [VIR_DOMAIN_NOSTATE] = "no state",
          [VIR_DOMAIN_RUNNING] = "the domain is running",
  #endif
  };
  
 +static int map_domain_event_to_state(int event) {
 +  int ret;
 +  switch (event) {
 +  case VIR_DOMAIN_EVENT_STARTED:
 +    ret = VIR_DOMAIN_RUNNING;
 +    break;
 +  case VIR_DOMAIN_EVENT_SUSPENDED:
 +    ret = VIR_DOMAIN_PAUSED;
 +    break;
 +  case VIR_DOMAIN_EVENT_RESUMED:
 +    ret = VIR_DOMAIN_RUNNING;
 +    break;
 +  case VIR_DOMAIN_EVENT_STOPPED:
 +    ret = VIR_DOMAIN_SHUTOFF;
 +    break;
 +  case VIR_DOMAIN_EVENT_SHUTDOWN:
 +    ret = VIR_DOMAIN_SHUTDOWN;
 +    break;
 +#ifdef HAVE_DOM_STATE_PMSUSPENDED
 +  case VIR_DOMAIN_EVENT_PMSUSPENDED:
 +    ret = VIR_DOMAIN_PMSUSPENDED;
 +    break;
 +#endif
 +#ifdef HAVE_DOM_REASON_CRASHED
 +  case VIR_DOMAIN_EVENT_CRASHED:
 +    ret = VIR_DOMAIN_CRASHED;
 +    break;
 +#endif
 +  default:
 +    ret = VIR_DOMAIN_NOSTATE;
 +  }
 +  return ret;
 +}
 +
  #ifdef HAVE_DOM_REASON
 +static int map_domain_event_detail_to_reason(int event, int detail) {
 +  int ret;
 +  switch (event) {
 +  case VIR_DOMAIN_EVENT_STARTED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_STARTED_BOOTED: /* Normal startup from boot */
 +      ret = VIR_DOMAIN_RUNNING_BOOTED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STARTED_MIGRATED: /* Incoming migration from another
 +                                               host */
 +      ret = VIR_DOMAIN_RUNNING_MIGRATED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STARTED_RESTORED: /* Restored from a state file */
 +      ret = VIR_DOMAIN_RUNNING_RESTORED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: /* Restored from snapshot */
 +      ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT;
 +      break;
 +#ifdef HAVE_DOM_REASON_RUNNING_WAKEUP
 +    case VIR_DOMAIN_EVENT_STARTED_WAKEUP: /* Started due to wakeup event */
 +      ret = VIR_DOMAIN_RUNNING_WAKEUP;
 +      break;
 +#endif
 +    default:
 +      ret = VIR_DOMAIN_RUNNING_UNKNOWN;
 +    }
 +    break;
 +  case VIR_DOMAIN_EVENT_SUSPENDED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: /* Normal suspend due to admin
 +                                               pause */
 +      ret = VIR_DOMAIN_PAUSED_USER;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: /* Suspended for offline
 +                                                 migration */
 +      ret = VIR_DOMAIN_PAUSED_MIGRATION;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: /* Suspended due to a disk I/O
 +                                                error */
 +      ret = VIR_DOMAIN_PAUSED_IOERROR;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: /* Suspended due to a watchdog
 +                                                 firing */
 +      ret = VIR_DOMAIN_PAUSED_WATCHDOG;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: /* Restored from paused state
 +                                                 file */
 +      ret = VIR_DOMAIN_PAUSED_UNKNOWN;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: /* Restored from paused
 +                                                      snapshot */
 +      ret = VIR_DOMAIN_PAUSED_FROM_SNAPSHOT;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: /* Suspended after failure during
 +                                                  libvirt API call */
 +      ret = VIR_DOMAIN_PAUSED_UNKNOWN;
 +      break;
 +#ifdef HAVE_DOM_REASON_POSTCOPY
 +    case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY: /* Suspended for post-copy
 +                                                 migration */
 +      ret = VIR_DOMAIN_PAUSED_POSTCOPY;
 +      break;
 +    case VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY_FAILED: /* Suspended after failed
 +                                                        post-copy */
 +      ret = VIR_DOMAIN_PAUSED_POSTCOPY_FAILED;
 +      break;
 +#endif
 +    default:
 +      ret = VIR_DOMAIN_PAUSED_UNKNOWN;
 +    }
 +    break;
 +  case VIR_DOMAIN_EVENT_RESUMED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: /* Normal resume due to admin
 +                                               unpause */
 +      ret = VIR_DOMAIN_RUNNING_UNPAUSED;
 +      break;
 +    case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: /* Resumed for completion of
 +                                               migration */
 +      ret = VIR_DOMAIN_RUNNING_MIGRATED;
 +      break;
 +    case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: /* Resumed from snapshot */
 +      ret = VIR_DOMAIN_RUNNING_FROM_SNAPSHOT;
 +      break;
 +#ifdef HAVE_DOM_REASON_POSTCOPY
 +    case VIR_DOMAIN_EVENT_RESUMED_POSTCOPY: /* Resumed, but migration is still
 +                                               running in post-copy mode */
 +      ret = VIR_DOMAIN_RUNNING_POSTCOPY;
 +      break;
 +#endif
 +    default:
 +      ret = VIR_DOMAIN_RUNNING_UNKNOWN;
 +    }
 +    break;
 +  case VIR_DOMAIN_EVENT_STOPPED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN: /* Normal shutdown */
 +      ret = VIR_DOMAIN_SHUTOFF_SHUTDOWN;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_DESTROYED: /* Forced poweroff from host */
 +      ret = VIR_DOMAIN_SHUTOFF_DESTROYED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_CRASHED: /* Guest crashed */
 +      ret = VIR_DOMAIN_SHUTOFF_CRASHED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_MIGRATED: /* Migrated off to another host */
 +      ret = VIR_DOMAIN_SHUTOFF_MIGRATED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_SAVED: /* Saved to a state file */
 +      ret = VIR_DOMAIN_SHUTOFF_SAVED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_FAILED: /* Host emulator/mgmt failed */
 +      ret = VIR_DOMAIN_SHUTOFF_FAILED;
 +      break;
 +    case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT: /* Offline snapshot loaded */
 +      ret = VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT;
 +      break;
 +    default:
 +      ret = VIR_DOMAIN_SHUTOFF_UNKNOWN;
 +    }
 +    break;
 +  case VIR_DOMAIN_EVENT_SHUTDOWN:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown
 +                                                sequence */
 +      ret = VIR_DOMAIN_SHUTDOWN_USER;
 +      break;
 +    default:
 +      ret = VIR_DOMAIN_SHUTDOWN_UNKNOWN;
 +    }
 +    break;
 +#ifdef HAVE_DOM_STATE_PMSUSPENDED
 +  case VIR_DOMAIN_EVENT_PMSUSPENDED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: /* Guest was PM suspended to
 +                                                 memory */
 +      ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN;
 +      break;
 +    case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: /* Guest was PM suspended to disk */
 +      ret = VIR_DOMAIN_PMSUSPENDED_DISK_UNKNOWN;
 +      break;
 +    default:
 +      ret = VIR_DOMAIN_PMSUSPENDED_UNKNOWN;
 +    }
 +    break;
 +#endif
 +  case VIR_DOMAIN_EVENT_CRASHED:
 +    switch (detail) {
 +    case VIR_DOMAIN_EVENT_CRASHED_PANICKED: /* Guest was panicked */
 +      ret = VIR_DOMAIN_CRASHED_PANICKED;
 +      break;
 +    default:
 +      ret = VIR_DOMAIN_CRASHED_UNKNOWN;
 +    }
 +    break;
 +  default:
 +    ret = VIR_DOMAIN_NOSTATE_UNKNOWN;
 +  }
 +  return ret;
 +}
 +
  #define DOMAIN_STATE_REASON_MAX_SIZE 20
  const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = {
          [VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] =
          [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] =
              "running in post-copy migration mode",
  #endif
 -
          [VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] =
              "the reason is unknown",
  
          [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] =
              "paused after failed post-copy",
  #endif
 -
          [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] =
              "the reason is unknown",
          [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] =
    } while (0)
  
  /* Connection. */
 -static virConnectPtr conn = 0;
 -static char *conn_string = NULL;
 +static virConnectPtr conn;
 +static char *conn_string;
  static c_complain_t conn_complain = C_COMPLAIN_INIT_STATIC;
  
  /* Node information required for %CPU */
@@@ -479,11 -252,11 +479,11 @@@ static virNodeInfo nodeinfo
  static int interval = 60;
  
  /* List of domains, if specified. */
 -static ignorelist_t *il_domains = NULL;
 +static ignorelist_t *il_domains;
  /* List of block devices, if specified. */
 -static ignorelist_t *il_block_devices = NULL;
 +static ignorelist_t *il_block_devices;
  /* List of network interface devices, if specified. */
 -static ignorelist_t *il_interface_devices = NULL;
 +static ignorelist_t *il_interface_devices;
  
  static int ignore_device_match(ignorelist_t *, const char *domname,
                                 const char *devpath);
@@@ -505,7 -278,6 +505,7 @@@ struct interface_device 
  typedef struct domain_s {
    virDomainPtr ptr;
    virDomainInfo info;
 +  bool active;
  } domain_t;
  
  struct lv_read_state {
  };
  
  static void free_domains(struct lv_read_state *state);
 -static int add_domain(struct lv_read_state *state, virDomainPtr dom);
 +static int add_domain(struct lv_read_state *state, virDomainPtr dom,
 +                      bool active);
  
  static void free_block_devices(struct lv_read_state *state);
  static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
@@@ -630,7 -401,7 +630,7 @@@ static const struct ex_stats_item ex_st
  };
  
  /* BlockDeviceFormatBasename */
 -_Bool blockdevice_format_basename = 0;
 +static bool blockdevice_format_basename;
  static enum bd_field blockdevice_format = target;
  static enum if_field interface_format = if_name;
  
@@@ -639,12 -410,6 +639,6 @@@ static time_t last_refresh = (time_t)0
  
  static int refresh_lists(struct lv_read_instance *inst);
  
- struct lv_info {
-   virDomainInfo di;
-   unsigned long long total_user_cpu_time;
-   unsigned long long total_syst_cpu_time;
- };
  struct lv_block_info {
    virDomainBlockStatsStruct bi;
  
@@@ -708,60 -473,11 +702,10 @@@ static int get_block_info(struct lv_blo
      virErrorPtr err;                                                           \
      err = (conn) ? virConnGetLastError((conn)) : virGetLastError();            \
      if (err)                                                                   \
-       ERROR("%s: %s", (s), err->message);                                      \
+       ERROR(PLUGIN_NAME " plugin: %s failed: %s", (s), err->message);          \
    } while (0)
  
- static void init_lv_info(struct lv_info *info) {
-   if (info != NULL)
-     memset(info, 0, sizeof(*info));
- }
- static int lv_domain_info(virDomainPtr dom, struct lv_info *info) {
- #ifdef HAVE_CPU_STATS
-   virTypedParameterPtr param = NULL;
-   int nparams = 0;
- #endif /* HAVE_CPU_STATS */
-   int ret = virDomainGetInfo(dom, &(info->di));
-   if (ret != 0) {
-     return ret;
-   }
- #ifdef HAVE_CPU_STATS
-   nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
-   if (nparams < 0) {
-     VIRT_ERROR(conn, "getting the CPU params count");
-     return -1;
-   }
-   param = calloc(nparams, sizeof(virTypedParameter));
-   if (param == NULL) {
-     ERROR("virt plugin: alloc(%i) for cpu parameters failed.", nparams);
-     return -1;
-   }
-   ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats.
-   if (ret < 0) {
-     virTypedParamsClear(param, nparams);
-     sfree(param);
-     VIRT_ERROR(conn, "getting the disk params values");
-     return -1;
-   }
-   for (int i = 0; i < nparams; ++i) {
-     if (!strcmp(param[i].field, "user_time"))
-       info->total_user_cpu_time = param[i].value.ul;
-     else if (!strcmp(param[i].field, "system_time"))
-       info->total_syst_cpu_time = param[i].value.ul;
-   }
-   virTypedParamsClear(param, nparams);
-   sfree(param);
- #endif /* HAVE_CPU_STATS */
-   return 0;
- }
  static void init_value_list(value_list_t *vl, virDomainPtr dom) {
 -  int n;
    const char *name;
    char uuid[VIR_UUID_STRING_BUFLEN];
  
      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--;
 -    }
 +    if (i > 0)
 +      SSTRNCAT(vl->host, ":", sizeof(vl->host));
  
      switch (hostname_format[i]) {
      case hf_none:
        break;
      case hf_hostname:
 -      strncat(vl->host, hostname_g, n);
 +      SSTRNCAT(vl->host, hostname_g, sizeof(vl->host));
        break;
      case hf_name:
        name = virDomainGetName(dom);
        if (name)
 -        strncat(vl->host, name, n);
 +        SSTRNCAT(vl->host, name, sizeof(vl->host));
        break;
      case hf_uuid:
        if (virDomainGetUUIDString(dom, uuid) == 0)
 -        strncat(vl->host, uuid, n);
 +        SSTRNCAT(vl->host, uuid, sizeof(vl->host));
        break;
      }
    }
  
 -  vl->host[sizeof(vl->host) - 1] = '\0';
 -
    /* Construct the plugin instance field according to PluginInstanceFormat. */
    for (int 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--;
 -    }
 +    if (i > 0)
 +      SSTRNCAT(vl->plugin_instance, ":", sizeof(vl->plugin_instance));
  
      switch (plugin_instance_format[i]) {
      case plginst_none:
      case plginst_name:
        name = virDomainGetName(dom);
        if (name)
 -        strncat(vl->plugin_instance, name, n);
 +        SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance));
        break;
      case plginst_uuid:
        if (virDomainGetUUIDString(dom, uuid) == 0)
 -        strncat(vl->plugin_instance, uuid, n);
 +        SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance));
        break;
      }
    }
  
 -  vl->plugin_instance[sizeof(vl->plugin_instance) - 1] = '\0';
 -
  } /* void init_value_list */
  
  static int init_notif(notification_t *notif, const virDomainPtr domain,
@@@ -892,14 -620,6 +836,6 @@@ static void submit_derive2(const char *
    submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values));
  } /* void submit_derive2 */
  
- static void pcpu_submit(virDomainPtr dom, struct lv_info *info) {
- #ifdef HAVE_CPU_STATS
-   if (extra_stats & ex_stats_pcpu)
-     submit_derive2("ps_cputime", info->total_user_cpu_time,
-                    info->total_syst_cpu_time, dom, NULL);
- #endif /* HAVE_CPU_STATS */
- }
  static double cpu_ns_to_percent(unsigned int node_cpus,
                                  unsigned long long cpu_time_old,
                                  unsigned long long cpu_time_new) {
                (time_diff_sec * node_cpus * NANOSEC_IN_SEC);
    }
  
 -  DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%llu cpu_time_new=%llu"
 -                    "cpu_time_diff=%llu time_diff_sec=%f percent=%f",
 -        node_cpus, cpu_time_old, cpu_time_new, cpu_time_diff, time_diff_sec,
 -        percent);
 +  DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%" PRIu64
 +                    " cpu_time_new=%" PRIu64 "cpu_time_diff=%" PRIu64
 +                    " time_diff_sec=%f percent=%f",
 +        node_cpus, (uint64_t)cpu_time_old, (uint64_t)cpu_time_new,
 +        (uint64_t)cpu_time_diff, time_diff_sec, percent);
  
    return percent;
  }
@@@ -1015,8 -734,9 +951,8 @@@ static unsigned int parse_ex_stats_flag
    return ex_stats_flags;
  }
  
 -static void domain_state_submit(virDomainPtr dom, int state, int reason) {
 -
 -  if ((state < 0) || (state >= STATIC_ARRAY_SIZE(domain_states))) {
 +static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) {
 +  if ((state < 0) || ((size_t)state >= STATIC_ARRAY_SIZE(domain_states))) {
      ERROR(PLUGIN_NAME ": Array index out of bounds: state=%d", state);
      return;
    }
    char msg[DATA_MAX_NAME_LEN];
    const char *state_str = domain_states[state];
  #ifdef HAVE_DOM_REASON
 -  if ((reason < 0) || (reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) {
 +  if ((reason < 0) ||
 +      ((size_t)reason >= STATIC_ARRAY_SIZE(domain_reasons[0]))) {
      ERROR(PLUGIN_NAME ": Array index out of bounds: reason=%d", reason);
      return;
    }
@@@ -1124,7 -843,7 +1060,7 @@@ static int lv_config(const char *key, c
      return 0;
    }
    if (strcasecmp(key, "BlockDeviceFormatBasename") == 0) {
 -    blockdevice_format_basename = IS_TRUE(value);
 +    blockdevice_format_basename = IS_TRUE(value) ? true : false;
      return 0;
    }
    if (strcasecmp(key, "InterfaceDevice") == 0) {
      }
    }
  
 +  if (strcasecmp(key, "PersistentNotification") == 0) {
 +    persistent_notification = IS_TRUE(value);
 +    return 0;
 +  }
 +
    /* Unrecognised option. */
    return -1;
  }
@@@ -1398,7 -1112,7 +1334,7 @@@ static void vcpu_pin_submit(virDomainPt
                              unsigned char *cpu_maps, int cpu_map_len) {
    for (int cpu = 0; cpu < max_cpus; ++cpu) {
      char type_instance[DATA_MAX_NAME_LEN];
 -    _Bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu) ? 1 : 0;
 +    bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu);
  
      snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu);
      submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1);
@@@ -1411,13 -1125,13 +1347,13 @@@ static int get_vcpu_stats(virDomainPtr 
  
    virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(vinfo[0]));
    if (vinfo == NULL) {
-     ERROR(PLUGIN_NAME " plugin: malloc failed.");
+     ERROR(PLUGIN_NAME " plugin: calloc failed.");
      return -1;
    }
  
    unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len);
    if (cpumaps == NULL) {
-     ERROR(PLUGIN_NAME " plugin: malloc failed.");
+     ERROR(PLUGIN_NAME " plugin: calloc failed.");
      sfree(vinfo);
      return -1;
    }
    return 0;
  }
  
+ #ifdef HAVE_CPU_STATS
+ static int get_pcpu_stats(virDomainPtr dom) {
+   int nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
+   if (nparams < 0) {
+     VIRT_ERROR(conn, "getting the CPU params count");
+     return -1;
+   }
+   virTypedParameterPtr param = calloc(nparams, sizeof(virTypedParameter));
+   if (param == NULL) {
+     ERROR(PLUGIN_NAME " plugin: alloc(%i) for cpu parameters failed.", nparams);
+     return -1;
+   }
+   int ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats.
+   if (ret < 0) {
+     virTypedParamsClear(param, nparams);
+     sfree(param);
+     VIRT_ERROR(conn, "getting the CPU params values");
+     return -1;
+   }
+   unsigned long long total_user_cpu_time = 0;
+   unsigned long long total_syst_cpu_time = 0;
+   for (int i = 0; i < nparams; ++i) {
+     if (!strcmp(param[i].field, "user_time"))
+       total_user_cpu_time = param[i].value.ul;
+     else if (!strcmp(param[i].field, "system_time"))
+       total_syst_cpu_time = param[i].value.ul;
+   }
+   if (total_user_cpu_time > 0 || total_syst_cpu_time > 0)
+     submit_derive2("ps_cputime", total_user_cpu_time, total_syst_cpu_time, dom,
+                    NULL);
+   virTypedParamsClear(param, nparams);
+   sfree(param);
+   return 0;
+ }
+ #endif /* HAVE_CPU_STATS */
  #ifdef HAVE_DOM_REASON
 +
 +static void domain_state_submit(virDomainPtr dom, int state, int reason) {
 +  value_t values[] = {
 +      {.gauge = (gauge_t)state}, {.gauge = (gauge_t)reason},
 +  };
 +
 +  submit(dom, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
 +}
 +
  static int get_domain_state(virDomainPtr domain) {
    int domain_state = 0;
    int domain_reason = 0;
    }
  
    domain_state_submit(domain, domain_state, domain_reason);
 +
    return status;
  }
 +
 +#ifdef HAVE_LIST_ALL_DOMAINS
 +static int get_domain_state_notify(virDomainPtr domain) {
 +  int domain_state = 0;
 +  int domain_reason = 0;
 +
 +  int status = virDomainGetState(domain, &domain_state, &domain_reason, 0);
 +  if (status != 0) {
 +    ERROR(PLUGIN_NAME " plugin: virDomainGetState failed with status %i.",
 +          status);
 +    return status;
 +  }
 +
 +  if (persistent_notification)
 +    domain_state_submit_notif(domain, domain_state, domain_reason);
 +
 +  return status;
 +}
 +#endif /* HAVE_LIST_ALL_DOMAINS */
  #endif /* HAVE_DOM_REASON */
  
  static int get_memory_stats(virDomainPtr domain) {
@@@ -1585,7 -1313,7 +1564,7 @@@ static int get_block_stats(struct block
  
  #define NM_ADD_STR_ITEMS(_items, _size)                                        \
    do {                                                                         \
 -    for (int _i = 0; _i < _size; ++_i) {                                       \
 +    for (size_t _i = 0; _i < _size; ++_i) {                                    \
        DEBUG(PLUGIN_NAME                                                        \
              " plugin: Adding notification metadata name=%s value=%s",          \
              _items[_i].name, _items[_i].value);                                \
@@@ -1610,7 -1338,7 +1589,7 @@@ static int fs_info_notify(virDomainPtr 
        {.name = "name", .value = fs_info->name},
        {.name = "fstype", .value = fs_info->fstype}};
  
 -  for (int i = 0; i < fs_info->ndevAlias; ++i) {
 +  for (size_t i = 0; i < fs_info->ndevAlias; ++i) {
      fs_dev_alias[i].name = "devAlias";
      fs_dev_alias[i].value = fs_info->devAlias[i];
    }
@@@ -1716,15 -1444,13 +1695,13 @@@ static int get_job_stats(virDomainPtr d
  #endif /* HAVE_JOB_STATS */
  
  static int get_domain_metrics(domain_t *domain) {
-   struct lv_info info;
    if (!domain || !domain->ptr) {
-     ERROR(PLUGIN_NAME ": get_domain_metrics: NULL pointer");
+     ERROR(PLUGIN_NAME "plugin: get_domain_metrics: NULL pointer");
      return -1;
    }
  
-   init_lv_info(&info);
-   int status = lv_domain_info(domain->ptr, &info);
+   virDomainInfo info;
+   int status = virDomainGetInfo(domain->ptr, &info);
    if (status != 0) {
      ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
            status);
       * We need to get it from virDomainGetState.
       */
      GET_STATS(get_domain_state, "domain reason", domain->ptr);
 -#else
 -    /* virDomainGetState is not available. Submit 0, which corresponds to
 -     * unknown reason. */
 -    domain_state_submit(domain->ptr, info.state, 0);
  #endif
    }
  
    /* Gather remaining stats only for running domains */
-   if (info.di.state != VIR_DOMAIN_RUNNING)
+   if (info.state != VIR_DOMAIN_RUNNING)
      return 0;
  
-   pcpu_submit(domain->ptr, &info);
-   cpu_submit(domain, info.di.cpuTime);
+ #ifdef HAVE_CPU_STATS
+   if (extra_stats & ex_stats_pcpu)
+     get_pcpu_stats(domain->ptr);
+ #endif
+   cpu_submit(domain, info.cpuTime);
  
-   memory_submit(domain->ptr, (gauge_t)info.di.memory * 1024);
+   memory_submit(domain->ptr, (gauge_t)info.memory * 1024);
  
-   GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.di.nrVirtCpu);
+   GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
    GET_STATS(get_memory_stats, "memory stats", domain->ptr);
  
  #ifdef HAVE_PERF_STATS
  #endif
  
    /* Update cached virDomainInfo. It has to be done after cpu_submit */
-   memcpy(&domain->info, &info.di, sizeof(domain->info));
+   memcpy(&domain->info, &info, sizeof(domain->info));
 +
    return 0;
  }
  
@@@ -1825,192 -1558,6 +1806,192 @@@ static int get_if_dev_stats(struct inte
    return 0;
  }
  
 +static int domain_lifecycle_event_cb(__attribute__((unused)) virConnectPtr con_,
 +                                     virDomainPtr dom, int event, int detail,
 +                                     __attribute__((unused)) void *opaque) {
 +  int domain_state = map_domain_event_to_state(event);
 +  int domain_reason = 0; /* 0 means UNKNOWN reason for any state */
 +#ifdef HAVE_DOM_REASON
 +  domain_reason = map_domain_event_detail_to_reason(event, detail);
 +#endif
 +  domain_state_submit_notif(dom, domain_state, domain_reason);
 +
 +  return 0;
 +}
 +
 +static int register_event_impl(void) {
 +  if (virEventRegisterDefaultImpl() < 0) {
 +    virErrorPtr err = virGetLastError();
 +    ERROR(PLUGIN_NAME
 +          " plugin: error while event implementation registering: %s",
 +          err && err->message ? err->message : "Unknown error");
 +    return -1;
 +  }
 +
 +  return 0;
 +}
 +
 +static void virt_notif_thread_set_active(virt_notif_thread_t *thread_data,
 +                                         const bool active) {
 +  assert(thread_data != NULL);
 +  pthread_mutex_lock(&thread_data->active_mutex);
 +  thread_data->is_active = active;
 +  pthread_mutex_unlock(&thread_data->active_mutex);
 +}
 +
 +static bool virt_notif_thread_is_active(virt_notif_thread_t *thread_data) {
 +  bool active = false;
 +
 +  assert(thread_data != NULL);
 +  pthread_mutex_lock(&thread_data->active_mutex);
 +  active = thread_data->is_active;
 +  pthread_mutex_unlock(&thread_data->active_mutex);
 +
 +  return active;
 +}
 +
 +/* worker function running default event implementation */
 +static void *event_loop_worker(void *arg) {
 +  virt_notif_thread_t *thread_data = (virt_notif_thread_t *)arg;
 +
 +  while (virt_notif_thread_is_active(thread_data)) {
 +    if (virEventRunDefaultImpl() < 0) {
 +      virErrorPtr err = virGetLastError();
 +      ERROR(PLUGIN_NAME " plugin: failed to run event loop: %s\n",
 +            err && err->message ? err->message : "Unknown error");
 +    }
 +  }
 +
 +  return NULL;
 +}
 +
 +static int virt_notif_thread_init(virt_notif_thread_t *thread_data) {
 +  int ret;
 +
 +  assert(thread_data != NULL);
 +  ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
 +  if (ret != 0) {
 +    ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret);
 +    return ret;
 +  }
 +
 +  /**
 +   * '0' and positive integers are meaningful ID's, therefore setting
 +   * domain_event_cb_id to '-1'
 +   */
 +  thread_data->domain_event_cb_id = -1;
 +  pthread_mutex_lock(&thread_data->active_mutex);
 +  thread_data->is_active = false;
 +  pthread_mutex_unlock(&thread_data->active_mutex);
 +
 +  return 0;
 +}
 +
 +/* register domain event callback and start event loop thread */
 +static int start_event_loop(virt_notif_thread_t *thread_data) {
 +  assert(thread_data != NULL);
 +  thread_data->domain_event_cb_id = virConnectDomainEventRegisterAny(
 +      conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE,
 +      VIR_DOMAIN_EVENT_CALLBACK(domain_lifecycle_event_cb), NULL, NULL);
 +  if (thread_data->domain_event_cb_id == -1) {
 +    ERROR(PLUGIN_NAME " plugin: error while callback registering");
 +    return -1;
 +  }
 +
 +  virt_notif_thread_set_active(thread_data, 1);
 +  if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker,
 +                     thread_data)) {
 +    ERROR(PLUGIN_NAME " plugin: failed event loop thread creation");
 +    virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
 +    return -1;
 +  }
 +
 +  return 0;
 +}
 +
 +/* stop event loop thread and deregister callback */
 +static void stop_event_loop(virt_notif_thread_t *thread_data) {
 +  /* stopping loop and de-registering event handler*/
 +  virt_notif_thread_set_active(thread_data, 0);
 +  if (conn != NULL && thread_data->domain_event_cb_id != -1)
 +    virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
 +
 +  if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
 +    ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
 +}
 +
 +static int persistent_domains_state_notification(void) {
 +  int status = 0;
 +  int n;
 +#ifdef HAVE_LIST_ALL_DOMAINS
 +  virDomainPtr *domains = NULL;
 +  n = virConnectListAllDomains(conn, &domains,
 +                               VIR_CONNECT_LIST_DOMAINS_PERSISTENT);
 +  if (n < 0) {
 +    VIRT_ERROR(conn, "reading list of persistent domains");
 +    status = -1;
 +  } else {
 +    DEBUG(PLUGIN_NAME " plugin: getting state of %i persistent domains", n);
 +    /* Fetch each persistent domain's state and notify it */
 +    int n_notified = n;
 +    for (int i = 0; i < n; ++i) {
 +      status = get_domain_state_notify(domains[i]);
 +      if (status != 0) {
 +        n_notified--;
 +        ERROR(PLUGIN_NAME " plugin: could not notify state of domain %s",
 +              virDomainGetName(domains[i]));
 +      }
 +      virDomainFree(domains[i]);
 +    }
 +
 +    sfree(domains);
 +    DEBUG(PLUGIN_NAME " plugin: notified state of %i persistent domains",
 +          n_notified);
 +  }
 +#else
 +  n = virConnectNumOfDomains(conn);
 +  if (n > 0) {
 +    int *domids;
 +    /* Get list of domains. */
 +    domids = calloc(n, sizeof(*domids));
 +    if (domids == NULL) {
 +      ERROR(PLUGIN_NAME " plugin: calloc failed.");
 +      return -1;
 +    }
 +    n = virConnectListDomains(conn, domids, n);
 +    if (n < 0) {
 +      VIRT_ERROR(conn, "reading list of domains");
 +      sfree(domids);
 +      return -1;
 +    }
 +    /* Fetch info of each active domain and notify it */
 +    for (int i = 0; i < n; ++i) {
 +      virDomainInfo info;
 +      virDomainPtr dom = NULL;
 +      dom = virDomainLookupByID(conn, domids[i]);
 +      if (dom == NULL) {
 +        VIRT_ERROR(conn, "virDomainLookupByID");
 +        /* Could be that the domain went away -- ignore it anyway. */
 +        continue;
 +      }
 +      status = virDomainGetInfo(dom, &info);
 +      if (status == 0)
 +        /* virDomainGetState is not available. Submit 0, which corresponds to
 +         * unknown reason. */
 +        domain_state_submit_notif(dom, info.state, 0);
 +      else
 +        ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
 +              status);
 +
 +      virDomainFree(dom);
 +    }
 +    sfree(domids);
 +  }
 +#endif
 +
 +  return status;
 +}
 +
  static int lv_read(user_data_t *ud) {
    time_t t;
    struct lv_read_instance *inst = NULL;
    inst = ud->data;
    state = &inst->read_state;
  
 +  bool reconnect = conn == NULL ? true : false;
 +  /* event implementation must be registered before connection is opened */
    if (inst->id == 0) {
 +    if (!persistent_notification && reconnect)
 +      if (register_event_impl() != 0)
 +        return -1;
 +
      if (lv_connect() < 0)
        return -1;
 +
 +    if (!persistent_notification && reconnect && conn != NULL)
 +      if (start_event_loop(&notif_thread) != 0)
 +        return -1;
    }
  
    time(&t);
    if ((last_refresh == (time_t)0) ||
        ((interval > 0) && ((last_refresh + interval) <= t))) {
      if (refresh_lists(inst) != 0) {
 -      if (inst->id == 0)
 +      if (inst->id == 0) {
 +        if (!persistent_notification)
 +          stop_event_loop(&notif_thread);
          lv_disconnect();
 +      }
        return -1;
      }
      last_refresh = t;
    }
  
 -#if 0
 -    for (int i = 0; i < nr_domains; ++i)
 -        fprintf (stderr, "domain %s\n", virDomainGetName (state->domains[i].ptr));
 -    for (int 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 (int 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);
 +  /* persistent domains state notifications are handled by instance 0 */
 +  if (inst->id == 0 && persistent_notification) {
 +    int status = persistent_domains_state_notification();
 +    if (status != 0)
 +      DEBUG(PLUGIN_NAME " plugin: persistent_domains_state_notifications "
 +                        "returned with status %i",
 +            status);
 +  }
 +
 +#if COLLECT_DEBUG
 +  for (int i = 0; i < state->nr_domains; ++i)
 +    DEBUG(PLUGIN_NAME " plugin: domain %s",
 +          virDomainGetName(state->domains[i].ptr));
 +  for (int i = 0; i < state->nr_block_devices; ++i)
 +    DEBUG(PLUGIN_NAME " plugin: block device %d %s:%s", i,
 +          virDomainGetName(state->block_devices[i].dom),
 +          state->block_devices[i].path);
 +  for (int i = 0; i < state->nr_interface_devices; ++i)
 +    DEBUG(PLUGIN_NAME " plugin: interface device %d %s:%s", i,
 +          virDomainGetName(state->interface_devices[i].dom),
 +          state->interface_devices[i].path);
  #endif
  
    /* Get domains' metrics */
    for (int i = 0; i < state->nr_domains; ++i) {
 -    int status = get_domain_metrics(&state->domains[i]);
 +    domain_t *dom = &state->domains[i];
 +    int status = 0;
 +    if (dom->active)
 +      status = get_domain_metrics(dom);
 +#ifdef HAVE_DOM_REASON
 +    else
 +      status = get_domain_state(dom->ptr);
 +#endif
 +
      if (status != 0)
        ERROR(PLUGIN_NAME " failed to get metrics for domain=%s",
 -            virDomainGetName(state->domains[i].ptr));
 +            virDomainGetName(dom->ptr));
    }
  
    /* Get block device stats for each domain. */
@@@ -2123,7 -1639,7 +2104,7 @@@ static int lv_init_instance(size_t i, p
  
    memset(lv_ud, 0, sizeof(*lv_ud));
  
 -  snprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i);
 +  snprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
    inst->id = i;
  
    user_data_t *ud = &(lv_ud->ud);
    ud->free_func = NULL;
  
    INFO(PLUGIN_NAME " plugin: reader %s initialized", inst->tag);
 +
    return plugin_register_complex_read(NULL, inst->tag, callback, 0, ud);
  }
  
@@@ -2146,7 -1661,6 +2127,7 @@@ static void lv_fini_instance(size_t i) 
    struct lv_read_state *state = &(inst->read_state);
  
    lv_clean_read_state(state);
 +
    INFO(PLUGIN_NAME " plugin: reader %s finalized", inst->tag);
  }
  
@@@ -2154,27 -1668,13 +2135,27 @@@ static int lv_init(void) 
    if (virInitialize() != 0)
      return -1;
  
 +  /* event implementation must be registered before connection is opened */
 +  if (!persistent_notification)
 +    if (register_event_impl() != 0)
 +      return -1;
 +
    if (lv_connect() != 0)
      return -1;
  
 +  DEBUG(PLUGIN_NAME " plugin: starting event loop");
 +
 +  if (!persistent_notification) {
 +    virt_notif_thread_init(&notif_thread);
 +    if (start_event_loop(&notif_thread) != 0)
 +      return -1;
 +  }
 +
    DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
  
    for (int i = 0; i < nr_instances; ++i)
 -    lv_init_instance(i, lv_read);
 +    if (lv_init_instance(i, lv_read) != 0)
 +      return -1;
  
    return 0;
  }
@@@ -2273,247 -1773,224 +2254,247 @@@ static int lv_instance_include_domain(s
    return 0;
  }
  
 -/*
 -  virConnectListAllDomains() appeared in 0.10.2
 -  Note that LIBVIR_CHECK_VERSION appeared a year later, so
 -  in some systems which actually have virConnectListAllDomains()
 -  we can't detect this.
 - */
 -#ifdef LIBVIR_CHECK_VERSION
 -#if LIBVIR_CHECK_VERSION(0, 10, 2)
 -#define HAVE_LIST_ALL_DOMAINS 1
 -#endif
 -#endif
 -
  static int refresh_lists(struct lv_read_instance *inst) {
    struct lv_read_state *state = &inst->read_state;
    int n;
  
 +#ifndef HAVE_LIST_ALL_DOMAINS
    n = virConnectNumOfDomains(conn);
    if (n < 0) {
      VIRT_ERROR(conn, "reading number of domains");
      return -1;
    }
 +#endif
  
    lv_clean_read_state(state);
  
 -  if (n > 0) {
 +#ifndef HAVE_LIST_ALL_DOMAINS
 +  if (n == 0)
 +    goto end;
 +#endif
 +
  #ifdef HAVE_LIST_ALL_DOMAINS
 -    virDomainPtr *domains;
 -    n = virConnectListAllDomains(conn, &domains,
 -                                 VIR_CONNECT_LIST_DOMAINS_ACTIVE);
 +  virDomainPtr *domains, *domains_inactive;
 +  int m = virConnectListAllDomains(conn, &domains_inactive,
 +                                   VIR_CONNECT_LIST_DOMAINS_INACTIVE);
 +  n = virConnectListAllDomains(conn, &domains, VIR_CONNECT_LIST_DOMAINS_ACTIVE);
  #else
 -    int *domids;
 +  int *domids;
  
 -    /* Get list of domains. */
 -    domids = malloc(sizeof(*domids) * n);
 -    if (domids == NULL) {
 -      ERROR(PLUGIN_NAME " plugin: malloc failed.");
 -      return -1;
 -    }
 +  /* Get list of domains. */
 +  domids = calloc(n, sizeof(*domids));
 +  if (domids == NULL) {
 +    ERROR(PLUGIN_NAME " plugin: calloc failed.");
 +    return -1;
 +  }
  
 -    n = virConnectListDomains(conn, domids, n);
 +  n = virConnectListDomains(conn, domids, n);
  #endif
  
 -    if (n < 0) {
 -      VIRT_ERROR(conn, "reading list of domains");
 +  if (n < 0) {
 +    VIRT_ERROR(conn, "reading list of domains");
  #ifndef HAVE_LIST_ALL_DOMAINS
 -      sfree(domids);
 +    sfree(domids);
 +#else
 +    for (int i = 0; i < m; ++i)
 +      virDomainFree(domains_inactive[i]);
 +    sfree(domains_inactive);
  #endif
 -      return -1;
 +    return -1;
 +  }
 +
 +#ifdef HAVE_LIST_ALL_DOMAINS
 +  for (int i = 0; i < m; ++i)
 +    if (add_domain(state, domains_inactive[i], 0) < 0) {
 +      ERROR(PLUGIN_NAME " plugin: malloc failed.");
 +      virDomainFree(domains_inactive[i]);
 +      domains_inactive[i] = NULL;
 +      continue;
      }
 +#endif
  
 -    /* Fetch each domain and add it to the list, unless ignore. */
 -    for (int i = 0; i < n; ++i) {
 -      const char *name;
 -      char *xml = NULL;
 -      xmlDocPtr xml_doc = NULL;
 -      xmlXPathContextPtr xpath_ctx = NULL;
 -      xmlXPathObjectPtr xpath_obj = NULL;
 -      char tag[PARTITION_TAG_MAX_LEN] = {'\0'};
 -      virDomainInfo info;
 -      int status;
 +  /* Fetch each domain and add it to the list, unless ignore. */
 +  for (int i = 0; i < n; ++i) {
 +    const char *name;
 +    char *xml = NULL;
 +    xmlDocPtr xml_doc = NULL;
 +    xmlXPathContextPtr xpath_ctx = NULL;
 +    xmlXPathObjectPtr xpath_obj = NULL;
 +    char tag[PARTITION_TAG_MAX_LEN] = {'\0'};
 +    virDomainInfo info;
 +    int status;
  
  #ifdef HAVE_LIST_ALL_DOMAINS
 -      virDomainPtr dom = domains[i];
 +    virDomainPtr dom = domains[i];
  #else
 -      virDomainPtr dom = NULL;
 -      dom = virDomainLookupByID(conn, domids[i]);
 -      if (dom == NULL) {
 -        VIRT_ERROR(conn, "virDomainLookupByID");
 -        /* Could be that the domain went away -- ignore it anyway. */
 -        continue;
 -      }
 +    virDomainPtr dom = NULL;
 +    dom = virDomainLookupByID(conn, domids[i]);
 +    if (dom == NULL) {
 +      VIRT_ERROR(conn, "virDomainLookupByID");
 +      /* Could be that the domain went away -- ignore it anyway. */
 +      continue;
 +    }
  #endif
  
 -      name = virDomainGetName(dom);
 -      if (name == NULL) {
 -        VIRT_ERROR(conn, "virDomainGetName");
 -        goto cont;
 -      }
 +    if (add_domain(state, dom, 1) < 0) {
 +      /*
 +       * When domain is already tracked, then there is
 +       * no problem with memory handling (will be freed
 +       * with the rest of domains cached data)
 +       * But in case of error like this (error occurred
 +       * before adding domain to track) we have to take
 +       * care it ourselves and call virDomainFree
 +       */
 +      ERROR(PLUGIN_NAME " plugin: malloc failed.");
 +      virDomainFree(dom);
 +      goto cont;
 +    }
  
 -      status = virDomainGetInfo(dom, &info);
 -      if (status != 0) {
 -        ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
 -              status);
 -        continue;
 -      }
 +    name = virDomainGetName(dom);
 +    if (name == NULL) {
 +      VIRT_ERROR(conn, "virDomainGetName");
 +      goto cont;
 +    }
  
 -      if (info.state != VIR_DOMAIN_RUNNING) {
 -        DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name);
 -        continue;
 -      }
 +    status = virDomainGetInfo(dom, &info);
 +    if (status != 0) {
 +      ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.",
 +            status);
 +      continue;
 +    }
  
 -      if (il_domains && ignorelist_match(il_domains, name) != 0)
 -        goto cont;
 +    if (info.state != VIR_DOMAIN_RUNNING) {
 +      DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name);
 +      continue;
 +    }
  
 -      /* Get a list of devices for this domain. */
 -      xml = virDomainGetXMLDesc(dom, 0);
 -      if (!xml) {
 -        VIRT_ERROR(conn, "virDomainGetXMLDesc");
 -        goto cont;
 -      }
 +    if (il_domains && ignorelist_match(il_domains, name) != 0)
 +      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;
 -      }
 +    /* Get a list of devices for this domain. */
 +    xml = virDomainGetXMLDesc(dom, 0);
 +    if (!xml) {
 +      VIRT_ERROR(conn, "virDomainGetXMLDesc");
 +      goto cont;
 +    }
  
 -      xpath_ctx = xmlXPathNewContext(xml_doc);
 +    /* 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;
 +    }
  
 -      if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) {
 -        ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed.");
 -        goto cont;
 -      }
 +    xpath_ctx = xmlXPathNewContext(xml_doc);
  
 -      if (!lv_instance_include_domain(inst, name, tag))
 -        goto cont;
 +    if (lv_domain_get_tag(xpath_ctx, name, tag) < 0) {
 +      ERROR(PLUGIN_NAME " plugin: lv_domain_get_tag failed.");
 +      goto cont;
 +    }
  
 -      if (add_domain(state, dom) < 0) {
 -        ERROR(PLUGIN_NAME " plugin: malloc failed.");
 -        goto cont;
 -      }
 +    if (!lv_instance_include_domain(inst, name, tag))
 +      goto cont;
  
 -      /* Block devices. */
 -      const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
 -      if (blockdevice_format == source)
 -        bd_xmlpath = "/domain/devices/disk/source[@dev]";
 -      xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
 +    /* Block devices. */
 +    const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
 +    if (blockdevice_format == source)
 +      bd_xmlpath = "/domain/devices/disk/source[@dev]";
 +    xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
  
 -      if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
 -          xpath_obj->nodesetval == NULL)
 -        goto cont;
 +    if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
 +        xpath_obj->nodesetval == NULL)
 +      goto cont;
  
 -      for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
 -        xmlNodePtr node;
 -        char *path = NULL;
 +    for (int 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;
 +      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;
 +      if (il_block_devices &&
 +          ignore_device_match(il_block_devices, name, path) != 0)
 +        goto cont2;
  
 -        add_block_device(state, dom, path);
 -      cont2:
 -        if (path)
 -          xmlFree(path);
 -      }
 -      xmlXPathFreeObject(xpath_obj);
 +      add_block_device(state, 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;
  
 -      /* 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;
  
 -      xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
 +    for (int j = 0; j < xml_interfaces->nodeNr; ++j) {
 +      char *path = NULL;
 +      char *address = NULL;
 +      xmlNodePtr xml_interface;
  
 -      for (int 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;
  
 -        xml_interface = xml_interfaces->nodeTab[j];
 -        if (!xml_interface)
 +      for (xmlNodePtr child = xml_interface->children; child;
 +           child = child->next) {
 +        if (child->type != XML_ELEMENT_NODE)
            continue;
  
 -        for (xmlNodePtr child = xml_interface->children; child;
 -             child = child->next) {
 -          if (child->type != XML_ELEMENT_NODE)
 +        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 (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(state, 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);
 +      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(state, 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);
 +  }
 +
  #ifdef HAVE_LIST_ALL_DOMAINS
 -    sfree(domains);
 +  /* NOTE: domains_active and domains_inactive data will be cleared during
 +     refresh of all domains (inside lv_clean_read_state function) so we need
 +     to free here only allocated arrays */
 +  sfree(domains);
 +  sfree(domains_inactive);
  #else
 -    sfree(domids);
 +  sfree(domids);
 +
 +end:
  #endif
 -  }
  
    DEBUG(PLUGIN_NAME " plugin#%s: refreshing"
                      " domains=%i block_devices=%i iface_devices=%i",
@@@ -2533,8 -2010,7 +2514,8 @@@ static void free_domains(struct lv_read
    state->nr_domains = 0;
  }
  
 -static int add_domain(struct lv_read_state *state, virDomainPtr dom) {
 +static int add_domain(struct lv_read_state *state, virDomainPtr dom,
 +                      bool active) {
    domain_t *new_ptr;
    int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1);
  
  
    state->domains = new_ptr;
    state->domains[state->nr_domains].ptr = dom;
 +  state->domains[state->nr_domains].active = active;
    memset(&state->domains[state->nr_domains].info, 0,
           sizeof(state->domains[state->nr_domains].info));
  
@@@ -2610,7 -2085,7 +2591,7 @@@ static int add_interface_device(struct 
    struct interface_device *new_ptr;
    int new_size =
        sizeof(state->interface_devices[0]) * (state->nr_interface_devices + 1);
 -  char *path_copy, *address_copy, number_string[15];
 +  char *path_copy, *address_copy, number_string[21];
  
    if ((path == NULL) || (address == NULL))
      return EINVAL;
  static int ignore_device_match(ignorelist_t *il, const char *domname,
                                 const char *devpath) {
    char *name;
 -  int n, r;
 +  int r;
  
    if ((domname == NULL) || (devpath == NULL))
      return 0;
  
 -  n = strlen(domname) + strlen(devpath) + 2;
 +  size_t n = strlen(domname) + strlen(devpath) + 2;
    name = malloc(n);
    if (name == NULL) {
      ERROR(PLUGIN_NAME " plugin: malloc failed.");
@@@ -2671,11 -2146,6 +2652,11 @@@ static int lv_shutdown(void) 
      lv_fini_instance(i);
    }
  
 +  DEBUG(PLUGIN_NAME " plugin: stopping event loop");
 +
 +  if (!persistent_notification)
 +    stop_event_loop(&notif_thread);
 +
    lv_disconnect();
  
    ignorelist_free(il_domains);
diff --combined src/zfs_arc.c
@@@ -207,8 -207,9 +207,8 @@@ static int za_read(void) 
  
    fh = fopen(ZOL_ARCSTATS_FILE, "r");
    if (fh == NULL) {
 -    char errbuf[1024];
      ERROR("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +          STRERRNO);
      return -1;
    }
  
      return -1;
    }
  
+   // Ignore the first two lines because they contain information about
+   // the rest of the file.
+   // See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel
+   // module.
+   if (fgets(buffer, sizeof(buffer), fh) == NULL) {
+     ERROR("zfs_arc plugin: \"%s\" does not contain a single line.",
+           ZOL_ARCSTATS_FILE);
+     fclose(fh);
+     return (-1);
+   }
+   if (fgets(buffer, sizeof(buffer), fh) == NULL) {
+     ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.",
+           ZOL_ARCSTATS_FILE);
+     fclose(fh);
+     return (-1);
+   }
    while (fgets(buffer, sizeof(buffer), fh) != NULL) {
      char *fields[3];
      value_t v;