Merge pull request #1874 from rubenk/utils-dns-fix-compiler-warning
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Sun, 14 Aug 2016 19:41:00 +0000 (21:41 +0200)
committerGitHub <noreply@github.com>
Sun, 14 Aug 2016 19:41:00 +0000 (21:41 +0200)
utils_dns.c: fix compiler warning

108 files changed:
.gitignore
AUTHORS
README
configure.ac
contrib/redhat/collectd.spec
proto/collectd.proto
proto/types.proto
src/Makefile.am
src/aggregation.c
src/apache.c
src/apcups.c
src/ascent.c
src/barometer.c
src/bind.c
src/ceph.c
src/cgroups.c
src/chrony.c
src/collectd-lua.pod [new file with mode: 0644]
src/collectd.conf.in
src/collectd.conf.pod
src/collectdctl.c
src/collectdmon.c
src/cpu.c
src/curl.c
src/curl_json.c
src/curl_xml.c
src/daemon/common.c
src/daemon/common.h
src/daemon/configfile.h
src/daemon/plugin.h
src/daemon/utils_complain.c
src/daemon/utils_match.c
src/dbi.c
src/df.c
src/dns.c
src/email.c
src/ethstat.c
src/exec.c
src/fhcount.c
src/gmond.c
src/gps.c
src/grpc.cc
src/hddtemp.c
src/interface.c
src/ipc.c
src/iptables.c
src/irq.c
src/java.c
src/libcollectdclient/client.c
src/liboconfig/oconfig.c
src/liboconfig/oconfig.h
src/liboconfig/scanner.l
src/lua.c [new file with mode: 0644]
src/madwifi.c
src/mbmon.c
src/md.c
src/memcachec.c
src/memcached.c
src/modbus.c
src/mqtt.c
src/mysql.c
src/netapp.c
src/network.c
src/nginx.c
src/notify_desktop.c
src/notify_nagios.c
src/ntpd.c
src/openldap.c
src/oracle.c
src/perl.c
src/pinba.c
src/ping.c
src/postgresql.c
src/powerdns.c
src/processes.c
src/python.c
src/redis.c
src/sensors.c
src/snmp.c
src/statsd.c
src/swap.c
src/table.c
src/tail.c
src/tail_csv.c
src/ted.c
src/thermal.c
src/turbostat.c
src/unixsock.c
src/utils_curl_stats.h
src/utils_db_query.c
src/utils_db_query.h
src/utils_format_json_test.c
src/utils_latency.c
src/utils_lua.c [new file with mode: 0644]
src/utils_lua.h [new file with mode: 0644]
src/uuid.c
src/varnish.c
src/virt.c
src/write_graphite.c
src/write_http.c
src/write_kafka.c
src/write_log.c
src/write_mongodb.c
src/write_redis.c
src/write_riemann.c
src/write_sensu.c
src/write_tsdb.c
src/zone.c

index b85dc48..8154d73 100644 (file)
@@ -84,6 +84,9 @@ bindings/java/org/collectd/java/*.class
 #ide stuff
 .vscode
 
+# cscope stuff
+cscope.*
+
 # Unit tests
 src/daemon/test-suite.log
 src/tests/
diff --git a/AUTHORS b/AUTHORS
index f5f6db0..28220e7 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -163,6 +163,9 @@ Jérôme Renard <jerome.renard at gmail.com>
 Jiri Tyr <jiri.tyr at gmail.com>
  - fhcount plugin.
 
+Julien Ammous <j.ammous at gmail.com>
+ - Lua plugin.
+
 Kevin Bowling <kbowling at llnw.com>
  - write_tsdb plugin for http://opentsdb.net/
 
diff --git a/README b/README
index f2df12c..2d552e4 100644 (file)
--- a/README
+++ b/README
@@ -168,6 +168,12 @@ Features
       Detailed CPU statistics of the “Logical Partitions” virtualization
       technique built into IBM's POWER processors.
 
+    - lua
+      The Lua plugin implements a Lua interpreter into collectd. This
+      makes it possible to write plugins in Lua which are executed by
+      collectd without the need to start a heavy interpreter every interval.
+      See collectd-lua(5) for details.
+
     - lvm
       Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
       “Logical Volume Manager” (LVM).
@@ -422,6 +428,10 @@ Features
       diskspace but is extremely portable and can be analysed with almost
       every program that can analyse anything. Even Microsoft's Excel..
 
+    - lua
+      It's possible to implement write plugins in Lua using the Lua
+      plugin. See collectd-lua(5) for details.
+
     - network
       Send the data to a remote host to save the data somehow. This is useful
       for large setups where the data should be saved by a dedicated machine.
@@ -729,6 +739,10 @@ Prerequisites
     Used by the `openldap' plugin.
     <http://www.openldap.org/>
 
+  * liblua (optional)
+    Used by the `lua' plugin. Currently, Lua 5.1 and later are supported.
+    <https://www.lua.org/>
+
   * liblvm2 (optional)
     Used by the `lvm' plugin.
     <ftp://sources.redhat.com/pub/lvm2/>
@@ -803,7 +817,7 @@ Prerequisites
     <http://code.google.com/p/protobuf-c/>
 
   * libpython (optional)
-    Used by the `python' plugin. Currently, Python 2.3 and later and Python 3
+    Used by the `python' plugin. Currently, Python 2.6 and later and Python 3
     are supported.
     <http://www.python.org/>
 
index 1bacddd..e27b046 100644 (file)
@@ -486,6 +486,7 @@ then
 #include <linux/major.h>
 #include <linux/types.h>
 ])
+       AC_CHECK_HEADERS([sys/sysmacros.h])
 else
        have_linux_raid_md_u_h="no"
 fi
@@ -682,10 +683,26 @@ AC_CHECK_HEADERS([ \
   wordexp.h \
 ])
 
-AC_CHECK_HEADERS([xfs/xqm.h], [], [],
-[
-#define _GNU_SOURCE
-])
+# --enable-xfs {{{
+AC_ARG_ENABLE([xfs],
+  [AS_HELP_STRING([--enable-xfs], [xfs support in df plugin @<:@default=yes@:>@])],
+  [],
+  [enable_xfs="auto"]
+)
+
+if test "x$enable_xfs" != "xno"; then
+  AC_CHECK_HEADERS([xfs/xqm.h],
+    [],
+    [
+      if test "x$enable_xfs" = "xyes"; then
+        AC_MSG_ERROR([xfs/xqm.h not found])
+      fi
+    ],
+    [[#define _GNU_SOURCE]]
+  )
+fi
+
+# }}}
 
 # For the dns plugin
 AC_CHECK_HEADERS(arpa/nameser.h)
@@ -2376,7 +2393,7 @@ if test "x$with_libgrpcpp" = "xyes"
 then
   AC_LANG_PUSH(C++)
   SAVE_CPPFLAGS="$CPPFLAGS"
-  CPPFLAGS="$with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS -std=c++11"
+  CPPFLAGS="-std=c++11 $with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS"
   AC_CHECK_HEADERS([grpc++/grpc++.h], [],
     [with_libgrpcpp="no (<grpc++/grpc++.h> not found)"]
   )
@@ -2386,8 +2403,10 @@ fi
 if test "x$with_libgrpcpp" = "xyes"
 then
   AC_LANG_PUSH(C++)
+  SAVE_CPPFLAGS="$CPPFLAGS"
   SAVE_LDFLAGS="$LDFLAGS"
   SAVE_LIBS="$LIBS"
+  CPPFLAGS="-std=c++11 $with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS"
   LDFLAGS="$with_libgrpcpp_ldflags"
   if test "x$GRPCPP_LIBS" = "x"
   then
@@ -2409,6 +2428,7 @@ then
     ],
     [with_libgrpcpp="no (libgrpc++ not found)"]
   )
+  CPPFLAGS="$SAVE_CPPFLAGS"
   LDFLAGS="$SAVE_LDFLAGS"
   LIBS="$SAVE_LIBS"
   AC_LANG_POP(C++)
@@ -2746,6 +2766,67 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBLDAP, test "x$with_libldap" = "xyes")
 # }}}
 
+# --with-liblua {{{
+with_liblua_cppflags=""
+with_liblua_ldflags=""
+with_liblua_libs=""
+with_liblua="yes"
+
+AC_ARG_VAR([LIBLUA_PKG_CONFIG_NAME], [Name of liblua used by pkg-config])
+if test "x$LIBLUA_PKG_CONFIG_NAME" = "x"
+then
+       LIBLUA_PKG_CONFIG_NAME="lua"
+fi
+
+if test "x$with_liblua" = "xyes"
+then
+       $PKG_CONFIG --exists $LIBLUA_PKG_CONFIG_NAME 2>/dev/null
+       lua_config_status=$?
+
+       if test 0 -ne $lua_config_status
+       then
+               with_liblua="no"
+       fi
+fi
+
+if test "x$with_liblua" = "xyes"
+then
+       with_liblua_cppflags=`$PKG_CONFIG --cflags-only-I $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+       with_liblua_ldflags=`$PKG_CONFIG --libs-only-L $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+       with_liblua_libs=`$PKG_CONFIG --libs-only-l $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+fi
+if test "x$with_liblua" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_liblua_cppflags"
+
+       AC_CHECK_HEADERS(lua.h lauxlib.h lualib.h, [], [with_liblua="no (header not found)"], [])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_liblua" = "xyes"
+then
+       SAVE_LDFLAGS="$LDFLAGS"
+       SAVE_LIBS="$LIBS"
+       LDFLAGS="$SAVE_LDFLAGS $with_liblua_ldflags"
+       LIBS="$LIBS $with_liblua_libs"
+
+       AC_CHECK_FUNC(lua_settop, [with_liblua="yes"], [with_liblua="no (symbol 'lua_settop' not found)"])
+
+       LDFLAGS="$SAVE_LDFLAGS"
+       LIBS="$SAVE_LIBS"
+fi
+if test "x$with_liblua" = "xyes"
+then
+    BUILD_WITH_LIBLUA_CPPFLAGS="$with_liblua_cppflags"
+    BUILD_WITH_LIBLUA_LDFLAGS="$with_liblua_ldflags"
+    BUILD_WITH_LIBLUA_LIBS="$with_liblua_libs"
+fi
+AC_SUBST(BUILD_WITH_LIBLUA_CPPFLAGS)
+AC_SUBST(BUILD_WITH_LIBLUA_LDFLAGS)
+AC_SUBST(BUILD_WITH_LIBLUA_LIBS)
+# }}}
+
 # --with-liblvm2app {{{
 with_liblvm2app_cppflags=""
 with_liblvm2app_ldflags=""
@@ -3328,9 +3409,6 @@ AM_CONDITIONAL(BUILD_WITH_LIBNETAPP, test "x$with_libnetapp" = "xyes")
 # }}}
 
 # --with-libnetsnmp {{{
-with_snmp_config="net-snmp-config"
-with_snmp_cflags=""
-with_snmp_libs=""
 AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])],
 [
        if test "x$withval" = "xno"
@@ -3340,57 +3418,42 @@ AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Pat
        then
                with_libnetsnmp="yes"
        else
-               if test -x "$withval"
-               then
-                       with_snmp_config="$withval"
-                       with_libnetsnmp="yes"
-               else
-                       with_snmp_config="$withval/bin/net-snmp-config"
-                       with_libnetsnmp="yes"
-               fi
+               with_libnetsnmp_cppflags="-I$withval/include"
+               with_libnetsnmp_ldflags="-I$withval/lib"
+               with_libnetsnmp="yes"
        fi; fi
 ],
 [with_libnetsnmp="yes"])
 if test "x$with_libnetsnmp" = "xyes"
 then
-       with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null`
-       snmp_config_status=$?
-
-       if test $snmp_config_status -ne 0
-       then
-               with_libnetsnmp="no ($with_snmp_config failed)"
-       else
-               SAVE_CPPFLAGS="$CPPFLAGS"
-               CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libnetsnmp_cppflags"
 
-               AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
+       AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
 
-               CPPFLAGS="$SAVE_CPPFLAGS"
-       fi
+       CPPFLAGS="$SAVE_CPPFLAGS"
 fi
 if test "x$with_libnetsnmp" = "xyes"
 then
-       with_snmp_libs=`$with_snmp_config --libs 2>/dev/null`
-       snmp_config_status=$?
+       SAVE_LDFLAGS="$LDFLAGS"
+       LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
 
-       if test $snmp_config_status -ne 0
-       then
-               with_libnetsnmp="no ($with_snmp_config failed)"
-       else
-               AC_CHECK_LIB(netsnmp, init_snmp,
+       AC_CHECK_LIB(netsnmp, init_snmp,
                [with_libnetsnmp="yes"],
                [with_libnetsnmp="no (libnetsnmp not found)"],
                [$with_snmp_libs])
-       fi
+
+       LDFLAGS="$SAVE_LDFLAGS"
 fi
 if test "x$with_libnetsnmp" = "xyes"
 then
-       BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags"
-       BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs"
-       AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS)
-       AC_SUBST(BUILD_WITH_LIBSNMP_LIBS)
+       BUILD_WITH_LIBNETSNMP_CPPFLAGS="$with_libnetsnmp_cppflags"
+       BUILD_WITH_LIBNETSNMP_LDFLAGS="$with_libnetsnmp_ldflags"
+       BUILD_WITH_LIBNETSNMP_LIBS="-lnetsnmp"
 fi
-AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+AC_SUBST(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
+AC_SUBST(BUILD_WITH_LIBNETSNMP_LDFLAGS)
+AC_SUBST(BUILD_WITH_LIBNETSNMP_LIBS)
 # }}}
 
 # --with-liboconfig {{{
@@ -3423,7 +3486,7 @@ save_LDFLAGS="$LDFLAGS"
 save_CPPFLAGS="$CPPFLAGS"
 LDFLAGS="$liboconfig_LDFLAGS"
 CPPFLAGS="$liboconfig_CPPFLAGS"
-AC_CHECK_LIB(oconfig, oconfig_parse_fh,
+AC_CHECK_LIB(oconfig, oconfig_parse_file,
 [
        with_liboconfig="yes"
        with_own_liboconfig="no"
@@ -6092,6 +6155,7 @@ 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])
@@ -6310,6 +6374,18 @@ AC_ARG_WITH(perl-bindings, [AS_HELP_STRING([--with-perl-bindings@<:@=OPTIONS@:>@
                with_perl_bindings="no (no perl interpreter found)"
        fi
 ])
+
+if test "x$with_perl_bindings" = "xyes"
+then
+       AC_MSG_CHECKING([for the ExtUtils::MakeMaker module])
+       if $PERL -MExtUtils::MakeMaker -e '' 2>/dev/null; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+               with_perl_bindings="no (ExtUtils::MakeMaker not found)"
+       fi
+fi
+
 if test "x$with_perl_bindings" = "xyes"
 then
        PERL_BINDINGS="perl"
@@ -6409,6 +6485,7 @@ AC_MSG_RESULT([    libjvm  . . . . . . . $with_java])
 AC_MSG_RESULT([    libkstat  . . . . . . $with_kstat])
 AC_MSG_RESULT([    libkvm  . . . . . . . $with_libkvm])
 AC_MSG_RESULT([    libldap . . . . . . . $with_libldap])
+AC_MSG_RESULT([    liblua  . . . . . . . $with_liblua])
 AC_MSG_RESULT([    liblvm2app  . . . . . $with_liblvm2app])
 AC_MSG_RESULT([    libmemcached  . . . . $with_libmemcached])
 AC_MSG_RESULT([    libmnl  . . . . . . . $with_libmnl])
@@ -6508,6 +6585,7 @@ AC_MSG_RESULT([    load  . . . . . . . . $enable_load])
 AC_MSG_RESULT([    logfile . . . . . . . $enable_logfile])
 AC_MSG_RESULT([    log_logstash  . . . . $enable_log_logstash])
 AC_MSG_RESULT([    lpar  . . . . . . . . $enable_lpar])
+AC_MSG_RESULT([    lua . . . . . . . . . $enable_lua])
 AC_MSG_RESULT([    lvm . . . . . . . . . $enable_lvm])
 AC_MSG_RESULT([    madwifi . . . . . . . $enable_madwifi])
 AC_MSG_RESULT([    match_empty_counter . $enable_match_empty_counter])
index 1eaba99..b56ac17 100644 (file)
@@ -71,6 +71,7 @@
 %define with_filecount 0%{!?_without_filecount:1}
 %define with_fscache 0%{!?_without_fscache:1}
 %define with_gmond 0%{!?_without_gmond:1}
+%define with_gps 0%{!?_without_gps:1}
 %define with_hddtemp 0%{!?_without_hddtemp:1}
 %define with_interface 0%{!?_without_interface:1}
 %define with_ipc 0%{!?_without_ipc:1}
@@ -82,6 +83,7 @@
 %define with_load 0%{!?_without_load:1}
 %define with_log_logstash 0%{!?_without_log_logstash:1}
 %define with_logfile 0%{!?_without_logfile:1}
+%define with_lua 0%{!?_without_lua:1}
 %define with_lvm 0%{!?_without_lvm:1}
 %define with_madwifi 0%{!?_without_madwifi:1}
 %define with_mbmon 0%{!?_without_mbmon:1}
 Summary:       Statistics collection and monitoring daemon
 Name:          collectd
 Version:       5.5.2
-Release:       1%{?dist}
+Release:       2%{?dist}
 URL:           https://collectd.org
 Source:                https://collectd.org/files/%{name}-%{version}.tar.bz2
 License:       GPLv2
@@ -494,6 +496,17 @@ BuildRequires: yajl-devel
 This plugin logs in logstash JSON format
 %endif
 
+%if %{with_lua}
+%package lua
+Summary:       Lua plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: lua-devel
+%description lua
+The Lua plugin embeds a Lua interpreter into collectd and exposes the
+application programming interface (API) to Lua scripts.
+%endif
+
 %if %{with_lvm}
 %package lvm
 Summary:       LVM plugin for collectd
@@ -1193,6 +1206,12 @@ Collectd utilities
 %define _with_lpar --disable-lpar
 %endif
 
+%if %{with_lua}
+%define _with_lua --enable-lua
+%else
+%define _with_lua --disable-lua
+%endif
+
 %if %{with_lvm}
 %define _with_lvm --enable-lvm
 %else
@@ -1754,6 +1773,7 @@ Collectd utilities
        %{?_with_log_logstash} \
        %{?_with_logfile} \
        %{?_with_lpar} \
+       %{?_with_lua} \
        %{?_with_lvm} \
        %{?_with_madwifi} \
        %{?_with_mbmon} \
@@ -1880,6 +1900,10 @@ rm -f %{buildroot}%{_datadir}/collectd/java/generic-jmx.jar
 rm -f %{buildroot}%{_mandir}/man5/collectd-java.5*
 %endif
 
+%if ! %{with_lua}
+rm -f %{buildroot}%{_mandir}/man5/collectd-lua.5*
+%endif
+
 %if ! %{with_perl}
 rm -f %{buildroot}%{_mandir}/man5/collectd-perl.5*
 rm -f %{buildroot}%{_mandir}/man3/Collectd::Unixsock.3pm*
@@ -2308,6 +2332,12 @@ fi
 %{_libdir}/%{name}/log_logstash.so
 %endif
 
+%if %{with_lua}
+%files lua
+%{_mandir}/man5/collectd-lua*
+%{_libdir}/%{name}/lua.so
+%endif
+
 %if %{with_lvm}
 %files lvm
 %{_libdir}/%{name}/lvm.so
@@ -2482,6 +2512,9 @@ fi
 %doc contrib/
 
 %changelog
+* Sun Aug 14 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.5.2-2
+- Add new Lua plugin
+
 * Tue Jul 26 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.5.2-1
 - New upstream version
 - Contains fix for CVE-2016-6254
index 5134dbf..917c5de 100644 (file)
 syntax = "proto3";
 
 package collectd;
+option go_package = "collectd.org/rpc/proto";
 
 import "types.proto";
 
 service Collectd {
-       // Dispatch collected values to collectd.
-       rpc DispatchValues(DispatchValuesRequest) returns (DispatchValuesReply);
-
-       // Query a list of values available from collectd's value cache.
-       rpc QueryValues(QueryValuesRequest) returns (QueryValuesReply);
+  // DispatchValues reads the value lists from the DispatchValuesRequest stream.
+  // The gRPC server embedded into collectd will inject them into the system
+  // just like the network plugin.
+  rpc DispatchValues(stream DispatchValuesRequest)
+      returns (DispatchValuesResponse);
+
+  // QueryValues returns a stream of matching value lists from collectd's
+  // internal cache.
+  rpc QueryValues(QueryValuesRequest) returns (stream QueryValuesResponse);
 }
 
 // The arguments to DispatchValues.
 message DispatchValuesRequest {
-       collectd.types.ValueList values = 1;
+  // value_list is the metric to be sent to the server.
+  collectd.types.ValueList value_list = 1;
 }
 
 // The response from DispatchValues.
-message DispatchValuesReply {
-}
+message DispatchValuesResponse {}
 
 // The arguments to QueryValues.
 message QueryValuesRequest {
-       // Query by the fields of the identifier. Only return values matching the
-       // specified shell wildcard patterns (see fnmatch(3)). Use '*' to match
-       // any value.
-       collectd.types.Identifier identifier = 1;
+  // Query by the fields of the identifier. Only return values matching the
+  // specified shell wildcard patterns (see fnmatch(3)). Use '*' to match
+  // any value.
+  collectd.types.Identifier identifier = 1;
 }
 
 // The response from QueryValues.
-message QueryValuesReply {
-       repeated collectd.types.ValueList values = 1;
-}
+message QueryValuesResponse { collectd.types.ValueList value_list = 1; }
index 4a852e4..952c541 100644 (file)
 syntax = "proto3";
 
 package collectd.types;
+option go_package = "collectd.org/rpc/proto/types";
 
 import "google/protobuf/duration.proto";
 import "google/protobuf/timestamp.proto";
 
 message Identifier {
-       string host = 1;
-       string plugin = 2;
-       string plugin_instance = 3;
-       string type = 4;
-       string type_instance = 5;
+  string host = 1;
+  string plugin = 2;
+  string plugin_instance = 3;
+  string type = 4;
+  string type_instance = 5;
 }
 
 message Value {
-       oneof value {
-               uint64 counter = 1;
-               double gauge = 2;
-               int64 derive = 3;
-               uint64 absolute = 4;
-       };
+  oneof value {
+    uint64 counter = 1;
+    double gauge = 2;
+    int64 derive = 3;
+    uint64 absolute = 4;
+  };
 }
 
 message ValueList {
-       repeated Value value = 1;
+  repeated Value values = 1;
 
-       google.protobuf.Timestamp time = 2;
-       google.protobuf.Duration interval = 3;
+  google.protobuf.Timestamp time = 2;
+  google.protobuf.Duration interval = 3;
 
-       Identifier identifier = 4;
+  Identifier identifier = 4;
+
+  repeated string ds_names = 5;
 }
index 12c7730..ce2f985 100644 (file)
@@ -170,6 +170,7 @@ apache_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
 apache_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
 endif
 
+
 if BUILD_PLUGIN_APCUPS
 pkglib_LTLIBRARIES += apcups.la
 apcups_la_SOURCES = apcups.c
@@ -574,6 +575,15 @@ lpar_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 lpar_la_LIBADD = -lperfstat
 endif
 
+if BUILD_PLUGIN_LUA
+pkglib_LTLIBRARIES += lua.la
+lua_la_SOURCES = lua.c \
+                utils_lua.c utils_lua.h
+lua_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLUA_CPPFLAGS)
+lua_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLUA_LDFLAGS)
+lua_la_LIBADD = $(BUILD_WITH_LIBLUA_LIBS)
+endif
+
 if BUILD_PLUGIN_LVM
 pkglib_LTLIBRARIES += lvm.la
 lvm_la_SOURCES = lvm.c
@@ -1005,13 +1015,9 @@ endif
 if BUILD_PLUGIN_SNMP
 pkglib_LTLIBRARIES += snmp.la
 snmp_la_SOURCES = snmp.c
-snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-snmp_la_CFLAGS = $(AM_CFLAGS)
-snmp_la_LIBADD =
-if BUILD_WITH_LIBNETSNMP
-snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
-snmp_la_LIBADD += $(BUILD_WITH_LIBSNMP_LIBS)
-endif
+snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
+snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
+snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
 endif
 
 if BUILD_PLUGIN_STATSD
@@ -1358,6 +1364,7 @@ dist_man_MANS = collectd.1 \
                collectd-exec.5 \
                collectdctl.1 \
                collectd-java.5 \
+               collectd-lua.5 \
                collectdmon.1 \
                collectd-nagios.1 \
                collectd-perl.5 \
@@ -1373,6 +1380,7 @@ EXTRA_DIST =      collectd.conf.pod \
                collectd-exec.pod \
                collectdctl.pod \
                collectd-java.pod \
+               collectd-lua.pod \
                collectdmon.pod \
                collectd-nagios.pod \
                collectd-perl.pod \
index b9db500..2744c89 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "meta_data.h"
 #include "utils_cache.h" /* for uc_get_rate() */
 #include "utils_subst.h"
