Merge branch 'collectd-5.6'
authorFlorian Forster <octo@collectd.org>
Wed, 2 Nov 2016 08:36:48 +0000 (09:36 +0100)
committerFlorian Forster <octo@collectd.org>
Wed, 2 Nov 2016 08:36:48 +0000 (09:36 +0100)
1  2 
configure.ac
src/battery.c
src/daemon/common.c
src/openvpn.c
src/powerdns.c
src/utils_format_graphite.c
src/write_kafka.c
src/zfs_arc.c

diff --combined configure.ac
  have_cpuid_h="no"
  AC_CHECK_HEADERS(cpuid.h, [have_cpuid_h="yes"])
  
- AC_CHECK_HEADERS(sys/capability.h)
+ have_capability="yes"
+ AC_CHECK_HEADERS(sys/capability.h,
+                  [have_capability="yes"],
+                  [have_capability="no (<sys/capability.h> not found)"])
+ if test "x$have_capability" = "xyes"; then
+ AC_CHECK_LIB(cap, cap_get_bound,
+                  [have_capability="yes"],
+                  [have_capability="no (cap_get_bound() not found)"])
+ fi
+ if test "x$have_capability" = "xyes"; then
+   AC_DEFINE(HAVE_CAPABILITY, 1, [Define to 1 if you have cap_get_bound() (-lcap).])
+ fi
+ AM_CONDITIONAL(BUILD_WITH_CAPABILITY, test "x$have_capability" = "xyes")
  #
  # Checks for typedefs, structures, and compiler characteristics.
  #
  fi
  # }}}
  
 +# --with-libdpdk {{{
 +AC_ARG_WITH(libdpdk, [AS_HELP_STRING([--with-libdpdk@<:@=PREFIX@:>@], [Path to the DPDK build directory.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              RTE_BUILD="$withval"
 +              with_libdpdk="yes"
 +      else
 +              RTE_BUILD="/usr"
 +              with_libdpdk="$withval"
 +      fi
 +      DPDK_INCLUDE="$RTE_BUILD/include"
 +      DPDK_LIB_DIR="$RTE_BUILD/lib"
 +      FOUND_DPDK=yes
 +], [with_libdpdk="no"])
 +
 +if test "x$with_libdpdk" = "xyes"
 +then
 +      LOCAL_DPDK_INSTALL="no"
 +      AC_CHECK_HEADER([$DPDK_INCLUDE/rte_config.h], [LOCAL_DPDK_INSTALL=yes],
 +              [AC_CHECK_HEADER([$DPDK_INCLUDE/dpdk/rte_config.h],
 +              [],
 +              [FOUND_DPDK=no], [])], [])
 +
 +      if test "x$LOCAL_DPDK_INSTALL" = "xno"
 +      then
 +              DPDK_INCLUDE=$DPDK_INCLUDE/dpdk
 +      fi
 +
 +      if test "x$FOUND_DPDK" = "xno"
 +      then
 +              AC_MSG_ERROR([libdpdk error: rte_config.h not found])
 +      fi
 +fi
 +
 +if test "x$with_libdpdk" = "xyes"
 +then
 +      SAVE_LDFLAGS="$LDFLAGS"
 +
 +      if test "x$LOCAL_DPDK_INSTALL" != "xyes"
 +      then
 +              LDFLAGS="$LDFLAGS -L$DPDK_LIB_DIR"
 +        fi
 +
 +      AC_CHECK_LIB(dpdk, rte_eal_init,
 +                     [BUILD_WITH_DPDK_LIBS="-Wl,-ldpdk"],
 +                     [FOUND_DPDK=no])
 +
 +      LDFLAGS="$SAVE_LDFLAGS"
 +      if test "x$FOUND_DPDK" = "xno"
 +      then
 +              AC_MSG_ERROR([libdpdk error: cannot link with dpdk in $DPDK_LIB_DIR])
 +      fi
 +fi
 +
 +#
 +# Note: An issue on Ubuntu 14.04 necessitates the use of -Wl,--no-as-needed:
 +# If you try compile with the older linker, the dpdk symbols will be undefined.
 +# This workaround should be removed when no longer necessary.
 +#
 +if test "x$with_libdpdk" = "xyes"
 +then
 +      BUILD_WITH_DPDK_CFLAGS+="-I$DPDK_INCLUDE"
 +      if test "x$LOCAL_DPDK_INSTALL" != "xyes"
 +      then
 +              BUILD_WITH_DPDK_LDFLAGS="-Wl,--no-as-needed"
 +      else
 +              BUILD_WITH_DPDK_LDFLAGS="-L$DPDK_LIB_DIR -Wl,--no-as-needed"
 +        fi
 +      AC_SUBST(BUILD_WITH_DPDK_CFLAGS)
 +      AC_SUBST(BUILD_WITH_DPDK_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_DPDK_LIBS)
 +fi
 +# }}}
 +
  # --with-java {{{
  with_java_home="$JAVA_HOME"
  if test "x$with_java_home" = "x"
@@@ -2633,7 -2571,7 +2646,7 @@@ the
        if test -d "$with_java_home"
        then
                AC_MSG_CHECKING([for jni.h])
-               TMPVAR=`find -L "$with_java_home" -name jni.h -type f -exec 'dirname' '{}' ';' 2>/dev/null | head -n 1`
+               TMPVAR=`find -L "$with_java_home" -name jni.h -type f -exec 'dirname' '{}' ';' 2>/dev/null | LC_ALL=C sort | head -n 1`
                if test "x$TMPVAR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPVAR])
                fi
  
                AC_MSG_CHECKING([for jni_md.h])
-               TMPVAR=`find -L "$with_java_home" -name jni_md.h -type f -exec 'dirname' '{}' ';' 2>/dev/null | head -n 1`
+               TMPVAR=`find -L "$with_java_home" -name jni_md.h -type f -exec 'dirname' '{}' ';' 2>/dev/null | LC_ALL=C sort | head -n 1`
                if test "x$TMPVAR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPVAR])
                fi
  
                AC_MSG_CHECKING([for libjvm.so])
-               TMPVAR=`find -L "$with_java_home" -type f \( -name libjvm.so -o -name libjvm.dylib \) -exec 'dirname' '{}' ';' 2>/dev/null | head -n 1`
+               TMPVAR=`find -L "$with_java_home" -type f \( -name libjvm.so -o -name libjvm.dylib \) -exec 'dirname' '{}' ';' 2>/dev/null | LC_ALL=C sort | head -n 1`
                if test "x$TMPVAR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPVAR])
                if test "x$JAVAC" = "x"
                then
                        AC_MSG_CHECKING([for javac])
-                       TMPVAR=`find -L "$with_java_home" -name javac -type f 2>/dev/null | head -n 1`
+                       TMPVAR=`find -L "$with_java_home" -name javac -type f 2>/dev/null | LC_ALL=C sort | head -n 1`
                        if test "x$TMPVAR" != "x"
                        then
                                JAVAC="$TMPVAR"
                if test "x$JAR" = "x"
                then
                        AC_MSG_CHECKING([for jar])
-                       TMPVAR=`find -L "$with_java_home" -name jar -type f 2>/dev/null | head -n 1`
+                       TMPVAR=`find -L "$with_java_home" -name jar -type f 2>/dev/null | LC_ALL=C sort | head -n 1`
                        if test "x$TMPVAR" != "x"
                        then
                                JAR="$TMPVAR"
  AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
  # }}}
  
 +# --with-libpqos {{{
 +with_libpqos_cppflags=""
 +with_libpqos_ldflags=""
 +AC_ARG_WITH(libpqos, [AS_HELP_STRING([--with-libpqos@<:@=PREFIX@:>@], [Path to libpqos.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              with_libpqos_cppflags="-I$withval/include"
 +              with_libpqos_ldflags="-L$withval/lib"
 +              with_libpqos="yes"
 +      else
 +              with_libpqos="$withval"
 +      fi
 +],
 +[
 +      with_libpqos="yes"
 +])
 +if test "x$with_libpqos" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags"
 +
 +      AC_CHECK_HEADERS(pqos.h, [with_libpqos="yes"], [with_libpqos="no (pqos.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libpqos" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags"
 +      LDFLAGS="$LDFLAGS $with_libpqos_ldflags"
 +
 +      AC_CHECK_LIB(pqos, pqos_init, [with_libpqos="yes"], [with_libpqos="no (Can't find libpqos)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libpqos" = "xyes"
 +then
 +      BUILD_WITH_LIBPQOS_CPPFLAGS="$with_libpqos_cppflags"
 +      BUILD_WITH_LIBPQOS_LDFLAGS="$with_libpqos_ldflags"
 +      BUILD_WITH_LIBPQOS_LIBS="-lpqos"
 +      AC_SUBST(BUILD_WITH_LIBPQOS_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBPQOS_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBPQOS_LIBS)
 +fi
 +# }}}
 +
  # --with-libprotobuf {{{
  with_libprotobuf_cppflags=""
  with_libprotobuf_ldflags=""
@@@ -5827,15 -5716,12 +5840,15 @@@ plugin_curl_xml="no
  plugin_df="no"
  plugin_disk="no"
  plugin_drbd="no"
 +plugin_dpdk="no"
  plugin_entropy="no"
  plugin_ethstat="no"
  plugin_fhcount="no"
  plugin_fscache="no"
  plugin_gps="no"
  plugin_grpc="no"
 +plugin_hugepages="no"
 +plugin_intel_rdt="no"
  plugin_interface="no"
  plugin_ipmi="no"
  plugin_ipvs="no"
@@@ -5884,7 -5770,6 +5897,7 @@@ the
        plugin_entropy="yes"
        plugin_fhcount="yes"
        plugin_fscache="yes"
 +      plugin_hugepages="yes"
        plugin_interface="yes"
        plugin_ipc="yes"
        plugin_irq="yes"
@@@ -6279,7 -6164,6 +6292,7 @@@ AC_PLUGIN([dbi],                 [$with
  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([dpdkstat],            [$with_libdpdk],           [Stats & Status from DPDK])
  AC_PLUGIN([drbd],                [$plugin_drbd],            [DRBD statistics])
  AC_PLUGIN([email],               [yes],                     [EMail statistics])
  AC_PLUGIN([entropy],             [$plugin_entropy],         [Entropy statistics])
@@@ -6292,8 -6176,6 +6305,8 @@@ AC_PLUGIN([gmond],               [$with
  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_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])
@@@ -6621,7 -6503,6 +6634,7 @@@ AC_MSG_RESULT([    libaquaero5 . . . . 
  AC_MSG_RESULT([    libatasmart . . . . . $with_libatasmart])
  AC_MSG_RESULT([    libcurl . . . . . . . $with_libcurl])
  AC_MSG_RESULT([    libdbi  . . . . . . . $with_libdbi])
 +AC_MSG_RESULT([    libdpdk . . . . . . . $with_libdpdk])
  AC_MSG_RESULT([    libesmtp  . . . . . . $with_libesmtp])
  AC_MSG_RESULT([    libganglia  . . . . . $with_libganglia])
  AC_MSG_RESULT([    libgcrypt . . . . . . $with_libgcrypt])
@@@ -6655,7 -6536,6 +6668,7 @@@ AC_MSG_RESULT([    libpcap . . . . . . 
  AC_MSG_RESULT([    libperfstat . . . . . $with_perfstat])
  AC_MSG_RESULT([    libperl . . . . . . . $with_libperl])
  AC_MSG_RESULT([    libpq . . . . . . . . $with_libpq])
 +AC_MSG_RESULT([    libpqos . . . . . . . $with_libpqos])
  AC_MSG_RESULT([    libprotobuf . . . . . $with_libprotobuf])
  AC_MSG_RESULT([    libprotobuf-c . . . . $with_libprotobuf_c])
  AC_MSG_RESULT([    libpython . . . . . . $with_libpython])
@@@ -6714,7 -6594,6 +6727,7 @@@ AC_MSG_RESULT([    dbi . . . . . . . . 
  AC_MSG_RESULT([    df  . . . . . . . . . $enable_df])
  AC_MSG_RESULT([    disk  . . . . . . . . $enable_disk])
  AC_MSG_RESULT([    dns . . . . . . . . . $enable_dns])
 +AC_MSG_RESULT([    dpdkstat . . . . . . .$enable_dpdkstat])
  AC_MSG_RESULT([    drbd  . . . . . . . . $enable_drbd])
  AC_MSG_RESULT([    email . . . . . . . . $enable_email])
  AC_MSG_RESULT([    entropy . . . . . . . $enable_entropy])
@@@ -6727,8 -6606,6 +6740,8 @@@ AC_MSG_RESULT([    gmond . . . . . . . 
  AC_MSG_RESULT([    gps . . . . . . . . . $enable_gps])
  AC_MSG_RESULT([    grpc  . . . . . . . . $enable_grpc])
  AC_MSG_RESULT([    hddtemp . . . . . . . $enable_hddtemp])
 +AC_MSG_RESULT([    hugepages . . . . . . $enable_hugepages])
 +AC_MSG_RESULT([    intel_rdt. . . . .  . $enable_intel_rdt])
  AC_MSG_RESULT([    interface . . . . . . $enable_interface])
  AC_MSG_RESULT([    ipc . . . . . . . . . $enable_ipc])
  AC_MSG_RESULT([    ipmi  . . . . . . . . $enable_ipmi])
diff --combined src/battery.c
  # define SYSFS_FACTOR 0.000001
  #endif /* KERNEL_LINUX */
  
 +int battery_read_statefs (void); /* defined in battery_statefs; used by StateFS backend */
 +
  static _Bool report_percent = 0;
  static _Bool report_degraded = 0;
 +static _Bool query_statefs = 0;
  
  static void battery_submit2 (char const *plugin_instance, /* {{{ */
                char const *type, char const *type_instance, gauge_t value)
  {
 -      value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      values[0].gauge = value;
 -
 -      vl.values = values;
 +      vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "battery", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@@ -358,9 -359,6 +358,9 @@@ static int battery_read (void) /* {{{ *
        gauge_t capacity_full = NAN; /* Total capacity */
        gauge_t capacity_design = NAN; /* Full design capacity */
  
 +      if (query_statefs)
 +              return battery_read_statefs ();
 +
  #if HAVE_IOKIT_PS_IOPOWERSOURCES_H
        get_via_io_power_sources (&charge_rel, &current, &voltage);
  #endif
@@@ -388,17 -386,47 +388,17 @@@ static int sysfs_file_to_buffer(char co
                char const *basename,
                char *buffer, size_t buffer_size)
  {
 -      int status;
 -      FILE *fp;
        char filename[PATH_MAX];
 +      int status;
  
        ssnprintf (filename, sizeof (filename), "%s/%s/%s",
                        dir, power_supply, basename);
  
 -      /* No file isn't the end of the world -- not every system will be
 -       * reporting the same set of statistics */
 -      if (access (filename, R_OK) != 0)
 -              return ENOENT;
 -
 -      fp = fopen (filename, "r");
 -      if (fp == NULL)
 -      {
 -              status = errno;
 -              if (status != ENOENT)
 -              {
 -                      char errbuf[1024];
 -                      WARNING ("battery plugin: fopen (%s) failed: %s", filename,
 -                                      sstrerror (status, errbuf, sizeof (errbuf)));
 -              }
 -              return status;
 -      }
 -
 -      if (fgets (buffer, buffer_size, fp) == NULL)
 -      {
 -              status = errno;
 -              if (status != ENODEV)
 -              {
 -                      char errbuf[1024];
 -                      WARNING ("battery plugin: fgets (%s) failed: %s", filename,
 -                                      sstrerror (status, errbuf, sizeof (errbuf)));
 -              }
 -              fclose (fp);
 +      status = (int) read_file_contents (filename, buffer, buffer_size);
 +      if (status < 0)
                return status;
 -      }
  
        strstripnewline (buffer);
 -
 -      fclose (fp);
        return 0;
  } /* }}} int sysfs_file_to_buffer */
  
@@@ -750,9 -778,6 +750,9 @@@ static int battery_read (void) /* {{{ *
  {
        int status;
  
 +      if (query_statefs)
 +              return battery_read_statefs ();
 +
        DEBUG ("battery plugin: Trying sysfs ...");
        status = read_sysfs ();
        if (status == 0)
        if (status == 0)
                return (0);
  
-       ERROR ("battery plugin: Add available input methods failed.");
+       ERROR ("battery plugin: All available input methods failed.");
        return (-1);
  } /* }}} int battery_read */
  #endif /* KERNEL_LINUX */
@@@ -783,8 -808,6 +783,8 @@@ static int battery_config (oconfig_item
                        cf_util_get_boolean (child, &report_percent);
                else if (strcasecmp ("ReportDegraded", child->key) == 0)
                        cf_util_get_boolean (child, &report_degraded);
 +              else if (strcasecmp ("QueryStateFS", child->key) == 0)
 +                      cf_util_get_boolean (child, &query_statefs);
                else
                        WARNING ("battery plugin: Ignoring unknown "
                                        "configuration option \"%s\".",
diff --combined src/daemon/common.c
@@@ -60,7 -60,7 +60,7 @@@
  # include <arpa/inet.h>
  #endif
  
- #ifdef HAVE_SYS_CAPABILITY_H
+ #if HAVE_CAPABILITY
  # include <sys/capability.h>
  #endif
  
@@@ -339,60 -339,50 +339,60 @@@ int strsplit (char *string, char **fiel
        return ((int) i);
  }
  
 -int strjoin (char *buffer, size_t buffer_size,
 -              char **fields, size_t fields_num,
 -              const char *sep)
 -{
 -      size_t avail;
 -      char *ptr;
 -      size_t sep_len;
 +int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num,
 +            const char *sep) {
 +  size_t avail = 0;
 +  char *ptr = buffer;
 +  size_t sep_len = 0;
  
 -      if ((buffer_size < 1) || (fields_num == 0))
 -              return (-1);
 +  size_t buffer_req = 0;
  
 -      memset (buffer, 0, buffer_size);
 -      ptr = buffer;
 -      avail = buffer_size - 1;
 +  if (((fields_num != 0) && (fields == NULL)) ||
 +      ((buffer_size != 0) && (buffer == NULL)))
 +    return (-EINVAL);
  
 -      sep_len = 0;
 -      if (sep != NULL)
 -              sep_len = strlen (sep);
 +  if (buffer != NULL)
 +    buffer[0] = 0;
  
 -      for (size_t i = 0; i < fields_num; i++)
 -      {
 -              size_t field_len;
 +  if (buffer_size != 0)
 +    avail = buffer_size - 1;
  
 -              if ((i > 0) && (sep_len > 0))
 -              {
 -                      if (avail < sep_len)
 -                              return (-1);
 +  if (sep != NULL)
 +    sep_len = strlen(sep);
  
 -                      memcpy (ptr, sep, sep_len);
 -                      ptr += sep_len;
 -                      avail -= sep_len;
 -              }
 +  for (size_t i = 0; i < fields_num; i++) {
 +    size_t field_len = strlen(fields[i]);
  
 -              field_len = strlen (fields[i]);
 -              if (avail < field_len)
 -                      return (-1);
 +    if (i != 0)
 +      buffer_req += sep_len;
 +    buffer_req += field_len;
  
 -              memcpy (ptr, fields[i], field_len);
 -              ptr += field_len;
 -              avail -= field_len;
 -      }
 +    if ((i != 0) && (sep_len > 0)) {
 +      if (sep_len >= avail) {
 +        /* prevent subsequent iterations from writing to the
 +         * buffer. */
 +        avail = 0;
 +        continue;
 +      }
 +
 +      memcpy(ptr, sep, sep_len);
  
 -      assert (buffer[buffer_size - 1] == 0);
 -      return ((int) strlen (buffer));
 +      ptr += sep_len;
 +      avail -= sep_len;
 +    }
 +
 +    if (field_len > avail)
 +      field_len = avail;
 +
 +    memcpy(ptr, fields[i], field_len);
 +    ptr += field_len;
 +
 +    avail -= field_len;
 +    if (ptr != NULL)
 +      *ptr = 0;
 +  }
 +
 +  return (int)buffer_req;
  }
  
  int escape_string (char *buffer, size_t buffer_size)
@@@ -1016,8 -1006,7 +1016,8 @@@ int format_values (char *ret, size_t re
  
  int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
 -              char **ret_type, char **ret_type_instance)
 +              char **ret_type, char **ret_type_instance,
 +              char *default_host)
  {
        char *hostname = NULL;
        char *plugin = NULL;
  
        type = strchr (plugin, '/');
        if (type == NULL)
 -              return (-1);
 -      *type = '\0'; type++;
 +      {
 +              if (default_host == NULL)
 +                      return (-1);
 +              /* else: no host specified; use default */
 +              type = plugin;
 +              plugin = hostname;
 +              hostname = default_host;
 +      }
 +      else
 +      {
 +              *type = '\0';
 +              type++;
 +      }
  
        plugin_instance = strchr (plugin, '-');
        if (plugin_instance != NULL)
@@@ -1089,8 -1067,7 +1089,8 @@@ int parse_identifier_vl (const char *st
  
        status = parse_identifier (str_copy, &host,
                        &plugin, &plugin_instance,
 -                      &type, &type_instance);
 +                      &type, &type_instance,
 +                      /* default_host = */ NULL);
        if (status != 0)
                return (status);
  
@@@ -1227,28 -1204,6 +1227,28 @@@ int parse_values (char *buffer, value_l
        return (0);
  } /* int parse_values */
  
 +int parse_value_file (char const *path, value_t *ret_value, int ds_type)
 +{
 +      FILE *fh;
 +      char buffer[256];
 +
 +      fh = fopen (path, "r");
 +      if (fh == NULL)
 +              return (-1);
 +
 +      if (fgets (buffer, sizeof (buffer), fh) == NULL)
 +      {
 +              fclose (fh);
 +              return (-1);
 +      }
 +
 +      fclose (fh);
 +
 +      strstripnewline (buffer);
 +
 +      return parse_value (buffer, ret_value, ds_type);
 +} /* int parse_value_file */
 +
  #if !HAVE_GETPWNAM_R
  int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
                size_t buflen, struct passwd **pwbufp)
@@@ -1620,8 -1575,10 +1620,8 @@@ void set_sock_opts (int sockfd) /* {{{ 
        int status;
        int socktype;
  
 -      socklen_t socklen = sizeof (socklen_t);
 -      int so_keepalive = 1;
 -
 -      status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen);
 +      status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE,
 +                      &socktype, &(socklen_t) { sizeof (socktype) });
        if (status != 0)
        {
                WARNING ("set_sock_opts: failed to determine socket type");
        if (socktype == SOCK_STREAM)
        {
                status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
 -                              &so_keepalive, sizeof (so_keepalive));
 +                              &(int) {1}, sizeof (int));
                if (status != 0)
                        WARNING ("set_sock_opts: failed to set socket keepalive flag");
  
@@@ -1721,51 -1678,25 +1721,25 @@@ void strarray_free (char **array, size_
        sfree (array);
  } /* }}} void strarray_free */
  
- #ifdef HAVE_SYS_CAPABILITY_H
- int check_capability (int capability) /* {{{ */
+ #if HAVE_CAPABILITY
+ int check_capability (int arg) /* {{{ */
  {
- #ifdef _LINUX_CAPABILITY_VERSION_3
-       cap_user_header_t cap_header = calloc(1, sizeof (*cap_header));
-       if (cap_header == NULL)
-       {
-               ERROR("check_capability: calloc failed");
-               return (-1);
-       }
+       cap_value_t cap = (cap_value_t) arg;
  
-       cap_user_data_t cap_data = calloc(1, sizeof (*cap_data));
-       if (cap_data == NULL)
-       {
-               ERROR("check_capability: calloc failed");
-               sfree(cap_header);
+       if (!CAP_IS_SUPPORTED (cap))
                return (-1);
-       }
  
-       cap_header->pid = getpid();
-       cap_header->version = _LINUX_CAPABILITY_VERSION_3;
-       if (capget(cap_header, cap_data) < 0)
-       {
-               ERROR("check_capability: capget failed");
-               sfree(cap_header);
-               sfree(cap_data);
+       int have_cap = cap_get_bound (cap);
+       if (have_cap != 1)
                return (-1);
-       }
  
-       if ((cap_data->effective & (1 << capability)) == 0)
-       {
-               sfree(cap_header);
-               sfree(cap_data);
-               return (-1);
-       }
-       else
-       {
-               sfree(cap_header);
-               sfree(cap_data);
-               return (0);
-       }
+       return (0);
+ } /* }}} int check_capability */
  #else
+ int check_capability (__attribute__((unused)) int arg) /* {{{ */
+ {
        WARNING ("check_capability: unsupported capability implementation. "
-           "Some plugin(s) may require elevated privileges to work properly.");
+                "Some plugin(s) may require elevated privileges to work properly.");
        return (0);
- #endif /* _LINUX_CAPABILITY_VERSION_3 */
  } /* }}} int check_capability */
- #endif /* HAVE_SYS_CAPABILITY_H */
+ #endif /* HAVE_CAPABILITY */
diff --combined src/openvpn.c
@@@ -99,10 -99,14 +99,10 @@@ static int openvpn_strsplit (char *stri
  static void numusers_submit (const char *pinst, const char *tinst,
                gauge_t value)
  {
 -      value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
  
 -      values[0].gauge = value;
 -
 -      vl.values = values;
 -      vl.values_len = STATIC_ARRAY_SIZE (values);
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
 +      vl.values = &(value_t) { .gauge = value };
 +      vl.values_len = 1;
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        sstrncpy (vl.type, "users", sizeof (vl.type));
        if (pinst != NULL)
  static void iostats_submit (const char *pinst, const char *tinst,
                derive_t rx, derive_t tx)
  {
 -      value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 -
 -      values[0].derive = rx;
 -      values[1].derive = tx;
 +      value_t values[] = {
 +    { .derive = rx },
 +    { .derive = tx },
 +  };
  
        /* NOTE ON THE NEW NAMING SCHEMA:
         *       using plugin_instance to identify each vpn config (and
  
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        if (pinst != NULL)
                sstrncpy (vl.plugin_instance, pinst,
  static void compression_submit (const char *pinst, const char *tinst,
                derive_t uncompressed, derive_t compressed)
  {
 -      value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 -
 -      values[0].derive = uncompressed;
 -      values[1].derive = compressed;
 +      value_t values[] = {
 +    { .derive = uncompressed },
 +    { .derive = compressed },
 +  };
  
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        if (pinst != NULL)
                sstrncpy (vl.plugin_instance, pinst,
@@@ -519,6 -525,9 +519,9 @@@ static int openvpn_read (void
        int  read;
  
        read = 0;
+       
+       if (vpn_num == 0)
+               return (0);
  
        /* call the right read function for every status entry in the list */
        for (int i = 0; i < vpn_num; i++)
@@@ -653,8 -662,8 +656,8 @@@ static int openvpn_config (const char *
  
                if (status_version == 0)
                {
-                       WARNING ("openvpn plugin: unable to detect status version, \
-                                       discarding status file \"%s\".", value);
+                       WARNING ("openvpn plugin: unable to detect status version, "
+                                       "discarding status file \"%s\".", value);
                        return (1);
                }
  
diff --combined src/powerdns.c
@@@ -43,7 -43,6 +43,7 @@@
  # define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
  #endif
  #define FUNC_ERROR(func) do { char errbuf[1024]; ERROR ("powerdns plugin: %s failed: %s", func, sstrerror (errno, errbuf, sizeof (errbuf))); } 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))); } while (0)
  
  #define SERVER_SOCKET  LOCALSTATEDIR"/run/pdns.controlsocket"
  #define SERVER_COMMAND "SHOW * \n"
@@@ -51,7 -50,7 +51,7 @@@
  #define RECURSOR_SOCKET  LOCALSTATEDIR"/run/pdns_recursor.controlsocket"
  #define RECURSOR_COMMAND "get noerror-answers nxdomain-answers " \
    "servfail-answers sys-msec user-msec qa-latency cache-entries cache-hits " \
-   "cache-misses questions\n"
+   "cache-misses questions \n"
  
  struct list_item_s;
  typedef struct list_item_s list_item_t;
@@@ -301,10 -300,10 +301,10 @@@ static char *local_sockpath = NULL
  
  /* <https://doc.powerdns.com/md/recursor/stats/> */
  static void submit (const char *plugin_instance, /* {{{ */
 -    const char *pdns_type, const char *value)
 +    const char *pdns_type, const char *value_str)
  {
    value_list_t vl = VALUE_LIST_INIT;
 -  value_t values[1];
 +  value_t value;
  
    const char *type = NULL;
    const char *type_instance = NULL;
    if (i >= lookup_table_length)
    {
      INFO ("powerdns plugin: submit: Not found in lookup table: %s = %s;",
 -        pdns_type, value);
 +        pdns_type, value_str);
      return;
    }
  
      return;
    }
  
 -  if (0 != parse_value (value, &values[0], ds->ds[0].type))
 +  if (0 != parse_value (value_str, &value, ds->ds[0].type))
    {
      ERROR ("powerdns plugin: Cannot convert `%s' "
 -        "to a number.", value);
 +        "to a number.", value_str);
      return;
    }
  
 -  vl.values = values;
 +  vl.values = &value;
    vl.values_len = 1;
 -  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
    sstrncpy (vl.plugin, "powerdns", sizeof (vl.plugin));
    sstrncpy (vl.type, type, sizeof (vl.type));
    if (type_instance != NULL)
@@@ -377,6 -377,7 +377,6 @@@ static int powerdns_get_data_dgram (lis
  
    struct sockaddr_un sa_unix = { 0 };
  
 -  struct timeval stv_timeout;
    cdtime_t cdt_timeout;
  
    sd = socket (PF_UNIX, item->socktype, 0);
    status = unlink (sa_unix.sun_path);
    if ((status != 0) && (errno != ENOENT))
    {
 -    FUNC_ERROR ("unlink");
 +    SOCK_ERROR ("unlink", sa_unix.sun_path);
      close (sd);
      return (-1);
    }
      status = bind (sd, (struct sockaddr *) &sa_unix, sizeof (sa_unix));
      if (status != 0)
      {
 -      FUNC_ERROR ("bind");
 +      SOCK_ERROR ("bind", sa_unix.sun_path);
        break;
      }
  
      status = chmod (sa_unix.sun_path, 0666);
      if (status != 0)
      {
 -      FUNC_ERROR ("chmod");
 +      SOCK_ERROR ("chmod", sa_unix.sun_path);
        break;
      }
  
      if (cdt_timeout < TIME_T_TO_CDTIME_T (2))
        cdt_timeout = TIME_T_TO_CDTIME_T (2);
  
 -    CDTIME_T_TO_TIMEVAL (cdt_timeout, &stv_timeout);
 -
 -    status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &stv_timeout, sizeof (stv_timeout));
 +    status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO,
 +                         &CDTIME_T_TO_TIMEVAL(cdt_timeout),
 +                         sizeof(struct timeval));
      if (status != 0)
      {
 -      FUNC_ERROR ("setsockopt");
 +      SOCK_ERROR ("setsockopt", sa_unix.sun_path);
        break;
      }
  
          sizeof (item->sockaddr));
      if (status != 0)
      {
 -      FUNC_ERROR ("connect");
 +      SOCK_ERROR ("connect", sa_unix.sun_path);
        break;
      }
  
      status = send (sd, item->command, strlen (item->command), 0);
      if (status < 0)
      {
 -      FUNC_ERROR ("send");
 +      SOCK_ERROR ("send", sa_unix.sun_path);
        break;
      }
  
      status = recv (sd, temp, sizeof (temp), /* flags = */ 0);
      if (status < 0)
      {
 -      FUNC_ERROR ("recv");
 +      SOCK_ERROR ("recv", sa_unix.sun_path);
        break;
      }
      buffer_size = status + 1;
@@@ -512,7 -513,7 +512,7 @@@ static int powerdns_get_data_stream (li
        sizeof (item->sockaddr));
    if (status != 0)
    {
 -    FUNC_ERROR ("connect");
 +    SOCK_ERROR ("connect", item->sockaddr.sun_path);
      close (sd);
      return (-1);
    }
        /* flags = */ 0);
    if (status < 0)
    {
 -    FUNC_ERROR ("send");
 +    SOCK_ERROR ("send", item->sockaddr.sun_path);
      close (sd);
      return (-1);
    }
      status = recv (sd, temp, sizeof (temp), /* flags = */ 0);
      if (status < 0)
      {
 -      FUNC_ERROR ("recv");
 +      SOCK_ERROR ("recv", item->sockaddr.sun_path);
        break;
      }
      else if (status == 0)
@@@ -150,29 -150,18 +150,29 @@@ static int gr_format_name (char *ret, i
          sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
  
      if (n_type_instance[0] != '\0')
 -        ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
 -            n_type,
 -            (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
 -            n_type_instance);
 +    {
 +        if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(n_plugin, n_type) == 0)
 +            sstrncpy (tmp_type, n_type_instance, sizeof (tmp_type));
 +        else
 +            ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
 +                n_type,
 +                (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
 +                n_type_instance);
 +    }
      else
          sstrncpy (tmp_type, n_type, sizeof (tmp_type));
  
      /* Assert always_append_ds -> ds_name */
      assert (!(flags & GRAPHITE_ALWAYS_APPEND_DS) || (ds_name != NULL));
      if (ds_name != NULL)
 -        ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
 -            prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
 +    {
 +        if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(tmp_plugin, tmp_type) == 0)
 +            ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
 +                prefix, n_host, postfix, tmp_plugin, ds_name);
 +        else
 +            ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
 +                prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
 +    }
      else
          ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
              prefix, n_host, postfix, tmp_plugin, tmp_type);
@@@ -257,6 -246,7 +257,7 @@@ int format_graphite (char *buffer, size
          }
          memcpy((void *) (buffer + buffer_pos), message, message_len);
          buffer_pos += message_len;
+         buffer[buffer_pos] = '\0';
      }
      sfree (rates);
      return (status);
diff --combined src/write_kafka.c
@@@ -78,6 -78,15 +78,15 @@@ static uint32_t kafka_hash(const char *
      return hash;
  }
  
+ /* 31 bit -> 4 byte -> 8 byte hex string + null byte */
+ #define KAFKA_RANDOM_KEY_SIZE 9
+ #define KAFKA_RANDOM_KEY_BUFFER (char[KAFKA_RANDOM_KEY_SIZE]) {""}
+ static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE])
+ {
+     ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08lX", (unsigned long) mrand48());
+     return buffer;
+ }
  static int32_t kafka_partition(const rd_kafka_topic_t *rkt,
                                 const void *keydata, size_t keylen,
                                 int32_t partition_cnt, void *p, void *m)
@@@ -172,9 -181,9 +181,9 @@@ static int kafka_write(const data_set_
  
      switch (ctx->format) {
      case KAFKA_FORMAT_COMMAND:
 -        status = create_putval(buffer, sizeof(buffer), ds, vl);
 +        status = cmd_create_putval(buffer, sizeof(buffer), ds, vl);
          if (status != 0) {
 -            ERROR("write_kafka plugin: create_putval failed with status %i.",
 +            ERROR("write_kafka plugin: cmd_create_putval failed with status %i.",
                    status);
              return status;
          }
          return -1;
      }
  
-     key = ctx->key;
-     if (key != NULL)
-         keylen = strlen (key);
-     else
-         keylen = 0;
+     key = (ctx->key != NULL)
+         ? ctx->key
+         : kafka_random_key(KAFKA_RANDOM_KEY_BUFFER);
+     keylen = strlen (key);
  
      rd_kafka_produce(ctx->topic, RD_KAFKA_PARTITION_UA,
                       RD_KAFKA_MSG_F_COPY, buffer, blen,
@@@ -319,8 -327,12 +327,12 @@@ static void kafka_config_topic(rd_kafka
              }
  
          } else if (strcasecmp ("Key", child->key) == 0)  {
-             cf_util_get_string (child, &tctx->key);
-             assert (tctx->key != NULL);
+             if (cf_util_get_string (child, &tctx->key) != 0)
+                 continue;
+             if (strcasecmp ("Random", tctx->key) == 0) {
+                 sfree(tctx->key);
+                 tctx->key = strdup (kafka_random_key (KAFKA_RANDOM_KEY_BUFFER));
+             }
          } else if (strcasecmp ("Format", child->key) == 0) {
              status = cf_util_get_string(child, &key);
              if (status != 0)
      ssnprintf(callback_name, sizeof(callback_name),
                "write_kafka/%s", tctx->topic_name);
  
 -    user_data_t ud = {
 -        .data = tctx,
 -        .free_func = kafka_topic_context_free
 -    };
 -
 -    status = plugin_register_write (callback_name, kafka_write, &ud);
 +    status = plugin_register_write (callback_name, kafka_write,
 +            &(user_data_t) {
 +                .data = tctx,
 +                .free_func = kafka_topic_context_free,
 +            });
      if (status != 0) {
          WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
                  "failed with status %i.",
diff --combined src/zfs_arc.c
@@@ -138,13 -138,14 +138,13 @@@ static long long get_zfs_value(kstat_t 
  }
  #endif
  
 -static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len)
 +static void za_submit (const char* type, const char* type_instance, value_t* values, size_t values_len)
  {
        value_list_t vl = VALUE_LIST_INIT;
  
        vl.values = values;
        vl.values_len = values_len;
  
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "zfs_arc", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
  
  static void za_submit_gauge (const char* type, const char* type_instance, gauge_t value)
  {
 -      value_t vv;
 -
 -      vv.gauge = value;
 -      za_submit (type, type_instance, &vv, 1);
 +      za_submit (type, type_instance, &(value_t) { .gauge = value }, 1);
  }
  
  static int za_read_derive (kstat_t *ksp, const char *kstat_value,
      const char *type, const char *type_instance)
  {
 -  long long tmp;
 -  value_t v;
 -
 -  tmp = get_zfs_value (ksp, (char *)kstat_value);
 +  long long tmp = get_zfs_value (ksp, (char *)kstat_value);
    if (tmp == -1LL)
    {
      WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
      return (-1);
    }
  
 -  v.derive = (derive_t) tmp;
 -  za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
 +  za_submit (type, type_instance, &(value_t) { .derive = (derive_t) tmp }, /* values_num = */ 1);
    return (0);
  }
  
  static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
      const char *type, const char *type_instance)
  {
 -  long long tmp;
 -  value_t v;
 -
 -  tmp = get_zfs_value (ksp, (char *)kstat_value);
 +  long long tmp = get_zfs_value (ksp, (char *)kstat_value);
    if (tmp == -1LL)
    {
      WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
      return (-1);
    }
  
 -  v.gauge = (gauge_t) tmp;
 -  za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
 +  za_submit (type, type_instance, &(value_t) { .gauge = (gauge_t) tmp }, /* values_num = */ 1);
    return (0);
  }
  
@@@ -203,6 -215,7 +203,6 @@@ static void za_submit_ratio (const char
  static int za_read (void)
  {
        gauge_t  arc_hits, arc_misses, l2_hits, l2_misses;
 -      value_t  l2_io[2];
        kstat_t  *ksp   = NULL;
  
  #if defined(KERNEL_LINUX)
        za_read_derive (ksp, "mfu_ghost_hits",           "cache_result", "mfu_ghost-hit");
        za_read_derive (ksp, "mru_hits",                 "cache_result", "mru-hit");
        za_read_derive (ksp, "mru_ghost_hits",           "cache_result", "mru_ghost-hit");
-       za_read_derive (ksp, "prefetch_metadata_misses", "cache_result", "prefetch_metadata-miss");
  
        /* Ratios */
        arc_hits   = (gauge_t) get_zfs_value(ksp, "hits");
        za_submit_ratio ("L2", l2_hits, l2_misses);
  
        /* I/O */
 -      l2_io[0].derive = get_zfs_value(ksp, "l2_read_bytes");
 -      l2_io[1].derive = get_zfs_value(ksp, "l2_write_bytes");
 -
 -      za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
 +      value_t  l2_io[] = {
 +              { .derive = (derive_t) get_zfs_value(ksp, "l2_read_bytes") },
 +              { .derive = (derive_t) get_zfs_value(ksp, "l2_write_bytes") },
 +      };
 +      za_submit ("io_octets", "L2", l2_io, STATIC_ARRAY_SIZE (l2_io));
  
  #if defined(KERNEL_LINUX)
        free_zfs_values (ksp);