From: Pavel Rochnyak Date: Sat, 10 Feb 2018 11:19:02 +0000 (+0700) Subject: Merge pull request #2613 from elfiesmelfie/update_dpdk_note X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=35a6c9c5fcd87cb78451a974c4d5b5707926845c;hp=13fa69a159fde3549cad939b6bd83b2cb1ddaa68;p=collectd.git Merge pull request #2613 from elfiesmelfie/update_dpdk_note docs: update dpdkstats documentation --- diff --git a/ChangeLog b/ChangeLog index db0b0621..f990dd46 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,69 @@ +2017-06-06, Version 5.7.2 + * Build system: The Notify Email plugin is no longer linked with + indirect dependencies. Thanks to Marc Fournier. + * collectd: A race condition when calculating a metric's rate has been + fixed. Thanks to Florian Forster. #1193 + * AMQP, Exec, UnixSock, Write Kafka plugins: Parsing of the PUTVAL + command with multiple values has been fixed. Thanks to Florian + Forster. #2274 + * AMQP plugin: The "ExchangeType" option is now also valid for + publishers. Thanks to Florian Forster. #2286 + * BIND plugin: Fix parsing of the sample time provided by BIND. + Previously, the time was assumed to be in the local timezone when in + fact it was in UTC. Thanks to Ed Ravin. #1268 + * BIND plugin: Memory leaks have been fixed. Thanks to Ruben Kerkhof. + #2303 + * cURL-JSON plugin: Handling of arrays has been fixed. Thanks to Florian + Forster. #2266 + * DPDKStat plugin: Error handling during initialization has been + improved. Thanks to Ruben Kerkhof. + * DPDKStat plugin: Handling of a number of metrics has been improved, + for example "rx_q0bytes". Thanks to Przemyslaw Szczerbik. #2167 + * Intel RDT plugin: Configuration handling has been changed to be more + graceful. Thanks to Maryam Tahhan. #2165 + * Log Logstash plugin: If writing the log entry fails, print it to + "STDERR" instead. Thanks to Marc Fournier. + * LogFile plugin: If writing to the file fails, print log messages on + "STDERR" instead. Thanks to Marc Fournier. + * memcachec, Tail plugins: A resource leak in the matching + infrastructure has been fixed. Thanks to Krzysztof Matczak. #2192 + * MQTT plugin: Invalid symbols in topic names are now replaced and a + resource leak has been fixed. Thanks to Denys Fedoryshchenko. #2123 + * Network plugin: A potential endless-loop has been fixed. This can be + triggered remotely by sending a signed network packet to a server + which is not set up to check signatures. Thanks to Marcin Kozlowski + and Pavel Rochnyack. #2174, #2233, CVE-2017-7401 + * Perl plugin: A potential double-free has been fixed. Thanks to Florian + Forster. #2278 + * Processes plugin: A compilation error on AIX has been fixed. Thanks to + Pavel Rochnyack. #2210 + * SMART plugin: A check for the "CAP_SYS_RAWIO" capability has been + added. Thanks to Marc Fournier. + * Write Graphite plugin: Error handling in the case that calculating a + metric's rate fails has been improved. Previously, the raw counter + values were sent to Graphite. Thanks to Iain Buclaw. #2209 + * Write Prometheus plugin: An incorrect use of "realloc(3)" has been + fixed. Thanks to Florian Forster. #2275 + +2017-01-23, Version 5.7.1 + * collectd: Handling of boolean configuration options has been unified. + Thanks to Sebastian Harl. #2083, #2098 + * collectd: Reporting of internal statistics has been fixed. Thanks to + Florian Forster. #2108 + * collectd, various plugins: Bugs and issues reported by scan-build and + coverity-scan have been fixed. Thanks to Ruben Kerkhof and Florian + Forster. + * Build system: Parallel build have been fixed. Thanks to Ruben Kerkhof. + #2110 + * DPDKStat plugin: Portability issues and a double-close bug have been + fixed. Thanks to Ruben Kerkhof and Marc Fournier. + * Intel RDT plugin: A check for the libpqos library version has been + added. Thanks to Serhiy Pshyk. + * NetApp plugin: Compilation problems have been corrected. Thanks to + Florian Forster. #2120 + * Write Prometheus plugin: A memory leak has been fixed. Thanks to Ruben + Kerkhof. + 2016-12-12, Version 5.7.0 * Documentation: The Turbostat plugin section has been improved. Thanks to Florian Forster @@ -68,6 +134,77 @@ embedded HTTP server, in a format compatible with Prometheus' collectd_exporter. Thanks to Florian Forster. #1967 +2017-10-06, Version 5.6.3 + * collectd: support for boolean string config values has been + reintroduced. Thanks to Sebastian Harl. #2083, #2098 + * collectd: The capability checking has been changed to use + "cap_get_proc()". Thanks to Marc Fournier. #2151 + * Documentation: A section documenting ignore lists has been added to + collectd.conf(5). Thanks to Florian Forster. + * AMQP plugin: The "ExchangeType" option is now also valid for + publishers. Thanks to Florian Forster. #2286 + * Apache, Ascent, BIND, cURL, cURL-JSON, cURL-XML, nginx, Write HTTP + plugins: Handling of URLs that redirect elsewhere has been fixed. + Thanks to Pavel Rochnyack. #2328 + * BIND plugin: Fix parsing of the sample time provided by BIND. + Previously, the time was assumed to be in the local time zone when in + fact it was in UTC. Thanks to Ed Ravin. #1268 + * BIND plugin: Memory leaks have been fixed. Thanks to Ruben Kerkhof. + #2303 + * Chrony plugin: Build flags have been fixed. Thanks to Thomas Jost and + Marc Fournier. #2133 + * cURL-JSON plugin: The timeout value has been changed to default to the + collection interval. This fixes a regression. Thanks to Marc Fournier. + * cURL-JSON plugin: Handling of arrays has been fixed. Thanks to Florian + Forster. #2266 + * DBI plugin: Memory leaks at shutdown have been fixes. Thanks to Pavel + Rochnyack and Florian Forster. + * E-Mail, Exec, UnixSock plugins: Group ID lookup on systems with many + groups has been fixed. Thanks to Ruben Kerkhof and Florian Forster. + #2208 + * IPC plugin: A compilation error on AIX has been fixed. Thanks to Pavel + Rochnyack. #2305 + * LogFile plugin: If writing to the file fails, print log messages on + "STDERR" instead. Thanks to Marc Fournier. + * Log Logstash plugin: If writing the log entry fails, print it to + "STDERR" instead. Thanks to Marc Fournier. + * memcachec, Tail plugins: A resource leak in the matching + infrastructure has been fixed. Thanks to Krzysztof Matczak. #2192 + * MQTT plugin: Invalid symbols in topic names are now replaced and a + resource leak has been fixed. Thanks to Denys Fedoryshchenko. #2123 + * Network plugin: A potential endless-loop has been fixed. This can be + triggered remotely by sending a signed network packet to a server + which is not set up to check signatures. Thanks to Marcin Kozlowski + and Pavel Rochnyack. #2174, #2233, CVE-2017-7401 + * Network plugin: A use-after-free has been fixed. Thanks to Pavel + Rochnyack. #2375 + * Notify Email plugin: The plugin is no longer explicitly linked against + libssl and libcrypto, relies on libesmtp being linked correctly. + Thanks to Marc Fournier. Debian#852924 + * NTPd plugin: Calculation of loop offset and error has been fixed. + Thanks to Neil Wilson. #2188 + * OpenLDAP plugin: An incorrect use of the ldap library, leading to a + crash, has been fixed. Thanks to Marc Fournier. #2331 + * Perl plugin: A potential double-free has been fixed. Thanks to Florian + Forster. #2278 + * Perl plugin: Print an error when an incorrect configuration is + encountered. Thanks to Pavel Rochnyack. #927 + * RRDtool plugin: Incorrect handling of the flushes timeout option has + been fixed. Handling of the "RandomTimeout" has been fixed. Thanks to + Pavel Rochnyack. #2363 + * SMART plugin: Some warning messages have been removed and the code has + been cleaned up. Thanks to Florian Forster. #2062 + * SMART plugin: A check for the "CAP_SYS_RAWIO" capability has been + added. Thanks to Marc Fournier. + * SNMP plugin: A double free has been fixed. Thanks to Pavel Rochnyack. + #2291 + * Write Graphite plugin: Error handling in the case that calculating a + metric's rate fails has been improved. Previously, the raw counter + values were sent to Graphite. Thanks to Iain Buclaw. #2209 + * Write Kafka plugin: A 32 bit random number is now used when formatting + a random key. Thanks to Florian Forster. #2074 + + 2016-11-30, Version 5.6.2 * collectd: A compile error on AIX has been fixed: "MSG_DONTWAIT" is not available on AIX. Thanks to Chao Yang. diff --git a/README b/README index 0989312f..803fbaaf 100644 --- a/README +++ b/README @@ -500,6 +500,10 @@ Features - write_mongodb Sends data to MongoDB, a NoSQL database. + - write_prometheus + Publish values using an embedded HTTP server, in a format compatible + with Prometheus' collectd_exporter. + - write_redis Sends the values to a Redis key-value database server. @@ -780,6 +784,10 @@ Prerequisites Used by the `memcachec' plugin to connect to a memcache daemon. + * libmicrohttpd (optional) + Used by the write_prometheus plugin to run an http daemon. + + * libmnl (optional) Used by the `netlink' plugin. diff --git a/configure.ac b/configure.ac index 993e319e..c4cdf4dd 100644 --- a/configure.ac +++ b/configure.ac @@ -805,42 +805,28 @@ AC_CACHE_CHECK([whether clock_boottime and clock_monotonic are supported], # For the turbostat plugin -have_asm_msrindex_h="no" -AC_CHECK_HEADERS(asm/msr-index.h, [have_asm_msrindex_h="yes"]) - -if test "x$have_asm_msrindex_h" = "xyes" -then - AC_CACHE_CHECK([whether asm/msr-index.h has MSR_PKG_C10_RESIDENCY], - [c_cv_have_usable_asm_msrindex_h], - AC_COMPILE_IFELSE([AC_LANG_PROGRAM( -[[[ -#include -]]], -[[[ -int y = MSR_PKG_C10_RESIDENCY; -return(y); -]]] - )], - [c_cv_have_usable_asm_msrindex_h="yes"], - [c_cv_have_usable_asm_msrindex_h="no"], - ) - ) -fi - -have_cpuid_h="no" -AC_CHECK_HEADERS(cpuid.h, [have_cpuid_h="yes"]) +AC_CHECK_HEADERS([cpuid.h], + [have_cpuid_h="yes"], + [have_cpuid_h="no (cpuid.h not found)"] +) have_capability="yes" AC_CHECK_HEADERS(sys/capability.h, [have_capability="yes"], [have_capability="no ( not found)"]) if test "x$have_capability" = "xyes"; then -AC_CHECK_LIB(cap, cap_get_bound, +AC_CHECK_LIB(cap, cap_get_proc, + [have_capability="yes"], + [have_capability="no (cap_get_proc() not found)"]) +fi +if test "x$have_capability" = "xyes"; then +AC_CHECK_DECL([CAP_IS_SUPPORTED], [have_capability="yes"], - [have_capability="no (cap_get_bound() not found)"]) + [have_capability="no (CAP_IS_SUPPORTED not found)"], + [[#include ]]) fi if test "x$have_capability" = "xyes"; then - AC_DEFINE(HAVE_CAPABILITY, 1, [Define to 1 if you have cap_get_bound() (-lcap).]) + AC_DEFINE(HAVE_CAPABILITY, 1, [Define to 1 if you have cap_get_proc() (-lcap).]) fi AM_CONDITIONAL(BUILD_WITH_CAPABILITY, test "x$have_capability" = "xyes") @@ -1062,6 +1048,92 @@ then fi # }}} Check for strptime +# Check for timegm {{{ + +# These checks need -Werror because implicit function declarations are only a +# warning ... +SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror" + +AC_CACHE_CHECK([for timegm], + [c_cv_have_timegm], + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( +[[[ +#if STRPTIME_NEEDS_STANDARDS +# ifndef _ISOC99_SOURCE +# define _ISOC99_SOURCE 1 +# endif +# ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +# endif +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 500 +# endif +#endif +#include +]]], +[[[ + time_t t = timegm(&(struct tm){0}); + if (t == ((time_t) -1)) { + return 1; + } +]]] + )], + [c_cv_have_timegm="yes"], + [c_cv_have_timegm="no"] + ) +) + +if test "x$c_cv_have_timegm" != "xyes" +then + AC_CACHE_CHECK([for timegm with _BSD_SOURCE], + [c_cv_have_timegm_bsd], + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( +[[[ +#if STRPTIME_NEEDS_STANDARDS +# ifndef _ISOC99_SOURCE +# define _ISOC99_SOURCE 1 +# endif +# ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 200112L +# endif +# ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 500 +# endif +#endif +#ifndef _BSD_SOURCE +# define _BSD_SOURCE 1 +#endif +#include +]]], +[[[ + time_t t = timegm(&(struct tm){0}); + if (t == ((time_t) -1)) { + return 1; + } +]]] + )], + [c_cv_have_timegm_bsd="yes" + c_cv_have_timegm="yes"], + [c_cv_have_timegm_bsd="no"] + ) + ) +fi + +if test "x$c_cv_have_timegm" = "xyes" +then + AC_DEFINE(HAVE_TIMEGM, 1, [Define if the timegm(3) function is available.]) + if test "x$c_cv_have_timegm_bsd" = "xyes" + then + AC_DEFINE(TIMEGM_NEEDS_BSD, 1, [Set to true if timegm is only exported in BSD mode.]) + fi +fi + +CFLAGS="$SAVE_CFLAGS" +# }}} Check for timegm + AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"]) if test "x$have_swapctl" = "xyes"; then AC_CACHE_CHECK([whether swapctl takes two arguments], @@ -2607,34 +2679,69 @@ fi # --with-libdpdk {{{ AC_ARG_VAR([LIBDPDK_CPPFLAGS], [Preprocessor flags for libdpdk]) +AC_ARG_VAR([LIBDPDK_CFLAGS], [Compiler flags for libdpdk]) AC_ARG_VAR([LIBDPDK_LDFLAGS], [Linker flags for libdpdk]) +AC_ARG_VAR([LIBDPDK_LIBS], [Libraries to link for libdpdk]) -AC_ARG_WITH([libdpdk], [AS_HELP_STRING([--without-libdpdk], [Disable libdpdk.])]) +AC_ARG_WITH([libdpdk], + [AS_HELP_STRING([--without-libdpdk], [Disable libdpdk.])], + [with_libdpdk="$withval"], + [with_libdpdk="yes"] +) -if test "x$with_libdpdk" != "xno" -then - if test "x$LIBDPDK_CPPFLAGS" = "x" - then - LIBDPDK_CPPFLAGS="-I/usr/include/dpdk" - fi - SAVE_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$LIBDPDK_CPPFLAGS $CPPFLAGS" - AC_CHECK_HEADERS([rte_config.h], - [with_libdpdk="yes"], - [with_libdpdk="no (rte_config.h not found)"] - ) - CPPFLAGS="$SAVE_CPPFLAGS" +if test "x$with_libdpdk" != "xno"; then + PKG_CHECK_MODULES([DPDK], [libdpdk], [], + [AC_MSG_NOTICE([no DPDK pkg-config, using defaults])]) + if test "x$LIBDPDK_CPPFLAGS" = "x"; then + LIBDPDK_CPPFLAGS="-I/usr/include/dpdk" + fi + if test "x$LIBDPDK_CFLAGS" = "x"; then + LIBDPDK_CFLAGS="$DPDK_CFLAGS" + LIBDPDK_CPPFLAGS="$LIBDPDK_CPPFLAGS $DPDK_CFLAGS" + fi + if test "x$LIBDPDK_LIBS" = "x"; then + if test "x$DPDK_LIBS" != "x"; then + LIBDPDK_LIBS="$DPDK_LIBS" + else + LIBDPDK_LIBS="-ldpdk" + fi + fi + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$LIBDPDK_CPPFLAGS $CPPFLAGS" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$LIBDPDK_CFLAGS $CFLAGS" + AC_CHECK_HEADERS([rte_config.h], + [ + with_libdpdk="yes" + AC_PREPROC_IFELSE( + [ + AC_LANG_SOURCE( + [[ + #include + #if RTE_VERSION < RTE_VERSION_NUM(16,7,0,0) + #error "required DPDK >= 16.07" + #endif + ]] + ) + ], + [dpdk_keepalive="yes"], + [dpdk_keepalive="no (DPDK version < 16.07)"] + ) + ], + [with_libdpdk="no (rte_config.h not found)"] + ) + CPPFLAGS="$SAVE_CPPFLAGS" + CFLAGS="$SAVE_CFLAGS" fi -if test "x$with_libdpdk" = "xyes" -then - SAVE_LDFLAGS="$LDFLAGS" - LDFLAGS="$LIBDPDK_LDFLAGS $LDFLAGS" - AC_CHECK_LIB([dpdk], [rte_eal_init], - [with_libdpdk="yes"], - [with_libdpdk="no (symbol 'rte_eal_init' not found)"] - ) - LDFLAGS="$SAVE_LDFLAGS" +if test "x$with_libdpdk" = "xyes"; then + SAVE_LDFLAGS="$LDFLAGS" + LDFLAGS="$LIBDPDK_LDFLAGS $LDFLAGS" + AC_CHECK_LIB([dpdk], [rte_eal_init], + [with_libdpdk="yes"], + [with_libdpdk="no (symbol 'rte_eal_init' not found)"] + ) + LDFLAGS="$SAVE_LDFLAGS" fi # }}} @@ -4235,6 +4342,16 @@ then fi if test "x$with_libpqos" = "xyes" then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags" + AC_RUN_IFELSE([AC_LANG_PROGRAM( + [[#include ]], + [[return !(PQOS_VERSION >= 106)]])], + [with_libpqos="yes"], [with_libpqos="no (pqos library version 1.06 or higher is required)"]) + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libpqos" = "xyes" +then BUILD_WITH_LIBPQOS_CPPFLAGS="$with_libpqos_cppflags" BUILD_WITH_LIBPQOS_LDFLAGS="$with_libpqos_ldflags" BUILD_WITH_LIBPQOS_LIBS="-lpqos" @@ -6006,8 +6123,7 @@ then then plugin_ipvs="yes" fi - if test "x$c_cv_have_usable_asm_msrindex_h" = "xyes" && test "x$have_cpuid_h" = "xyes" - then + if test "x$have_cpuid_h" = "xyes"; then plugin_turbostat="yes" fi diff --git a/contrib/redhat/collectd.spec b/contrib/redhat/collectd.spec index 4fc76e11..9f93f410 100644 --- a/contrib/redhat/collectd.spec +++ b/contrib/redhat/collectd.spec @@ -150,6 +150,7 @@ %define with_write_log 0%{!?_without_write_log:1} %define with_write_prometheus 0%{!?_without_write_prometheus:1} %define with_write_redis 0%{!?_without_write_redis:1} +%define with_write_riemann 0%{!?_without_write_riemann:1} %define with_write_sensu 0%{!?_without_write_sensu:1} %define with_write_tsdb 0%{!?_without_write_tsdb:1} %define with_xmms 0%{!?_without_xmms:0%{?_has_xmms}} @@ -195,8 +196,6 @@ %define with_write_kafka 0%{!?_without_write_kafka:0} # plugin write_mongodb disabled, requires libmongoc %define with_write_mongodb 0%{!?_without_write_mongodb:0} -# plugin write_riemann disabled, requires a new enough riemann_c_client -%define with_write_riemann 0%{!?_without_write_riemann:0} # plugin xencpu disabled, requires xen-devel from non-default repo %define with_xencpu 0%{!?_without_xencpu:0} # plugin zone disabled, requires Solaris @@ -220,6 +219,7 @@ %define with_turbostat 0 %define with_write_prometheus 0 %define with_write_redis 0 +%define with_write_riemann 0 %endif # Plugins not buildable on RHEL < 7 @@ -230,13 +230,14 @@ %define with_redis 0 %define with_rrdcached 0 %define with_write_redis 0 +%define with_write_riemann 0 %define with_xmms 0 %endif Summary: Statistics collection and monitoring daemon Name: collectd -Version: 5.7.0 -Release: 2%{?dist} +Version: 5.7.1 +Release: 3%{?dist} URL: https://collectd.org Source: https://collectd.org/files/%{name}-%{version}.tar.bz2 License: GPLv2 @@ -246,6 +247,7 @@ BuildRequires: libgcrypt-devel, kernel-headers, libtool-ltdl-devel, libcap-devel Vendor: collectd development team %if 0%{?fedora} || 0%{?rhel} >= 7 +BuildRequires: xfsprogs-devel %{?systemd_requires} BuildRequires: systemd %else @@ -499,8 +501,8 @@ the byte- and packet-counters of selected rules and submit them to collectd. Summary: Java plugin for collectd Group: System Environment/Daemons Requires: %{name}%{?_isa} = %{version}-%{release} -BuildRequires: java-devel, jpackage-utils -Requires: java, jpackage-utils +BuildRequires: java-devel >= 1.6, jpackage-utils >= 1.6 +Requires: java >= 1.6, jpackage-utils >= 1.6 %description java This plugin for collectd allows plugins to be written in Java and executed in an embedded JVM. @@ -858,7 +860,7 @@ The Write Redis plugin stores values in Redis, a “data structures server”. Summary: riemann plugin for collectd Group: System Environment/Daemons Requires: %{name}%{?_isa} = %{version}-%{release} -BuildRequires: protobuf-c-devel +BuildRequires: riemann-c-client-devel >= 1.6 %description write_riemann The riemann plugin submits values to Riemann, an event stream processor. %endif @@ -2587,6 +2589,16 @@ fi %doc contrib/ %changelog +* Sun Mar 05 2017 Ruben Kerkhof - 5.7.1-2 +- Don't enable XFS support on RHEL6, it is missing for i386 + +* Wed Feb 22 2017 Ruben Kerkhof - 5.7.1-2 +- Enable XFS support in df plugin +- Fix bogus date in changelog + +* Sun Jan 01 2017 Marc Fournier - 5.7.1-1 +- New upstream version + * Tue Nov 29 2016 Ruben Kerkhof - 5.7.0-2 - Disable redis plugin on RHEL 6, hiredis has been retired from EPEL6 diff --git a/contrib/systemd.collectd.service b/contrib/systemd.collectd.service index d0f1bdea..a3b689ac 100644 --- a/contrib/systemd.collectd.service +++ b/contrib/systemd.collectd.service @@ -20,6 +20,7 @@ ProtectHome=true # exec CAP_SETUID CAP_SETGID # iptables CAP_NET_ADMIN # ping CAP_NET_RAW +# smart CAP_SYS_RAWIO # turbostat CAP_SYS_RAWIO # # Example, if you use the iptables plugin alongside the dns or ping plugin: @@ -28,8 +29,6 @@ ProtectHome=true # By default, drop all capabilities: CapabilityBoundingSet= -NoNewPrivileges=true - # Tell systemd it will receive a notification from collectd over it's control # socket once the daemon is ready. See systemd.service(5) for more details. Type=notify diff --git a/src/Makefile.am b/src/Makefile.am index bd6d901b..e3627c39 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -273,6 +273,7 @@ if BUILD_PLUGIN_CHRONY pkglib_LTLIBRARIES += chrony.la chrony_la_SOURCES = chrony.c chrony_la_LDFLAGS = $(PLUGIN_LDFLAGS) +chrony_la_LIBADD = -lm endif if BUILD_PLUGIN_CONNTRACK @@ -419,8 +420,9 @@ if BUILD_PLUGIN_DPDKSTAT pkglib_LTLIBRARIES += dpdkstat.la dpdkstat_la_SOURCES = dpdkstat.c dpdkstat_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS) +dpdkstat_la_CFLAGS = $(AM_CFLAGS) $(LIBDPDK_CFLAGS) dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS) -dpdkstat_la_LIBADD = -ldpdk +dpdkstat_la_LIBADD = $(LIBDPDK_LIBS) endif if BUILD_PLUGIN_DRBD @@ -444,7 +446,8 @@ endif if BUILD_PLUGIN_EXEC pkglib_LTLIBRARIES += exec.la exec_la_SOURCES = exec.c -exec_la_LDFLAGS = $(PLUGIN_LDFLAGS) libcmds.la +exec_la_LDFLAGS = $(PLUGIN_LDFLAGS) +exec_la_LIBADD = libcmds.la endif if BUILD_PLUGIN_ETHSTAT @@ -823,7 +826,7 @@ if BUILD_PLUGIN_NOTIFY_EMAIL pkglib_LTLIBRARIES += notify_email.la notify_email_la_SOURCES = notify_email.c notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS) -notify_email_la_LIBADD = -lesmtp -lssl -lcrypto +notify_email_la_LIBADD = -lesmtp endif if BUILD_PLUGIN_NOTIFY_NAGIOS @@ -1210,14 +1213,17 @@ endif if BUILD_PLUGIN_TURBOSTAT pkglib_LTLIBRARIES += turbostat.la -turbostat_la_SOURCES = turbostat.c +turbostat_la_SOURCES = \ + turbostat.c \ + msr-index.h turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif if BUILD_PLUGIN_UNIXSOCK pkglib_LTLIBRARIES += unixsock.la unixsock_la_SOURCES = unixsock.c -unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS) libcmds.la +unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS) +unixsock_la_LIBADD = libcmds.la endif if BUILD_PLUGIN_UPTIME diff --git a/src/aggregation.c b/src/aggregation.c index 4e20d0cf..272a04fb 100644 --- a/src/aggregation.c +++ b/src/aggregation.c @@ -405,9 +405,10 @@ static int agg_instance_read(agg_instance_t *inst, cdtime_t t) /* {{{ */ READ_FUNC(average, (inst->sum / ((gauge_t)inst->num))); READ_FUNC(min, inst->min); READ_FUNC(max, inst->max); - READ_FUNC(stddev, sqrt((((gauge_t)inst->num) * inst->squares_sum) - - (inst->sum * inst->sum)) / - ((gauge_t)inst->num)); + READ_FUNC(stddev, + sqrt((((gauge_t)inst->num) * inst->squares_sum) - + (inst->sum * inst->sum)) / + ((gauge_t)inst->num)); } /* Reset internal state. */ @@ -506,11 +507,7 @@ static int agg_config_handle_group_by(oconfig_item_t const *ci, /* {{{ */ static int agg_config_aggregation(oconfig_item_t *ci) /* {{{ */ { - aggregation_t *agg; - _Bool is_valid; - int status; - - agg = calloc(1, sizeof(*agg)); + aggregation_t *agg = calloc(1, sizeof(*agg)); if (agg == NULL) { ERROR("aggregation plugin: calloc failed."); return (-1); @@ -525,49 +522,55 @@ static int agg_config_aggregation(oconfig_item_t *ci) /* {{{ */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; + int status = 0; if (strcasecmp("Host", child->key) == 0) - cf_util_get_string_buffer(child, agg->ident.host, - sizeof(agg->ident.host)); + status = cf_util_get_string_buffer(child, agg->ident.host, + sizeof(agg->ident.host)); else if (strcasecmp("Plugin", child->key) == 0) - cf_util_get_string_buffer(child, agg->ident.plugin, - sizeof(agg->ident.plugin)); + status = cf_util_get_string_buffer(child, agg->ident.plugin, + sizeof(agg->ident.plugin)); else if (strcasecmp("PluginInstance", child->key) == 0) - cf_util_get_string_buffer(child, agg->ident.plugin_instance, - sizeof(agg->ident.plugin_instance)); + status = cf_util_get_string_buffer(child, agg->ident.plugin_instance, + sizeof(agg->ident.plugin_instance)); else if (strcasecmp("Type", child->key) == 0) - cf_util_get_string_buffer(child, agg->ident.type, - sizeof(agg->ident.type)); + status = cf_util_get_string_buffer(child, agg->ident.type, + sizeof(agg->ident.type)); else if (strcasecmp("TypeInstance", child->key) == 0) - cf_util_get_string_buffer(child, agg->ident.type_instance, - sizeof(agg->ident.type_instance)); + status = cf_util_get_string_buffer(child, agg->ident.type_instance, + sizeof(agg->ident.type_instance)); else if (strcasecmp("SetHost", child->key) == 0) - cf_util_get_string(child, &agg->set_host); + status = cf_util_get_string(child, &agg->set_host); else if (strcasecmp("SetPlugin", child->key) == 0) - cf_util_get_string(child, &agg->set_plugin); + status = cf_util_get_string(child, &agg->set_plugin); else if (strcasecmp("SetPluginInstance", child->key) == 0) - cf_util_get_string(child, &agg->set_plugin_instance); + status = cf_util_get_string(child, &agg->set_plugin_instance); else if (strcasecmp("SetTypeInstance", child->key) == 0) - cf_util_get_string(child, &agg->set_type_instance); + status = cf_util_get_string(child, &agg->set_type_instance); else if (strcasecmp("GroupBy", child->key) == 0) - agg_config_handle_group_by(child, agg); + status = agg_config_handle_group_by(child, agg); else if (strcasecmp("CalculateNum", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_num); + status = cf_util_get_boolean(child, &agg->calc_num); else if (strcasecmp("CalculateSum", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_sum); + status = cf_util_get_boolean(child, &agg->calc_sum); else if (strcasecmp("CalculateAverage", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_average); + status = cf_util_get_boolean(child, &agg->calc_average); else if (strcasecmp("CalculateMinimum", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_min); + status = cf_util_get_boolean(child, &agg->calc_min); else if (strcasecmp("CalculateMaximum", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_max); + status = cf_util_get_boolean(child, &agg->calc_max); else if (strcasecmp("CalculateStddev", child->key) == 0) - cf_util_get_boolean(child, &agg->calc_stddev); + status = cf_util_get_boolean(child, &agg->calc_stddev); else WARNING("aggregation plugin: The \"%s\" key is not allowed inside " " blocks and will be ignored.", child->key); - } + + if (status != 0) { + sfree(agg); + return status; + } + } /* for (int i = 0; i < ci->children_num; i++) */ if (agg_is_regex(agg->ident.host)) agg->regex_fields |= LU_GROUP_BY_HOST; @@ -579,7 +582,7 @@ static int agg_config_aggregation(oconfig_item_t *ci) /* {{{ */ agg->regex_fields |= LU_GROUP_BY_TYPE_INSTANCE; /* Sanity checking */ - is_valid = 1; + _Bool is_valid = 1; if (strcmp("/.*/", agg->ident.type) == 0) /* {{{ */ { ERROR("aggregation plugin: It appears you did not specify the required " @@ -633,13 +636,12 @@ static int agg_config_aggregation(oconfig_item_t *ci) /* {{{ */ is_valid = 0; } /* }}} */ - if (!is_valid) /* {{{ */ - { + if (!is_valid) { /* {{{ */ sfree(agg); return (-1); } /* }}} */ - status = lookup_add(lookup, &agg->ident, agg->group_by, agg); + int status = lookup_add(lookup, &agg->ident, agg->group_by, agg); if (status != 0) { ERROR("aggregation plugin: lookup_add failed with status %i.", status); sfree(agg); diff --git a/src/amqp.c b/src/amqp.c index cd07023f..c54a1e09 100644 --- a/src/amqp.c +++ b/src/amqp.c @@ -901,7 +901,7 @@ static int camqp_config_connection(oconfig_item_t *ci, /* {{{ */ status = cf_util_get_string(child, &conf->password); else if (strcasecmp("Exchange", child->key) == 0) status = cf_util_get_string(child, &conf->exchange); - else if ((strcasecmp("ExchangeType", child->key) == 0) && !publish) + else if (strcasecmp("ExchangeType", child->key) == 0) status = cf_util_get_string(child, &conf->exchange_type); else if ((strcasecmp("Queue", child->key) == 0) && !publish) status = cf_util_get_string(child, &conf->queue); diff --git a/src/apache.c b/src/apache.c index eaef61b1..29c36cc0 100644 --- a/src/apache.c +++ b/src/apache.c @@ -328,7 +328,6 @@ static int init_host(apache_t *st) /* {{{ */ #endif } - curl_easy_setopt(st->curl, CURLOPT_URL, st->url); curl_easy_setopt(st->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(st->curl, CURLOPT_MAXREDIRS, 50L); @@ -510,6 +509,9 @@ static int apache_read_host(user_data_t *user_data) /* {{{ */ assert(st->curl != NULL); st->apache_buffer_fill = 0; + + curl_easy_setopt(st->curl, CURLOPT_URL, st->url); + if (curl_easy_perform(st->curl) != CURLE_OK) { ERROR("apache: curl_easy_perform failed: %s", st->apache_curl_error); return (-1); diff --git a/src/ascent.c b/src/ascent.c index 840fe8b8..74cef333 100644 --- a/src/ascent.c +++ b/src/ascent.c @@ -511,7 +511,6 @@ static int ascent_init(void) /* {{{ */ #endif } - curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); @@ -554,6 +553,9 @@ static int ascent_read(void) /* {{{ */ } ascent_buffer_fill = 0; + + curl_easy_setopt(curl, CURLOPT_URL, url); + if (curl_easy_perform(curl) != CURLE_OK) { ERROR("ascent plugin: curl_easy_perform failed: %s", ascent_curl_error); return (-1); diff --git a/src/battery.c b/src/battery.c index 5c02fee2..78e96b25 100644 --- a/src/battery.c +++ b/src/battery.c @@ -350,10 +350,12 @@ static int sysfs_file_to_buffer(char const *dir, /* {{{ */ ssnprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply, basename); - status = (int)read_file_contents(filename, buffer, buffer_size); + status = (int)read_file_contents(filename, buffer, buffer_size - 1); if (status < 0) return status; + buffer[status] = '\0'; + strstripnewline(buffer); return 0; } /* }}} int sysfs_file_to_buffer */ @@ -364,7 +366,7 @@ static int sysfs_file_to_gauge(char const *dir, /* {{{ */ char const *power_supply, char const *basename, gauge_t *ret_value) { int status; - char buffer[32] = ""; + char buffer[32]; status = sysfs_file_to_buffer(dir, power_supply, basename, buffer, sizeof(buffer)); diff --git a/src/bind.c b/src/bind.c index 9bb662fc..8a3148cc 100644 --- a/src/bind.c +++ b/src/bind.c @@ -35,11 +35,19 @@ #endif #endif /* STRPTIME_NEEDS_STANDARDS */ +#if TIMEGM_NEEDS_BSD +#ifndef _BSD_SOURCE +#define _BSD_SOURCE 1 +#endif +#endif /* TIMEGM_NEEDS_BSD */ + #include "collectd.h" #include "common.h" #include "plugin.h" +#include + /* Some versions of libcurl don't include this themselves and then don't have * fd_set available. */ #if HAVE_SYS_SELECT_H @@ -429,7 +437,28 @@ static int bind_xml_read_timestamp(const char *xpath_expression, /* {{{ */ return (-1); } - *ret_value = mktime(&tm); +#if HAVE_TIMEGM + time_t t = timegm(&tm); + if (t == ((time_t)-1)) { + char errbuf[1024]; + ERROR("bind plugin: timegm() failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + return (-1); + } + *ret_value = t; +#else + time_t t = mktime(&tm); + if (t == ((time_t)-1)) { + char errbuf[1024]; + ERROR("bind plugin: mktime() failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + return (-1); + } + /* mktime assumes that tm is local time. Luckily, it also sets timezone to + * the offset used for the conversion, and we undo the conversion to convert + * back to UTC. */ + *ret_value = t - timezone; +#endif xmlXPathFreeObject(xpathObj); return (0); @@ -493,8 +522,10 @@ static int bind_parse_generic_name_value(const char *xpath_expression, /* {{{ */ status = bind_xml_read_gauge(doc, counter, &value.gauge); else status = bind_xml_read_derive(doc, counter, &value.derive); - if (status != 0) + if (status != 0) { + xmlFree(name); continue; + } status = (*list_callback)(name, value, current_time, user_data); if (status == 0) @@ -626,12 +657,16 @@ static int bind_parse_generic_name_attr_value_list( status = bind_xml_read_gauge(doc, child, &value.gauge); else status = bind_xml_read_derive(doc, child, &value.derive); - if (status != 0) + if (status != 0) { + xmlFree(attr_name); continue; + } status = (*list_callback)(attr_name, value, current_time, user_data); if (status == 0) num_entries++; + + xmlFree(attr_name); } } @@ -1563,7 +1598,6 @@ static int bind_init(void) /* {{{ */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, bind_curl_callback); curl_easy_setopt(curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, bind_curl_error); - curl_easy_setopt(curl, CURLOPT_URL, (url != NULL) ? url : BIND_DEFAULT_URL); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); #ifdef HAVE_CURLOPT_TIMEOUT_MS @@ -1585,6 +1619,9 @@ static int bind_read(void) /* {{{ */ } bind_buffer_fill = 0; + + curl_easy_setopt(curl, CURLOPT_URL, (url != NULL) ? url : BIND_DEFAULT_URL); + if (curl_easy_perform(curl) != CURLE_OK) { ERROR("bind plugin: curl_easy_perform failed: %s", bind_curl_error); return (-1); diff --git a/src/collectd-python.pod b/src/collectd-python.pod index 16b26afa..ada1ff55 100644 --- a/src/collectd-python.pod +++ b/src/collectd-python.pod @@ -475,7 +475,7 @@ Methods defined here: =over 4 -=item B([type][, values][, plugin_instance][, type_instance][, plugin][, host][, time][, interval]) -> None. Dispatch a value list. +=item B([type][, message][, plugin_instance][, type_instance][, plugin][, host][, time][, severity]) -> None. Dispatch a notification. Dispatch this instance to the collectd process. The object has members for each of the possible arguments for this method. For a detailed explanation of these diff --git a/src/collectd.conf.in b/src/collectd.conf.in index e5b96435..c65191d1 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -1059,7 +1059,7 @@ # # Interval 60 # Service "service_name" -# Query backend # predefined +# Query backends # predefined # Query rt36_tickets # # diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 11cfaebd..3ab264a3 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -338,7 +338,7 @@ is enabled by default. =item B I Configure the name of the "pre-cache chain" and the "post-cache chain". Please -see L below on information on chains and how these +see L below on information on chains and how these setting change the daemon's behavior. =back @@ -1372,6 +1372,8 @@ Select I based on the name. Whether only matching I are collected or if they are ignored is controlled by the B option; see below. +See F for details. + =item B B|B Invert the selection: If set to true, all cgroups I the ones that @@ -2268,14 +2270,20 @@ values. Defaults to the global hostname setting. Select partitions based on the devicename. +See F for details. + =item B I Select partitions based on the mountpoint. +See F for details. + =item B I Select partitions based on the filesystem type. +See F for details. + =item B B|B Invert the selection: If set to true, all partitions B the ones that @@ -2337,6 +2345,8 @@ is interpreted as a regular expression. Examples: Disk "sdd" Disk "/hda[34]/" +See F for details. + =item B B|B Sets whether selected disks, i.Ee. the ones matches by any of the B @@ -2998,6 +3008,8 @@ than 1 sec. Select this interface. By default these interfaces will then be collected. For a more detailed description see B below. +See F for details. + =item B I|I If no configuration if given, the B-plugin will collect data from @@ -3059,6 +3071,8 @@ This option is only available on Solaris. Selects sensors to collect or to ignore, depending on B. +See F for details. + =item B I|I If no configuration if given, the B plugin will collect data from all @@ -3115,6 +3129,8 @@ comment or the number. Select this irq. By default these irqs will then be collected. For a more detailed description see B below. +See F for details. + =item B I|I If no configuration if given, the B-plugin will collect data from all @@ -3338,6 +3354,8 @@ Select md devices based on device name. The I is the basename of the device, i.e. the name of the block device without the leading C. See B for more details. +See F for details. + =item B B|B Invert device selection: If set to B, all md devices B those @@ -4501,6 +4519,8 @@ regular and exact matching are case sensitive. If no volume was specified at all for either of the three options, that data will be collected for all available volumes. +See F for details. + =item B B|B =item B B|B @@ -4686,6 +4706,8 @@ Here are some examples to help you understand the above text more easily: Filter "ppp0" "u32-1:0" +See F for details. + =item B The behavior is the same as with all other similar plugins: If nothing is @@ -5208,6 +5230,8 @@ C). B is not used. As there can be multiple devices on the bus you can list multiple sensor (use multiple B elements). +See F for details. + =item B I|I If no configuration is given, the B plugin will collect data from all @@ -5532,10 +5556,10 @@ multiple hosts. =item B I Sets the interval in which to send ICMP echo packets to the configured hosts. -This is B the interval in which statistics are queries from the plugin but -the interval in which the hosts are "pinged". Therefore, the setting here -should be smaller than or equal to the global B setting. Fractional -times, such as "1.24" are allowed. +This is B the interval in which metrics are read from the plugin but the +interval in which the hosts are "pinged". Therefore, the setting here should be +smaller than or equal to the global B setting. Fractional times, such +as "1.24" are allowed. Default: B<1.0> @@ -5652,7 +5676,7 @@ L. Interval 300 Service "service_name" - Query backend # predefined + Query backends # predefined Query rt36_tickets @@ -6267,6 +6291,8 @@ Whether only matched values are selected or all matched values are ignored depends on the B. By default, only matched values are selected. If no value is configured at all, all values will be selected. +See F for details. + =item B B|B If set to B, inverts the selection made by B, i.Ee. all @@ -6620,14 +6646,20 @@ one (exclusive). When the C plugin uses a cache (by setting B, see below) it writes all values for a certain RRD-file if the oldest value is older than -(or equal to) the number of seconds specified. If some RRD-file is not updated +(or equal to) the number of seconds specified by B. +That check happens on new values arriwal. If some RRD-file is not updated anymore for some reason (the computer was shut down, the network is broken, -etc.) some values may still be in the cache. If B is set, then the -entire cache is searched for entries older than B seconds and -written to disk every I seconds. Since this is kind of expensive and -does nothing under normal circumstances, this value should not be too small. -900 seconds might be a good value, though setting this to 7200 seconds doesn't -normally do much harm either. +etc.) some values may still be in the cache. If B is set, then +every I seconds the entire cache is searched for entries older than +B + B seconds. The entries found are written to +disk. Since scanning the entire cache is kind of expensive and does nothing +under normal circumstances, this value should not be too small. 900 seconds +might be a good value, though setting this to 7200 seconds doesn't normally +do much harm either. + +Defaults to 10x B. +B must be larger than or equal to B, otherwise the +above default is used. =item B I @@ -6695,6 +6727,8 @@ on the B below. For example, the option "B I" will cause collectd to gather data for the voltage sensor I of the I on the isa bus at the address 0290. +See F for details. + =item B I|I If no configuration if given, the B-plugin will collect data from all @@ -6804,6 +6838,8 @@ is interpreted as a regular expression. Examples: Disk "sdd" Disk "/hda[34]/" +See F for details. + =item B B|B Sets whether selected disks, i.Ee. the ones matches by any of the B @@ -6903,6 +6939,8 @@ Calculate and dispatch various values out of I metrics received during an interval. If set to B, the default, these values aren't calculated / dispatched. +Please note what reported timer values less than 0.001 are ignored in all B reports. + =back =head2 Plugin C @@ -7491,6 +7529,8 @@ Selects the name of the thermal device that you want to collect or ignore, depending on the value of the B option. This option may be used multiple times to specify a list of devices. +See F for details. + =item B I|I Invert the selection: If set to true, all devices B the ones that @@ -9855,6 +9895,48 @@ be an FQDN. Target "write" +=head1 IGNORELISTS + +B are a generic framework to either ignore some metrics or report +specific metircs only. Plugins usually provide one or more options to specify +the items (mounts points, devices, ...) and the boolean option +C. + +=over 4 + +=item B option may be repeated to select multiple items. + +=item B B|B + +If set to B, matching metrics are I and all other metrics are +collected. If set to B, matching metrics are I and all other +metrics are ignored. + +=back + =head1 SEE ALSO L, diff --git a/src/curl.c b/src/curl.c index c6f0b607..26ca7e7a 100644 --- a/src/curl.c +++ b/src/curl.c @@ -347,7 +347,6 @@ static int cc_page_init_curl(web_page_t *wp) /* {{{ */ curl_easy_setopt(wp->curl, CURLOPT_WRITEDATA, wp); curl_easy_setopt(wp->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt(wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf); - curl_easy_setopt(wp->curl, CURLOPT_URL, wp->url); curl_easy_setopt(wp->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(wp->curl, CURLOPT_MAXREDIRS, 50L); @@ -611,6 +610,9 @@ static int cc_read_page(web_page_t *wp) /* {{{ */ start = cdtime(); wp->buffer_fill = 0; + + curl_easy_setopt(wp->curl, CURLOPT_URL, wp->url); + status = curl_easy_perform(wp->curl); if (status != CURLE_OK) { ERROR("curl plugin: curl_easy_perform failed with status %i: %s", status, diff --git a/src/curl_json.c b/src/curl_json.c index aa1ae797..8f6382b8 100644 --- a/src/curl_json.c +++ b/src/curl_json.c @@ -171,23 +171,53 @@ static int cj_get_type(cj_key_t *key) { return ds->ds[0].type; } -static int cj_cb_map_key(void *ctx, const unsigned char *val, yajl_len_t len); +/* cj_load_key loads the configuration for "key" from the parent context and + * sets either .key or .tree in the current context. */ +static int cj_load_key(cj_t *db, char const *key) { + if (db == NULL || key == NULL || db->depth <= 0) + return EINVAL; -static void cj_cb_inc_array_index(void *ctx, _Bool update_key) { - cj_t *db = (cj_t *)ctx; + sstrncpy(db->state[db->depth].name, key, sizeof(db->state[db->depth].name)); + + c_avl_tree_t *tree = db->state[db->depth - 1].tree; + if (tree == NULL) { + return 0; + } + + /* the parent has a key, so the tree pointer is invalid. */ + if (CJ_IS_KEY(db->state[db->depth - 1].key)) { + return 0; + } + + void *value = NULL; + if (c_avl_get(tree, key, (void *)&value) == 0) { + if (CJ_IS_KEY((cj_key_t *)value)) { + db->state[db->depth].key = value; + } else { + db->state[db->depth].tree = value; + } + } else if (c_avl_get(tree, CJ_ANY, (void *)&value) == 0) { + if (CJ_IS_KEY((cj_key_t *)value)) { + db->state[db->depth].key = value; + } else { + db->state[db->depth].tree = value; + } + } else { + db->state[db->depth].key = NULL; + } + + return 0; +} +static void cj_advance_array(cj_t *db) { if (!db->state[db->depth].in_array) return; db->state[db->depth].index++; - if (update_key) { - char name[DATA_MAX_NAME_LEN]; - - ssnprintf(name, sizeof(name), "%d", db->state[db->depth].index - 1); - - cj_cb_map_key(ctx, (unsigned char *)name, (yajl_len_t)strlen(name)); - } + char name[DATA_MAX_NAME_LEN]; + ssnprintf(name, sizeof(name), "%d", db->state[db->depth].index); + cj_load_key(db, name); } /* yajl callbacks */ @@ -195,12 +225,12 @@ static void cj_cb_inc_array_index(void *ctx, _Bool update_key) { #define CJ_CB_CONTINUE 1 static int cj_cb_boolean(void *ctx, int boolVal) { - cj_cb_inc_array_index(ctx, /* update_key = */ 0); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } static int cj_cb_null(void *ctx) { - cj_cb_inc_array_index(ctx, /* update_key = */ 0); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } @@ -209,40 +239,37 @@ static int cj_cb_number(void *ctx, const char *number, yajl_len_t number_len) { cj_t *db = (cj_t *)ctx; cj_key_t *key = db->state[db->depth].key; - value_t vt; - int type; - int status; /* Create a null-terminated version of the string. */ memcpy(buffer, number, number_len); buffer[sizeof(buffer) - 1] = 0; - if ((key == NULL) || !CJ_IS_KEY(key)) { - if (key != NULL && - !db->state[db->depth].in_array /*can be inhomogeneous*/) { - NOTICE("curl_json plugin: Found \"%s\", but the configuration expects" - " a map.", - buffer); - return (CJ_CB_CONTINUE); - } - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - key = db->state[db->depth].key; - if ((key == NULL) || !CJ_IS_KEY(key)) { - return (CJ_CB_CONTINUE); - } - } else { - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - } - type = cj_get_type(key); - status = parse_value(buffer, &vt, type); + if (key == NULL) { + /* no config for this element. */ + cj_advance_array(ctx); + return CJ_CB_CONTINUE; + } else if (!CJ_IS_KEY(key)) { + /* the config expects a map or an array. */ + NOTICE( + "curl_json plugin: Found \"%s\", but the configuration expects a map.", + buffer); + cj_advance_array(ctx); + return CJ_CB_CONTINUE; + } + + int type = cj_get_type(key); + value_t vt; + int status = parse_value(buffer, &vt, type); if (status != 0) { NOTICE("curl_json plugin: Unable to parse number: \"%s\"", buffer); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } cj_submit(db, key, &vt); + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } /* int cj_cb_number */ @@ -251,40 +278,15 @@ static int cj_cb_number(void *ctx, const char *number, yajl_len_t number_len) { * NULL. */ static int cj_cb_map_key(void *ctx, unsigned char const *in_name, yajl_len_t in_name_len) { - cj_t *db = (cj_t *)ctx; - c_avl_tree_t *tree; + char name[in_name_len + 1]; - tree = db->state[db->depth - 1].tree; - - if (tree != NULL) { - cj_key_t *value = NULL; - char *name; - size_t name_len; - - /* Create a null-terminated version of the name. */ - name = db->state[db->depth].name; - name_len = - COUCH_MIN((size_t)in_name_len, sizeof(db->state[db->depth].name) - 1); - memcpy(name, in_name, name_len); - name[name_len] = 0; - - if (c_avl_get(tree, name, (void *)&value) == 0) { - if (CJ_IS_KEY((cj_key_t *)value)) { - db->state[db->depth].key = value; - } else { - db->state[db->depth].tree = (c_avl_tree_t *)value; - } - } else if (c_avl_get(tree, CJ_ANY, (void *)&value) == 0) - if (CJ_IS_KEY((cj_key_t *)value)) { - db->state[db->depth].key = value; - } else { - db->state[db->depth].tree = (c_avl_tree_t *)value; - } - else - db->state[db->depth].key = NULL; - } + memmove(name, in_name, in_name_len); + name[sizeof(name) - 1] = 0; - return (CJ_CB_CONTINUE); + if (cj_load_key(ctx, name) != 0) + return CJ_CB_ABORT; + + return CJ_CB_CONTINUE; } static int cj_cb_string(void *ctx, const unsigned char *val, yajl_len_t len) { @@ -292,38 +294,43 @@ static int cj_cb_string(void *ctx, const unsigned char *val, yajl_len_t len) { return (cj_cb_number(ctx, (const char *)val, len)); } /* int cj_cb_string */ -static int cj_cb_start(void *ctx) { - cj_t *db = (cj_t *)ctx; - if (++db->depth >= YAJL_MAX_DEPTH) { - ERROR("curl_json plugin: %s depth exceeds max, aborting.", - db->url ? db->url : db->sock); - return (CJ_CB_ABORT); - } - return (CJ_CB_CONTINUE); -} - static int cj_cb_end(void *ctx) { cj_t *db = (cj_t *)ctx; db->state[db->depth].tree = NULL; - --db->depth; + db->depth--; + cj_advance_array(ctx); return (CJ_CB_CONTINUE); } static int cj_cb_start_map(void *ctx) { - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - return cj_cb_start(ctx); + cj_t *db = (cj_t *)ctx; + + if ((db->depth + 1) >= YAJL_MAX_DEPTH) { + ERROR("curl_json plugin: %s depth exceeds max, aborting.", + db->url ? db->url : db->sock); + return (CJ_CB_ABORT); + } + db->depth++; + return (CJ_CB_CONTINUE); } static int cj_cb_end_map(void *ctx) { return cj_cb_end(ctx); } static int cj_cb_start_array(void *ctx) { cj_t *db = (cj_t *)ctx; - cj_cb_inc_array_index(ctx, /* update_key = */ 1); - if (db->depth + 1 < YAJL_MAX_DEPTH) { - db->state[db->depth + 1].in_array = 1; - db->state[db->depth + 1].index = 0; + + if ((db->depth + 1) >= YAJL_MAX_DEPTH) { + ERROR("curl_json plugin: %s depth exceeds max, aborting.", + db->url ? db->url : db->sock); + return CJ_CB_ABORT; } - return cj_cb_start(ctx); + db->depth++; + db->state[db->depth].in_array = 1; + db->state[db->depth].index = 0; + + cj_load_key(db, "0"); + + return CJ_CB_CONTINUE; } static int cj_cb_end_array(void *ctx) { @@ -555,7 +562,6 @@ static int cj_init_curl(cj_t *db) /* {{{ */ curl_easy_setopt(db->curl, CURLOPT_WRITEDATA, db); curl_easy_setopt(db->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf); - curl_easy_setopt(db->curl, CURLOPT_URL, db->url); curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L); @@ -600,7 +606,7 @@ static int cj_init_curl(cj_t *db) /* {{{ */ curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, (long)db->timeout); else if (db->interval > 0) curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, - (long)CDTIME_T_TO_MS(db->timeout)); + (long)CDTIME_T_TO_MS(db->interval)); else curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, (long)CDTIME_T_TO_MS(plugin_get_interval())); @@ -834,12 +840,13 @@ static int cj_curl_perform(cj_t *db) /* {{{ */ int status; long rc; char *url; - url = db->url; + + curl_easy_setopt(db->curl, CURLOPT_URL, db->url); status = curl_easy_perform(db->curl); if (status != CURLE_OK) { ERROR("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)", - status, db->curl_errbuf, url); + status, db->curl_errbuf, db->url); return (-1); } if (db->stats != NULL) diff --git a/src/curl_xml.c b/src/curl_xml.c index 4e4c6f99..7c422c71 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -602,13 +602,15 @@ static int cx_curl_perform(cx_t *db, CURL *curl) /* {{{ */ long rc; char *ptr; char *url; - url = db->url; db->buffer_fill = 0; + + curl_easy_setopt(db->curl, CURLOPT_URL, db->url); + status = curl_easy_perform(curl); if (status != CURLE_OK) { ERROR("curl_xml plugin: curl_easy_perform failed with status %i: %s (%s)", - status, db->curl_errbuf, url); + status, db->curl_errbuf, db->url); return (-1); } if (db->stats != NULL) @@ -817,7 +819,6 @@ static int cx_init_curl(cx_t *db) /* {{{ */ curl_easy_setopt(db->curl, CURLOPT_WRITEDATA, db); curl_easy_setopt(db->curl, CURLOPT_USERAGENT, COLLECTD_USERAGENT); curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf); - curl_easy_setopt(db->curl, CURLOPT_URL, db->url); curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L); diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index f3df795d..6b7c4136 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -521,7 +521,7 @@ int main(int argc, char **argv) { */ if (cf_read(configfile)) { fprintf(stderr, "Error: Reading the config file failed!\n" - "Read the syslog for details.\n"); + "Read the logs for details.\n"); return (1); } diff --git a/src/daemon/common.c b/src/daemon/common.c index 0aa5345b..ec5c7aba 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -271,8 +271,10 @@ ssize_t swrite(int fd, const void *buf, size_t count) { ptr = (const char *)buf; nleft = count; - if (fd < 0) - return (-1); + if (fd < 0) { + errno = EINVAL; + return errno; + } /* checking for closed peer connection */ pfd.fd = fd; @@ -281,10 +283,9 @@ ssize_t swrite(int fd, const void *buf, size_t count) { if (poll(&pfd, 1, 0) > 0) { char buffer[32]; if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - // if recv returns zero (even though poll() said there is data to be - // read), - // that means the connection has been closed - return -1; + /* if recv returns zero (even though poll() said there is data to be + * read), that means the connection has been closed */ + return errno ? errno : -1; } } @@ -295,7 +296,7 @@ ssize_t swrite(int fd, const void *buf, size_t count) { continue; if (status < 0) - return (status); + return errno ? errno : status; nleft = nleft - ((size_t)status); ptr = ptr + ((size_t)status); @@ -1567,16 +1568,26 @@ void strarray_free(char **array, size_t array_len) /* {{{ */ #if HAVE_CAPABILITY int check_capability(int arg) /* {{{ */ { - cap_value_t cap = (cap_value_t)arg; + cap_value_t cap_value = (cap_value_t)arg; + cap_t cap; + cap_flag_value_t cap_flag_value; - if (!CAP_IS_SUPPORTED(cap)) + if (!CAP_IS_SUPPORTED(cap_value)) return (-1); - int have_cap = cap_get_bound(cap); - if (have_cap != 1) + if (!(cap = cap_get_proc())) { + ERROR("check_capability: cap_get_proc failed."); return (-1); + } - return (0); + if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) { + ERROR("check_capability: cap_get_flag failed."); + cap_free(cap); + return (-1); + } + cap_free(cap); + + return (cap_flag_value != CAP_SET); } /* }}} int check_capability */ #else int check_capability(__attribute__((unused)) int arg) /* {{{ */ diff --git a/src/daemon/common.h b/src/daemon/common.h index a1a25289..8947c575 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -385,7 +385,7 @@ void strarray_free(char **array, size_t array_len); * 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); +int check_capability(int arg); #endif /* HAVE_SYS_CAPABILITY_H */ #endif /* COMMON_H */ diff --git a/src/daemon/configfile.c b/src/daemon/configfile.c index d5f01e07..3934e1f9 100644 --- a/src/daemon/configfile.c +++ b/src/daemon/configfile.c @@ -1119,14 +1119,36 @@ int cf_util_get_boolean(const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */ if ((ci == NULL) || (ret_bool == NULL)) return (EINVAL); - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) { + if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN) && + (ci->values[0].type != OCONFIG_TYPE_STRING))) { ERROR("cf_util_get_boolean: The %s option requires " "exactly one boolean argument.", ci->key); return (-1); } - *ret_bool = ci->values[0].value.boolean ? 1 : 0; + switch (ci->values[0].type) { + case OCONFIG_TYPE_BOOLEAN: + *ret_bool = ci->values[0].value.boolean ? 1 : 0; + break; + case OCONFIG_TYPE_STRING: + WARNING("cf_util_get_boolean: Using string value `%s' for boolean option " + "`%s' is deprecated and will be removed in future releases. " + "Use unquoted true or false instead.", + ci->values[0].value.string, ci->key); + + if (IS_TRUE(ci->values[0].value.string)) + *ret_bool = 1; + else if (IS_FALSE(ci->values[0].value.string)) + *ret_bool = 0; + else { + ERROR("cf_util_get_boolean: Cannot parse string value `%s' of the `%s' " + "option as a boolean value.", + ci->values[0].value.string, ci->key); + return (-1); + } + break; + } return (0); } /* }}} int cf_util_get_boolean */ diff --git a/src/daemon/meta_data.c b/src/daemon/meta_data.c index 583d8196..76846904 100644 --- a/src/daemon/meta_data.c +++ b/src/daemon/meta_data.c @@ -737,7 +737,6 @@ int meta_data_as_string(meta_data_t *md, /* {{{ */ temp = md_strdup(actual); if (temp == NULL) { - pthread_mutex_unlock(&md->lock); ERROR("meta_data_as_string: md_strdup failed for key `%s'.", key); return (-ENOMEM); } diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c index f313f368..0f067374 100644 --- a/src/daemon/plugin.c +++ b/src/daemon/plugin.c @@ -153,14 +153,13 @@ static const char *plugin_get_dir(void) { return (plugindir); } -static void plugin_update_internal_statistics(void) { /* {{{ */ - +static int plugin_update_internal_statistics(void) { /* {{{ */ gauge_t copy_write_queue_length = (gauge_t)write_queue_length; /* Initialize `vl' */ value_list_t vl = VALUE_LIST_INIT; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin, "collectd", sizeof(vl.plugin)); + vl.interval = plugin_get_interval(); /* Write queue */ sstrncpy(vl.plugin_instance, "write_queue", sizeof(vl.plugin_instance)); @@ -189,8 +188,8 @@ static void plugin_update_internal_statistics(void) { /* {{{ */ vl.type_instance[0] = 0; plugin_dispatch_values(&vl); - return; -} /* }}} void plugin_update_internal_statistics */ + return 0; +} /* }}} int plugin_update_internal_statistics */ static void destroy_callback(callback_func_t *cf) /* {{{ */ { @@ -1572,8 +1571,10 @@ int plugin_init_all(void) { /* Init the value cache */ uc_init(); - if (IS_TRUE(global_option_get("CollectInternalStats"))) + if (IS_TRUE(global_option_get("CollectInternalStats"))) { record_statistics = 1; + plugin_register_read("collectd", plugin_update_internal_statistics); + } chain_name = global_option_get("PreCacheChain"); pre_cache_chain = fc_chain_get_by_name(chain_name); @@ -1661,9 +1662,6 @@ int plugin_init_all(void) { /* TODO: Rename this function. */ void plugin_read_all(void) { - if (record_statistics) { - plugin_update_internal_statistics(); - } uc_check_timeout(); return; diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c index fe0e083e..aa8ce9ef 100644 --- a/src/daemon/utils_cache.c +++ b/src/daemon/utils_cache.c @@ -222,8 +222,6 @@ int uc_init(void) { } /* int uc_init */ int uc_check_timeout(void) { - cdtime_t now = cdtime(); - struct { char *key; cdtime_t time; @@ -232,6 +230,7 @@ int uc_check_timeout(void) { size_t expired_num = 0; pthread_mutex_lock(&cache_lock); + cdtime_t now = cdtime(); /* Build a list of entries to be flushed */ c_avl_iterator_t *iter = c_avl_get_iterator(cache_tree); @@ -423,6 +422,9 @@ int uc_get_rate_by_name(const char *name, gauge_t **ret_values, /* remove missing values from getval */ if (ce->state == STATE_MISSING) { + DEBUG("utils_cache: uc_get_rate_by_name: requested metric \"%s\" is in " + "state \"missing\".", + name); status = -1; } else { ret_num = ce->values_num; @@ -466,7 +468,7 @@ gauge_t *uc_get_rate(const data_set_t *ds, const value_list_t *vl) { /* This is important - the caller has no other way of knowing how many * values are returned. */ - if (ret_num != (size_t)ds->ds_num) { + if (ret_num != ds->ds_num) { ERROR("utils_cache: uc_get_rate: ds[%s] has %zu values, " "but uc_get_rate_by_name returned %zu.", ds->type, ds->ds_num, ret_num); diff --git a/src/dbi.c b/src/dbi.c index 7cab1d54..0e5c5dec 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -172,7 +172,9 @@ static void cdbi_database_free(cdbi_database_t *db) /* {{{ */ return; sfree(db->name); + sfree(db->select_db); sfree(db->driver); + sfree(db->host); for (size_t i = 0; i < db->driver_options_num; i++) { sfree(db->driver_options[i].key); @@ -184,7 +186,10 @@ static void cdbi_database_free(cdbi_database_t *db) /* {{{ */ if (db->q_prep_areas) for (size_t i = 0; i < db->queries_num; ++i) udb_query_delete_preparation_area(db->q_prep_areas[i]); - free(db->q_prep_areas); + sfree(db->q_prep_areas); + /* N.B.: db->queries references objects "owned" by the global queries + * variable. Free the array here, but not the content. */ + sfree(db->queries); sfree(db); } /* }}} void cdbi_database_free */ diff --git a/src/dpdkstat.c b/src/dpdkstat.c index de75c0c0..6d0aabf7 100644 --- a/src/dpdkstat.c +++ b/src/dpdkstat.c @@ -159,8 +159,8 @@ static int dpdk_shm_init(size_t size); static void dpdk_config_init_default(void) { g_configuration->interval = plugin_get_interval(); if (g_configuration->interval == cf_get_default_interval()) - WARNING("dpdkstat: No time interval was configured, default value %lu ms " - "is set", + WARNING("dpdkstat: No time interval was configured, default value %" PRIu64 + " ms is set", CDTIME_T_TO_MS(g_configuration->interval)); /* Default is all ports enabled */ g_configuration->enabled_port_mask = ~0; @@ -289,13 +289,13 @@ static int dpdk_shm_init(size_t size) { if (err) { ERROR("dpdkstat semaphore init failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); - goto fail_close; + goto fail; } err = sem_init(&g_configuration->sema_stats_in_shm, 1, 0); if (err) { ERROR("dpdkstat semaphore init failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); - goto fail_close; + goto fail; } g_configuration->xstats = NULL; @@ -413,7 +413,7 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action) { if (pid > 0) { close(g_configuration->helper_pipes[1]); g_configuration->helper_pid = pid; - DEBUG("dpdkstat: helper pid %lu", (long)g_configuration->helper_pid); + DEBUG("dpdkstat: helper pid %li", (long)g_configuration->helper_pid); /* Kick helper once its alive to have it start processing */ sem_post(&g_configuration->sema_helper_get_stats); } else if (pid == 0) { @@ -620,17 +620,17 @@ static void dpdk_submit_xstats(const char *dev_name, int count, if ((type_end != NULL) && (strncmp(counter_name, "rx_", strlen("rx_")) == 0)) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "bytes") != NULL) { + sstrncpy(vl.type, "if_rx_octets", sizeof(vl.type)); + } else if (strstr(type_end, "error") != NULL) { sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type)); - } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + } else if (strstr(type_end, "dropped") != NULL) { sstrncpy(vl.type, "if_rx_dropped", sizeof(vl.type)); - } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { - sstrncpy(vl.type, "if_rx_octets", sizeof(vl.type)); - } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + } else if (strstr(type_end, "packets") != NULL) { sstrncpy(vl.type, "if_rx_packets", sizeof(vl.type)); - } else if (strncmp(type_end, "_placement", strlen("_placement")) == 0) { + } else if (strstr(type_end, "_placement") != NULL) { sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type)); - } else if (strncmp(type_end, "_buff", strlen("_buff")) == 0) { + } else if (strstr(type_end, "_buff") != NULL) { sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type)); } else { /* Does not fit obvious type: use a more generic one */ @@ -639,13 +639,13 @@ static void dpdk_submit_xstats(const char *dev_name, int count, } else if ((type_end != NULL) && (strncmp(counter_name, "tx_", strlen("tx_"))) == 0) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "bytes") != NULL) { + sstrncpy(vl.type, "if_tx_octets", sizeof(vl.type)); + } else if (strstr(type_end, "error") != NULL) { sstrncpy(vl.type, "if_tx_errors", sizeof(vl.type)); - } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + } else if (strstr(type_end, "dropped") != NULL) { sstrncpy(vl.type, "if_tx_dropped", sizeof(vl.type)); - } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { - sstrncpy(vl.type, "if_tx_octets", sizeof(vl.type)); - } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + } else if (strstr(type_end, "packets") != NULL) { sstrncpy(vl.type, "if_tx_packets", sizeof(vl.type)); } else { /* Does not fit obvious type: use a more generic one */ @@ -654,16 +654,14 @@ static void dpdk_submit_xstats(const char *dev_name, int count, } else if ((type_end != NULL) && (strncmp(counter_name, "flow_", strlen("flow_"))) == 0) { - if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { + if (strstr(type_end, "_filters") != NULL) { sstrncpy(vl.type, "operations", sizeof(vl.type)); - } else if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + } else if (strstr(type_end, "error") != NULL) sstrncpy(vl.type, "errors", sizeof(vl.type)); - } else if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { - sstrncpy(vl.type, "filter_result", sizeof(vl.type)); - } + } else if ((type_end != NULL) && (strncmp(counter_name, "mac_", strlen("mac_"))) == 0) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "error") != NULL) { sstrncpy(vl.type, "errors", sizeof(vl.type)); } } else { diff --git a/src/email.c b/src/email.c index 34e99984..611da560 100644 --- a/src/email.c +++ b/src/email.c @@ -299,22 +299,21 @@ static void *collect(void *arg) { } if ('e' == line[0]) { /* e:: */ - char *ptr = NULL; - char *type = strtok_r(line + 2, ":", &ptr); - char *tmp = strtok_r(NULL, ":", &ptr); - int bytes = 0; - - if (NULL == tmp) { + char *type = line + 2; + char *bytes_str = strchr(type, ':'); + if (bytes_str == NULL) { log_err("collect: syntax error in line '%s'", line); continue; } - bytes = atoi(tmp); + *bytes_str = 0; + bytes_str++; pthread_mutex_lock(&count_mutex); type_list_incr(&list_count, type, /* increment = */ 1); pthread_mutex_unlock(&count_mutex); + int bytes = atoi(bytes_str); if (bytes > 0) { pthread_mutex_lock(&size_mutex); type_list_incr(&list_size, type, /* increment = */ bytes); @@ -374,7 +373,7 @@ static void *open_connection(void __attribute__((unused)) * arg) { } struct sockaddr_un addr = { - .sun_family = AF_UNIX + .sun_family = AF_UNIX, }; sstrncpy(addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1)); @@ -403,15 +402,21 @@ static void *open_connection(void __attribute__((unused)) * arg) { { struct group sg; struct group *grp; - char grbuf[2048]; int status; + long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuf_size <= 0) + grbuf_size = sysconf(_SC_PAGESIZE); + if (grbuf_size <= 0) + grbuf_size = 4096; + char grbuf[grbuf_size]; + grp = NULL; status = getgrnam_r(group, &sg, grbuf, sizeof(grbuf), &grp); if (status != 0) { char errbuf[1024]; log_warn("getgrnam_r (%s) failed: %s", group, - sstrerror(errno, errbuf, sizeof(errbuf))); + sstrerror(status, errbuf, sizeof(errbuf))); } else if (grp == NULL) { log_warn("No such group: `%s'", group); } else { diff --git a/src/exec.c b/src/exec.c index d34f9d91..60bd961e 100644 --- a/src/exec.c +++ b/src/exec.c @@ -369,11 +369,17 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, struct passwd *sp_ptr; struct passwd sp; - char nambuf[2048]; if (pl->pid != 0) return (-1); + long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX); + if (nambuf_size <= 0) + nambuf_size = sysconf(_SC_PAGESIZE); + if (nambuf_size <= 0) + nambuf_size = 4096; + char nambuf[nambuf_size]; + if ((create_pipe(fd_pipe_in) == -1) || (create_pipe(fd_pipe_out) == -1) || (create_pipe(fd_pipe_err) == -1)) goto failed; @@ -382,7 +388,7 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, status = getpwnam_r(pl->user, &sp, nambuf, sizeof(nambuf), &sp_ptr); if (status != 0) { ERROR("exec plugin: Failed to get user information for user ``%s'': %s", - pl->user, sstrerror(errno, errbuf, sizeof(errbuf))); + pl->user, sstrerror(status, errbuf, sizeof(errbuf))); goto failed; } @@ -406,11 +412,18 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, struct group *gr_ptr = NULL; struct group gr; - status = getgrnam_r(pl->group, &gr, nambuf, sizeof(nambuf), &gr_ptr); + long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuf_size <= 0) + grbuf_size = sysconf(_SC_PAGESIZE); + if (grbuf_size <= 0) + grbuf_size = 4096; + char grbuf[grbuf_size]; + + status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr); if (0 != status) { ERROR("exec plugin: Failed to get group information " "for group ``%s'': %s", - pl->group, sstrerror(errno, errbuf, sizeof(errbuf))); + pl->group, sstrerror(status, errbuf, sizeof(errbuf))); goto failed; } if (NULL == gr_ptr) { @@ -787,7 +800,11 @@ static int exec_read(void) /* {{{ */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read"); + int status = + plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read"); + if (status != 0) { + ERROR("exec plugin: plugin_thread_create failed."); + } pthread_attr_destroy(&attr); } /* for (pl) */ @@ -826,8 +843,11 @@ static int exec_notification(const notification_t *n, /* {{{ */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - plugin_thread_create(&t, &attr, exec_notification_one, (void *)pln, - "exec notify"); + int status = plugin_thread_create(&t, &attr, exec_notification_one, + (void *)pln, "exec notify"); + if (status != 0) { + ERROR("exec plugin: plugin_thread_create failed."); + } pthread_attr_destroy(&attr); } /* for (pl) */ diff --git a/src/gps.c b/src/gps.c index a4b3e2e7..686710ba 100644 --- a/src/gps.c +++ b/src/gps.c @@ -26,10 +26,10 @@ * Marc Fournier **/ +#include "collectd.h" #include "common.h" #include "plugin.h" #include "utils_time.h" -#include "collectd.h" #define CGPS_TRUE 1 #define CGPS_FALSE 0 @@ -80,7 +80,7 @@ static int cgps_thread_pause(cdtime_t pTime) { int ret = !cgps_thread_shutdown; - pthread_mutex_lock(&cgps_thread_lock); + pthread_mutex_unlock(&cgps_thread_lock); return ret; } @@ -307,7 +307,6 @@ static int cgps_shutdown(void) { free(res); // Clean mutex: - pthread_mutex_unlock(&cgps_thread_lock); pthread_mutex_destroy(&cgps_thread_lock); pthread_mutex_unlock(&cgps_data_lock); pthread_mutex_destroy(&cgps_data_lock); diff --git a/src/intel_rdt.c b/src/intel_rdt.c index 2ef65f57..6f157b8f 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -36,6 +36,11 @@ #define RDT_MAX_SOCKET_CORES 64 #define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS) +typedef enum { + UNKNOWN = 0, + CONFIGURATION_ERROR, +} rdt_config_status; + struct rdt_core_group_s { char *desc; size_t num_cores; @@ -56,6 +61,8 @@ typedef struct rdt_ctx_s rdt_ctx_t; static rdt_ctx_t *g_rdt = NULL; +static rdt_config_status g_state = UNKNOWN; + static int isdup(const uint64_t *nums, size_t size, uint64_t val) { for (size_t i = 0; i < size; i++) if (nums[i] == val) @@ -520,25 +527,31 @@ rdt_preinit_error1: } static int rdt_config(oconfig_item_t *ci) { - int ret = 0; - - ret = rdt_preinit(); - if (ret != 0) - return ret; + if (rdt_preinit() != 0) { + g_state = CONFIGURATION_ERROR; + /* if we return -1 at this point collectd + reports a failure in configuration and + aborts + */ + return (0); + } for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("Cores", child->key) == 0) { - - ret = rdt_config_cgroups(child); - if (ret != 0) - return ret; + if (rdt_config_cgroups(child) != 0) { + g_state = CONFIGURATION_ERROR; + /* if we return -1 at this point collectd + reports a failure in configuration and + aborts + */ + return (0); + } #if COLLECT_DEBUG rdt_dump_cgroups(); #endif /* COLLECT_DEBUG */ - } else { ERROR(RDT_PLUGIN ": Unknown configuration parameter \"%s\".", child->key); } @@ -626,6 +639,9 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) { static int rdt_init(void) { int ret; + if(g_state == CONFIGURATION_ERROR) + return (-1); + ret = rdt_preinit(); if (ret != 0) return ret; diff --git a/src/ipc.c b/src/ipc.c index c9fb003e..74db3adf 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -251,14 +251,14 @@ static int ipc_read_shm(void) /* {{{ */ ipcinfo_shm_t *pshm; unsigned int shm_segments = 0; size64_t shm_bytes = 0; - int n; + int i, n; ipcinfo_shm = (ipcinfo_shm_t *)ipc_get_info( 0, GET_IPCINFO_SHM_ALL, IPCINFO_SHM_VERSION, sizeof(ipcinfo_shm_t), &n); if (ipcinfo_shm == NULL) return -1; - for (int i = 0, pshm = ipcinfo_shm; i < n; i++, pshm++) { + for (i = 0, pshm = ipcinfo_shm; i < n; i++, pshm++) { shm_segments++; shm_bytes += pshm->shm_segsz; } diff --git a/src/liboconfig/parser.y b/src/liboconfig/parser.y index 4a550b32..90f51de7 100644 --- a/src/liboconfig/parser.y +++ b/src/liboconfig/parser.y @@ -31,7 +31,7 @@ #include "aux_types.h" static char *unquote (const char *orig); -static int yyerror (const char *s); +static void yyerror(const char *s); /* Lexer variables */ extern int yylineno; @@ -94,13 +94,23 @@ argument_list: argument_list argument { $$ = $1; + oconfig_value_t *tmp = realloc($$.argument, + ($$.argument_num+1) * sizeof(*$$.argument)); + if (tmp == NULL) { + yyerror("realloc failed"); + YYERROR; + } + $$.argument = tmp; + $$.argument[$$.argument_num] = $2; $$.argument_num++; - $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t)); - $$.argument[$$.argument_num-1] = $2; } | argument { - $$.argument = malloc (sizeof (oconfig_value_t)); + $$.argument = calloc(1, sizeof(*$$.argument)); + if ($$.argument == NULL) { + yyerror("calloc failed"); + YYERROR; + } $$.argument[0] = $1; $$.argument_num = 1; } @@ -113,7 +123,7 @@ identifier: option: identifier argument_list EOL { - memset (&$$, '\0', sizeof ($$)); + memset(&$$, 0, sizeof($$)); $$.key = $1; $$.values = $2.argument; $$.values_num = $2.argument_num; @@ -123,13 +133,13 @@ option: block_begin: OPENBRAC identifier CLOSEBRAC EOL { - memset (&$$, '\0', sizeof ($$)); + memset(&$$, 0, sizeof($$)); $$.key = $2; } | OPENBRAC identifier argument_list CLOSEBRAC EOL { - memset (&$$, '\0', sizeof ($$)); + memset(&$$, 0, sizeof($$)); $$.key = $2; $$.values = $3.argument; $$.values_num = $3.argument_num; @@ -146,11 +156,11 @@ block_end: block: block_begin statement_list block_end { - if (strcmp ($1.key, $3) != 0) + if (strcmp($1.key, $3) != 0) { - printf ("block_begin = %s; block_end = %s;\n", $1.key, $3); - yyerror ("Block not closed..\n"); - exit (1); + printf("block_begin = %s; block_end = %s;\n", $1.key, $3); + yyerror("block not closed"); + YYERROR; } free ($3); $3 = NULL; $$ = $1; @@ -159,11 +169,11 @@ block: } | block_begin block_end { - if (strcmp ($1.key, $2) != 0) + if (strcmp($1.key, $2) != 0) { - printf ("block_begin = %s; block_end = %s;\n", $1.key, $2); - yyerror ("Block not closed..\n"); - exit (1); + printf("block_begin = %s; block_end = %s;\n", $1.key, $2); + yyerror("block not closed"); + YYERROR; } free ($2); $2 = NULL; $$ = $1; @@ -184,16 +194,26 @@ statement_list: $$ = $1; if (($2.values_num > 0) || ($2.children_num > 0)) { + oconfig_item_t *tmp = realloc($$.statement, + ($$.statement_num+1) * sizeof(*tmp)); + if (tmp == NULL) { + yyerror("realloc failed"); + YYERROR; + } + $$.statement = tmp; + $$.statement[$$.statement_num] = $2; $$.statement_num++; - $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t)); - $$.statement[$$.statement_num-1] = $2; } } | statement { if (($1.values_num > 0) || ($1.children_num > 0)) { - $$.statement = malloc (sizeof (oconfig_item_t)); + $$.statement = calloc(1, sizeof(*$$.statement)); + if ($$.statement == NULL) { + yyerror("calloc failed"); + YYERROR; + } $$.statement[0] = $1; $$.statement_num = 1; } @@ -208,31 +228,38 @@ statement_list: entire_file: statement_list { - ci_root = calloc (1, sizeof (*ci_root)); + ci_root = calloc(1, sizeof(*ci_root)); + if (ci_root == NULL) { + yyerror("calloc failed"); + YYERROR; + } ci_root->children = $1.statement; ci_root->children_num = $1.statement_num; } | /* epsilon */ { - ci_root = calloc (1, sizeof (*ci_root)); - ci_root->children = NULL; - ci_root->children_num = 0; + ci_root = calloc(1, sizeof(*ci_root)); + if (ci_root == NULL) { + yyerror("calloc failed"); + YYERROR; + } } ; %% -static int yyerror (const char *s) +static void yyerror(const char *s) { const char *text; - if (*yytext == '\n') + if (yytext == NULL) + text = ""; + else if (*yytext == '\n') text = ""; else text = yytext; - fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n", + fprintf(stderr, "Parse error in file `%s', line %i near `%s': %s\n", c_file, yylineno, text, s); - return (-1); } /* int yyerror */ static char *unquote (const char *orig) @@ -250,7 +277,7 @@ static char *unquote (const char *orig) len -= 2; memmove (ret, ret + 1, len); - ret[len] = '\0'; + ret[len] = 0; for (int i = 0; i < len; i++) { diff --git a/src/log_logstash.c b/src/log_logstash.c index 303976b5..8df43136 100644 --- a/src/log_logstash.c +++ b/src/log_logstash.c @@ -41,8 +41,6 @@ #define HAVE_YAJL_V2 1 #endif -#define DEFAULT_LOGFILE LOCALSTATEDIR "/log/" PACKAGE_NAME ".json.log" - #if COLLECT_DEBUG static int log_level = LOG_DEBUG; #else @@ -149,8 +147,7 @@ static void log_logstash_print(yajl_gen g, int severity, pthread_mutex_lock(&file_lock); if (log_file == NULL) { - fh = fopen(DEFAULT_LOGFILE, "a"); - do_close = 1; + fh = stderr; } else if (strcasecmp(log_file, "stdout") == 0) { fh = stdout; do_close = 0; @@ -164,8 +161,7 @@ static void log_logstash_print(yajl_gen g, int severity, if (fh == NULL) { char errbuf[1024]; - fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", - (log_file == NULL) ? DEFAULT_LOGFILE : log_file, + fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", log_file, sstrerror(errno, errbuf, sizeof(errbuf))); } else { fprintf(fh, "%s\n", buf); diff --git a/src/logfile.c b/src/logfile.c index db122915..6629c0b3 100644 --- a/src/logfile.c +++ b/src/logfile.c @@ -31,8 +31,6 @@ #include "common.h" #include "plugin.h" -#define DEFAULT_LOGFILE LOCALSTATEDIR "/log/collectd.log" - #if COLLECT_DEBUG static int log_level = LOG_DEBUG; #else @@ -117,8 +115,7 @@ static void logfile_print(const char *msg, int severity, pthread_mutex_lock(&file_lock); if (log_file == NULL) { - fh = fopen(DEFAULT_LOGFILE, "a"); - do_close = 1; + fh = stderr; } else if (strcasecmp(log_file, "stderr") == 0) fh = stderr; else if (strcasecmp(log_file, "stdout") == 0) @@ -130,8 +127,7 @@ static void logfile_print(const char *msg, int severity, if (fh == NULL) { char errbuf[1024]; - fprintf(stderr, "logfile plugin: fopen (%s) failed: %s\n", - (log_file == NULL) ? DEFAULT_LOGFILE : log_file, + fprintf(stderr, "logfile plugin: fopen (%s) failed: %s\n", log_file, sstrerror(errno, errbuf, sizeof(errbuf))); } else { if (print_timestamp) diff --git a/src/memcached.c b/src/memcached.c index 79c38a79..cfdf903d 100644 --- a/src/memcached.c +++ b/src/memcached.c @@ -341,9 +341,10 @@ static int memcached_read(user_data_t *user_data) { * CPU time consumed by the memcached process */ if (FIELD_IS("rusage_user")) { - rusage_user = atoll(fields[2]); + /* Convert to useconds */ + rusage_user = atof(fields[2]) * 1000000; } else if (FIELD_IS("rusage_system")) { - rusage_syst = atoll(fields[2]); + rusage_syst = atof(fields[2]) * 1000000; } /* diff --git a/src/mqtt.c b/src/mqtt.c index b578b99b..315974b6 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -448,6 +448,7 @@ static int publish(mqtt_client_conf_t *conf, char const *topic, * measure; we will try to reconnect the next time we have to publish a * message */ conf->connected = 0; + mosquitto_disconnect(conf->mosq); pthread_mutex_unlock(&conf->lock); return (-1); @@ -461,6 +462,7 @@ static int format_topic(char *buf, size_t buf_len, data_set_t const *ds, value_list_t const *vl, mqtt_client_conf_t *conf) { char name[MQTT_MAX_TOPIC_SIZE]; int status; + char *c; if ((conf->topic_prefix == NULL) || (conf->topic_prefix[0] == 0)) return (FORMAT_VL(buf, buf_len, vl)); @@ -473,6 +475,10 @@ static int format_topic(char *buf, size_t buf_len, data_set_t const *ds, if ((status < 0) || (((size_t)status) >= buf_len)) return (ENOMEM); + while((c = strchr(buf, '#')) || (c = strchr(buf, '+'))) { + *c = '_'; + } + return (0); } /* int format_topic */ diff --git a/src/msr-index.h b/src/msr-index.h new file mode 100644 index 00000000..c8077b77 --- /dev/null +++ b/src/msr-index.h @@ -0,0 +1,85 @@ +/* + * Partial header file imported from the linux kernel + * (arch/x86/include/asm/msr-index.h) + * as it is not provided by the kernel sources anymore + * + * Only the minimal blocks of macro have been included + * ---- + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * ---- + */ + +#ifndef _ASM_X86_MSR_INDEX_H +#define _ASM_X86_MSR_INDEX_H + +/* + * CPU model specific register (MSR) numbers. + * + * Do not add new entries to this file unless the definitions are shared + * between multiple compilation units. + */ + +/* Intel MSRs. Some also available on other CPUs */ + +/* C-state Residency Counters */ +#define MSR_PKG_C3_RESIDENCY 0x000003f8 +#define MSR_PKG_C6_RESIDENCY 0x000003f9 +#define MSR_ATOM_PKG_C6_RESIDENCY 0x000003fa +#define MSR_PKG_C7_RESIDENCY 0x000003fa +#define MSR_CORE_C3_RESIDENCY 0x000003fc +#define MSR_CORE_C6_RESIDENCY 0x000003fd +#define MSR_CORE_C7_RESIDENCY 0x000003fe +#define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff +#define MSR_PKG_C2_RESIDENCY 0x0000060d +#define MSR_PKG_C8_RESIDENCY 0x00000630 +#define MSR_PKG_C9_RESIDENCY 0x00000631 +#define MSR_PKG_C10_RESIDENCY 0x00000632 + +/* Run Time Average Power Limiting (RAPL) Interface */ + +#define MSR_RAPL_POWER_UNIT 0x00000606 + +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_PERF_STATUS 0x00000613 +#define MSR_PKG_POWER_INFO 0x00000614 + +#define MSR_DRAM_POWER_LIMIT 0x00000618 +#define MSR_DRAM_ENERGY_STATUS 0x00000619 +#define MSR_DRAM_PERF_STATUS 0x0000061b +#define MSR_DRAM_POWER_INFO 0x0000061c + +#define MSR_PP0_POWER_LIMIT 0x00000638 +#define MSR_PP0_ENERGY_STATUS 0x00000639 +#define MSR_PP0_POLICY 0x0000063a +#define MSR_PP0_PERF_STATUS 0x0000063b + +#define MSR_PP1_POWER_LIMIT 0x00000640 +#define MSR_PP1_ENERGY_STATUS 0x00000641 +#define MSR_PP1_POLICY 0x00000642 + +/* Intel defined MSRs. */ +#define MSR_IA32_TSC 0x00000010 +#define MSR_SMI_COUNT 0x00000034 + +#define MSR_IA32_MPERF 0x000000e7 +#define MSR_IA32_APERF 0x000000e8 + +#define MSR_IA32_THERM_STATUS 0x0000019c + +#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 + +#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 + +#endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/src/netapp.c b/src/netapp.c index 4d458793..45144bf1 100644 --- a/src/netapp.c +++ b/src/netapp.c @@ -674,7 +674,7 @@ static int submit_double(const char *host, const char *plugin_inst, /* {{{ */ const char *type, const char *type_inst, double d, cdtime_t timestamp, cdtime_t interval) { return (submit_values(host, plugin_inst, type, type_inst, - &(value_t){.gauge = counter}, 1, timestamp, interval)); + &(value_t){.gauge = d}, 1, timestamp, interval)); } /* }}} int submit_uint64 */ /* Calculate hit ratio from old and new counters and submit the resulting @@ -1910,15 +1910,13 @@ static int cna_query_quota(host_config_t *host) /* {{{ */ static int cna_handle_snapvault_data(const char *hostname, /* {{{ */ cfg_snapvault_t *cfg_snapvault, na_elem_t *data, cdtime_t interval) { - na_elem_iter_t status_iter; - - status = na_elem_child(data, "status-list"); - if (!status) { + na_elem_t *status_list = na_elem_child(data, "status-list"); + if (status_list == NULL) { ERROR("netapp plugin: SnapVault status record missing status-list"); return (0); } - status_iter = na_child_iterator(status); + na_elem_iter_t status_iter = na_child_iterator(status_list); for (na_elem_t *status = na_iterator_next(&status_iter); status != NULL; status = na_iterator_next(&status_iter)) { const char *dest_sys, *dest_path, *src_sys, *src_path; diff --git a/src/netlink.c b/src/netlink.c index 8076c1fa..66129ad8 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -353,8 +353,10 @@ static int link_filter_cb(const struct nlmsghdr *nlh, continue; if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*stats.stats64)) < 0) { + char errbuf[1024]; ERROR("netlink plugin: link_filter_cb: IFLA_STATS64 mnl_attr_validate2 " - "failed."); + "failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return MNL_CB_ERROR; } stats.stats64 = mnl_attr_get_payload(attr); @@ -369,8 +371,10 @@ static int link_filter_cb(const struct nlmsghdr *nlh, continue; if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*stats.stats32)) < 0) { + char errbuf[1024]; ERROR("netlink plugin: link_filter_cb: IFLA_STATS mnl_attr_validate2 " - "failed."); + "failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return MNL_CB_ERROR; } stats.stats32 = mnl_attr_get_payload(attr); @@ -395,8 +399,10 @@ static int qos_attr_cb(const struct nlattr *attr, void *data) { if (mnl_attr_get_type(attr) == TCA_STATS_BASIC) { if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(**bs)) < 0) { + char errbuf[1024]; ERROR("netlink plugin: qos_attr_cb: TCA_STATS_BASIC mnl_attr_validate2 " - "failed."); + "failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return MNL_CB_ERROR; } *bs = mnl_attr_get_payload(attr); @@ -529,8 +535,10 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) { continue; if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*ts)) < 0) { + char errbuf[1024]; ERROR("netlink plugin: qos_filter_cb: TCA_STATS mnl_attr_validate2 " - "failed."); + "failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return MNL_CB_ERROR; } ts = mnl_attr_get_payload(attr); @@ -666,7 +674,9 @@ static int ir_read(void) { ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret < 0) { - ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed."); + char errbuf[1024]; + ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return (-1); } @@ -711,10 +721,11 @@ static int ir_read(void) { ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); } if (ret < 0) { - ERROR("netlink plugin: ir_read:mnl_socket_recvfrom failed."); + char errbuf[1024]; + ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); continue; } - } /* for (type_index) */ } /* for (if_index) */ diff --git a/src/network.c b/src/network.c index 8eab08b6..e28316d5 100644 --- a/src/network.c +++ b/src/network.c @@ -1003,14 +1003,6 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */ buffer_len = *ret_buffer_len; buffer_offset = 0; - if (se->data.server.userdb == NULL) { - c_complain( - LOG_NOTICE, &complain_no_users, - "network plugin: Received signed network packet but can't verify it " - "because no user DB has been configured. Will accept it."); - return (0); - } - /* Check if the buffer has enough data for this structure. */ if (buffer_len <= PART_SIGNATURE_SHA256_SIZE) return (-ENOMEM); @@ -1027,6 +1019,18 @@ static int parse_part_sign_sha256(sockent_t *se, /* {{{ */ return (-1); } + if (se->data.server.userdb == NULL) { + c_complain( + LOG_NOTICE, &complain_no_users, + "network plugin: Received signed network packet but can't verify it " + "because no user DB has been configured. Will accept it."); + + *ret_buffer = buffer + pss_head_length; + *ret_buffer_len -= pss_head_length; + + return (0); + } + /* Copy the hash. */ BUFFER_READ(pss.hash, sizeof(pss.hash)); @@ -1226,9 +1230,9 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */ part_size - buffer_offset, /* in = */ NULL, /* in len = */ 0); if (err != 0) { - sfree(pea.username); ERROR("network plugin: gcry_cipher_decrypt returned: %s. Username: %s", gcry_strerror(err), pea.username); + sfree(pea.username); return (-1); } @@ -1250,8 +1254,6 @@ static int parse_part_encr_aes256(sockent_t *se, /* {{{ */ parse_packet(se, buffer + buffer_offset, payload_len, flags | PP_ENCRYPTED, pea.username); - /* XXX: Free pea.username?!? */ - /* Update return values */ *ret_buffer = buffer + part_size; *ret_buffer_len = buffer_len - part_size; diff --git a/src/nginx.c b/src/nginx.c index ffc545c4..060eae23 100644 --- a/src/nginx.c +++ b/src/nginx.c @@ -133,10 +133,6 @@ static int init(void) { #endif } - if (url != NULL) { - curl_easy_setopt(curl, CURLOPT_URL, url); - } - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); @@ -207,6 +203,9 @@ static int nginx_read(void) { return (-1); nginx_buffer_len = 0; + + curl_easy_setopt(curl, CURLOPT_URL, url); + if (curl_easy_perform(curl) != CURLE_OK) { WARNING("nginx plugin: curl_easy_perform failed: %s", nginx_curl_error); return (-1); diff --git a/src/ntpd.c b/src/ntpd.c index 1dc1857b..bc81cdd8 100644 --- a/src/ntpd.c +++ b/src/ntpd.c @@ -850,9 +850,9 @@ static int ntpd_read(void) { } /* kerninfo -> estimated error */ - offset_loop = scale_loop * ((gauge_t)ntohl(ik->offset)); + offset_loop = (gauge_t)((int32_t)ntohl(ik->offset) * scale_loop); freq_loop = ntpd_read_fp(ik->freq); - offset_error = scale_error * ((gauge_t)ntohl(ik->esterror)); + offset_error = (gauge_t)((int32_t)ntohl(ik->esterror) * scale_error); DEBUG("info_kernel:\n" " pll offset = %.8g\n" diff --git a/src/openldap.c b/src/openldap.c index 5269e5f2..50757db8 100644 --- a/src/openldap.c +++ b/src/openldap.c @@ -92,7 +92,8 @@ static int cldap_init_host(cldap_t *st) /* {{{ */ if (rc != LDAP_SUCCESS) { ERROR("openldap plugin: ldap_initialize failed: %s", ldap_err2string(rc)); st->state = 0; - ldap_unbind_ext_s(ld, NULL, NULL); + if (ld != NULL) + ldap_unbind_ext_s(ld, NULL, NULL); return (-1); } @@ -119,7 +120,8 @@ static int cldap_init_host(cldap_t *st) /* {{{ */ ERROR("openldap plugin: Failed to start tls on %s: %s", st->url, ldap_err2string(rc)); st->state = 0; - ldap_unbind_ext_s(st->ld, NULL, NULL); + if (st->ld != NULL) + ldap_unbind_ext_s(st->ld, NULL, NULL); return (-1); } } @@ -139,7 +141,8 @@ static int cldap_init_host(cldap_t *st) /* {{{ */ ERROR("openldap plugin: Failed to bind to %s: %s", st->url, ldap_err2string(rc)); st->state = 0; - ldap_unbind_ext_s(st->ld, NULL, NULL); + if (st->ld != NULL) + ldap_unbind_ext_s(st->ld, NULL, NULL); return (-1); } else { DEBUG("openldap plugin: Successfully connected to %s", st->url); @@ -214,7 +217,8 @@ static int cldap_read_host(user_data_t *ud) /* {{{ */ ERROR("openldap plugin: Failed to execute search: %s", ldap_err2string(rc)); ldap_msgfree(result); st->state = 0; - ldap_unbind_ext_s(st->ld, NULL, NULL); + if (st->ld != NULL) + ldap_unbind_ext_s(st->ld, NULL, NULL); return (-1); } diff --git a/src/perl.c b/src/perl.c index 59109133..b39250f3 100644 --- a/src/perl.c +++ b/src/perl.c @@ -496,16 +496,16 @@ static int av2data_set(pTHX_ AV *array, char *name, data_set_t *ds) { * meta => [ { name => , value => }, ... ] * } */ -static int av2notification_meta(pTHX_ AV *array, notification_meta_t **meta) { - notification_meta_t **m = meta; +static int av2notification_meta(pTHX_ AV *array, + notification_meta_t **ret_meta) { + notification_meta_t *tail = NULL; int len = av_len(array); for (int i = 0; i <= len; ++i) { SV **tmp = av_fetch(array, i, 0); - HV *hash; - if (NULL == tmp) + if (tmp == NULL) return -1; if (!(SvROK(*tmp) && (SVt_PVHV == SvTYPE(SvRV(*tmp))))) { @@ -514,42 +514,51 @@ static int av2notification_meta(pTHX_ AV *array, notification_meta_t **meta) { continue; } - hash = (HV *)SvRV(*tmp); + HV *hash = (HV *)SvRV(*tmp); - *m = smalloc(sizeof(**m)); + notification_meta_t *m = calloc(1, sizeof(*m)); + if (m == NULL) + return ENOMEM; - if (NULL == (tmp = hv_fetch(hash, "name", 4, 0))) { + SV **name = hv_fetch(hash, "name", strlen("name"), 0); + if (name == NULL) { log_warn("av2notification_meta: Skipping invalid " "meta information."); - free(*m); + sfree(m); continue; } - sstrncpy((*m)->name, SvPV_nolen(*tmp), sizeof((*m)->name)); + sstrncpy(m->name, SvPV_nolen(*name), sizeof(m->name)); - if (NULL == (tmp = hv_fetch(hash, "value", 5, 0))) { + SV **value = hv_fetch(hash, "value", strlen("value"), 0); + if (value == NULL) { log_warn("av2notification_meta: Skipping invalid " "meta information."); - free(*m); + sfree(m); continue; } - if (SvNOK(*tmp)) { - (*m)->nm_value.nm_double = SvNVX(*tmp); - (*m)->type = NM_TYPE_DOUBLE; - } else if (SvUOK(*tmp)) { - (*m)->nm_value.nm_unsigned_int = SvUVX(*tmp); - (*m)->type = NM_TYPE_UNSIGNED_INT; - } else if (SvIOK(*tmp)) { - (*m)->nm_value.nm_signed_int = SvIVX(*tmp); - (*m)->type = NM_TYPE_SIGNED_INT; + if (SvNOK(*value)) { + m->nm_value.nm_double = SvNVX(*value); + m->type = NM_TYPE_DOUBLE; + } else if (SvUOK(*value)) { + m->nm_value.nm_unsigned_int = SvUVX(*value); + m->type = NM_TYPE_UNSIGNED_INT; + } else if (SvIOK(*value)) { + m->nm_value.nm_signed_int = SvIVX(*value); + m->type = NM_TYPE_SIGNED_INT; } else { - (*m)->nm_value.nm_string = sstrdup(SvPV_nolen(*tmp)); - (*m)->type = NM_TYPE_STRING; + m->nm_value.nm_string = sstrdup(SvPV_nolen(*value)); + m->type = NM_TYPE_STRING; } - (*m)->next = NULL; - m = &((*m)->next); + m->next = NULL; + if (tail == NULL) + *ret_meta = m; + else + tail->next = m; + tail = m; } + return 0; } /* static int av2notification_meta (AV *, notification_meta_t *) */ @@ -707,10 +716,8 @@ static int value_list2hv(pTHX_ value_list_t *vl, data_set_t *ds, HV *hash) { static int notification_meta2av(pTHX_ notification_meta_t *meta, AV *array) { int meta_num = 0; - - while (meta) { + for (notification_meta_t *m = meta; m != NULL; m = m->next) { ++meta_num; - meta = meta->next; } av_extend(array, meta_num); @@ -2343,14 +2350,25 @@ static int g_interval_set(pTHX_ SV *var, MAGIC *mg) { return 0; } /* static int g_interval_set (pTHX_ SV *, MAGIC *) */ -static MGVTBL g_pv_vtbl = {g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL +static MGVTBL g_pv_vtbl = {g_pv_get, + g_pv_set, + NULL, + NULL, + NULL, + NULL, + NULL #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL , NULL #endif }; -static MGVTBL g_interval_vtbl = {g_interval_get, g_interval_set, NULL, NULL, - NULL, NULL, NULL +static MGVTBL g_interval_vtbl = {g_interval_get, + g_interval_set, + NULL, + NULL, + NULL, + NULL, + NULL #if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL , NULL @@ -2610,6 +2628,12 @@ static int perl_config_plugin(pTHX_ oconfig_item_t *ci) { char *plugin; HV *config; + if (NULL == perl_threads) { + log_err("A `Plugin' block was encountered but no plugin was loaded yet. " + "Put the appropriate `LoadPlugin' option in front of it."); + return -1; + } + dSP; if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) { diff --git a/src/ping.c b/src/ping.c index 82de59f0..03dea6db 100644 --- a/src/ping.c +++ b/src/ping.c @@ -81,11 +81,11 @@ static double ping_interval = 1.0; static double ping_timeout = 0.9; static int ping_max_missed = -1; +static pthread_mutex_t ping_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t ping_cond = PTHREAD_COND_INITIALIZER; static int ping_thread_loop = 0; static int ping_thread_error = 0; static pthread_t ping_thread_id; -static pthread_mutex_t ping_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t ping_cond = PTHREAD_COND_INITIALIZER; static const char *config_keys[] = {"Host", "SourceAddress", #ifdef HAVE_OPING_1_3 @@ -224,8 +224,6 @@ static int ping_dispatch_all(pingobj_t *pingobj) /* {{{ */ static void *ping_thread(void *arg) /* {{{ */ { - pingobj_t *pingobj = NULL; - struct timeval tv_begin; struct timeval tv_end; struct timespec ts_wait; @@ -235,11 +233,10 @@ static void *ping_thread(void *arg) /* {{{ */ c_complain_t complaint = C_COMPLAIN_INIT_STATIC; - pthread_mutex_lock(&ping_lock); - - pingobj = ping_construct(); + pingobj_t *pingobj = ping_construct(); if (pingobj == NULL) { ERROR("ping plugin: ping_construct failed."); + pthread_mutex_lock(&ping_lock); ping_thread_error = 1; pthread_mutex_unlock(&ping_lock); return ((void *)-1); @@ -276,6 +273,7 @@ static void *ping_thread(void *arg) /* {{{ */ if (count == 0) { ERROR("ping plugin: No host could be added to ping object. Giving up."); + pthread_mutex_lock(&ping_lock); ping_thread_error = 1; pthread_mutex_unlock(&ping_lock); return ((void *)-1); @@ -291,8 +289,8 @@ static void *ping_thread(void *arg) /* {{{ */ ts_int.tv_nsec = (long)(temp_nsec * 1000000000L); } + pthread_mutex_lock(&ping_lock); while (ping_thread_loop > 0) { - int status; _Bool send_successful = 0; if (gettimeofday(&tv_begin, NULL) < 0) { @@ -305,7 +303,7 @@ static void *ping_thread(void *arg) /* {{{ */ pthread_mutex_unlock(&ping_lock); - status = ping_send(pingobj); + int status = ping_send(pingobj); if (status < 0) { c_complain(LOG_ERR, &complaint, "ping plugin: ping_send failed: %s", ping_get_error(pingobj)); diff --git a/src/postgresql_default.conf b/src/postgresql_default.conf index 0aac41e2..50799013 100644 --- a/src/postgresql_default.conf +++ b/src/postgresql_default.conf @@ -38,9 +38,9 @@ - Statement "SELECT sum(n_tup_ins) AS ins, \ - sum(n_tup_upd) AS upd, \ - sum(n_tup_del) AS del \ + Statement "SELECT coalesce(sum(n_tup_ins), 0) AS ins, \ + coalesce(sum(n_tup_upd), 0) AS upd, \ + coalesce(sum(n_tup_del), 0) AS del \ FROM pg_stat_user_tables;" @@ -63,10 +63,10 @@ - Statement "SELECT sum(n_tup_ins) AS ins, \ - sum(n_tup_upd) AS upd, \ - sum(n_tup_del) AS del, \ - sum(n_tup_hot_upd) AS hot_upd \ + Statement "SELECT coalesce(sum(n_tup_ins), 0) AS ins, \ + coalesce(sum(n_tup_upd), 0) AS upd, \ + coalesce(sum(n_tup_del), 0) AS del, \ + coalesce(sum(n_tup_hot_upd), 0) AS hot_upd \ FROM pg_stat_user_tables;" @@ -188,7 +188,8 @@ - Statement "SELECT sum(n_live_tup) AS live, sum(n_dead_tup) AS dead \ + Statement "SELECT coalesce(sum(n_live_tup), 0) AS live, \ + coalesce(sum(n_dead_tup), 0) AS dead \ FROM pg_stat_user_tables;" diff --git a/src/powerdns.c b/src/powerdns.c index f2149ef2..da72ec8d 100644 --- a/src/powerdns.c +++ b/src/powerdns.c @@ -379,8 +379,8 @@ static void submit(const char *plugin_instance, /* {{{ */ plugin_dispatch_values(&vl); } /* }}} static void submit */ -static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */ - char **ret_buffer, size_t *ret_buffer_size) { +static int powerdns_get_data_dgram(list_item_t *item, char **ret_buffer) { + /* {{{ */ int sd; int status; @@ -478,14 +478,11 @@ static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */ buffer[buffer_size - 1] = 0; *ret_buffer = buffer; - *ret_buffer_size = buffer_size; - return (0); } /* }}} int powerdns_get_data_dgram */ -static int powerdns_get_data_stream(list_item_t *item, /* {{{ */ - char **ret_buffer, - size_t *ret_buffer_size) { +static int powerdns_get_data_stream(list_item_t *item, char **ret_buffer) { + /* {{{ */ int sd; int status; @@ -533,13 +530,14 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */ if (status < 0) { SOCK_ERROR("recv", item->sockaddr.sun_path); break; - } else if (status == 0) + } else if (status == 0) { break; + } buffer_new = realloc(buffer, buffer_size + status + 1); if (buffer_new == NULL) { FUNC_ERROR("realloc"); - status = -1; + status = ENOMEM; break; } buffer = buffer_new; @@ -550,23 +548,20 @@ static int powerdns_get_data_stream(list_item_t *item, /* {{{ */ } /* while (42) */ close(sd); - if (status < 0) { + if (status != 0) { sfree(buffer); - } else { - assert(status == 0); - *ret_buffer = buffer; - *ret_buffer_size = buffer_size; + return status; } - return (status); + *ret_buffer = buffer; + return 0; } /* }}} int powerdns_get_data_stream */ -static int powerdns_get_data(list_item_t *item, char **ret_buffer, - size_t *ret_buffer_size) { +static int powerdns_get_data(list_item_t *item, char **ret_buffer) { if (item->socktype == SOCK_DGRAM) - return (powerdns_get_data_dgram(item, ret_buffer, ret_buffer_size)); + return (powerdns_get_data_dgram(item, ret_buffer)); else if (item->socktype == SOCK_STREAM) - return (powerdns_get_data_stream(item, ret_buffer, ret_buffer_size)); + return (powerdns_get_data_stream(item, ret_buffer)); else { ERROR("powerdns plugin: Unknown socket type: %i", (int)item->socktype); return (-1); @@ -575,19 +570,6 @@ static int powerdns_get_data(list_item_t *item, char **ret_buffer, static int powerdns_read_server(list_item_t *item) /* {{{ */ { - char *buffer = NULL; - size_t buffer_size = 0; - int status; - - char *dummy; - char *saveptr; - - char *key; - char *value; - - const char *const *fields; - int fields_num; - if (item->command == NULL) item->command = strdup(SERVER_COMMAND); if (item->command == NULL) { @@ -595,16 +577,21 @@ static int powerdns_read_server(list_item_t *item) /* {{{ */ return (-1); } - status = powerdns_get_data(item, &buffer, &buffer_size); - if (status != 0) - return (-1); + char *buffer = NULL; + int status = powerdns_get_data(item, &buffer); + if (status != 0) { + ERROR("powerdns plugin: powerdns_get_data failed."); + return (status); + } + if (buffer == NULL) { + return EINVAL; + } + const char *const *fields = default_server_fields; + int fields_num = default_server_fields_num; if (item->fields_num != 0) { fields = (const char *const *)item->fields; fields_num = item->fields_num; - } else { - fields = default_server_fields; - fields_num = default_server_fields_num; } assert(fields != NULL); @@ -612,12 +599,13 @@ static int powerdns_read_server(list_item_t *item) /* {{{ */ /* corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,latency=0,packetcache-hit=0,packetcache-miss=0,packetcache-size=0,qsize-q=0,query-cache-hit=0,query-cache-miss=0,recursing-answers=0,recursing-questions=0,servfail-packets=0,tcp-answers=0,tcp-queries=0,timedout-packets=0,udp-answers=0,udp-queries=0,udp4-answers=0,udp4-queries=0,udp6-answers=0,udp6-queries=0, */ - dummy = buffer; - saveptr = NULL; + char *dummy = buffer; + char *saveptr = NULL; + char *key; while ((key = strtok_r(dummy, ",", &saveptr)) != NULL) { dummy = NULL; - value = strchr(key, '='); + char *value = strchr(key, '='); if (value == NULL) break; @@ -691,7 +679,6 @@ static int powerdns_update_recursor_command(list_item_t *li) /* {{{ */ static int powerdns_read_recursor(list_item_t *item) /* {{{ */ { char *buffer = NULL; - size_t buffer_size = 0; int status; char *dummy; @@ -714,7 +701,7 @@ static int powerdns_read_recursor(list_item_t *item) /* {{{ */ } assert(item->command != NULL); - status = powerdns_get_data(item, &buffer, &buffer_size); + status = powerdns_get_data(item, &buffer); if (status != 0) { ERROR("powerdns plugin: powerdns_get_data failed."); return (-1); diff --git a/src/processes.c b/src/processes.c index 86f690f3..87c96c88 100644 --- a/src/processes.c +++ b/src/processes.c @@ -2127,7 +2127,6 @@ static int ps_read(void) { pse.cpu_user_counter = procentry[i].pi_ru.ru_utime.tv_sec * 1000000 + procentry[i].pi_ru.ru_utime.tv_usec / 1000; - pse.cpu_system = 0; /* tv_usec is nanosec ??? */ pse.cpu_system_counter = procentry[i].pi_ru.ru_stime.tv_sec * 1000000 + procentry[i].pi_ru.ru_stime.tv_usec / 1000; diff --git a/src/rrdtool.c b/src/rrdtool.c index e29d637d..4fcbad40 100644 --- a/src/rrdtool.c +++ b/src/rrdtool.c @@ -87,7 +87,7 @@ static rrdcreate_config_t rrdcreate_config = { * ALWAYS lock `cache_lock' first! */ static cdtime_t cache_timeout = 0; static cdtime_t cache_flush_timeout = 0; -static cdtime_t random_timeout = TIME_T_TO_CDTIME_T_STATIC(1); +static cdtime_t random_timeout = 0; static cdtime_t cache_flush_last; static c_avl_tree_t *cache = NULL; static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; @@ -505,7 +505,6 @@ static void rrd_cache_flush(cdtime_t timeout) { CDTIME_T_TO_DOUBLE(timeout)); now = cdtime(); - timeout = TIME_T_TO_CDTIME_T(timeout); /* Build a list of entries to be flushed */ iter = c_avl_get_iterator(cache); @@ -606,23 +605,10 @@ static int rrd_cache_flush_identifier(cdtime_t timeout, } /* int rrd_cache_flush_identifier */ static int64_t rrd_get_random_variation(void) { - long min; - long max; - if (random_timeout == 0) return (0); - /* Assure that "cache_timeout + random_variation" is never negative. */ - if (random_timeout > cache_timeout) { - INFO("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.", - CDTIME_T_TO_DOUBLE(cache_timeout)); - random_timeout = cache_timeout; - } - - max = (long)(random_timeout / 2); - min = max - ((long)random_timeout); - - return ((int64_t)cdrand_range(min, max)); + return (int64_t)cdrand_range(-random_timeout, random_timeout); } /* int64_t rrd_get_random_variation */ static int rrd_cache_insert(const char *filename, const char *value, @@ -641,9 +627,8 @@ static int rrd_cache_insert(const char *filename, const char *value, return (-1); } - c_avl_get(cache, filename, (void *)&rc); - - if (rc == NULL) { + int status = c_avl_get(cache, filename, (void *)&rc); + if ((status != 0) || (rc == NULL)) { rc = malloc(sizeof(*rc)); if (rc == NULL) { pthread_mutex_unlock(&cache_lock); @@ -740,7 +725,7 @@ static int rrd_cache_insert(const char *filename, const char *value, if ((cache_timeout > 0) && ((cdtime() - cache_flush_last) > cache_flush_timeout)) - rrd_cache_flush(cache_flush_timeout); + rrd_cache_flush(cache_timeout + random_timeout); pthread_mutex_unlock(&cache_lock); @@ -877,7 +862,7 @@ static int rrd_config(const char *key, const char *value) { } cache_timeout = DOUBLE_TO_CDTIME_T(tmp); } else if (strcasecmp("CacheFlush", key) == 0) { - int tmp = atoi(value); + double tmp = atof(value); if (tmp < 0) { fprintf(stderr, "rrdtool: `CacheFlush' must " "be greater than 0.\n"); @@ -885,7 +870,7 @@ static int rrd_config(const char *key, const char *value) { "be greater than 0.\n"); return (1); } - cache_flush_timeout = tmp; + cache_flush_timeout = DOUBLE_TO_CDTIME_T(tmp); } else if (strcasecmp("DataDir", key) == 0) { char *tmp; size_t len; @@ -1065,9 +1050,23 @@ static int rrd_init(void) { cache_flush_last = cdtime(); if (cache_timeout == 0) { + random_timeout = 0; cache_flush_timeout = 0; - } else if (cache_flush_timeout < cache_timeout) + } else if (cache_flush_timeout < cache_timeout) { + INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout " + "%.3f\". Adjusting \"CacheFlush\" to %.3f seconds.", + CDTIME_T_TO_DOUBLE(cache_flush_timeout), + CDTIME_T_TO_DOUBLE(cache_timeout), + CDTIME_T_TO_DOUBLE(cache_timeout * 10)); cache_flush_timeout = 10 * cache_timeout; + } + + /* Assure that "cache_timeout + random_variation" is never negative. */ + if (random_timeout > cache_timeout) { + INFO("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.", + CDTIME_T_TO_DOUBLE(cache_timeout)); + random_timeout = cache_timeout; + } pthread_mutex_unlock(&cache_lock); diff --git a/src/smart.c b/src/smart.c index 9395945b..3188d1c8 100644 --- a/src/smart.c +++ b/src/smart.c @@ -33,6 +33,10 @@ #include #include +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + static const char *config_keys[] = {"Disk", "IgnoreSelected", "IgnoreSleepMode", "UseSerial"}; @@ -238,7 +242,25 @@ static int smart_read(void) { return (0); } /* int smart_read */ +static int smart_init(void) { +#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_RAWIO) + if (check_capability(CAP_SYS_RAWIO) != 0) { + if (getuid() == 0) + WARNING("smart plugin: Running collectd as root, but the " + "CAP_SYS_RAWIO capability is missing. The plugin's read " + "function will probably fail. Is your init system dropping " + "capabilities?"); + else + WARNING("smart plugin: collectd doesn't have the CAP_SYS_RAWIO " + "capability. If you don't want to run collectd as root, try " + "running \"setcap cap_sys_rawio=ep\" on the collectd binary."); + } +#endif + return (0); +} /* int smart_init */ + void module_register(void) { plugin_register_config("smart", smart_config, config_keys, config_keys_num); + plugin_register_init("smart", smart_init); plugin_register_read("smart", smart_read); } /* void module_register */ diff --git a/src/snmp.c b/src/snmp.c index 3bfec47d..ffeface9 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -1357,12 +1357,17 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { if (oid_list_todo_num == 0) { /* The request is still empty - so we are finished */ DEBUG("snmp plugin: all variables have left their subtree"); + snmp_free_pdu(req); status = 0; break; } res = NULL; status = snmp_sess_synch_response(host->sess_handle, req, &res); + + /* snmp_sess_synch_response always frees our req PDU */ + req = NULL; + if ((status != STAT_SUCCESS) || (res == NULL)) { char *errstr = NULL; @@ -1376,8 +1381,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { snmp_free_pdu(res); res = NULL; - /* snmp_synch_response already freed our PDU */ - req = NULL; sfree(errstr); csnmp_host_close_session(host); @@ -1400,8 +1403,12 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { for (vb = res->variables, i = 0; (vb != NULL); vb = vb->next_variable, i++) { /* Calculate value index from todo list */ - while ((i < oid_list_len) && !oid_list_todo[i]) + while ((i < oid_list_len) && !oid_list_todo[i]) { i++; + } + if (i >= oid_list_len) { + break; + } /* An instance is configured and the res variable we process is the * instance value (last index) */ @@ -1492,10 +1499,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { snmp_free_pdu(res); res = NULL; - if (req != NULL) - snmp_free_pdu(req); - req = NULL; - if (status == 0) csnmp_dispatch_table(host, data, instance_list_head, value_list_head); diff --git a/src/table.c b/src/table.c index 3e8feada..eb18660c 100644 --- a/src/table.c +++ b/src/table.c @@ -77,6 +77,10 @@ static void tbl_result_setup(tbl_result_t *res) { } /* tbl_result_setup */ static void tbl_result_clear(tbl_result_t *res) { + if (res == NULL) { + return; + } + sfree(res->type); sfree(res->instance_prefix); @@ -101,10 +105,16 @@ static void tbl_setup(tbl_t *tbl, char *file) { } /* tbl_setup */ static void tbl_clear(tbl_t *tbl) { + if (tbl == NULL) { + return; + } + sfree(tbl->file); sfree(tbl->sep); sfree(tbl->instance); + /* (tbl->results == NULL) -> (tbl->results_num == 0) */ + assert((tbl->results != NULL) || (tbl->results_num == 0)); for (size_t i = 0; i < tbl->results_num; ++i) tbl_result_clear(tbl->results + i); sfree(tbl->results); @@ -166,16 +176,13 @@ static int tbl_config_append_array_i(char *name, size_t **var, size_t *len, } /* tbl_config_append_array_s */ static int tbl_config_result(tbl_t *tbl, oconfig_item_t *ci) { - tbl_result_t *res; - - int status = 0; - if (0 != ci->values_num) { log_err(" does not expect any arguments."); return 1; } - res = realloc(tbl->results, (tbl->results_num + 1) * sizeof(*tbl->results)); + tbl_result_t *res = + realloc(tbl->results, (tbl->results_num + 1) * sizeof(*tbl->results)); if (res == NULL) { char errbuf[1024]; log_err("realloc failed: %s.", sstrerror(errno, errbuf, sizeof(errbuf))); @@ -183,9 +190,8 @@ static int tbl_config_result(tbl_t *tbl, oconfig_item_t *ci) { } tbl->results = res; - ++tbl->results_num; - res = tbl->results + tbl->results_num - 1; + res = tbl->results + tbl->results_num; tbl_result_setup(res); for (int i = 0; i < ci->children_num; ++i) { @@ -206,39 +212,35 @@ static int tbl_config_result(tbl_t *tbl, oconfig_item_t *ci) { c->key); } + int status = 0; if (NULL == res->type) { - log_err("No \"Type\" option specified for " - "in table \"%s\".", + log_err("No \"Type\" option specified for in table \"%s\".", tbl->file); status = 1; } if (NULL == res->values) { - log_err("No \"ValuesFrom\" option specified for " - "in table \"%s\".", + log_err("No \"ValuesFrom\" option specified for in table \"%s\".", tbl->file); status = 1; } if (0 != status) { tbl_result_clear(res); - --tbl->results_num; return status; } + + tbl->results_num++; return 0; } /* tbl_config_result */ static int tbl_config_table(oconfig_item_t *ci) { - tbl_t *tbl; - - int status = 0; - if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) { log_err(" expects a single string argument."); return 1; } - tbl = realloc(tables, (tables_num + 1) * sizeof(*tables)); + tbl_t *tbl = realloc(tables, (tables_num + 1) * sizeof(*tables)); if (NULL == tbl) { char errbuf[1024]; log_err("realloc failed: %s.", sstrerror(errno, errbuf, sizeof(errbuf))); @@ -246,9 +248,8 @@ static int tbl_config_table(oconfig_item_t *ci) { } tables = tbl; - ++tables_num; - tbl = tables + tables_num - 1; + tbl = tables + tables_num; tbl_setup(tbl, ci->values[0].value.string); for (size_t i = 0; i < ((size_t)ci->children_num); ++i) { @@ -266,6 +267,7 @@ static int tbl_config_table(oconfig_item_t *ci) { c->key, tbl->file); } + int status = 0; if (NULL == tbl->sep) { log_err("Table \"%s\" does not specify any separator.", tbl->file); status = 1; @@ -279,13 +281,13 @@ static int tbl_config_table(oconfig_item_t *ci) { } if (NULL == tbl->results) { + assert(tbl->results_num == 0); log_err("Table \"%s\" does not specify any (valid) results.", tbl->file); status = 1; } if (0 != status) { tbl_clear(tbl); - --tables_num; return status; } @@ -300,6 +302,8 @@ static int tbl_config_table(oconfig_item_t *ci) { if (res->values[j] > tbl->max_colnum) tbl->max_colnum = res->values[j]; } + + tables_num++; return 0; } /* tbl_config_table */ diff --git a/src/target_set.c b/src/target_set.c index 5bf40fa3..e7a32885 100644 --- a/src/target_set.c +++ b/src/target_set.c @@ -183,9 +183,13 @@ static void ts_subst(char *dest, size_t size, const char *string, /* {{{ */ REPLACE_FIELD("%{type_instance}", vl->type_instance); if (vl->meta != NULL) { - char **meta_toc; - int meta_entries = meta_data_toc(vl->meta, &meta_toc); - for (int i = 0; i < meta_entries; i++) { + char **meta_toc = NULL; + int status = meta_data_toc(vl->meta, &meta_toc); + if (status <= 0) + return; + size_t meta_entries = (size_t)status; + + for (size_t i = 0; i < meta_entries; i++) { char meta_name[DATA_MAX_NAME_LEN]; char *value_str; const char *key = meta_toc[i]; @@ -339,7 +343,6 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ if (data->meta != NULL) { char temp[DATA_MAX_NAME_LEN * 2]; - int meta_entries; char **meta_toc; if ((new_meta = meta_data_create()) == NULL) { @@ -347,8 +350,15 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ return (-ENOMEM); } - meta_entries = meta_data_toc(data->meta, &meta_toc); - for (int i = 0; i < meta_entries; i++) { + int status = meta_data_toc(data->meta, &meta_toc); + if (status < 0) { + ERROR("Target `set': meta_data_toc failed with status %d.", status); + meta_data_destroy(new_meta); + return status; + } + size_t meta_entries = (size_t)status; + + for (size_t i = 0; i < meta_entries; i++) { const char *key = meta_toc[i]; char *string; int status; @@ -357,7 +367,8 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ if (status) { ERROR("Target `set': Unable to get replacement metadata value `%s'.", key); - strarray_free(meta_toc, (size_t)meta_entries); + strarray_free(meta_toc, meta_entries); + meta_data_destroy(new_meta); return (status); } @@ -372,12 +383,13 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ status = meta_data_add_string(new_meta, key, temp); if (status) { ERROR("Target `set': Unable to set metadata value `%s'.", key); - strarray_free(meta_toc, (size_t)meta_entries); + strarray_free(meta_toc, meta_entries); + meta_data_destroy(new_meta); return (status); } } - strarray_free(meta_toc, (size_t)meta_entries); + strarray_free(meta_toc, meta_entries); } #define SUBST_FIELD(f) \ diff --git a/src/tcpconns.c b/src/tcpconns.c index f949d34e..7036d08b 100644 --- a/src/tcpconns.c +++ b/src/tcpconns.c @@ -745,9 +745,15 @@ static int conn_read(void) { for (in_ptr = (struct xinpgen *)(((char *)in_orig) + in_orig->xig_len); in_ptr->xig_len > sizeof(struct xinpgen); in_ptr = (struct xinpgen *)(((char *)in_ptr) + in_ptr->xig_len)) { +#if __FreeBSD_version >= 1200026 + struct xtcpcb *tp = (struct xtcpcb *)in_ptr; + struct xinpcb *inp = &tp->xt_inp; + struct xsocket *so = &inp->xi_socket; +#else struct tcpcb *tp = &((struct xtcpcb *)in_ptr)->xt_tp; struct inpcb *inp = &((struct xtcpcb *)in_ptr)->xt_inp; struct xsocket *so = &((struct xtcpcb *)in_ptr)->xt_socket; +#endif /* Ignore non-TCP sockets */ if (so->xso_protocol != IPPROTO_TCP) diff --git a/src/turbostat.c b/src/turbostat.c index 62bd92b1..568fb1e6 100644 --- a/src/turbostat.c +++ b/src/turbostat.c @@ -41,7 +41,7 @@ #include "plugin.h" #include "utils_time.h" -#include +#include "msr-index.h" #include #ifdef HAVE_SYS_CAPABILITY_H #include @@ -567,9 +567,9 @@ static int submit_counters(struct thread_data *t, struct core_data *c, 1.0 / 1000000 * t->aperf / interval_float); if ((!aperf_mperf_unstable) || (!(t->aperf > t->tsc || t->mperf > t->tsc))) - turbostat_submit(name, "frequency", "busy", 1.0 * t->tsc / 1000000 * - t->aperf / t->mperf / - interval_float); + turbostat_submit(name, "frequency", "busy", + 1.0 * t->tsc / 1000000 * t->aperf / t->mperf / + interval_float); /* Sanity check (should stay stable) */ turbostat_submit(name, "gauge", "TSC", diff --git a/src/unixsock.c b/src/unixsock.c index f61360ef..a4245689 100644 --- a/src/unixsock.c +++ b/src/unixsock.c @@ -134,7 +134,13 @@ static int us_open_socket(void) { const char *grpname; struct group *g; struct group sg; - char grbuf[2048]; + + long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuf_size <= 0) + grbuf_size = sysconf(_SC_PAGESIZE); + if (grbuf_size <= 0) + grbuf_size = 4096; + char grbuf[grbuf_size]; grpname = (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME; g = NULL; @@ -143,7 +149,7 @@ static int us_open_socket(void) { if (status != 0) { char errbuf[1024]; WARNING("unixsock plugin: getgrnam_r (%s) failed: %s", grpname, - sstrerror(errno, errbuf, sizeof(errbuf))); + sstrerror(status, errbuf, sizeof(errbuf))); break; } if (g == NULL) { diff --git a/src/utils_cmd_getthreshold.c b/src/utils_cmd_getthreshold.c index 60363da5..926375d6 100644 --- a/src/utils_cmd_getthreshold.c +++ b/src/utils_cmd_getthreshold.c @@ -155,48 +155,31 @@ int handle_getthreshold(FILE *fh, char *buffer) { print_to_socket(fh, "%zu Threshold found\n", i); if (threshold.host[0] != 0) - print_to_socket(fh, "Host: %s\n", threshold.host) if ( - threshold.plugin[0] != - 0) print_to_socket(fh, "Plugin: %s\n", - threshold.plugin) if (threshold.plugin_instance[0] != - 0) - print_to_socket(fh, "Plugin Instance: %s\n", - threshold.plugin_instance) if (threshold.type[0] != 0) - print_to_socket(fh, "Type: %s\n", threshold.type) if ( - threshold.type_instance[0] != - 0) print_to_socket(fh, "Type Instance: %s\n", - threshold - .type_instance) if (threshold.data_source - [0] != 0) - print_to_socket( - fh, "Data Source: %s\n", - threshold.data_source) if (!isnan(threshold.warning_min)) - print_to_socket( - fh, "Warning Min: %g\n", - threshold - .warning_min) if (!isnan(threshold.warning_max)) - print_to_socket( - fh, "Warning Max: %g\n", - threshold - .warning_max) if (!isnan(threshold.failure_min)) - print_to_socket( - fh, "Failure Min: %g\n", - threshold - .failure_min) if (!isnan(threshold - .failure_max)) - print_to_socket( - fh, "Failure Max: %g\n", - threshold.failure_max) if (threshold - .hysteresis > - 0.0) - print_to_socket( - fh, "Hysteresis: %g\n", - threshold.hysteresis) if (threshold - .hits > 1) - print_to_socket(fh, "Hits: %i\n", - threshold.hits) - - return (0); + print_to_socket(fh, "Host: %s\n", threshold.host); + if (threshold.plugin[0] != 0) + print_to_socket(fh, "Plugin: %s\n", threshold.plugin); + if (threshold.plugin_instance[0] != 0) + print_to_socket(fh, "Plugin Instance: %s\n", threshold.plugin_instance); + if (threshold.type[0] != 0) + print_to_socket(fh, "Type: %s\n", threshold.type); + if (threshold.type_instance[0] != 0) + print_to_socket(fh, "Type Instance: %s\n", threshold.type_instance); + if (threshold.data_source[0] != 0) + print_to_socket(fh, "Data Source: %s\n", threshold.data_source); + if (!isnan(threshold.warning_min)) + print_to_socket(fh, "Warning Min: %g\n", threshold.warning_min); + if (!isnan(threshold.warning_max)) + print_to_socket(fh, "Warning Max: %g\n", threshold.warning_max); + if (!isnan(threshold.failure_min)) + print_to_socket(fh, "Failure Min: %g\n", threshold.failure_min); + if (!isnan(threshold.failure_max)) + print_to_socket(fh, "Failure Max: %g\n", threshold.failure_max); + if (threshold.hysteresis > 0.0) + print_to_socket(fh, "Hysteresis: %g\n", threshold.hysteresis); + if (threshold.hits > 1) + print_to_socket(fh, "Hits: %i\n", threshold.hits); + + return (0); } /* int handle_getthreshold */ /* vim: set sw=2 sts=2 ts=8 et : */ diff --git a/src/utils_cmd_putval.c b/src/utils_cmd_putval.c index 817f954b..f1fe6d76 100644 --- a/src/utils_cmd_putval.c +++ b/src/utils_cmd_putval.c @@ -138,14 +138,6 @@ cmd_status_t cmd_parse_putval(size_t argc, char **argv, type = NULL; type_instance = NULL; - vl.values_len = ds->ds_num; - vl.values = malloc(vl.values_len * sizeof(*vl.values)); - if (vl.values == NULL) { - cmd_error(CMD_ERROR, err, "malloc failed."); - sfree(identifier_copy); - return (CMD_ERROR); - } - ret_putval->raw_identifier = identifier_copy; if (ret_putval->raw_identifier == NULL) { cmd_error(CMD_ERROR, err, "malloc failed."); @@ -177,33 +169,46 @@ cmd_status_t cmd_parse_putval(size_t argc, char **argv, /* else: cmd_parse_option did not find an option; treat this as a * value list. */ + vl.values_len = ds->ds_num; + vl.values = calloc(vl.values_len, sizeof(*vl.values)); + if (vl.values == NULL) { + cmd_error(CMD_ERROR, err, "malloc failed."); + result = CMD_ERROR; + break; + } + status = parse_values(argv[i], &vl, ds); if (status != 0) { cmd_error(CMD_PARSE_ERROR, err, "Parsing the values string failed."); result = CMD_PARSE_ERROR; + vl.values_len = 0; + sfree(vl.values); break; } - tmp = (value_list_t *)realloc(ret_putval->vl, (ret_putval->vl_num + 1) * - sizeof(*ret_putval->vl)); + tmp = realloc(ret_putval->vl, + (ret_putval->vl_num + 1) * sizeof(*ret_putval->vl)); if (tmp == NULL) { cmd_error(CMD_ERROR, err, "realloc failed."); cmd_destroy_putval(ret_putval); result = CMD_ERROR; + vl.values_len = 0; + sfree(vl.values); break; } ret_putval->vl = tmp; ret_putval->vl_num++; memcpy(&ret_putval->vl[ret_putval->vl_num - 1], &vl, sizeof(vl)); + + /* pointer is now owned by ret_putval->vl[] */ + vl.values_len = 0; + vl.values = NULL; } /* while (*buffer != 0) */ /* Done parsing the options. */ - if (result != CMD_OK) { - if (ret_putval->vl_num == 0) - sfree(vl.values); + if (result != CMD_OK) cmd_destroy_putval(ret_putval); - } return (result); } /* cmd_status_t cmd_parse_putval */ @@ -215,8 +220,7 @@ void cmd_destroy_putval(cmd_putval_t *putval) { sfree(putval->raw_identifier); for (size_t i = 0; i < putval->vl_num; ++i) { - if (i == 0) /* values is shared between all entries */ - sfree(putval->vl[i].values); + sfree(putval->vl[i].values); meta_data_destroy(putval->vl[i].meta); putval->vl[i].meta = NULL; } diff --git a/src/utils_format_graphite.c b/src/utils_format_graphite.c index 4f509f4a..9c7d96f1 100644 --- a/src/utils_format_graphite.c +++ b/src/utils_format_graphite.c @@ -180,8 +180,13 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds, int buffer_pos = 0; gauge_t *rates = NULL; - if (flags & GRAPHITE_STORE_RATES) + if (flags & GRAPHITE_STORE_RATES) { rates = uc_get_rate(ds, vl); + if (rates == NULL) { + ERROR("format_graphite: error with uc_get_rate"); + return -1; + } + } for (size_t i = 0; i < ds->ds_num; i++) { char const *ds_name = NULL; diff --git a/src/utils_format_json.c b/src/utils_format_json.c index 0a95a86d..9fb8f395 100644 --- a/src/utils_format_json.c +++ b/src/utils_format_json.c @@ -500,6 +500,14 @@ static int json_add_string(yajl_gen g, char const *str) /* {{{ */ } \ } while (0) +#define CHECK_SUCCESS(cmd) \ + do { \ + yajl_gen_status s = (cmd); \ + if (s != yajl_gen_status_ok) { \ + return (int)s; \ + } \ + } while (0) + static int format_json_meta(yajl_gen g, notification_meta_t *meta) /* {{{ */ { if (meta == NULL) @@ -525,7 +533,7 @@ static int format_json_meta(yajl_gen g, notification_meta_t *meta) /* {{{ */ default: ERROR("format_json_meta: unknown meta data type %d (name \"%s\")", meta->type, meta->name); - yajl_gen_null(g); + CHECK_SUCCESS(yajl_gen_null(g)); } return format_json_meta(g, meta->next); @@ -544,14 +552,14 @@ static int format_time(yajl_gen g, cdtime_t t) /* {{{ */ static int format_alert(yajl_gen g, notification_t const *n) /* {{{ */ { - yajl_gen_array_open(g); - yajl_gen_map_open(g); /* BEGIN alert */ + CHECK_SUCCESS(yajl_gen_array_open(g)); /* BEGIN array */ + CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN alert */ /* * labels */ JSON_ADD(g, "labels"); - yajl_gen_map_open(g); /* BEGIN labels */ + CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN labels */ JSON_ADD(g, "alertname"); if (strncmp(n->plugin, n->type, strlen(n->plugin)) == 0) @@ -577,36 +585,40 @@ static int format_alert(yajl_gen g, notification_t const *n) /* {{{ */ } JSON_ADD(g, "severity"); - JSON_ADD(g, (n->severity == NOTIF_FAILURE) - ? "FAILURE" - : (n->severity == NOTIF_WARNING) - ? "WARNING" - : (n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN"); + JSON_ADD(g, + (n->severity == NOTIF_FAILURE) + ? "FAILURE" + : (n->severity == NOTIF_WARNING) + ? "WARNING" + : (n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN"); JSON_ADD(g, "service"); JSON_ADD(g, "collectd"); - yajl_gen_map_close(g); /* END labels */ + CHECK_SUCCESS(yajl_gen_map_close(g)); /* END labels */ /* * annotations */ JSON_ADD(g, "annotations"); - yajl_gen_map_open(g); /* BEGIN annotations */ + CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN annotations */ JSON_ADD(g, "summary"); JSON_ADD(g, n->message); - if (format_json_meta(g, n->meta) != 0) + if (format_json_meta(g, n->meta) != 0) { return -1; + } - yajl_gen_map_close(g); /* END annotations */ + CHECK_SUCCESS(yajl_gen_map_close(g)); /* END annotations */ JSON_ADD(g, "startsAt"); - format_time(g, n->time); + if (format_time(g, n->time) != 0) { + return -1; + } - yajl_gen_map_close(g); /* END alert */ - yajl_gen_array_close(g); + CHECK_SUCCESS(yajl_gen_map_close(g)); /* END alert */ + CHECK_SUCCESS(yajl_gen_array_close(g)); /* END array */ return 0; } /* }}} format_alert */ @@ -671,7 +683,11 @@ int format_json_notification(char *buffer, size_t buffer_size, /* {{{ */ } /* copy to output buffer */ - yajl_gen_get_buf(g, &out, &unused_out_len); + if (yajl_gen_get_buf(g, &out, &unused_out_len) != yajl_gen_status_ok) { + yajl_gen_clear(g); + yajl_gen_free(g); + return -1; + } sstrncpy(buffer, (void *)out, buffer_size); yajl_gen_clear(g); diff --git a/src/utils_match.c b/src/utils_match.c index 2e487b59..11b3f74f 100644 --- a/src/utils_match.c +++ b/src/utils_match.c @@ -34,6 +34,7 @@ #include #define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02 +#define UTILS_MATCH_FLAGS_REGEX 0x04 struct cu_match_s { regex_t regex; @@ -234,6 +235,7 @@ match_create_callback(const char *regex, const char *excluderegex, sfree(obj); return (NULL); } + obj->flags |= UTILS_MATCH_FLAGS_REGEX; if (excluderegex && strcmp(excluderegex, "") != 0) { status = regcomp(&obj->excluderegex, excluderegex, REG_EXTENDED); @@ -301,6 +303,10 @@ void match_destroy(cu_match_t *obj) { if (obj == NULL) return; + if (obj->flags & UTILS_MATCH_FLAGS_REGEX) + regfree(&obj->regex); + if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) + regfree(&obj->excluderegex); if ((obj->user_data != NULL) && (obj->free != NULL)) (*obj->free)(obj->user_data); diff --git a/src/write_graphite.c b/src/write_graphite.c index b85ab470..13adff50 100644 --- a/src/write_graphite.c +++ b/src/write_graphite.c @@ -312,6 +312,7 @@ static void wg_callback_free(void *data) { sfree(cb->prefix); sfree(cb->postfix); + pthread_mutex_unlock(&cb->send_lock); pthread_mutex_destroy(&cb->send_lock); sfree(cb); diff --git a/src/write_http.c b/src/write_http.c index c1b3f0b0..46889280 100644 --- a/src/write_http.c +++ b/src/write_http.c @@ -114,6 +114,7 @@ static int wh_post_nolock(wh_callback_t *cb, char const *data) /* {{{ */ { int status = 0; + curl_easy_setopt(cb->curl, CURLOPT_URL, cb->location); curl_easy_setopt(cb->curl, CURLOPT_POSTFIELDS, data); status = curl_easy_perform(cb->curl); @@ -163,7 +164,6 @@ static int wh_callback_init(wh_callback_t *cb) /* {{{ */ curl_easy_setopt(cb->curl, CURLOPT_HTTPHEADER, cb->headers); curl_easy_setopt(cb->curl, CURLOPT_ERRORBUFFER, cb->curl_errbuf); - curl_easy_setopt(cb->curl, CURLOPT_URL, cb->location); curl_easy_setopt(cb->curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(cb->curl, CURLOPT_MAXREDIRS, 50L); diff --git a/src/write_kafka.c b/src/write_kafka.c index 306d92cc..17a83e0e 100644 --- a/src/write_kafka.c +++ b/src/write_kafka.c @@ -77,6 +77,14 @@ static void kafka_log(const rd_kafka_t *rkt, int level, const char *fac, } #endif +static rd_kafka_resp_err_t kafka_error() { +#if RD_KAFKA_VERSION >= 0x000b00ff + return rd_kafka_last_error(); +#else + return rd_kafka_errno2err(errno); +#endif +} + static uint32_t kafka_hash(const char *keydata, size_t keylen) { uint32_t hash = 5381; for (; keylen > 0; keylen--) @@ -147,7 +155,7 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */ if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name, topic_conf)) == NULL) { ERROR("write_kafka plugin: cannot create topic : %s\n", - rd_kafka_err2str(rd_kafka_errno2err(errno))); + rd_kafka_err2str(kafka_error())); return errno; } diff --git a/src/write_prometheus.c b/src/write_prometheus.c index 991415ef..97f583f3 100644 --- a/src/write_prometheus.c +++ b/src/write_prometheus.c @@ -36,6 +36,10 @@ #include +#include +#include +#include + #ifndef PROMETHEUS_DEFAULT_STALENESS_DELTA #define PROMETHEUS_DEFAULT_STALENESS_DELTA TIME_T_TO_CDTIME_T_STATIC(300) #endif @@ -546,9 +550,14 @@ metric_family_delete_metric(Io__Prometheus__Client__MetricFamily *fam, ((fam->n_metric - 1) - i) * sizeof(fam->metric[i])); fam->n_metric--; + if (fam->n_metric == 0) { + sfree(fam->metric); + return 0; + } + Io__Prometheus__Client__Metric **tmp = realloc(fam->metric, fam->n_metric * sizeof(*fam->metric)); - if ((tmp != NULL) || (fam->n_metric == 0)) + if (tmp != NULL) fam->metric = tmp; return 0; @@ -694,8 +703,10 @@ metric_family_get(data_set_t const *ds, value_list_t const *vl, size_t ds_index, return fam; } - if (!allocate) + if (!allocate) { + sfree(name); return NULL; + } fam = metric_family_create(name, ds, vl, ds_index); if (fam == NULL) { @@ -720,6 +731,100 @@ metric_family_get(data_set_t const *ds, value_list_t const *vl, size_t ds_index, } /* }}} */ +static void prom_logger(__attribute__((unused)) void *arg, char const *fmt, + va_list ap) { + /* {{{ */ + char errbuf[1024]; + vsnprintf(errbuf, sizeof(errbuf), fmt, ap); + + ERROR("write_prometheus plugin: %s", errbuf); +} /* }}} prom_logger */ + +#if MHD_VERSION >= 0x00090000 +static int prom_open_socket(int addrfamily) { + /* {{{ */ + char service[NI_MAXSERV]; + snprintf(service, sizeof(service), "%hu", httpd_port); + + struct addrinfo *res; + int status = getaddrinfo(NULL, service, + &(struct addrinfo){ + .ai_flags = AI_PASSIVE | AI_ADDRCONFIG, + .ai_family = addrfamily, + .ai_socktype = SOCK_STREAM, + }, + &res); + if (status != 0) { + return -1; + } + + int fd = -1; + for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) { + fd = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC, 0); + if (fd == -1) + continue; + + if (bind(fd, ai->ai_addr, ai->ai_addrlen) != 0) { + close(fd); + fd = -1; + continue; + } + + if (listen(fd, /* backlog = */ 16) != 0) { + close(fd); + fd = -1; + continue; + } + + break; + } + + freeaddrinfo(res); + + return fd; +} /* }}} int prom_open_socket */ + +static struct MHD_Daemon *prom_start_daemon() { + /* {{{ */ + int fd = prom_open_socket(PF_INET6); + if (fd == -1) + fd = prom_open_socket(PF_INET); + if (fd == -1) { + ERROR("write_prometheus plugin: Opening a listening socket failed."); + return NULL; + } + + struct MHD_Daemon *d = MHD_start_daemon( + MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, httpd_port, + /* MHD_AcceptPolicyCallback = */ NULL, + /* MHD_AcceptPolicyCallback arg = */ NULL, http_handler, NULL, + MHD_OPTION_LISTEN_SOCKET, fd, MHD_OPTION_EXTERNAL_LOGGER, prom_logger, + NULL, MHD_OPTION_END); + if (d == NULL) { + ERROR("write_prometheus plugin: MHD_start_daemon() failed."); + close(fd); + return NULL; + } + + return d; +} /* }}} struct MHD_Daemon *prom_start_daemon */ +#else /* if MHD_VERSION < 0x00090000 */ +static struct MHD_Daemon *prom_start_daemon() { + /* {{{ */ + struct MHD_Daemon *d = MHD_start_daemon( + MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, httpd_port, + /* MHD_AcceptPolicyCallback = */ NULL, + /* MHD_AcceptPolicyCallback arg = */ NULL, http_handler, NULL, + MHD_OPTION_EXTERNAL_LOGGER, prom_logger, NULL, MHD_OPTION_END); + if (d == NULL) { + ERROR("write_prometheus plugin: MHD_start_daemon() failed."); + return NULL; + } + + return d; +} /* }}} struct MHD_Daemon *prom_start_daemon */ +#endif + /* * collectd callbacks */ @@ -753,15 +858,7 @@ static int prom_init() { } if (httpd == NULL) { - unsigned int flags = MHD_USE_THREAD_PER_CONNECTION; -#if MHD_VERSION >= 0x00093300 - flags |= MHD_USE_DUAL_STACK; -#endif - - httpd = MHD_start_daemon(flags, httpd_port, - /* MHD_AcceptPolicyCallback = */ NULL, - /* MHD_AcceptPolicyCallback arg = */ NULL, - http_handler, NULL, MHD_OPTION_END); + httpd = prom_start_daemon(); if (httpd == NULL) { ERROR("write_prometheus plugin: MHD_start_daemon() failed."); return -1; diff --git a/src/write_riemann.c b/src/write_riemann.c index 3835a3d5..00852ffb 100644 --- a/src/write_riemann.c +++ b/src/write_riemann.c @@ -601,6 +601,7 @@ static void wrr_free(void *p) /* {{{ */ wrr_disconnect(host); + pthread_mutex_lock(&host->lock); pthread_mutex_destroy(&host->lock); sfree(host); } /* }}} void wrr_free */ diff --git a/src/write_sensu.c b/src/write_sensu.c index 72ed6bc0..92f1743d 100644 --- a/src/write_sensu.c +++ b/src/write_sensu.c @@ -28,14 +28,15 @@ #include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "utils_cache.h" + #include #include #include #include #include -#include "common.h" -#include "plugin.h" -#include "utils_cache.h" #include #define SENSU_HOST "localhost" @@ -998,7 +999,10 @@ static void sensu_free(void *p) /* {{{ */ sfree(host->separator); free_str_list(&(host->metric_handlers)); free_str_list(&(host->notification_handlers)); + + pthread_mutex_unlock(&host->lock); pthread_mutex_destroy(&host->lock); + sfree(host); } /* }}} void sensu_free */ diff --git a/src/write_tsdb.c b/src/write_tsdb.c index 0c87c473..9cb3c97d 100644 --- a/src/write_tsdb.c +++ b/src/write_tsdb.c @@ -219,6 +219,7 @@ static void wt_callback_free(void *data) { sfree(cb->service); sfree(cb->host_tags); + pthread_mutex_unlock(&cb->send_lock); pthread_mutex_destroy(&cb->send_lock); sfree(cb); diff --git a/version-gen.sh b/version-gen.sh index 2083ec38..2c7a2e55 100755 --- a/version-gen.sh +++ b/version-gen.sh @@ -1,6 +1,6 @@ #!/bin/sh -DEFAULT_VERSION="5.7.0.git" +DEFAULT_VERSION="5.7.2.git" if [ -d .git ]; then VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"