index 650d678..e10a15d 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <curl/curl.h>
 
index cc20357..af5f24c 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"      /* rrd_update_file */
 #include "plugin.h"      /* plugin_register, plugin_submit */
-#include "configfile.h"  /* cf_register */
 
 #if HAVE_SYS_TYPES_H
 # include <sys/types.h>
index 20fef65..11bb97f 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <curl/curl.h>
 #include <libxml/parser.h>
index fba3450..998932d 100644 (file)
@@ -30,6 +30,7 @@
 #include <unistd.h>
 #include <linux/i2c-dev.h>
 #include <math.h>
+#include <sys/ioctl.h>
 
 /* ------------ MPL115 defines ------------ */
 /* I2C address of the MPL115 sensor */
index 7fda034..9b6b32e 100644 (file)
@@ -39,7 +39,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 /* Some versions of libcurl don't include this themselves and then don't have
  * fd_set available. */
index cbfdd22..5b79239 100644 (file)
@@ -38,6 +38,9 @@
 #if HAVE_YAJL_YAJL_VERSION_H
 #include <yajl/yajl_version.h>
 #endif
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
 
 #include <limits.h>
 #include <poll.h>
@@ -164,7 +167,7 @@ static int convert_special_metrics = 1;
 static struct ceph_daemon **g_daemons = NULL;
 
 /** Number of elements in g_daemons */
-static int g_num_daemons = 0;
+static size_t g_num_daemons = 0;
 
 /**
  * A set of data that we build up in memory while parsing the JSON.
@@ -259,8 +262,11 @@ static int ceph_cb_boolean(void *ctx, int bool_val)
 
 #define BUFFER_ADD(dest, src) do { \
     size_t dest_size = sizeof (dest); \
-    strncat ((dest), (src), dest_size - strlen (dest)); \
-    (dest)[dest_size - 1] = '\0'; \
+    size_t dest_len = strlen (dest); \
+    if (dest_size > dest_len) { \
+        sstrncpy ((dest) + dest_len, (src), dest_size - dest_len); \
+    } \
+    (dest)[dest_size - 1] = 0; \
 } while (0)
 
 static int
@@ -268,11 +274,10 @@ ceph_cb_number(void *ctx, const char *number_val, yajl_len_t number_len)
 {
     yajl_struct *state = (yajl_struct*) ctx;
     char buffer[number_len+1];
-    char key[2 * DATA_MAX_NAME_LEN];
+    char key[2 * DATA_MAX_NAME_LEN] = { 0 };
     _Bool latency_type = 0;
     int status;
 
-    key[0] = '\0';
     memcpy(buffer, number_val, number_len);
     buffer[sizeof(buffer) - 1] = '\0';
 
@@ -422,7 +427,7 @@ static void ceph_daemon_print(const struct ceph_daemon *d)
 
 static void ceph_daemons_print(void)
 {
-    for(int i = 0; i < g_num_daemons; ++i)
+    for(size_t i = 0; i < g_num_daemons; ++i)
     {
         ceph_daemon_print(g_daemons[i]);
     }
@@ -749,7 +754,8 @@ static int cc_add_daemon_config(oconfig_item_t *ci)
         return ENOMEM;
     }
     memcpy(nd, &cd, sizeof(*nd));
-    g_daemons[g_num_daemons++] = nd;
+    g_daemons[g_num_daemons] = nd;
+    g_num_daemons++;
     return 0;
 }
 
@@ -1461,7 +1467,7 @@ static int cconn_main_loop(uint32_t request_type)
 
     /* create cconn array */
     memset(io_array, 0, sizeof(io_array));
-    for(int i = 0; i < g_num_daemons; ++i)
+    for(size_t i = 0; i < g_num_daemons; ++i)
     {
         io_array[i].d = g_daemons[i];
         io_array[i].request_type = request_type;
@@ -1480,13 +1486,13 @@ static int cconn_main_loop(uint32_t request_type)
         struct pollfd fds[g_num_daemons];
         memset(fds, 0, sizeof(fds));
         nfds = 0;
-        for(int i = 0; i < g_num_daemons; ++i)
+        for(size_t i = 0; i < g_num_daemons; ++i)
         {
             struct cconn *io = io_array + i;
             ret = cconn_prepare(io, fds + nfds);
             if(ret < 0)
             {
-                WARNING("ceph plugin: cconn_prepare(name=%s,i=%d,st=%d)=%d",
+                WARNING("ceph plugin: cconn_prepare(name=%s,i=%zu,st=%d)=%d",
                         io->d->name, i, io->state, ret);
                 cconn_close(io);
                 io->request_type = ASOK_REQ_NONE;
@@ -1525,6 +1531,7 @@ static int cconn_main_loop(uint32_t request_type)
             if(revents == 0)
             {
                 /* do nothing */
+                continue;
             }
             else if(cconn_validate_revents(io, revents))
             {
@@ -1549,7 +1556,7 @@ static int cconn_main_loop(uint32_t request_type)
             }
         }
     }
-    done: for(int i = 0; i < g_num_daemons; ++i)
+    done: for(size_t i = 0; i < g_num_daemons; ++i)
     {
         cconn_close(io_array + i);
     }
@@ -1573,6 +1580,22 @@ static int ceph_read(void)
 static int ceph_init(void)
 {
     int ret;
+
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_DAC_OVERRIDE)
+  if (check_capability (CAP_DAC_OVERRIDE) != 0)
+  {
+    if (getuid () == 0)
+      WARNING ("ceph plugin: Running collectd as root, but the "
+          "CAP_DAC_OVERRIDE capability is missing. The plugin's read "
+          "function will probably fail. Is your init system dropping "
+          "capabilities?");
+    else
+      WARNING ("ceph plugin: collectd doesn't have the CAP_DAC_OVERRIDE "
+          "capability. If you don't want to run collectd as root, try running "
+          "\"setcap cap_dac_override=ep\" on the collectd binary.");
+  }
+#endif
+
     ceph_daemons_print();
 
     ret = cconn_main_loop(ASOK_REQ_VERSION);
@@ -1582,7 +1605,7 @@ static int ceph_init(void)
 
 static int ceph_shutdown(void)
 {
-    for(int i = 0; i < g_num_daemons; ++i)
+    for(size_t i = 0; i < g_num_daemons; ++i)
     {
         ceph_daemon_free(g_daemons[i]);
     }
index 3a59ec4..f7c7e0d 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_mount.h"
 #include "utils_ignorelist.h"
 
index 0485036..f6294e4 100644 (file)
@@ -452,8 +452,8 @@ chrony_connect(void)
 
   if (chrony_set_timeout())
   {
-    ERROR(PLUGIN_NAME ": Error setting timeout to %lds. Errno = %d",
-          g_chrony_timeout, errno);
+    ERROR(PLUGIN_NAME ": Error setting timeout to %llds. Errno = %d",
+          (long long)g_chrony_timeout, errno);
     return CHRONY_RC_FAIL;
   }
   return CHRONY_RC_OK;
diff --git a/src/collectd-lua.pod b/src/collectd-lua.pod
new file mode 100644 (file)
index 0000000..7a25655
--- /dev/null
@@ -0,0 +1,163 @@
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+=encoding UTF-8
+
+=head1 NAME
+
+collectd-lua - Documentation of collectd's C<Lua plugin>
+
+=head1 SYNOPSIS
+
+  LoadPlugin lua
+  # ...
+  <Plugin lua>
+    BasePath "/path/to/your/lua/scripts"
+    Script "script1.lua"
+    Script "script2.lua"
+  </Plugin>
+
+=head1 DESCRIPTION
+
+The C<Lua plugin> embeds a Lua interpreter into collectd and provides an
+interface to collectd's plugin system. This makes it possible to write plugins
+for collectd in Lua. This is a lot more efficient than executing a
+Lua script every time you want to read a value with the C<exec plugin> (see
+L<collectd-exec(5)>) and provides a lot more functionality, too.
+
+The minimum required Lua version is I<5.1>.
+
+=head1 CONFIGURATION
+
+=over 4
+
+=item B<LoadPlugin> I<Lua>
+
+Loads the Lua plugin.
+
+=item B<BasePath> I<Name>
+
+The directory the C<Lua plugin> looks in to find script B<Script>.
+If set, this is also prepended to B<package.path>.
+
+=item B<Script> I<Name>
+
+The script the C<Lua plugin> is going to run.
+If B<BasePath> is not specified, this needs to be an absolute path.
+
+=back
+
+=head1 WRITING YOUR OWN PLUGINS
+
+Writing your own plugins is quite simple. collectd manages plugins by means of
+B<dispatch functions> which call the appropriate B<callback functions>
+registered by the plugins. Any plugin basically consists of the implementation
+of these callback functions and initializing code which registers the
+functions with collectd. See the section "EXAMPLES" below for a really basic
+example. The following types of B<callback functions> are implemented in the
+Lua plugin (all of them are optional):
+
+=over 4
+
+=item read functions
+
+These are used to collect the actual data. It is called once
+per interval (see the B<Interval> configuration option of collectd). Usually
+it will call B<collectd.dispatch_values> to dispatch the values to collectd
+which will pass them on to all registered B<write functions>. If this function
+does not return 0 the plugin will be skipped for an increasing
+amount of time until it returns normally again.
+
+=item write functions
+
+These are used to write the dispatched values. They are called
+once for every value that was dispatched by any plugin.
+
+=back
+
+=head1 FUNCTIONS
+
+The following functions are provided to Lua modules:
+
+=over 4
+
+=item register_read(callback)
+
+The callback will be called without arguments.
+If this callback function does not return 0 the next call will be delayed by
+an increasing interval.
+
+=item register_write
+
+The callback function will be called with one argument passed, which will be a
+table of values.
+If this callback function does not return 0 next call will be delayed by
+an increasing interval.
+
+=item log_error, log_warning, log_notice, log_info, log_debug(I<message>)
+
+Log a message with the specified severity.
+
+=back
+
+=head1 EXAMPLES
+
+=over 4
+
+A very simple read function might look like:
+
+  function read()
+    collectd.log_info("read function called")
+    t = {
+        host = 'localhost',
+        plugin = 'myplugin',
+        type = 'counter',
+        values = {42},
+    }
+    collectd.dispatch_values(t)
+    return 0
+  end
+
+A very simple write function might look like:
+
+  function write(vl)
+    for i = 1, #vl.values do
+      collectd.log_info(vl.host .. '.' .. vl.plugin .. '.' .. vl.type .. ' ' .. vl.values[i])
+    end
+    return 0
+  end
+
+To register those functions with collectd:
+
+  collectd.register_read(read)
+  collectd.register_write(write)
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<lua(1)>,
+
+=head1 AUTHOR
+
+The C<Lua plugin> has been written by
+Julien Ammous E<lt>j.ammous<nbsp>atE<nbsp>gmail.comE<gt>,
+Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
+Ruben Kerkhof E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt> and
+
+This manpage has been written by Ruben Kerkhof
+E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt>.
+It is based on the L<collectd-perl(5)> manual page by
+Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
+Sebastian Harl E<lt>shE<nbsp>atE<nbsp>tokkee.orgE<gt>.
+
+=cut
index e3f2aa3..f689811 100644 (file)
 #@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
 @BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
 #@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
+#@BUILD_PLUGIN_LUA_TRUE@LoadPlugin lua
 #@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
 #@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
 #@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
 #</Plugin>
 
 #<Plugin grpc>
-#      WorkerThreads 5
+#      <Server "example.com" "50051">
+#              EnableSSL true
+#              SSLCACertificateFile "/path/to/root.pem"
+#              SSLCertificateFile "/path/to/server.pem"
+#              SSLCertificateKeyFile "/path/to/server.key"
+#      </Server>
 #      <Listen "0.0.0.0" "50051">
 #              EnableSSL true
-#              SSLRootCerts "/path/to/root.pem"
-#              SSLServerCert "/path/to/server.pem"
-#              SSLServerKey "/path/to/server.key"
+#              SSLCACertificateFile "/path/to/root.pem"
+#              SSLCertificateFile "/path/to/client.pem"
+#              SSLCertificateKeyFile "/path/to/client.key"
 #      </Listen>
 #</Plugin>
 
 #      ReportBySerial false
 #</Plugin>
 
+#<Plugin lua>
+#      BasePath "@prefix@/share/@PACKAGE_NAME@/lua"
+#      Script "script1.lua"
+#      Script "script2.lua"
+#</Plugin>
+
 #<Plugin madwifi>
 #      Interface "wlan0"
 #      IgnoreSelected false
 #              User "db_user"
 #              Password "secret"
 #              Database "db_name"
+#              SSLKey "/path/to/key.pem"
+#              SSLCert "/path/to/cert.pem"
+#              SSLCA "/path/to/ca.pem"
+#              SSLCAPath "/path/to/cas/"
+#              SSLCipher "DHE-RSA-AES256-SHA"
 #              MasterStats true
 #              ConnectTimeout 10
 #              InnodbStats true
index 6ada5f1..e302e81 100644 (file)
@@ -1447,6 +1447,11 @@ are set to B<true>. In this case, by default, metrics will be reported as
 Jiffies. By setting this option to B<true>, you can request percentage values
 in the un-aggregated (per-CPU, per-state) mode as well.
 
+=item B<ReportNumCpu> B<false>|B<true>
+
+When set to B<true>, reports the number of available CPUs.
+Defaults to B<false>.
+
 =back
 
 =head2 Plugin C<cpufreq>
@@ -1770,6 +1775,11 @@ The following options are valid within B<URL> blocks:
 
 =over 4
 
+=item B<Host> I<Name>
+
+Use I<Name> as the host name when submitting values. Defaults to the global
+host name setting.
+
 =item B<Instance> I<Instance>
 
 Sets the plugin instance to I<Instance>.
@@ -2723,6 +2733,33 @@ The B<gRPC> homepage can be found at L<https://grpc.io/>.
 
 =over 4
 
+=item B<Server> I<Host> I<Port>
+
+The B<Server> statement sets the address of a server to which to send metrics
+via the C<DispatchValues> function.
+
+The argument I<Host> may be a hostname, an IPv4 address, or an IPv6 address.
+
+Optionally, B<Server> may be specified as a configuration block which supports
+the following options:
+
+=over 4
+
+=item B<EnableSSL> B<false>|B<true>
+
+Whether to require SSL for outgoing connections. Default: false.
+
+=item B<SSLCACertificateFile> I<Filename>
+
+=item B<SSLCertificateFile> I<Filename>
+
+=item B<SSLCertificateKeyFile> I<Filename>
+
+Filenames specifying SSL certificate and key material to be used with SSL
+connections.
+
+=back
+
 =item B<Listen> I<Host> I<Port>
 
 The B<Listen> statement sets the network address to bind to. When multiple
@@ -2740,22 +2777,17 @@ supports the following options:
 
 Whether to enable SSL for incoming connections. Default: false.
 
-=item B<SSLRootCerts> I<Filename>
+=item B<SSLCACertificateFile> I<Filename>
 
-=item B<SSLServerKey> I<Filename>
+=item B<SSLCertificateFile> I<Filename>
 
-=item B<SSLServerCert> I<Filename>
+=item B<SSLCertificateKeyFile> I<Filename>
 
 Filenames specifying SSL certificate and key material to be used with SSL
 connections.
 
 =back
 
-=item B<WorkerThreads> I<Num>
-
-Number of threads to start for handling incoming connections. The default
-value is B<5>.
-
 =back
 
 =head2 Plugin C<hddtemp>
@@ -3083,6 +3115,12 @@ Defaults to false.
 
 =back
 
+=head2 Plugin C<lua>
+
+This plugin embeds a Lua interpreter into collectd and provides an interface
+to collectd's plugin system. See L<collectd-lua(5)> for its documentation.
+
+
 =head2 Plugin C<mbmon>
 
 The C<mbmon plugin> uses mbmon to retrieve temperature, voltage, etc.
@@ -3734,6 +3772,11 @@ Synopsis:
       Port "3306"
       MasterStats true
       ConnectTimeout 10
+      SSLKey "/path/to/key.pem"
+      SSLCert "/path/to/cert.pem"
+      SSLCA "/path/to/ca.pem"
+      SSLCAPath "/path/to/cas/"
+      SSLCipher "DHE-RSA-AES256-SHA"
     </Database>
 
     <Database bar>
@@ -3755,7 +3798,8 @@ Synopsis:
 A B<Database> block defines one connection to a MySQL database. It accepts a
 single argument which specifies the name of the database. None of the other
 options are required. MySQL will use default values as documented in the
-section "mysql_real_connect()" in the B<MySQL reference manual>.
+"mysql_real_connect()" and "mysql_ssl_set()" sections in the
+B<MySQL reference manual>.
 
 =over 4
 
@@ -3830,6 +3874,26 @@ or SQL threads are not running. Defaults to B<false>.
 
 Sets the connect timeout for the MySQL client.
 
+=item B<SSLKey> I<Path>
+
+If provided, the X509 key in PEM format.
+
+=item B<SSLCert> I<Path>
+
+If provided, the X509 cert in PEM format.
+
+=item B<SSLCA> I<Path>
+
+If provided, the CA file in PEM format (check OpenSSL docs).
+
+=item B<SSLCAPath> I<Path>
+
+If provided, the CA directory (check OpenSSL docs).
+
+=item B<SSLCipher> I<String>
+
+If provided, the SSL cipher to use.
+
 =back
 
 =head2 Plugin C<netapp>
index 31183b1..8c88479 100644 (file)
 
 #include "libcollectdclient/collectd/client.h"
 
+#ifndef PREFIX
+# define PREFIX "/opt/" PACKAGE_NAME
+#endif
+
+#ifndef LOCALSTATEDIR
+# define LOCALSTATEDIR PREFIX "/var"
+#endif
+
 #define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
 
 extern char *optarg;
index 13304f2..61daa58 100644 (file)
 
 #include <unistd.h>
 
+#ifndef PREFIX
+# define PREFIX "/opt/" PACKAGE_NAME
+#endif
+
+#ifndef LOCALSTATEDIR
+# define LOCALSTATEDIR PREFIX "/var"
+#endif
+
 #ifndef COLLECTDMON_PIDFILE
 # define COLLECTDMON_PIDFILE LOCALSTATEDIR"/run/collectdmon.pid"
 #endif /* ! COLLECTDMON_PIDFILE */
index 8002966..1ac5b4a 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -192,11 +192,13 @@ static size_t global_cpu_num = 0;
 static _Bool report_by_cpu = 1;
 static _Bool report_by_state = 1;
 static _Bool report_percent = 0;
+static _Bool report_num_cpu = 0;
 
 static const char *config_keys[] =
 {
        "ReportByCpu",
        "ReportByState",
+       "ReportNumCpu",
        "ValuesPercentage"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
@@ -209,6 +211,8 @@ static int cpu_config (char const *key, char const *value) /* {{{ */
                report_percent = IS_TRUE (value) ? 1 : 0;
        else if (strcasecmp (key, "ReportByState") == 0)
                report_by_state = IS_TRUE (value) ? 1 : 0;
+       else if (strcasecmp (key, "ReportNumCpu") == 0)
+               report_num_cpu = IS_TRUE (value) ? 1 : 0;
        else
                return (-1);
 
@@ -459,6 +463,24 @@ static void cpu_commit_one (int cpu_num, /* {{{ */
        }
 } /* }}} void cpu_commit_one */
 
+/* Commits the number of cores */
+static void cpu_commit_num_cpu (gauge_t num_cpu) /* {{{ */
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].gauge = num_cpu;
+
+       vl.values = values;
+       vl.values_len = 1;
+
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
+       sstrncpy (vl.type, "count", sizeof (vl.type));
+
+       plugin_dispatch_values (&vl);
+} /* }}} void cpu_commit_num_cpu */
+
 /* Resets the internal aggregation. This is called by the read callback after
  * each iteration / after each call to cpu_commit(). */
 static void cpu_reset (void) /* {{{ */
@@ -493,6 +515,9 @@ static void cpu_commit (void) /* {{{ */
                NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
        };
 
+       if (report_num_cpu)
+               cpu_commit_num_cpu ((gauge_t) global_cpu_num);
+
        if (report_by_state && report_by_cpu && !report_percent)
        {
                cpu_commit_without_aggregation ();
@@ -565,7 +590,7 @@ static int cpu_read (void)
 
        host_t cpu_host;
 
-       for (int cpu = 0; cpu < cpu_list_len; cpu++)
+       for (mach_msg_type_number_t cpu = 0; cpu < cpu_list_len; cpu++)
        {
                cpu_host = 0;
                cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
index 8d7baa5..74ef13c 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_curl_stats.h"
 #include "utils_match.h"
 #include "utils_time.h"
index d4e7803..ab0237e 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_avltree.h"
 #include "utils_complain.h"
 #include "utils_curl_stats.h"
@@ -759,7 +758,6 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
   /* If all went well, register this database for reading */
   if (status == 0)
   {
-    user_data_t ud = { 0 };
     char *cb_name;
 
     if (db->instance == NULL)
@@ -768,12 +766,14 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
     DEBUG ("curl_json plugin: Registering new read callback: %s",
            db->instance);
 
-    ud.data = (void *) db;
-    ud.free_func = cj_free;
-
     cb_name = ssnprintf_alloc ("curl_json-%s-%s",
                db->instance, db->url ? db->url : db->sock);
 
+    user_data_t ud = {
+      .data = db,
+      .free_func = cj_free
+    };
+
     plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
                                   /* interval = */ db->interval,
                                   &ud);
index f3aa2d9..c8a1313 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_curl_stats.h"
 #include "utils_llist.h"
 
@@ -1017,7 +1016,6 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
   /* If all went well, register this database for reading */
   if (status == 0)
   {
-    user_data_t ud = { 0 };
     char *cb_name;
 
     if (db->instance == NULL)
@@ -1026,10 +1024,13 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
     DEBUG ("curl_xml plugin: Registering new read callback: %s",
            db->instance);
 
-    ud.data = (void *) db;
-    ud.free_func = cx_free;
-
     cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
+
+    user_data_t ud = {
+      .data = db,
+      .free_func = cx_free
+    };
+
     plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
                                   /* interval = */ 0, &ud);
     sfree (cb_name);
index b60530a..05b1199 100644 (file)
 # include <netinet/in.h>
 #endif
 
+#if HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
 /* for ntohl and htonl */
 #if HAVE_ARPA_INET_H
 # include <arpa/inet.h>
 #endif
 
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
 #ifdef HAVE_LIBKSTAT
 extern kstat_ctl_t *kc;
 #endif
@@ -1557,6 +1565,46 @@ int service_name_to_port_number (const char *service_name)
        return (-1);
 } /* int service_name_to_port_number */
 
+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);
+       if (status != 0)
+       {
+               WARNING ("set_sock_opts: failed to determine socket type");
+               return;
+       }
+
+       if (socktype == SOCK_STREAM)
+       {
+               status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+                               &so_keepalive, sizeof (so_keepalive));
+               if (status != 0)
+                       WARNING ("set_sock_opts: failed to set socket keepalive flag");
+
+#ifdef TCP_KEEPIDLE
+               int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
+               status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+                               &tcp_keepidle, sizeof (tcp_keepidle));
+               if (status != 0)
+                       WARNING ("set_sock_opts: failed to set socket tcp keepalive time");
+#endif
+
+#ifdef TCP_KEEPINTVL
+               int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1);
+               status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+                               &tcp_keepintvl, sizeof (tcp_keepintvl));
+               if (status != 0)
+                       WARNING ("set_sock_opts: failed to set socket tcp keepalive interval");
+#endif
+       }
+} /* }}} void set_sock_opts */
+
 int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
 {
        derive_t tmp;
@@ -1624,3 +1672,52 @@ void strarray_free (char **array, size_t array_len) /* {{{ */
                sfree (array[i]);
        sfree (array);
 } /* }}} void strarray_free */
+
+#ifdef HAVE_SYS_CAPABILITY_H
+int check_capability (int capability) /* {{{ */
+{
+#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_user_data_t cap_data = calloc(1, sizeof (*cap_data));
+       if (cap_data == NULL)
+       {
+               ERROR("check_capability: calloc failed");
+               sfree(cap_header);
+               return (-1);
+       }
+
+       cap_header->pid = getpid();
+       cap_header->version = _LINUX_CAPABILITY_VERSION;
+       if (capget(cap_header, cap_data) < 0)
+       {
+               ERROR("check_capability: capget failed");
+               sfree(cap_header);
+               sfree(cap_data);
+               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);
+       }
+#else
+       WARNING ("check_capability: unsupported capability implementation. "
+           "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 */
index 8079661..720e5f1 100644 (file)
@@ -361,6 +361,9 @@ int value_to_rate (gauge_t *ret_rate, value_t value, int ds_type, cdtime_t t,
  * (in the range [1-65535]). Returns less than zero on error. */
 int service_name_to_port_number (const char *service_name);
 
+/* Sets various, non-default, socket options */
+void set_sock_opts (int sockfd);
+
 /** Parse a string to a derive_t value. Returns zero on success or non-zero on
  * failure. If failure is returned, ret_value is not touched. */
 int strtoderive (const char *string, derive_t *ret_value);
@@ -372,4 +375,12 @@ int strtogauge (const char *string, gauge_t *ret_value);
 int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str);
 void strarray_free (char **array, size_t array_len);
 
+#ifdef HAVE_SYS_CAPABILITY_H
+/** Check if the current process benefits from the capability passed in
+ * argument. Returns zero if it does, less than zero if it doesn't or on error.
+ * See capabilities(7) for the list of possible capabilities.
+ * */
+int check_capability (int capability);
+#endif /* HAVE_SYS_CAPABILITY_H */
+
 #endif /* COMMON_H */
index ae2c6c0..a13bc09 100644 (file)
@@ -93,7 +93,6 @@ int cf_read (const char *filename);
 int global_option_set (const char *option, const char *value, _Bool from_cli);
 const char *global_option_get (const char *option);
 long global_option_get_long (const char *option, long default_value);
-long global_option_get_long_in_range (const char *option, long default_value, long min, long max);
 
 cdtime_t global_option_get_time (char const *option, cdtime_t default_value);
 
index 49edba2..de42c06 100644 (file)
@@ -201,7 +201,6 @@ typedef void (*plugin_log_cb) (int severity, const char *message,
 typedef int (*plugin_shutdown_cb) (void);
 typedef int (*plugin_notification_cb) (const notification_t *,
                user_data_t *);
-
 /*
  * NAME
  *  plugin_set_dir
index d028c06..69909bb 100644 (file)
@@ -32,6 +32,7 @@
 #include "plugin.h"
 
 /* vcomplain returns 0 if it did not report, 1 else */
+__attribute__ ((format (printf, 3, 0)))
 static int vcomplain (int level, c_complain_t *c,
                const char *format, va_list ap)
 {
index 5273c90..914b6e2 100644 (file)
@@ -170,7 +170,7 @@ static int default_callback (const char __attribute__((unused)) *str,
 
     if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
     {
-      data->value.counter++;
+      data->value.derive++;
       data->values_num++;
       return (0);
     }
index b93aa51..068bf4d 100644 (file)
--- a/src/dbi.c
+++ b/src/dbi.c
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_db_query.h"
 
 #include <dbi/dbi.h>
@@ -391,17 +390,18 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
     }
     else
     {
-      user_data_t ud = { 0 };
       char *name = NULL;
 
       databases = temp;
       databases[databases_num] = db;
       databases_num++;
 
-      ud.data = (void *) db;
-      ud.free_func = NULL;
       name = ssnprintf_alloc("dbi:%s", db->name);
 
+      user_data_t ud = {
+        .data = db
+      };
+
       plugin_register_complex_read (/* group = */ NULL,
           /* name = */ name ? name : db->name,
           /* callback = */ cdbi_read_database,
index 83be176..4a86799 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_mount.h"
 #include "utils_ignorelist.h"
 
index 15fa15a..0494b4b 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include "utils_dns.h"
 #include <poll.h>
 
 #include <pcap.h>
 
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
 /*
  * Private data types
  */
@@ -347,6 +350,20 @@ static int dns_init (void)
 
        listen_thread_init = 1;
 
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_RAW)
+       if (check_capability (CAP_NET_RAW) != 0)
+       {
+               if (getuid () == 0)
+                       WARNING ("dns plugin: Running collectd as root, but the CAP_NET_RAW "
+                                       "capability is missing. The plugin's read function will probably "
+                                       "fail. Is your init system dropping capabilities?");
+               else
+                       WARNING ("dns plugin: collectd doesn't have the CAP_NET_RAW capability. "
+                                       "If you don't want to run collectd as root, try running \"setcap "
+                                       "cap_net_raw=ep\" on the collectd binary.");
+       }
+#endif
+
        return (0);
 } /* int dns_init */
 
index 9dce34c..2662da9 100644 (file)
@@ -43,8 +43,6 @@
 #include "common.h"
 #include "plugin.h"
 
-#include "configfile.h"
-
 #include <stddef.h>
 
 #include <sys/un.h>
index a213b60..d0e7728 100644 (file)
@@ -26,7 +26,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_avltree.h"
 #include "utils_complain.h"
 
index e90f83c..dfd4b05 100644 (file)
 #include <grp.h>
 #include <signal.h>
 
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
 #define PL_NORMAL        0x01
 #define PL_NOTIF_ACTION  0x02
 
@@ -806,6 +810,22 @@ static int exec_init (void) /* {{{ */
 
   sigaction (SIGCHLD, &sa, NULL);
 
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SETUID) && defined(CAP_SETGID)
+  if ((check_capability (CAP_SETUID) != 0) ||
+      (check_capability (CAP_SETGID) != 0))
+  {
+    if (getuid () == 0)
+      WARNING ("exec plugin: Running collectd as root, but the CAP_SETUID "
+          "or CAP_SETGID capabilities are missing. The plugin's read function "
+          "will probably fail. Is your init system dropping capabilities?");
+    else
+      WARNING ("exec plugin: collectd doesn't have the CAP_SETUID or "
+          "CAP_SETGID capabilities. If you don't want to run collectd as root, "
+          "try running \"setcap 'cap_setuid=ep cap_setgid=ep'\" on the "
+          "collectd binary.");
+  }
+#endif
+
   return (0);
 } /* int exec_init }}} */
 
index c7603c7..4b3abff 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 
 static const char *config_keys[] = {
index 2b299ca..13ec638 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_avltree.h"
 
 #if HAVE_NETDB_H
index 19f317c..f72cef4 100644 (file)
--- a/src/gps.c
+++ b/src/gps.c
@@ -30,7 +30,6 @@
 #include "common.h"
 #include "plugin.h"
 #include "utils_time.h"
-#include "configfile.h"
 
 #define CGPS_TRUE                  1
 #define CGPS_FALSE                 0
index ae3dab2..8b76954 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <queue>
 #include <vector>
 
 #include "collectd.grpc.pb.h"
@@ -39,7 +40,6 @@ extern "C" {
 
 #include "collectd.h"
 #include "common.h"
-#include "configfile.h"
 #include "plugin.h"
 
 #include "daemon/utils_cache.h"
@@ -48,9 +48,9 @@ extern "C" {
 using collectd::Collectd;
 
 using collectd::DispatchValuesRequest;
-using collectd::DispatchValuesReply;
+using collectd::DispatchValuesResponse;
 using collectd::QueryValuesRequest;
-using collectd::QueryValuesReply;
+using collectd::QueryValuesResponse;
 
 using google::protobuf::util::TimeUtil;
 
@@ -172,7 +172,7 @@ static grpc::Status marshal_value_list(const value_list_t *vl, collectd::types::
        msg->set_allocated_interval(new google::protobuf::Duration(d));
 
        for (size_t i = 0; i < vl->values_len; ++i) {
-               auto v = msg->add_value();
+               auto v = msg->add_values();
                switch (ds->ds[i].type) {
                        case DS_TYPE_COUNTER:
                                v->set_counter(vl->values[i].counter);
@@ -190,6 +190,9 @@ static grpc::Status marshal_value_list(const value_list_t *vl, collectd::types::
                                return grpc::Status(grpc::StatusCode::INTERNAL,
                                                grpc::string("unknown value type"));
                }
+
+               auto name = msg->add_ds_names();
+               name->assign(ds->ds[i].name);
        }
 
        return grpc::Status::OK;
@@ -208,7 +211,7 @@ static grpc::Status unmarshal_value_list(const collectd::types::ValueList &msg,
        size_t values_len = 0;
 
        status = grpc::Status::OK;
-       for (auto v : msg.value()) {
+       for (auto v : msg.values()) {
                value_t *val = (value_t *)realloc(values, (values_len + 1) * sizeof(*values));
                if (!val) {
                        status = grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED,
@@ -254,168 +257,124 @@ static grpc::Status unmarshal_value_list(const collectd::types::ValueList &msg,
 } /* unmarshal_value_list() */
 
 /*
- * request call-backs and call objects
+ * Collectd service
  */
-
-static grpc::Status Process(grpc::ServerContext *ctx,
-               DispatchValuesRequest request, DispatchValuesReply *reply)
-{
-       value_list_t vl = VALUE_LIST_INIT;
-       auto status = unmarshal_value_list(request.values(), &vl);
-       if (!status.ok())
-               return status;
-
-       if (plugin_dispatch_values(&vl))
-               status = grpc::Status(grpc::StatusCode::INTERNAL,
-                               grpc::string("failed to enqueue values for writing"));
-       return status;
-} /* Process(): DispatchValues */
-
-static grpc::Status Process(grpc::ServerContext *ctx,
-               QueryValuesRequest request, QueryValuesReply *reply)
-{
-       uc_iter_t *iter;
-       char *name = NULL;
-
-       value_list_t matcher;
-       auto status = unmarshal_ident(request.identifier(), &matcher, false);
-       if (!status.ok())
-               return status;
-
-       if ((iter = uc_get_iterator()) == NULL) {
-               return grpc::Status(grpc::StatusCode::INTERNAL,
-                               grpc::string("failed to query values: cannot create iterator"));
-       }
-
-       status = grpc::Status::OK;
-       while (uc_iterator_next(iter, &name) == 0) {
-               value_list_t res;
-               if (parse_identifier_vl(name, &res) != 0) {
-                       status = grpc::Status(grpc::StatusCode::INTERNAL,
-                                       grpc::string("failed to parse identifier"));
-                       break;
+class CollectdImpl : public collectd::Collectd::Service {
+public:
+       grpc::Status QueryValues(grpc::ServerContext *ctx, QueryValuesRequest const *req, grpc::ServerWriter<QueryValuesResponse> *writer) override {
+               value_list_t match;
+               auto status = unmarshal_ident(req->identifier(), &match, false);
+               if (!status.ok()) {
+                       return status;
                }
 
-               if (!ident_matches(&res, &matcher))
-                       continue;
-
-               if (uc_iterator_get_time(iter, &res.time) < 0) {
-                       status = grpc::Status(grpc::StatusCode::INTERNAL,
-                                       grpc::string("failed to retrieve value timestamp"));
-                       break;
+               std::queue<value_list_t> value_lists;
+               status = this->queryValuesRead(&match, &value_lists);
+               if (status.ok()) {
+                       status = this->queryValuesWrite(ctx, writer, &value_lists);
                }
-               if (uc_iterator_get_interval(iter, &res.interval) < 0) {
-                       status = grpc::Status(grpc::StatusCode::INTERNAL,
-                                       grpc::string("failed to retrieve value interval"));
-                       break;
-               }
-               if (uc_iterator_get_values(iter, &res.values, &res.values_len) < 0) {
-                       status = grpc::Status(grpc::StatusCode::INTERNAL,
-                                       grpc::string("failed to retrieve values"));
-                       break;
+
+               while (!value_lists.empty()) {
+                       auto vl = value_lists.front();
+                       value_lists.pop();
+                       sfree(vl.values);
                }
 
-               auto vl = reply->add_values();
-               status = marshal_value_list(&res, vl);
-               free(res.values);
-               if (!status.ok())
-                       break;
+               return status;
        }
 
-       uc_iterator_destroy(iter);
+       grpc::Status DispatchValues(grpc::ServerContext *ctx,
+                                                               grpc::ServerReader<DispatchValuesRequest> *reader,
+                                                               DispatchValuesResponse *res) override {
+               DispatchValuesRequest req;
 
-       return status;
-} /* Process(): QueryValues */
-
-class Call
-{
-public:
-       Call(Collectd::AsyncService *service, grpc::ServerCompletionQueue *cq)
-               : service_(service), cq_(cq), status_(CREATE)
-       { }
-
-       virtual ~Call()
-       { }
+               while (reader->Read(&req)) {
+                       value_list_t vl = VALUE_LIST_INIT;
+                       auto status = unmarshal_value_list(req.value_list(), &vl);
+                       if (!status.ok())
+                               return status;
 
-       void Handle()
-       {
-               if (status_ == CREATE) {
-                       Create();
-                       status_ = PROCESS;
-               }
-               else if (status_ == PROCESS) {
-                       Process();
-                       status_ = FINISH;
-               }
-               else {
-                       GPR_ASSERT(status_ == FINISH);
-                       Finish();
+                       if (plugin_dispatch_values(&vl))
+                               return grpc::Status(grpc::StatusCode::INTERNAL,
+                                                                       grpc::string("failed to enqueue values for writing"));
                }
-       } /* Handle() */
-
-protected:
-       virtual void Create() = 0;
-       virtual void Process() = 0;
-       virtual void Finish() = 0;
 
-       Collectd::AsyncService *service_;
-       grpc::ServerCompletionQueue *cq_;
-       grpc::ServerContext ctx_;
+               res->Clear();
+               return grpc::Status::OK;
+       }
 
 private:
-       enum CallStatus { CREATE, PROCESS, FINISH };
-       CallStatus status_;
-}; /* class Call */
+       grpc::Status queryValuesRead(value_list_t const *match, std::queue<value_list_t> *value_lists) {
+               uc_iter_t *iter;
+               if ((iter = uc_get_iterator()) == NULL) {
+                       return grpc::Status(grpc::StatusCode::INTERNAL,
+                                                               grpc::string("failed to query values: cannot create iterator"));
+               }
 
-template<typename RequestT, typename ReplyT>
-class RpcCall final : public Call
-{
-       typedef void (Collectd::AsyncService::*CreatorT)(grpc::ServerContext *,
-                       RequestT *, grpc::ServerAsyncResponseWriter<ReplyT> *,
-                       grpc::CompletionQueue *, grpc::ServerCompletionQueue *, void *);
+               grpc::Status status = grpc::Status::OK;
+               char *name = NULL;
+               while (uc_iterator_next(iter, &name) == 0) {
+                       value_list_t vl;
+                       if (parse_identifier_vl(name, &vl) != 0) {
+                               status = grpc::Status(grpc::StatusCode::INTERNAL,
+                                                                         grpc::string("failed to parse identifier"));
+                               break;
+                       }
 
-public:
-       RpcCall(Collectd::AsyncService *service,
-                       CreatorT creator, grpc::ServerCompletionQueue *cq)
-               : Call(service, cq), creator_(creator), responder_(&ctx_)
-       {
-               Handle();
-       } /* RpcCall() */
+                       if (!ident_matches(&vl, match))
+                               continue;
 
-       virtual ~RpcCall()
-       { }
+                       if (uc_iterator_get_time(iter, &vl.time) < 0) {
+                               status = grpc::Status(grpc::StatusCode::INTERNAL,
+                                                                         grpc::string("failed to retrieve value timestamp"));
+                               break;
+                       }
+                       if (uc_iterator_get_interval(iter, &vl.interval) < 0) {
+                               status = grpc::Status(grpc::StatusCode::INTERNAL,
+                                                                         grpc::string("failed to retrieve value interval"));
+                               break;
+                       }
+                       if (uc_iterator_get_values(iter, &vl.values, &vl.values_len) < 0) {
+                               status = grpc::Status(grpc::StatusCode::INTERNAL,
+                                                                         grpc::string("failed to retrieve values"));
+                               break;
+                       }
 
-private:
-       void Create()
-       {
-               (service_->*creator_)(&ctx_, &request_, &responder_, cq_, cq_, this);
-       } /* Create() */
+                       value_lists->push(vl);
+               } // while (uc_iterator_next(iter, &name) == 0)
 
-       void Process()
-       {
-               // Add a new request object to the queue.
-               new RpcCall<RequestT, ReplyT>(service_, creator_, cq_);
-               grpc::Status status = ::Process(&ctx_, request_, &reply_);
-               responder_.Finish(reply_, status, this);
-       } /* Process() */
+               uc_iterator_destroy(iter);
+               return status;
+       }
 
-       void Finish()
-       {
-               delete this;
-       } /* Finish() */
+       grpc::Status queryValuesWrite(grpc::ServerContext *ctx,
+                                          grpc::ServerWriter<QueryValuesResponse> *writer,
+                                          std::queue<value_list_t> *value_lists) {
+               while (!value_lists->empty()) {
+                       auto vl = value_lists->front();
+                       QueryValuesResponse res;
+                       res.Clear();
+
+                       auto status = marshal_value_list(&vl, res.mutable_value_list());
+                       if (!status.ok()) {
+                               return status;
+                       }
 
-       CreatorT creator_;
+                       if (!writer->Write(res)) {
+                               return grpc::Status::CANCELLED;
+                       }
 
-       RequestT request_;
-       ReplyT reply_;
+                       value_lists->pop();
+                       sfree(vl.values);
+               }
 
-       grpc::ServerAsyncResponseWriter<ReplyT> responder_;
-}; /* class RpcCall */
+               return grpc::Status::OK;
+       }
+};
 
 /*
  * gRPC server implementation
  */
-
 class CollectdServer final
 {
 public:
@@ -445,63 +404,75 @@ public:
                        }
                }
 
-               builder.RegisterService(&service_);
-               cq_ = builder.AddCompletionQueue();
+               builder.RegisterService(&collectd_service_);
+
                server_ = builder.BuildAndStart();
        } /* Start() */
 
        void Shutdown()
        {
                server_->Shutdown();
-               cq_->Shutdown();
        } /* Shutdown() */
 
-       void Mainloop()
-       {
-               // Register request types.
-               new RpcCall<DispatchValuesRequest, DispatchValuesReply>(&service_,
-                               &Collectd::AsyncService::RequestDispatchValues, cq_.get());
-               new RpcCall<QueryValuesRequest, QueryValuesReply>(&service_,
-                               &Collectd::AsyncService::RequestQueryValues, cq_.get());
-
-               while (true) {
-                       void *req = NULL;
-                       bool ok = false;
-
-                       if (!cq_->Next(&req, &ok))
-                               break; // Queue shut down.
-                       if (!ok) {
-                               ERROR("grpc: Failed to read from queue");
-                               break;
-                       }
-
-                       static_cast<Call *>(req)->Handle();
-               }
-       } /* Mainloop() */
-
 private:
-       Collectd::AsyncService service_;
+       CollectdImpl collectd_service_;
 
        std::unique_ptr<grpc::Server> server_;
-       std::unique_ptr<grpc::ServerCompletionQueue> cq_;
 }; /* class CollectdServer */
 
+class CollectdClient final
+{
+public:
+       CollectdClient(std::shared_ptr<grpc::ChannelInterface> channel) : stub_(Collectd::NewStub(channel)) {
+       }
+
+       int DispatchValues(value_list_t const *vl) {
+               grpc::ClientContext ctx;
+
+               DispatchValuesRequest req;
+               auto status = marshal_value_list(vl, req.mutable_value_list());
+               if (!status.ok()) {
+                       ERROR("grpc: Marshalling value_list_t failed.");
+                       return -1;
+               }
+
+               DispatchValuesResponse res;
+               auto stream = stub_->DispatchValues(&ctx, &res);
+               if (!stream->Write(req)) {
+                       NOTICE("grpc: Broken stream.");
+                       /* intentionally not returning. */
+               }
+
+               stream->WritesDone();
+               status = stream->Finish();
+               if (!status.ok()) {
+                       ERROR ("grpc: Error while closing stream.");
+                       return -1;
+               }
+
+               return 0;
+       } /* int DispatchValues */
+
+private:
+       std::unique_ptr<Collectd::Stub> stub_;
+};
+
 static CollectdServer *server = nullptr;
 
 /*
  * collectd plugin interface
  */
-
 extern "C" {
-       static pthread_t *workers;
-       static size_t workers_num = 5;
+       static void c_grpc_destroy_write_callback (void *ptr) {
+               delete (CollectdClient *) ptr;
+       }
 
-       static void *worker_thread(void *arg)
-       {
-               CollectdServer *s = (CollectdServer *)arg;
-               s->Mainloop();
-               return NULL;
-       } /* worker_thread() */
+       static int c_grpc_write(__attribute__((unused)) data_set_t const *ds,
+                       value_list_t const *vl,
+                       user_data_t *ud) {
+               CollectdClient *c = (CollectdClient *) ud->data;
+               return c->DispatchValues(vl);
+       }
 
        static int c_grpc_config_listen(oconfig_item_t *ci)
        {
@@ -532,7 +503,7 @@ extern "C" {
                                        return -1;
                                }
                        }
-                       else if (!strcasecmp("SSLRootCerts", child->key)) {
+                       else if (!strcasecmp("SSLCACertificateFile", child->key)) {
                                char *certs = NULL;
                                if (cf_util_get_string(child, &certs)) {
                                        ERROR("grpc: Option `%s` expects a string value",
@@ -541,7 +512,7 @@ extern "C" {
                                }
                                ssl_opts->pem_root_certs = read_file(certs);
                        }
-                       else if (!strcasecmp("SSLServerKey", child->key)) {
+                       else if (!strcasecmp("SSLCertificateKeyFile", child->key)) {
                                char *key = NULL;
                                if (cf_util_get_string(child, &key)) {
                                        ERROR("grpc: Option `%s` expects a string value",
@@ -550,7 +521,7 @@ extern "C" {
                                }
                                pkcp.private_key = read_file(key);
                        }
-                       else if (!strcasecmp("SSLServerCert", child->key)) {
+                       else if (!strcasecmp("SSLCertificateFile", child->key)) {
                                char *cert = NULL;
                                if (cf_util_get_string(child, &cert)) {
                                        ERROR("grpc: Option `%s` expects a string value",
@@ -575,6 +546,78 @@ extern "C" {
                return 0;
        } /* c_grpc_config_listen() */
 
+       static int c_grpc_config_server(oconfig_item_t *ci)
+       {
+               if ((ci->values_num != 2)
+                               || (ci->values[0].type != OCONFIG_TYPE_STRING)
+                               || (ci->values[1].type != OCONFIG_TYPE_STRING)) {
+                       ERROR("grpc: The `%s` config option needs exactly "
+                                       "two string argument (address and port).", ci->key);
+                       return -1;
+               }
+
+               grpc::SslCredentialsOptions ssl_opts;
+               bool use_ssl = false;
+
+               for (int i = 0; i < ci->children_num; i++) {
+                       oconfig_item_t *child = ci->children + i;
+
+                       if (!strcasecmp("EnableSSL", child->key)) {
+                               if (cf_util_get_boolean(child, &use_ssl)) {
+                                       return -1;
+                               }
+                       }
+                       else if (!strcasecmp("SSLCACertificateFile", child->key)) {
+                               char *certs = NULL;
+                               if (cf_util_get_string(child, &certs)) {
+                                       return -1;
+                               }
+                               ssl_opts.pem_root_certs = read_file(certs);
+                       }
+                       else if (!strcasecmp("SSLCertificateKeyFile", child->key)) {
+                               char *key = NULL;
+                               if (cf_util_get_string(child, &key)) {
+                                       return -1;
+                               }
+                               ssl_opts.pem_private_key = read_file(key);
+                       }
+                       else if (!strcasecmp("SSLCertificateFile", child->key)) {
+                               char *cert = NULL;
+                               if (cf_util_get_string(child, &cert)) {
+                                       return -1;
+                               }
+                               ssl_opts.pem_cert_chain = read_file(cert);
+                       }
+                       else {
+                               WARNING("grpc: Option `%s` not allowed in <%s> block.",
+                                               child->key, ci->key);
+                       }
+               }
+
+               auto node    = grpc::string(ci->values[0].value.string);
+               auto service = grpc::string(ci->values[1].value.string);
+               auto addr    = node + ":" + service;
+
+               CollectdClient *client;
+               if (use_ssl) {
+                       auto channel_creds = grpc::SslCredentials(ssl_opts);
+                       auto channel = grpc::CreateChannel(addr, channel_creds);
+                       client = new CollectdClient(channel);
+               } else {
+                       auto channel = grpc::CreateChannel(addr, grpc::InsecureChannelCredentials());
+                       client = new CollectdClient(channel);
+               }
+
+               auto callback_name = grpc::string("grpc/") + addr;
+               user_data_t ud = {
+                       .data = client,
+                       .free_func = c_grpc_destroy_write_callback,
+               };
+
+               plugin_register_write (callback_name.c_str(), c_grpc_write, &ud);
+               return 0;
+       } /* c_grpc_config_server() */
+
        static int c_grpc_config(oconfig_item_t *ci)
        {
                int i;
@@ -586,12 +629,11 @@ extern "C" {
                                if (c_grpc_config_listen(child))
                                        return -1;
                        }
-                       else if (!strcasecmp("WorkerThreads", child->key)) {
-                               int n;
-                               if (cf_util_get_int(child, &n))
+                       else if (!strcasecmp("Server", child->key)) {
+                               if (c_grpc_config_server(child))
                                        return -1;
-                               workers_num = (size_t)n;
                        }
+
                        else {
                                WARNING("grpc: Option `%s` not allowed here.", child->key);
                        }
@@ -603,47 +645,22 @@ extern "C" {
        static int c_grpc_init(void)
        {
                server = new CollectdServer();
-               size_t i;
-
-               if (! server) {
+               if (!server) {
                        ERROR("grpc: Failed to create server");
                        return -1;
                }
 
-               workers = (pthread_t *)calloc(workers_num, sizeof(*workers));
-               if (! workers) {
-                       delete server;
-                       server = nullptr;
-
-                       ERROR("grpc: Failed to allocate worker threads");
-                       return -1;
-               }
-
                server->Start();
-               for (i = 0; i < workers_num; i++) {
-                       plugin_thread_create(&workers[i], /* attr = */ NULL,
-                                       worker_thread, server);
-               }
-               INFO("grpc: Started %zu workers", workers_num);
                return 0;
        } /* c_grpc_init() */
 
        static int c_grpc_shutdown(void)
        {
-               size_t i;
-
                if (!server)
-                       return -1;
+                       return 0;
 
                server->Shutdown();
 
-               INFO("grpc: Waiting for %zu workers to terminate", workers_num);
-               for (i = 0; i < workers_num; i++)
-                       pthread_join(workers[i], NULL);
-               free(workers);
-               workers = NULL;
-               workers_num = 0;
-
                delete server;
                server = nullptr;
 
index 8213e97..865ea86 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 # include <netdb.h>
 # include <netinet/in.h>
index a74699e..b8ed6e4 100644 (file)
@@ -26,7 +26,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 
 #if HAVE_SYS_TYPES_H
index 70c55dc..b164cdf 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -30,7 +30,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #if KERNEL_LINUX
   /* _GNU_SOURCE is needed for struct shm_info.used_ids on musl libc */
index e035a88..f691122 100644 (file)
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <libiptc/libiptc.h>
 #include <libiptc/libip6tc.h>
 
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
 /*
  * iptc_handle_t was available before libiptc was officially available as a
  * shared library. Note, that when the shared lib was introduced, the API and
@@ -499,10 +502,30 @@ static int iptables_shutdown (void)
     return (0);
 } /* int iptables_shutdown */
 
+static int iptables_init (void)
+{
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_ADMIN)
+    if (check_capability (CAP_NET_ADMIN) != 0)
+    {
+        if (getuid () == 0)
+            WARNING ("iptables plugin: Running collectd as root, but the "
+                  "CAP_NET_ADMIN capability is missing. The plugin's read "
+                  "function will probably fail. Is your init system dropping "
+                  "capabilities?");
+        else
+            WARNING ("iptables plugin: collectd doesn't have the CAP_NET_ADMIN "
+                  "capability. If you don't want to run collectd as root, try "
+                  "running \"setcap cap_net_admin=ep\" on the collectd binary.");
+    }
+#endif
+    return (0);
+} /* int iptables_init */
+
 void module_register (void)
 {
     plugin_register_config ("iptables", iptables_config,
                              config_keys, config_keys_num);
+    plugin_register_init ("iptables", iptables_init);
     plugin_register_read ("iptables", iptables_read);
     plugin_register_shutdown ("iptables", iptables_shutdown);
 } /* void module_register */
index 0c36379..0f1d3f0 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 
 #if !KERNEL_LINUX
index 47f4cd3..67740ac 100644 (file)
@@ -1417,7 +1417,6 @@ static jint JNICALL cjni_api_register_init (JNIEnv *jvm_env, /* {{{ */
 static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
     jobject this, jobject o_name, jobject o_read)
 {
-  user_data_t ud = { 0 };
   cjni_callback_info_t *cbi;
 
   cbi = cjni_callback_info_create (jvm_env, o_name, o_read, CB_TYPE_READ);
@@ -1426,8 +1425,10 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new read callback: %s", cbi->name);
 
-  ud.data = (void *) cbi;
-  ud.free_func = cjni_callback_info_destroy;
+  user_data_t ud = {
+    .data = cbi,
+    .free_func = cjni_callback_info_destroy
+  };
 
   plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read,
       /* interval = */ 0, &ud);
@@ -1440,7 +1441,6 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
 static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
     jobject this, jobject o_name, jobject o_write)
 {
-  user_data_t ud = { 0 };
   cjni_callback_info_t *cbi;
 
   cbi = cjni_callback_info_create (jvm_env, o_name, o_write, CB_TYPE_WRITE);
@@ -1449,8 +1449,10 @@ static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new write callback: %s", cbi->name);
 
-  ud.data = (void *) cbi;
-  ud.free_func = cjni_callback_info_destroy;
+  user_data_t ud = {
+    .data = cbi,
+    .free_func = cjni_callback_info_destroy
+  };
 
   plugin_register_write (cbi->name, cjni_write, &ud);
 
@@ -1462,7 +1464,6 @@ static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
 static jint JNICALL cjni_api_register_flush (JNIEnv *jvm_env, /* {{{ */
     jobject this, jobject o_name, jobject o_flush)
 {
-  user_data_t ud = { 0 };
   cjni_callback_info_t *cbi;
 
   cbi = cjni_callback_info_create (jvm_env, o_name, o_flush, CB_TYPE_FLUSH);
@@ -1471,8 +1472,10 @@ static jint JNICALL cjni_api_register_flush (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new flush callback: %s", cbi->name);
 
-  ud.data = (void *) cbi;
-  ud.free_func = cjni_callback_info_destroy;
+  user_data_t ud = {
+    .data = cbi,
+    .free_func = cjni_callback_info_destroy
+  };
 
   plugin_register_flush (cbi->name, cjni_flush, &ud);
 
@@ -1491,7 +1494,6 @@ static jint JNICALL cjni_api_register_shutdown (JNIEnv *jvm_env, /* {{{ */
 static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */
     jobject this, jobject o_name, jobject o_log)
 {
-  user_data_t ud = { 0 };
   cjni_callback_info_t *cbi;
 
   cbi = cjni_callback_info_create (jvm_env, o_name, o_log, CB_TYPE_LOG);
@@ -1500,8 +1502,10 @@ static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new log callback: %s", cbi->name);
 
-  ud.data = (void *) cbi;
-  ud.free_func = cjni_callback_info_destroy;
+  user_data_t ud = {
+    .data = cbi,
+    .free_func = cjni_callback_info_destroy
+  };
 
   plugin_register_log (cbi->name, cjni_log, &ud);
 
@@ -1513,7 +1517,6 @@ static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */
 static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */
     jobject this, jobject o_name, jobject o_notification)
 {
-  user_data_t ud = { 0 };
   cjni_callback_info_t *cbi;
 
   cbi = cjni_callback_info_create (jvm_env, o_name, o_notification,
@@ -1523,8 +1526,10 @@ static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new notification callback: %s", cbi->name);
 
-  ud.data = (void *) cbi;
-  ud.free_func = cjni_callback_info_destroy;
+  user_data_t ud = {
+    .data = cbi,
+    .free_func = cjni_callback_info_destroy
+  };
 
   plugin_register_notification (cbi->name, cjni_notification, &ud);
 
index a15e0aa..4dbee1e 100644 (file)
@@ -113,6 +113,7 @@ typedef struct lcc_response_s lcc_response_t;
 /*
  * Private functions
  */
+__attribute__ ((format (printf, 1, 0)))
 static int lcc_tracef(char const *format, ...)
 {
   va_list ap;
index 319aae8..d6f0744 100644 (file)
@@ -43,7 +43,7 @@ static void yyset_in  (FILE *fd)
   yyin = fd;
 } /* void yyset_in */
 
-oconfig_item_t *oconfig_parse_fh (FILE *fh)
+static oconfig_item_t *oconfig_parse_fh (FILE *fh)
 {
   int status;
   oconfig_item_t *ret;
index 840137c..24045de 100644 (file)
@@ -64,7 +64,6 @@ struct oconfig_item_s
 /*
  * Functions
  */
-oconfig_item_t *oconfig_parse_fh (FILE *fh);
 oconfig_item_t *oconfig_parse_file (const char *file);
 
 oconfig_item_t *oconfig_clone (const oconfig_item_t *ci);
index 7a831c2..09de4d2 100644 (file)
 #include "aux_types.h"
 #include "parser.h"
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+
 /* multiline string buffer */
 static char *ml_buffer = NULL;
 static int   ml_pos    = 0;
@@ -159,3 +164,5 @@ static void ml_append (char *string)
        return;
 } /* ml_append */
 
+#pragma clang diagnostic pop
+#pragma GCC diagnostic pop
diff --git a/src/lua.c b/src/lua.c
new file mode 100644 (file)
index 0000000..ba5fbce
--- /dev/null
+++ b/src/lua.c
@@ -0,0 +1,593 @@
+/**
+ * collectd - src/lua.c
+ * Copyright (C) 2010       Julien Ammous
+ * Copyright (C) 2010       Florian Forster
+ * Copyright (C) 2016       Ruben Kerkhof
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Julien Ammous
+ *   Florian Forster <octo at collectd.org>
+ *   Ruben Kerkhof <ruben at rubenkerkhof.com>
+ **/
+
+/* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
+ * GCC will complain about the macro definition. */
+#define DONT_POISON_SPRINTF_YET
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+/* Include the Lua API header files. */
+#include "utils_lua.h"
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#include <pthread.h>
+
+#if COLLECT_DEBUG && __GNUC__
+#undef sprintf
+#pragma GCC poison sprintf
+#endif
+
+typedef struct lua_script_s {
+  char *script_path;
+  lua_State *lua_state;
+  struct lua_script_s *next;
+} lua_script_t;
+
+typedef struct {
+  lua_State *lua_state;
+  const char *lua_function_name;
+  pthread_mutex_t lock;
+  int callback_id;
+} clua_callback_data_t;
+
+static char base_path[PATH_MAX];
+static lua_script_t *scripts;
+
+static int clua_store_callback(lua_State *L, int idx) /* {{{ */
+{
+  /* Copy the function pointer */
+  lua_pushvalue(L, idx);
+
+  return luaL_ref(L, LUA_REGISTRYINDEX);
+} /* }}} int clua_store_callback */
+
+static int clua_load_callback(lua_State *L, int callback_ref) /* {{{ */
+{
+  lua_rawgeti(L, LUA_REGISTRYINDEX, callback_ref);
+
+  if (!lua_isfunction(L, -1)) {
+    lua_pop(L, 1);
+    return (-1);
+  }
+
+  return (0);
+} /* }}} int clua_load_callback */
+
+/* Store the threads in a global variable so they are not cleaned up by the
+ * garbage collector. */
+static int clua_store_thread(lua_State *L, int idx) /* {{{ */
+{
+  if (idx < 0)
+    idx += lua_gettop(L) + 1;
+
+  /* Copy the thread pointer */
+  lua_pushvalue(L, idx); /* +1 = 3 */
+  if (!lua_isthread(L, -1)) {
+    lua_pop(L, 3); /* -3 = 0 */
+    return (-1);
+  }
+
+  luaL_ref(L, LUA_REGISTRYINDEX);
+  lua_pop(L, 1); /* -1 = 0 */
+  return (0);
+} /* }}} int clua_store_thread */
+
+static int clua_read(user_data_t *ud) /* {{{ */
+{
+  clua_callback_data_t *cb = ud->data;
+
+  pthread_mutex_lock(&cb->lock);
+
+  lua_State *L = cb->lua_state;
+
+  int status = clua_load_callback(L, cb->callback_id);
+  if (status != 0) {
+    ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
+          cb->lua_function_name, cb->callback_id);
+    pthread_mutex_unlock(&cb->lock);
+    return (-1);
+  }
+  /* +1 = 1 */
+
+  status = lua_pcall(L, 0, 1, 0);
+  if (status != 0) {
+    const char *errmsg = lua_tostring(L, -1);
+    if (errmsg == NULL)
+      ERROR("Lua plugin: Calling a read callback failed. "
+            "In addition, retrieving the error message failed.");
+    else
+      ERROR("Lua plugin: Calling a read callback failed: %s", errmsg);
+    lua_pop(L, 1);
+    pthread_mutex_unlock(&cb->lock);
+    return (-1);
+  }
+
+  if (!lua_isnumber(L, -1)) {
+    ERROR("Lua plugin: Read function \"%s\" (id %i) did not return a numeric "
+          "status.",
+          cb->lua_function_name, cb->callback_id);
+    status = -1;
+  } else {
+    status = (int)lua_tointeger(L, -1);
+  }
+
+  /* pop return value and function */
+  lua_pop(L, 1); /* -1 = 0 */
+
+  pthread_mutex_unlock(&cb->lock);
+  return (status);
+} /* }}} int clua_read */
+
+static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
+                      user_data_t *ud) {
+  clua_callback_data_t *cb = ud->data;
+
+  pthread_mutex_lock(&cb->lock);
+
+  lua_State *L = cb->lua_state;
+
+  int status = clua_load_callback(L, cb->callback_id);
+  if (status != 0) {
+    ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
+          cb->lua_function_name, cb->callback_id);
+    pthread_mutex_unlock(&cb->lock);
+    return (-1);
+  }
+  /* +1 = 1 */
+
+  status = luaC_pushvaluelist(L, ds, vl);
+  if (status != 0) {
+    lua_pop(L, 1); /* -1 = 0 */
+    pthread_mutex_unlock(&cb->lock);
+    ERROR("Lua plugin: luaC_pushvaluelist failed.");
+    return (-1);
+  }
+  /* +1 = 2 */
+
+  status = lua_pcall(L, 1, 1, 0); /* -2+1 = 1 */
+  if (status != 0) {
+    const char *errmsg = lua_tostring(L, -1);
+    if (errmsg == NULL)
+      ERROR("Lua plugin: Calling the write callback failed. "
+            "In addition, retrieving the error message failed.");
+    else
+      ERROR("Lua plugin: Calling the write callback failed:\n%s", errmsg);
+    lua_pop(L, 1); /* -1 = 0 */
+    pthread_mutex_unlock(&cb->lock);
+    return (-1);
+  }
+
+  if (!lua_isnumber(L, -1)) {
+    ERROR("Lua plugin: Write function \"%s\" (id %i) did not return a numeric "
+          "value.",
+          cb->lua_function_name, cb->callback_id);
+    status = -1;
+  } else {
+    status = (int)lua_tointeger(L, -1);
+  }
+
+  lua_pop(L, 1); /* -1 = 0 */
+  pthread_mutex_unlock(&cb->lock);
+  return (status);
+} /* }}} int clua_write */
+
+/*
+ * Exported functions
+ */
+
+static int lua_cb_log_debug(lua_State *L) /* {{{ */
+{
+  const char *msg = luaL_checkstring(L, 1);
+  plugin_log(LOG_DEBUG, "%s", msg);
+  return 0;
+} /* }}} int lua_cb_log_debug */
+
+static int lua_cb_log_error(lua_State *L) /* {{{ */
+{
+  const char *msg = luaL_checkstring(L, 1);
+  plugin_log(LOG_ERR, "%s", msg);
+  return 0;
+} /* }}} int lua_cb_log_error */
+
+static int lua_cb_log_info(lua_State *L) /* {{{ */
+{
+  const char *msg = luaL_checkstring(L, 1);
+  plugin_log(LOG_INFO, "%s", msg);
+  return 0;
+} /* }}} int lua_cb_log_info */
+
+static int lua_cb_log_notice(lua_State *L) /* {{{ */
+{
+  const char *msg = luaL_checkstring(L, 1);
+  plugin_log(LOG_NOTICE, "%s", msg);
+  return 0;
+} /* }}} int lua_cb_log_notice */
+
+static int lua_cb_log_warning(lua_State *L) /* {{{ */
+{
+  const char *msg = luaL_checkstring(L, 1);
+  plugin_log(LOG_WARNING, "%s", msg);
+  return 0;
+} /* }}} int lua_cb_log_warning */
+
+static int lua_cb_dispatch_values(lua_State *L) /* {{{ */
+{
+  int nargs = lua_gettop(L);
+
+  if (nargs != 1)
+    return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+  luaL_checktype(L, 1, LUA_TTABLE);
+
+  value_list_t *vl = luaC_tovaluelist(L, -1);
+  if (vl == NULL)
+    return luaL_error(L, "%s", "luaC_tovaluelist failed");
+
+#if COLLECT_DEBUG
+  char identifier[6 * DATA_MAX_NAME_LEN];
+  FORMAT_VL(identifier, sizeof(identifier), vl);
+
+  DEBUG("Lua plugin: collectd.dispatch_values(): Received value list \"%s\", "
+        "time %.3f, interval %.3f.",
+        identifier, CDTIME_T_TO_DOUBLE(vl->time),
+        CDTIME_T_TO_DOUBLE(vl->interval));
+#endif
+
+  plugin_dispatch_values(vl);
+
+  sfree(vl->values);
+  sfree(vl);
+  return 0;
+} /* }}} lua_cb_dispatch_values */
+
+static int lua_cb_register_read(lua_State *L) /* {{{ */
+{
+  int nargs = lua_gettop(L);
+
+  if (nargs != 1)
+    return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+
+  char function_name[DATA_MAX_NAME_LEN];
+  ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+
+  int callback_id = clua_store_callback(L, 1);
+  if (callback_id < 0)
+    return luaL_error(L, "%s", "Storing callback function failed");
+
+  lua_State *thread = lua_newthread(L);
+  if (thread == NULL)
+    return luaL_error(L, "%s", "lua_newthread failed");
+  clua_store_thread(L, -1);
+  lua_pop(L, 1);
+
+  clua_callback_data_t *cb = calloc(1, sizeof(*cb));
+  if (cb == NULL)
+    return luaL_error(L, "%s", "calloc failed");
+
+  cb->lua_state = thread;
+  cb->callback_id = callback_id;
+  cb->lua_function_name = strdup(function_name);
+  pthread_mutex_init(&cb->lock, NULL);
+
+  user_data_t ud = {
+    .data = cb
+  };
+
+  int status = plugin_register_complex_read(/* group = */ "lua",
+                                            /* name      = */ function_name,
+                                            /* callback  = */ clua_read,
+                                            /* interval  = */ 0,
+                                            /* user_data = */ &ud);
+
+  if (status != 0)
+    return luaL_error(L, "%s", "plugin_register_complex_read failed");
+  return 0;
+} /* }}} int lua_cb_register_read */
+
+static int lua_cb_register_write(lua_State *L) /* {{{ */
+{
+  int nargs = lua_gettop(L);
+
+  if (nargs != 1)
+    return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+
+  char function_name[DATA_MAX_NAME_LEN] = "";
+  ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+
+  int callback_id = clua_store_callback(L, 1);
+  if (callback_id < 0)
+    return luaL_error(L, "%s", "Storing callback function failed");
+
+  lua_State *thread = lua_newthread(L);
+  if (thread == NULL)
+    return luaL_error(L, "%s", "lua_newthread failed");
+  clua_store_thread(L, -1);
+  lua_pop(L, 1);
+
+  clua_callback_data_t *cb = calloc(1, sizeof(*cb));
+  if (cb == NULL)
+    return luaL_error(L, "%s", "calloc failed");
+
+  cb->lua_state = thread;
+  cb->callback_id = callback_id;
+  cb->lua_function_name = strdup(function_name);
+  pthread_mutex_init(&cb->lock, NULL);
+
+  user_data_t ud = {
+    .data = cb
+  };
+
+  int status = plugin_register_write(/* name = */ function_name,
+                                    /* callback  = */ clua_write,
+                                    /* user_data = */ &ud);
+
+  if (status != 0)
+    return luaL_error(L, "%s", "plugin_register_write failed");
+  return 0;
+} /* }}} int lua_cb_register_write */
+
+static const luaL_Reg collectdlib[] = {
+    {"log_debug", lua_cb_log_debug},
+    {"log_error", lua_cb_log_error},
+    {"log_info", lua_cb_log_info},
+    {"log_notice", lua_cb_log_notice},
+    {"log_warning", lua_cb_log_warning},
+    {"dispatch_values", lua_cb_dispatch_values},
+    {"register_read", lua_cb_register_read},
+    {"register_write", lua_cb_register_write},
+    {NULL, NULL}
+};
+
+static int open_collectd(lua_State *L) /* {{{ */
+{
+#if LUA_VERSION_NUM < 502
+  luaL_register(L, "collectd", collectdlib);
+#else
+  luaL_newlib(L, collectdlib);
+#endif
+  return 1;
+} /* }}} */
+
+static void lua_script_free(lua_script_t *script) /* {{{ */
+{
+  if (script == NULL)
+    return;
+
+  lua_script_t *next = script->next;
+
+  if (script->lua_state != NULL) {
+    lua_close(script->lua_state);
+    script->lua_state = NULL;
+  }
+
+  sfree(script->script_path);
+  sfree(script);
+
+  lua_script_free(next);
+} /* }}} void lua_script_free */
+
+static int lua_script_init(lua_script_t *script) /* {{{ */
+{
+  memset(script, 0, sizeof(*script));
+
+  /* initialize the lua context */
+  script->lua_state = luaL_newstate();
+  if (script->lua_state == NULL) {
+    ERROR("Lua plugin: luaL_newstate() failed.");
+    return (-1);
+  }
+
+  /* Open up all the standard Lua libraries. */
+  luaL_openlibs(script->lua_state);
+
+  /* Load the 'collectd' library */
+#if LUA_VERSION_NUM < 502
+  lua_pushcfunction(script->lua_state, open_collectd);
+  lua_pushstring(script->lua_state, "collectd");
+  lua_call(script->lua_state, 1, 0);
+#else
+  luaL_requiref(script->lua_state, "collectd", open_collectd, 1);
+  lua_pop(script->lua_state, 1);
+#endif
+
+  /* Prepend BasePath to package.path */
+  if (base_path[0] != '\0') {
+    lua_getglobal(script->lua_state, "package");
+    lua_getfield(script->lua_state, -1, "path");
+
+    const char *cur_path = lua_tostring(script->lua_state, -1);
+    char *new_path = ssnprintf_alloc("%s/?.lua;%s", base_path, cur_path);
+
+    lua_pop(script->lua_state, 1);
+    lua_pushstring(script->lua_state, new_path);
+
+    free(new_path);
+
+    lua_setfield(script->lua_state, -2, "path");
+    lua_pop(script->lua_state, 1);
+  }
+
+  return (0);
+} /* }}} int lua_script_init */
+
+static int lua_script_load(const char *script_path) /* {{{ */
+{
+  lua_script_t *script = malloc(sizeof(*script));
+  if (script == NULL) {
+    ERROR("Lua plugin: malloc failed.");
+    return (-1);
+  }
+
+  int status = lua_script_init(script);
+  if (status != 0) {
+    lua_script_free(script);
+    return (status);
+  }
+
+  script->script_path = strdup(script_path);
+  if (script->script_path == NULL) {
+    ERROR("Lua plugin: strdup failed.");
+    lua_script_free(script);
+    return (-1);
+  }
+
+  status = luaL_loadfile(script->lua_state, script->script_path);
+  if (status != 0) {
+    ERROR("Lua plugin: luaL_loadfile failed: %s",
+          lua_tostring(script->lua_state, -1));
+    lua_pop(script->lua_state, 1);
+    lua_script_free(script);
+    return (-1);
+  }
+
+  status = lua_pcall(script->lua_state,
+                     /* nargs = */ 0,
+                     /* nresults = */ LUA_MULTRET,
+                     /* errfunc = */ 0);
+  if (status != 0) {
+    const char *errmsg = lua_tostring(script->lua_state, -1);
+
+    if (errmsg == NULL)
+      ERROR("Lua plugin: lua_pcall failed with status %i. "
+            "In addition, no error message could be retrieved from the stack.",
+            status);
+    else
+      ERROR("Lua plugin: Executing script \"%s\" failed:\n%s",
+            script->script_path, errmsg);
+
+    lua_script_free(script);
+    return (-1);
+  }
+
+  /* Append this script to the global list of scripts. */
+  if (scripts) {
+    lua_script_t *last = scripts;
+    while (last->next)
+      last = last->next;
+
+    last->next = script;
+  } else {
+    scripts = script;
+  }
+
+  return (0);
+} /* }}} int lua_script_load */
+
+static int lua_config_base_path(const oconfig_item_t *ci) /* {{{ */
+{
+  int status = cf_util_get_string_buffer(ci, base_path, sizeof(base_path));
+  if (status != 0)
+    return (status);
+
+  size_t len = strlen(base_path);
+  while ((len > 0) && (base_path[len - 1] == '/')) {
+    len--;
+    base_path[len] = '\0';
+  }
+
+  DEBUG("Lua plugin: base_path = \"%s\";", base_path);
+
+  return (0);
+} /* }}} int lua_config_base_path */
+
+static int lua_config_script(const oconfig_item_t *ci) /* {{{ */
+{
+  char rel_path[PATH_MAX];
+
+  int status = cf_util_get_string_buffer(ci, rel_path, sizeof(rel_path));
+  if (status != 0)
+    return (status);
+
+  char abs_path[PATH_MAX];
+
+  if (base_path[0] == '\0')
+    sstrncpy(abs_path, rel_path, sizeof(abs_path));
+  else
+    ssnprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path);
+
+  DEBUG("Lua plugin: abs_path = \"%s\";", abs_path);
+
+  status = lua_script_load(abs_path);
+  if (status != 0)
+    return (status);
+
+  INFO("Lua plugin: File \"%s\" loaded succesfully", abs_path);
+
+  return 0;
+} /* }}} int lua_config_script */
+
+/*
+ * <Plugin lua>
+ *   BasePath "/"
+ *   Script "script1.lua"
+ *   Script "script2.lua"
+ * </Plugin>
+ */
+static int lua_config(oconfig_item_t *ci) /* {{{ */
+{
+  int status = 0;
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp("BasePath", child->key) == 0) {
+      status = lua_config_base_path(child);
+    } else if (strcasecmp("Script", child->key) == 0) {
+      status = lua_config_script(child);
+    } else {
+      ERROR("Lua plugin: Option `%s' is not allowed here.", child->key);
+      status = 1;
+    }
+  }
+
+  return status;
+} /* }}} int lua_config */
+
+static int lua_shutdown(void) /* {{{ */
+{
+  lua_script_free(scripts);
+
+  return (0);
+} /* }}} int lua_shutdown */
+
+void module_register(void) {
+  plugin_register_complex_config("lua", lua_config);
+  plugin_register_shutdown("lua", lua_shutdown);
+}
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
index 728fcd8..053bd7f 100644 (file)
@@ -92,7 +92,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 
 #include <dirent.h>
index 184bb99..9629b89 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <netdb.h>
 #include <netinet/in.h>
index 6a96a90..44cad2e 100644 (file)
--- a/src/md.c
+++ b/src/md.c
 #include <linux/major.h>
 #include <linux/raid/md_u.h>
 
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+
 #define PROC_DISKSTATS "/proc/diskstats"
 #define DEV_DIR "/dev"
 
index 1b6ab67..dff5546 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_match.h"
 
 #include <libmemcached/memcached.h>
index 42882ae..9e6e725 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <netdb.h>
 #include <sys/un.h>
@@ -549,16 +548,17 @@ static int memcached_read (user_data_t *user_data)
 
 static int memcached_add_read_callback (memcached_t *st)
 {
-  user_data_t ud = { 0 };
   char callback_name[3*DATA_MAX_NAME_LEN];
   int status;
 
-  ud.data = st;
-  ud.free_func = memcached_free;
-
   assert (st->name != NULL);
   ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
 
+  user_data_t ud = {
+    .data = st,
+    .free_func = memcached_free
+  };
+
   status = plugin_register_complex_read (/* group = */ "memcached",
       /* name      = */ callback_name,
       /* callback  = */ memcached_read,
index db7d033..93fd54a 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <netdb.h>
 
index a7a0b86..ad88995 100644 (file)
@@ -548,7 +548,6 @@ static int mqtt_config_publisher (oconfig_item_t *ci)
 {
     mqtt_client_conf_t *conf;
     char cb_name[1024];
-    user_data_t user_data = { 0 };
     int status;
 
     conf = calloc (1, sizeof (*conf));
@@ -632,7 +631,9 @@ static int mqtt_config_publisher (oconfig_item_t *ci)
     }
 
     ssnprintf (cb_name, sizeof (cb_name), "mqtt/%s", conf->name);
-    user_data.data = conf;
+    user_data_t user_data = {
+        .data = conf
+    };
 
     plugin_register_write (cb_name, mqtt_write, &user_data);
     return (0);
index 6ba3005..32b72e2 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #ifdef HAVE_MYSQL_H
 #include <mysql.h>
@@ -47,6 +46,14 @@ struct mysql_database_s /* {{{ */
        char *user;
        char *pass;
        char *database;
+
+       /* mysql_ssl_set params */
+       char *key;
+       char *cert;
+       char *ca;
+       char *capath;
+       char *cipher;
+
        char *socket;
        int   port;
        int   timeout;
@@ -88,6 +95,11 @@ static void mysql_database_free (void *arg) /* {{{ */
        sfree (db->socket);
        sfree (db->instance);
        sfree (db->database);
+       sfree (db->key);
+       sfree (db->cert);
+       sfree (db->ca);
+       sfree (db->capath);
+       sfree (db->cipher);
        sfree (db);
 } /* }}} void mysql_database_free */
 
@@ -127,6 +139,12 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
        db->user     = NULL;
        db->pass     = NULL;
        db->database = NULL;
+       db->key      = NULL;
+       db->cert     = NULL;
+       db->ca       = NULL;
+       db->capath   = NULL;
+       db->cipher   = NULL;
+
        db->socket   = NULL;
        db->con      = NULL;
        db->timeout  = 0;
@@ -169,6 +187,16 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
                        status = cf_util_get_string (child, &db->socket);
                else if (strcasecmp ("Database", child->key) == 0)
                        status = cf_util_get_string (child, &db->database);
+               else if (strcasecmp ("SSLKey", child->key) == 0)
+                       status = cf_util_get_string (child, &db->key);
+               else if (strcasecmp ("SSLCert", child->key) == 0)
+                       status = cf_util_get_string (child, &db->cert);
+               else if (strcasecmp ("SSLCA", child->key) == 0)
+                       status = cf_util_get_string (child, &db->ca);
+               else if (strcasecmp ("SSLCAPath", child->key) == 0)
+                       status = cf_util_get_string (child, &db->capath);
+               else if (strcasecmp ("SSLCipher", child->key) == 0)
+                       status = cf_util_get_string (child, &db->cipher);
                else if (strcasecmp ("ConnectTimeout", child->key) == 0)
                        status = cf_util_get_int (child, &db->timeout);
                else if (strcasecmp ("MasterStats", child->key) == 0)
@@ -194,21 +222,22 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
        /* If all went well, register this database for reading */
        if (status == 0)
        {
-               user_data_t ud = { 0 };
                char cb_name[DATA_MAX_NAME_LEN];
 
                DEBUG ("mysql plugin: Registering new read callback: %s",
                                (db->database != NULL) ? db->database : "<default>");
 
-               ud.data = (void *) db;
-               ud.free_func = mysql_database_free;
-
                if (db->instance != NULL)
                        ssnprintf (cb_name, sizeof (cb_name), "mysql-%s",
                                        db->instance);
                else
                        sstrncpy (cb_name, "mysql", sizeof (cb_name));
 
+               user_data_t ud = {
+                       .data = db,
+                       .free_func = mysql_database_free
+               };
+
                plugin_register_complex_read (/* group = */ NULL, cb_name,
                                              mysql_read,
                                              /* interval = */ 0, &ud);
@@ -246,6 +275,8 @@ static int mysql_config (oconfig_item_t *ci) /* {{{ */
 
 static MYSQL *getconnection (mysql_database_t *db)
 {
+       const char *cipher;
+
        if (db->is_connected)
        {
                int status;
@@ -273,6 +304,8 @@ static MYSQL *getconnection (mysql_database_t *db)
        /* Configure TCP connect timeout (default: 0) */
        db->con->options.connect_timeout = db->timeout;
 
+       mysql_ssl_set (db->con, db->key, db->cert, db->ca, db->capath, db->cipher);
+
        if (mysql_real_connect (db->con, db->host, db->user, db->pass,
                                db->database, db->port, db->socket, 0) == NULL)
        {
@@ -284,10 +317,14 @@ static MYSQL *getconnection (mysql_database_t *db)
                return (NULL);
        }
 
+       cipher = mysql_get_ssl_cipher (db->con);
+
        INFO ("mysql plugin: Successfully connected to database %s "
-                       "at server %s (server version: %s, protocol version: %d)",
+                       "at server %s with cipher %s "
+                       "(server version: %s, protocol version: %d) ",
                        (db->database != NULL) ? db->database : "<none>",
                        mysql_get_host_info (db->con),
+                       (cipher != NULL) ?  cipher : "<none>",
                        mysql_get_server_info (db->con),
                        mysql_get_proto_info (db->con));
 
@@ -964,7 +1001,7 @@ static int mysql_read (user_data_t *ud)
                                counter_submit ("mysql_sort", "scan", val, db);
 
                }
-               else if (strncmp (key, "Slow_queries", strlen ("Slow_queries")) == 0) 
+               else if (strncmp (key, "Slow_queries", strlen ("Slow_queries")) == 0)
                {
                        counter_submit ("mysql_slow_queries", NULL , val, db);
                }
index 26577da..d739696 100644 (file)
@@ -2872,7 +2872,6 @@ static int cna_read (user_data_t *ud);
 static int cna_register_host (host_config_t *host) /* {{{ */
 {
        char cb_name[256];
-       user_data_t ud = { 0 };
 
        if (host->vfiler)
                ssnprintf (cb_name, sizeof (cb_name), "netapp-%s-%s",
@@ -2880,8 +2879,10 @@ static int cna_register_host (host_config_t *host) /* {{{ */
        else
                ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
 
-       ud.data = host;
-       ud.free_func = (void (*) (void *)) free_host_config;
+       user_data_t ud = {
+               .data = host,
+               .free_func = (void (*) (void *)) free_host_config
+       };
 
        plugin_register_complex_read (/* group = */ NULL, cb_name,
                        /* callback  = */ cna_read,
index 1458a0a..51c0757 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_fbhash.h"
 #include "utils_cache.h"
 #include "utils_complain.h"
index e346cee..16ce3d5 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <curl/curl.h>
 
index ef7b95b..5cab119 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <glib.h>
 #include <libnotify/notify.h>
index 57a034d..b08c411 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 
 #define NAGIOS_OK       0
 #define NAGIOS_WARNING  1
index a009365..30f29c9 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #if HAVE_STDINT_H
 # include <stdint.h>
index 282e2dc..d424cb4 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #if defined(__APPLE__)
 #pragma clang diagnostic push
@@ -653,19 +652,20 @@ static int cldap_config_add (oconfig_item_t *ci) /* {{{ */
                }
                else
                {
-                       user_data_t ud = { 0 };
                        char callback_name[3*DATA_MAX_NAME_LEN] = { 0 };
 
                        databases = temp;
                        databases[databases_num] = st;
                        databases_num++;
 
-                       ud.data = st;
-
                        ssnprintf (callback_name, sizeof (callback_name),
                                        "openldap/%s/%s",
                                        (st->host != NULL) ? st->host : hostname_g,
-                                       (st->name != NULL) ? st->name : "default"),
+                                       (st->name != NULL) ? st->name : "default");
+
+                       user_data_t ud = {
+                               .data = st
+                       };
 
                        status = plugin_register_complex_read (/* group = */ NULL,
                                        /* name      = */ callback_name,
index 1554830..c0f2fa4 100644 (file)
@@ -49,7 +49,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_db_query.h"
 
 #include <oci.h>
index 48374b6..9eef6c1 100644 (file)
@@ -37,8 +37,6 @@
 
 #undef DONT_POISON_SPRINTF_YET
 
-#include "configfile.h"
-
 #if HAVE_STDBOOL_H
 # include <stdbool.h>
 #endif
index b9eed68..8a0902a 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <netdb.h>
 #include <poll.h>
index 4932bae..5f66aab 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_complain.h"
 
 #include <netinet/in.h>
 # include <netdb.h> /* NI_MAXHOST */
 #endif
 
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
 #include <oping.h>
 
 #ifndef NI_MAXHOST
@@ -448,6 +451,20 @@ static int ping_init (void) /* {{{ */
         "Will use a timeout of %gs.", ping_timeout);
   }
 
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_RAW)
+  if (check_capability (CAP_NET_RAW) != 0)
+  {
+    if (getuid () == 0)
+      WARNING ("ping plugin: Running collectd as root, but the CAP_NET_RAW "
+          "capability is missing. The plugin's read function will probably "
+          "fail. Is your init system dropping capabilities?");
+    else
+      WARNING ("ping plugin: collectd doesn't have the CAP_NET_RAW capability. "
+          "If you don't want to run collectd as root, try running \"setcap "
+          "cap_net_raw=ep\" on the collectd binary.");
+  }
+#endif
+
   return (start_thread ());
 } /* }}} int ping_init */
 
index 7e69877..084eae4 100644 (file)
@@ -34,7 +34,6 @@
 
 #include "common.h"
 
-#include "configfile.h"
 #include "plugin.h"
 
 #include "utils_cache.h"
@@ -1177,8 +1176,6 @@ static int c_psql_config_database (oconfig_item_t *ci)
        c_psql_database_t *db;
 
        char cb_name[DATA_MAX_NAME_LEN];
-       user_data_t ud = { 0 };
-
        static _Bool have_flush = 0;
 
        if ((1 != ci->values_num)
@@ -1261,11 +1258,13 @@ static int c_psql_config_database (oconfig_item_t *ci)
                }
        }
 
-       ud.data = db;
-       ud.free_func = c_psql_database_delete;
-
        ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
 
+       user_data_t ud = {
+               .data = db,
+               .free_func = c_psql_database_delete
+       };
+
        if (db->queries_num > 0) {
                ++db->ref_cnt;
                plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
index e215a8c..f907d00 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_llist.h"
 
 #include <sys/stat.h>
index d34fe40..0513a15 100644 (file)
@@ -38,7 +38,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 /* Include header files for the mach system, if they exist.. */
 #if HAVE_THREAD_INFO
@@ -1567,7 +1566,7 @@ static int ps_read (void)
         * Tasks are assigned to sets of processors, so that's where you go to
         * get a list.
         */
-       for (int pset = 0; pset < pset_list_len; pset++)
+       for (mach_msg_type_number_t pset = 0; pset < pset_list_len; pset++)
        {
                if ((status = host_processor_set_priv (port_host_self,
                                                pset_list[pset],
@@ -1588,7 +1587,7 @@ static int ps_read (void)
                        continue;
                }
 
-               for (int task = 0; task < task_list_len; task++)
+               for (mach_msg_type_number_t task = 0; task < task_list_len; task++)
                {
                        ps = NULL;
                        if (mach_get_task_name (task_list[task],
@@ -1686,7 +1685,7 @@ static int ps_read (void)
                                continue; /* with next task_list */
                        }
 
-                       for (int thread = 0; thread < thread_list_len; thread++)
+                       for (mach_msg_type_number_t thread = 0; thread < thread_list_len; thread++)
                        {
                                thread_data_len = THREAD_BASIC_INFO_COUNT;
                                status = thread_info (thread_list[thread],
index 24046de..05a44aa 100644 (file)
@@ -389,12 +389,11 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                }
                dict = PyDict_New();  /* New reference. */
                if (value_list->meta) {
-                       int num;
                        char **table;
                        meta_data_t *meta = value_list->meta;
 
-                       num = meta_data_toc(meta, &table);
-                       for (size_t i = 0; i < num; ++i) {
+                       int num = meta_data_toc(meta, &table);
+                       for (int i = 0; i < num; ++i) {
                                int type;
                                char *string;
                                int64_t si;
@@ -624,7 +623,6 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
        char buf[512];
        reg_function_t *register_function = (reg_function_t *) reg;
        cpy_callback_t *c = NULL;
-       user_data_t user_data = { 0 };
        char *name = NULL;
        PyObject *callback = NULL, *data = NULL;
        static char *kwlist[] = {"callback", "data", "name", NULL};
@@ -650,8 +648,10 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
        c->data = data;
        c->next = NULL;
 
-       user_data.free_func = cpy_destroy_user_data;
-       user_data.data = c;
+       user_data_t user_data = {
+               .data = c,
+               .free_func = cpy_destroy_user_data
+       };
 
        register_function(buf, handler, &user_data);
        return cpy_string_to_unicode_or_bytes(buf);
@@ -660,7 +660,6 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
 static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
        char buf[512];
        cpy_callback_t *c = NULL;
-       user_data_t user_data = { 0 };
        double interval = 0;
        char *name = NULL;
        PyObject *callback = NULL, *data = NULL;
@@ -687,8 +686,10 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
        c->data = data;
        c->next = NULL;
 
-       user_data.free_func = cpy_destroy_user_data;
-       user_data.data = c;
+       user_data_t user_data = {
+               .data = c,
+               .free_func = cpy_destroy_user_data
+       };
 
        plugin_register_complex_read(/* group = */ "python", buf,
                        cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), &user_data);
index 7395ba0..5214ecc 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include <sys/time.h>
 #include <hiredis/hiredis.h>
index de2a4f7..4f3d0d6 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 
 #if defined(HAVE_SENSORS_SENSORS_H)
index e0e1973..abeda43 100644 (file)
@@ -634,7 +634,6 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
 
   /* Registration stuff. */
   char cb_name[DATA_MAX_NAME_LEN];
-  user_data_t cb_data = { 0 };
 
   hd = calloc (1, sizeof (*hd));
   if (hd == NULL)
@@ -765,11 +764,13 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
 
   ssnprintf (cb_name, sizeof (cb_name), "snmp-%s", hd->name);
 
-  cb_data.data = hd;
-  cb_data.free_func = csnmp_host_definition_destroy;
+  user_data_t ud = {
+    .data = hd,
+    .free_func = csnmp_host_definition_destroy
+  };
 
   status = plugin_register_complex_read (/* group = */ NULL, cb_name,
-      csnmp_read_host, hd->interval, /* user_data = */ &cb_data);
+      csnmp_read_host, hd->interval, /* user_data = */ &ud);
   if (status != 0)
   {
     ERROR ("snmp plugin: Registering complex read function failed.");
index 040181a..9c138f9 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_avltree.h"
 #include "utils_latency.h"
 
index 15eca9a..9c63e9b 100644 (file)
@@ -674,6 +674,7 @@ static int swap_read (void) /* {{{ */
        {
                ERROR ("swap plugin: Total swap space (%g) is less than used swap space (%g).",
                                total, used);
+               sfree (swap_entries);
                return (-1);
        }
 
index ba65f41..81e9461 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "common.h"
 
-#include "configfile.h"
 #include "plugin.h"
 
 #define log_err(...) ERROR ("table plugin: " __VA_ARGS__)
index b8922ec..e8cde1e 100644 (file)
@@ -328,7 +328,6 @@ static int ctail_read (user_data_t *ud)
 static int ctail_init (void)
 {
   char str[255];
-  user_data_t ud = { 0 };
 
   if (tail_match_list_num == 0)
   {
@@ -338,8 +337,12 @@ static int ctail_init (void)
 
   for (size_t i = 0; i < tail_match_list_num; i++)
   {
-    ud.data = (void *)tail_match_list[i];
     ssnprintf(str, sizeof(str), "tail-%zu", i);
+
+    user_data_t ud = {
+     .data = tail_match_list[i]
+    };
+
     plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i], &ud);
   }
 
index 79ea466..1bdf8b2 100644 (file)
@@ -421,7 +421,6 @@ static int tcsv_config_add_file(oconfig_item_t *ci)
 
     /* Registration variables */
     char cb_name[DATA_MAX_NAME_LEN];
-    user_data_t cb_data = { 0 };
 
     id = calloc(1, sizeof(*id));
     if (id == NULL)
@@ -482,9 +481,13 @@ static int tcsv_config_add_file(oconfig_item_t *ci)
     }
 
     ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->path);
-    cb_data.data = id;
-    cb_data.free_func = tcsv_instance_definition_destroy;
-    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &cb_data);
+
+    user_data_t ud = {
+        .data = id,
+        .free_func = tcsv_instance_definition_destroy
+    };
+
+    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &ud);
 
     if (status != 0){
         ERROR("tail_csv plugin: Registering complex read function failed.");
index 96c94e5..5ed6c27 100644 (file)
--- a/src/ted.c
+++ b/src/ted.c
@@ -38,7 +38,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #if HAVE_TERMIOS_H && HAVE_SYS_IOCTL_H && HAVE_MATH_H
 # include <termios.h>
index c6db8c0..e001a62 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 
 #if !KERNEL_LINUX
index 913511f..2d8a08e 100644 (file)
@@ -1474,35 +1474,22 @@ out:
 static int
 check_permissions(void)
 {
-#ifdef HAVE_SYS_CAPABILITY_H
-       struct __user_cap_header_struct cap_header_data;
-       cap_user_header_t cap_header = &cap_header_data;
-       struct __user_cap_data_struct cap_data_data;
-       cap_user_data_t cap_data = &cap_data_data;
-       int ret = 0;
-#endif /* HAVE_SYS_CAPABILITY_H */
 
        if (getuid() == 0) {
                /* We have everything we need */
                return 0;
-#ifndef HAVE_SYS_CAPABILITY_H
+#if !defined(HAVE_SYS_CAPABILITY_H) && !defined(CAP_SYS_RAWIO)
        } else {
                ERROR("turbostat plugin: Initialization failed: this plugin "
                      "requires collectd to run as root");
                return -1;
        }
-#else /* HAVE_SYS_CAPABILITY_H */
+#else /* HAVE_SYS_CAPABILITY_H && CAP_SYS_RAWIO */
        }
 
-       /* check for CAP_SYS_RAWIO */
-       cap_header->pid = getpid();
-       cap_header->version = _LINUX_CAPABILITY_VERSION;
-       if (capget(cap_header, cap_data) < 0) {
-               ERROR("turbostat plugin: capget failed");
-               return -1;
-       }
+       int ret = 0;
 
-       if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
+       if (check_capability(CAP_SYS_RAWIO) != 0) {
                WARNING("turbostat plugin: Collectd doesn't have the "
                        "CAP_SYS_RAWIO capability. If you don't want to run "
                        "collectd as root, try running \"setcap "
@@ -1524,7 +1511,7 @@ check_permissions(void)
                      "collectd a special capability (CAP_SYS_RAWIO) and read "
                       "access to /dev/cpu/*/msr (see previous warnings)");
        return ret;
-#endif /* HAVE_SYS_CAPABILITY_H */
+#endif /* HAVE_SYS_CAPABILITY_H && CAP_SYS_RAWIO */
 }
 
 static int
index 1faeff9..808ba98 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include "utils_cmd_flush.h"
 #include "utils_cmd_getval.h"
index f708c62..b6d0bb4 100644 (file)
@@ -27,7 +27,6 @@
 #ifndef UTILS_CURL_STATS_H
 #define UTILS_CURL_STATS_H 1
 
-#include "configfile.h"
 #include "plugin.h"
 
 #include <curl/curl.h>
index c801984..bbee90a 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_db_query.h"
 
 /*
@@ -257,7 +256,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
     {
       int status = strjoin (vl.type_instance, sizeof (vl.type_instance),
           r_area->instances_buffer, r->instances_num, "-");
-      if (status != 0)
+      if (status < 0)
       {
         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
             status);
@@ -270,7 +269,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
 
       int status = strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
           r->instances_num, "-");
-      if (status != 0)
+      if (status < 0)
       {
         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
             status);
index 8586adb..fe06de9 100644 (file)
@@ -27,8 +27,6 @@
 #ifndef UTILS_DB_QUERY_H
 #define UTILS_DB_QUERY_H 1
 
-#include "configfile.h"
-
 /*
  * Data types
  */
index 1c8a8ce..1400694 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  */
 
+/* Workaround for Solaris 10 defining label_t
+ * Issue #1301
+ */
+#if KERNEL_SOLARIS
+# ifndef _POSIX_C_SOURCE
+#  define _POSIX_C_SOURCE 200112L
+# endif
+# undef __EXTENSIONS__
+#endif
+
 #include "collectd.h"
 
 #include "testing.h"
index bfb9292..c67752a 100644 (file)
@@ -125,8 +125,8 @@ latency_counter_t *latency_counter_create (void) /* {{{ */
   if (lc == NULL)
     return (NULL);
 
-  latency_counter_reset (lc);
   lc->bin_width = HISTOGRAM_DEFAULT_BIN_WIDTH;
+  latency_counter_reset (lc);
   return (lc);
 } /* }}} latency_counter_t *latency_counter_create */
 
@@ -175,6 +175,28 @@ void latency_counter_reset (latency_counter_t *lc) /* {{{ */
     return;
 
   cdtime_t bin_width = lc->bin_width;
+  cdtime_t max_bin = (lc->max - 1) / lc->bin_width;
+
+/*
+  If max latency is REDUCE_THRESHOLD times less than histogram's range,
+  then cut it in half. REDUCE_THRESHOLD must be >= 2.
+  Value of 4 is selected to reduce frequent changes of bin width.
+*/
+#define REDUCE_THRESHOLD 4
+  if ((lc->num > 0) && (lc->bin_width >= HISTOGRAM_DEFAULT_BIN_WIDTH * 2)
+     && (max_bin < HISTOGRAM_NUM_BINS / REDUCE_THRESHOLD))
+  {
+    /* new bin width will be the previous power of 2 */
+    bin_width = bin_width / 2;
+
+    DEBUG("utils_latency: latency_counter_reset: max_latency = %.3f; "
+          "max_bin = %"PRIu64"; old_bin_width = %.3f; new_bin_width = %.3f;",
+        CDTIME_T_TO_DOUBLE (lc->max),
+        max_bin,
+        CDTIME_T_TO_DOUBLE (lc->bin_width),
+        CDTIME_T_TO_DOUBLE (bin_width));
+  }
+
   memset (lc, 0, sizeof (*lc));
 
   /* preserve bin width */
diff --git a/src/utils_lua.c b/src/utils_lua.c
new file mode 100644 (file)
index 0000000..f746655
--- /dev/null
@@ -0,0 +1,322 @@
+/**
+ * collectd - src/utils_lua.c
+ * Copyright (C) 2010       Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Florian Forster <octo at collectd.org>
+ **/
+
+/* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
+ * GCC will complain about the macro definition. */
+#define DONT_POISON_SPRINTF_YET
+
+#include "utils_lua.h"
+#include "common.h"
+
+static int ltoc_values(lua_State *L, /* {{{ */
+                       const data_set_t *ds, value_t *ret_values) {
+  if (!lua_istable(L, -1)) {
+    WARNING("ltoc_values: not a table");
+    return (-1);
+  }
+
+  /* Push initial key */
+  lua_pushnil(L); /* +1 = 1 */
+  size_t i = 0;
+  while (lua_next(L, -2) != 0) /* -1+2 = 2 || -1 = 0 */
+  {
+    if (i >= ds->ds_num) {
+      lua_pop(L, 2); /* -2 = 0 */
+      i++;
+      break;
+    }
+
+    ret_values[i] = luaC_tovalue(L, -1, ds->ds[i].type);
+
+    /* Pop the value */
+    lua_pop(L, 1); /* -1 = 1 */
+    i++;
+  } /* while (lua_next) */
+
+  if (i != ds->ds_num) {
+    WARNING("ltoc_values: invalid size for datasource \"%s\": expected %zu, "
+            "got %zu",
+            ds->type, ds->ds_num, i);
+    return (-1);
+  }
+
+  return (0);
+} /* }}} int ltoc_values */
+
+static int ltoc_table_values(lua_State *L, int idx, /* {{{ */
+                             const data_set_t *ds, value_list_t *vl) {
+  /* We're only called from "luaC_tovaluelist", which ensures that "idx" is an
+   * absolute index (i.e. a positive number) */
+  assert(idx > 0);
+
+  lua_getfield(L, idx, "values");
+  if (!lua_istable(L, -1)) {
+    WARNING("utils_lua: ltoc_table_values: The \"values\" member is a %s "
+            "value, not a table.",
+            lua_typename(L, lua_type(L, -1)));
+    lua_pop(L, 1);
+    return (-1);
+  }
+
+  vl->values_len = ds->ds_num;
+  vl->values = calloc(vl->values_len, sizeof(*vl->values));
+  if (vl->values == NULL) {
+    ERROR("utils_lua: calloc failed.");
+    vl->values_len = 0;
+    lua_pop(L, 1);
+    return (-1);
+  }
+
+  int status = ltoc_values(L, ds, vl->values);
+
+  lua_pop(L, 1);
+
+  if (status != 0) {
+    vl->values_len = 0;
+    sfree(vl->values);
+  }
+
+  return (status);
+} /* }}} int ltoc_table_values */
+
+static int luaC_pushvalues(lua_State *L, const data_set_t *ds,
+                           const value_list_t *vl) /* {{{ */
+{
+  assert(vl->values_len == ds->ds_num);
+
+  lua_newtable(L);
+  for (size_t i = 0; i < vl->values_len; i++) {
+    lua_pushinteger(L, (lua_Integer)i + 1);
+    luaC_pushvalue(L, vl->values[i], ds->ds[i].type);
+    lua_settable(L, -3);
+  }
+
+  return (0);
+} /* }}} int luaC_pushvalues */
+
+static int luaC_pushdstypes(lua_State *L, const data_set_t *ds) /* {{{ */
+{
+  lua_newtable(L);
+  for (size_t i = 0; i < ds->ds_num; i++) {
+    lua_pushinteger(L, (lua_Integer)i);
+    lua_pushstring(L, DS_TYPE_TO_STRING(ds->ds[i].type));
+    lua_settable(L, -3);
+  }
+
+  return (0);
+} /* }}} int luaC_pushdstypes */
+
+static int luaC_pushdsnames(lua_State *L, const data_set_t *ds) /* {{{ */
+{
+  lua_newtable(L);
+  for (size_t i = 0; i < ds->ds_num; i++) {
+    lua_pushinteger(L, (lua_Integer)i);
+    lua_pushstring(L, ds->ds[i].name);
+    lua_settable(L, -3);
+  }
+
+  return (0);
+} /* }}} int luaC_pushdsnames */
+
+/*
+ * Public functions
+ */
+cdtime_t luaC_tocdtime(lua_State *L, int idx) /* {{{ */
+{
+  if (!lua_isnumber(L, /* stack pos = */ idx))
+    return (0);
+
+  double d = lua_tonumber(L, idx);
+
+  return (DOUBLE_TO_CDTIME_T(d));
+} /* }}} int ltoc_table_cdtime */
+
+int luaC_tostringbuffer(lua_State *L, int idx, /* {{{ */
+                        char *buffer, size_t buffer_size) {
+  const char *str = lua_tostring(L, idx);
+  if (str == NULL)
+    return (-1);
+
+  sstrncpy(buffer, str, buffer_size);
+  return (0);
+} /* }}} int luaC_tostringbuffer */
+
+value_t luaC_tovalue(lua_State *L, int idx, int ds_type) /* {{{ */
+{
+  value_t v = { 0 };
+
+  if (!lua_isnumber(L, idx))
+    return (v);
+
+  if (ds_type == DS_TYPE_GAUGE)
+    v.gauge = (gauge_t)lua_tonumber(L, /* stack pos = */ -1);
+  else if (ds_type == DS_TYPE_DERIVE)
+    v.derive = (derive_t)lua_tointeger(L, /* stack pos = */ -1);
+  else if (ds_type == DS_TYPE_COUNTER)
+    v.counter = (counter_t)lua_tointeger(L, /* stack pos = */ -1);
+  else if (ds_type == DS_TYPE_ABSOLUTE)
+    v.absolute = (absolute_t)lua_tointeger(L, /* stack pos = */ -1);
+
+  return (v);
+} /* }}} value_t luaC_tovalue */
+
+value_list_t *luaC_tovaluelist(lua_State *L, int idx) /* {{{ */
+{
+#if COLLECT_DEBUG
+  int stack_top_before = lua_gettop(L);
+#endif
+
+  /* Convert relative indexes to absolute indexes, so it doesn't change when we
+   * push / pop stuff. */
+  if (idx < 1)
+    idx += lua_gettop(L) + 1;
+
+  /* Check that idx is in the valid range */
+  if ((idx < 1) || (idx > lua_gettop(L))) {
+    DEBUG("luaC_tovaluelist: idx(%d), top(%d)", idx, stack_top_before);
+    return (NULL);
+  }
+
+  value_list_t *vl = calloc(1, sizeof(*vl));
+  if (vl == NULL) {
+    DEBUG("luaC_tovaluelist: calloc failed");
+    return (NULL);
+  }
+
+  /* Push initial key */
+  lua_pushnil(L);
+  while (lua_next(L, idx) != 0) {
+    const char *key = lua_tostring(L, -2);
+
+    if (key == NULL) {
+      DEBUG("luaC_tovaluelist: Ignoring non-string key.");
+    } else if (strcasecmp("host", key) == 0)
+      luaC_tostringbuffer(L, -1, vl->host, sizeof(vl->host));
+    else if (strcasecmp("plugin", key) == 0)
+      luaC_tostringbuffer(L, -1, vl->plugin, sizeof(vl->plugin));
+    else if (strcasecmp("plugin_instance", key) == 0)
+      luaC_tostringbuffer(L, -1, vl->plugin_instance,
+                          sizeof(vl->plugin_instance));
+    else if (strcasecmp("type", key) == 0)
+      luaC_tostringbuffer(L, -1, vl->type, sizeof(vl->type));
+    else if (strcasecmp("type_instance", key) == 0)
+      luaC_tostringbuffer(L, -1, vl->type_instance,
+                          sizeof(vl->type_instance));
+    else if (strcasecmp("time", key) == 0)
+      vl->time = luaC_tocdtime(L, -1);
+    else if (strcasecmp("interval", key) == 0)
+      vl->interval = luaC_tocdtime(L, -1);
+    else if (strcasecmp("values", key) == 0) {
+      /* This key is not handled here, because we have to assure "type" is read
+       * first. */
+    } else {
+      DEBUG("luaC_tovaluelist: Ignoring unknown key \"%s\".", key);
+    }
+
+    /* Pop the value */
+    lua_pop(L, 1);
+  }
+
+  const data_set_t *ds = plugin_get_ds(vl->type);
+  if (ds == NULL) {
+    INFO("utils_lua: Unable to lookup type \"%s\".", vl->type);
+    sfree(vl);
+    return (NULL);
+  }
+
+  int status = ltoc_table_values(L, idx, ds, vl);
+  if (status != 0) {
+    WARNING("utils_lua: ltoc_table_values failed.");
+    sfree(vl);
+    return (NULL);
+  }
+
+#if COLLECT_DEBUG
+  assert(stack_top_before == lua_gettop(L));
+#endif
+  return (vl);
+} /* }}} value_list_t *luaC_tovaluelist */
+
+int luaC_pushcdtime(lua_State *L, cdtime_t t) /* {{{ */
+{
+  double d = CDTIME_T_TO_DOUBLE(t);
+
+  lua_pushnumber(L, (lua_Number)d);
+  return (0);
+} /* }}} int luaC_pushcdtime */
+
+int luaC_pushvalue(lua_State *L, value_t v, int ds_type) /* {{{ */
+{
+  if (ds_type == DS_TYPE_GAUGE)
+    lua_pushnumber(L, (lua_Number)v.gauge);
+  else if (ds_type == DS_TYPE_DERIVE)
+    lua_pushinteger(L, (lua_Integer)v.derive);
+  else if (ds_type == DS_TYPE_COUNTER)
+    lua_pushinteger(L, (lua_Integer)v.counter);
+  else if (ds_type == DS_TYPE_ABSOLUTE)
+    lua_pushinteger(L, (lua_Integer)v.absolute);
+  else
+    return (-1);
+  return (0);
+} /* }}} int luaC_pushvalue */
+
+int luaC_pushvaluelist(lua_State *L, const data_set_t *ds,
+                       const value_list_t *vl) /* {{{ */
+{
+  lua_newtable(L);
+
+  lua_pushstring(L, vl->host);
+  lua_setfield(L, -2, "host");
+
+  lua_pushstring(L, vl->plugin);
+  lua_setfield(L, -2, "plugin");
+  lua_pushstring(L, vl->plugin_instance);
+  lua_setfield(L, -2, "plugin_instance");
+
+  lua_pushstring(L, vl->type);
+  lua_setfield(L, -2, "type");
+  lua_pushstring(L, vl->type_instance);
+  lua_setfield(L, -2, "type_instance");
+
+  luaC_pushvalues(L, ds, vl);
+  lua_setfield(L, -2, "values");
+
+  luaC_pushdstypes(L, ds);
+  lua_setfield(L, -2, "dstypes");
+
+  luaC_pushdsnames(L, ds);
+  lua_setfield(L, -2, "dsnames");
+
+  luaC_pushcdtime(L, vl->time);
+  lua_setfield(L, -2, "time");
+
+  luaC_pushcdtime(L, vl->interval);
+  lua_setfield(L, -2, "interval");
+
+  return (0);
+} /* }}} int luaC_pushvaluelist */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_lua.h b/src/utils_lua.h
new file mode 100644 (file)
index 0000000..b594190
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * collectd - src/utils_lua.h
+ * Copyright (C) 2010       Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Florian Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_LUA_H
+#define UTILS_LUA_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+#ifndef DONT_POISON_SPRINTF_YET
+#error "Files including utils_lua.h need to define DONT_POISON_SPRINTF_YET."
+#endif
+#include <lua.h>
+
+/*
+ * access functions (stack -> C)
+ */
+cdtime_t luaC_tocdtime(lua_State *L, int idx);
+int luaC_tostringbuffer(lua_State *L, int idx, char *buffer,
+                        size_t buffer_size);
+value_t luaC_tovalue(lua_State *L, int idx, int ds_type);
+value_list_t *luaC_tovaluelist(lua_State *L, int idx);
+
+/*
+ * push functions (C -> stack)
+ */
+int luaC_pushcdtime(lua_State *L, cdtime_t t);
+int luaC_pushvalue(lua_State *L, value_t v, int ds_type);
+int luaC_pushvaluelist(lua_State *L, const data_set_t *ds,
+                       const value_list_t *vl);
+
+#endif /* UTILS_LUA_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
index 8976626..8bae376 100644 (file)
@@ -27,7 +27,6 @@
 #include "collectd.h"
 
 #include "common.h"
-#include "configfile.h"
 #include "plugin.h"
 
 #if HAVE_SYS_SYSCTL_H
index bc6d294..6cc092c 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #if HAVE_VARNISH_V4
 #include <vapi/vsm.h>
@@ -939,7 +938,6 @@ static int varnish_config_apply_default (user_config_t *conf) /* {{{ */
 static int varnish_init (void) /* {{{ */
 {
        user_config_t *conf;
-       user_data_t ud;
 
        if (have_instance)
                return (0);
@@ -953,8 +951,10 @@ static int varnish_init (void) /* {{{ */
 
        varnish_config_apply_default (conf);
 
-       ud.data = conf;
-       ud.free_func = varnish_config_free;
+       user_data_t ud = {
+               .data = conf,
+               .free_func = varnish_config_free
+       };
 
        plugin_register_complex_read (/* group = */ "varnish",
                        /* name      = */ "varnish/localhost",
index 7df51c1..c1c77bc 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 #include "utils_ignorelist.h"
 #include "utils_complain.h"
 
index 2dce2d7..fe2376a 100644 (file)
@@ -46,7 +46,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include "utils_complain.h"
 #include "utils_format_graphite.h"
@@ -240,6 +239,8 @@ static int wg_callback_init (struct wg_callback *cb)
             continue;
         }
 
+        set_sock_opts (cb->sock_fd);
+
         status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
         if (status != 0)
         {
@@ -473,7 +474,6 @@ static int config_set_char (char *dest,
 static int wg_config_node (oconfig_item_t *ci)
 {
     struct wg_callback *cb;
-    user_data_t user_data = { 0 };
     char callback_name[DATA_MAX_NAME_LEN];
     int status = 0;
 
@@ -575,12 +575,15 @@ static int wg_config_node (oconfig_item_t *ci)
         ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
                 cb->name);
 
-    user_data.data = cb;
-    user_data.free_func = wg_callback_free;
-    plugin_register_write (callback_name, wg_write, &user_data);
+    user_data_t ud = {
+        .data = cb,
+        .free_func = wg_callback_free
+    };
+
+    plugin_register_write (callback_name, wg_write, &ud);
 
-    user_data.free_func = NULL;
-    plugin_register_flush (callback_name, wg_flush, &user_data);
+    ud.free_func = NULL;
+    plugin_register_flush (callback_name, wg_flush, &ud);
 
     return (0);
 }
index d8d8c34..41615d3 100644 (file)
@@ -362,7 +362,11 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
 
         int status;
 
-        if (0 != strcmp (ds->type, vl->type)) {
+        /* sanity checks, primarily to make static analyzers happy. */
+        if ((cb == NULL) || (cb->send_buffer == NULL))
+                return -1;
+
+        if (strcmp (ds->type, vl->type) == 0) {
                 ERROR ("write_http plugin: DS type does not match "
                                 "value list type");
                 return -1;
@@ -649,7 +653,6 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
 {
         wh_callback_t *cb;
         int buffer_size = 0;
-        user_data_t user_data = { 0 };
         char callback_name[DATA_MAX_NAME_LEN];
         int status = 0;
 
@@ -813,7 +816,10 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
         DEBUG ("write_http: Registering write callback '%s' with URL '%s'",
                         callback_name, cb->location);
 
-        user_data.data = cb;
+        user_data_t user_data = {
+                .data = cb
+        };
+
         plugin_register_flush (callback_name, wh_flush, &user_data);
 
         user_data.free_func = wh_callback_free;
index 6364c6c..9fda2df 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_cmd_putval.h"
 #include "utils_format_graphite.h"
 #include "utils_format_json.h"
@@ -246,7 +245,6 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     char                        *val;
     char                         callback_name[DATA_MAX_NAME_LEN];
     char                         errbuf[1024];
-    user_data_t                  ud;
     oconfig_item_t              *child;
     rd_kafka_conf_res_t          ret;
 
@@ -385,8 +383,10 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     ssnprintf(callback_name, sizeof(callback_name),
               "write_kafka/%s", tctx->topic_name);
 
-    ud.data = tctx;
-    ud.free_func = kafka_topic_context_free;
+    user_data_t ud = {
+        .data = tctx,
+        .free_func = kafka_topic_context_free
+    };
 
     status = plugin_register_write (callback_name, kafka_write, &ud);
     if (status != 0) {
index 3c59978..b0dc6f1 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include "utils_format_graphite.h"
 
@@ -60,7 +59,7 @@ static int wl_write_messages (const data_set_t *ds, const value_list_t *vl)
 } /* int wl_write_messages */
 
 static int wl_write (const data_set_t *ds, const value_list_t *vl,
-        user_data_t *user_data)
+        __attribute__ ((unused)) user_data_t *user_data)
 {
     int status;
 
index 8fb13c3..6d5f379 100644 (file)
@@ -32,7 +32,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_cache.h"
 
 #if HAVE_STDINT_H
@@ -337,12 +336,13 @@ static int wm_config_node (oconfig_item_t *ci) /* {{{ */
   if (status == 0)
   {
     char cb_name[DATA_MAX_NAME_LEN];
-    user_data_t ud;
 
     ssnprintf (cb_name, sizeof (cb_name), "write_mongodb/%s", node->name);
 
-    ud.data = node;
-    ud.free_func = wm_config_free;
+    user_data_t ud = {
+      .data = node,
+      .free_func = wm_config_free
+    };
 
     status = plugin_register_write (cb_name, wm_write, &ud);
     INFO ("write_mongodb plugin: registered write plugin %s %d",cb_name,status);
index 135a458..4722416 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 
 #include <sys/time.h>
 #include <hiredis/hiredis.h>
@@ -232,12 +231,13 @@ static int wr_config_node (oconfig_item_t *ci) /* {{{ */
   if (status == 0)
   {
     char cb_name[DATA_MAX_NAME_LEN];
-    user_data_t ud;
 
     ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
 
-    ud.data = node;
-    ud.free_func = wr_config_free;
+    user_data_t ud = {
+      .data = node,
+      .free_func = wr_config_free
+    };
 
     status = plugin_register_write (cb_name, wr_write, &ud);
   }
index 10f8958..043a06b 100644 (file)
@@ -31,7 +31,6 @@
 #include "collectd.h"
 
 #include "common.h"
-#include "configfile.h"
 #include "plugin.h"
 #include "utils_cache.h"
 #include "utils_complain.h"
@@ -112,6 +111,8 @@ static int wrr_connect(struct riemann_host *host) /* {{{ */
     }
   }
 
+  set_sock_opts(riemann_client_get_fd(host->client));
+
   c_release(LOG_INFO, &host->init_complaint,
             "write_riemann plugin: Successfully connected to %s:%d", node,
             port);
@@ -610,7 +611,6 @@ static int wrr_config_node(oconfig_item_t *ci) /* {{{ */
   int i;
   oconfig_item_t *child;
   char callback_name[DATA_MAX_NAME_LEN];
-  user_data_t ud;
 
   if ((host = calloc(1, sizeof(*host))) == NULL) {
     ERROR("write_riemann plugin: calloc failed.");
@@ -788,8 +788,11 @@ static int wrr_config_node(oconfig_item_t *ci) /* {{{ */
 
   ssnprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
             host->name);
-  ud.data = host;
-  ud.free_func = wrr_free;
+
+  user_data_t ud = {
+    .data = host,
+    .free_func = wrr_free
+  };
 
   pthread_mutex_lock(&host->lock);
 
index b07b3bf..d764d26 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "plugin.h"
 #include "common.h"
-#include "configfile.h"
 #include "utils_cache.h"
 #include <arpa/inet.h>
 #include <errno.h>
@@ -196,6 +195,8 @@ static int sensu_connect(struct sensu_host *host) /* {{{ */
                if (setsockopt(host->s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) != 0)
                        WARNING("write_sensu plugin: failed to set socket close() lingering");
 
+               set_sock_opts(host->s);
+
                // connect the socket
                if (connect(host->s, ai->ai_addr, ai->ai_addrlen) != 0) {
                        close(host->s);
@@ -530,7 +531,7 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */
        in_place_replace_sensu_name_reserved(service_buffer);
 
        // finalize the buffer by setting the output and closing curly bracket
-       res = my_asprintf(&temp_str, "%s, \"output\": \"%s %s %ld\"}\n", ret_str, service_buffer, value_str, CDTIME_T_TO_TIME_T(vl->time));
+       res = my_asprintf(&temp_str, "%s, \"output\": \"%s %s %lld\"}\n",ret_str, service_buffer, value_str, (long long)CDTIME_T_TO_TIME_T(vl->time));
        free(ret_str);
        free(value_str);
        if (res == -1) {
@@ -666,7 +667,7 @@ static char *sensu_notification_to_json(struct sensu_host *host, /* {{{ */
        ret_str = temp_str;
 
        // incorporate the timestamp
-       res = my_asprintf(&temp_str, "%s, \"timestamp\": %ld", ret_str, CDTIME_T_TO_TIME_T(n->time));
+       res = my_asprintf(&temp_str, "%s, \"timestamp\": %lld", ret_str, (long long)CDTIME_T_TO_TIME_T(n->time));
        free(ret_str);
        if (res == -1) {
                ERROR("write_sensu plugin: Unable to alloc memory");
@@ -977,7 +978,6 @@ static int sensu_config_node(oconfig_item_t *ci) /* {{{ */
        int                                     status = 0;
        oconfig_item_t          *child;
        char                            callback_name[DATA_MAX_NAME_LEN];
-       user_data_t                     ud;
 
        if ((host = calloc(1, sizeof(*host))) == NULL) {
                ERROR("write_sensu plugin: calloc failed.");
@@ -1107,8 +1107,11 @@ static int sensu_config_node(oconfig_item_t *ci) /* {{{ */
        }
 
        ssnprintf(callback_name, sizeof(callback_name), "write_sensu/%s", host->name);
-       ud.data = host;
-       ud.free_func = sensu_free;
+
+       user_data_t ud = {
+               .data = host,
+               .free_func = sensu_free
+       };
 
        pthread_mutex_lock(&host->lock);
 
index 309418a..b670f3a 100644 (file)
@@ -45,7 +45,6 @@
 
 #include "common.h"
 #include "plugin.h"
-#include "configfile.h"
 
 #include "utils_cache.h"
 
@@ -187,6 +186,8 @@ static int wt_callback_init(struct wt_callback *cb)
         if (cb->sock_fd < 0)
             continue;
 
+        set_sock_opts(cb->sock_fd);
+
         status = connect(cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
         if (status != 0)
         {
@@ -569,7 +570,6 @@ static int wt_write(const data_set_t *ds, const value_list_t *vl,
 static int wt_config_tsd(oconfig_item_t *ci)
 {
     struct wt_callback *cb;
-    user_data_t user_data = { 0 };
     char callback_name[DATA_MAX_NAME_LEN];
 
     cb = calloc(1, sizeof(*cb));
@@ -611,8 +611,11 @@ static int wt_config_tsd(oconfig_item_t *ci)
               cb->node != NULL ? cb->node : WT_DEFAULT_NODE,
               cb->service != NULL ? cb->service : WT_DEFAULT_SERVICE);
 
-    user_data.data = cb;
-    user_data.free_func = wt_callback_free;
+    user_data_t user_data = {
+        .data = cb,
+        .free_func = wt_callback_free
+    };
+
     plugin_register_write(callback_name, wt_write, &user_data);
 
     user_data.free_func = NULL;
index 3751bfd..d9e46f5 100644 (file)
@@ -134,7 +134,7 @@ zone_submit_values(c_avl_tree_t *tree)
        while (c_avl_pick (tree, (void **)&zoneid, (void **)&stats) == 0)
        {
                if (getzonenamebyid(*zoneid, zonename, sizeof( zonename )) == -1) {
-                       WARNING("zone plugin: error retreiving zonename");
+                       WARNING("zone plugin: error retrieving zonename");
                } else {
                        zone_submit_value(zonename, (gauge_t)FRC2PCT(stats->pctcpu));
                }