From: Florian Forster Date: Fri, 29 Sep 2017 06:49:29 +0000 (+0200) Subject: Merge remote-tracking branch 'github/pr/1707' X-Git-Tag: collectd-5.8.0~66 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=9f77f493ef7cf6077deaa2385d2392d144cf606f;hp=7e7a5a6a0096f1919a80bb05371142990717c41e Merge remote-tracking branch 'github/pr/1707' --- diff --git a/AUTHORS b/AUTHORS index d866c700..b99c156a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -285,6 +285,11 @@ Scott Sanders Sebastien Pahl - AMQP plugin. +Serhiy Pshyk + - intel_pmu plugin + - intel_rdt plugin + - snmp_agent plugin + Simon Kuhnle - OpenBSD code for the cpu and memory plugins. diff --git a/Makefile.am b/Makefile.am index f9273990..04636b3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -89,9 +89,12 @@ nodist_pkgconfig_DATA = \ pkginclude_HEADERS = \ src/libcollectdclient/collectd/client.h \ - src/libcollectdclient/collectd/network.h \ + src/libcollectdclient/collectd/lcc_features.h \ src/libcollectdclient/collectd/network_buffer.h \ - src/libcollectdclient/collectd/lcc_features.h + src/libcollectdclient/collectd/network.h \ + src/libcollectdclient/collectd/network_parse.h \ + src/libcollectdclient/collectd/server.h \ + src/libcollectdclient/collectd/types.h lib_LTLIBRARIES = libcollectdclient.la @@ -137,7 +140,8 @@ check_PROGRAMS = \ test_utils_mount \ test_utils_subst \ test_utils_time \ - test_utils_vl_lookup + test_utils_vl_lookup \ + test_libcollectd_network_parse TESTS = $(check_PROGRAMS) @@ -246,8 +250,8 @@ collectdmon_SOURCES = src/collectdmon.c collectd_nagios_SOURCES = src/collectd-nagios.c collectd_nagios_CPPFLAGS = $(AM_CPPFLAGS) \ - -I$(srcdir)/src/libcollectdclient/collectd \ - -I$(top_builddir)/src/libcollectdclient/collectd + -I$(srcdir)/src/libcollectdclient \ + -I$(top_builddir)/src/libcollectdclient collectd_nagios_LDADD = libcollectdclient.la if BUILD_WITH_LIBSOCKET collectd_nagios_LDADD += -lsocket @@ -259,8 +263,8 @@ endif collectdctl_SOURCES = src/collectdctl.c collectdctl_CPPFLAGS = $(AM_CPPFLAGS) \ - -I$(srcdir)/src/libcollectdclient/collectd \ - -I$(top_builddir)/src/libcollectdclient/collectd + -I$(srcdir)/src/libcollectdclient \ + -I$(top_builddir)/src/libcollectdclient collectdctl_LDADD = libcollectdclient.la if BUILD_WITH_LIBSOCKET collectdctl_LDADD += -lsocket @@ -272,8 +276,8 @@ endif collectd_tg_SOURCES = src/collectd-tg.c collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) \ - -I$(srcdir)/src/libcollectdclient/collectd \ - -I$(top_builddir)/src/libcollectdclient/collectd + -I$(srcdir)/src/libcollectdclient \ + -I$(top_builddir)/src/libcollectdclient collectd_tg_LDADD = \ $(PTHREAD_LIBS) \ libheap.la \ @@ -475,20 +479,34 @@ endif libcollectdclient_la_SOURCES = \ src/libcollectdclient/client.c \ src/libcollectdclient/network.c \ - src/libcollectdclient/network_buffer.c + src/libcollectdclient/network_buffer.c \ + src/libcollectdclient/network_parse.c \ + src/libcollectdclient/server.c libcollectdclient_la_CPPFLAGS = \ $(AM_CPPFLAGS) \ - -I$(srcdir)/src/libcollectdclient/collectd \ - -I$(top_builddir)/src/libcollectdclient/collectd \ + -I$(srcdir)/src/libcollectdclient \ + -I$(top_builddir)/src/libcollectdclient \ -I$(srcdir)/src/daemon -libcollectdclient_la_LDFLAGS = -version-info 1:0:0 -libcollectdclient_la_LIBADD = +libcollectdclient_la_LDFLAGS = -version-info 2:0:1 +libcollectdclient_la_LIBADD = -lm if BUILD_WITH_LIBGCRYPT libcollectdclient_la_CPPFLAGS += $(GCRYPT_CPPFLAGS) libcollectdclient_la_LDFLAGS += $(GCRYPT_LDFLAGS) libcollectdclient_la_LIBADD += $(GCRYPT_LIBS) endif +# network_parse_test.c includes network_parse.c, so no need to link with +# libcollectdclient.so. +test_libcollectd_network_parse_SOURCES = src/libcollectdclient/network_parse_test.c +test_libcollectd_network_parse_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(srcdir)/src/libcollectdclient \ + -I$(top_builddir)/src/libcollectdclient +if BUILD_WITH_LIBGCRYPT +test_libcollectd_network_parse_CPPFLAGS += $(GCRYPT_CPPFLAGS) +test_libcollectd_network_parse_LDFLAGS = $(GCRYPT_LDFLAGS) +test_libcollectd_network_parse_LDADD = $(GCRYPT_LIBS) +endif liboconfig_la_SOURCES = \ src/liboconfig/oconfig.c \ @@ -783,16 +801,18 @@ if BUILD_PLUGIN_DPDKEVENTS pkglib_LTLIBRARIES += dpdkevents.la dpdkevents_la_SOURCES = src/dpdkevents.c src/utils_dpdk.c src/utils_dpdk.h dpdkevents_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS) +dpdkevents_la_CFLAGS = $(AM_CFLAGS) $(LIBDPDK_CFLAGS) dpdkevents_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS) -dpdkevents_la_LIBADD = -ldpdk +dpdkevents_la_LIBADD = $(LIBDPDK_LIBS) endif if BUILD_PLUGIN_DPDKSTAT pkglib_LTLIBRARIES += dpdkstat.la dpdkstat_la_SOURCES = src/dpdkstat.c src/utils_dpdk.c src/utils_dpdk.h 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 @@ -888,6 +908,14 @@ hugepages_la_SOURCES = src/hugepages.c hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif +if BUILD_PLUGIN_INTEL_PMU +pkglib_LTLIBRARIES += intel_pmu.la +intel_pmu_la_SOURCES = src/intel_pmu.c +intel_pmu_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBJEVENTS_CPPFLAGS) +intel_pmu_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBJEVENTS_LDFLAGS) +intel_pmu_la_LIBADD = $(BUILD_WITH_LIBJEVENTS_LIBS) +endif + if BUILD_PLUGIN_INTEL_RDT pkglib_LTLIBRARIES += intel_rdt.la intel_rdt_la_SOURCES = src/intel_rdt.c @@ -1526,6 +1554,12 @@ endif endif +if BUILD_PLUGIN_SYNPROXY +pkglib_LTLIBRARIES += synproxy.la +synproxy_la_SOURCES = src/synproxy.c +synproxy_la_LDFLAGS = $(PLUGIN_LDFLAGS) +endif + if BUILD_PLUGIN_SYSLOG pkglib_LTLIBRARIES += syslog.la syslog_la_SOURCES = src/syslog.c @@ -1646,7 +1680,9 @@ endif if BUILD_PLUGIN_TURBOSTAT pkglib_LTLIBRARIES += turbostat.la -turbostat_la_SOURCES = src/turbostat.c +turbostat_la_SOURCES = \ + src/turbostat.c \ + src/msr-index.h turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif diff --git a/README b/README index b0b59214..ca86c84d 100644 --- a/README +++ b/README @@ -140,6 +140,11 @@ Features hugepages can be found here: https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt. + - intel_pmu + The intel_pmu plugin reads performance counters provided by the Linux + kernel perf interface. The plugin uses jevents library to resolve named + events to perf events and access perf interface. + - intel_rdt The intel_rdt plugin collects information provided by monitoring features of Intel Resource Director Technology (Intel(R) RDT) like Cache Monitoring @@ -240,7 +245,7 @@ Features - netapp Plugin to query performance values from a NetApp storage system using the - “Manage ONTAP” SDK provided by NetApp. + “Manage ONTAP” SDK provided by NetApp. - netlink Very detailed Linux network interface and routing statistics. You can get @@ -253,8 +258,7 @@ Features plugin of choice for that. - nfs - NFS Procedures: Which NFS command were called how often. Only NFSv2 and - NFSv3 right now. + NFS Procedures: Which NFS command were called how often. - nginx Collects statistics from `nginx' (speak: engine X), a HTTP and mail @@ -786,6 +790,13 @@ Prerequisites For querying iptables counters. + * libjevents (optional) + The jevents library is used by the `intel_pmu' plugin to access the Linux + kernel perf interface. + Note: the library should be build with -fPIC flag to be linked with + intel_pmu shared object correctly. + + * libjvm (optional) Library that encapsulates the `Java Virtual Machine' (JVM). This library is used by the `java' plugin to execute Java bytecode. diff --git a/configure.ac b/configure.ac index 3357375e..55f78d8a 100644 --- a/configure.ac +++ b/configure.ac @@ -168,6 +168,7 @@ AC_CHECK_HEADERS_ONCE([ \ pthread_np.h \ pwd.h \ regex.h \ + sys/endian.h \ sys/fs_types.h \ sys/fstyp.h \ sys/ioctl.h \ @@ -520,32 +521,6 @@ if test "x$ac_system" = "xLinux"; then ]] ) # For the turbostat plugin - AC_CHECK_HEADERS([asm/msr-index.h], - [have_asm_msrindex_h="yes"], - [have_asm_msrindex_h="no"] - ) - - 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 - AC_CHECK_HEADERS([cpuid.h], [have_cpuid_h="yes"], [have_cpuid_h="no (cpuid.h not found)"] @@ -2349,7 +2324,9 @@ AC_SUBST(BUILD_WITH_LIBDBI_LIBS) # --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.])], @@ -2358,11 +2335,26 @@ AC_ARG_WITH([libdpdk], ) 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" @@ -2384,6 +2376,7 @@ if test "x$with_libdpdk" != "xno"; then [with_libdpdk="no (rte_config.h not found)"] ) CPPFLAGS="$SAVE_CPPFLAGS" + CFLAGS="$SAVE_CFLAGS" fi if test "x$with_libdpdk" = "xyes"; then @@ -4429,6 +4422,49 @@ AC_SUBST([BUILD_WITH_LIBPQOS_LDFLAGS]) AC_SUBST([BUILD_WITH_LIBPQOS_LIBS]) # }}} +# --with-libjevents {{{ +with_libjevents_cppflags="" +with_libjevents_ldflags="" +AC_ARG_WITH([libjevents], + [AS_HELP_STRING([--with-libjevents@<:@=PREFIX@:>@], [Path to libjevents.])], + [ + if test "x$withval" != "xno" && test "x$withval" != "xyes"; then + with_libjevents_cppflags="-I$withval/include" + with_libjevents_ldflags="-L$withval/lib" + with_libjevents="yes" + else + with_libjevents="$withval" + fi + ], + [with_libjevents="yes"] +) + +if test "x$with_libjevents" = "xyes"; then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libjevents_cppflags" + + AC_CHECK_HEADERS([jevents.h], [with_libjevents="yes"], [with_libjevents="no (jevents.h not found)"]) + + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libjevents" = "xyes"; then + SAVE_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $with_libjevents_ldflags" + + AC_CHECK_LIB([jevents], [json_events], [with_libjevents="yes"], [with_libjevents="no (Can't find libjevents)"]) + + LDFLAGS="$SAVE_LDFLAGS" +fi +if test "x$with_libjevents" = "xyes"; then + BUILD_WITH_LIBJEVENTS_CPPFLAGS="$with_libjevents_cppflags" + BUILD_WITH_LIBJEVENTS_LDFLAGS="$with_libjevents_ldflags" + BUILD_WITH_LIBJEVENTS_LIBS="-ljevents" +fi +AC_SUBST([BUILD_WITH_LIBJEVENTS_CPPFLAGS]) +AC_SUBST([BUILD_WITH_LIBJEVENTS_LDFLAGS]) +AC_SUBST([BUILD_WITH_LIBJEVENTS_LIBS]) +# }}} + # --with-libprotobuf {{{ with_libprotobuf_cppflags="" with_libprotobuf_ldflags="" @@ -5375,6 +5411,10 @@ if test "x$with_libupsclient" = "xyes"; then [AC_DEFINE([HAVE_UPSCLI_INIT], [1], [Define when upscli_init() (since version 2-7) is available.])] ) + AC_CHECK_LIB([upsclient], [upscli_tryconnect], + [AC_DEFINE([HAVE_UPSCLI_TRYCONNECT], [1], [Define when upscli_tryconnect() (since version 2.6.2) is available.])] + ) + LDFLAGS="$SAVE_LDFLAGS" fi @@ -6079,6 +6119,7 @@ plugin_fscache="no" plugin_gps="no" plugin_grpc="no" plugin_hugepages="no" +plugin_intel_pmu="no" plugin_intel_rdt="no" plugin_interface="no" plugin_ipc="no" @@ -6102,6 +6143,7 @@ plugin_python="no" plugin_serial="no" plugin_smart="no" plugin_swap="no" +plugin_synproxy="no" plugin_tape="no" plugin_tcpconns="no" plugin_ted="no" @@ -6146,6 +6188,7 @@ if test "x$ac_system" = "xLinux"; then plugin_protocols="yes" plugin_serial="yes" plugin_swap="yes" + plugin_synproxy="yes" plugin_tcpconns="yes" plugin_thermal="yes" plugin_uptime="yes" @@ -6158,7 +6201,7 @@ if test "x$ac_system" = "xLinux"; 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 @@ -6421,8 +6464,7 @@ if test "x$with_libxenctrl" = "xyes"; then plugin_xencpu="yes" fi -if test "x$with_libdpdk" = "xyes" -then +if test "x$with_libdpdk" = "xyes"; then plugin_dpdkevents="$dpdk_keepalive" plugin_dpdkstat="yes" fi @@ -6487,6 +6529,7 @@ AC_PLUGIN([gps], [$plugin_gps], [GPS plugin]) AC_PLUGIN([grpc], [$plugin_grpc], [gRPC plugin]) AC_PLUGIN([hddtemp], [yes], [Query hddtempd]) AC_PLUGIN([hugepages], [$plugin_hugepages], [Hugepages statistics]) +AC_PLUGIN([intel_pmu], [$with_libjevents], [Intel performance monitor plugin]) AC_PLUGIN([intel_rdt], [$with_libpqos], [Intel RDT monitor plugin]) AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics]) AC_PLUGIN([ipc], [$plugin_ipc], [IPC statistics]) @@ -6558,6 +6601,7 @@ AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugi AC_PLUGIN([snmp_agent], [$with_libnetsnmpagent], [SNMP agent plugin]) AC_PLUGIN([statsd], [yes], [StatsD plugin]) AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics]) +AC_PLUGIN([synproxy], [$plugin_synproxy], [Synproxy stats plugin]) AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin]) AC_PLUGIN([table], [yes], [Parsing of tabular data]) AC_PLUGIN([tail], [yes], [Parsing of logfiles]) @@ -6805,6 +6849,7 @@ AC_MSG_RESULT([ libhiredis . . . . . $with_libhiredis]) AC_MSG_RESULT([ libi2c-dev . . . . . $with_libi2c]) AC_MSG_RESULT([ libiokit . . . . . . $with_libiokit]) AC_MSG_RESULT([ libiptc . . . . . . . $with_libiptc]) +AC_MSG_RESULT([ libjevents . . . . . $with_libjevents]) AC_MSG_RESULT([ libjvm . . . . . . . $with_java]) AC_MSG_RESULT([ libkstat . . . . . . $with_kstat]) AC_MSG_RESULT([ libkvm . . . . . . . $with_libkvm]) @@ -6903,6 +6948,7 @@ AC_MSG_RESULT([ gps . . . . . . . . . $enable_gps]) AC_MSG_RESULT([ grpc . . . . . . . . $enable_grpc]) AC_MSG_RESULT([ hddtemp . . . . . . . $enable_hddtemp]) AC_MSG_RESULT([ hugepages . . . . . . $enable_hugepages]) +AC_MSG_RESULT([ intel_pmu . . . . . . $enable_intel_pmu]) AC_MSG_RESULT([ intel_rdt . . . . . . $enable_intel_rdt]) AC_MSG_RESULT([ interface . . . . . . $enable_interface]) AC_MSG_RESULT([ ipc . . . . . . . . . $enable_ipc]) @@ -6973,6 +7019,7 @@ AC_MSG_RESULT([ snmp . . . . . . . . $enable_snmp]) AC_MSG_RESULT([ snmp_agent . . . . . $enable_snmp_agent]) AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd]) AC_MSG_RESULT([ swap . . . . . . . . $enable_swap]) +AC_MSG_RESULT([ synproxy . . . . . . $enable_synproxy]) AC_MSG_RESULT([ syslog . . . . . . . $enable_syslog]) AC_MSG_RESULT([ table . . . . . . . . $enable_table]) AC_MSG_RESULT([ tail_csv . . . . . . $enable_tail_csv]) diff --git a/contrib/curl_json/php-fpm.conf b/contrib/curl_json/php-fpm.conf new file mode 100644 index 00000000..34b8b67d --- /dev/null +++ b/contrib/curl_json/php-fpm.conf @@ -0,0 +1,27 @@ +# Example configuration for PHP-FPM + + + Plugin "phpfpm" + Instance "main" + + Type "total_requests" + Instance "accepted" + + + Type "total_requests" + Instance "slow" + + + Type "queue_length" + Instance "listen" + + + Type "vs_processes" + Instance "active" + + + Type "vs_processes" + Instance "total" + + + diff --git a/contrib/redhat/collectd.spec b/contrib/redhat/collectd.spec index b36e2a27..23cac9a0 100644 --- a/contrib/redhat/collectd.spec +++ b/contrib/redhat/collectd.spec @@ -178,6 +178,8 @@ %define with_grpc 0%{!?_without_grpc:0} # plugin lpar disabled, requires AIX %define with_lpar 0%{!?_without_lpar:0} +# plugin intel_pmu disabled, requires libjevents +%define with_intel_pmu 0%{!?_without_intel_pmu:0} # plugin intel_rdt disabled, requires intel-cmt-cat %define with_intel_rdt 0%{!?_without_intel_rdt:0} # plugin mic disabled, requires Mic @@ -245,7 +247,7 @@ Summary: Statistics collection and monitoring daemon Name: collectd Version: 5.7.1 -Release: 6%{?dist} +Release: 7%{?dist} URL: https://collectd.org Source: https://collectd.org/files/%{name}-%{version}.tar.bz2 License: GPLv2 @@ -470,6 +472,16 @@ The HDDTemp plugin collects the temperature of hard disks. The temperatures are provided via SMART and queried by the external hddtemp daemon. %endif +%if %{with_intel_pmu} +%package intel_pmu +Summary: Intel PMU plugin for collectd +Group: System Environment/Daemons +Requires: %{name}%{?_isa} = %{version}-%{release} +%description intel_pmu +The intel_pmu plugin reads performance counters provided by the Linux +kernel perf interface. +%endif + %if %{with_intel_rdt} %package intel_rdt Summary: Intel RDT plugin for collectd @@ -509,8 +521,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. @@ -1236,6 +1248,12 @@ Collectd utilities %define _with_hugepages --disable-hugepages %endif +%if %{with_intel_pmu} +%define _with_intel_pmu --enable-intel_pmu +%else +%define _with_intel_pmu --disable-intel_pmu +%endif + %if %{with_intel_rdt} %define _with_intel_rdt --enable-intel_rdt %else @@ -1902,6 +1920,7 @@ Collectd utilities %{?_with_grpc} \ %{?_with_hddtemp} \ %{?_with_hugepages} \ + %{?_with_intel_pmu} \ %{?_with_intel_rdt} \ %{?_with_interface} \ %{?_with_ipc} \ @@ -2466,6 +2485,11 @@ fi %{_libdir}/%{name}/hddtemp.so %endif +%if %{with_intel_pmu} +%files intel_pmu +%{_libdir}/%{name}/intel_pmu.so +%endif + %if %{with_intel_rdt} %files intel_rdt %{_libdir}/%{name}/intel_rdt.so @@ -2699,6 +2723,9 @@ fi %doc contrib/ %changelog +* Fri Aug 18 2017 Ruben Kerkhof - 5.7.1-7 +- Add new intel_pmu plugin + * Sun Mar 05 2017 Ruben Kerkhof - 5.7.1-6 - Move recently added plugins to subpackages diff --git a/contrib/systemd.collectd.service b/contrib/systemd.collectd.service index 853363d7..9c037a4e 100644 --- a/contrib/systemd.collectd.service +++ b/contrib/systemd.collectd.service @@ -19,6 +19,7 @@ ProtectHome=true # dns CAP_NET_RAW # exec CAP_SETUID CAP_SETGID # intel_rdt CAP_SYS_RAWIO +# intel_pmu CAP_SYS_ADMIN # iptables CAP_NET_ADMIN # ping CAP_NET_RAW # smart CAP_SYS_RAWIO @@ -30,8 +31,6 @@ ProtectHome=true # By default, drop all capabilities: CapabilityBoundingSet= -NoNewPrivileges=true - # Tell systemd it will receive a notification from collectd over its control # socket once the daemon is ready. See systemd.service(5) for more details. Type=notify diff --git a/proto/types.proto b/proto/types.proto index 952c5418..fde3afaf 100644 --- a/proto/types.proto +++ b/proto/types.proto @@ -38,6 +38,16 @@ message Identifier { string type_instance = 5; } +message MetadataValue { + oneof value { + string string_value = 1; + int64 int64_value = 2; + uint64 uint64_value = 3; + double double_value = 4; + bool bool_value = 5; + }; +} + message Value { oneof value { uint64 counter = 1; @@ -56,4 +66,5 @@ message ValueList { Identifier identifier = 4; repeated string ds_names = 5; -} + map meta_data = 6; +} \ No newline at end of file diff --git a/src/aggregation.c b/src/aggregation.c index ffee1cd4..5fea279c 100644 --- a/src/aggregation.c +++ b/src/aggregation.c @@ -200,17 +200,15 @@ static int agg_instance_create_name(agg_instance_t *inst, /* {{{ */ sstrncpy(inst->ident.plugin_instance, AGG_FUNC_PLACEHOLDER, sizeof(inst->ident.plugin_instance)); else if (strcmp("", tmp_plugin) != 0) - ssnprintf(inst->ident.plugin_instance, - sizeof(inst->ident.plugin_instance), "%s-%s", tmp_plugin, - AGG_FUNC_PLACEHOLDER); + snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance), + "%s-%s", tmp_plugin, AGG_FUNC_PLACEHOLDER); else if (strcmp("", tmp_plugin_instance) != 0) - ssnprintf(inst->ident.plugin_instance, - sizeof(inst->ident.plugin_instance), "%s-%s", - tmp_plugin_instance, AGG_FUNC_PLACEHOLDER); + snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance), + "%s-%s", tmp_plugin_instance, AGG_FUNC_PLACEHOLDER); else - ssnprintf(inst->ident.plugin_instance, - sizeof(inst->ident.plugin_instance), "%s-%s-%s", tmp_plugin, - tmp_plugin_instance, AGG_FUNC_PLACEHOLDER); + snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance), + "%s-%s-%s", tmp_plugin, tmp_plugin_instance, + AGG_FUNC_PLACEHOLDER); } /* Type */ diff --git a/src/amqp.c b/src/amqp.c index 1adc6271..467b7ff4 100644 --- a/src/amqp.c +++ b/src/amqp.c @@ -217,23 +217,23 @@ static char *camqp_strerror(camqp_config_t *conf, /* {{{ */ if (r.reply.id == AMQP_CONNECTION_CLOSE_METHOD) { amqp_connection_close_t *m = r.reply.decoded; char *tmp = camqp_bytes_cstring(&m->reply_text); - ssnprintf(buffer, buffer_size, "Server connection error %d: %s", - m->reply_code, tmp); + snprintf(buffer, buffer_size, "Server connection error %d: %s", + m->reply_code, tmp); sfree(tmp); } else if (r.reply.id == AMQP_CHANNEL_CLOSE_METHOD) { amqp_channel_close_t *m = r.reply.decoded; char *tmp = camqp_bytes_cstring(&m->reply_text); - ssnprintf(buffer, buffer_size, "Server channel error %d: %s", - m->reply_code, tmp); + snprintf(buffer, buffer_size, "Server channel error %d: %s", + m->reply_code, tmp); sfree(tmp); } else { - ssnprintf(buffer, buffer_size, "Server error method %#" PRIx32, - r.reply.id); + snprintf(buffer, buffer_size, "Server error method %#" PRIx32, + r.reply.id); } break; default: - ssnprintf(buffer, buffer_size, "Unknown reply type %i", (int)r.reply_type); + snprintf(buffer, buffer_size, "Unknown reply type %i", (int)r.reply_type); } return buffer; @@ -758,9 +758,9 @@ static int camqp_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */ if (conf->routing_key != NULL) { sstrncpy(routing_key, conf->routing_key, sizeof(routing_key)); } else { - ssnprintf(routing_key, sizeof(routing_key), "collectd/%s/%s/%s/%s/%s", - vl->host, vl->plugin, vl->plugin_instance, vl->type, - vl->type_instance); + snprintf(routing_key, sizeof(routing_key), "collectd/%s/%s/%s/%s/%s", + vl->host, vl->plugin, vl->plugin_instance, vl->type, + vl->type_instance); /* Switch slashes (the only character forbidden by collectd) and dots * (the separation character used by AMQP). */ @@ -980,7 +980,7 @@ static int camqp_config_connection(oconfig_item_t *ci, /* {{{ */ if (publish) { char cbname[128]; - ssnprintf(cbname, sizeof(cbname), "amqp/%s", conf->name); + snprintf(cbname, sizeof(cbname), "amqp/%s", conf->name); status = plugin_register_write( cbname, camqp_write, &(user_data_t){ diff --git a/src/apache.c b/src/apache.c index 92c2c8be..07b2b57d 100644 --- a/src/apache.c +++ b/src/apache.c @@ -216,28 +216,25 @@ static int config_add(oconfig_item_t *ci) { status = -1; } - if (status == 0) { - char callback_name[3 * DATA_MAX_NAME_LEN]; - - ssnprintf(callback_name, sizeof(callback_name), "apache/%s/%s", - (st->host != NULL) ? st->host : hostname_g, - (st->name != NULL) ? st->name : "default"); - - status = plugin_register_complex_read( - /* group = */ NULL, - /* name = */ callback_name, - /* callback = */ apache_read_host, - /* interval = */ 0, &(user_data_t){ - .data = st, .free_func = apache_free, - }); - } - if (status != 0) { apache_free(st); return -1; } - return 0; + char callback_name[3 * DATA_MAX_NAME_LEN]; + + snprintf(callback_name, sizeof(callback_name), "apache/%s/%s", + (st->host != NULL) ? st->host : hostname_g, + (st->name != NULL) ? st->name : "default"); + + return plugin_register_complex_read( + /* group = */ NULL, + /* name = */ callback_name, + /* callback = */ apache_read_host, + /* interval = */ 0, + &(user_data_t){ + .data = st, .free_func = apache_free, + }); } /* int config_add */ static int config(oconfig_item_t *ci) { @@ -313,8 +310,8 @@ static int init_host(apache_t *st) /* {{{ */ static char credentials[1024]; int status; - status = ssnprintf(credentials, sizeof(credentials), "%s:%s", st->user, - (st->pass == NULL) ? "" : st->pass); + status = snprintf(credentials, sizeof(credentials), "%s:%s", st->user, + (st->pass == NULL) ? "" : st->pass); if ((status < 0) || ((size_t)status >= sizeof(credentials))) { ERROR("apache plugin: init_host: Returning an error " "because the credentials have been " diff --git a/src/ascent.c b/src/ascent.c index 40b15369..36694f61 100644 --- a/src/ascent.c +++ b/src/ascent.c @@ -499,8 +499,8 @@ static int ascent_init(void) /* {{{ */ static char credentials[1024]; int status; - status = ssnprintf(credentials, sizeof(credentials), "%s:%s", user, - (pass == NULL) ? "" : pass); + status = snprintf(credentials, sizeof(credentials), "%s:%s", user, + (pass == NULL) ? "" : pass); if ((status < 0) || ((size_t)status >= sizeof(credentials))) { ERROR("ascent plugin: ascent_init: Returning an error because the " "credentials have been truncated."); diff --git a/src/battery.c b/src/battery.c index 5a0b089f..b6dea0f3 100644 --- a/src/battery.c +++ b/src/battery.c @@ -347,8 +347,7 @@ static int sysfs_file_to_buffer(char const *dir, /* {{{ */ char filename[PATH_MAX]; int status; - ssnprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply, - basename); + snprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply, basename); status = (int)read_file_contents(filename, buffer, buffer_size - 1); if (status < 0) @@ -479,7 +478,7 @@ static int read_acpi_full_capacity(char const *dir, /* {{{ */ FILE *fh; - ssnprintf(filename, sizeof(filename), "%s/%s/info", dir, power_supply); + snprintf(filename, sizeof(filename), "%s/%s/info", dir, power_supply); fh = fopen(filename, "r"); if (fh == NULL) return errno; @@ -532,7 +531,7 @@ static int read_acpi_callback(char const *dir, /* {{{ */ FILE *fh; - ssnprintf(filename, sizeof(filename), "%s/%s/state", dir, power_supply); + snprintf(filename, sizeof(filename), "%s/%s/state", dir, power_supply); fh = fopen(filename, "r"); if (fh == NULL) { if ((errno == EAGAIN) || (errno == EINTR) || (errno == ENOENT)) @@ -641,11 +640,11 @@ static int read_pmu(void) /* {{{ */ gauge_t voltage = NAN; gauge_t charge = NAN; - ssnprintf(filename, sizeof(filename), PROC_PMU_PATH_FORMAT, i); + snprintf(filename, sizeof(filename), PROC_PMU_PATH_FORMAT, i); if (access(filename, R_OK) != 0) break; - ssnprintf(plugin_instance, sizeof(plugin_instance), "%i", i); + snprintf(plugin_instance, sizeof(plugin_instance), "%i", i); fh = fopen(filename, "r"); if (fh == NULL) { diff --git a/src/bind.c b/src/bind.c index 824d0447..990e2ca7 100644 --- a/src/bind.c +++ b/src/bind.c @@ -737,8 +737,8 @@ static int bind_xml_stats_handle_zone(int version, xmlDoc *doc, /* {{{ */ nsstats_translation_table_length, plugin_instance}; - ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-zone-%s", - view->name, zone_name); + snprintf(plugin_instance, sizeof(plugin_instance), "%s-zone-%s", view->name, + zone_name); if (version == 3) { list_info_ptr_t list_info = {plugin_instance, @@ -868,8 +868,7 @@ static int bind_xml_stats_handle_view(int version, xmlDoc *doc, /* {{{ */ list_info_ptr_t list_info = {plugin_instance, /* type = */ "dns_qtype"}; - ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-qtypes", - view->name); + snprintf(plugin_instance, sizeof(plugin_instance), "%s-qtypes", view->name); if (version == 3) { bind_parse_generic_name_attr_value_list( /* xpath = */ "counters[@type='resqtype']", @@ -891,8 +890,8 @@ static int bind_xml_stats_handle_view(int version, xmlDoc *doc, /* {{{ */ resstats_translation_table_length, plugin_instance}; - ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-resolver_stats", - view->name); + snprintf(plugin_instance, sizeof(plugin_instance), "%s-resolver_stats", + view->name); if (version == 3) { bind_parse_generic_name_attr_value_list( "counters[@type='resstats']", @@ -914,8 +913,8 @@ static int bind_xml_stats_handle_view(int version, xmlDoc *doc, /* {{{ */ list_info_ptr_t list_info = {plugin_instance, /* type = */ "dns_qtype_cached"}; - ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-cache_rr_sets", - view->name); + snprintf(plugin_instance, sizeof(plugin_instance), "%s-cache_rr_sets", + view->name); bind_parse_generic_name_value(/* xpath = */ "cache/rrset", /* callback = */ bind_xml_list_callback, diff --git a/src/cgroups.c b/src/cgroups.c index 9cb7cf95..18e489d0 100644 --- a/src/cgroups.c +++ b/src/cgroups.c @@ -63,7 +63,7 @@ static int read_cpuacct_procs(const char *dirname, char const *cgroup_name, if (ignorelist_match(il_cgroup, cgroup_name)) return 0; - ssnprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, cgroup_name); + snprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, cgroup_name); status = lstat(abs_path, &statbuf); if (status != 0) { @@ -75,8 +75,8 @@ static int read_cpuacct_procs(const char *dirname, char const *cgroup_name, if (!S_ISDIR(statbuf.st_mode)) return 0; - ssnprintf(abs_path, sizeof(abs_path), "%s/%s/cpuacct.stat", dirname, - cgroup_name); + snprintf(abs_path, sizeof(abs_path), "%s/%s/cpuacct.stat", dirname, + cgroup_name); fh = fopen(abs_path, "r"); if (fh == NULL) { char errbuf[1024]; @@ -138,7 +138,7 @@ static int read_cpuacct_root(const char *dirname, const char *filename, struct stat statbuf; int status; - ssnprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename); + snprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename); status = lstat(abs_path, &statbuf); if (status != 0) { diff --git a/src/collectd-nagios.c b/src/collectd-nagios.c index 4c54dad4..89f73b83 100644 --- a/src/collectd-nagios.c +++ b/src/collectd-nagios.c @@ -71,7 +71,7 @@ #endif #endif /* NAN_ZERO_ZERO */ -#include "libcollectdclient/collectd/client.h" +#include "collectd/client.h" #define RET_OKAY 0 #define RET_WARNING 1 diff --git a/src/collectd-tg.c b/src/collectd-tg.c index d8b2ea19..48f2dc43 100644 --- a/src/collectd-tg.c +++ b/src/collectd-tg.c @@ -44,8 +44,8 @@ #include "utils_heap.h" -#include "libcollectdclient/collectd/client.h" -#include "libcollectdclient/collectd/network.h" +#include "collectd/client.h" +#include "collectd/network.h" #define DEF_NUM_HOSTS 1000 #define DEF_NUM_PLUGINS 20 diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 6b677d26..7b685aac 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -129,6 +129,7 @@ #@BUILD_PLUGIN_GRPC_TRUE@LoadPlugin grpc #@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp #@BUILD_PLUGIN_HUGEPAGES_TRUE@LoadPlugin hugepages +#@BUILD_PLUGIN_INTEL_PMU_TRUE@LoadPlugin intel_pmu #@BUILD_PLUGIN_INTEL_RDT_TRUE@LoadPlugin intel_rdt @BUILD_PLUGIN_INTERFACE_TRUE@@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface #@BUILD_PLUGIN_IPC_TRUE@LoadPlugin ipc @@ -363,6 +364,9 @@ # ReportByCpu true # ReportByState true # ValuesPercentage false +# ReportNumCpu false +# ReportGuestState false +# SubtractGuestState true # # # @@ -588,12 +592,16 @@ # # +# #Plugin "foo" # Instance "foodir" # Name "*.conf" # MTime "-5m" # Size "+10k" # Recursive true # IncludeHidden false +# #FilesSizeType "bytes" +# #FilesCountType "files" +# #TypeInstance "instance" # # @@ -646,6 +654,14 @@ # ValuesPercentage false # +# +# ReportHardwareCacheEvents true +# ReportKernelPMUEvents true +# ReportSoftwareEvents true +# EventList "/var/cache/pmu/GenuineIntel-6-2D-core.json" +# HardwareEvents "L2_RQSTS.CODE_RD_HIT,L2_RQSTS.CODE_RD_MISS" "L2_RQSTS.ALL_CODE_RD" +# + # # Cores "0-2" # @@ -720,8 +736,11 @@ # # -# McelogClientSocket "/var/run/mcelog-client" -# McelogLogfile "/var/log/mcelog" +# +# McelogClientSocket "/var/run/mcelog-client" +# PersistentNotification false +# +# McelogLogfile "/var/log/mcelog" # # @@ -803,6 +822,11 @@ # QoS 2 # Topic "collectd/#" # CleanSession true +# CACert "/etc/ssl/ca.crt" +# CertificateFile "/etc/ssl/client.crt" +# CertificateKeyFile "/etc/ssl/client.pem" +# TLSProtocol "tlsv1.2" +# CipherSuite "ciphers" # # @@ -929,6 +953,12 @@ # CacheFlush 1800 @LOAD_PLUGIN_NETWORK@ +# +# ReportV2 false +# #ReportV3 false +# #ReportV4 false +# + # # URL "http://localhost/status?auto" # User "www-user" @@ -970,6 +1000,7 @@ # ForceSSL true # VerifyPeer true # CAPath "/path/to/folder" +# #ConnectTimeout 5000 # # @@ -1323,10 +1354,12 @@ # ReportBytes true # ValuesAbsolute true # ValuesPercentage false +# ReportIO true # # # +# #Plugin "table" # Instance "slabinfo" # Separator " " # @@ -1378,6 +1411,7 @@ # Bucket 0.5 1.0 # -> bucket-latency-foo-0.5_1 # Bucket 1.0 2.0 # -> bucket-latency-foo-1_2 # Bucket 2.0 0 # -> bucket-latency-foo-2_inf +# #BucketType "bucket" # # Type "latency" # Instance "foo" @@ -1457,7 +1491,7 @@ # SystemManagementInterrupt true # DigitalTemperatureSensor true # PackageThermalManagement true -# RunningAveragePowerLimit "7" +# RunningAveragePowerLimit "7" # # @@ -1507,7 +1541,7 @@ # CollectPurge false # Varnish 2 only # CollectSession false # CollectSHM true -# CollectSMA false # Varnish 2 only +# CollectSMA false # Varnish 2 & 4 only # CollectSMS false # CollectSM false # Varnish 2 only # CollectStruct false @@ -1516,6 +1550,11 @@ # CollectVCL false # CollectVSM false # Varnish 4 only # CollectWorkers false +# CollectLock false # Varnish 4 only +# CollectMempool false # Varnish 4 only +# CollectManagement false # Varnish 4 only +# CollectSMF false # Varnish 4 only +# CollectVBE false # Varnish 4 only # # diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index cf34e9ed..c30256fc 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -1474,6 +1474,19 @@ in the un-aggregated (per-CPU, per-state) mode as well. When set to B, reports the number of available CPUs. Defaults to B. +=item B B|B + +When set to B, reports the "guest" and "guest_nice" CPU states. +Defaults to B. + +=item B B|B + +This option is only considered when B is set to B. +"guest" and "guest_nice" are included in respectively "user" and "nice". +If set to B, "guest" will be subtracted from "user" and "guest_nice" +will be subtracted from "nice". +Defaults to B. + =back =head2 Plugin C @@ -1611,6 +1624,7 @@ finance page and dispatch the value to collectd. + Plugin "quotes" URL "http://finance.google.com/finance?q=NYSE%3AAMD" User "foo" Password "bar" @@ -1642,6 +1656,11 @@ The following options are valid within B blocks: =over 4 +=item B I + +Use I as the plugin name when submitting values. +Defaults to C. + =item B I URL of the web site to retrieve. Since a regular expression will be used to @@ -1802,6 +1821,11 @@ The following options are valid within B blocks: Use I as the host name when submitting values. Defaults to the global host name setting. +=item B I + +Use I as the plugin name when submitting values. +Defaults to C. + =item B I Sets the plugin instance to I. @@ -2736,12 +2760,16 @@ blocks, the following options are recognized: =over 4 +=item B I + +Use I as the plugin name when submitting values. +Defaults to B. + =item B I -Sets the plugin instance to I. That instance name must be unique, but -it's your responsibility, the plugin doesn't check for that. If not given, the -instance is set to the directory name with all slashes replaced by underscores -and all leading underscores removed. +Sets the plugin instance to I. If not given, the instance is set to +the directory name with all slashes replaced by underscores and all leading +underscores removed. Empty value is allowed. =item B I @@ -2787,6 +2815,21 @@ Controls whether or not to include "hidden" files and directories in the count. "Hidden" files and directories are those, whose name begins with a dot. Defaults to I, i.e. by default hidden files and directories are ignored. +=item B I + +Sets the type used to dispatch files combined size. Empty value ("") disables +reporting. Defaults to B. + +=item B I + +Sets the type used to dispatch number of files. Empty value ("") disables +reporting. Defaults to B. + +=item B I + +Sets the I used to dispatch values. Defaults to an empty string +(no plugin instance). + =back =head2 Plugin C @@ -3079,6 +3122,92 @@ Defaults to B. =back +=head2 Plugin C + +The I plugin collects performance counters data on Intel CPUs using +Linux perf interface. All events are reported on a per core basis. + +B + + + ReportHardwareCacheEvents true + ReportKernelPMUEvents true + ReportSoftwareEvents true + EventList "/var/cache/pmu/GenuineIntel-6-2D-core.json" + HardwareEvents "L2_RQSTS.CODE_RD_HIT,L2_RQSTS.CODE_RD_MISS" "L2_RQSTS.ALL_CODE_RD" + + +B + +=over 4 + +=item B B|B + +Enable or disable measuring of hardware CPU cache events: + - L1-dcache-loads + - L1-dcache-load-misses + - L1-dcache-stores + - L1-dcache-store-misses + - L1-dcache-prefetches + - L1-dcache-prefetch-misses + - L1-icache-loads + - L1-icache-load-misses + - L1-icache-prefetches + - L1-icache-prefetch-misses + - LLC-loads + - LLC-load-misses + - LLC-stores + - LLC-store-misses + - LLC-prefetches + - LLC-prefetch-misses + - dTLB-loads + - dTLB-load-misses + - dTLB-stores + - dTLB-store-misses + - dTLB-prefetches + - dTLB-prefetch-misses + - iTLB-loads + - iTLB-load-misses + - branch-loads + - branch-load-misses + +=item B B|B + +Enable or disable measuring of the following events: + - cpu-cycles + - instructions + - cache-references + - cache-misses + - branches + - branch-misses + - bus-cycles + +=item B B|B + +Enable or disable measuring of software events provided by kernel: + - cpu-clock + - task-clock + - context-switches + - cpu-migrations + - page-faults + - minor-faults + - major-faults + - alignment-faults + - emulation-faults + +=item B I + +JSON performance counter event list file name. To be able to monitor all Intel +CPU specific events JSON event list file should be downloaded. Use the pmu-tools +event_download.py script to download event list for current CPU. + +=item B I + +This field is a list of event names or groups of comma separated event names. +This option requires B option to be configured. + +=back + =head2 Plugin C The I plugin collects information provided by monitoring features of @@ -3484,17 +3613,36 @@ By default the plugin connects to B<"/var/run/mcelog-client"> to check if the mcelog server is running. When the server is running, the plugin will tail the specified logfile to retrieve machine check exception information and send a notification with the details from the logfile. The plugin will use the mcelog -client protocol to retrieve memory related machine check exceptions. +client protocol to retrieve memory related machine check exceptions. Note that +for memory exceptions, notifications are only sent when there is a change in +the number of corrected/uncorrected memory errors. -=over 4 +=head3 The Memory block + +Note: these options cannot be used in conjunction with the logfile options, they are mutually +exclusive. + +=over 3 =item B I Connect to the mcelog client socket using the UNIX domain socket at I. Defaults to B<"/var/run/mcelog-client">. +=item B B|B +Override default configuration to only send notifications when sent when there +is a change in the number of corrected/uncorrected memory errors. When set to +true notifications will be sent for every read cycle. Default is false. Does +not affect the stats being dispatched. + +=back + +=over 4 + =item B I -The mcelog file to parse. Defaults to B<"/var/log/mcelog">. +The mcelog file to parse. Defaults to B<"/var/log/mcelog">. Note: this option +cannot be used in conjunction with the memory block options, they are mutually +exclusive. =back @@ -3542,6 +3690,7 @@ Synopsis of the configuration: Server "localhost" Key "page_key" + Plugin "plugin_name" Regex "(\\d+) bytes sent" DSType CounterAdd @@ -3569,6 +3718,11 @@ B block. When connected to the memcached server, asks for the page I. +=item B I + +Use I as the plugin name when submitting values. +Defaults to C. + =item EBE Match blocks define which strings to look for and how matches substrings are @@ -4074,18 +4228,18 @@ the B branch. Path to the PEM-encoded CA certificate file. Setting this option enables TLS communication with the MQTT broker, and as such, B should be the TLS-enabled port of the MQTT broker. -A valid TLS configuration requires B, B and B. +This option enables the use of TLS. =item B I Path to the PEM-encoded certificate file to use as client certificate when connecting to the MQTT broker. -A valid TLS configuration requires B, B and B. +Only valid if B and B are also set. =item B I Path to the unencrypted PEM-encoded key file corresponding to B. -A valid TLS configuration requires B, B and B. +Only valid if B and B are also set. =item B I @@ -4093,13 +4247,14 @@ If configured, this specifies the string protocol version (e.g. C, C) to use for the TLS connection to the broker. If not set a default version is used which depends on the version of OpenSSL the Mosquitto library was linked against. +Only valid if B is set. =item B I A string describing the ciphers available for use. See L and the C utility for more information. If unset, the default ciphers will be used. - +Only valid if B is set. =back @@ -4229,11 +4384,11 @@ If enabled, the plugin sends a notification if the replication slave I/O and / or SQL threads are not running. Defaults to B. =item B I - + Enable the collection of wsrep plugin statistics, used in Master-Master replication setups like in MySQL Galera/Percona XtraDB Cluster. User needs only privileges to execute 'SHOW GLOBAL STATUS' - + =item B I Sets the connect timeout for the MySQL client. @@ -5067,6 +5222,25 @@ statistics available. Defaults to B. =back +=head2 Plugin C + +The I collects information about the usage of the Network File +System (NFS). It counts the number of procedure calls for each procedure, +grouped by version and whether the system runs as server or client. + +It is possibly to omit metrics for a specific NFS version by setting one or +more of the following options to B (all of them default to B). + +=over 4 + +=item B B|B + +=item B B|B + +=item B B|B + +=back + =head2 Plugin C This plugin collects the number of connections and requests handled by the @@ -5297,6 +5471,11 @@ generate links like the one described above for ALL certs in a given folder. Example usage: C +=item B I + +The B option sets the connect timeout, in milliseconds. +By default, the configured B is used to set the timeout. + =back =head2 Plugin C @@ -5532,15 +5711,12 @@ The OpenVPN plugin reads a status file maintained by OpenVPN and gathers traffic statistics about connected clients. To set up OpenVPN to write to the status file periodically, use the -B<--status> option of OpenVPN. Since OpenVPN can write two different formats, -you need to set the required format, too. This is done by setting -B<--status-version> to B<2>. +B<--status> option of OpenVPN. So, in a nutshell you need: openvpn $OTHER_OPTIONS \ - --status "/var/run/openvpn-status" 10 \ - --status-version 2 + --status "/var/run/openvpn-status" 10 Available options: @@ -5678,7 +5854,7 @@ The address of the OVS DB server JSON-RPC interface used by the plugin. To enable the interface, OVS DB daemon should be running with C<--remote=ptcp:> option. See L for more details. The option may be either network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string -format. Defaults to B<'localhost'>. +format. Defaults to C. =item B I @@ -5744,7 +5920,7 @@ The address of the OVS DB server JSON-RPC interface used by the plugin. To enable the interface, OVS DB daemon should be running with C<--remote=ptcp:> option. See L for more details. The option may be either network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string -format. Defaults to B<'localhost'>. +format. Defaults to C. =item B I @@ -6970,14 +7146,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 @@ -7207,6 +7389,7 @@ B Plugin "memory" + #PluginInstance "some" Type "memory" TypeInstance "free" OIDs "1.3.6.1.4.1.2021.4.6.0" @@ -7250,6 +7433,12 @@ scalar data type B has no effect and can be omitted. Read plugin name whose collected data will be mapped to specified OIDs. +=item B I + +Read plugin instance whose collected data will be mapped to specified OIDs. +The field is optional and by default there is no plugin instance check. +Allowed only if B block defines scalar data type. + =item B I Collectd's type that is to be used for specified OID, e.Eg. "if_octets" @@ -7262,9 +7451,9 @@ Collectd's type-instance that is to be used for specified OID. =item B I [I ...] Configures the OIDs to be handled by I plugin. Values for these OIDs -are taken from collectd data type specified by B, B, -B fields of this B block. Number of the OIDs configured -should correspond to number of values in specified B. +are taken from collectd data type specified by B, B, +B, B fields of this B block. Number of the OIDs +configured should correspond to number of values in specified B. For example two OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" can be mapped to "rx" and "tx" values of "if_octets" type. @@ -7403,6 +7592,13 @@ available and free. Defaults to B. This is useful for deploying I in a heterogeneous environment, where swap sizes differ and you want to specify generic thresholds or similar. +=item B B|B + +Enables or disables reporting swap IO. Defaults to B. + +This is useful for the cases when swap IO is not neccessary, is not available, +or is not reliable. + =back =head2 Plugin C @@ -7438,6 +7634,7 @@ filesystem or CSV (comma separated values) files.
+ #Plugin "slab" Instance "slabinfo" Separator " " @@ -7464,10 +7661,14 @@ The following options are available inside a B
block: =over 4 +=item B I + +If specified, I is used as the plugin name when submitting values. +Defaults to B
. + =item B I -If specified, I is used as the plugin instance. So, in the above -example, the plugin name C would be used. If omitted, the +If specified, I is used as the plugin instance. If omitted, the filename of the table is used instead, with all special characters replaced with an underscore (C<_>). @@ -7537,6 +7738,7 @@ user using (extended) regular expressions, as described in L. + Plugin "mail" Instance "exim" Interval 60 @@ -7557,6 +7759,7 @@ user using (extended) regular expressions, as described in L. Percentile 99 Bucket 0 100 + #BucketType "bucket" Type "latency" Instance "foo" @@ -7568,11 +7771,13 @@ The config consists of one or more B blocks, each of which configures one logfile to parse. Within each B block, there are one or more B blocks, which configure a regular expression to search for. -The B option in the B block may be used to set the plugin -instance. So in the above example the plugin name C would be used. -This plugin instance is for all B blocks that B it, until the -next B option. This way you can extract several plugin instances from -one logfile, handy when parsing syslog and the like. +The B and B options in the B block may be used to set +the plugin name and instance respectively. So in the above example the plugin name +C would be used. + +These options are applied for all B blocks that B it, until the +next B or B option. This way you can extract several plugin +instances from one logfile, handy when parsing syslog and the like. The B option allows you to define the length of time between reads. If this is not set, the default Interval will be used. @@ -7676,6 +7881,7 @@ B Percentile 99 Bucket 0 100 + BucketType "bucket" =over 4 @@ -7712,11 +7918,17 @@ the following schema: Bucket 20 50 Bucket 50 0 -Metrics are reported with the I C and the I +Metrics are reported with the I set by B option (C +by default) and the I CTypeE[-EInstanceE]-Elower_boundE_Eupper_boundE>. This option may be repeated to calculate more than one rate. +=item B I + +Sets the type used to dispatch B metrics. +Optional, by default C will be used. + =back =back @@ -7753,7 +7965,8 @@ B Index 1 - Instance "snort-eth0" + Plugin "snortstats" + Instance "eth0" Interval 600 Collect "snort-dropped" @@ -7805,6 +8018,11 @@ I block but there can be multiple if you have multiple CSV files. =over 4 +=item B I + +Use I as the plugin name when submitting values. +Defaults to C. + =item B I Sets the I used when dispatching the values. @@ -8068,9 +8286,9 @@ collections. The different bits of this bit mask accepted by this plugin are: Boolean enabling the use of logical core numbering for per core statistics. When enabled, CnE> is used as plugin instance, where I is a -sequential number assigned by the kernel. Otherwise, CnE> is used -where I is the n-th core of the socket, causing name conflicts when there is -more than one socket. +dynamic number assigned by the kernel. Otherwise, CnE> is used +if there is only one package and CnE-coreEmE> if there is +more than one, where I is the n-th core of package I. =back @@ -8176,6 +8394,11 @@ Synopsis: CollectVCL false CollectVSM false CollectWorkers false + CollectLock false + CollectMempool false + CollectManagement false + CollectSMF false + CollectVBE false @@ -8251,7 +8474,10 @@ log messages which is flushed to disk when full. True by default. =item B B|B malloc or umem (umem_alloc(3MALLOC) based) storage statistics. The umem storage -component is Solaris specific. Only available with Varnish 2.x. False by +component is Solaris specific. +Note: SMA and SMF share counters, enable only the one used by the Varnish +instance. +Only available with Varnish 2.x. False by default. =item B B|B @@ -8261,7 +8487,8 @@ component is used internally only. False by default. =item B B|B -file (memory mapped file) storage statistics. Only available with Varnish 2.x. +file (memory mapped file) storage statistics. Only available with Varnish 2.x., +in varnish 4.x. use CollectSMF. False by default. =item B B|B @@ -8292,6 +8519,29 @@ statistics subsystems). Only available with Varnish 4.x. False by default. Collect statistics about worker threads. False by default. +=item B B|B + +Backend counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +file (memory mapped file) storage statistics. Only available with Varnish 4.x. +Note: SMA and SMF share counters, enable only the one used by the Varnish +instance. +Used to be called SM in Varnish 2.x. False by default. + +=item B B|B + +Management process counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +Lock counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +Memory pool counters. Only available with Varnish 4.x. False by default. + =back =head2 Plugin C @@ -8356,7 +8606,7 @@ will be collected. =item B B|B If I is set to B, the default, then the device name -seen by the guest will be used for reporting metrics. +seen by the guest will be used for reporting metrics. This corresponds to the CtargetE> node in the XML definition of the domain. @@ -9117,6 +9367,7 @@ Synopsis: Prefix "collectd/" Database 1 MaxSetSize -1 + MaxSetDuration -1 StoreRates true @@ -9179,6 +9430,12 @@ to C<0>. The B option limits the number of items that the I can hold. Negative values for I sets no limit, which is the default behavior. +=item B I + +The B option limits the duration of items that the +I can hold. Negative values for I sets no duration, which +is the default behavior. + =item B B|B If set to B (the default), convert counter values to rates. If set to diff --git a/src/collectd.pod b/src/collectd.pod index 8e68fc01..1dd899b8 100644 --- a/src/collectd.pod +++ b/src/collectd.pod @@ -40,11 +40,17 @@ the read callbacks once. A return code not equal to zero indicates an error. =item B<-P> Ipid-fileE> -Specify an alternative pid file. This overwrites any settings in the config +Specify an alternative pid file. This overwrites any settings in the config file. This is thought for init-scripts that require the PID-file in a certain directory to work correctly. For everyday-usage use the B config-option. +=item B<-B> + +If set, collectd will I try to create its base directory. If the base +directory does not exist, it will exit rather than trying to create the +directory. + =item B<-f> Don't fork to the background. I will also B close standard file diff --git a/src/collectdctl.c b/src/collectdctl.c index 4b0db2a7..54c8081e 100644 --- a/src/collectdctl.c +++ b/src/collectdctl.c @@ -65,7 +65,7 @@ #endif #endif /* NAN_ZERO_ZERO */ -#include "libcollectdclient/collectd/client.h" +#include "collectd/client.h" #ifndef PREFIX #define PREFIX "/opt/" PACKAGE_NAME diff --git a/src/cpu.c b/src/cpu.c index a5a136ec..d48ab886 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -98,9 +98,11 @@ #define COLLECTD_CPU_STATE_INTERRUPT 5 #define COLLECTD_CPU_STATE_SOFTIRQ 6 #define COLLECTD_CPU_STATE_STEAL 7 -#define COLLECTD_CPU_STATE_IDLE 8 -#define COLLECTD_CPU_STATE_ACTIVE 9 /* sum of (!idle) */ -#define COLLECTD_CPU_STATE_MAX 10 /* #states */ +#define COLLECTD_CPU_STATE_GUEST 8 +#define COLLECTD_CPU_STATE_GUEST_NICE 9 +#define COLLECTD_CPU_STATE_IDLE 10 +#define COLLECTD_CPU_STATE_ACTIVE 11 /* sum of (!idle) */ +#define COLLECTD_CPU_STATE_MAX 12 /* #states */ #if HAVE_STATGRAB_H #include @@ -119,7 +121,7 @@ static const char *cpu_state_names[] = {"user", "system", "wait", "nice", "swap", "interrupt", "softirq", "steal", - "idle", "active"}; + "guest", "guest_nice", "idle", "active"}; #ifdef PROCESSOR_CPU_LOAD_INFO static mach_port_t port_host; @@ -193,9 +195,12 @@ static _Bool report_by_cpu = 1; static _Bool report_by_state = 1; static _Bool report_percent = 0; static _Bool report_num_cpu = 0; +static _Bool report_guest = 0; +static _Bool subtract_guest = 1; static const char *config_keys[] = {"ReportByCpu", "ReportByState", - "ReportNumCpu", "ValuesPercentage"}; + "ReportNumCpu", "ValuesPercentage", + "ReportGuestState", "SubtractGuestState"}; static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); static int cpu_config(char const *key, char const *value) /* {{{ */ @@ -208,6 +213,10 @@ static int cpu_config(char const *key, char const *value) /* {{{ */ report_by_state = IS_TRUE(value) ? 1 : 0; else if (strcasecmp(key, "ReportNumCpu") == 0) report_num_cpu = IS_TRUE(value) ? 1 : 0; + else if (strcasecmp(key, "ReportGuestState") == 0) + report_guest = IS_TRUE(value) ? 1 : 0; + else if (strcasecmp(key, "SubtractGuestState") == 0) + subtract_guest = IS_TRUE(value) ? 1 : 0; else return -1; @@ -326,7 +335,7 @@ static void submit_value(int cpu_num, int cpu_state, const char *type, sizeof(vl.type_instance)); if (cpu_num >= 0) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", cpu_num); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", cpu_num); } plugin_dispatch_values(&vl); } @@ -524,7 +533,7 @@ static void cpu_commit_without_aggregation(void) /* {{{ */ static void cpu_commit(void) /* {{{ */ { gauge_t global_rates[COLLECTD_CPU_STATE_MAX] = { - NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */ + NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */ }; if (report_num_cpu) @@ -545,7 +554,8 @@ static void cpu_commit(void) /* {{{ */ for (size_t cpu_num = 0; cpu_num < global_cpu_num; cpu_num++) { cpu_state_t *this_cpu_states = get_cpu_state(cpu_num, 0); gauge_t local_rates[COLLECTD_CPU_STATE_MAX] = {NAN, NAN, NAN, NAN, NAN, - NAN, NAN, NAN, NAN, NAN}; + NAN, NAN, NAN, NAN, NAN, + NAN, NAN }; for (size_t state = 0; state < COLLECTD_CPU_STATE_MAX; state++) if (this_cpu_states[state].has_value) @@ -632,7 +642,7 @@ static int cpu_read(void) { FILE *fh; char buf[1024]; - char *fields[9]; + char *fields[11]; int numfields; if ((fh = fopen("/proc/stat", "r")) == NULL) { @@ -648,14 +658,15 @@ static int cpu_read(void) { if ((buf[3] < '0') || (buf[3] > '9')) continue; - numfields = strsplit(buf, fields, 9); + numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE(fields)); if (numfields < 5) continue; cpu = atoi(fields[0] + 3); - cpu_stage(cpu, COLLECTD_CPU_STATE_USER, (derive_t)atoll(fields[1]), now); - cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)atoll(fields[2]), now); + /* Do not stage User and Nice immediately: we may need to alter them later: */ + long long user_value = atoll(fields[1]); + long long nice_value = atoll(fields[2]); cpu_stage(cpu, COLLECTD_CPU_STATE_SYSTEM, (derive_t)atoll(fields[3]), now); cpu_stage(cpu, COLLECTD_CPU_STATE_IDLE, (derive_t)atoll(fields[4]), now); @@ -665,11 +676,40 @@ static int cpu_read(void) { now); cpu_stage(cpu, COLLECTD_CPU_STATE_SOFTIRQ, (derive_t)atoll(fields[7]), now); + } - if (numfields >= 9) - cpu_stage(cpu, COLLECTD_CPU_STATE_STEAL, (derive_t)atoll(fields[8]), - now); + if (numfields >= 9) { /* Steal (since Linux 2.6.11) */ + cpu_stage(cpu, COLLECTD_CPU_STATE_STEAL, (derive_t)atoll(fields[8]), now); } + + if (numfields >= 10) { /* Guest (since Linux 2.6.24) */ + if (report_guest) { + long long value = atoll(fields[9]); + cpu_stage(cpu, COLLECTD_CPU_STATE_GUEST, (derive_t)value, now); + /* Guest is included in User; optionally subtract Guest from User: */ + if (subtract_guest) { + user_value -= value; + if (user_value < 0) user_value = 0; + } + } + } + + if (numfields >= 11) { /* Guest_nice (since Linux 2.6.33) */ + if (report_guest) { + long long value = atoll(fields[10]); + cpu_stage(cpu, COLLECTD_CPU_STATE_GUEST_NICE, (derive_t)value, now); + /* Guest_nice is included in Nice; optionally subtract Guest_nice from + Nice: */ + if (subtract_guest) { + nice_value -= value; + if (nice_value < 0) nice_value = 0; + } + } + } + + /* Eventually stage User and Nice: */ + cpu_stage(cpu, COLLECTD_CPU_STATE_USER, (derive_t)user_value, now); + cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)nice_value, now); } fclose(fh); /* }}} #endif defined(KERNEL_LINUX) */ diff --git a/src/cpufreq.c b/src/cpufreq.c index 608e60e3..0139947e 100644 --- a/src/cpufreq.c +++ b/src/cpufreq.c @@ -34,10 +34,10 @@ static int cpufreq_init(void) { num_cpu = 0; while (1) { - status = ssnprintf(filename, sizeof(filename), - "/sys/devices/system/cpu/cpu%d/cpufreq/" - "scaling_cur_freq", - num_cpu); + status = snprintf(filename, sizeof(filename), + "/sys/devices/system/cpu/cpu%d/cpufreq/" + "scaling_cur_freq", + num_cpu); if ((status < 1) || ((unsigned int)status >= sizeof(filename))) break; @@ -62,7 +62,7 @@ static void cpufreq_submit(int cpu_num, value_t value) { vl.values_len = 1; sstrncpy(vl.plugin, "cpufreq", sizeof(vl.plugin)); sstrncpy(vl.type, "cpufreq", sizeof(vl.type)); - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%i", cpu_num); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%i", cpu_num); plugin_dispatch_values(&vl); } @@ -70,8 +70,8 @@ static void cpufreq_submit(int cpu_num, value_t value) { static int cpufreq_read(void) { for (int i = 0; i < num_cpu; i++) { char filename[PATH_MAX]; - ssnprintf(filename, sizeof(filename), - "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i); + snprintf(filename, sizeof(filename), + "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i); value_t v; if (parse_value_file(filename, &v, DS_TYPE_GAUGE) != 0) { diff --git a/src/csv.c b/src/csv.c index e4c84f7f..debe0953 100644 --- a/src/csv.c +++ b/src/csv.c @@ -47,7 +47,7 @@ static int value_list_to_string(char *buffer, int buffer_len, memset(buffer, '\0', buffer_len); - status = ssnprintf(buffer, buffer_len, "%.3f", CDTIME_T_TO_DOUBLE(vl->time)); + status = snprintf(buffer, buffer_len, "%.3f", CDTIME_T_TO_DOUBLE(vl->time)); if ((status < 1) || (status >= buffer_len)) return -1; offset = status; @@ -62,8 +62,8 @@ static int value_list_to_string(char *buffer, int buffer_len, } if (ds->ds[i].type == DS_TYPE_GAUGE) { - status = ssnprintf(buffer + offset, buffer_len - offset, ",%lf", - vl->values[i].gauge); + status = snprintf(buffer + offset, buffer_len - offset, ",%lf", + vl->values[i].gauge); } else if (store_rates != 0) { if (rates == NULL) rates = uc_get_rate(ds, vl); @@ -72,17 +72,16 @@ static int value_list_to_string(char *buffer, int buffer_len, "uc_get_rate failed."); return -1; } - status = - ssnprintf(buffer + offset, buffer_len - offset, ",%lf", rates[i]); + status = snprintf(buffer + offset, buffer_len - offset, ",%lf", rates[i]); } else if (ds->ds[i].type == DS_TYPE_COUNTER) { - status = ssnprintf(buffer + offset, buffer_len - offset, ",%llu", - vl->values[i].counter); + status = snprintf(buffer + offset, buffer_len - offset, ",%llu", + vl->values[i].counter); } else if (ds->ds[i].type == DS_TYPE_DERIVE) { - status = ssnprintf(buffer + offset, buffer_len - offset, ",%" PRIi64, - vl->values[i].derive); + status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIi64, + vl->values[i].derive); } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) { - status = ssnprintf(buffer + offset, buffer_len - offset, ",%" PRIu64, - vl->values[i].absolute); + status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIu64, + vl->values[i].absolute); } if ((status < 1) || (status >= (buffer_len - offset))) { diff --git a/src/curl.c b/src/curl.c index cde383d3..35ec1f83 100644 --- a/src/curl.c +++ b/src/curl.c @@ -53,6 +53,7 @@ struct web_page_s; typedef struct web_page_s web_page_t; struct web_page_s /* {{{ */ { + char *plugin_name; char *instance; char *url; @@ -146,6 +147,7 @@ static void cc_web_page_free(web_page_t *wp) /* {{{ */ curl_easy_cleanup(wp->curl); wp->curl = NULL; + sfree(wp->plugin_name); sfree(wp->instance); sfree(wp->url); @@ -368,8 +370,8 @@ static int cc_page_init_curl(web_page_t *wp) /* {{{ */ return -1; } - ssnprintf(wp->credentials, credentials_size, "%s:%s", wp->user, - (wp->pass == NULL) ? "" : wp->pass); + snprintf(wp->credentials, credentials_size, "%s:%s", wp->user, + (wp->pass == NULL) ? "" : wp->pass); curl_easy_setopt(wp->curl, CURLOPT_USERPWD, wp->credentials); #endif @@ -412,6 +414,7 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */ ERROR("curl plugin: calloc failed."); return -1; } + page->plugin_name = NULL; page->url = NULL; page->user = NULL; page->pass = NULL; @@ -435,7 +438,9 @@ static int cc_config_add_page(oconfig_item_t *ci) /* {{{ */ for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; - if (strcasecmp("URL", child->key) == 0) + if (strcasecmp("Plugin", child->key) == 0) + status = cf_util_get_string(child, &page->plugin_name); + else if (strcasecmp("URL", child->key) == 0) status = cf_util_get_string(child, &page->url); else if (strcasecmp("User", child->key) == 0) status = cf_util_get_string(child, &page->user); @@ -566,7 +571,8 @@ static void cc_submit(const web_page_t *wp, const web_match_t *wm, /* {{{ */ vl.values = &value; vl.values_len = 1; - sstrncpy(vl.plugin, "curl", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl", + sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, wm->type, sizeof(vl.type)); if (wm->instance != NULL) @@ -581,7 +587,8 @@ static void cc_submit_response_code(const web_page_t *wp, long code) /* {{{ */ vl.values = &(value_t){.gauge = (gauge_t)code}; vl.values_len = 1; - sstrncpy(vl.plugin, "curl", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl", + sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, "response_code", sizeof(vl.type)); @@ -594,7 +601,8 @@ static void cc_submit_response_time(const web_page_t *wp, /* {{{ */ vl.values = &(value_t){.gauge = response_time}; vl.values_len = 1; - sstrncpy(vl.plugin, "curl", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl", + sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, "response_time", sizeof(vl.type)); @@ -623,7 +631,7 @@ static int cc_read_page(web_page_t *wp) /* {{{ */ if (wp->response_time) cc_submit_response_time(wp, CDTIME_T_TO_DOUBLE(cdtime() - start)); if (wp->stats != NULL) - curl_stats_dispatch(wp->stats, wp->curl, hostname_g, "curl", wp->instance); + curl_stats_dispatch(wp->stats, wp->curl, NULL, "curl", wp->instance); if (wp->response_code) { long response_code = 0; diff --git a/src/curl_json.c b/src/curl_json.c index cc5600f3..756f24f3 100644 --- a/src/curl_json.c +++ b/src/curl_json.c @@ -82,6 +82,7 @@ typedef struct { struct cj_s /* {{{ */ { char *instance; + char *plugin_name; char *host; char *sock; @@ -217,7 +218,7 @@ static void cj_advance_array(cj_t *db) { db->state[db->depth].index++; char name[DATA_MAX_NAME_LEN]; - ssnprintf(name, sizeof(name), "%d", db->state[db->depth].index); + snprintf(name, sizeof(name), "%d", db->state[db->depth].index); cj_load_key(db, name); } @@ -396,6 +397,7 @@ static void cj_free(void *arg) /* {{{ */ db->tree = NULL; sfree(db->instance); + sfree(db->plugin_name); sfree(db->host); sfree(db->sock); @@ -599,8 +601,8 @@ static int cj_init_curl(cj_t *db) /* {{{ */ return -1; } - ssnprintf(db->credentials, credentials_size, "%s:%s", db->user, - (db->pass == NULL) ? "" : db->pass); + snprintf(db->credentials, credentials_size, "%s:%s", db->user, + (db->pass == NULL) ? "" : db->pass); curl_easy_setopt(db->curl, CURLOPT_USERPWD, db->credentials); #endif @@ -672,6 +674,8 @@ static int cj_config_add_url(oconfig_item_t *ci) /* {{{ */ if (strcasecmp("Instance", child->key) == 0) status = cf_util_get_string(child, &db->instance); + else if (strcasecmp("Plugin", child->key) == 0) + status = cf_util_get_string(child, &db->plugin_name); else if (strcasecmp("Host", child->key) == 0) status = cf_util_get_string(child, &db->host); else if (db->url && strcasecmp("User", child->key) == 0) @@ -799,13 +803,14 @@ static void cj_submit_impl(cj_t *db, cj_key_t *key, value_t *value) /* {{{ */ if (key->instance == NULL) { int len = 0; for (int i = 0; i < db->depth; i++) - len += ssnprintf(vl.type_instance + len, sizeof(vl.type_instance) - len, - i ? "-%s" : "%s", db->state[i + 1].name); + len += snprintf(vl.type_instance + len, sizeof(vl.type_instance) - len, + i ? "-%s" : "%s", db->state[i + 1].name); } else sstrncpy(vl.type_instance, key->instance, sizeof(vl.type_instance)); sstrncpy(vl.host, cj_host(db), sizeof(vl.host)); - sstrncpy(vl.plugin, "curl_json", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (db->plugin_name != NULL) ? db->plugin_name : "curl_json", + sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, key->type, sizeof(vl.type)); diff --git a/src/curl_xml.c b/src/curl_xml.c index 43561a83..e83de73e 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -369,7 +369,7 @@ static int cx_handle_all_value_xpaths(xmlXPathContextPtr xpath_ctx, /* {{{ */ status = cx_handle_single_value_xpath(xpath_ctx, xpath, ds, vl, i); if (status != 0) return -1; /* An error has been printed. */ - } /* for (i = 0; i < xpath->values_len; i++) */ + } /* for (i = 0; i < xpath->values_len; i++) */ plugin_dispatch_values(vl); vl->values = NULL; @@ -441,8 +441,8 @@ static int cx_handle_instance_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */ if (xpath->instance_prefix != NULL) { if (instance_node != NULL) { char *node_value = (char *)xmlNodeGetContent(instance_node->nodeTab[0]); - ssnprintf(vl->type_instance, sizeof(vl->type_instance), "%s%s", - xpath->instance_prefix, node_value); + snprintf(vl->type_instance, sizeof(vl->type_instance), "%s%s", + xpath->instance_prefix, node_value); sfree(node_value); } else sstrncpy(vl->type_instance, xpath->instance_prefix, @@ -840,8 +840,8 @@ static int cx_init_curl(cx_t *db) /* {{{ */ return -1; } - ssnprintf(db->credentials, credentials_size, "%s:%s", db->user, - (db->pass == NULL) ? "" : db->pass); + snprintf(db->credentials, credentials_size, "%s:%s", db->user, + (db->pass == NULL) ? "" : db->pass); curl_easy_setopt(db->curl, CURLOPT_USERPWD, db->credentials); #endif diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index 2edfa377..af8fb568 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -158,7 +158,7 @@ static int init_global_variables(void) { return 0; } /* int init_global_variables */ -static int change_basedir(const char *orig_dir) { +static int change_basedir(const char *orig_dir, _Bool create) { char *dir; size_t dirlen; int status; @@ -183,7 +183,7 @@ static int change_basedir(const char *orig_dir) { if (status == 0) { free(dir); return 0; - } else if (errno != ENOENT) { + } else if (!create || (errno != ENOENT)) { char errbuf[1024]; ERROR("change_basedir: chdir (%s): %s", dir, sstrerror(errno, errbuf, sizeof(errbuf))); @@ -250,6 +250,7 @@ __attribute__((noreturn)) static void exit_usage(int status) { #if COLLECT_DAEMON " -f Don't fork to the background.\n" #endif + " -B Don't create the BaseDir\n" " -h Display help (this message)\n" "\nBuiltin defaults:\n" " Config file " CONFIGFILE "\n" @@ -459,6 +460,7 @@ int main(int argc, char **argv) { int test_config = 0; int test_readall = 0; const char *basedir; + _Bool opt_create_basedir = 1; #if COLLECT_DAEMON pid_t pid; int daemonize = 1; @@ -469,7 +471,7 @@ int main(int argc, char **argv) { while (1) { int c; - c = getopt(argc, argv, "htTC:" + c = getopt(argc, argv, "BhtTC:" #if COLLECT_DAEMON "fP:" #endif @@ -479,6 +481,9 @@ int main(int argc, char **argv) { break; switch (c) { + case 'B': + opt_create_basedir = 0; + break; case 'C': configfile = optarg; break; @@ -533,7 +538,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Don't have a basedir to use. This should not happen. Ever."); return 1; - } else if (change_basedir(basedir)) { + } else if (change_basedir(basedir, opt_create_basedir)) { fprintf(stderr, "Error: Unable to change to directory `%s'.\n", basedir); return 1; } diff --git a/src/daemon/common.c b/src/daemon/common.c index d9c83483..6c856a6b 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -84,18 +84,6 @@ char *sstrncpy(char *dest, const char *src, size_t n) { return dest; } /* char *sstrncpy */ -int ssnprintf(char *dest, size_t n, const char *format, ...) { - int ret = 0; - va_list ap; - - va_start(ap, format); - ret = vsnprintf(dest, n, format, ap); - dest[n - 1] = '\0'; - va_end(ap); - - return ret; -} /* int ssnprintf */ - char *ssnprintf_alloc(char const *format, ...) /* {{{ */ { char static_buffer[1024] = ""; @@ -191,9 +179,9 @@ char *sstrerror(int errnum, char *buf, size_t buflen) { #else if (strerror_r(errnum, buf, buflen) != 0) { - ssnprintf(buf, buflen, "Error #%i; " - "Additionally, strerror_r failed.", - errnum); + snprintf(buf, buflen, "Error #%i; " + "Additionally, strerror_r failed.", + errnum); } #endif /* STRERROR_R_CHAR_P */ @@ -281,7 +269,8 @@ ssize_t swrite(int fd, const void *buf, size_t count) { 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 errno ? errno : -1; + errno = ECONNRESET; + return -1; } } @@ -675,7 +664,7 @@ int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name) { if (kc == NULL) return -1; - ssnprintf(ident, sizeof(ident), "%s,%i,%s", module, instance, name); + snprintf(ident, sizeof(ident), "%s,%i,%s", module, instance, name); *ksp_ptr = kstat_lookup(kc, module, instance, name); if (*ksp_ptr == NULL) { @@ -882,7 +871,7 @@ int format_values(char *ret, size_t ret_len, /* {{{ */ #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ + status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ if (status < 1) { \ sfree(rates); \ return -1; \ diff --git a/src/daemon/common.h b/src/daemon/common.h index 8947c575..afd292a3 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -66,9 +66,6 @@ typedef struct value_to_rate_state_s value_to_rate_state_t; char *sstrncpy(char *dest, const char *src, size_t n); -__attribute__((format(printf, 3, 4))) int ssnprintf(char *dest, size_t n, - const char *format, ...); - __attribute__((format(printf, 1, 2))) char *ssnprintf_alloc(char const *format, ...); diff --git a/src/daemon/common_test.c b/src/daemon/common_test.c index 5b577d45..4d2ccaa3 100644 --- a/src/daemon/common_test.c +++ b/src/daemon/common_test.c @@ -58,27 +58,6 @@ DEF_TEST(sstrncpy) { return 0; } -DEF_TEST(ssnprintf) { - char buffer[16] = ""; - char *ptr = &buffer[4]; - int status; - - buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0xff; - buffer[12] = buffer[13] = buffer[14] = buffer[15] = 0xff; - - status = ssnprintf(ptr, 8, "%i", 1337); - OK(status == 4); - EXPECT_EQ_STR("1337", ptr); - - status = ssnprintf(ptr, 8, "%s", "collectd"); - OK(status == 8); - OK(ptr[7] == 0); - EXPECT_EQ_STR("collect", ptr); - OK(buffer[3] == buffer[12]); - - return 0; -} - DEF_TEST(sstrdup) { char *ptr; @@ -380,7 +359,6 @@ DEF_TEST(value_to_rate) { int main(void) { RUN_TEST(sstrncpy); - RUN_TEST(ssnprintf); RUN_TEST(sstrdup); RUN_TEST(strsplit); RUN_TEST(strjoin); diff --git a/src/daemon/configfile.c b/src/daemon/configfile.c index 5594bb7a..0d295c1c 100644 --- a/src/daemon/configfile.c +++ b/src/daemon/configfile.c @@ -196,7 +196,7 @@ static int dispatch_global_option(const oconfig_item_t *ci) { return global_option_set(ci->key, ci->values[0].value.string, 0); else if (ci->values[0].type == OCONFIG_TYPE_NUMBER) { char tmp[128]; - ssnprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number); + snprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number); return global_option_set(ci->key, tmp, 0); } else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) { if (ci->values[0].value.boolean) @@ -305,13 +305,13 @@ static int dispatch_value_plugin(const char *plugin, oconfig_item_t *ci) { if (ci->values[i].type == OCONFIG_TYPE_STRING) status = - ssnprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string); + snprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string); else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) - status = ssnprintf(buffer_ptr, buffer_free, " %lf", - ci->values[i].value.number); + status = + snprintf(buffer_ptr, buffer_free, " %lf", ci->values[i].value.number); else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN) - status = ssnprintf(buffer_ptr, buffer_free, " %s", - ci->values[i].value.boolean ? "true" : "false"); + status = snprintf(buffer_ptr, buffer_free, " %s", + ci->values[i].value.boolean ? "true" : "false"); if ((status < 0) || (status >= buffer_free)) return -1; @@ -653,7 +653,7 @@ static oconfig_item_t *cf_read_dir(const char *dir, const char *pattern, if ((de->d_name[0] == '.') || (de->d_name[0] == 0)) continue; - status = ssnprintf(name, sizeof(name), "%s/%s", dir, de->d_name); + status = snprintf(name, sizeof(name), "%s/%s", dir, de->d_name); if ((status < 0) || ((size_t)status >= sizeof(name))) { ERROR("configfile: Not including `%s/%s' because its" " name is too long.", @@ -1246,7 +1246,7 @@ int cf_util_get_service(const oconfig_item_t *ci, char **ret_string) /* {{{ */ ERROR("cf_util_get_service: Out of memory."); return -1; } - ssnprintf(service, 6, "%i", port); + snprintf(service, 6, "%i", port); sfree(*ret_string); *ret_string = service; diff --git a/src/daemon/filter_chain.c b/src/daemon/filter_chain.c index 5a2d6472..1352f5b3 100644 --- a/src/daemon/filter_chain.c +++ b/src/daemon/filter_chain.c @@ -343,8 +343,8 @@ static int fc_config_add_rule(fc_chain_t *chain, /* {{{ */ if (ci->values_num == 1) { sstrncpy(rule->name, ci->values[0].value.string, sizeof(rule->name)); - ssnprintf(rule_name, sizeof(rule_name), "Rule \"%s\"", - ci->values[0].value.string); + snprintf(rule_name, sizeof(rule_name), "Rule \"%s\"", + ci->values[0].value.string); } for (int i = 0; i < ci->children_num; i++) { diff --git a/src/daemon/meta_data.c b/src/daemon/meta_data.c index 502ca108..ce3e1020 100644 --- a/src/daemon/meta_data.c +++ b/src/daemon/meta_data.c @@ -713,15 +713,15 @@ int meta_data_as_string(meta_data_t *md, /* {{{ */ actual = e->value.mv_string; break; case MD_TYPE_SIGNED_INT: - ssnprintf(buffer, sizeof(buffer), "%" PRIi64, e->value.mv_signed_int); + snprintf(buffer, sizeof(buffer), "%" PRIi64, e->value.mv_signed_int); actual = buffer; break; case MD_TYPE_UNSIGNED_INT: - ssnprintf(buffer, sizeof(buffer), "%" PRIu64, e->value.mv_unsigned_int); + snprintf(buffer, sizeof(buffer), "%" PRIu64, e->value.mv_unsigned_int); actual = buffer; break; case MD_TYPE_DOUBLE: - ssnprintf(buffer, sizeof(buffer), GAUGE_FORMAT, e->value.mv_double); + snprintf(buffer, sizeof(buffer), GAUGE_FORMAT, e->value.mv_double); actual = buffer; break; case MD_TYPE_BOOLEAN: diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c index 3bf183d9..ae99d5fd 100644 --- a/src/daemon/plugin.c +++ b/src/daemon/plugin.c @@ -191,16 +191,21 @@ static int plugin_update_internal_statistics(void) { /* {{{ */ return 0; } /* }}} int plugin_update_internal_statistics */ -static void destroy_callback(callback_func_t *cf) /* {{{ */ +static void free_userdata(user_data_t const *ud) /* {{{ */ { - if (cf == NULL) + if (ud == NULL) return; - if ((cf->cf_udata.data != NULL) && (cf->cf_udata.free_func != NULL)) { - cf->cf_udata.free_func(cf->cf_udata.data); - cf->cf_udata.data = NULL; - cf->cf_udata.free_func = NULL; + if ((ud->data != NULL) && (ud->free_func != NULL)) { + ud->free_func(ud->data); } +} /* }}} void free_userdata */ + +static void destroy_callback(callback_func_t *cf) /* {{{ */ +{ + if (cf == NULL) + return; + free_userdata(&cf->cf_udata); sfree(cf); } /* }}} void destroy_callback */ @@ -345,6 +350,7 @@ static int create_register_callback(llist_t **list, /* {{{ */ cf = calloc(1, sizeof(*cf)); if (cf == NULL) { + free_userdata(ud); ERROR("plugin: create_register_callback: calloc failed."); return -1; } @@ -400,13 +406,13 @@ static int plugin_load_file(const char *file, _Bool global) { if (dlh == NULL) { char errbuf[1024] = ""; - ssnprintf(errbuf, sizeof(errbuf), - "dlopen (\"%s\") failed: %s. " - "The most common cause for this problem is " - "missing dependencies. Use ldd(1) to check " - "the dependencies of the plugin " - "/ shared object.", - file, dlerror()); + snprintf(errbuf, sizeof(errbuf), + "dlopen (\"%s\") failed: %s. " + "The most common cause for this problem is " + "missing dependencies. Use ldd(1) to check " + "the dependencies of the plugin " + "/ shared object.", + file, dlerror()); ERROR("%s", errbuf); /* Make sure this is printed to STDERR in any case, but also @@ -640,7 +646,7 @@ static void start_read_threads(size_t num) /* {{{ */ } char name[THREAD_NAME_MAX]; - ssnprintf(name, sizeof(name), "reader#%zu", read_threads_num); + snprintf(name, sizeof(name), "reader#%zu", read_threads_num); set_thread_name(read_threads[read_threads_num], name); read_threads_num++; @@ -847,7 +853,7 @@ static void start_write_threads(size_t num) /* {{{ */ } char name[THREAD_NAME_MAX]; - ssnprintf(name, sizeof(name), "writer#%zu", write_threads_num); + snprintf(name, sizeof(name), "writer#%zu", write_threads_num); set_thread_name(write_threads[write_threads_num], name); write_threads_num++; @@ -996,7 +1002,7 @@ int plugin_load(char const *plugin_name, _Bool global) { /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the * type when matching the filename */ - status = ssnprintf(typename, sizeof(typename), "%s.so", plugin_name); + status = snprintf(typename, sizeof(typename), "%s.so", plugin_name); if ((status < 0) || ((size_t)status >= sizeof(typename))) { WARNING("plugin_load: Filename too long: \"%s.so\"", plugin_name); return -1; @@ -1013,7 +1019,7 @@ int plugin_load(char const *plugin_name, _Bool global) { if (strcasecmp(de->d_name, typename)) continue; - status = ssnprintf(filename, sizeof(filename), "%s/%s", dir, de->d_name); + status = snprintf(filename, sizeof(filename), "%s/%s", dir, de->d_name); if ((status < 0) || ((size_t)status >= sizeof(filename))) { WARNING("plugin_load: Filename too long: \"%s/%s\"", dir, de->d_name); continue; @@ -1120,8 +1126,7 @@ static int plugin_insert_read(read_func_t *rf) { if (le != NULL) { pthread_mutex_unlock(&read_lock); WARNING("The read function \"%s\" is already registered. " - "Check for duplicate \"LoadPlugin\" lines " - "in your configuration!", + "Check for duplicates in your configuration!", rf->rf_name); return EINVAL; } @@ -1186,6 +1191,7 @@ int plugin_register_complex_read(const char *group, const char *name, rf = calloc(1, sizeof(*rf)); if (rf == NULL) { + free_userdata(user_data); ERROR("plugin_register_complex_read: calloc failed."); return ENOMEM; } @@ -1211,6 +1217,7 @@ int plugin_register_complex_read(const char *group, const char *name, status = plugin_insert_read(rf); if (status != 0) { + free_userdata(&rf->rf_udata); sfree(rf->rf_name); sfree(rf); } @@ -1303,11 +1310,7 @@ int plugin_register_flush(const char *name, plugin_flush_cb callback, }); sfree(flush_name); - if (status != 0) { - sfree(cb->name); - sfree(cb); - return status; - } + return status; } return 0; diff --git a/src/daemon/utils_cache.c b/src/daemon/utils_cache.c index 7d6e8fd6..ea7c3e33 100644 --- a/src/daemon/utils_cache.c +++ b/src/daemon/utils_cache.c @@ -913,6 +913,15 @@ int uc_iterator_get_interval(uc_iter_t *iter, cdtime_t *ret_interval) { return 0; } /* int uc_iterator_get_name */ +int uc_iterator_get_meta(uc_iter_t *iter, meta_data_t **ret_meta) { + if ((iter == NULL) || (iter->entry == NULL) || (ret_meta == NULL)) + return -1; + + *ret_meta = meta_data_clone(iter->entry->meta); + + return 0; +} /* int uc_iterator_get_meta */ + /* * Meta data interface */ diff --git a/src/daemon/utils_cache.h b/src/daemon/utils_cache.h index 8ba7133a..08c2f10a 100644 --- a/src/daemon/utils_cache.h +++ b/src/daemon/utils_cache.h @@ -106,6 +106,8 @@ int uc_iterator_get_values(uc_iter_t *iter, value_t **ret_values, size_t *ret_num); /* Return the interval of the value at the current position. */ int uc_iterator_get_interval(uc_iter_t *iter, cdtime_t *ret_interval); +/* Return the metadata for the value at the current position. */ +int uc_iterator_get_meta(uc_iter_t *iter, meta_data_t **ret_meta); /* * Meta data interface diff --git a/src/daemon/utils_time.c b/src/daemon/utils_time.c index 815d9697..ab440edb 100644 --- a/src/daemon/utils_time.c +++ b/src/daemon/utils_time.c @@ -164,7 +164,7 @@ int format_rfc3339(char *buffer, size_t buffer_size, struct tm const *t_tm, size_left -= len; if (print_nano) { - if ((len = ssnprintf(pos, size_left, ".%09ld", nsec)) == 0) + if ((len = snprintf(pos, size_left, ".%09ld", nsec)) == 0) return ENOMEM; pos += len; size_left -= len; diff --git a/src/dbi.c b/src/dbi.c index 7f3f2072..a965b071 100644 --- a/src/dbi.c +++ b/src/dbi.c @@ -108,10 +108,10 @@ static const char *cdbi_strerror(dbi_conn conn, /* {{{ */ msg = NULL; status = dbi_conn_error(conn, &msg); if ((status >= 0) && (msg != NULL)) - ssnprintf(buffer, buffer_size, "%s (status %i)", msg, status); + snprintf(buffer, buffer_size, "%s (status %i)", msg, status); else - ssnprintf(buffer, buffer_size, "dbi_conn_error failed with status %i", - status); + snprintf(buffer, buffer_size, "dbi_conn_error failed with status %i", + status); return buffer; } /* }}} const char *cdbi_conn_error */ @@ -132,12 +132,12 @@ static int cdbi_result_get_field(dbi_result res, /* {{{ */ long long value; value = dbi_result_get_longlong_idx(res, index); - ssnprintf(buffer, buffer_size, "%lli", value); + snprintf(buffer, buffer_size, "%lli", value); } else if (src_type == DBI_TYPE_DECIMAL) { double value; value = dbi_result_get_double_idx(res, index); - ssnprintf(buffer, buffer_size, "%63.15g", value); + snprintf(buffer, buffer_size, "%63.15g", value); } else if (src_type == DBI_TYPE_STRING) { const char *value; diff --git a/src/disk.c b/src/disk.c index 4a217c30..51a50fd1 100644 --- a/src/disk.c +++ b/src/disk.c @@ -405,8 +405,8 @@ static int disk_read(void) { /* Get the list of all disk objects. */ if (IOServiceGetMatchingServices( - io_master_port, IOServiceMatching(kIOBlockStorageDriverClass), - &disk_list) != kIOReturnSuccess) { + io_master_port, IOServiceMatching(kIOBlockStorageDriverClass), + &disk_list) != kIOReturnSuccess) { ERROR("disk plugin: IOServiceGetMatchingServices failed."); return -1; } @@ -490,11 +490,10 @@ static int disk_read(void) { sstrncpy(disk_name, props_disk_name_bsd, sizeof(disk_name)); else { ERROR("disk plugin: can't find bsd disk name."); - ssnprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, - disk_minor); + snprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor); } } else - ssnprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor); + snprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor); DEBUG("disk plugin: disk_name = \"%s\"", disk_name); diff --git a/src/dpdkevents.c b/src/dpdkevents.c index b7429273..32d3d6af 100644 --- a/src/dpdkevents.c +++ b/src/dpdkevents.c @@ -488,7 +488,6 @@ static void dpdk_events_gauge_submit(const char *plugin_instance, .plugin = DPDK_EVENTS_PLUGIN, .type = "gauge", .meta = NULL}; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); plugin_dispatch_values(&vl); @@ -510,17 +509,17 @@ static int dpdk_events_link_status_dispatch(dpdk_helper_ctx_t *phc) { char dev_name[DATA_MAX_NAME_LEN]; if (ec->config.link_status.port_name[i][0] != 0) { - ssnprintf(dev_name, sizeof(dev_name), "%s", - ec->config.link_status.port_name[i]); + snprintf(dev_name, sizeof(dev_name), "%s", + ec->config.link_status.port_name[i]); } else { - ssnprintf(dev_name, sizeof(dev_name), "port.%d", i); + snprintf(dev_name, sizeof(dev_name), "port.%d", i); } if (ec->config.link_status.notify) { int sev = ec->link_info[i].link_status ? NOTIF_OKAY : NOTIF_WARNING; char msg[DATA_MAX_NAME_LEN]; - ssnprintf(msg, sizeof(msg), "Link Status: %s", - ec->link_info[i].link_status ? "UP" : "DOWN"); + snprintf(msg, sizeof(msg), "Link Status: %s", + ec->link_info[i].link_status ? "UP" : "DOWN"); dpdk_events_notification_dispatch(sev, dev_name, ec->link_info[i].read_time, msg); } else { @@ -556,7 +555,7 @@ static void dpdk_events_keep_alive_dispatch(dpdk_helper_ctx_t *phc) { } char core_name[DATA_MAX_NAME_LEN]; - ssnprintf(core_name, sizeof(core_name), "lcore%u", i); + snprintf(core_name, sizeof(core_name), "lcore%u", i); if (!ec->config.keep_alive.send_updated || (ec->core_info[i].lcore_state != @@ -571,34 +570,34 @@ static void dpdk_events_keep_alive_dispatch(dpdk_helper_ctx_t *phc) { switch (ec->config.keep_alive.shm->core_state[i]) { case RTE_KA_STATE_ALIVE: sev = NOTIF_OKAY; - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: ALIVE", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: ALIVE", i); break; case RTE_KA_STATE_MISSING: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: MISSING", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: MISSING", i); sev = NOTIF_WARNING; break; case RTE_KA_STATE_DEAD: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DEAD", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DEAD", i); sev = NOTIF_FAILURE; break; case RTE_KA_STATE_UNUSED: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNUSED", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNUSED", i); sev = NOTIF_OKAY; break; case RTE_KA_STATE_GONE: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: GONE", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: GONE", i); sev = NOTIF_FAILURE; break; case RTE_KA_STATE_DOZING: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DOZING", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DOZING", i); sev = NOTIF_OKAY; break; case RTE_KA_STATE_SLEEP: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: SLEEP", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: SLEEP", i); sev = NOTIF_OKAY; break; default: - ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNKNOWN", i); + snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNKNOWN", i); sev = NOTIF_FAILURE; } diff --git a/src/dpdkstat.c b/src/dpdkstat.c index 2f24630f..c95ba0c6 100644 --- a/src/dpdkstat.c +++ b/src/dpdkstat.c @@ -373,7 +373,6 @@ static void dpdk_stats_counter_submit(const char *plugin_instance, vl.values = &(value_t){.derive = value}; vl.values_len = 1; vl.time = port_read_time; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin, DPDK_STATS_PLUGIN, sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); dpdk_stats_resolve_cnt_type(vl.type, sizeof(vl.type), cnt_name); @@ -397,9 +396,9 @@ static int dpdk_stats_counters_dispatch(dpdk_helper_ctx_t *phc) { char dev_name[64]; if (ctx->config.port_name[i][0] != 0) { - ssnprintf(dev_name, sizeof(dev_name), "%s", ctx->config.port_name[i]); + snprintf(dev_name, sizeof(dev_name), "%s", ctx->config.port_name[i]); } else { - ssnprintf(dev_name, sizeof(dev_name), "port.%d", i); + snprintf(dev_name, sizeof(dev_name), "port.%d", i); } DEBUG(" === Dispatch stats for port %d (name=%s; stats_count=%d)", i, diff --git a/src/drbd.c b/src/drbd.c index 97a4f032..5a0eac30 100644 --- a/src/drbd.c +++ b/src/drbd.c @@ -77,7 +77,7 @@ static int drbd_submit_fields(long int resource, char **fields, return EINVAL; } - ssnprintf(plugin_instance, sizeof(plugin_instance), "r%ld", resource); + snprintf(plugin_instance, sizeof(plugin_instance), "r%ld", resource); for (size_t i = 0; i < drbd_names_num; i++) { char *data; diff --git a/src/exec.c b/src/exec.c index 3d12a2de..22da3160 100644 --- a/src/exec.c +++ b/src/exec.c @@ -187,8 +187,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ pl->argv[i] = strdup(ci->values[i + 1].value.string); } else { if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER) { - ssnprintf(buffer, sizeof(buffer), "%lf", - ci->values[i + 1].value.number); + snprintf(buffer, sizeof(buffer), "%lf", ci->values[i + 1].value.number); } else { if (ci->values[i + 1].value.boolean) sstrncpy(buffer, "true", sizeof(buffer)); @@ -246,18 +245,18 @@ static void set_environment(void) /* {{{ */ char buffer[1024]; #ifdef HAVE_SETENV - ssnprintf(buffer, sizeof(buffer), "%.3f", - CDTIME_T_TO_DOUBLE(plugin_get_interval())); + snprintf(buffer, sizeof(buffer), "%.3f", + CDTIME_T_TO_DOUBLE(plugin_get_interval())); setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1); sstrncpy(buffer, hostname_g, sizeof(buffer)); setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1); #else - ssnprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f", - CDTIME_T_TO_DOUBLE(plugin_get_interval())); + snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f", + CDTIME_T_TO_DOUBLE(plugin_get_interval())); putenv(buffer); - ssnprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g); + snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g); putenv(buffer); #endif } /* }}} void set_environment */ diff --git a/src/filecount.c b/src/filecount.c index 7eb51047..5b812b88 100644 --- a/src/filecount.c +++ b/src/filecount.c @@ -37,7 +37,11 @@ struct fc_directory_conf_s { char *path; + char *plugin_name; char *instance; + char *files_size_type; + char *files_num_type; + char *type_instance; int options; @@ -58,31 +62,56 @@ typedef struct fc_directory_conf_s fc_directory_conf_t; static fc_directory_conf_t **directories = NULL; static size_t directories_num = 0; +void fc_free_dir(fc_directory_conf_t *dir) { + sfree(dir->path); + sfree(dir->plugin_name); + sfree(dir->instance); + sfree(dir->files_size_type); + sfree(dir->files_num_type); + sfree(dir->type_instance); + sfree(dir->name); + + sfree(dir); +} /* void fc_free_dir */ + static void fc_submit_dir(const fc_directory_conf_t *dir) { value_list_t vl = VALUE_LIST_INIT; - vl.values = &(value_t){.gauge = (gauge_t)dir->files_num}; - vl.values_len = 1; - sstrncpy(vl.plugin, "filecount", sizeof(vl.plugin)); - sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance)); - sstrncpy(vl.type, "files", sizeof(vl.type)); + sstrncpy(vl.plugin, dir->plugin_name, sizeof(vl.plugin)); + if (dir->instance != NULL) + sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance)); + if (dir->type_instance != NULL) + sstrncpy(vl.type_instance, dir->type_instance, sizeof(vl.type_instance)); - plugin_dispatch_values(&vl); + vl.values_len = 1; - vl.values = &(value_t){.gauge = (gauge_t)dir->files_size}; - sstrncpy(vl.type, "bytes", sizeof(vl.type)); + if (dir->files_num_type != NULL) { + vl.values = &(value_t){.gauge = (gauge_t)dir->files_num}; + sstrncpy(vl.type, dir->files_num_type, sizeof(vl.type)); + plugin_dispatch_values(&vl); + } - plugin_dispatch_values(&vl); + if (dir->files_size_type != NULL) { + vl.values = &(value_t){.gauge = (gauge_t)dir->files_size}; + sstrncpy(vl.type, dir->files_size_type, sizeof(vl.type)); + plugin_dispatch_values(&vl); + } } /* void fc_submit_dir */ /* * Config: * * + * Plugin "foo" * Instance "foobar" * Name "*.conf" * MTime -3600 * Size "+10M" + * Recursive true + * IncludeHidden false + * FilesSizeType "bytes" + * FilesCountType "files" + * TypeInstance "instance" * * * @@ -94,7 +123,6 @@ static void fc_submit_dir(const fc_directory_conf_t *dir) { static int fc_config_set_instance(fc_directory_conf_t *dir, const char *str) { char buffer[1024]; char *ptr; - char *copy; sstrncpy(buffer, str, sizeof(buffer)); for (ptr = buffer; *ptr != 0; ptr++) @@ -104,10 +132,7 @@ static int fc_config_set_instance(fc_directory_conf_t *dir, const char *str) { for (ptr = buffer; *ptr == '_'; ptr++) /* do nothing */; - if (*ptr == 0) - return -1; - - copy = strdup(ptr); + char *copy = strdup(ptr); if (copy == NULL) return -1; @@ -130,15 +155,13 @@ static int fc_config_add_dir_instance(fc_directory_conf_t *dir, static int fc_config_add_dir_name(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *temp; - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("filecount plugin: The `Name' config option needs exactly one " "string argument."); return -1; } - temp = strdup(ci->values[0].value.string); + char *temp = strdup(ci->values[0].value.string); if (temp == NULL) { ERROR("filecount plugin: strdup failed."); return -1; @@ -152,9 +175,6 @@ static int fc_config_add_dir_name(fc_directory_conf_t *dir, static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *endptr; - double temp; - if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) && (ci->values[0].type != OCONFIG_TYPE_NUMBER))) { WARNING("filecount plugin: The `MTime' config option needs exactly one " @@ -168,8 +188,8 @@ static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, } errno = 0; - endptr = NULL; - temp = strtod(ci->values[0].value.string, &endptr); + char *endptr = NULL; + double temp = strtod(ci->values[0].value.string, &endptr); if ((errno != 0) || (endptr == NULL) || (endptr == ci->values[0].value.string)) { WARNING("filecount plugin: Converting `%s' to a number failed.", @@ -220,9 +240,6 @@ static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, static int fc_config_add_dir_size(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *endptr; - double temp; - if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) && (ci->values[0].type != OCONFIG_TYPE_NUMBER))) { WARNING("filecount plugin: The `Size' config option needs exactly one " @@ -236,8 +253,8 @@ static int fc_config_add_dir_size(fc_directory_conf_t *dir, } errno = 0; - endptr = NULL; - temp = strtod(ci->values[0].value.string, &endptr); + char *endptr = NULL; + double temp = strtod(ci->values[0].value.string, &endptr); if ((errno != 0) || (endptr == NULL) || (endptr == ci->values[0].value.string)) { WARNING("filecount plugin: Converting `%s' to a number failed.", @@ -303,9 +320,6 @@ static int fc_config_add_dir_option(fc_directory_conf_t *dir, } /* int fc_config_add_dir_option */ static int fc_config_add_dir(oconfig_item_t *ci) { - fc_directory_conf_t *dir; - int status; - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("filecount plugin: `Directory' needs exactly one string " "argument."); @@ -313,7 +327,7 @@ static int fc_config_add_dir(oconfig_item_t *ci) { } /* Initialize `dir' */ - dir = calloc(1, sizeof(*dir)); + fc_directory_conf_t *dir = calloc(1, sizeof(*dir)); if (dir == NULL) { ERROR("filecount plugin: calloc failed."); return -1; @@ -322,23 +336,36 @@ static int fc_config_add_dir(oconfig_item_t *ci) { dir->path = strdup(ci->values[0].value.string); if (dir->path == NULL) { ERROR("filecount plugin: strdup failed."); - sfree(dir); + fc_free_dir(dir); return -1; } - fc_config_set_instance(dir, dir->path); - dir->options = FC_RECURSIVE; dir->name = NULL; + dir->plugin_name = strdup("filecount"); + dir->instance = NULL; + dir->type_instance = NULL; dir->mtime = 0; dir->size = 0; - status = 0; + dir->files_size_type = strdup("bytes"); + dir->files_num_type = strdup("files"); + + if (dir->plugin_name == NULL || dir->files_size_type == NULL || + dir->files_num_type == NULL) { + ERROR("filecount plugin: strdup failed."); + fc_free_dir(dir); + return -1; + } + + int status = 0; for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - if (strcasecmp("Instance", option->key) == 0) + if (strcasecmp("Plugin", option->key) == 0) + status = cf_util_get_string(option, &dir->plugin_name); + else if (strcasecmp("Instance", option->key) == 0) status = fc_config_add_dir_instance(dir, option); else if (strcasecmp("Name", option->key) == 0) status = fc_config_add_dir_name(dir, option); @@ -350,6 +377,12 @@ static int fc_config_add_dir(oconfig_item_t *ci) { status = fc_config_add_dir_option(dir, option, FC_RECURSIVE); else if (strcasecmp("IncludeHidden", option->key) == 0) status = fc_config_add_dir_option(dir, option, FC_HIDDEN); + else if (strcasecmp("FilesSizeType", option->key) == 0) + status = cf_util_get_string(option, &dir->files_size_type); + else if (strcasecmp("FilesCountType", option->key) == 0) + status = cf_util_get_string(option, &dir->files_num_type); + else if (strcasecmp("TypeInstance", option->key) == 0) + status = cf_util_get_string(option, &dir->type_instance); else { WARNING("filecount plugin: fc_config_add_dir: " "Option `%s' not allowed here.", @@ -361,28 +394,52 @@ static int fc_config_add_dir(oconfig_item_t *ci) { break; } /* for (ci->children) */ - if (status == 0) { - fc_directory_conf_t **temp; + if (status != 0) { + fc_free_dir(dir); + return -1; + } - temp = realloc(directories, sizeof(*directories) * (directories_num + 1)); - if (temp == NULL) { - ERROR("filecount plugin: realloc failed."); - status = -1; - } else { - directories = temp; - directories[directories_num] = dir; - directories_num++; + /* Set default plugin instance */ + if (dir->instance == NULL) { + fc_config_set_instance(dir, dir->path); + if (dir->instance == NULL || strlen(dir->instance) == 0) { + ERROR("filecount plugin: failed to build plugin instance name."); + fc_free_dir(dir); + return -1; } } - if (status != 0) { - sfree(dir->name); + /* Handle disabled types */ + if (strlen(dir->instance) == 0) sfree(dir->instance); - sfree(dir->path); - sfree(dir); + + if (strlen(dir->files_size_type) == 0) + sfree(dir->files_size_type); + + if (strlen(dir->files_num_type) == 0) + sfree(dir->files_num_type); + + if (dir->files_size_type == NULL && dir->files_num_type == NULL) { + WARNING("filecount plugin: Both `FilesSizeType' and `FilesCountType ' " + "are disabled for '%s'. There's no types to report.", + dir->path); + fc_free_dir(dir); + return -1; + } + + /* Ready to add it to list */ + fc_directory_conf_t **temp = + realloc(directories, sizeof(*directories) * (directories_num + 1)); + if (temp == NULL) { + ERROR("filecount plugin: realloc failed."); + fc_free_dir(dir); return -1; } + directories = temp; + directories[directories_num] = dir; + directories_num++; + return 0; } /* int fc_config_add_dir */ @@ -414,14 +471,13 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, fc_directory_conf_t *dir = user_data; char abs_path[PATH_MAX]; struct stat statbuf; - int status; if (dir == NULL) return -1; - ssnprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename); + snprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename); - status = lstat(abs_path, &statbuf); + int status = lstat(abs_path, &statbuf); if (status != 0) { ERROR("filecount plugin: stat (%s) failed.", abs_path); return -1; @@ -478,15 +534,13 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, } /* int fc_read_dir_callback */ static int fc_read_dir(fc_directory_conf_t *dir) { - int status; - dir->files_num = 0; dir->files_size = 0; if (dir->mtime != 0) dir->now = time(NULL); - status = + int status = walk_directory(dir->path, fc_read_dir_callback, dir, /* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0); if (status != 0) { diff --git a/src/gmond.c b/src/gmond.c index c6804276..50bd8323 100644 --- a/src/gmond.c +++ b/src/gmond.c @@ -417,8 +417,8 @@ static staging_entry_t *staging_entry_get(const char *host, /* {{{ */ if (staging_tree == NULL) return NULL; - ssnprintf(key, sizeof(key), "%s/%s/%s", host, type, - (type_instance != NULL) ? type_instance : ""); + snprintf(key, sizeof(key), "%s/%s/%s", host, type, + (type_instance != NULL) ? type_instance : ""); se = NULL; status = c_avl_get(staging_tree, key, (void *)&se); diff --git a/src/grpc.cc b/src/grpc.cc index 2f16dbcb..0f5cfec0 100644 --- a/src/grpc.cc +++ b/src/grpc.cc @@ -56,6 +56,8 @@ using collectd::QueryValuesResponse; using google::protobuf::util::TimeUtil; +typedef google::protobuf::Map grpcMetadata; + /* * private types */ @@ -154,6 +156,124 @@ static grpc::Status unmarshal_ident(const collectd::types::Identifier &msg, return grpc::Status::OK; } /* unmarshal_ident() */ +static grpc::Status marshal_meta_data(meta_data_t *meta, + grpcMetadata *mutable_meta_data) { + char **meta_data_keys = nullptr; + int meta_data_keys_len = meta_data_toc(meta, &meta_data_keys); + if (meta_data_keys_len < 0) { + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("error getting metadata keys")); + } + + for (int i = 0; i < meta_data_keys_len; i++) { + char *key = meta_data_keys[i]; + int md_type = meta_data_type(meta, key); + + collectd::types::MetadataValue md_value; + md_value.Clear(); + + switch (md_type) { + case MD_TYPE_STRING: + char *md_string; + if (meta_data_get_string(meta, key, &md_string) != 0 || md_string == nullptr) { + strarray_free(meta_data_keys, meta_data_keys_len); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("missing metadata")); + } + md_value.set_string_value(md_string); + free(md_string); + break; + case MD_TYPE_SIGNED_INT: + int64_t int64_value; + if (meta_data_get_signed_int(meta, key, &int64_value) != 0) { + strarray_free(meta_data_keys, meta_data_keys_len); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("missing metadata")); + } + md_value.set_int64_value(int64_value); + break; + case MD_TYPE_UNSIGNED_INT: + uint64_t uint64_value; + if (meta_data_get_unsigned_int(meta, key, &uint64_value) != 0) { + strarray_free(meta_data_keys, meta_data_keys_len); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("missing metadata")); + } + md_value.set_uint64_value(uint64_value); + break; + case MD_TYPE_DOUBLE: + double double_value; + if (meta_data_get_double(meta, key, &double_value) != 0) { + strarray_free(meta_data_keys, meta_data_keys_len); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("missing metadata")); + } + md_value.set_double_value(double_value); + break; + case MD_TYPE_BOOLEAN: + bool bool_value; + if (meta_data_get_boolean(meta, key, &bool_value) != 0) { + strarray_free(meta_data_keys, meta_data_keys_len); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("missing metadata")); + } + md_value.set_bool_value(bool_value); + break; + default: + strarray_free(meta_data_keys, meta_data_keys_len); + ERROR("grpc: invalid metadata type (%d)", md_type); + return grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("unknown metadata type")); + } + + (*mutable_meta_data)[grpc::string(key)] = md_value; + + strarray_free(meta_data_keys, meta_data_keys_len); + } + + return grpc::Status::OK; +} + +static grpc::Status unmarshal_meta_data(const grpcMetadata &rpc_metadata, + meta_data_t **md_out) { + *md_out = meta_data_create(); + if (*md_out == nullptr) { + return grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED, + grpc::string("failed to metadata list")); + } + for (auto kv: rpc_metadata) { + auto k = kv.first.c_str(); + auto v = kv.second; + + // The meta_data collection individually allocates copies of the keys and + // string values for each entry, so it's safe for us to pass a reference + // to our short-lived strings. + + switch (v.value_case()) { + case collectd::types::MetadataValue::ValueCase::kStringValue: + meta_data_add_string(*md_out, k, v.string_value().c_str()); + break; + case collectd::types::MetadataValue::ValueCase::kInt64Value: + meta_data_add_signed_int(*md_out, k, v.int64_value()); + break; + case collectd::types::MetadataValue::ValueCase::kUint64Value: + meta_data_add_unsigned_int(*md_out, k, v.uint64_value()); + break; + case collectd::types::MetadataValue::ValueCase::kDoubleValue: + meta_data_add_double(*md_out, k, v.double_value()); + break; + case collectd::types::MetadataValue::ValueCase::kBoolValue: + meta_data_add_boolean(*md_out, k, v.bool_value()); + break; + default: + meta_data_destroy(*md_out); + return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + grpc::string("Metadata of unknown type")); + } + } + return grpc::Status::OK; +} + static grpc::Status marshal_value_list(const value_list_t *vl, collectd::types::ValueList *msg) { auto id = msg->mutable_identifier(); @@ -170,9 +290,18 @@ static grpc::Status marshal_value_list(const value_list_t *vl, msg->set_allocated_time(new google::protobuf::Timestamp(t)); msg->set_allocated_interval(new google::protobuf::Duration(d)); + msg->clear_meta_data(); + if (vl->meta != nullptr) { + grpc::Status status = marshal_meta_data(vl->meta, msg->mutable_meta_data()); + if (!status.ok()) { + return status; + } + } + for (size_t i = 0; i < vl->values_len; ++i) { auto v = msg->add_values(); - switch (ds->ds[i].type) { + int value_type = ds->ds[i].type; + switch (value_type) { case DS_TYPE_COUNTER: v->set_counter(vl->values[i].counter); break; @@ -186,6 +315,7 @@ static grpc::Status marshal_value_list(const value_list_t *vl, v->set_absolute(vl->values[i].absolute); break; default: + ERROR("grpc: invalid value type (%d)", value_type); return grpc::Status(grpc::StatusCode::INTERNAL, grpc::string("unknown value type")); } @@ -207,6 +337,10 @@ static grpc::Status unmarshal_value_list(const collectd::types::ValueList &msg, if (!status.ok()) return status; + status = unmarshal_meta_data(msg.meta_data(), &vl->meta); + if (!status.ok()) + return status; + value_t *values = NULL; size_t values_len = 0; @@ -249,7 +383,8 @@ static grpc::Status unmarshal_value_list(const collectd::types::ValueList &msg, if (status.ok()) { vl->values = values; vl->values_len = values_len; - } else if (values) { + } else { + meta_data_destroy(vl->meta); free(values); } @@ -280,6 +415,7 @@ public: auto vl = value_lists.front(); value_lists.pop(); sfree(vl.values); + meta_data_destroy(vl.meta); } return status; @@ -328,7 +464,6 @@ private: if (!ident_matches(&vl, match)) continue; - if (uc_iterator_get_time(iter, &vl.time) < 0) { status = grpc::Status(grpc::StatusCode::INTERNAL, @@ -346,6 +481,10 @@ private: grpc::string("failed to retrieve values")); break; } + if (uc_iterator_get_meta(iter, &vl.meta) < 0) { + status = grpc::Status(grpc::StatusCode::INTERNAL, + grpc::string("failed to retrieve value metadata")); + } value_lists->push(vl); } // while (uc_iterator_next(iter, &name) == 0) diff --git a/src/hddtemp.c b/src/hddtemp.c index 3af9c0fa..a7eaf369 100644 --- a/src/hddtemp.c +++ b/src/hddtemp.c @@ -214,7 +214,7 @@ static int hddtemp_config(const char *key, const char *value) { } else if (strcasecmp(key, "Port") == 0) { int port = (int)(atof(value)); if ((port > 0) && (port <= 65535)) - ssnprintf(hddtemp_port, sizeof(hddtemp_port), "%i", port); + snprintf(hddtemp_port, sizeof(hddtemp_port), "%i", port); else sstrncpy(hddtemp_port, value, sizeof(hddtemp_port)); } else { diff --git a/src/hugepages.c b/src/hugepages.c index 871e625f..c5b0ecb9 100644 --- a/src/hugepages.c +++ b/src/hugepages.c @@ -87,11 +87,11 @@ static void submit_hp(const struct entry_info *info) { sstrncpy(vl.plugin, g_plugin_name, sizeof(vl.plugin)); if (info->node) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%zuKb", - info->node, info->page_size_kb); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%zuKb", + info->node, info->page_size_kb); } else { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%zuKb", - info->page_size_kb); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%zuKb", + info->page_size_kb); } /* ensure all metrics have the same timestamp */ @@ -125,7 +125,7 @@ static int read_hugepage_entry(const char *path, const char *entry, struct entry_info *info = e_info; double value; - ssnprintf(path2, sizeof(path2), "%s/%s", path, entry); + snprintf(path2, sizeof(path2), "%s/%s", path, entry); FILE *fh = fopen(path2, "rt"); if (fh == NULL) { @@ -193,7 +193,7 @@ static int read_syshugepages(const char *path, const char *node) { } /* /sys/devices/system/node/node?/hugepages/ */ - ssnprintf(path2, sizeof(path2), "%s/%s", path, result->d_name); + snprintf(path2, sizeof(path2), "%s/%s", path, result->d_name); walk_directory(path2, read_hugepage_entry, &(struct entry_info){ @@ -238,7 +238,7 @@ static int read_nodes(void) { continue; } - ssnprintf(path, sizeof(path), sys_node_hugepages, result->d_name); + snprintf(path, sizeof(path), sys_node_hugepages, result->d_name); read_syshugepages(path, result->d_name); errno = 0; } diff --git a/src/intel_pmu.c b/src/intel_pmu.c new file mode 100644 index 00000000..e5f19cee --- /dev/null +++ b/src/intel_pmu.c @@ -0,0 +1,566 @@ +/** + * collectd - src/intel_pmu.c + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Serhiy Pshyk + **/ + +#include "collectd.h" +#include "common.h" + +#include +#include + +#define PMU_PLUGIN "intel_pmu" + +#define HW_CACHE_READ_ACCESS \ + (((PERF_COUNT_HW_CACHE_OP_READ) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_ACCESS) << 16)) + +#define HW_CACHE_WRITE_ACCESS \ + (((PERF_COUNT_HW_CACHE_OP_WRITE) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_ACCESS) << 16)) + +#define HW_CACHE_PREFETCH_ACCESS \ + (((PERF_COUNT_HW_CACHE_OP_PREFETCH) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_ACCESS) << 16)) + +#define HW_CACHE_READ_MISS \ + (((PERF_COUNT_HW_CACHE_OP_READ) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) + +#define HW_CACHE_WRITE_MISS \ + (((PERF_COUNT_HW_CACHE_OP_WRITE) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) + +#define HW_CACHE_PREFETCH_MISS \ + (((PERF_COUNT_HW_CACHE_OP_PREFETCH) << 8) | \ + ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) + +struct event_info { + char *name; + uint64_t config; +}; +typedef struct event_info event_info_t; + +struct intel_pmu_ctx_s { + _Bool hw_cache_events; + _Bool kernel_pmu_events; + _Bool sw_events; + char event_list_fn[PATH_MAX]; + char **hw_events; + size_t hw_events_count; + struct eventlist *event_list; +}; +typedef struct intel_pmu_ctx_s intel_pmu_ctx_t; + +event_info_t g_kernel_pmu_events[] = { + {.name = "cpu-cycles", .config = PERF_COUNT_HW_CPU_CYCLES}, + {.name = "instructions", .config = PERF_COUNT_HW_INSTRUCTIONS}, + {.name = "cache-references", .config = PERF_COUNT_HW_CACHE_REFERENCES}, + {.name = "cache-misses", .config = PERF_COUNT_HW_CACHE_MISSES}, + {.name = "branches", .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS}, + {.name = "branch-misses", .config = PERF_COUNT_HW_BRANCH_MISSES}, + {.name = "bus-cycles", .config = PERF_COUNT_HW_BUS_CYCLES}, +}; + +event_info_t g_hw_cache_events[] = { + + {.name = "L1-dcache-loads", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_READ_ACCESS)}, + {.name = "L1-dcache-load-misses", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_READ_MISS)}, + {.name = "L1-dcache-stores", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_WRITE_ACCESS)}, + {.name = "L1-dcache-store-misses", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_WRITE_MISS)}, + {.name = "L1-dcache-prefetches", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_PREFETCH_ACCESS)}, + {.name = "L1-dcache-prefetch-misses", + .config = (PERF_COUNT_HW_CACHE_L1D | HW_CACHE_PREFETCH_MISS)}, + + {.name = "L1-icache-loads", + .config = (PERF_COUNT_HW_CACHE_L1I | HW_CACHE_READ_ACCESS)}, + {.name = "L1-icache-load-misses", + .config = (PERF_COUNT_HW_CACHE_L1I | HW_CACHE_READ_MISS)}, + {.name = "L1-icache-prefetches", + .config = (PERF_COUNT_HW_CACHE_L1I | HW_CACHE_PREFETCH_ACCESS)}, + {.name = "L1-icache-prefetch-misses", + .config = (PERF_COUNT_HW_CACHE_L1I | HW_CACHE_PREFETCH_MISS)}, + + {.name = "LLC-loads", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_READ_ACCESS)}, + {.name = "LLC-load-misses", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_READ_MISS)}, + {.name = "LLC-stores", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_WRITE_ACCESS)}, + {.name = "LLC-store-misses", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_WRITE_MISS)}, + {.name = "LLC-prefetches", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_PREFETCH_ACCESS)}, + {.name = "LLC-prefetch-misses", + .config = (PERF_COUNT_HW_CACHE_LL | HW_CACHE_PREFETCH_MISS)}, + + {.name = "dTLB-loads", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_READ_ACCESS)}, + {.name = "dTLB-load-misses", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_READ_MISS)}, + {.name = "dTLB-stores", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_WRITE_ACCESS)}, + {.name = "dTLB-store-misses", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_WRITE_MISS)}, + {.name = "dTLB-prefetches", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_PREFETCH_ACCESS)}, + {.name = "dTLB-prefetch-misses", + .config = (PERF_COUNT_HW_CACHE_DTLB | HW_CACHE_PREFETCH_MISS)}, + + {.name = "iTLB-loads", + .config = (PERF_COUNT_HW_CACHE_ITLB | HW_CACHE_READ_ACCESS)}, + {.name = "iTLB-load-misses", + .config = (PERF_COUNT_HW_CACHE_ITLB | HW_CACHE_READ_MISS)}, + + {.name = "branch-loads", + .config = (PERF_COUNT_HW_CACHE_BPU | HW_CACHE_READ_ACCESS)}, + {.name = "branch-load-misses", + .config = (PERF_COUNT_HW_CACHE_BPU | HW_CACHE_READ_MISS)}, +}; + +event_info_t g_sw_events[] = { + {.name = "cpu-clock", .config = PERF_COUNT_SW_CPU_CLOCK}, + + {.name = "task-clock", .config = PERF_COUNT_SW_TASK_CLOCK}, + + {.name = "context-switches", .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, + + {.name = "cpu-migrations", .config = PERF_COUNT_SW_CPU_MIGRATIONS}, + + {.name = "page-faults", .config = PERF_COUNT_SW_PAGE_FAULTS}, + + {.name = "minor-faults", .config = PERF_COUNT_SW_PAGE_FAULTS_MIN}, + + {.name = "major-faults", .config = PERF_COUNT_SW_PAGE_FAULTS_MAJ}, + + {.name = "alignment-faults", .config = PERF_COUNT_SW_ALIGNMENT_FAULTS}, + + {.name = "emulation-faults", .config = PERF_COUNT_SW_EMULATION_FAULTS}, +}; + +static intel_pmu_ctx_t g_ctx; + +#if COLLECT_DEBUG +static void pmu_dump_events() { + + DEBUG(PMU_PLUGIN ": Events:"); + + struct event *e; + + for (e = g_ctx.event_list->eventlist; e; e = e->next) { + DEBUG(PMU_PLUGIN ": event : %s", e->event); + DEBUG(PMU_PLUGIN ": group_lead: %d", e->group_leader); + DEBUG(PMU_PLUGIN ": end_group : %d", e->end_group); + DEBUG(PMU_PLUGIN ": type : %#x", e->attr.type); + DEBUG(PMU_PLUGIN ": config : %#x", (unsigned)e->attr.config); + DEBUG(PMU_PLUGIN ": size : %d", e->attr.size); + } +} + +static void pmu_dump_config(void) { + + DEBUG(PMU_PLUGIN ": Config:"); + DEBUG(PMU_PLUGIN ": hw_cache_events : %d", g_ctx.hw_cache_events); + DEBUG(PMU_PLUGIN ": kernel_pmu_events : %d", g_ctx.kernel_pmu_events); + DEBUG(PMU_PLUGIN ": software_events : %d", g_ctx.sw_events); + + for (size_t i = 0; i < g_ctx.hw_events_count; i++) { + DEBUG(PMU_PLUGIN ": hardware_events[%zu]: %s", i, g_ctx.hw_events[i]); + } +} + +#endif /* COLLECT_DEBUG */ + +static int pmu_config_hw_events(oconfig_item_t *ci) { + + if (strcasecmp("HardwareEvents", ci->key) != 0) { + return -EINVAL; + } + + g_ctx.hw_events = calloc(ci->values_num, sizeof(char *)); + if (g_ctx.hw_events == NULL) { + ERROR(PMU_PLUGIN ": Failed to allocate hw events."); + return -ENOMEM; + } + + for (int i = 0; i < ci->values_num; i++) { + if (ci->values[i].type != OCONFIG_TYPE_STRING) { + WARNING(PMU_PLUGIN ": The %s option requires string arguments.", ci->key); + continue; + } + + g_ctx.hw_events[g_ctx.hw_events_count] = strdup(ci->values[i].value.string); + if (g_ctx.hw_events[g_ctx.hw_events_count] == NULL) { + ERROR(PMU_PLUGIN ": Failed to allocate hw events entry."); + return -ENOMEM; + } + + g_ctx.hw_events_count++; + } + + return 0; +} + +static int pmu_config(oconfig_item_t *ci) { + + DEBUG(PMU_PLUGIN ": %s:%d", __FUNCTION__, __LINE__); + + for (int i = 0; i < ci->children_num; i++) { + int ret = 0; + oconfig_item_t *child = ci->children + i; + + if (strcasecmp("ReportHardwareCacheEvents", child->key) == 0) { + ret = cf_util_get_boolean(child, &g_ctx.hw_cache_events); + } else if (strcasecmp("ReportKernelPMUEvents", child->key) == 0) { + ret = cf_util_get_boolean(child, &g_ctx.kernel_pmu_events); + } else if (strcasecmp("EventList", child->key) == 0) { + ret = cf_util_get_string_buffer(child, g_ctx.event_list_fn, + sizeof(g_ctx.event_list_fn)); + } else if (strcasecmp("HardwareEvents", child->key) == 0) { + ret = pmu_config_hw_events(child); + } else if (strcasecmp("ReportSoftwareEvents", child->key) == 0) { + ret = cf_util_get_boolean(child, &g_ctx.sw_events); + } else { + ERROR(PMU_PLUGIN ": Unknown configuration parameter \"%s\".", child->key); + ret = -1; + } + + if (ret != 0) { + DEBUG(PMU_PLUGIN ": %s:%d ret=%d", __FUNCTION__, __LINE__, ret); + return ret; + } + } + +#if COLLECT_DEBUG + pmu_dump_config(); +#endif + + return 0; +} + +static void pmu_submit_counter(int cpu, char *event, counter_t value) { + value_list_t vl = VALUE_LIST_INIT; + + vl.values = &(value_t){.counter = value}; + vl.values_len = 1; + + sstrncpy(vl.plugin, PMU_PLUGIN, sizeof(vl.plugin)); + if (cpu == -1) { + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "all"); + } else { + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%d", cpu); + } + sstrncpy(vl.type, "counter", sizeof(vl.type)); + sstrncpy(vl.type_instance, event, sizeof(vl.type_instance)); + + plugin_dispatch_values(&vl); +} + +static void pmu_dispatch_data(void) { + + struct event *e; + + for (e = g_ctx.event_list->eventlist; e; e = e->next) { + uint64_t all_value = 0; + int event_enabled = 0; + for (int i = 0; i < g_ctx.event_list->num_cpus; i++) { + + if (e->efd[i].fd < 0) + continue; + + event_enabled++; + + uint64_t value = event_scaled_value(e, i); + all_value += value; + + /* dispatch per CPU value */ + pmu_submit_counter(i, e->event, value); + } + + if (event_enabled > 0) { + DEBUG(PMU_PLUGIN ": %-20s %'10lu", e->event, all_value); + /* dispatch all CPU value */ + pmu_submit_counter(-1, e->event, all_value); + } + } +} + +static int pmu_read(__attribute__((unused)) user_data_t *ud) { + int ret; + + DEBUG(PMU_PLUGIN ": %s:%d", __FUNCTION__, __LINE__); + + ret = read_all_events(g_ctx.event_list); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to read values of all events."); + return ret; + } + + pmu_dispatch_data(); + + return 0; +} + +static int pmu_add_events(struct eventlist *el, uint32_t type, + event_info_t *events, size_t count) { + + for (size_t i = 0; i < count; i++) { + /* Allocate memory for event struct that contains array of efd structs + for all cores */ + struct event *e = + calloc(sizeof(struct event) + sizeof(struct efd) * el->num_cpus, 1); + if (e == NULL) { + ERROR(PMU_PLUGIN ": Failed to allocate event structure"); + return -ENOMEM; + } + + e->attr.type = type; + e->attr.config = events[i].config; + e->attr.size = PERF_ATTR_SIZE_VER0; + if (!el->eventlist) + el->eventlist = e; + if (el->eventlist_last) + el->eventlist_last->next = e; + el->eventlist_last = e; + e->event = strdup(events[i].name); + } + + return 0; +} + +static int pmu_add_hw_events(struct eventlist *el, char **e, size_t count) { + + for (size_t i = 0; i < count; i++) { + + size_t group_events_count = 0; + + char *events = strdup(e[i]); + if (!events) + return -1; + + char *s, *tmp; + for (s = strtok_r(events, ",", &tmp); s; s = strtok_r(NULL, ",", &tmp)) { + + /* Multiple events parsed in one entry */ + if (group_events_count == 1) { + /* Mark previously added event as group leader */ + el->eventlist_last->group_leader = 1; + } + + /* Allocate memory for event struct that contains array of efd structs + for all cores */ + struct event *e = + calloc(sizeof(struct event) + sizeof(struct efd) * el->num_cpus, 1); + if (e == NULL) { + free(events); + return -ENOMEM; + } + + if (resolve_event(s, &e->attr) == 0) { + e->next = NULL; + if (!el->eventlist) + el->eventlist = e; + if (el->eventlist_last) + el->eventlist_last->next = e; + el->eventlist_last = e; + e->event = strdup(s); + } else { + DEBUG(PMU_PLUGIN ": Cannot resolve %s", s); + sfree(e); + } + + group_events_count++; + } + + /* Multiple events parsed in one entry */ + if (group_events_count > 1) { + /* Mark last added event as group end */ + el->eventlist_last->end_group = 1; + } + + free(events); + } + + return 0; +} + +static void pmu_free_events(struct eventlist *el) { + + if (el == NULL) + return; + + struct event *e = el->eventlist; + + while (e) { + struct event *next = e->next; + sfree(e); + e = next; + } + + el->eventlist = NULL; +} + +static int pmu_setup_events(struct eventlist *el, bool measure_all, + int measure_pid) { + struct event *e, *leader = NULL; + int ret = -1; + + for (e = el->eventlist; e; e = e->next) { + + for (int i = 0; i < el->num_cpus; i++) { + if (setup_event(e, i, leader, measure_all, measure_pid) < 0) { + WARNING(PMU_PLUGIN ": perf event '%s' is not available (cpu=%d).", + e->event, i); + } else { + /* success if at least one event was set */ + ret = 0; + } + } + + if (e->group_leader) + leader = e; + if (e->end_group) + leader = NULL; + } + + return ret; +} + +static int pmu_init(void) { + int ret; + + DEBUG(PMU_PLUGIN ": %s:%d", __FUNCTION__, __LINE__); + + g_ctx.event_list = alloc_eventlist(); + if (g_ctx.event_list == NULL) { + ERROR(PMU_PLUGIN ": Failed to allocate event list."); + return -ENOMEM; + } + + if (g_ctx.hw_cache_events) { + ret = + pmu_add_events(g_ctx.event_list, PERF_TYPE_HW_CACHE, g_hw_cache_events, + STATIC_ARRAY_SIZE(g_hw_cache_events)); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to add hw cache events."); + goto init_error; + } + } + + if (g_ctx.kernel_pmu_events) { + ret = pmu_add_events(g_ctx.event_list, PERF_TYPE_HARDWARE, + g_kernel_pmu_events, + STATIC_ARRAY_SIZE(g_kernel_pmu_events)); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to add kernel PMU events."); + goto init_error; + } + } + + /* parse events names if config option is present and is not empty */ + if (g_ctx.hw_events_count) { + + ret = read_events(g_ctx.event_list_fn); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to read event list file '%s'.", + g_ctx.event_list_fn); + return ret; + } + + ret = pmu_add_hw_events(g_ctx.event_list, g_ctx.hw_events, + g_ctx.hw_events_count); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to add hardware events."); + goto init_error; + } + } + + if (g_ctx.sw_events) { + ret = pmu_add_events(g_ctx.event_list, PERF_TYPE_SOFTWARE, g_sw_events, + STATIC_ARRAY_SIZE(g_sw_events)); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to add software events."); + goto init_error; + } + } + +#if COLLECT_DEBUG + pmu_dump_events(); +#endif + + if (g_ctx.event_list->eventlist != NULL) { + /* measure all processes */ + ret = pmu_setup_events(g_ctx.event_list, true, -1); + if (ret != 0) { + ERROR(PMU_PLUGIN ": Failed to setup perf events for the event list."); + goto init_error; + } + } else { + WARNING(PMU_PLUGIN + ": Events list is empty. No events were setup for monitoring."); + } + + return 0; + +init_error: + + pmu_free_events(g_ctx.event_list); + sfree(g_ctx.event_list); + for (size_t i = 0; i < g_ctx.hw_events_count; i++) { + sfree(g_ctx.hw_events[i]); + } + sfree(g_ctx.hw_events); + g_ctx.hw_events_count = 0; + + + return ret; +} + +static int pmu_shutdown(void) { + + DEBUG(PMU_PLUGIN ": %s:%d", __FUNCTION__, __LINE__); + + pmu_free_events(g_ctx.event_list); + sfree(g_ctx.event_list); + for (size_t i = 0; i < g_ctx.hw_events_count; i++) { + sfree(g_ctx.hw_events[i]); + } + sfree(g_ctx.hw_events); + g_ctx.hw_events_count = 0; + + return 0; +} + +void module_register(void) { + plugin_register_init(PMU_PLUGIN, pmu_init); + plugin_register_complex_config(PMU_PLUGIN, pmu_config); + plugin_register_complex_read(NULL, PMU_PLUGIN, pmu_read, 0, NULL); + plugin_register_shutdown(PMU_PLUGIN, pmu_shutdown); +} diff --git a/src/intel_rdt.c b/src/intel_rdt.c index 7966daa5..a3f77c97 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -375,7 +375,7 @@ static int rdt_default_cgroups(void) { char desc[DATA_MAX_NAME_LEN]; uint64_t core = i; - ssnprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore); + snprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore); /* set core group info */ ret = cgroup_set(&g_rdt->cgroups[i], desc, &core, 1); @@ -656,7 +656,7 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) { static int rdt_init(void) { int ret; - if(g_state == CONFIGURATION_ERROR) + if (g_state == CONFIGURATION_ERROR) return -1; ret = rdt_preinit(); diff --git a/src/interface.c b/src/interface.c index 78a0d694..deba1860 100644 --- a/src/interface.c +++ b/src/interface.c @@ -296,8 +296,8 @@ static int interface_read(void) { continue; if (unique_name) - ssnprintf(iname, sizeof(iname), "%s_%d_%s", ksp[i]->ks_module, - ksp[i]->ks_instance, ksp[i]->ks_name); + snprintf(iname, sizeof(iname), "%s_%d_%s", ksp[i]->ks_module, + ksp[i]->ks_instance, ksp[i]->ks_name); else sstrncpy(iname, ksp[i]->ks_name, sizeof(iname)); diff --git a/src/ipc.c b/src/ipc.c index 432c5e08..ed8a0c01 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/ipmi.c b/src/ipmi.c index 98e77bfe..c8c80429 100644 --- a/src/ipmi.c +++ b/src/ipmi.c @@ -83,7 +83,7 @@ static void c_ipmi_error(const char *func, int status) { } if (errbuf[0] == 0) { - ssnprintf(errbuf, sizeof(errbuf), "Unknown error %#x", status); + snprintf(errbuf, sizeof(errbuf), "Unknown error %#x", status); } errbuf[sizeof(errbuf) - 1] = 0; @@ -123,8 +123,8 @@ static void sensor_read_handler(ipmi_sensor_t *sensor, int err, sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance)); sstrncpy(n.type, list_item->sensor_type, sizeof(n.type)); - ssnprintf(n.message, sizeof(n.message), "sensor %s not present", - list_item->sensor_name); + snprintf(n.message, sizeof(n.message), "sensor %s not present", + list_item->sensor_name); plugin_dispatch_notification(&n); } @@ -172,8 +172,8 @@ static void sensor_read_handler(ipmi_sensor_t *sensor, int err, sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance)); sstrncpy(n.type, list_item->sensor_type, sizeof(n.type)); - ssnprintf(n.message, sizeof(n.message), "sensor %s present", - list_item->sensor_name); + snprintf(n.message, sizeof(n.message), "sensor %s present", + list_item->sensor_name); plugin_dispatch_notification(&n); } @@ -223,8 +223,8 @@ static int sensor_list_add(ipmi_sensor_t *sensor) { if (entity_id_string == NULL) sstrncpy(sensor_name, buffer, sizeof(sensor_name)); else - ssnprintf(sensor_name, sizeof(sensor_name), "%s %s", buffer, - entity_id_string); + snprintf(sensor_name, sizeof(sensor_name), "%s %s", buffer, + entity_id_string); sstrncpy(buffer, sensor_name, sizeof(buffer)); sensor_name_ptr = strstr(buffer, ")."); @@ -244,8 +244,8 @@ static int sensor_list_add(ipmi_sensor_t *sensor) { sensor_id_ptr = strstr(buffer, "("); if (sensor_id_ptr != NULL) { /* `sensor_id_ptr' now points to "(123)". */ - ssnprintf(sensor_name, sizeof(sensor_name), "%s %s", sensor_name_ptr, - sensor_id_ptr); + snprintf(sensor_name, sizeof(sensor_name), "%s %s", sensor_name_ptr, + sensor_id_ptr); } /* else: don't touch sensor_name. */ } @@ -327,8 +327,8 @@ static int sensor_list_add(ipmi_sensor_t *sensor) { sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance)); sstrncpy(n.type, list_item->sensor_type, sizeof(n.type)); - ssnprintf(n.message, sizeof(n.message), "sensor %s added", - list_item->sensor_name); + snprintf(n.message, sizeof(n.message), "sensor %s added", + list_item->sensor_name); plugin_dispatch_notification(&n); } @@ -375,8 +375,8 @@ static int sensor_list_remove(ipmi_sensor_t *sensor) { sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance)); sstrncpy(n.type, list_item->sensor_type, sizeof(n.type)); - ssnprintf(n.message, sizeof(n.message), "sensor %s removed", - list_item->sensor_name); + snprintf(n.message, sizeof(n.message), "sensor %s removed", + list_item->sensor_name); plugin_dispatch_notification(&n); } diff --git a/src/iptables.c b/src/iptables.c index 1d127bf7..286c6e9b 100644 --- a/src/iptables.c +++ b/src/iptables.c @@ -101,7 +101,7 @@ static int iptables_config(const char *key, const char *value) { return 1; ip_chain_t temp = {0}; - ip_chain_t * final, **list; + ip_chain_t *final, **list; char *table; int table_len; char *chain; @@ -189,7 +189,7 @@ static int iptables_config(const char *key, const char *value) { } chain_list = list; - final = malloc(sizeof(* final)); + final = malloc(sizeof(*final)); if (final == NULL) { char errbuf[1024]; ERROR("malloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); @@ -226,8 +226,8 @@ static int submit6_match(const struct ip6t_entry_match *match, sstrncpy(vl.plugin, "ip6tables", sizeof(vl.plugin)); - status = ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", - chain->table, chain->chain); + status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", + chain->table, chain->chain); if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance))) return 0; @@ -235,8 +235,8 @@ static int submit6_match(const struct ip6t_entry_match *match, sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance)); } else { if (chain->rule_type == RTYPE_NUM) - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%i", - chain->rule.num); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%i", + chain->rule.num); else sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance)); } @@ -274,8 +274,8 @@ static int submit_match(const struct ipt_entry_match *match, sstrncpy(vl.plugin, "iptables", sizeof(vl.plugin)); - status = ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", - chain->table, chain->chain); + status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", + chain->table, chain->chain); if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance))) return 0; @@ -283,8 +283,8 @@ static int submit_match(const struct ipt_entry_match *match, sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance)); } else { if (chain->rule_type == RTYPE_NUM) - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%i", - chain->rule.num); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%i", + chain->rule.num); else sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance)); } diff --git a/src/ipvs.c b/src/ipvs.c index da67970d..3d399bd5 100644 --- a/src/ipvs.c +++ b/src/ipvs.c @@ -172,8 +172,8 @@ static int get_pi(struct ip_vs_service_entry *se, char *pi, size_t size) { struct in_addr addr = {.s_addr = se->addr}; int len = - ssnprintf(pi, size, "%s_%s%u", inet_ntoa(addr), - (se->protocol == IPPROTO_TCP) ? "TCP" : "UDP", ntohs(se->port)); + snprintf(pi, size, "%s_%s%u", inet_ntoa(addr), + (se->protocol == IPPROTO_TCP) ? "TCP" : "UDP", ntohs(se->port)); if ((len < 0) || (size <= ((size_t)len))) { log_err("plugin instance truncated: %s", pi); @@ -189,7 +189,7 @@ static int get_ti(struct ip_vs_dest_entry *de, char *ti, size_t size) { struct in_addr addr = {.s_addr = de->addr}; - int len = ssnprintf(ti, size, "%s_%u", inet_ntoa(addr), ntohs(de->port)); + int len = snprintf(ti, size, "%s_%u", inet_ntoa(addr), ntohs(de->port)); if ((len < 0) || (size <= ((size_t)len))) { log_err("type instance truncated: %s", ti); diff --git a/src/java.c b/src/java.c index e3d3442a..c7b0be3d 100644 --- a/src/java.c +++ b/src/java.c @@ -1213,9 +1213,9 @@ static int jtoc_notification(JNIEnv *jvm_env, notification_t *n, /* {{{ */ return 0; } /* }}} int jtoc_notification */ - /* - * Functions accessible from Java - */ +/* + * Functions accessible from Java + */ static jint JNICALL cjni_api_dispatch_values(JNIEnv *jvm_env, /* {{{ */ jobject this, jobject java_vl) { value_list_t vl = VALUE_LIST_INIT; diff --git a/src/libcollectdclient/client.c b/src/libcollectdclient/client.c index c3cd414f..d4703245 100644 --- a/src/libcollectdclient/client.c +++ b/src/libcollectdclient/client.c @@ -24,9 +24,7 @@ * Florian octo Forster **/ -#if HAVE_CONFIG_H #include "config.h" -#endif #if !defined(__GNUC__) || !__GNUC__ #define __attribute__(x) /**/ @@ -92,7 +90,6 @@ #define LCC_SET_ERRSTR(c, ...) \ do { \ snprintf((c)->errbuf, sizeof((c)->errbuf), __VA_ARGS__); \ - (c)->errbuf[sizeof((c)->errbuf) - 1] = 0; \ } while (0) /* @@ -100,7 +97,7 @@ */ struct lcc_connection_s { FILE *fh; - char errbuf[1024]; + char errbuf[2048]; }; struct lcc_response_s { diff --git a/src/libcollectdclient/collectd/client.h b/src/libcollectdclient/collectd/client.h index 8604ff6b..ea812c1b 100644 --- a/src/libcollectdclient/collectd/client.h +++ b/src/libcollectdclient/collectd/client.h @@ -27,7 +27,8 @@ #ifndef LIBCOLLECTD_COLLECTDCLIENT_H #define LIBCOLLECTD_COLLECTDCLIENT_H 1 -#include "lcc_features.h" +#include "collectd/lcc_features.h" +#include "collectd/types.h" /* COLLECTD_TRACE is the environment variable used to control trace output. When * set to something non-zero, all lines sent to / received from the daemon are @@ -39,62 +40,12 @@ /* * Includes (for data types) */ -#include #include +#include #include -/* - * Defines - */ -#define LCC_NAME_LEN 64 -#define LCC_DEFAULT_PORT "25826" - -/* - * Types - */ -#define LCC_TYPE_COUNTER 0 -#define LCC_TYPE_GAUGE 1 -#define LCC_TYPE_DERIVE 2 -#define LCC_TYPE_ABSOLUTE 3 - LCC_BEGIN_DECLS -typedef uint64_t counter_t; -typedef double gauge_t; -typedef uint64_t derive_t; -typedef uint64_t absolute_t; - -union value_u { - counter_t counter; - gauge_t gauge; - derive_t derive; - absolute_t absolute; -}; -typedef union value_u value_t; - -struct lcc_identifier_s { - char host[LCC_NAME_LEN]; - char plugin[LCC_NAME_LEN]; - char plugin_instance[LCC_NAME_LEN]; - char type[LCC_NAME_LEN]; - char type_instance[LCC_NAME_LEN]; -}; -typedef struct lcc_identifier_s lcc_identifier_t; -#define LCC_IDENTIFIER_INIT \ - { "localhost", "", "", "", "" } - -struct lcc_value_list_s { - value_t *values; - int *values_types; - size_t values_len; - double time; - double interval; - lcc_identifier_t identifier; -}; -typedef struct lcc_value_list_s lcc_value_list_t; -#define LCC_VALUE_LIST_INIT \ - { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT } - struct lcc_connection_s; typedef struct lcc_connection_s lcc_connection_t; diff --git a/src/libcollectdclient/collectd/network.h b/src/libcollectdclient/collectd/network.h index 35fd7d62..c8a5da54 100644 --- a/src/libcollectdclient/collectd/network.h +++ b/src/libcollectdclient/collectd/network.h @@ -27,11 +27,11 @@ #ifndef LIBCOLLECTDCLIENT_NETWORK_H #define LIBCOLLECTDCLIENT_NETWORK_H 1 +#include "collectd/client.h" + #include #include -#include "client.h" - #define NET_DEFAULT_V4_ADDR "239.192.74.66" #define NET_DEFAULT_V6_ADDR "ff18::efc0:4a42" #define NET_DEFAULT_PORT "25826" diff --git a/src/libcollectdclient/collectd/network_buffer.h b/src/libcollectdclient/collectd/network_buffer.h index 9f393103..d66b8155 100644 --- a/src/libcollectdclient/collectd/network_buffer.h +++ b/src/libcollectdclient/collectd/network_buffer.h @@ -27,9 +27,8 @@ #ifndef LIBCOLLECTDCLIENT_NETWORK_BUFFER_H #define LIBCOLLECTDCLIENT_NETWORK_BUFFER_H 1 -/* FIXME */ -#include "client.h" -#include "network.h" +#include "collectd/network.h" /* for lcc_security_level_t */ +#include "collectd/types.h" /* Ethernet frame - (IPv6 header + UDP header) */ #define LCC_NETWORK_BUFFER_SIZE_DEFAULT 1452 diff --git a/src/libcollectdclient/collectd/network_parse.h b/src/libcollectdclient/collectd/network_parse.h new file mode 100644 index 00000000..0cd9a792 --- /dev/null +++ b/src/libcollectdclient/collectd/network_parse.h @@ -0,0 +1,56 @@ +/** + * Copyright 2017 Florian Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#ifndef LIBCOLLECTD_NETWORK_PARSE_H +#define LIBCOLLECTD_NETWORK_PARSE_H 1 + +#include "collectd/lcc_features.h" + +#include "collectd/network.h" /* for lcc_security_level_t */ +#include "collectd/types.h" + +#include + +LCC_BEGIN_DECLS + +typedef struct { + /* writer is the callback used to send incoming lcc_value_list_t to. */ + lcc_value_list_writer_t writer; + + /* password_lookup is used to look up the password for a given username. */ + lcc_password_lookup_t password_lookup; + + /* security_level is the minimal required security level. */ + lcc_security_level_t security_level; +} lcc_network_parse_options_t; + +/* lcc_network_parse parses data received from the network and calls "w" with + * the parsed lcc_value_list_ts. */ +int lcc_network_parse(void *buffer, size_t buffer_size, + lcc_network_parse_options_t opts); + +LCC_END_DECLS + +#endif /* LIBCOLLECTD_NETWORK_PARSE_H */ diff --git a/src/libcollectdclient/collectd/server.h b/src/libcollectdclient/collectd/server.h new file mode 100644 index 00000000..ef6b792b --- /dev/null +++ b/src/libcollectdclient/collectd/server.h @@ -0,0 +1,88 @@ +/** + * Copyright 2017 Florian Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#ifndef LIBCOLLECTD_SERVER_H +#define LIBCOLLECTD_SERVER_H 1 + +#include "collectd/lcc_features.h" + +#include "collectd/network.h" /* for lcc_security_level_t */ +#include "collectd/network_parse.h" /* for lcc_network_parse_options_t */ +#include "collectd/types.h" + +#include + +#ifndef LCC_NETWORK_BUFFER_SIZE +#define LCC_NETWORK_BUFFER_SIZE 1452 +#endif + +LCC_BEGIN_DECLS + +/* lcc_network_parser_t is a callback that parses received network packets. It + * is expected to call lcc_network_parse_options_t.writer with each + * lcc_value_list_t it parses that has the required security level. */ +typedef int (*lcc_network_parser_t)(void *payload, size_t payload_size, + lcc_network_parse_options_t opts); + +/* lcc_listener_t holds parameters for running a collectd server. */ +typedef struct { + /* conn is a UDP socket for the server to listen on. If set to <0 node and + * service will be used to open a new UDP socket. If >=0, it is the caller's + * job to clean up the socket. */ + int conn; + + /* node is the local address to listen on if conn is <0. Defaults to "::" (any + * address). */ + char *node; + + /* service is the local address to listen on if conn is <0. Defaults to + * LCC_DEFAULT_PORT. */ + char *service; + + /* parser is the callback used to parse incoming network packets. Defaults to + * lcc_network_parse() if set to NULL. */ + lcc_network_parser_t parser; + + /* parse_options contains options for parser and is passed on verbatimely. */ + lcc_network_parse_options_t parse_options; + + /* buffer_size determines the maximum packet size to accept. Defaults to + * LCC_NETWORK_BUFFER_SIZE if set to zero. */ + uint16_t buffer_size; + + /* interface is the name of the interface to use when subscribing to a + * multicast group. Has no effect when using unicast. */ + char *interface; +} lcc_listener_t; + +/* lcc_listen_and_write listens on the provided UDP socket (or opens one using + * srv.addr if srv.conn is less than zero), parses the received packets and + * writes them to the provided lcc_value_list_writer_t. Returns non-zero on + * failure and does not return otherwise. */ +int lcc_listen_and_write(lcc_listener_t srv); + +LCC_END_DECLS + +#endif /* LIBCOLLECTD_SERVER_H */ diff --git a/src/libcollectdclient/collectd/types.h b/src/libcollectdclient/collectd/types.h new file mode 100644 index 00000000..7043e677 --- /dev/null +++ b/src/libcollectdclient/collectd/types.h @@ -0,0 +1,97 @@ +/** + * libcollectdclient - src/libcollectdclient/collectd/types.h + * Copyright (C) 2008-2017 Florian octo Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#ifndef LIBCOLLECTD_COLLECTD_TYPES_H +#define LIBCOLLECTD_COLLECTD_TYPES_H 1 + +#include "collectd/lcc_features.h" + +#include /* for uint64_t */ +#include /* for size_t */ + +/* + * Defines + */ +#define LCC_NAME_LEN 64 +#define LCC_DEFAULT_PORT "25826" + +/* + * Types + */ +#define LCC_TYPE_COUNTER 0 +#define LCC_TYPE_GAUGE 1 +#define LCC_TYPE_DERIVE 2 +#define LCC_TYPE_ABSOLUTE 3 + +LCC_BEGIN_DECLS + +typedef uint64_t counter_t; +typedef double gauge_t; +typedef uint64_t derive_t; +typedef uint64_t absolute_t; + +union value_u { + counter_t counter; + gauge_t gauge; + derive_t derive; + absolute_t absolute; +}; +typedef union value_u value_t; + +struct lcc_identifier_s { + char host[LCC_NAME_LEN]; + char plugin[LCC_NAME_LEN]; + char plugin_instance[LCC_NAME_LEN]; + char type[LCC_NAME_LEN]; + char type_instance[LCC_NAME_LEN]; +}; +typedef struct lcc_identifier_s lcc_identifier_t; +#define LCC_IDENTIFIER_INIT \ + { "localhost", "", "", "", "" } + +struct lcc_value_list_s { + value_t *values; + int *values_types; + size_t values_len; + double time; + double interval; + lcc_identifier_t identifier; +}; +typedef struct lcc_value_list_s lcc_value_list_t; +#define LCC_VALUE_LIST_INIT \ + { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT } + +/* lcc_value_list_writer_t is a write callback to which value lists are + * dispatched. */ +typedef int (*lcc_value_list_writer_t)(lcc_value_list_t const *); + +/* lcc_password_lookup_t is a callback for looking up the password for a given + * user. Must return NULL if the user is not known. */ +typedef char const *(*lcc_password_lookup_t)(char const *); + +LCC_END_DECLS + +#endif /* LIBCOLLECTD_COLLECTD_TYPES_H */ diff --git a/src/libcollectdclient/network_parse.c b/src/libcollectdclient/network_parse.c new file mode 100644 index 00000000..4083e1ec --- /dev/null +++ b/src/libcollectdclient/network_parse.c @@ -0,0 +1,623 @@ +/** + * Copyright 2017 Florian Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#include "config.h" + +#if !defined(__GNUC__) || !__GNUC__ +#define __attribute__(x) /**/ +#endif + +#include "collectd/lcc_features.h" +#include "collectd/network_parse.h" + +#include +#include +#include +#include +#include + +/* for be{16,64}toh */ +#if HAVE_ENDIAN_H +#include +#elif HAVE_SYS_ENDIAN_H +#include +#endif + +#if HAVE_GCRYPT_H +#define GCRYPT_NO_DEPRECATED +#include +#endif + +#include +#define DEBUG(...) printf(__VA_ARGS__) + +#if HAVE_GCRYPT_H +#if GCRYPT_VERSION_NUMBER < 0x010600 +GCRY_THREAD_OPTION_PTHREAD_IMPL; +#endif +#endif + +/* forward declaration because parse_sign_sha256()/parse_encrypt_aes256() and + * network_parse() need to call each other. */ +static int network_parse(void *data, size_t data_size, lcc_security_level_t sl, + lcc_network_parse_options_t const *opts); + +#if HAVE_GCRYPT_H +static int init_gcrypt() { + /* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html + * Because you can't know in a library whether another library has + * already initialized the library */ + if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) + return (0); + +/* http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html + * To ensure thread-safety, it's important to set GCRYCTL_SET_THREAD_CBS + * *before* initalizing Libgcrypt with gcry_check_version(), which itself must + * be called before any other gcry_* function. GCRYCTL_ANY_INITIALIZATION_P + * above doesn't count, as it doesn't implicitly initalize Libgcrypt. + * + * tl;dr: keep all these gry_* statements in this exact order please. */ +#if GCRYPT_VERSION_NUMBER < 0x010600 + if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)) { + return -1; + } +#endif + + gcry_check_version(NULL); + + if (gcry_control(GCRYCTL_INIT_SECMEM, 32768)) { + return -1; + } + + gcry_control(GCRYCTL_INITIALIZATION_FINISHED); + return 0; +} +#endif + +typedef struct { + uint8_t *data; + size_t len; +} buffer_t; + +static int buffer_next(buffer_t *b, void *out, size_t n) { + if (b->len < n) { + return -1; + } + memmove(out, b->data, n); + + b->data += n; + b->len -= n; + + return 0; +} + +static int buffer_uint16(buffer_t *b, uint16_t *out) { + uint16_t tmp; + if (buffer_next(b, &tmp, sizeof(tmp)) != 0) + return -1; + + *out = be16toh(tmp); + return 0; +} + +#define TYPE_HOST 0x0000 +#define TYPE_TIME 0x0001 +#define TYPE_TIME_HR 0x0008 +#define TYPE_PLUGIN 0x0002 +#define TYPE_PLUGIN_INSTANCE 0x0003 +#define TYPE_TYPE 0x0004 +#define TYPE_TYPE_INSTANCE 0x0005 +#define TYPE_VALUES 0x0006 +#define TYPE_INTERVAL 0x0007 +#define TYPE_INTERVAL_HR 0x0009 +#define TYPE_SIGN_SHA256 0x0200 +#define TYPE_ENCR_AES256 0x0210 + +static int parse_int(void *payload, size_t payload_size, uint64_t *out) { + uint64_t tmp; + + if (payload_size != sizeof(tmp)) + return EINVAL; + + memmove(&tmp, payload, sizeof(tmp)); + *out = be64toh(tmp); + return 0; +} + +static int parse_string(void *payload, size_t payload_size, char *out, + size_t out_size) { + char *in = payload; + + if ((payload_size < 1) || (in[payload_size - 1] != 0) || + (payload_size > out_size)) + return EINVAL; + + strncpy(out, in, out_size); + return 0; +} + +static int parse_identifier(uint16_t type, void *payload, size_t payload_size, + lcc_value_list_t *state) { + char buf[LCC_NAME_LEN]; + + if (parse_string(payload, payload_size, buf, sizeof(buf)) != 0) + return EINVAL; + + switch (type) { + case TYPE_HOST: + memmove(state->identifier.host, buf, LCC_NAME_LEN); + break; + case TYPE_PLUGIN: + memmove(state->identifier.plugin, buf, LCC_NAME_LEN); + break; + case TYPE_PLUGIN_INSTANCE: + memmove(state->identifier.plugin_instance, buf, LCC_NAME_LEN); + break; + case TYPE_TYPE: + memmove(state->identifier.type, buf, LCC_NAME_LEN); + break; + case TYPE_TYPE_INSTANCE: + memmove(state->identifier.type_instance, buf, LCC_NAME_LEN); + break; + default: + return EINVAL; + } + + return 0; +} + +static int parse_time(uint16_t type, void *payload, size_t payload_size, + lcc_value_list_t *state) { + uint64_t tmp = 0; + if (parse_int(payload, payload_size, &tmp)) + return EINVAL; + + double t = (double)tmp; + switch (type) { + case TYPE_INTERVAL: + state->interval = t; + break; + case TYPE_INTERVAL_HR: + state->interval = t / 1073741824.0; + break; + case TYPE_TIME: + state->time = t; + break; + case TYPE_TIME_HR: + state->time = t / 1073741824.0; + break; + default: + return EINVAL; + } + + return 0; +} + +static double ntohd(double val) /* {{{ */ +{ + static int config = 0; + + union { + uint8_t byte[8]; + double floating; + } in = { + .floating = val, + }; + union { + uint8_t byte[8]; + double floating; + } out = { + .byte = {0}, + }; + + if (config == 0) { + double d = 8.642135e130; + uint8_t b[8]; + + memcpy(b, &d, sizeof(b)); + + if ((b[0] == 0x2f) && (b[1] == 0x25) && (b[2] == 0xc0) && (b[3] == 0xc7) && + (b[4] == 0x43) && (b[5] == 0x2b) && (b[6] == 0x1f) && (b[7] == 0x5b)) + config = 1; /* need nothing */ + else if ((b[7] == 0x2f) && (b[6] == 0x25) && (b[5] == 0xc0) && + (b[4] == 0xc7) && (b[3] == 0x43) && (b[2] == 0x2b) && + (b[1] == 0x1f) && (b[0] == 0x5b)) + config = 2; /* endian flip */ + else if ((b[4] == 0x2f) && (b[5] == 0x25) && (b[6] == 0xc0) && + (b[7] == 0xc7) && (b[0] == 0x43) && (b[1] == 0x2b) && + (b[2] == 0x1f) && (b[3] == 0x5b)) + config = 3; /* int swap */ + else + config = 4; + } + + if (memcmp((char[]){0, 0, 0, 0, 0, 0, 0xf8, 0x7f}, in.byte, 8) == 0) { + return NAN; + } else if (config == 1) { + return val; + } else if (config == 2) { + in.floating = val; + out.byte[0] = in.byte[7]; + out.byte[1] = in.byte[6]; + out.byte[2] = in.byte[5]; + out.byte[3] = in.byte[4]; + out.byte[4] = in.byte[3]; + out.byte[5] = in.byte[2]; + out.byte[6] = in.byte[1]; + out.byte[7] = in.byte[0]; + return (out.floating); + } else if (config == 3) { + in.floating = val; + out.byte[0] = in.byte[4]; + out.byte[1] = in.byte[5]; + out.byte[2] = in.byte[6]; + out.byte[3] = in.byte[7]; + out.byte[4] = in.byte[0]; + out.byte[5] = in.byte[1]; + out.byte[6] = in.byte[2]; + out.byte[7] = in.byte[3]; + return out.floating; + } else { + /* If in doubt, just copy the value back to the caller. */ + return val; + } +} /* }}} double ntohd */ + +static int parse_values(void *payload, size_t payload_size, + lcc_value_list_t *state) { + buffer_t *b = &(buffer_t){ + .data = payload, .len = payload_size, + }; + + uint16_t n; + if (buffer_uint16(b, &n)) + return EINVAL; + + if (((size_t)n * 9) != b->len) + return EINVAL; + + state->values_len = (size_t)n; + state->values = calloc(sizeof(*state->values), state->values_len); + state->values_types = calloc(sizeof(*state->values_types), state->values_len); + if ((state->values == NULL) || (state->values_types == NULL)) { + free(state->values); + free(state->values_types); + return ENOMEM; + } + + for (uint16_t i = 0; i < n; i++) { + uint8_t tmp; + if (buffer_next(b, &tmp, sizeof(tmp))) + return EINVAL; + state->values_types[i] = (int)tmp; + } + + for (uint16_t i = 0; i < n; i++) { + uint64_t tmp; + if (buffer_next(b, &tmp, sizeof(tmp))) + return EINVAL; + + if (state->values_types[i] == LCC_TYPE_GAUGE) { + union { + uint64_t i; + double d; + } conv = {.i = tmp}; + state->values[i].gauge = ntohd(conv.d); + continue; + } + + tmp = be64toh(tmp); + switch (state->values_types[i]) { + case LCC_TYPE_COUNTER: + state->values[i].counter = (counter_t)tmp; + break; + case LCC_TYPE_DERIVE: + state->values[i].derive = (derive_t)tmp; + break; + case LCC_TYPE_ABSOLUTE: + state->values[i].absolute = (absolute_t)tmp; + break; + default: + return EINVAL; + } + } + + return 0; +} + +#if HAVE_GCRYPT_H +static int verify_sha256(void *payload, size_t payload_size, + char const *username, char const *password, + uint8_t hash_provided[32]) { + gcry_md_hd_t hd = NULL; + + gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); + if (err != 0) { + return (int)err; + } + + err = gcry_md_setkey(hd, password, strlen(password)); + if (err != 0) { + gcry_md_close(hd); + return (int)err; + } + + gcry_md_write(hd, username, strlen(username)); + gcry_md_write(hd, payload, payload_size); + + unsigned char *hash_calculated = gcry_md_read(hd, GCRY_MD_SHA256); + if (!hash_calculated) { + gcry_md_close(hd); + return -1; + } + + int ret = memcmp(hash_provided, hash_calculated, 32); + + gcry_md_close(hd); + hash_calculated = NULL; + + return !!ret; +} +#else /* !HAVE_GCRYPT_H */ +static int verify_sha256(void *payload, size_t payload_size, + char const *username, char const *password, + uint8_t hash_provided[32]) { + return ENOTSUP; +} +#endif + +static int parse_sign_sha256(void *signature, size_t signature_len, + void *payload, size_t payload_size, + lcc_network_parse_options_t const *opts) { + if (opts->password_lookup == NULL) { + /* The sender signed the packet but we can't verify it. Handle it as if it + * were unsigned, i.e. security level NONE. */ + return network_parse(payload, payload_size, NONE, opts); + } + + buffer_t *b = &(buffer_t){ + .data = signature, .len = signature_len, + }; + + uint8_t hash[32]; + if (buffer_next(b, hash, sizeof(hash))) + return EINVAL; + + char username[b->len + 1]; + memset(username, 0, sizeof(username)); + if (buffer_next(b, username, sizeof(username) - 1)) { + return EINVAL; + } + + char const *password = opts->password_lookup(username); + if (!password) + return network_parse(payload, payload_size, NONE, opts); + + int status = verify_sha256(payload, payload_size, username, password, hash); + if (status != 0) + return status; + + return network_parse(payload, payload_size, SIGN, opts); +} + +#if HAVE_GCRYPT_H +static int decrypt_aes256(buffer_t *b, void *iv, size_t iv_size, + char const *password) { + gcry_cipher_hd_t cipher = NULL; + + if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, + /* flags = */ 0)) + return -1; + + uint8_t pwhash[32] = {0}; + gcry_md_hash_buffer(GCRY_MD_SHA256, pwhash, password, strlen(password)); + + fprintf(stderr, "sizeof(iv) = %zu\n", sizeof(iv)); + if (gcry_cipher_setkey(cipher, pwhash, sizeof(pwhash)) || + gcry_cipher_setiv(cipher, iv, iv_size) || + gcry_cipher_decrypt(cipher, b->data, b->len, /* in = */ NULL, + /* in_size = */ 0)) { + gcry_cipher_close(cipher); + return -1; + } + + gcry_cipher_close(cipher); + return 0; +} + +static int parse_encrypt_aes256(void *data, size_t data_size, + lcc_network_parse_options_t const *opts) { + if (opts->password_lookup == NULL) { + /* Without a password source it's (hopefully) impossible to decrypt the + * network packet. */ + return ENOENT; + } + + buffer_t *b = &(buffer_t){ + .data = data, .len = data_size, + }; + + uint16_t username_len; + if (buffer_uint16(b, &username_len)) + return EINVAL; + if ((size_t)username_len > data_size) + return ENOMEM; + char username[((size_t)username_len) + 1]; + memset(username, 0, sizeof(username)); + if (buffer_next(b, username, (size_t)username_len)) + return EINVAL; + + char const *password = opts->password_lookup(username); + if (!password) + return ENOENT; + + uint8_t iv[16]; + if (buffer_next(b, iv, sizeof(iv))) + return EINVAL; + + int status = decrypt_aes256(b, iv, sizeof(iv), password); + if (status != 0) + return status; + + uint8_t hash_provided[20]; + if (buffer_next(b, hash_provided, sizeof(hash_provided))) { + return -1; + } + + uint8_t hash_calculated[20]; + gcry_md_hash_buffer(GCRY_MD_SHA1, hash_calculated, b->data, b->len); + + if (memcmp(hash_provided, hash_calculated, sizeof(hash_provided)) != 0) { + return -1; + } + + return network_parse(b->data, b->len, ENCRYPT, opts); +} +#else /* !HAVE_GCRYPT_H */ +static int parse_encrypt_aes256(void *data, size_t data_size, + lcc_network_parse_options_t const *opts) { + return ENOTSUP; +} +#endif + +static int network_parse(void *data, size_t data_size, lcc_security_level_t sl, + lcc_network_parse_options_t const *opts) { + buffer_t *b = &(buffer_t){ + .data = data, .len = data_size, + }; + + lcc_value_list_t state = {0}; + + while (b->len > 0) { + uint16_t type = 0, sz = 0; + if (buffer_uint16(b, &type) || buffer_uint16(b, &sz)) { + DEBUG("lcc_network_parse(): reading type and/or length failed.\n"); + return EINVAL; + } + + if ((sz < 5) || (((size_t)sz - 4) > b->len)) { + DEBUG("lcc_network_parse(): invalid 'sz' field: sz = %" PRIu16 + ", b->len = %zu\n", + sz, b->len); + return EINVAL; + } + sz -= 4; + + uint8_t payload[sz]; + if (buffer_next(b, payload, sizeof(payload))) + return EINVAL; + + switch (type) { + case TYPE_HOST: + case TYPE_PLUGIN: + case TYPE_PLUGIN_INSTANCE: + case TYPE_TYPE: + case TYPE_TYPE_INSTANCE: { + if (parse_identifier(type, payload, sizeof(payload), &state)) { + DEBUG("lcc_network_parse(): parse_identifier failed.\n"); + return EINVAL; + } + break; + } + + case TYPE_INTERVAL: + case TYPE_INTERVAL_HR: + case TYPE_TIME: + case TYPE_TIME_HR: { + if (parse_time(type, payload, sizeof(payload), &state)) { + DEBUG("lcc_network_parse(): parse_time failed.\n"); + return EINVAL; + } + break; + } + + case TYPE_VALUES: { + lcc_value_list_t vl = state; + if (parse_values(payload, sizeof(payload), &vl)) { + DEBUG("lcc_network_parse(): parse_values failed.\n"); + return EINVAL; + } + + int status = 0; + + /* Write metrics if they have the required security level. */ + if (sl >= opts->security_level) + status = opts->writer(&vl); + + free(vl.values); + free(vl.values_types); + + if (status != 0) + return status; + break; + } + + case TYPE_SIGN_SHA256: { + int status = + parse_sign_sha256(payload, sizeof(payload), b->data, b->len, opts); + if (status != 0) { + DEBUG("lcc_network_parse(): parse_sign_sha256() = %d\n", status); + return -1; + } + /* parse_sign_sha256, if successful, consumes all remaining data. */ + b->data = NULL; + b->len = 0; + break; + } + + case TYPE_ENCR_AES256: { + int status = parse_encrypt_aes256(payload, sizeof(payload), opts); + if (status != 0) { + DEBUG("lcc_network_parse(): parse_encrypt_aes256() = %d\n", status); + return -1; + } + break; + } + + default: { + DEBUG("lcc_network_parse(): ignoring unknown type %" PRIu16 "\n", type); + return EINVAL; + } + } + } + + return 0; +} + +int lcc_network_parse(void *data, size_t data_size, + lcc_network_parse_options_t opts) { + if (opts.password_lookup) { +#if HAVE_GCRYPT_H + int status; + if ((status = init_gcrypt())) { + return status; + } +#else + return ENOTSUP; +#endif + } + + return network_parse(data, data_size, NONE, &opts); +} diff --git a/src/libcollectdclient/network_parse_test.c b/src/libcollectdclient/network_parse_test.c new file mode 100644 index 00000000..9efd4bd8 --- /dev/null +++ b/src/libcollectdclient/network_parse_test.c @@ -0,0 +1,511 @@ +/** + * Copyright 2017 Florian Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#include "collectd/lcc_features.h" + +#include "collectd/network_buffer.h" /* for LCC_NETWORK_BUFFER_SIZE_DEFAULT */ + +#include + +#include "network_parse.c" /* sic */ + +char *raw_packet_data[] = { + "0000000e6c6f63616c686f7374000008000c1513676ac3a6e0970009000c00000002800000" + "000002000973776170000004000973776170000005000966726565000006000f0001010000" + "0080ff610f420008000c1513676ac3a8fc120004000c737761705f696f0000050007696e00" + "0006000f00010200000000000000000008000c1513676ac3a9077d000500086f7574000006" + "000f00010200000000000000000008000c1513676ac3bd2a8c0002000e696e746572666163" + "65000003000965746830000004000e69665f6f637465747300000500050000060018000202" + "02000000000000000000000000000000000008000c1513676ac3bd5a970004000e69665f65" + "72726f7273000006001800020202000000000000000000000000000000000008000c151367" + "6ac3bd7fea000300076c6f000004000e69665f6f6374657473000006001800020202000000" + "000009e79c000000000009e79c0008000c1513676ac3bdaae60003000a776c616e30000006" + "001800020202000000001009fa5400000000011cf6670008000c1513676ac3bdb0e0000400" + "0e69665f6572726f7273000006001800020202000000000000000000000000000000000008" + "000c1513676ac3bd3d6d0003000965746830000004000f69665f7061636b65747300000600" + "1800020202000000000000000000000000000000000008000c1513676ac3bdae290003000a" + "776c616e300000060018000202020000000000032f8f00000000000205e50008000c151367" + "6ac3bdbb7b0003000c646f636b657230000006001800020202000000000000000000000000" + "000000000008000c1513676ac3bda0db000300076c6f000004000e69665f6572726f727300" + "0006001800020202000000000000000000000000000000000008000c1513676ac3bdbde800" + "03000c646f636b657230000006001800020202000000000000000000000000000000000008" + "000c1513676ac3bd8d8e000300076c6f000004000f69665f7061636b657473000006001800" + "0202020000000000000c9c0000000000000c9c0008000c1513676ac3bdb90b0003000c646f" + "636b657230000004000e69665f6f6374657473000006001800020202000000000000000000" + "000000000000000008000c1513676ac469b10f0002000e70726f6365737365730000030005" + "000004000d70735f7374617465000005000c7a6f6d62696573000006000f00010100000000" + "000000000008000c1513676ac469a4a30005000d736c656570696e67000006000f00010100" + "00000000006e400008000c1513676ac469c6320005000b706167696e67000006000f000101" + "00000000000000000008000c1513676ac469f06e0005000c626c6f636b6564000006000f00" + "010100000000000000000008000c1513676ac4698af40005000c72756e6e696e6700000600" + "0f00010100000000000000000008000c1513676ac469bbe10005000c73746f707065640000" + "06000f00010100000000000000000008000c1513676ac46b8e710004000e666f726b5f7261" + "74650000050005000006000f0001020000000000001bcf0008000c1513676d437f12960002" + "00086370750000030006300000040008637075000005000b73797374656d000006000f0001" + "0200000000000021870008000c1513676d437f36020005000969646c65000006000f000102" + "000000000005847a0008000c1513676d437f979b0005000977616974000006000f00010200" + "000000000005210008000c1513676d43802ff60005000c736f6674697271000006000f0001" + "02000000000000001f0008000c1513676d43803b3a0005000a737465616c000006000f0001" + "020000000000000000", + "0000000e6c6f63616c686f7374000008000c1513676d4380551f0009000c00000002800000" + "00000200086370750000030006310000040008637075000005000975736572000006000f00" + "01020000000000007cad0008000c1513676d43805dbe000500096e696365000006000f0001" + "0200000000000001de0008000c1513676d4380697d0005000b73797374656d000006000f00" + "01020000000000001ce80008000c1513676d438072bd0005000969646c65000006000f0001" + "02000000000005931c0008000c1513676d43807c430005000977616974000006000f000102" + "000000000000094b0008000c1513676d43808cee0005000c736f6674697271000006000f00" + "010200000000000000120008000c1513676d4380843a0005000e696e746572727570740000" + "06000f00010200000000000000000008000c1513676d438096230005000a737465616c0000" + "06000f00010200000000000000000008000c1513676d4380aa9c0003000632000005000975" + "736572000006000f00010200000000000089580008000c1513676d4380b29f000500096e69" + "6365000006000f00010200000000000003610008000c1513676d4380c44c0005000969646c" + "65000006000f000102000000000005873d0008000c1513676d4380bc0f0005000b73797374" + "656d000006000f000102000000000000201d0008000c1513676d4380cea400050009776169" + "74000006000f00010200000000000005810008000c1513676d4380d7370005000e696e7465" + "7272757074000006000f00010200000000000000000008000c1513676d4380ea830005000a" + "737465616c000006000f00010200000000000000000008000c1513676d437eef6200030006" + "3000000500096e696365000006000f00010200000000000003920008000c1513676d4380e0" + "260003000632000005000c736f6674697271000006000f0001020000000000000016000800" + "0c1513676d438101410003000633000005000975736572000006000f000102000000000000" + "7d8a0008000c1513676d438109f5000500096e696365000006000f00010200000000000004" + "350008000c1513676d4380244b0003000630000005000e696e74657272757074000006000f" + "00010200000000000000000008000c1513676d438122070003000633000005000969646c65" + "000006000f0001020000000000058eb60008000c1513676d43812e83000500097761697400" + "0006000f0001020000000000000ca80008000c1513676d438141480005000c736f66746972" + "71000006000f000102000000000000001e0008000c1513676d43814a5d0005000a73746561" + "6c000006000f00010200000000000000000008000c1513676d4381149e0005000b73797374" + "656d000006000f0001020000000000001b9a0008000c1513676d437ea86000030006300000" + "05000975736572000006000f00010200000000000089a80008000c1513676d438138190003" + "000633000005000e696e74657272757074000006000f00010200000000000000000008000c" + "1513676d438a9ca00002000e696e74657266616365000003000965746830000004000e6966" + "5f6f6374657473000005000500000600180002020200000000000000000000000000000000" + "0008000c1513676d438aea760004000f69665f7061636b6574730000060018000202020000" + "00000000000000000000000000000008000c1513676d438b214d0004000e69665f6572726f" + "727300000600180002020200000000000000000000000000000000", + "0000000e6c6f63616c686f7374000008000c1513676d438aac590009000c00000002800000" + "000002000764660000030009726f6f74000004000f64665f636f6d706c6578000005000966" + "726565000006000f0001010000004c077e57420008000c1513676d438b6ada0005000d7265" + "736572766564000006000f00010100000000338116420008000c1513676d438b7a17000200" + "0e696e7465726661636500000300076c6f000004000e69665f6f6374657473000005000500" + "0006001800020202000000000009ecf5000000000009ecf50008000c1513676d438b757800" + "02000764660000030009726f6f74000004000f64665f636f6d706c65780000050009757365" + "64000006000f000101000000e0a41b26420008000c1513676d438b8ed20002000e696e7465" + "726661636500000300076c6f000004000e69665f6572726f72730000050005000006001800" + "020202000000000000000000000000000000000008000c1513676d438b86bf0004000f6966" + "5f7061636b6574730000060018000202020000000000000c9d0000000000000c9d0008000c" + "1513676d438bb3e60003000a776c616e300000060018000202020000000000032fab000000" + "00000205ed0008000c1513676d438bd62e0003000c646f636b657230000004000e69665f6f" + "6374657473000006001800020202000000000000000000000000000000000008000c151367" + "6d438bbc8f0003000a776c616e30000004000e69665f6572726f7273000006001800020202" + "000000000000000000000000000000000008000c1513676d438bdf030003000c646f636b65" + "7230000004000f69665f7061636b6574730000060018000202020000000000000000000000" + "00000000000008000c1513676d438baaf10003000a776c616e30000004000e69665f6f6374" + "65747300000600180002020200000000100a042300000000011cfa460008000c1513676d43" + "8c5f100002000764660000030009626f6f74000004000f64665f636f6d706c657800000500" + "0966726565000006000f0001010000000010e198410008000c1513676d438c689c0005000d" + "7265736572766564000006000f00010100000000804c68410008000c1513676d438c70ce00" + "05000975736564000006000f0001010000000020ea9e410008000c1513676d438be7bc0002" + "000e696e74657266616365000003000c646f636b657230000004000e69665f6572726f7273" + "0000050005000006001800020202000000000000000000000000000000000008000c151367" + "6d43beca8c0002000c656e74726f70790000030005000004000c656e74726f707900000600" + "0f0001010000000000088f400008000c1513676d43bf1d13000200096c6f61640000040009" + "6c6f6164000006002100030101019a9999999999a93f666666666666d63f5c8fc2f5285cdf" + "3f0008000c1513676d43c02b85000200096469736b00000300087364610000040010646973" + "6b5f6f63746574730000060018000202020000000075887800000000005b6f3c000008000c" + "1513676d43c06d1f0004000d6469736b5f6f7073000006001800020202000000000003cbbd" + "000000000001c0510008000c1513676d43c08b6a0004000e6469736b5f74696d6500000600" + "1800020202000000000000003f00000000000001720008000c1513676d43c0a5fb00040010" + "6469736b5f6d65726765640000060018000202020000000000001285000000000000f80100" + "08000c1513676d43c0c8b4000300097364613100000400106469736b5f6f63746574730000" + "060018000202020000000001107c000000000000003c00", + "0000000e6c6f63616c686f7374000008000c1513676d43c0d00a0009000c00000002800000" + "00000200096469736b000003000973646131000004000d6469736b5f6f7073000006001800" + "020202000000000000029b00000000000000080008000c1513676d43c0d7b20004000e6469" + "736b5f74696d650000060018000202020000000000000004000000000000000f0008000c15" + "13676d43c0df73000400106469736b5f6d6572676564000006001800020202000000000000" + "0fb400000000000000010008000c1513676d43c0f87c000300097364613200000400106469" + "736b5f6f637465747300000600180002020200000000000008000000000000000000000800" + "0c1513676d43c1003e0004000d6469736b5f6f707300000600180002020200000000000000" + "0200000000000000000008000c1513676d43c107bf000400106469736b5f6d657267656400" + "0006001800020202000000000000000000000000000000000008000c1513676d43c12fa400" + "03000973646135000004000d6469736b5f6f7073000006001800020202000000000003c867" + "000000000001aef20008000c1513676d43c13d5e000400106469736b5f6d65726765640000" + "0600180002020200000000000002d1000000000000f8000008000c1513676d43c136a90004" + "000e6469736b5f74696d65000006001800020202000000000000003f000000000000011c00" + "08000c1513676d43c1740500030009646d2d3000000400106469736b5f6f63746574730000" + "060018000202020000000074596400000000005b6f00000008000c1513676d43c179c70004" + "000d6469736b5f6f7073000006001800020202000000000003cae4000000000002b0f30008" + "000c1513676d43c18abe000400106469736b5f6d6572676564000006001800020202000000" + "000000000000000000000000000008000c1513676d43c181b90004000e6469736b5f74696d" + "650000060018000202020000000000000040000000000000013e0008000c1513676d43c1a9" + "5e00030009646d2d3100000400106469736b5f6f6374657473000006001800020202000000" + "00000e000000000000000000000008000c1513676d43c1b7ea0004000e6469736b5f74696d" + "65000006001800020202000000000000000200000000000000000008000c1513676d43c1b0" + "3e0004000d6469736b5f6f707300000600180002020200000000000000e000000000000000" + "000008000c1513676d43c1c00d000400106469736b5f6d6572676564000006001800020202" + "000000000000000000000000000000000008000c1513676d43c12818000300097364613500" + "000400106469736b5f6f637465747300000600180002020200000000746c6400000000005b" + "6f00000008000c1513676d43d320a80002000c62617474657279000003000630000004000b" + "636861726765000006000f0001018fc2f5285c2f58400008000c1513676d43d36fd6000400" + "0c63757272656e74000006000f00010100000000000000800008000c1513676d43d3cdb600" + "04000c766f6c74616765000006000f000101736891ed7cbf28400008000c1513676d43d59d" + "d60002000869727100000300050000040008697271000005000630000006000f0001020000" + "0000000000110008000c1513676d43d5d2cf0005000631000006000f000102000000000000" + "00100008000c1513676d43d5fe820005000638000006000f00010200000000000000010008" + "000c1513676d43d635440005000639000006000f00010200000000000035210008000c1513" + "676d43d66265000500073132000006000f0001020000000000000790", + "0000000e6c6f63616c686f7374000008000c1513676d43d68e940009000c00000002800000" + "0000020008697271000004000869727100000500073136000006000f000102000000000000" + "00210008000c1513676d43d69be20002000a7573657273000004000a757365727300000500" + "05000006000f00010100000000000010400008000c1513676d43d6aa5d0002000869727100" + "0004000869727100000500073233000006000f00010200000000000000250008000c151367" + "6d43d6c7dc000500073431000006000f000102000000000000ff7d0008000c1513676d43d6" + "e23d000500073432000006000f00010200000000000008070008000c1513676d43d9aa3a00" + "0500073437000006000f0001020000000000079a260008000c1513676d43d9cca900050007" + "3438000006000f00010200000000000000c70008000c1513676d43d9ea5d00050007343900" + "0006000f00010200000000000004c20008000c1513676d43da050e00050007353000000600" + "0f000102000000000000001c0008000c1513676d43da1efa000500084e4d49000006000f00" + "010200000000000000000008000c1513676d43da3c82000500084c4f43000006000f000102" + "000000000018d3080008000c1513676d43da544e00050008535055000006000f0001020000" + "0000000000000008000c1513676d43da6cca00050008504d49000006000f00010200000000" + "000000000008000c1513676d43da885400050008495749000006000f000102000000000000" + "a9da0008000c1513676d43daa23a00050008525452000006000f0001020000000000000003" + "0008000c1513676d43dabaed00050008524553000006000f00010200000000000ac8360008" + "000c1513676d43dad4150005000843414c000006000f000102000000000000191f0008000c" + "1513676d43daeef300050008544c42000006000f000102000000000003dbdc0008000c1513" + "676d43db11410005000854524d000006000f00010200000000000000000008000c1513676d" + "43db292c00050008544852000006000f00010200000000000000000008000c1513676d43db" + "411d000500084d4345000006000f00010200000000000000000008000c1513676d43db5b59" + "000500084d4350000006000f000102000000000000003c0008000c1513676d43db68010005" + "0008455252000006000f00010200000000000000000008000c1513676d43db758a00050008" + "4d4953000006000f00010200000000000000000008000c1513676d43dd2e800002000b6d65" + "6d6f7279000004000b6d656d6f7279000005000975736564000006000f00010100000000fe" + "bbe0410008000c1513676d43dd3f4b0005000d6275666665726564000006000f0001010000" + "000070fbc8410008000c1513676d43dd48700005000b636163686564000006000f00010100" + "000000c008df410008000c1513676d43dd51c60005000966726565000006000f0001010000" + "0080481d05420008000c1513676d43dec7e300020009737761700000040009737761700000" + "05000975736564000006000f00010100000000000000000008000c1513676d43ded4490005" + "000966726565000006000f00010100000080ff610f420008000c1513676d43dedcfd000500" + "0b636163686564000006000f00010100000000000000000008000c1513676d43d715e30002" + "0008697271000004000869727100000500073434000006000f0001020000000000031b6100" + "08000c1513676d43d73116000500073435000006000f00010200000000000000180008000c" + "1513676d43ee00150002000973776170000004000c737761705f696f0000050007696e0000" + "06000f0001020000000000000000", +}; + +static int decode_string(char const *in, uint8_t *out, size_t *out_size) { + size_t in_size = strlen(in); + if (*out_size < (in_size / 2)) + return -1; + *out_size = in_size / 2; + + for (size_t i = 0; i < *out_size; i++) { + char tmp[] = {in[2 * i], in[2 * i + 1], 0}; + out[i] = (uint8_t)strtoul(tmp, NULL, 16); + } + + return 0; +} + +static int nop_writer(lcc_value_list_t const *vl) { + if (!strlen(vl->identifier.host) || !strlen(vl->identifier.plugin) || + !strlen(vl->identifier.type)) { + return EINVAL; + } + return 0; +} + +static int test_network_parse() { + int ret = 0; + + for (size_t i = 0; i < sizeof(raw_packet_data) / sizeof(raw_packet_data[0]); + i++) { + uint8_t buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT]; + size_t buffer_size = sizeof(buffer); + if (decode_string(raw_packet_data[i], buffer, &buffer_size)) { + fprintf( + stderr, + "lcc_network_parse(raw_packet_data[%zu]): decoding string failed\n", + i); + return -1; + } + + int status = + lcc_network_parse(buffer, buffer_size, (lcc_network_parse_options_t){ + .writer = nop_writer, + }); + if (status != 0) { + fprintf(stderr, "lcc_network_parse(raw_packet_data[%zu]) = %d, want 0\n", + i, status); + ret = status; + } + + printf("ok - lcc_network_parse(raw_packet_data[%zu])\n", i); + } + + return ret; +} + +static int test_parse_time() { + int ret = 0; + + struct { + uint64_t in; + double want; + } cases[] = { + {1439980823, 1439980823.0}, + {1439981005, 1439981005.0}, + {1439981150, 1439981150.0}, + }; + + for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + lcc_value_list_t vl = LCC_VALUE_LIST_INIT; + + uint64_t be = htobe64(cases[i].in); + int status = parse_time(TYPE_TIME, &be, sizeof(be), &vl); + if ((status != 0) || (vl.time != cases[i].want)) { + fprintf(stderr, "parse_time(%" PRIu64 ") = (%.0f, %d), want (%.0f, 0)\n", + cases[i].in, vl.time, status, cases[i].want); + ret = -1; + } + } + + struct { + uint64_t in; + double want; + } cases_hr[] = { + {1546167635576736987, 1439980823.152453627}, + {1546167831554815222, 1439981005.671262017}, + {1546167986577716567, 1439981150.047589622}, + }; + + for (size_t i = 0; i < sizeof(cases_hr) / sizeof(cases_hr[0]); i++) { + lcc_value_list_t vl = LCC_VALUE_LIST_INIT; + + uint64_t be = htobe64(cases_hr[i].in); + int status = parse_time(TYPE_TIME_HR, &be, sizeof(be), &vl); + if ((status != 0) || (vl.time != cases_hr[i].want)) { + fprintf(stderr, "parse_time(%" PRIu64 ") = (%.9f, %d), want (%.9f, 0)\n", + cases_hr[i].in, vl.time, status, cases_hr[i].want); + ret = -1; + } + } + + return ret; +} + +static int test_parse_string() { + int ret = 0; + + struct { + uint8_t *in; + size_t in_len; + char *want; + } cases[] = { + {(uint8_t[]){0}, 1, ""}, + {(uint8_t[]){'t', 'e', 's', 't', 0}, 5, "test"}, + {(uint8_t[]){'t', 'e', 's', 't'}, 4, NULL}, // null byte missing + {(uint8_t[]){'t', 'e', 's', 't', 'x', 0}, 6, + NULL}, // output buffer too small + }; + + for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { + char got[5] = {0}; + + int status = parse_string(cases[i].in, cases[i].in_len, got, sizeof(got)); + if (cases[i].want == NULL) { + if (status == 0) { + fprintf(stderr, "parse_string() = (\"%s\", 0), want error\n", got); + ret = -1; + } + } else /* if cases[i].want != NULL */ { + if (status != 0) { + fprintf(stderr, "parse_string() = %d, want 0\n", status); + ret = -1; + } else if (strcmp(got, cases[i].want) != 0) { + fprintf(stderr, "parse_string() = (\"%s\", 0), want (\"%s\", 0)\n", got, + cases[i].want); + ret = -1; + } + } + } + + return ret; +} + +static int test_parse_values() { + int ret = 0; + + uint8_t testcase[] = { + // 0, 6, // pkg type + // 0, 33, // pkg len + 0, 3, // num values + 1, 2, 1, // gauge, derive, gauge + 0, 0, 0, 0, 0, 0, 0x45, 0x40, // 42.0 + 0, 0, 0, 0, 0, 0, 0x7a, 0x69, // 31337 + 0, 0, 0, 0, 0, 0, 0xf8, 0x7f, // NaN + }; + + lcc_value_list_t vl = LCC_VALUE_LIST_INIT; + int status = parse_values(testcase, sizeof(testcase), &vl); + if (status != 0) { + fprintf(stderr, "parse_values() = %d, want 0\n", status); + return -1; + } + + if (vl.values_len != 3) { + fprintf(stderr, "parse_values(): vl.values_len = %zu, want 3\n", + vl.values_len); + return -1; + } + + int want_types[] = {LCC_TYPE_GAUGE, LCC_TYPE_DERIVE, LCC_TYPE_GAUGE}; + for (size_t i = 0; i < sizeof(want_types) / sizeof(want_types[0]); i++) { + if (vl.values_types[i] != want_types[i]) { + fprintf(stderr, "parse_values(): vl.values_types[%zu] = %d, want %d\n", i, + vl.values_types[i], want_types[i]); + ret = -1; + } + } + + if (vl.values[0].gauge != 42.0) { + fprintf(stderr, "parse_values(): vl.values[0] = %g, want 42\n", + vl.values[0].gauge); + ret = -1; + } + if (vl.values[1].derive != 31337) { + fprintf(stderr, "parse_values(): vl.values[1] = %" PRIu64 ", want 31337\n", + vl.values[1].derive); + ret = -1; + } + if (!isnan(vl.values[2].gauge)) { + fprintf(stderr, "parse_values(): vl.values[2] = %g, want NaN\n", + vl.values[2].gauge); + ret = -1; + } + + free(vl.values); + free(vl.values_types); + + return ret; +} + +static int test_verify_sha256() { + int ret = 0; + + int status = verify_sha256( + (char[]){'c', 'o', 'l', 'l', 'e', 'c', 't', 'd'}, 8, "admin", "admin", + (uint8_t[]){ + 0xcd, 0xa5, 0x9a, 0x37, 0xb0, 0x81, 0xc2, 0x31, 0x24, 0x2a, 0x6d, + 0xbd, 0xfb, 0x44, 0xdb, 0xd7, 0x41, 0x2a, 0xf4, 0x29, 0x83, 0xde, + 0xa5, 0x11, 0x96, 0xd2, 0xe9, 0x30, 0x21, 0xae, 0xc5, 0x45, + }); + if (status != 0) { + fprintf(stderr, "verify_sha256() = %d, want 0\n", status); + ret = -1; + } + + status = verify_sha256( + (char[]){'c', 'o', 'l', 'l', 'E', 'c', 't', 'd'}, 8, "admin", "admin", + (uint8_t[]){ + 0xcd, 0xa5, 0x9a, 0x37, 0xb0, 0x81, 0xc2, 0x31, 0x24, 0x2a, 0x6d, + 0xbd, 0xfb, 0x44, 0xdb, 0xd7, 0x41, 0x2a, 0xf4, 0x29, 0x83, 0xde, + 0xa5, 0x11, 0x96, 0xd2, 0xe9, 0x30, 0x21, 0xae, 0xc5, 0x45, + }); + if (status != 1) { + fprintf(stderr, "verify_sha256() = %d, want 1\n", status); + ret = -1; + } + + return ret; +} + +static int test_decrypt_aes256() { + char const *iv_str = "4cbe2a747c9f9dcfa0e66f0c2fa74875"; + uint8_t iv[16] = {0}; + size_t iv_len = sizeof(iv); + + char const *ciphertext_str = + "8f023b0b15178f8428da1221a5f653e840f065db4aff032c22e5a3df"; + uint8_t ciphertext[28] = {0}; + size_t ciphertext_len = sizeof(ciphertext); + + if (decode_string(iv_str, iv, &iv_len) || + decode_string(ciphertext_str, ciphertext, &ciphertext_len)) { + fprintf(stderr, "test_decrypt_aes256: decode_string failed.\n"); + return -1; + } + assert(iv_len == sizeof(iv)); + assert(ciphertext_len == sizeof(ciphertext)); + + int status = decrypt_aes256( + &(buffer_t){ + .data = ciphertext, .len = ciphertext_len, + }, + iv, iv_len, "admin"); + if (status != 0) { + fprintf(stderr, "decrypt_aes256() = %d, want 0\n", status); + return -1; + } + + char const *want = "collectd"; + char got[9] = {0}; + memmove(got, &ciphertext[20], sizeof(got) - 1); + if (strcmp(got, want) != 0) { + fprintf(stderr, "decrypt_aes256() = \"%s\", want \"%s\"\n", got, want); + return -1; + } + + return 0; +} + +int main(void) { + int ret = 0; + + printf("libcollectdclient/server_test.c\n"); + + int status; + if ((status = test_network_parse())) { + ret = status; + } + if ((status = test_parse_time())) { + ret = status; + } + if ((status = test_parse_string())) { + ret = status; + } + if ((status = test_parse_values())) { + ret = status; + } + + if ((status = test_verify_sha256())) { + ret = status; + } + if ((status = test_decrypt_aes256())) { + ret = status; + } + + return ret; +} diff --git a/src/libcollectdclient/server.c b/src/libcollectdclient/server.c new file mode 100644 index 00000000..d18cc7da --- /dev/null +++ b/src/libcollectdclient/server.c @@ -0,0 +1,213 @@ +/** + * Copyright 2017 Florian Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#include "config.h" + +#if !defined(__GNUC__) || !__GNUC__ +#define __attribute__(x) /**/ +#endif + +#include "collectd/lcc_features.h" +#include "collectd/network_parse.h" /* for lcc_network_parse_options_t */ +#include "collectd/server.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define DEBUG(...) printf(__VA_ARGS__) + +static _Bool is_multicast(struct addrinfo const *ai) { + if (ai->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)ai->ai_addr; + return IN_MULTICAST(ntohl(addr->sin_addr.s_addr)); + } else if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ai->ai_addr; + return IN6_IS_ADDR_MULTICAST(&addr->sin6_addr); + } + return 0; +} + +static int server_multicast_join(lcc_listener_t *srv, + struct sockaddr_storage *group, int loop_back, + int ttl) { + if (group->ss_family == AF_INET) { + struct sockaddr_in *sa = (struct sockaddr_in *)group; + + int status = setsockopt(srv->conn, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop_back, sizeof(loop_back)); + if (status == -1) { + DEBUG("setsockopt(IP_MULTICAST_LOOP, %d) = %d\n", loop_back, errno); + return errno; + } + + status = + setsockopt(srv->conn, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + if (status == -1) + return errno; + +#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + struct ip_mreqn mreq = { + .imr_address.s_addr = INADDR_ANY, + .imr_multiaddr.s_addr = sa->sin_addr.s_addr, + .imr_ifindex = if_nametoindex(srv->interface), + }; +#else + struct ip_mreq mreq = { + .imr_address.s_addr = INADDR_ANY, .imr_multiaddr.s_addr = sa->s_addr, + }; +#endif + status = setsockopt(srv->conn, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)); + if (status == -1) + return errno; + } else if (group->ss_family == AF_INET6) { + struct sockaddr_in6 *sa = (struct sockaddr_in6 *)group; + + int status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &loop_back, sizeof(loop_back)); + if (status == -1) + return errno; + + status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, + sizeof(ttl)); + if (status == -1) + return errno; + + struct ipv6_mreq mreq6 = { + .ipv6mr_interface = if_nametoindex(srv->interface), + }; + memmove(&mreq6.ipv6mr_multiaddr, &sa->sin6_addr, sizeof(struct in6_addr)); + + status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, + sizeof(mreq6)); + if (status == -1) + return errno; + } else { + return EINVAL; + } + + return 0; +} + +static int server_bind_socket(lcc_listener_t *srv, struct addrinfo const *ai) { + /* allow multiple sockets to use the same PORT number */ + if (setsockopt(srv->conn, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == + -1) { + return errno; + } + + if (bind(srv->conn, ai->ai_addr, ai->ai_addrlen) == -1) { + return -1; + } + + if (is_multicast(ai)) { + int status = server_multicast_join(srv, (void *)ai->ai_addr, /* loop = */ 1, + /* ttl = */ 16); + if (status != 0) + return status; + } + + return 0; +} + +static int server_open(lcc_listener_t *srv) { + struct addrinfo *res = NULL; + int status = getaddrinfo(srv->node ? srv->node : "::", + srv->service ? srv->service : LCC_DEFAULT_PORT, + &(struct addrinfo){ + .ai_flags = AI_ADDRCONFIG, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM, + }, + &res); + if (status != 0) + return status; + + for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) { + srv->conn = socket(ai->ai_family, ai->ai_socktype, 0); + if (srv->conn == -1) + continue; + + status = server_bind_socket(srv, ai); + if (status != 0) { + close(srv->conn); + srv->conn = -1; + continue; + } + + break; + } + + freeaddrinfo(res); + + if (srv->conn >= 0) + return 0; + return status != 0 ? status : -1; +} + +int lcc_listen_and_write(lcc_listener_t srv) { + _Bool close_socket = 0; + + if (srv.conn < 0) { + int status = server_open(&srv); + if (status != 0) + return status; + close_socket = 1; + } + + if (srv.buffer_size == 0) + srv.buffer_size = LCC_NETWORK_BUFFER_SIZE; + + if (srv.parser == NULL) + srv.parser = lcc_network_parse; + + int ret = 0; + while (42) { + char buffer[srv.buffer_size]; + ssize_t len = recv(srv.conn, buffer, sizeof(buffer), /* flags = */ 0); + if (len == -1) { + ret = errno; + break; + } else if (len == 0) { + break; + } + + (void)srv.parser(buffer, (size_t)len, srv.parse_options); + } + + if (close_socket) { + close(srv.conn); + srv.conn = -1; + } + + return ret; +} diff --git a/src/logfile.c b/src/logfile.c index e5807f1b..de9b1f75 100644 --- a/src/logfile.c +++ b/src/logfile.c @@ -163,7 +163,7 @@ static int logfile_notification(const notification_t *n, int buf_len = sizeof(buf); int status; - status = ssnprintf( + status = snprintf( buf_ptr, buf_len, "Notification: severity = %s", (n->severity == NOTIF_FAILURE) ? "FAILURE" @@ -177,7 +177,7 @@ static int logfile_notification(const notification_t *n, #define APPEND(bufptr, buflen, key, value) \ if ((buflen > 0) && (strlen(value) > 0)) { \ - status = ssnprintf(bufptr, buflen, ", %s = %s", key, value); \ + status = snprintf(bufptr, buflen, ", %s = %s", key, value); \ if (status > 0) { \ bufptr += status; \ buflen -= status; \ diff --git a/src/lpar.c b/src/lpar.c index a0dde32c..3ecf0495 100644 --- a/src/lpar.c +++ b/src/lpar.c @@ -226,10 +226,10 @@ static int lpar_read(void) { if (pool_busy_cpus < 0.0) pool_busy_cpus = 0.0; - ssnprintf(typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id); + snprintf(typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id); lpar_submit(typinst, pool_busy_cpus); - ssnprintf(typinst, sizeof(typinst), "pool-%X-idle", lparstats.pool_id); + snprintf(typinst, sizeof(typinst), "pool-%X-idle", lparstats.pool_id); lpar_submit(typinst, pool_idle_cpus); } diff --git a/src/lua.c b/src/lua.c index aeaeff24..8cfb7045 100644 --- a/src/lua.c +++ b/src/lua.c @@ -282,7 +282,7 @@ static int lua_cb_register_read(lua_State *L) /* {{{ */ luaL_checktype(L, 1, LUA_TFUNCTION); char function_name[DATA_MAX_NAME_LEN]; - ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1)); + snprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1)); int callback_id = clua_store_callback(L, 1); if (callback_id < 0) @@ -306,9 +306,10 @@ static int lua_cb_register_read(lua_State *L) /* {{{ */ int status = plugin_register_complex_read(/* group = */ "lua", /* name = */ function_name, /* callback = */ clua_read, - /* interval = */ 0, &(user_data_t){ - .data = cb, - }); + /* interval = */ 0, + &(user_data_t){ + .data = cb, + }); if (status != 0) return luaL_error(L, "%s", "plugin_register_complex_read failed"); @@ -325,7 +326,7 @@ static int lua_cb_register_write(lua_State *L) /* {{{ */ luaL_checktype(L, 1, LUA_TFUNCTION); char function_name[DATA_MAX_NAME_LEN] = ""; - ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1)); + snprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1)); int callback_id = clua_store_callback(L, 1); if (callback_id < 0) @@ -346,11 +347,11 @@ static int lua_cb_register_write(lua_State *L) /* {{{ */ cb->lua_function_name = strdup(function_name); pthread_mutex_init(&cb->lock, NULL); - int status = - plugin_register_write(/* name = */ function_name, - /* callback = */ clua_write, &(user_data_t){ - .data = cb, - }); + int status = plugin_register_write(/* name = */ function_name, + /* callback = */ clua_write, + &(user_data_t){ + .data = cb, + }); if (status != 0) return luaL_error(L, "%s", "plugin_register_write failed"); @@ -533,7 +534,7 @@ static int lua_config_script(const oconfig_item_t *ci) /* {{{ */ if (base_path[0] == '\0') sstrncpy(abs_path, rel_path, sizeof(abs_path)); else - ssnprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path); + snprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path); DEBUG("Lua plugin: abs_path = \"%s\";", abs_path); diff --git a/src/lvm.c b/src/lvm.c index c3214b07..63107279 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -77,8 +77,7 @@ static void report_lv_utilization(lv_t lv, char const *vg_name, return; used_bytes = lv_size * (used_percent_unscaled * PERCENT_SCALE_FACTOR); - ssnprintf(plugin_instance, sizeof(plugin_instance), "%s-%s", vg_name, - lv_name); + snprintf(plugin_instance, sizeof(plugin_instance), "%s-%s", vg_name, lv_name); lvm_submit(plugin_instance, "used", used_bytes); lvm_submit(plugin_instance, "free", lv_size - used_bytes); } diff --git a/src/madwifi.c b/src/madwifi.c index 5a915b62..1a387b78 100644 --- a/src/madwifi.c +++ b/src/madwifi.c @@ -519,7 +519,7 @@ static void submit(const char *dev, const char *type, const char *ti1, sstrncpy(vl.type, type, sizeof(vl.type)); if ((ti1 != NULL) && (ti2 != NULL)) - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s", ti1, ti2); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s", ti1, ti2); else if ((ti1 != NULL) && (ti2 == NULL)) sstrncpy(vl.type_instance, ti1, sizeof(vl.type_instance)); @@ -553,15 +553,15 @@ static void submit_antx(const char *dev, const char *name, u_int32_t *vals, if (vals[i] == 0) continue; - ssnprintf(ti2, sizeof(ti2), "%i", i); + snprintf(ti2, sizeof(ti2), "%i", i); submit_derive(dev, "ath_stat", name, ti2, (derive_t)vals[i]); } } static inline void macaddr_to_str(char *buf, size_t bufsize, const uint8_t mac[IEEE80211_ADDR_LEN]) { - ssnprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], - mac[2], mac[3], mac[4], mac[5]); + snprintf(buf, bufsize, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], + mac[2], mac[3], mac[4], mac[5]); } static void process_stat_struct(int which, const void *ptr, const char *dev, @@ -753,7 +753,7 @@ static int check_devname(const char *dev) { if (dev[0] == '.') return 0; - ssnprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", dev); + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", dev); buf[sizeof(buf) - 1] = '\0'; i = readlink(buf, buf2, sizeof(buf2) - 1); diff --git a/src/match_regex.c b/src/match_regex.c index 6b45f6c9..dd4018b0 100644 --- a/src/match_regex.c +++ b/src/match_regex.c @@ -224,7 +224,7 @@ static int mr_config_add_meta_regex(llist_t **meta, /* {{{ */ llist_append(*meta, entry); } - ssnprintf(buffer, sizeof(buffer), "%s `%s'", ci->key, meta_key); + snprintf(buffer, sizeof(buffer), "%s `%s'", ci->key, meta_key); /* Can't pass &entry->value into mr_add_regex, so copy in/out. */ re_head = entry->value; status = mr_add_regex(&re_head, ci->values[1].value.string, buffer); diff --git a/src/mcelog.c b/src/mcelog.c index fad18d50..6b10b04c 100644 --- a/src/mcelog.c +++ b/src/mcelog.c @@ -2,7 +2,7 @@ * collectd - src/mcelog.c * MIT License * - * Copyright(c) 2016 Intel Corporation. All rights reserved. + * Copyright(c) 2016-2017 Intel Corporation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -29,9 +29,11 @@ * Krzysztof Matczak */ -#include "common.h" #include "collectd.h" +#include "common.h" +#include "utils_llist.h" + #include #include #include @@ -44,10 +46,17 @@ #define MCELOG_DIMM_NAME "DMI_NAME" #define MCELOG_CORRECTED_ERR "corrected memory errors" #define MCELOG_UNCORRECTED_ERR "uncorrected memory errors" +#define MCELOG_CORRECTED_ERR_TIMED "corrected memory timed errors" +#define MCELOG_UNCORRECTED_ERR_TIMED "uncorrected memory timed errors" +#define MCELOG_CORRECTED_ERR_TYPE_INS "corrected_memory_errors" +#define MCELOG_UNCORRECTED_ERR_TYPE_INS "uncorrected_memory_errors" typedef struct mcelog_config_s { char logfile[PATH_MAX]; /* mcelog logfile */ pthread_t tid; /* poll thread id */ + llist_t *dimms_list; /* DIMMs list */ + pthread_mutex_t dimms_lock; /* lock for dimms cache */ + _Bool persist; } mcelog_config_t; typedef struct socket_adapter_s socket_adapter_t; @@ -80,7 +89,9 @@ static int socket_write(socket_adapter_t *self, const char *msg, static int socket_reinit(socket_adapter_t *self); static int socket_receive(socket_adapter_t *self, FILE **p_file); -static mcelog_config_t g_mcelog_config = {.logfile = "/var/log/mcelog"}; +static mcelog_config_t g_mcelog_config = { + .logfile = "/var/log/mcelog", .persist = 0, +}; static socket_adapter_t socket_adapter = { .sock_fd = -1, @@ -96,31 +107,129 @@ static socket_adapter_t socket_adapter = { }; static _Bool mcelog_thread_running; +static _Bool mcelog_apply_defaults; + +static void mcelog_free_dimms_list_records(llist_t *dimms_list) { + + for (llentry_t *e = llist_head(dimms_list); e != NULL; e = e->next) { + sfree(e->key); + sfree(e->value); + } +} + +/* Create or get dimm by dimm name/location */ +static llentry_t *mcelog_dimm(const mcelog_memory_rec_t *rec, + llist_t *dimms_list) { + + char dimm_name[DATA_MAX_NAME_LEN]; + + if (strlen(rec->dimm_name) > 0) { + snprintf(dimm_name, sizeof(dimm_name), "%s_%s", rec->location, + rec->dimm_name); + } else + sstrncpy(dimm_name, rec->location, sizeof(dimm_name)); + + llentry_t *dimm_le = llist_search(g_mcelog_config.dimms_list, dimm_name); + + if (dimm_le != NULL) + return dimm_le; + + /* allocate new linked list entry */ + mcelog_memory_rec_t *dimm_mr = calloc(1, sizeof(*dimm_mr)); + if (dimm_mr == NULL) { + ERROR(MCELOG_PLUGIN ": Error allocating dimm memory item"); + return NULL; + } + char *p_name = strdup(dimm_name); + if (p_name == NULL) { + ERROR(MCELOG_PLUGIN ": strdup: error"); + free(dimm_mr); + return NULL; + } + + /* add new dimm */ + dimm_le = llentry_create(p_name, dimm_mr); + if (dimm_le == NULL) { + ERROR(MCELOG_PLUGIN ": llentry_create(): error"); + free(dimm_mr); + free(p_name); + return NULL; + } + pthread_mutex_lock(&g_mcelog_config.dimms_lock); + llist_append(g_mcelog_config.dimms_list, dimm_le); + pthread_mutex_unlock(&g_mcelog_config.dimms_lock); + + return dimm_le; +} + +static void mcelog_update_dimm_stats(llentry_t *dimm, + const mcelog_memory_rec_t *rec) { + pthread_mutex_lock(&g_mcelog_config.dimms_lock); + memcpy(dimm->value, rec, sizeof(mcelog_memory_rec_t)); + pthread_mutex_unlock(&g_mcelog_config.dimms_lock); +} static int mcelog_config(oconfig_item_t *ci) { + int use_logfile = 0, use_memory = 0; for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; - if (strcasecmp("McelogClientSocket", child->key) == 0) { - if (cf_util_get_string_buffer(child, socket_adapter.unix_sock.sun_path, - sizeof(socket_adapter.unix_sock.sun_path)) < - 0) { - ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", + if (strcasecmp("McelogLogfile", child->key) == 0) { + use_logfile = 1; + if (use_memory) { + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\", Memory " + "option is already configured.", child->key); return -1; } - } else if (strcasecmp("McelogLogfile", child->key) == 0) { if (cf_util_get_string_buffer(child, g_mcelog_config.logfile, sizeof(g_mcelog_config.logfile)) < 0) { ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", child->key); return -1; } + memset(socket_adapter.unix_sock.sun_path, 0, + sizeof(socket_adapter.unix_sock.sun_path)); + } else if (strcasecmp("Memory", child->key) == 0) { + if (use_logfile) { + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\", Logfile " + "option is already configured.", + child->key); + return -1; + } + use_memory = 1; + for (int j = 0; j < child->children_num; j++) { + oconfig_item_t *mem_child = child->children + j; + if (strcasecmp("McelogClientSocket", mem_child->key) == 0) { + if (cf_util_get_string_buffer( + mem_child, socket_adapter.unix_sock.sun_path, + sizeof(socket_adapter.unix_sock.sun_path)) < 0) { + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", + mem_child->key); + return -1; + } + } else if (strcasecmp("PersistentNotification", mem_child->key) == 0) { + if (cf_util_get_boolean(mem_child, &g_mcelog_config.persist) < 0) { + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", + mem_child->key); + return -1; + } + } else { + ERROR(MCELOG_PLUGIN ": Invalid Memory configuration option: \"%s\".", + mem_child->key); + return -1; + } + } + memset(g_mcelog_config.logfile, 0, sizeof(g_mcelog_config.logfile)); } else { ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", child->key); return -1; } } + + if (!use_logfile && !use_memory) + mcelog_apply_defaults = 1; + return 0; } @@ -212,64 +321,82 @@ static int socket_reinit(socket_adapter_t *self) { return ret; } -static int mcelog_prepare_notification(notification_t *n, - const mcelog_memory_rec_t *mr) { - if (n == NULL || mr == NULL) - return -1; +static int mcelog_dispatch_mem_notifications(const mcelog_memory_rec_t *mr) { + notification_t n = {.severity = NOTIF_WARNING, + .time = cdtime(), + .plugin = MCELOG_PLUGIN, + .type = "errors"}; - if ((mr->location[0] != '\0') && - (plugin_notification_meta_add_string(n, MCELOG_SOCKET_STR, mr->location) < - 0)) { - ERROR(MCELOG_PLUGIN ": add memory location meta data failed"); - return -1; - } - if ((mr->dimm_name[0] != '\0') && - (plugin_notification_meta_add_string(n, MCELOG_DIMM_NAME, mr->dimm_name) < - 0)) { - ERROR(MCELOG_PLUGIN ": add DIMM name meta data failed"); - plugin_notification_meta_free(n->meta); - return -1; - } - if (plugin_notification_meta_add_signed_int(n, MCELOG_CORRECTED_ERR, - mr->corrected_err_total) < 0) { - ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed"); - plugin_notification_meta_free(n->meta); - return -1; - } - if (plugin_notification_meta_add_signed_int( - n, "corrected memory timed errors", mr->corrected_err_timed) < 0) { - ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed"); - plugin_notification_meta_free(n->meta); + int dispatch_corrected_notifs = 0, dispatch_uncorrected_notifs = 0; + + if (mr == NULL) return -1; - } - if ((mr->corrected_err_timed_period[0] != '\0') && - (plugin_notification_meta_add_string(n, "corrected errors time period", - mr->corrected_err_timed_period) < - 0)) { - ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed"); - plugin_notification_meta_free(n->meta); + + llentry_t *dimm = mcelog_dimm(mr, g_mcelog_config.dimms_list); + if (dimm == NULL) { + ERROR(MCELOG_PLUGIN + ": Error adding/getting dimm memory item to/from cache"); return -1; } - if (plugin_notification_meta_add_signed_int(n, MCELOG_UNCORRECTED_ERR, - mr->uncorrected_err_total) < 0) { - ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed"); - plugin_notification_meta_free(n->meta); - return -1; + mcelog_memory_rec_t *mr_old = dimm->value; + if (!g_mcelog_config.persist) { + + if (mr_old->corrected_err_total != mr->corrected_err_total || + mr_old->corrected_err_timed != mr->corrected_err_timed) + dispatch_corrected_notifs = 1; + + if (mr_old->uncorrected_err_total != mr->uncorrected_err_total || + mr_old->uncorrected_err_timed != mr->uncorrected_err_timed) + dispatch_uncorrected_notifs = 1; + + if (!dispatch_corrected_notifs && !dispatch_uncorrected_notifs) { + DEBUG("%s: No new notifications to dispatch", MCELOG_PLUGIN); + return 0; + } + } else { + dispatch_corrected_notifs = 1; + dispatch_uncorrected_notifs = 1; } - if (plugin_notification_meta_add_signed_int(n, - "uncorrected memory timed errors", - mr->uncorrected_err_timed) < 0) { - ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed"); - plugin_notification_meta_free(n->meta); - return -1; + + sstrncpy(n.host, hostname_g, sizeof(n.host)); + + if (mr->dimm_name[0] != '\0') + snprintf(n.plugin_instance, sizeof(n.plugin_instance), "%s_%s", + mr->location, mr->dimm_name); + else + sstrncpy(n.plugin_instance, mr->location, sizeof(n.plugin_instance)); + + if (dispatch_corrected_notifs && + (mr->corrected_err_total > 0 || mr->corrected_err_timed > 0)) { + /* Corrected Error Notifications */ + plugin_notification_meta_add_signed_int(&n, MCELOG_CORRECTED_ERR, + mr->corrected_err_total); + plugin_notification_meta_add_signed_int(&n, MCELOG_CORRECTED_ERR_TIMED, + mr->corrected_err_timed); + snprintf(n.message, sizeof(n.message), MCELOG_CORRECTED_ERR); + sstrncpy(n.type_instance, MCELOG_CORRECTED_ERR_TYPE_INS, + sizeof(n.type_instance)); + plugin_dispatch_notification(&n); + if (n.meta) + plugin_notification_meta_free(n.meta); + n.meta = NULL; } - if ((mr->uncorrected_err_timed_period[0] != '\0') && - (plugin_notification_meta_add_string(n, "uncorrected errors time period", - mr->uncorrected_err_timed_period) < - 0)) { - ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed"); - plugin_notification_meta_free(n->meta); - return -1; + + if (dispatch_uncorrected_notifs && + (mr->uncorrected_err_total > 0 || mr->uncorrected_err_timed > 0)) { + /* Uncorrected Error Notifications */ + plugin_notification_meta_add_signed_int(&n, MCELOG_UNCORRECTED_ERR, + mr->uncorrected_err_total); + plugin_notification_meta_add_signed_int(&n, MCELOG_UNCORRECTED_ERR_TIMED, + mr->uncorrected_err_timed); + snprintf(n.message, sizeof(n.message), MCELOG_UNCORRECTED_ERR); + sstrncpy(n.type_instance, MCELOG_UNCORRECTED_ERR_TYPE_INS, + sizeof(n.type_instance)); + n.severity = NOTIF_FAILURE; + plugin_dispatch_notification(&n); + if (n.meta) + plugin_notification_meta_free(n.meta); + n.meta = NULL; } return 0; @@ -282,35 +409,43 @@ static int mcelog_submit(const mcelog_memory_rec_t *mr) { return -1; } + llentry_t *dimm = mcelog_dimm(mr, g_mcelog_config.dimms_list); + if (dimm == NULL) { + ERROR(MCELOG_PLUGIN + ": Error adding/getting dimm memory item to/from cache"); + return -1; + } + value_list_t vl = { .values_len = 1, .values = &(value_t){.derive = (derive_t)mr->corrected_err_total}, .time = cdtime(), .plugin = MCELOG_PLUGIN, .type = "errors", - .type_instance = "corrected_memory_errors"}; + .type_instance = MCELOG_CORRECTED_ERR_TYPE_INS}; + + mcelog_update_dimm_stats(dimm, mr); if (mr->dimm_name[0] != '\0') - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s_%s", - mr->location, mr->dimm_name); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s_%s", + mr->location, mr->dimm_name); else sstrncpy(vl.plugin_instance, mr->location, sizeof(vl.plugin_instance)); plugin_dispatch_values(&vl); - ssnprintf(vl.type_instance, sizeof(vl.type_instance), - "corrected_memory_errors_in_%s", mr->corrected_err_timed_period); + snprintf(vl.type_instance, sizeof(vl.type_instance), + "corrected_memory_errors_in_%s", mr->corrected_err_timed_period); vl.values = &(value_t){.derive = (derive_t)mr->corrected_err_timed}; plugin_dispatch_values(&vl); - sstrncpy(vl.type_instance, "uncorrected_memory_errors", + sstrncpy(vl.type_instance, MCELOG_UNCORRECTED_ERR_TYPE_INS, sizeof(vl.type_instance)); vl.values = &(value_t){.derive = (derive_t)mr->uncorrected_err_total}; plugin_dispatch_values(&vl); - ssnprintf(vl.type_instance, sizeof(vl.type_instance), - "uncorrected_memory_errors_in_%s", - mr->uncorrected_err_timed_period); + snprintf(vl.type_instance, sizeof(vl.type_instance), + "uncorrected_memory_errors_in_%s", mr->uncorrected_err_timed_period); vl.values = &(value_t){.derive = (derive_t)mr->uncorrected_err_timed}; plugin_dispatch_values(&vl); @@ -473,14 +608,8 @@ static void *poll_worker(__attribute__((unused)) void *arg) { continue; } - notification_t n = {.severity = NOTIF_OKAY, - .time = cdtime(), - .message = "Got memory errors info.", - .plugin = MCELOG_PLUGIN, - .type_instance = "memory_erros"}; - - if (mcelog_prepare_notification(&n, &memory_record) == 0) - mcelog_dispatch_notification(&n); + if (mcelog_dispatch_mem_notifications(&memory_record) != 0) + ERROR(MCELOG_PLUGIN ": Failed to submit memory errors notification"); if (mcelog_submit(&memory_record) != 0) ERROR(MCELOG_PLUGIN ": Failed to submit memory errors"); memset(&memory_record, 0, sizeof(memory_record)); @@ -496,15 +625,29 @@ static void *poll_worker(__attribute__((unused)) void *arg) { } static int mcelog_init(void) { + if (mcelog_apply_defaults) { + INFO(MCELOG_PLUGIN + ": No configuration selected defaulting to memory errors."); + memset(g_mcelog_config.logfile, 0, sizeof(g_mcelog_config.logfile)); + } + g_mcelog_config.dimms_list = llist_create(); + int err = pthread_mutex_init(&g_mcelog_config.dimms_lock, NULL); + if (err < 0) { + ERROR(MCELOG_PLUGIN ": plugin: failed to initialize cache lock"); + return -1; + } + if (socket_adapter.reinit(&socket_adapter) != 0) { ERROR(MCELOG_PLUGIN ": Cannot connect to client socket"); return -1; } - if (plugin_thread_create(&g_mcelog_config.tid, NULL, poll_worker, NULL, - NULL) != 0) { - ERROR(MCELOG_PLUGIN ": Error creating poll thread."); - return -1; + if (strlen(socket_adapter.unix_sock.sun_path)) { + if (plugin_thread_create(&g_mcelog_config.tid, NULL, poll_worker, NULL, + NULL) != 0) { + ERROR(MCELOG_PLUGIN ": Error creating poll thread."); + return -1; + } } return 0; } @@ -537,7 +680,12 @@ static int mcelog_shutdown(void) { ret = -1; } } - + pthread_mutex_lock(&g_mcelog_config.dimms_lock); + mcelog_free_dimms_list_records(g_mcelog_config.dimms_list); + llist_destroy(g_mcelog_config.dimms_list); + g_mcelog_config.dimms_list = NULL; + pthread_mutex_unlock(&g_mcelog_config.dimms_lock); + pthread_mutex_destroy(&g_mcelog_config.dimms_lock); ret = socket_adapter.close(&socket_adapter) || ret; pthread_rwlock_destroy(&(socket_adapter.lock)); return -ret; diff --git a/src/md.c b/src/md.c index 98cef1d4..016e6b0c 100644 --- a/src/md.c +++ b/src/md.c @@ -66,7 +66,7 @@ static void md_submit(const int minor, const char *type_instance, vl.values = &(value_t){.gauge = value}; vl.values_len = 1; sstrncpy(vl.plugin, "md", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", minor); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", minor); sstrncpy(vl.type, "md_disks", sizeof(vl.type)); sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); @@ -180,7 +180,7 @@ static int md_read(void) { * major/minor, but that again can be tricky if the filesystem * with the device file is mounted using the "nodev" option. */ - ssnprintf(path, sizeof(path), "%s/%s", DEV_DIR, name); + snprintf(path, sizeof(path), "%s/%s", DEV_DIR, name); md_process(minor, path); } diff --git a/src/memcachec.c b/src/memcachec.c index c2147fd5..bd088ecd 100644 --- a/src/memcachec.c +++ b/src/memcachec.c @@ -51,6 +51,7 @@ struct web_page_s; typedef struct web_page_s web_page_t; struct web_page_s /* {{{ */ { + char *plugin_name; char *instance; char *server; @@ -94,6 +95,7 @@ static void cmc_web_page_free(web_page_t *wp) /* {{{ */ memcached_free(wp->memc); wp->memc = NULL; + sfree(wp->plugin_name); sfree(wp->instance); sfree(wp->server); sfree(wp->key); @@ -302,6 +304,8 @@ static int cmc_config_add_page(oconfig_item_t *ci) /* {{{ */ status = cmc_config_add_string("Server", &page->server, child); else if (strcasecmp("Key", child->key) == 0) status = cmc_config_add_string("Key", &page->key, child); + else if (strcasecmp("Plugin", child->key) == 0) + status = cmc_config_add_string("Plugin", &page->plugin_name, child); else if (strcasecmp("Match", child->key) == 0) /* Be liberal with failing matches => don't set `status'. */ cmc_config_add_match(page, child); @@ -407,7 +411,8 @@ static void cmc_submit(const web_page_t *wp, const web_match_t *wm, /* {{{ */ vl.values = &value; vl.values_len = 1; - sstrncpy(vl.plugin, "memcachec", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "memcachec", + sizeof (vl.plugin)); sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, wm->type, sizeof(vl.type)); sstrncpy(vl.type_instance, wm->instance, sizeof(vl.type_instance)); diff --git a/src/memcached.c b/src/memcached.c index 5fc17df3..90f323f8 100644 --- a/src/memcached.c +++ b/src/memcached.c @@ -5,6 +5,7 @@ * Copyright (C) 2009 Doug MacEachern * Copyright (C) 2009 Franck Lombardi * Copyright (C) 2012 Nicolas Szalay + * Copyright (C) 2017 Pavel Rochnyak * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,6 +27,7 @@ * Doug MacEachern * Franck Lombardi * Nicolas Szalay + * Pavel Rochnyak **/ #include "collectd.h" @@ -38,8 +40,12 @@ #include #include +#include + #define MEMCACHED_DEF_HOST "127.0.0.1" #define MEMCACHED_DEF_PORT "11211" +#define MEMCACHED_CONNECT_TIMEOUT 10000 +#define MEMCACHED_IO_TIMEOUT 5000 struct memcached_s { char *name; @@ -47,6 +53,7 @@ struct memcached_s { char *socket; char *connhost; char *connport; + int fd; }; typedef struct memcached_s memcached_t; @@ -57,6 +64,12 @@ static void memcached_free(void *arg) { if (st == NULL) return; + if (st->fd >= 0) { + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; + } + sfree(st->name); sfree(st->host); sfree(st->socket); @@ -86,7 +99,15 @@ static int memcached_connect_unix(memcached_t *st) { if (status != 0) { shutdown(fd, SHUT_RDWR); close(fd); - fd = -1; + return -1; + } + + /* switch to non-blocking mode */ + int flags = fcntl(fd, F_GETFL); + status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (status != 0) { + close(fd); + return -1; } return fd; @@ -124,16 +145,47 @@ static int memcached_connect_inet(memcached_t *st) { continue; } + /* switch socket to non-blocking mode */ + int flags = fcntl(fd, F_GETFL); + status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (status != 0) { + close(fd); + fd = -1; + continue; + } + /* connect to the memcached daemon */ status = (int)connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); - if (status != 0) { + if (status != 0 && errno != EINPROGRESS) { shutdown(fd, SHUT_RDWR); close(fd); fd = -1; continue; } - /* A socket could be opened and connecting succeeded. We're done. */ + /* Wait until connection establishes */ + struct pollfd pollfd = { + .fd = fd, .events = POLLOUT, + }; + do + status = poll(&pollfd, 1, MEMCACHED_CONNECT_TIMEOUT); + while (status < 0 && errno == EINTR); + if (status <= 0) { + close(fd); + fd = -1; + continue; + } + + /* Check if all is good */ + int socket_error; + status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&socket_error, + &(socklen_t){sizeof(socket_error)}); + if (status != 0 || socket_error != 0) { + close(fd); + fd = -1; + continue; + } + /* A socket is opened and connection succeeded. We're done. */ break; } @@ -141,32 +193,55 @@ static int memcached_connect_inet(memcached_t *st) { return fd; } /* int memcached_connect_inet */ -static int memcached_connect(memcached_t *st) { +static void memcached_connect(memcached_t *st) { + if (st->fd >= 0) + return; + if (st->socket != NULL) - return memcached_connect_unix(st); + st->fd = memcached_connect_unix(st); else - return memcached_connect_inet(st); + st->fd = memcached_connect_inet(st); + + if (st->fd >= 0) + INFO("memcached plugin: Instance \"%s\": connection established.", + st->name); } static int memcached_query_daemon(char *buffer, size_t buffer_size, memcached_t *st) { - int fd, status; + int status; size_t buffer_fill; - fd = memcached_connect(st); - if (fd < 0) { + memcached_connect(st); + if (st->fd < 0) { ERROR("memcached plugin: Instance \"%s\" could not connect to daemon.", st->name); return -1; } - status = (int)swrite(fd, "stats\r\n", strlen("stats\r\n")); + struct pollfd pollfd = { + .fd = st->fd, .events = POLLOUT, + }; + + do + status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT); + while (status < 0 && errno == EINTR); + + if (status <= 0) { + ERROR("memcached plugin: poll() failed for write() call."); + close(st->fd); + st->fd = -1; + return -1; + } + + status = (int)swrite(st->fd, "stats\r\n", strlen("stats\r\n")); if (status != 0) { char errbuf[1024]; - ERROR("memcached plugin: write(2) failed: %s", + ERROR("memcached plugin: Instance \"%s\": write(2) failed: %s", st->name, sstrerror(errno, errbuf, sizeof(errbuf))); - shutdown(fd, SHUT_RDWR); - close(fd); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; return -1; } @@ -174,27 +249,48 @@ static int memcached_query_daemon(char *buffer, size_t buffer_size, memset(buffer, 0, buffer_size); buffer_fill = 0; - while ((status = (int)recv(fd, buffer + buffer_fill, - buffer_size - buffer_fill, /* flags = */ 0)) != - 0) { + pollfd.events = POLLIN; + while (1) { + do + status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT); + while (status < 0 && errno == EINTR); + + if (status <= 0) { + ERROR("memcached plugin: Instance \"%s\": Timeout reading from socket", + st->name); + close(st->fd); + st->fd = -1; + return -1; + } + + do + status = (int)recv(st->fd, buffer + buffer_fill, + buffer_size - buffer_fill, /* flags = */ 0); + while (status < 0 && errno == EINTR); + char const end_token[5] = {'E', 'N', 'D', '\r', '\n'}; if (status < 0) { char errbuf[1024]; - if ((errno == EAGAIN) || (errno == EINTR)) + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) continue; - ERROR("memcached: Error reading from socket: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); - shutdown(fd, SHUT_RDWR); - close(fd); + ERROR("memcached plugin: Instance \"%s\": Error reading from socket: %s", + st->name, sstrerror(errno, errbuf, sizeof(errbuf))); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; return -1; } buffer_fill += (size_t)status; if (buffer_fill > buffer_size) { buffer_fill = buffer_size; - WARNING("memcached plugin: Message was truncated."); + WARNING("memcached plugin: Instance \"%s\": Message was truncated.", + st->name); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; break; } @@ -206,12 +302,11 @@ static int memcached_query_daemon(char *buffer, size_t buffer_size, status = 0; if (buffer_fill == 0) { - WARNING("memcached plugin: No data returned by memcached."); + WARNING("memcached plugin: Instance \"%s\": No data returned by memcached.", + st->name); status = -1; } - shutdown(fd, SHUT_RDWR); - close(fd); return status; } /* int memcached_query_daemon */ @@ -377,6 +472,13 @@ static int memcached_read(user_data_t *user_data) { } else if (FIELD_IS("listen_disabled_num")) { submit_derive("connections", "listen_disabled", atof(fields[2]), st); } + /* + * Total number of connections opened since the server started running + * Report this as connection rate. + */ + else if (FIELD_IS("total_connections")) { + submit_derive("connections", "opened", atof(fields[2]), st); + } /* * Commands @@ -473,13 +575,7 @@ static int memcached_read(user_data_t *user_data) { return 0; } /* int memcached_read */ -static int memcached_add_read_callback(memcached_t *st) { - char callback_name[3 * DATA_MAX_NAME_LEN]; - int status; - - ssnprintf(callback_name, sizeof(callback_name), "memcached/%s", - (st->name != NULL) ? st->name : "__legacy__"); - +static int memcached_set_defaults(memcached_t *st) { /* If no
used then: * - Connect to the destination specified by , if present. * If not, use the default address. @@ -516,15 +612,28 @@ static int memcached_add_read_callback(memcached_t *st) { assert(st->connhost != NULL); assert(st->connport != NULL); - status = plugin_register_complex_read( + return 0; +} /* int memcached_set_defaults */ + +static int memcached_add_read_callback(memcached_t *st) { + char callback_name[3 * DATA_MAX_NAME_LEN]; + + if (memcached_set_defaults(st) != 0) { + memcached_free(st); + return -1; + } + + snprintf(callback_name, sizeof(callback_name), "memcached/%s", + (st->name != NULL) ? st->name : "__legacy__"); + + return plugin_register_complex_read( /* group = */ "memcached", /* name = */ callback_name, /* callback = */ memcached_read, - /* interval = */ 0, &(user_data_t){ - .data = st, .free_func = memcached_free, - }); - - return status; + /* interval = */ 0, + &(user_data_t){ + .data = st, .free_func = memcached_free, + }); } /* int memcached_add_read_callback */ /* Configuration handling functiions @@ -555,6 +664,8 @@ static int config_add_instance(oconfig_item_t *ci) { st->connhost = NULL; st->connport = NULL; + st->fd = -1; + if (strcasecmp(ci->key, "Instance") == 0) status = cf_util_get_string(ci, &st->name); @@ -583,19 +694,15 @@ static int config_add_instance(oconfig_item_t *ci) { break; } - if (status == 0) - status = memcached_add_read_callback(st); - if (status != 0) { memcached_free(st); return -1; } - return 0; -} + return memcached_add_read_callback(st); +} /* int config_add_instance */ static int memcached_config(oconfig_item_t *ci) { - int status = 0; _Bool have_instance_block = 0; for (int i = 0; i < ci->children_num; i++) { @@ -616,8 +723,8 @@ static int memcached_config(oconfig_item_t *ci) { child->key); } /* for (ci->children) */ - return status; -} + return 0; +} /* int memcached_config */ static int memcached_init(void) { memcached_t *st; @@ -636,11 +743,11 @@ static int memcached_init(void) { st->connhost = NULL; st->connport = NULL; + st->fd = -1; + status = memcached_add_read_callback(st); if (status == 0) memcached_have_instances = 1; - else - memcached_free(st); return status; } /* int memcached_init */ diff --git a/src/mic.c b/src/mic.c index 90a61789..3f9521d8 100644 --- a/src/mic.c +++ b/src/mic.c @@ -132,7 +132,7 @@ static void mic_submit_memory_use(int micnumber, const char *type_instance, vl.values_len = 1; strncpy(vl.plugin, "mic", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, "memory", sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); @@ -163,9 +163,8 @@ static void mic_submit_temp(int micnumber, const char *type, gauge_t value) { vl.values = &(value_t){.gauge = value}; vl.values_len = 1; - strncpy(vl.host, hostname_g, sizeof(vl.host)); strncpy(vl.plugin, "mic", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, "temperature", sizeof(vl.type)); strncpy(vl.type_instance, type, sizeof(vl.type_instance)); @@ -205,13 +204,12 @@ static void mic_submit_cpu(int micnumber, const char *type_instance, int core, vl.values = &(value_t){.derive = value}; vl.values_len = 1; - strncpy(vl.host, hostname_g, sizeof(vl.host)); strncpy(vl.plugin, "mic", sizeof(vl.plugin)); if (core < 0) /* global aggregation */ - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); else /* per-core statistics */ - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i-cpu-%i", - micnumber, core); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i-cpu-%i", + micnumber, core); strncpy(vl.type, "cpu", sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); @@ -259,9 +257,8 @@ static void mic_submit_power(int micnumber, const char *type, vl.values = &(value_t){.gauge = value}; vl.values_len = 1; - strncpy(vl.host, hostname_g, sizeof(vl.host)); strncpy(vl.plugin, "mic", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber); strncpy(vl.type, type, sizeof(vl.type)); strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); diff --git a/src/modbus.c b/src/modbus.c index f45fe21c..715724d1 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -248,7 +248,7 @@ static int mb_submit(mb_host_t *host, mb_slave_t *slave, /* {{{ */ host->interval = plugin_get_interval(); if (slave->instance[0] == 0) - ssnprintf(slave->instance, sizeof(slave->instance), "slave_%i", slave->id); + snprintf(slave->instance, sizeof(slave->instance), "slave_%i", slave->id); vl.values = &value; vl.values_len = 1; @@ -934,7 +934,7 @@ static int mb_config_add_host(oconfig_item_t *ci) /* {{{ */ if (status == 0) { char name[1024]; - ssnprintf(name, sizeof(name), "modbus-%s", host->host); + snprintf(name, sizeof(name), "modbus-%s", host->host); plugin_register_complex_read(/* group = */ NULL, name, /* callback = */ mb_read, diff --git a/src/mqtt.c b/src/mqtt.c index 36e65778..51644855 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -471,12 +471,12 @@ static int format_topic(char *buf, size_t buf_len, data_set_t const *ds, if (status != 0) return status; - status = ssnprintf(buf, buf_len, "%s/%s", conf->topic_prefix, name); + status = snprintf(buf, buf_len, "%s/%s", conf->topic_prefix, name); if ((status < 0) || (((size_t)status) >= buf_len)) return ENOMEM; - while((c = strchr(buf, '#')) || (c = strchr(buf, '+'))) { - *c = '_'; + while ((c = strchr(buf, '#')) || (c = strchr(buf, '+'))) { + *c = '_'; } return 0; @@ -525,10 +525,10 @@ static int mqtt_write(const data_set_t *ds, const value_list_t *vl, * StoreRates true * Retain false * QoS 0 - * CACert "ca.pem" Enables TLS if set - * CertificateFile "client-cert.pem" optional - * CertificateKeyFile "client-key.pem" optional - * TLSProtocol "tlsv1.2" optional + * CACert "ca.pem" Enables TLS if set + * CertificateFile "client-cert.pem" optional + * CertificateKeyFile "client-key.pem" optional + * TLSProtocol "tlsv1.2" optional * */ static int mqtt_config_publisher(oconfig_item_t *ci) { @@ -608,10 +608,11 @@ static int mqtt_config_publisher(oconfig_item_t *ci) { ERROR("mqtt plugin: Unknown config option: %s", child->key); } - ssnprintf(cb_name, sizeof(cb_name), "mqtt/%s", conf->name); - plugin_register_write(cb_name, mqtt_write, &(user_data_t){ - .data = conf, - }); + snprintf(cb_name, sizeof(cb_name), "mqtt/%s", conf->name); + plugin_register_write(cb_name, mqtt_write, + &(user_data_t){ + .data = conf, + }); return 0; } /* mqtt_config_publisher */ @@ -623,6 +624,10 @@ static int mqtt_config_publisher(oconfig_item_t *ci) { * User "guest" * Password "secret" * Topic "collectd/#" + * CACert "ca.pem" Enables TLS if set + * CertificateFile "client-cert.pem" optional + * CertificateKeyFile "client-key.pem" optional + * TLSProtocol "tlsv1.2" optional * */ static int mqtt_config_subscriber(oconfig_item_t *ci) { @@ -686,6 +691,16 @@ static int mqtt_config_subscriber(oconfig_item_t *ci) { cf_util_get_string(child, &conf->topic); else if (strcasecmp("CleanSession", child->key) == 0) cf_util_get_boolean(child, &conf->clean_session); + else if (strcasecmp("CACert", child->key) == 0) + cf_util_get_string(child, &conf->cacertificatefile); + else if (strcasecmp("CertificateFile", child->key) == 0) + cf_util_get_string(child, &conf->certificatefile); + else if (strcasecmp("CertificateKeyFile", child->key) == 0) + cf_util_get_string(child, &conf->certificatekeyfile); + else if (strcasecmp("TLSProtocol", child->key) == 0) + cf_util_get_string(child, &conf->tlsprotocol); + else if (strcasecmp("CipherSuite", child->key) == 0) + cf_util_get_string(child, &conf->ciphersuite); else ERROR("mqtt plugin: Unknown config option: %s", child->key); } diff --git a/src/msr-index.h b/src/msr-index.h new file mode 100644 index 00000000..2adca577 --- /dev/null +++ b/src/msr-index.h @@ -0,0 +1,88 @@ +/* + * 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/mysql.c b/src/mysql.c index b6edce0d..7fe6d764 100644 --- a/src/mysql.c +++ b/src/mysql.c @@ -218,7 +218,7 @@ static int mysql_config_database(oconfig_item_t *ci) /* {{{ */ (db->database != NULL) ? db->database : ""); if (db->instance != NULL) - ssnprintf(cb_name, sizeof(cb_name), "mysql-%s", db->instance); + snprintf(cb_name, sizeof(cb_name), "mysql-%s", db->instance); else sstrncpy(cb_name, "mysql", sizeof(cb_name)); @@ -496,15 +496,15 @@ static int mysql_read_slave_stats(mysql_database_t *db, MYSQL *con) { if (((io == NULL) || (strcasecmp(io, "yes") != 0)) && (db->slave_io_running)) { n.severity = NOTIF_WARNING; - ssnprintf(n.message, sizeof(n.message), - "slave I/O thread not started or not connected to master"); + snprintf(n.message, sizeof(n.message), + "slave I/O thread not started or not connected to master"); plugin_dispatch_notification(&n); db->slave_io_running = 0; } else if (((io != NULL) && (strcasecmp(io, "yes") == 0)) && (!db->slave_io_running)) { n.severity = NOTIF_OKAY; - ssnprintf(n.message, sizeof(n.message), - "slave I/O thread started and connected to master"); + snprintf(n.message, sizeof(n.message), + "slave I/O thread started and connected to master"); plugin_dispatch_notification(&n); db->slave_io_running = 1; } @@ -512,13 +512,13 @@ static int mysql_read_slave_stats(mysql_database_t *db, MYSQL *con) { if (((sql == NULL) || (strcasecmp(sql, "yes") != 0)) && (db->slave_sql_running)) { n.severity = NOTIF_WARNING; - ssnprintf(n.message, sizeof(n.message), "slave SQL thread not started"); + snprintf(n.message, sizeof(n.message), "slave SQL thread not started"); plugin_dispatch_notification(&n); db->slave_sql_running = 0; } else if (((sql != NULL) && (strcasecmp(sql, "yes") == 0)) && (!db->slave_sql_running)) { n.severity = NOTIF_OKAY; - ssnprintf(n.message, sizeof(n.message), "slave SQL thread started"); + snprintf(n.message, sizeof(n.message), "slave SQL thread started"); plugin_dispatch_notification(&n); db->slave_sql_running = 1; } diff --git a/src/netapp.c b/src/netapp.c index 701ac2f7..44fb9768 100644 --- a/src/netapp.c +++ b/src/netapp.c @@ -654,9 +654,11 @@ static int submit_derive(const char *host, const char *plugin_inst, /* {{{ */ const char *type, const char *type_inst, derive_t counter, cdtime_t timestamp, cdtime_t interval) { - return submit_values(host, plugin_inst, type, type_inst, &(value_t){ - .derive=counter, - }, 1, timestamp, interval); + return submit_values(host, plugin_inst, type, type_inst, + &(value_t){ + .derive = counter, + }, + 1, timestamp, interval); } /* }}} int submit_derive */ static int submit_two_gauge(const char *host, const char *plugin_inst, /* {{{ */ @@ -674,9 +676,11 @@ static int submit_two_gauge(const char *host, const char *plugin_inst, /* {{{ */ 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=d, - }, 1, timestamp, interval); + return submit_values(host, plugin_inst, type, type_inst, + &(value_t){ + .gauge = d, + }, + 1, timestamp, interval); } /* }}} int submit_uint64 */ /* Calculate hit ratio from old and new counters and submit the resulting @@ -769,13 +773,14 @@ static int submit_volume_perf_data(const char *hostname, /* {{{ */ if ((hostname == NULL) || (old_data == NULL) || (new_data == NULL)) return -1; - ssnprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", - old_data->name); + snprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", + old_data->name); /* Check for and submit disk-octet values */ if (HAS_ALL_FLAGS(old_data->flags, CFG_VOLUME_PERF_IO) && - HAS_ALL_FLAGS(new_data->flags, HAVE_VOLUME_PERF_BYTES_READ | - HAVE_VOLUME_PERF_BYTES_WRITE)) { + HAS_ALL_FLAGS(new_data->flags, + HAVE_VOLUME_PERF_BYTES_READ | + HAVE_VOLUME_PERF_BYTES_WRITE)) { submit_two_derive( hostname, plugin_instance, "disk_octets", /* type instance = */ NULL, (derive_t)new_data->read_bytes, (derive_t)new_data->write_bytes, @@ -793,15 +798,15 @@ static int submit_volume_perf_data(const char *hostname, /* {{{ */ } /* Check for, calculate and submit disk-latency values */ - if (HAS_ALL_FLAGS(old_data->flags, CFG_VOLUME_PERF_LATENCY | - HAVE_VOLUME_PERF_OPS_READ | - HAVE_VOLUME_PERF_OPS_WRITE | - HAVE_VOLUME_PERF_LATENCY_READ | - HAVE_VOLUME_PERF_LATENCY_WRITE) && - HAS_ALL_FLAGS(new_data->flags, HAVE_VOLUME_PERF_OPS_READ | - HAVE_VOLUME_PERF_OPS_WRITE | - HAVE_VOLUME_PERF_LATENCY_READ | - HAVE_VOLUME_PERF_LATENCY_WRITE)) { + if (HAS_ALL_FLAGS(old_data->flags, + CFG_VOLUME_PERF_LATENCY | HAVE_VOLUME_PERF_OPS_READ | + HAVE_VOLUME_PERF_OPS_WRITE | + HAVE_VOLUME_PERF_LATENCY_READ | + HAVE_VOLUME_PERF_LATENCY_WRITE) && + HAS_ALL_FLAGS(new_data->flags, + HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE | + HAVE_VOLUME_PERF_LATENCY_READ | + HAVE_VOLUME_PERF_LATENCY_WRITE)) { gauge_t latency_per_op_read; gauge_t latency_per_op_write; @@ -1399,10 +1404,11 @@ static int cna_submit_volume_usage_data(const char *hostname, /* {{{ */ uint64_t snap_reserve_free = v->snap_reserved; uint64_t snap_norm_used = v->snap_used; - ssnprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", v->name); + snprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", v->name); - if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_SNAP_USED | - HAVE_VOLUME_USAGE_SNAP_RSVD)) { + if (HAS_ALL_FLAGS(v->flags, + HAVE_VOLUME_USAGE_SNAP_USED | + HAVE_VOLUME_USAGE_SNAP_RSVD)) { if (v->snap_reserved > v->snap_used) { snap_reserve_free = v->snap_reserved - v->snap_used; snap_reserve_used = v->snap_used; @@ -1416,8 +1422,9 @@ static int cna_submit_volume_usage_data(const char *hostname, /* {{{ */ /* The space used by snapshots but not reserved for them is included in * both, norm_used and snap_norm_used. If possible, subtract this here. */ - if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_NORM_USED | - HAVE_VOLUME_USAGE_SNAP_USED)) { + if (HAS_ALL_FLAGS(v->flags, + HAVE_VOLUME_USAGE_NORM_USED | + HAVE_VOLUME_USAGE_SNAP_USED)) { if (norm_used >= snap_norm_used) norm_used -= snap_norm_used; else { @@ -1459,8 +1466,9 @@ static int cna_submit_volume_usage_data(const char *hostname, /* {{{ */ "df_complex", "snap_reserved", (double)snap_reserve_free, /* timestamp = */ 0, interval); - if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_SNAP_USED | - HAVE_VOLUME_USAGE_SNAP_RSVD)) + if (HAS_ALL_FLAGS(v->flags, + HAVE_VOLUME_USAGE_SNAP_USED | + HAVE_VOLUME_USAGE_SNAP_RSVD)) submit_double(hostname, /* plugin instance = */ plugin_instance, "df_complex", "snap_reserve_used", (double)snap_reserve_used, /* timestamp = */ 0, interval); @@ -1490,13 +1498,12 @@ static int cna_change_volume_status(const char *hostname, /* {{{ */ if ((v->flags & IS_VOLUME_USAGE_OFFLINE) != 0) { n.severity = NOTIF_OKAY; - ssnprintf(n.message, sizeof(n.message), "Volume %s is now online.", - v->name); + snprintf(n.message, sizeof(n.message), "Volume %s is now online.", v->name); v->flags &= ~IS_VOLUME_USAGE_OFFLINE; } else { n.severity = NOTIF_WARNING; - ssnprintf(n.message, sizeof(n.message), "Volume %s is now offline.", - v->name); + snprintf(n.message, sizeof(n.message), "Volume %s is now offline.", + v->name); v->flags |= IS_VOLUME_USAGE_OFFLINE; } @@ -1723,8 +1730,8 @@ static int cna_handle_volume_usage_data(const host_config_t *host, /* {{{ */ } } /* for (elem_volume) */ - return cna_submit_volume_usage_data(host->name, cfg_volume, - host->cfg_volume_usage->interval.interval); + return cna_submit_volume_usage_data( + host->name, cfg_volume, host->cfg_volume_usage->interval.interval); } /* }}} int cna_handle_volume_usage_data */ static int cna_setup_volume_usage(cfg_volume_usage_t *cvu) /* {{{ */ @@ -1825,8 +1832,8 @@ static int cna_handle_quota_data(const host_config_t *host, /* {{{ */ if (volume_name == NULL) continue; - ssnprintf(plugin_instance, sizeof(plugin_instance), "quota-%s-%s", - volume_name, tree_name); + snprintf(plugin_instance, sizeof(plugin_instance), "quota-%s-%s", + volume_name, tree_name); value = na_child_get_uint64(elem_quota, "disk-used", UINT64_MAX); if (value != UINT64_MAX) { @@ -1938,8 +1945,8 @@ static int cna_handle_snapvault_data(const char *hostname, /* {{{ */ continue; /* possible TODO: make plugin instance configurable */ - ssnprintf(plugin_instance, sizeof(plugin_instance), "snapvault-%s", - dest_path); + snprintf(plugin_instance, sizeof(plugin_instance), "snapvault-%s", + dest_path); submit_double(hostname, plugin_instance, /* type = */ "delay", NULL, (double)value, /* timestamp = */ 0, interval); @@ -2816,10 +2823,10 @@ static int cna_register_host(host_config_t *host) /* {{{ */ char cb_name[256]; if (host->vfiler) - ssnprintf(cb_name, sizeof(cb_name), "netapp-%s-%s", host->name, - host->vfiler); + snprintf(cb_name, sizeof(cb_name), "netapp-%s-%s", host->name, + host->vfiler); else - ssnprintf(cb_name, sizeof(cb_name), "netapp-%s", host->name); + snprintf(cb_name, sizeof(cb_name), "netapp-%s", host->name); plugin_register_complex_read( /* group = */ NULL, cb_name, diff --git a/src/netlink.c b/src/netlink.c index 3cc1084b..0bac3e75 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -495,8 +495,8 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) { if (strcmp(tc_type, "filter") == 0) numberic_id = tm->tcm_parent; - ssnprintf(tc_inst, sizeof(tc_inst), "%s-%x:%x", kind, numberic_id >> 16, - numberic_id & 0x0000FFFF); + snprintf(tc_inst, sizeof(tc_inst), "%s-%x:%x", kind, numberic_id >> 16, + numberic_id & 0x0000FFFF); } DEBUG("netlink plugin: qos_filter_cb: got %s for %s (%i).", tc_type, dev, @@ -527,8 +527,7 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) { stats_submitted = 1; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type, - tc_inst); + snprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type, tc_inst); if (q_stats.bs != NULL) { submit_one(dev, "ipt_bytes", type_instance, q_stats.bs->bytes); @@ -560,8 +559,7 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) { if (!stats_submitted && ts != NULL) { char type_instance[DATA_MAX_NAME_LEN]; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type, - tc_inst); + snprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type, tc_inst); submit_one(dev, "ipt_bytes", type_instance, ts->bytes); submit_one(dev, "ipt_packets", type_instance, ts->packets); diff --git a/src/network.c b/src/network.c index 00c6c756..4e684215 100644 --- a/src/network.c +++ b/src/network.c @@ -1230,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; } @@ -1254,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/nfs.c b/src/nfs.c index 62906133..a7adc920 100644 --- a/src/nfs.c +++ b/src/nfs.c @@ -31,6 +31,12 @@ #include #endif +static const char *config_keys[] = {"ReportV2", "ReportV3", "ReportV4"}; +static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); +static _Bool report_v2 = 1; +static _Bool report_v3 = 1; +static _Bool report_v4 = 1; + /* see /proc/net/rpc/nfs see http://www.missioncriticallinux.com/orph/NFS-Statistics @@ -295,6 +301,19 @@ static kstat_t *nfs4_ksp_client; static kstat_t *nfs4_ksp_server; #endif +static int nfs_config(const char *key, const char *value) { + if (strcasecmp(key, "ReportV2") == 0) + report_v2 = IS_TRUE(value); + else if (strcasecmp(key, "ReportV3") == 0) + report_v3 = IS_TRUE(value); + else if (strcasecmp(key, "ReportV4") == 0) + report_v4 = IS_TRUE(value); + else + return -1; + + return 0; +} + #if KERNEL_LINUX static int nfs_init(void) { return 0; } /* #endif KERNEL_LINUX */ @@ -357,8 +376,8 @@ static void nfs_submit_fields(int nfs_version, const char *instance, char plugin_instance[DATA_MAX_NAME_LEN]; value_t values[fields_num]; - ssnprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version, - instance); + snprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version, + instance); for (size_t i = 0; i < fields_num; i++) (void)parse_value(fields[i], &values[i], DS_TYPE_DERIVE); @@ -495,18 +514,18 @@ static void nfs_read_linux(FILE *fh, const char *inst) { if (fields_num < 3) continue; - if (strcmp(fields[0], "proc2") == 0) { + if (strcmp(fields[0], "proc2") == 0 && report_v2) { nfs_submit_fields_safe(/* version = */ 2, inst, fields + 2, (size_t)(fields_num - 2), nfs2_procedures_names, nfs2_procedures_names_num); - } else if (strncmp(fields[0], "proc3", 5) == 0) { + } else if (strncmp(fields[0], "proc3", 5) == 0 && report_v3) { nfs_submit_fields_safe(/* version = */ 3, inst, fields + 2, (size_t)(fields_num - 2), nfs3_procedures_names, nfs3_procedures_names_num); - } else if (strcmp(fields[0], "proc4ops") == 0) { + } else if (strcmp(fields[0], "proc4ops") == 0 && report_v4) { if (inst[0] == 's') nfs_submit_nfs4_server(inst, fields + 2, (size_t)(fields_num - 2)); - } else if (strcmp(fields[0], "proc4") == 0) { + } else if (strcmp(fields[0], "proc4") == 0 && report_v4) { if (inst[0] == 'c') nfs_submit_nfs4_client(inst, fields + 2, (size_t)(fields_num - 2)); } @@ -523,8 +542,8 @@ static int nfs_read_kstat(kstat_t *ksp, int nfs_version, const char *inst, if (ksp == NULL) return EINVAL; - ssnprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version, - inst); + snprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version, + inst); kstat_read(kc, ksp, NULL); for (size_t i = 0; i < proc_names_num; i++) { @@ -561,24 +580,31 @@ static int nfs_read(void) { #elif HAVE_LIBKSTAT static int nfs_read(void) { - nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client", - nfs2_procedures_names, nfs2_procedures_names_num); - nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server", - nfs2_procedures_names, nfs2_procedures_names_num); - nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client", - nfs3_procedures_names, nfs3_procedures_names_num); - nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server", - nfs3_procedures_names, nfs3_procedures_names_num); - nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client", - nfs4_procedures_names, nfs4_procedures_names_num); - nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server", - nfs4_procedures_names, nfs4_procedures_names_num); + if (report_v2) { + nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client", + nfs2_procedures_names, nfs2_procedures_names_num); + nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server", + nfs2_procedures_names, nfs2_procedures_names_num); + } + if (report_v3) { + nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client", + nfs3_procedures_names, nfs3_procedures_names_num); + nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server", + nfs3_procedures_names, nfs3_procedures_names_num); + } + if (report_v4) { + nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client", + nfs4_procedures_names, nfs4_procedures_names_num); + nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server", + nfs4_procedures_names, nfs4_procedures_names_num); + } return 0; } #endif /* HAVE_LIBKSTAT */ void module_register(void) { + plugin_register_config("nfs", nfs_config, config_keys, config_keys_num); plugin_register_init("nfs", nfs_init); plugin_register_read("nfs", nfs_read); } /* void module_register */ diff --git a/src/nginx.c b/src/nginx.c index c7e8a08e..88118b9b 100644 --- a/src/nginx.c +++ b/src/nginx.c @@ -122,8 +122,8 @@ static int init(void) { curl_easy_setopt(curl, CURLOPT_PASSWORD, (pass == NULL) ? "" : pass); #else static char credentials[1024]; - int status = ssnprintf(credentials, sizeof(credentials), "%s:%s", user, - pass == NULL ? "" : pass); + int status = snprintf(credentials, sizeof(credentials), "%s:%s", user, + pass == NULL ? "" : pass); if ((status < 0) || ((size_t)status >= sizeof(credentials))) { ERROR("nginx plugin: Credentials would have been truncated."); return -1; diff --git a/src/notify_desktop.c b/src/notify_desktop.c index d167fbfe..e391cf27 100644 --- a/src/notify_desktop.c +++ b/src/notify_desktop.c @@ -93,12 +93,12 @@ static int c_notify(const notification_t *n, timeout = fail_timeout; } - ssnprintf(summary, sizeof(summary), "collectd %s notification", - (NOTIF_FAILURE == n->severity) - ? "FAILURE" - : (NOTIF_WARNING == n->severity) - ? "WARNING" - : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN"); + snprintf(summary, sizeof(summary), "collectd %s notification", + (NOTIF_FAILURE == n->severity) + ? "FAILURE" + : (NOTIF_WARNING == n->severity) + ? "WARNING" + : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN"); notification = notify_notification_new(summary, n->message, NULL #if NOTIFY_CHECK_VERSION(0, 7, 0) diff --git a/src/notify_email.c b/src/notify_email.c index c1ce2f8b..52cc8384 100644 --- a/src/notify_email.c +++ b/src/notify_email.c @@ -104,8 +104,8 @@ static void monitor_cb(const char *buf, int buflen, int writing, static int notify_email_init(void) { char server[MAXSTRING]; - ssnprintf(server, sizeof(server), "%s:%i", - (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host, smtp_port); + snprintf(server, sizeof(server), "%s:%i", + (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host, smtp_port); pthread_mutex_lock(&session_lock); @@ -214,16 +214,16 @@ static int notify_email_notification(const notification_t *n, int buf_len = sizeof(buf); int i; - ssnprintf(severity, sizeof(severity), "%s", - (n->severity == NOTIF_FAILURE) - ? "FAILURE" - : ((n->severity == NOTIF_WARNING) - ? "WARNING" - : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN"))); + snprintf(severity, sizeof(severity), "%s", + (n->severity == NOTIF_FAILURE) + ? "FAILURE" + : ((n->severity == NOTIF_WARNING) + ? "WARNING" + : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN"))); - ssnprintf(subject, sizeof(subject), - (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject, - severity, n->host); + snprintf(subject, sizeof(subject), + (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject, + severity, n->host); localtime_r(&CDTIME_T_TO_TIME_T(n->time), ×tamp_tm); strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", @@ -231,15 +231,15 @@ static int notify_email_notification(const notification_t *n, timestamp_str[sizeof(timestamp_str) - 1] = '\0'; /* Let's make RFC822 message text with \r\n EOLs */ - ssnprintf(buf, buf_len, "MIME-Version: 1.0\r\n" - "Content-Type: text/plain; charset=\"US-ASCII\"\r\n" - "Content-Transfer-Encoding: 8bit\r\n" - "Subject: %s\r\n" - "\r\n" - "%s - %s@%s\r\n" - "\r\n" - "Message: %s", - subject, timestamp_str, severity, n->host, n->message); + snprintf(buf, buf_len, "MIME-Version: 1.0\r\n" + "Content-Type: text/plain; charset=\"US-ASCII\"\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "Subject: %s\r\n" + "\r\n" + "%s - %s@%s\r\n" + "\r\n" + "Message: %s", + subject, timestamp_str, severity, n->host, n->message); pthread_mutex_lock(&session_lock); diff --git a/src/notify_nagios.c b/src/notify_nagios.c index c95f7cb9..f744d486 100644 --- a/src/notify_nagios.c +++ b/src/notify_nagios.c @@ -141,10 +141,10 @@ static int nagios_notify(const notification_t *n, /* {{{ */ break; } - ssnprintf(buffer, sizeof(buffer), - "[%.0f] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", - CDTIME_T_TO_DOUBLE(n->time), n->host, &svc_description[1], code, - n->message); + snprintf(buffer, sizeof(buffer), + "[%.0f] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", + CDTIME_T_TO_DOUBLE(n->time), n->host, &svc_description[1], code, + n->message); return nagios_print(buffer); } /* }}} int nagios_notify */ diff --git a/src/ntpd.c b/src/ntpd.c index 68ac3a75..48d7aa72 100644 --- a/src/ntpd.c +++ b/src/ntpd.c @@ -267,7 +267,7 @@ static int ntpd_config(const char *key, const char *value) { } else if (strcasecmp(key, "Port") == 0) { int port = (int)(atof(value)); if ((port > 0) && (port <= 65535)) - ssnprintf(ntpd_port, sizeof(ntpd_port), "%i", port); + snprintf(ntpd_port, sizeof(ntpd_port), "%i", port); else sstrncpy(ntpd_port, value, sizeof(ntpd_port)); } else if (strcasecmp(key, "ReverseLookups") == 0) { @@ -782,8 +782,8 @@ static int ntpd_get_name_refclock(char *buffer, size_t buffer_size, return ntpd_get_name_from_address(buffer, buffer_size, peer_info, 0); if (include_unit_id) - ssnprintf(buffer, buffer_size, "%s-%" PRIu32, refclock_names[refclock_id], - unit_id); + snprintf(buffer, buffer_size, "%s-%" PRIu32, refclock_names[refclock_id], + unit_id); else sstrncpy(buffer, refclock_names[refclock_id], buffer_size); @@ -846,9 +846,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/numa.c b/src/numa.c index 6ef3f090..56ea707c 100644 --- a/src/numa.c +++ b/src/numa.c @@ -47,7 +47,7 @@ static void numa_dispatch_value(int node, /* {{{ */ vl.values_len = 1; sstrncpy(vl.plugin, "numa", sizeof(vl.plugin)); - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "node%i", node); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "node%i", node); sstrncpy(vl.type, "vmpage_action", sizeof(vl.type)); sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); @@ -62,7 +62,7 @@ static int numa_read_node(int node) /* {{{ */ int status; int success; - ssnprintf(path, sizeof(path), NUMA_ROOT_DIR "/node%i/numastat", node); + snprintf(path, sizeof(path), NUMA_ROOT_DIR "/node%i/numastat", node); fh = fopen(path, "r"); if (fh == NULL) { @@ -127,7 +127,7 @@ static int numa_init(void) /* {{{ */ struct stat statbuf = {0}; int status; - ssnprintf(path, sizeof(path), NUMA_ROOT_DIR "/node%i", max_node + 1); + snprintf(path, sizeof(path), NUMA_ROOT_DIR "/node%i", max_node + 1); status = stat(path, &statbuf); if (status == 0) { diff --git a/src/nut.c b/src/nut.c index 2173af9b..58c7d797 100644 --- a/src/nut.c +++ b/src/nut.c @@ -22,6 +22,7 @@ * * Authors: * Florian octo Forster + * Pavel Rochnyak **/ #include "collectd.h" @@ -49,18 +50,20 @@ struct nut_ups_s { nut_ups_t *next; }; -static nut_ups_t *upslist_head = NULL; - -static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER; -static int read_busy = 0; - -static const char *config_keys[] = {"UPS", "FORCESSL", "VERIFYPEER", "CAPATH"}; +static const char *config_keys[] = {"UPS", "FORCESSL", "VERIFYPEER", "CAPATH", + "CONNECTTIMEOUT"}; static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); static int force_ssl = 0; // Initialized to default of 0 (false) static int verify_peer = 0; // Initialized to default of 0 (false) +static int ssl_flags = UPSCLI_CONN_TRYSSL; +static int connect_timeout = -1; static char *ca_path = NULL; -static void free_nut_ups_t(nut_ups_t *ups) { +static int nut_read(user_data_t *user_data); + +static void free_nut_ups_t(void *arg) { + nut_ups_t *ups = arg; + if (ups->conn != NULL) { upscli_disconnect(ups->conn); sfree(ups->conn); @@ -73,6 +76,7 @@ static void free_nut_ups_t(nut_ups_t *ups) { static int nut_add_ups(const char *name) { nut_ups_t *ups; int status; + char *cb_name; DEBUG("nut plugin: nut_add_ups (name = %s);", name); @@ -89,13 +93,24 @@ static int nut_add_ups(const char *name) { return 1; } - if (upslist_head == NULL) - upslist_head = ups; - else { - nut_ups_t *last = upslist_head; - while (last->next != NULL) - last = last->next; - last->next = ups; + cb_name = ssnprintf_alloc("nut/%s", name); + + status = plugin_register_complex_read( + /* group = */ "nut", + /* name = */ cb_name, + /* callback = */ nut_read, + /* interval = */ 0, + /* user_data = */ &(user_data_t){ + .data = ups, .free_func = free_nut_ups_t, + }); + + sfree(cb_name); + + if (status == EINVAL) { + WARNING("nut plugin: UPS \"%s\" already added. " + "Please check your configuration.", + name); + return -1; } return 0; @@ -137,6 +152,24 @@ static int nut_ca_path(const char *value) { return 0; } /* int nut_ca_path */ +static int nut_set_connect_timeout(const char *value) { +#if HAVE_UPSCLI_TRYCONNECT + long ret; + + errno = 0; + ret = strtol(value, /* endptr = */ NULL, /* base = */ 10); + if (errno == 0) + connect_timeout = ret; + else + WARNING("nut plugin: The ConnectTimeout option requires numeric argument. " + "Setting ignored."); +#else /* #if HAVE_UPSCLI_TRYCONNECT */ + WARNING("nut plugin: Dependency libupsclient version insufficient (<2.6.2) " + "for ConnectTimeout option support. Setting ignored."); +#endif + return 0; +} /* int nut_set_connect_timeout */ + static int nut_config(const char *key, const char *value) { if (strcasecmp(key, "UPS") == 0) return nut_add_ups(value); @@ -146,6 +179,8 @@ static int nut_config(const char *key, const char *value) { return nut_verify_peer(value); else if (strcasecmp(key, "CAPATH") == 0) return nut_ca_path(value); + else if (strcasecmp(key, "CONNECTTIMEOUT") == 0) + return nut_set_connect_timeout(value); else return -1; } /* int nut_config */ @@ -156,10 +191,8 @@ static void nut_submit(nut_ups_t *ups, const char *type, vl.values = &(value_t){.gauge = value}; vl.values_len = 1; - sstrncpy(vl.host, - (strcasecmp(ups->hostname, "localhost") == 0) ? hostname_g - : ups->hostname, - sizeof(vl.host)); + if (strcasecmp(ups->hostname, "localhost") != 0) + sstrncpy(vl.host, ups->hostname, sizeof(vl.host)); sstrncpy(vl.plugin, "nut", sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, ups->upsname, sizeof(vl.plugin_instance)); sstrncpy(vl.type, type, sizeof(vl.type)); @@ -169,48 +202,23 @@ static void nut_submit(nut_ups_t *ups, const char *type, } /* void nut_submit */ static int nut_connect(nut_ups_t *ups) { -#if HAVE_UPSCLI_INIT - int status; - int ssl_status; - int ssl_flags; + int status, ssl_status; - if (verify_peer == 1 && force_ssl == 0) { - WARNING("nut plugin: nut_connect: VerifyPeer true but ForceSSL " - "false. Setting ForceSSL to true."); - force_ssl = 1; - } - - if (verify_peer == 1 && ca_path == NULL) { - ERROR("nut plugin: nut_connect: VerifyPeer true but missing " - "CAPath value."); - return -1; - } - - if (verify_peer == 1) { - status = upscli_init(verify_peer, ca_path, NULL, NULL); - - if (status != 1) { - ERROR("nut plugin: nut_connect: upscli_init (%i, %s) failed: %s", - verify_peer, ca_path, upscli_strerror(ups->conn)); - upscli_cleanup(); - return -1; - } - } /* if (verify_peer == 1) */ - - if (verify_peer == 1) - ssl_flags = (UPSCLI_CONN_REQSSL | UPSCLI_CONN_CERTVERIF); - else if (force_ssl == 1) - ssl_flags = UPSCLI_CONN_REQSSL; - else - ssl_flags = UPSCLI_CONN_TRYSSL; +#if HAVE_UPSCLI_TRYCONNECT + struct timeval tv; + tv.tv_sec = connect_timeout / 1000; + tv.tv_usec = connect_timeout % 1000; + status = + upscli_tryconnect(ups->conn, ups->hostname, ups->port, ssl_flags, &tv); +#else /* #if HAVE_UPSCLI_TRYCONNECT */ status = upscli_connect(ups->conn, ups->hostname, ups->port, ssl_flags); +#endif if (status != 0) { ERROR("nut plugin: nut_connect: upscli_connect (%s, %i) failed: %s", ups->hostname, ups->port, upscli_strerror(ups->conn)); sfree(ups->conn); - upscli_cleanup(); return -1; } /* if (status != 0) */ @@ -231,57 +239,13 @@ static int nut_connect(nut_ups_t *ups) { ERROR("nut plugin: nut_connect: upscli_ssl failed: %s", upscli_strerror(ups->conn)); sfree(ups->conn); - upscli_cleanup(); return -1; } /* if (ssl_status == 1 && verify_peer == 1) */ return 0; - -#else /* #if HAVE_UPSCLI_INIT */ - int status; - int ssl_status; - int ssl_flags; - - if (verify_peer == 1 || ca_path != NULL) { - WARNING("nut plugin: nut_connect: Dependency libupsclient version " - "insufficient (<2.7) for VerifyPeer support. Ignoring VerifyPeer " - "and CAPath."); - } - - if (force_ssl == 1) - ssl_flags = UPSCLI_CONN_REQSSL; - else - ssl_flags = UPSCLI_CONN_TRYSSL; - - status = upscli_connect(ups->conn, ups->hostname, ups->port, ssl_flags); - - if (status != 0) { - ERROR("nut plugin: nut_connect: upscli_connect (%s, %i) failed: %s", - ups->hostname, ups->port, upscli_strerror(ups->conn)); - sfree(ups->conn); - return -1; - } /* if (status != 0) */ - - INFO("nut plugin: Connection to (%s, %i) established.", ups->hostname, - ups->port); - - // Output INFO or WARNING based on SSL - ssl_status = upscli_ssl(ups->conn); // 1 for SSL, 0 for not, -1 for error - if (ssl_status == 1) { - INFO("nut plugin: Connection is secured with SSL with no verification " - "of server SSL certificate."); - } else if (ssl_status == 0) { - WARNING("nut plugin: Connection is unsecured (no SSL)."); - } else { - ERROR("nut plugin: nut_connect: upscli_ssl failed: %s", - upscli_strerror(ups->conn)); - sfree(ups->conn); - return -1; - } /* if (ssl_status == 1 && verify_peer == 1) */ - return 0; -#endif } -static int nut_read_one(nut_ups_t *ups) { +static int nut_read(user_data_t *user_data) { + nut_ups_t *ups = user_data->data; const char *query[3] = {"VAR", ups->upsname, NULL}; unsigned int query_num = 2; char **answer; @@ -306,13 +270,10 @@ static int nut_read_one(nut_ups_t *ups) { * error */ status = upscli_list_start(ups->conn, query_num, query); if (status != 0) { - ERROR("nut plugin: nut_read_one: upscli_list_start (%s) failed: %s", + ERROR("nut plugin: nut_read: upscli_list_start (%s) failed: %s", ups->upsname, upscli_strerror(ups->conn)); upscli_disconnect(ups->conn); sfree(ups->conn); -#if HAVE_UPSCLI_INIT - upscli_cleanup(); -#endif return -1; } @@ -366,40 +327,58 @@ static int nut_read_one(nut_ups_t *ups) { } /* while (upscli_list_next) */ return 0; -} /* int nut_read_one */ +} /* int nut_read */ + +static int nut_init(void) { +#if HAVE_UPSCLI_INIT + if (verify_peer == 1 && force_ssl == 0) { + WARNING("nut plugin: nut_connect: VerifyPeer true but ForceSSL " + "false. Setting ForceSSL to true."); + force_ssl = 1; + } + + if (verify_peer == 1 && ca_path == NULL) { + ERROR("nut plugin: nut_connect: VerifyPeer true but missing " + "CAPath value."); + plugin_unregister_read_group("nut"); + return -1; + } -static int nut_read(void) { - int success = 0; + if (verify_peer == 1 || force_ssl == 1) { + int status = upscli_init(verify_peer, ca_path, NULL, NULL); - pthread_mutex_lock(&read_lock); - success = read_busy; - read_busy = 1; - pthread_mutex_unlock(&read_lock); + if (status != 1) { + ERROR("nut plugin: upscli_init (%i, %s) failed", verify_peer, ca_path); + upscli_cleanup(); + plugin_unregister_read_group("nut"); + return -1; + } + } /* if (verify_peer == 1) */ + + if (verify_peer == 1) + ssl_flags = (UPSCLI_CONN_REQSSL | UPSCLI_CONN_CERTVERIF); + else if (force_ssl == 1) + ssl_flags = UPSCLI_CONN_REQSSL; - if (success != 0) - return 0; +#else /* #if HAVE_UPSCLI_INIT */ + if (verify_peer == 1 || ca_path != NULL) { + WARNING("nut plugin: nut_connect: Dependency libupsclient version " + "insufficient (<2.7) for VerifyPeer support. Ignoring VerifyPeer " + "and CAPath."); + verify_peer = 0; + } - for (nut_ups_t *ups = upslist_head; ups != NULL; ups = ups->next) - if (nut_read_one(ups) == 0) - success++; + if (force_ssl == 1) + ssl_flags = UPSCLI_CONN_REQSSL; +#endif - pthread_mutex_lock(&read_lock); - read_busy = 0; - pthread_mutex_unlock(&read_lock); + if (connect_timeout <= 0) + connect_timeout = (long)CDTIME_T_TO_MS(plugin_get_interval()); - return (success != 0) ? 0 : -1; -} /* int nut_read */ + return 0; +} /* int nut_init */ static int nut_shutdown(void) { - nut_ups_t *this; - nut_ups_t *next; - - this = upslist_head; - while (this != NULL) { - next = this->next; - free_nut_ups_t(this); - this = next; - } #if HAVE_UPSCLI_INIT upscli_cleanup(); #endif @@ -409,6 +388,6 @@ static int nut_shutdown(void) { void module_register(void) { plugin_register_config("nut", nut_config, config_keys, config_keys_num); - plugin_register_read("nut", nut_read); + plugin_register_init("nut", nut_init); plugin_register_shutdown("nut", nut_shutdown); } /* void module_register */ diff --git a/src/olsrd.c b/src/olsrd.c index eccafae2..1ac1d426 100644 --- a/src/olsrd.c +++ b/src/olsrd.c @@ -294,8 +294,8 @@ static int olsrd_cb_links(int lineno, /* {{{ */ if (config_want_links == OLSRD_WANT_DETAIL) { char type_instance[DATA_MAX_NAME_LEN]; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-lq", fields[0], - fields[1]); + snprintf(type_instance, sizeof(type_instance), "%s-%s-lq", fields[0], + fields[1]); DEBUG("olsrd plugin: links: type_instance = %s; lq = %g;", type_instance, lq); @@ -318,8 +318,8 @@ static int olsrd_cb_links(int lineno, /* {{{ */ if (config_want_links == OLSRD_WANT_DETAIL) { char type_instance[DATA_MAX_NAME_LEN]; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-rx", fields[0], - fields[1]); + snprintf(type_instance, sizeof(type_instance), "%s-%s-rx", fields[0], + fields[1]); DEBUG("olsrd plugin: links: type_instance = %s; nlq = %g;", type_instance, lq); @@ -496,8 +496,8 @@ static int olsrd_cb_topology(int lineno, /* {{{ */ if (config_want_topology == OLSRD_WANT_DETAIL) { char type_instance[DATA_MAX_NAME_LEN] = {0}; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-lq", fields[0], - fields[1]); + snprintf(type_instance, sizeof(type_instance), "%s-%s-lq", fields[0], + fields[1]); DEBUG("olsrd plugin: type_instance = %s; lq = %g;", type_instance, lq); olsrd_submit(/* p.-inst = */ "topology", /* type = */ "signal_quality", type_instance, lq); @@ -515,8 +515,8 @@ static int olsrd_cb_topology(int lineno, /* {{{ */ } else { char type_instance[DATA_MAX_NAME_LEN] = {0}; - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-nlq", fields[0], - fields[1]); + snprintf(type_instance, sizeof(type_instance), "%s-%s-nlq", fields[0], + fields[1]); DEBUG("olsrd plugin: type_instance = %s; nlq = %g;", type_instance, nlq); olsrd_submit(/* p.-inst = */ "topology", /* type = */ "signal_quality", type_instance, nlq); diff --git a/src/onewire.c b/src/onewire.c index 2d594ec9..5c5152db 100644 --- a/src/onewire.c +++ b/src/onewire.c @@ -350,11 +350,11 @@ static int cow_read_ds2409(const char *path) { char subpath[4096]; int status; - status = ssnprintf(subpath, sizeof(subpath), "%s/main", path); + status = snprintf(subpath, sizeof(subpath), "%s/main", path); if ((status > 0) && (status < (int)sizeof(subpath))) cow_read_bus(subpath); - status = ssnprintf(subpath, sizeof(subpath), "%s/aux", path); + status = snprintf(subpath, sizeof(subpath), "%s/aux", path); if ((status > 0) && (status < (int)sizeof(subpath))) cow_read_bus(subpath); @@ -388,9 +388,9 @@ static int cow_read_bus(const char *path) { dummy = NULL; if (strcmp("/", path) == 0) - status = ssnprintf(subpath, sizeof(subpath), "/%s", buffer_ptr); + status = snprintf(subpath, sizeof(subpath), "/%s", buffer_ptr); else - status = ssnprintf(subpath, sizeof(subpath), "%s/%s", path, buffer_ptr); + status = snprintf(subpath, sizeof(subpath), "%s/%s", path, buffer_ptr); if ((status <= 0) || (status >= (int)sizeof(subpath))) continue; diff --git a/src/openldap.c b/src/openldap.c index 80539290..afe2479e 100644 --- a/src/openldap.c +++ b/src/openldap.c @@ -47,7 +47,6 @@ struct cldap_s /* {{{ */ char *password; char *cacert; char *host; - int state; _Bool starttls; int timeout; char *url; @@ -58,11 +57,10 @@ struct cldap_s /* {{{ */ }; typedef struct cldap_s cldap_t; /* }}} */ -static cldap_t **databases = NULL; -static size_t databases_num = 0; - -static void cldap_free(cldap_t *st) /* {{{ */ +static void cldap_free(void *arg) /* {{{ */ { + cldap_t *st = arg; + if (st == NULL) return; @@ -73,32 +71,30 @@ static void cldap_free(cldap_t *st) /* {{{ */ sfree(st->name); sfree(st->url); if (st->ld) - ldap_memfree(st->ld); + ldap_unbind_ext_s(st->ld, NULL, NULL); + sfree(st); } /* }}} void cldap_free */ /* initialize ldap for each host */ static int cldap_init_host(cldap_t *st) /* {{{ */ { - LDAP *ld; int rc; - if (st->state && st->ld) { + if (st->ld) { DEBUG("openldap plugin: Already connected to %s", st->url); return 0; } - rc = ldap_initialize(&ld, st->url); + rc = ldap_initialize(&st->ld, st->url); if (rc != LDAP_SUCCESS) { ERROR("openldap plugin: ldap_initialize failed: %s", ldap_err2string(rc)); - st->state = 0; - if (ld != NULL) - ldap_unbind_ext_s(ld, NULL, NULL); + if (st->ld != NULL) + ldap_unbind_ext_s(st->ld, NULL, NULL); + st->ld = NULL; return (-1); } - st->ld = ld; - ldap_set_option(st->ld, LDAP_OPT_PROTOCOL_VERSION, &st->version); ldap_set_option(st->ld, LDAP_OPT_TIMEOUT, @@ -115,13 +111,12 @@ static int cldap_init_host(cldap_t *st) /* {{{ */ } if (st->starttls != 0) { - rc = ldap_start_tls_s(ld, NULL, NULL); + rc = ldap_start_tls_s(st->ld, NULL, NULL); if (rc != LDAP_SUCCESS) { ERROR("openldap plugin: Failed to start tls on %s: %s", st->url, ldap_err2string(rc)); - st->state = 0; - if (st->ld != NULL) - ldap_unbind_ext_s(st->ld, NULL, NULL); + ldap_unbind_ext_s(st->ld, NULL, NULL); + st->ld = NULL; return (-1); } } @@ -140,13 +135,11 @@ static int cldap_init_host(cldap_t *st) /* {{{ */ if (rc != LDAP_SUCCESS) { ERROR("openldap plugin: Failed to bind to %s: %s", st->url, ldap_err2string(rc)); - st->state = 0; - if (st->ld != NULL) - ldap_unbind_ext_s(st->ld, NULL, NULL); + ldap_unbind_ext_s(st->ld, NULL, NULL); + st->ld = NULL; return (-1); } else { DEBUG("openldap plugin: Successfully connected to %s", st->url); - st->state = 1; return 0; } } /* }}} static cldap_init_host */ @@ -216,9 +209,8 @@ static int cldap_read_host(user_data_t *ud) /* {{{ */ if (rc != LDAP_SUCCESS) { ERROR("openldap plugin: Failed to execute search: %s", ldap_err2string(rc)); ldap_msgfree(result); - st->state = 0; - if (st->ld != NULL) - ldap_unbind_ext_s(st->ld, NULL, NULL); + ldap_unbind_ext_s(st->ld, NULL, NULL); + st->ld = NULL; return (-1); } @@ -314,8 +306,8 @@ static int cldap_read_host(user_data_t *ud) /* {{{ */ if ((olmbdb_list = ldap_get_values_len(st->ld, e, "olmBDBEntryCache")) != NULL) { olmbdb_data = *olmbdb_list[0]; - ssnprintf(typeinst, sizeof(typeinst), "bdbentrycache-%s", - nc_data.bv_val); + snprintf(typeinst, sizeof(typeinst), "bdbentrycache-%s", + nc_data.bv_val); cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val), st); ldap_value_free_len(olmbdb_list); @@ -324,8 +316,7 @@ static int cldap_read_host(user_data_t *ud) /* {{{ */ if ((olmbdb_list = ldap_get_values_len(st->ld, e, "olmBDBDNCache")) != NULL) { olmbdb_data = *olmbdb_list[0]; - ssnprintf(typeinst, sizeof(typeinst), "bdbdncache-%s", - nc_data.bv_val); + snprintf(typeinst, sizeof(typeinst), "bdbdncache-%s", nc_data.bv_val); cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val), st); ldap_value_free_len(olmbdb_list); @@ -334,8 +325,8 @@ static int cldap_read_host(user_data_t *ud) /* {{{ */ if ((olmbdb_list = ldap_get_values_len(st->ld, e, "olmBDBIDLCache")) != NULL) { olmbdb_data = *olmbdb_list[0]; - ssnprintf(typeinst, sizeof(typeinst), "bdbidlcache-%s", - nc_data.bv_val); + snprintf(typeinst, sizeof(typeinst), "bdbidlcache-%s", + nc_data.bv_val); cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val), st); ldap_value_free_len(olmbdb_list); @@ -464,41 +455,24 @@ static int cldap_config_add(oconfig_item_t *ci) /* {{{ */ ldap_free_urldesc(ludpp); } - if (status == 0) { - cldap_t **temp; - - temp = (cldap_t **)realloc(databases, - sizeof(*databases) * (databases_num + 1)); - - if (temp == NULL) { - ERROR("openldap plugin: realloc failed"); - status = -1; - } else { - char callback_name[3 * DATA_MAX_NAME_LEN] = {0}; - - databases = temp; - databases[databases_num] = st; - databases_num++; - - ssnprintf(callback_name, sizeof(callback_name), "openldap/%s/%s", - (st->host != NULL) ? st->host : hostname_g, - (st->name != NULL) ? st->name : "default"); - - status = plugin_register_complex_read(/* group = */ NULL, - /* name = */ callback_name, - /* callback = */ cldap_read_host, - /* interval = */ 0, &(user_data_t){ - .data = st, - }); - } - } - if (status != 0) { cldap_free(st); return -1; } - return 0; + char callback_name[3 * DATA_MAX_NAME_LEN] = {0}; + + snprintf(callback_name, sizeof(callback_name), "openldap/%s/%s", + (st->host != NULL) ? st->host : hostname_g, + (st->name != NULL) ? st->name : "default"); + + return plugin_register_complex_read(/* group = */ NULL, + /* name = */ callback_name, + /* callback = */ cldap_read_host, + /* interval = */ 0, + &(user_data_t){ + .data = st, .free_func = cldap_free, + }); } /* }}} int cldap_config_add */ static int cldap_config(oconfig_item_t *ci) /* {{{ */ @@ -532,22 +506,10 @@ static int cldap_init(void) /* {{{ */ return 0; } /* }}} int cldap_init */ -static int cldap_shutdown(void) /* {{{ */ -{ - for (size_t i = 0; i < databases_num; i++) - if (databases[i]->ld != NULL) - ldap_unbind_ext_s(databases[i]->ld, NULL, NULL); - sfree(databases); - databases_num = 0; - - return 0; -} /* }}} int cldap_shutdown */ - void module_register(void) /* {{{ */ { plugin_register_complex_config("openldap", cldap_config); plugin_register_init("openldap", cldap_init); - plugin_register_shutdown("openldap", cldap_shutdown); } /* }}} void module_register */ #if defined(__APPLE__) diff --git a/src/openvpn.c b/src/openvpn.c index 143a770b..a98649b6 100644 --- a/src/openvpn.c +++ b/src/openvpn.c @@ -23,6 +23,7 @@ * Florian octo Forster * Marco Chiappero * Fabian Schuh + * Pavel Rochnyak **/ #include "collectd.h" @@ -30,35 +31,55 @@ #include "common.h" #include "plugin.h" -#define V1STRING \ +/** + * There is two main kinds of OpenVPN status file: + * - for 'single' mode (point-to-point or client mode) + * - for 'multi' mode (server with multiple clients) + * + * For 'multi' there is 3 versions of status file format: + * - version 1 - First version of status file: without line type tokens, + * comma delimited for easy machine parsing. Currently used by default. + * Added in openvpn-2.0-beta3. + * - version 2 - with line type tokens, with 'HEADER' line type, uses comma + * as a delimiter. + * Added in openvpn-2.0-beta15. + * - version 3 - The only difference from version 2 is delimiter: in version 3 + * tabs are used instead of commas. Set of fields is the same. + * Added in openvpn-2.1_rc14. + * + * For versions 2/3 there may be different sets of fields in different + * OpenVPN versions. + * + * Versions 2.0, 2.1, 2.2: + * Common Name,Real Address,Virtual Address, + * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t) + * + * Version 2.3: + * Common Name,Real Address,Virtual Address, + * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username + * + * Version 2.4: + * Common Name,Real Address,Virtual Address,Virtual IPv6 Address, + * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username, + * Client ID,Peer ID + * + * Current Collectd code tries to handle changes in this field set, + * if they are backward-compatible. + **/ + +#define TITLE_SINGLE "OpenVPN STATISTICS\n" +#define TITLE_V1 "OpenVPN CLIENT LIST\n" +#define TITLE_V2 "TITLE" + +#define V1HEADER \ "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since\n" -#define V2STRING \ - "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes " \ - "Received,Bytes Sent,Connected Since,Connected Since (time_t)\n" -#define V3STRING \ - "HEADER CLIENT_LIST Common Name Real Address Virtual Address Bytes " \ - "Received Bytes Sent Connected Since Connected Since (time_t)\n" -#define V4STRING \ - "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes " \ - "Received,Bytes Sent,Connected Since,Connected Since (time_t),Username\n" -#define VSSTRING "OpenVPN STATISTICS\n" struct vpn_status_s { char *file; - enum { - MULTI1 = 1, /* status-version 1 */ - MULTI2, /* status-version 2 */ - MULTI3, /* status-version 3 */ - MULTI4, /* status-version 4 */ - SINGLE = 10 /* currently no versions for single mode, maybe in the future */ - } version; char *name; }; typedef struct vpn_status_s vpn_status_t; -static vpn_status_t **vpn_list = NULL; -static int vpn_num = 0; - static _Bool new_naming_schema = 0; static _Bool collect_compression = 1; static _Bool collect_user_count = 0; @@ -71,16 +92,13 @@ static const char *config_keys[] = { static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); /* Helper function - * copy-n-pasted from common.c - changed delim to "," */ + * copy-n-pasted from common.c - changed delim to ",\t" */ static int openvpn_strsplit(char *string, char **fields, size_t size) { - size_t i; - char *ptr; - char *saveptr; - - i = 0; - ptr = string; - saveptr = NULL; - while ((fields[i] = strtok_r(ptr, ",", &saveptr)) != NULL) { + size_t i = 0; + char *ptr = string; + char *saveptr = NULL; + + while ((fields[i] = strtok_r(ptr, ",\t", &saveptr)) != NULL) { ptr = NULL; i++; @@ -91,6 +109,13 @@ static int openvpn_strsplit(char *string, char **fields, size_t size) { return i; } /* int openvpn_strsplit */ +static void openvpn_free(void *arg) { + vpn_status_t *st = arg; + + sfree(st->file); + sfree(st); +} /* void openvpn_free */ + /* dispatches number of users */ static void numusers_submit(const char *pinst, const char *tinst, gauge_t value) { @@ -159,25 +184,14 @@ static int single_read(const char *name, FILE *fh) { char buffer[1024]; char *fields[4]; const int max_fields = STATIC_ARRAY_SIZE(fields); - int fields_num, read = 0; - - derive_t link_rx, link_tx; - derive_t tun_rx, tun_tx; - derive_t pre_compress, post_compress; - derive_t pre_decompress, post_decompress; - derive_t overhead_rx, overhead_tx; - - link_rx = 0; - link_tx = 0; - tun_rx = 0; - tun_tx = 0; - pre_compress = 0; - post_compress = 0; - pre_decompress = 0; - post_decompress = 0; + + derive_t link_rx = 0, link_tx = 0; + derive_t tun_rx = 0, tun_tx = 0; + derive_t pre_compress = 0, post_compress = 0; + derive_t pre_decompress = 0, post_decompress = 0; while (fgets(buffer, sizeof(buffer), fh) != NULL) { - fields_num = openvpn_strsplit(buffer, fields, max_fields); + int fields_num = openvpn_strsplit(buffer, fields, max_fields); /* status file is generated by openvpn/sig.c:print_status() * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/sig.c @@ -213,8 +227,9 @@ static int single_read(const char *name, FILE *fh) { iostats_submit(name, "traffic", link_rx, link_tx); /* we need to force this order to avoid negative values with these unsigned */ - overhead_rx = (((link_rx - pre_decompress) + post_decompress) - tun_rx); - overhead_tx = (((link_tx - post_compress) + pre_compress) - tun_tx); + derive_t overhead_rx = + (((link_rx - pre_decompress) + post_decompress) - tun_rx); + derive_t overhead_tx = (((link_tx - post_compress) + pre_compress) - tun_tx); iostats_submit(name, "overhead", overhead_rx, overhead_tx); @@ -223,17 +238,16 @@ static int single_read(const char *name, FILE *fh) { compression_submit(name, "data_out", pre_compress, post_compress); } - read = 1; - - return read; + return 0; } /* int single_read */ /* for reading status version 1 */ static int multi1_read(const char *name, FILE *fh) { char buffer[1024]; char *fields[10]; - int fields_num, found_header = 0; + const int max_fields = STATIC_ARRAY_SIZE(fields); long long sum_users = 0; + _Bool found_header = 0; /* read the file until the "ROUTING TABLE" line is found (no more info after) */ @@ -241,7 +255,7 @@ static int multi1_read(const char *name, FILE *fh) { if (strcmp(buffer, "ROUTING TABLE\n") == 0) break; - if (strcmp(buffer, V1STRING) == 0) { + if (strcmp(buffer, V1HEADER) == 0) { found_header = 1; continue; } @@ -251,7 +265,7 @@ static int multi1_read(const char *name, FILE *fh) { /* we can't start reading data until this string is found */ continue; - fields_num = openvpn_strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields)); + int fields_num = openvpn_strsplit(buffer, fields, max_fields); if (fields_num < 4) continue; @@ -276,325 +290,196 @@ static int multi1_read(const char *name, FILE *fh) { } if (ferror(fh)) - return 0; + return -1; + + if (found_header == 0) { + NOTICE("openvpn plugin: Unknown file format in instance %s, please " + "report this as bug. Make sure to include " + "your status file, so the plugin can " + "be adapted.", + name); + return -1; + } if (collect_user_count) numusers_submit(name, name, sum_users); - return 1; + return 0; } /* int multi1_read */ -/* for reading status version 2 */ +/* for reading status version 2 / version 3 + * status file is generated by openvpn/multi.c:multi_print_status() + * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c + */ static int multi2_read(const char *name, FILE *fh) { char buffer[1024]; - char *fields[10]; + /* OpenVPN-2.4 has 11 fields of data + 2 fields for "HEADER" and "CLIENT_LIST" + * So, set array size to 20 elements, to support future extensions. + */ + char *fields[20]; const int max_fields = STATIC_ARRAY_SIZE(fields); - int fields_num, read = 0; long long sum_users = 0; - while (fgets(buffer, sizeof(buffer), fh) != NULL) { - fields_num = openvpn_strsplit(buffer, fields, max_fields); - - /* status file is generated by openvpn/multi.c:multi_print_status() - * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c - * - * The line we're expecting has 8 fields. We ignore all lines - * with more or less fields. - */ - if (fields_num != 8) - continue; - - if (strcmp(fields[0], "CLIENT_LIST") != 0) - continue; - - if (collect_user_count) - /* If so, sum all users, ignore the individuals*/ - { - sum_users += 1; - } - if (collect_individual_users) { - if (new_naming_schema) { - /* plugin inst = file name, type inst = fields[1] */ - iostats_submit(name, /* vpn instance */ - fields[1], /* "Common Name" */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ - } else { - /* plugin inst = fields[1], type inst = "" */ - iostats_submit(fields[1], /* "Common Name" */ - NULL, /* unused when in multimode */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ - } - } - - read = 1; - } - - if (collect_user_count) { - numusers_submit(name, name, sum_users); - read = 1; - } - - return read; -} /* int multi2_read */ - -/* for reading status version 3 */ -static int multi3_read(const char *name, FILE *fh) { - char buffer[1024]; - char *fields[15]; - const int max_fields = STATIC_ARRAY_SIZE(fields); - int fields_num, read = 0; - long long sum_users = 0; + _Bool found_header = 0; + int idx_cname = 0; + int idx_bytes_recv = 0; + int idx_bytes_sent = 0; + int columns = 0; while (fgets(buffer, sizeof(buffer), fh) != NULL) { - fields_num = strsplit(buffer, fields, max_fields); + int fields_num = openvpn_strsplit(buffer, fields, max_fields); - /* status file is generated by openvpn/multi.c:multi_print_status() - * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c - * - * The line we're expecting has 12 fields. We ignore all lines - * with more or less fields. - */ - if (fields_num != 12) { - continue; - } else { - if (strcmp(fields[0], "CLIENT_LIST") != 0) + /* Try to find section header */ + if (found_header == 0) { + if (fields_num < 2) + continue; + if (strcmp(fields[0], "HEADER") != 0) + continue; + if (strcmp(fields[1], "CLIENT_LIST") != 0) continue; - if (collect_user_count) - /* If so, sum all users, ignore the individuals*/ - { - sum_users += 1; - } - - if (collect_individual_users) { - if (new_naming_schema) { - iostats_submit(name, /* vpn instance */ - fields[1], /* "Common Name" */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ - } else { - iostats_submit(fields[1], /* "Common Name" */ - NULL, /* unused when in multimode */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ + for (int i = 2; i < fields_num; i++) { + if (strcmp(fields[i], "Common Name") == 0) { + idx_cname = i - 1; + } else if (strcmp(fields[i], "Bytes Received") == 0) { + idx_bytes_recv = i - 1; + } else if (strcmp(fields[i], "Bytes Sent") == 0) { + idx_bytes_sent = i - 1; } } - read = 1; - } - } - - if (collect_user_count) { - numusers_submit(name, name, sum_users); - read = 1; - } + DEBUG("openvpn plugin: found MULTI v2/v3 HEADER. " + "Column idx: cname: %d, bytes_recv: %d, bytes_sent: %d", + idx_cname, idx_bytes_recv, idx_bytes_sent); - return read; -} /* int multi3_read */ + if (idx_cname == 0 || idx_bytes_recv == 0 || idx_bytes_sent == 0) + break; -/* for reading status version 4 */ -static int multi4_read(const char *name, FILE *fh) { - char buffer[1024]; - char *fields[11]; - const int max_fields = STATIC_ARRAY_SIZE(fields); - int fields_num, read = 0; - long long sum_users = 0; + /* Data row has 1 field ("HEADER") less than header row */ + columns = fields_num - 1; - while (fgets(buffer, sizeof(buffer), fh) != NULL) { - fields_num = openvpn_strsplit(buffer, fields, max_fields); + found_header = 1; + continue; + } - /* status file is generated by openvpn/multi.c:multi_print_status() - * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c - * - * The line we're expecting has 9 fields. We ignore all lines - * with more or less fields. + /* Header already found. Check if the line is the section data. + * If no match, then section was finished and there is no more data. + * Empty section is OK too. */ - if (fields_num != 9) - continue; + if (fields_num == 0 || strcmp(fields[0], "CLIENT_LIST") != 0) + break; - if (strcmp(fields[0], "CLIENT_LIST") != 0) - continue; + /* Check if the data line fields count matches header line. */ + if (fields_num != columns) { + ERROR("openvpn plugin: File format error in instance %s: Fields count " + "mismatch.", + name); + return -1; + } + + DEBUG("openvpn plugin: found MULTI v2/v3 CLIENT_LIST. " + "Columns: cname: %s, bytes_recv: %s, bytes_sent: %s", + fields[idx_cname], fields[idx_bytes_recv], fields[idx_bytes_sent]); if (collect_user_count) - /* If so, sum all users, ignore the individuals*/ - { sum_users += 1; - } + if (collect_individual_users) { if (new_naming_schema) { /* plugin inst = file name, type inst = fields[1] */ - iostats_submit(name, /* vpn instance */ - fields[1], /* "Common Name" */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ + iostats_submit(name, /* vpn instance */ + fields[idx_cname], /* "Common Name" */ + atoll(fields[idx_bytes_recv]), /* "Bytes Received" */ + atoll(fields[idx_bytes_sent])); /* "Bytes Sent" */ } else { - /* plugin inst = fields[1], type inst = "" */ - iostats_submit(fields[1], /* "Common Name" */ - NULL, /* unused when in multimode */ - atoll(fields[4]), /* "Bytes Received" */ - atoll(fields[5])); /* "Bytes Sent" */ + /* plugin inst = fields[idx_cname], type inst = "" */ + iostats_submit(fields[idx_cname], /* "Common Name" */ + NULL, /* unused when in multimode */ + atoll(fields[idx_bytes_recv]), /* "Bytes Received" */ + atoll(fields[idx_bytes_sent])); /* "Bytes Sent" */ } } + } + + if (ferror(fh)) + return -1; - read = 1; + if (found_header == 0) { + NOTICE("openvpn plugin: Unknown file format in instance %s, please " + "report this as bug. Make sure to include " + "your status file, so the plugin can " + "be adapted.", + name); + return -1; } if (collect_user_count) { numusers_submit(name, name, sum_users); - read = 1; } - return read; -} /* int multi4_read */ + return 0; +} /* int multi2_read */ /* read callback */ -static int openvpn_read(void) { - FILE *fh; - int read; - - read = 0; - - if (vpn_num == 0) - return 0; - - /* call the right read function for every status entry in the list */ - for (int i = 0; i < vpn_num; i++) { - int vpn_read = 0; - - fh = fopen(vpn_list[i]->file, "r"); - if (fh == NULL) { - char errbuf[1024]; - WARNING("openvpn plugin: fopen(%s) failed: %s", vpn_list[i]->file, - sstrerror(errno, errbuf, sizeof(errbuf))); - - continue; - } - - switch (vpn_list[i]->version) { - case SINGLE: - vpn_read = single_read(vpn_list[i]->name, fh); - break; - - case MULTI1: - vpn_read = multi1_read(vpn_list[i]->name, fh); - break; - - case MULTI2: - vpn_read = multi2_read(vpn_list[i]->name, fh); - break; - - case MULTI3: - vpn_read = multi3_read(vpn_list[i]->name, fh); - break; - - case MULTI4: - vpn_read = multi4_read(vpn_list[i]->name, fh); - break; - } - - fclose(fh); - read += vpn_read; - } - - return read ? 0 : -1; -} /* int openvpn_read */ - -static int version_detect(const char *filename) { - FILE *fh; +static int openvpn_read(user_data_t *user_data) { char buffer[1024]; - int version = 0; + int read = 0; - /* Sanity checking. We're called from the config handling routine, so - * better play it save. */ - if ((filename == NULL) || (*filename == 0)) - return 0; + vpn_status_t *st = user_data->data; - fh = fopen(filename, "r"); + FILE *fh = fopen(st->file, "r"); if (fh == NULL) { char errbuf[1024]; - WARNING("openvpn plugin: Unable to read \"%s\": %s", filename, + WARNING("openvpn plugin: fopen(%s) failed: %s", st->file, sstrerror(errno, errbuf, sizeof(errbuf))); - return 0; + + return -1; } - /* now search for the specific multimode data format */ - while ((fgets(buffer, sizeof(buffer), fh)) != NULL) { - /* we look at the first line searching for SINGLE mode configuration */ - if (strcmp(buffer, VSSTRING) == 0) { - DEBUG("openvpn plugin: found status file version SINGLE"); - version = SINGLE; - break; - } - /* searching for multi version 1 */ - else if (strcmp(buffer, V1STRING) == 0) { - DEBUG("openvpn plugin: found status file version MULTI1"); - version = MULTI1; - break; - } - /* searching for multi version 2 */ - else if (strcmp(buffer, V2STRING) == 0) { - DEBUG("openvpn plugin: found status file version MULTI2"); - version = MULTI2; - break; - } - /* searching for multi version 3 */ - else if (strcmp(buffer, V3STRING) == 0) { - DEBUG("openvpn plugin: found status file version MULTI3"); - version = MULTI3; - break; - } - /* searching for multi version 4 */ - else if (strcmp(buffer, V4STRING) == 0) { - DEBUG("openvpn plugin: found status file version MULTI4"); - version = MULTI4; - break; - } + // Try to detect file format by its first line + if ((fgets(buffer, sizeof(buffer), fh)) == NULL) { + WARNING("openvpn plugin: failed to get data from: %s", st->file); + fclose(fh); + return -1; } - if (version == 0) { - /* This is only reached during configuration, so complaining to - * the user is in order. */ + if (strcmp(buffer, TITLE_SINGLE) == 0) { // OpenVPN STATISTICS + DEBUG("openvpn plugin: found status file SINGLE"); + read = single_read(st->name, fh); + } else if (strcmp(buffer, TITLE_V1) == 0) { // OpenVPN CLIENT LIST + DEBUG("openvpn plugin: found status file MULTI version 1"); + read = multi1_read(st->name, fh); + } else if (strncmp(buffer, TITLE_V2, strlen(TITLE_V2)) == 0) { // TITLE + DEBUG("openvpn plugin: found status file MULTI version 2/3"); + read = multi2_read(st->name, fh); + } else { NOTICE("openvpn plugin: %s: Unknown file format, please " "report this as bug. Make sure to include " "your status file, so the plugin can " "be adapted.", - filename); + st->file); + read = -1; } - fclose(fh); - - return version; -} /* int version_detect */ + return read; +} /* int openvpn_read */ static int openvpn_config(const char *key, const char *value) { if (strcasecmp("StatusFile", key) == 0) { - char *status_file, *status_name, *filename; - int status_version; - vpn_status_t *temp; + char callback_name[3 * DATA_MAX_NAME_LEN]; + char *status_name; - /* try to detect the status file format */ - status_version = version_detect(value); - - if (status_version == 0) { - WARNING("openvpn plugin: unable to detect status version, " - "discarding status file \"%s\".", - value); - return 1; - } - - status_file = sstrdup(value); + char *status_file = strdup(value); if (status_file == NULL) { char errbuf[1024]; - WARNING("openvpn plugin: sstrdup failed: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("openvpn plugin: strdup failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); return 1; } /* it determines the file name as string starting at location filename + 1 */ - filename = strrchr(status_file, (int)'/'); + char *filename = strrchr(status_file, (int)'/'); if (filename == NULL) { /* status_file is already the file name only */ status_name = status_file; @@ -603,50 +488,38 @@ static int openvpn_config(const char *key, const char *value) { status_name = filename + 1; } - /* scan the list looking for a clone */ - for (int i = 0; i < vpn_num; i++) { - if (strcasecmp(vpn_list[i]->name, status_name) == 0) { - WARNING("openvpn plugin: status filename \"%s\" " - "already used, please choose a " - "different one.", - status_name); - sfree(status_file); - return 1; - } - } - - /* create a new vpn element since file, version and name are ok */ - temp = malloc(sizeof(*temp)); - if (temp == NULL) { + /* create a new vpn element */ + vpn_status_t *instance = calloc(1, sizeof(*instance)); + if (instance == NULL) { char errbuf[1024]; ERROR("openvpn plugin: malloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); sfree(status_file); return 1; } - temp->file = status_file; - temp->version = status_version; - temp->name = status_name; - - vpn_status_t **tmp_list = - realloc(vpn_list, (vpn_num + 1) * sizeof(*vpn_list)); - if (tmp_list == NULL) { - char errbuf[1024]; - ERROR("openvpn plugin: realloc failed: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); - - sfree(vpn_list); - sfree(temp->file); - sfree(temp); - return 1; + instance->file = status_file; + instance->name = status_name; + + snprintf(callback_name, sizeof(callback_name), "openvpn/%s", status_name); + + int status = plugin_register_complex_read( + /* group = */ "openvpn", + /* name = */ callback_name, + /* callback = */ openvpn_read, + /* interval = */ 0, + &(user_data_t){ + .data = instance, .free_func = openvpn_free, + }); + + if (status == EINVAL) { + WARNING("openvpn plugin: status filename \"%s\" " + "already used, please choose a " + "different one.", + status_name); + return -1; } - vpn_list = tmp_list; - - vpn_list[vpn_num] = temp; - vpn_num++; - - DEBUG("openvpn plugin: status file \"%s\" added", temp->file); + DEBUG("openvpn plugin: status file \"%s\" added", instance->file); } /* if (strcasecmp ("StatusFile", key) == 0) */ else if ((strcasecmp("CollectCompression", key) == 0) || (strcasecmp("Compression", key) == 0)) /* old, deprecated name */ @@ -683,18 +556,6 @@ static int openvpn_config(const char *key, const char *value) { return 0; } /* int openvpn_config */ -/* shutdown callback */ -static int openvpn_shutdown(void) { - for (int i = 0; i < vpn_num; i++) { - sfree(vpn_list[i]->file); - sfree(vpn_list[i]); - } - - sfree(vpn_list); - - return 0; -} /* int openvpn_shutdown */ - static int openvpn_init(void) { if (!collect_individual_users && !collect_compression && !collect_user_count) { @@ -704,9 +565,6 @@ static int openvpn_init(void) { return -1; } - plugin_register_read("openvpn", openvpn_read); - plugin_register_shutdown("openvpn", openvpn_shutdown); - return 0; } /* int openvpn_init */ diff --git a/src/oracle.c b/src/oracle.c index 6d245dd9..099013e3 100644 --- a/src/oracle.c +++ b/src/oracle.c @@ -481,8 +481,7 @@ static int o_read_database_query(o_database_t *db, /* {{{ */ column_names[i] = column_names[i - 1] + DATA_MAX_NAME_LEN; ALLOC_OR_FAIL(column_values, column_num * sizeof(char *)); - ALLOC_OR_FAIL(column_values[0], - column_num * DATA_MAX_NAME_LEN); + ALLOC_OR_FAIL(column_values[0], column_num * DATA_MAX_NAME_LEN); for (size_t i = 1; i < column_num; i++) column_values[i] = column_values[i - 1] + DATA_MAX_NAME_LEN; @@ -642,7 +641,7 @@ static int o_read_database(o_database_t *db) /* {{{ */ if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO)) { char errfunc[256]; - ssnprintf(errfunc, sizeof(errfunc), "OCILogon(\"%s\")", db->connect_id); + snprintf(errfunc, sizeof(errfunc), "OCILogon(\"%s\")", db->connect_id); o_report_error("o_read_database", db->name, NULL, errfunc, oci_error); DEBUG("oracle plugin: OCILogon (%s): db->oci_service_context = %p;", diff --git a/src/ovs_events.c b/src/ovs_events.c index 65042343..afa11997 100644 --- a/src/ovs_events.c +++ b/src/ovs_events.c @@ -3,14 +3,17 @@ * * Copyright(c) 2016 Intel Corporation. All rights reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a copy of + * Permission is hereby granted, free of charge, to any person obtaining a copy + *of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do + * of the Software, and to permit persons to whom the Software is furnished to + *do * so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all + * The above copyright notice and this permission notice shall be included in + *all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -155,8 +158,8 @@ static char *ovs_events_get_select_params() { return NULL; } opt_buff = new_buff; - int ret = ssnprintf(opt_buff + buff_off, buff_size - buff_off, option_fmt, - iface->name); + int ret = snprintf(opt_buff + buff_off, buff_size - buff_off, option_fmt, + iface->name); if (ret < 0) { sfree(opt_buff); return NULL; @@ -177,7 +180,7 @@ static char *ovs_events_get_select_params() { } /* create OVS DB select params */ - if (ssnprintf(params_buff, params_size, params_fmt, opt_buff) < 0) + if (snprintf(params_buff, params_size, params_fmt, opt_buff) < 0) sfree(params_buff); sfree(opt_buff); @@ -202,8 +205,8 @@ static int ovs_events_config_get_interfaces(const oconfig_item_t *ci) { for (int j = 0; j < ci->values_num; j++) { /* check interface name type */ if (ci->values[j].type != OCONFIG_TYPE_STRING) { - ERROR(OVS_EVENTS_PLUGIN - ": given interface name is not a string [idx=%d]", j); + ERROR(OVS_EVENTS_PLUGIN ": given interface name is not a string [idx=%d]", + j); return -1; } /* allocate memory for configured interface */ @@ -278,9 +281,10 @@ static int ovs_events_plugin_config(oconfig_item_t *ci) { } /* Check and warn about invalid configuration */ if (!ovs_events_ctx.config.send_notification && !dispatch_values) { - WARNING(OVS_EVENTS_PLUGIN ": send notification and dispatch values " - "options are disabled. No information will be dispatched by the " - "plugin. Please check your configuration"); + WARNING(OVS_EVENTS_PLUGIN + ": send notification and dispatch values " + "options are disabled. No information will be dispatched by the " + "plugin. Please check your configuration"); } /* Dispatch link status values if configured */ if (dispatch_values) @@ -291,7 +295,8 @@ static int ovs_events_plugin_config(oconfig_item_t *ci) { } /* Dispatch OVS interface link status event to collectd */ -static void ovs_events_dispatch_notification(const ovs_events_iface_info_t *ifinfo) { +static void +ovs_events_dispatch_notification(const ovs_events_iface_info_t *ifinfo) { const char *msg_link_status = NULL; notification_t n = { NOTIF_FAILURE, cdtime(), "", "", OVS_EVENTS_PLUGIN, "", "", "", NULL}; @@ -334,9 +339,9 @@ static void ovs_events_dispatch_notification(const ovs_events_iface_info_t *ifin } /* fill the notification data */ - ssnprintf(n.message, sizeof(n.message), - "link state of \"%s\" interface has been changed to \"%s\"", - ifinfo->name, msg_link_status); + snprintf(n.message, sizeof(n.message), + "link state of \"%s\" interface has been changed to \"%s\"", + ifinfo->name, msg_link_status); sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ifinfo->name, sizeof(n.plugin_instance)); sstrncpy(n.type, "gauge", sizeof(n.type)); @@ -345,7 +350,8 @@ static void ovs_events_dispatch_notification(const ovs_events_iface_info_t *ifin } /* Dispatch OVS interface link status value to collectd */ -static void ovs_events_link_status_submit(const ovs_events_iface_info_t *ifinfo) { +static void +ovs_events_link_status_submit(const ovs_events_iface_info_t *ifinfo) { value_list_t vl = VALUE_LIST_INIT; meta_data_t *meta = NULL; diff --git a/src/ovs_stats.c b/src/ovs_stats.c index 31af77c8..20b0dd1f 100644 --- a/src/ovs_stats.c +++ b/src/ovs_stats.c @@ -3,14 +3,17 @@ * * Copyright(c) 2016 Intel Corporation. All rights reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a copy of + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do + * of the Software, and to permit persons to whom the Software is furnished to + * do * so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all + * The above copyright notice and this permission notice shall be included in + * all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -711,33 +714,30 @@ static void ovs_stats_initialize(ovs_db_t *pdb) { "external_ids", NULL}; /* subscribe to a tables */ - ovs_db_table_cb_register(pdb, "Bridge", bridge_columns, - ovs_stats_bridge_table_change_cb, + ovs_db_table_cb_register( + pdb, "Bridge", bridge_columns, ovs_stats_bridge_table_change_cb, ovs_stats_bridge_table_result_cb, - OVS_DB_TABLE_CB_FLAG_INITIAL | - OVS_DB_TABLE_CB_FLAG_INSERT | + OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT | OVS_DB_TABLE_CB_FLAG_MODIFY); ovs_db_table_cb_register(pdb, "Bridge", bridge_columns, ovs_stats_bridge_table_delete_cb, NULL, OVS_DB_TABLE_CB_FLAG_DELETE); - ovs_db_table_cb_register(pdb, "Port", port_columns, - ovs_stats_port_table_change_cb, + ovs_db_table_cb_register( + pdb, "Port", port_columns, ovs_stats_port_table_change_cb, ovs_stats_port_table_result_cb, - OVS_DB_TABLE_CB_FLAG_INITIAL | - OVS_DB_TABLE_CB_FLAG_INSERT | + OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT | OVS_DB_TABLE_CB_FLAG_MODIFY); ovs_db_table_cb_register(pdb, "Port", port_columns, ovs_stats_port_table_delete_cb, NULL, OVS_DB_TABLE_CB_FLAG_DELETE); - ovs_db_table_cb_register(pdb, "Interface", interface_columns, - ovs_stats_interface_table_change_cb, + ovs_db_table_cb_register( + pdb, "Interface", interface_columns, ovs_stats_interface_table_change_cb, ovs_stats_interface_table_result_cb, - OVS_DB_TABLE_CB_FLAG_INITIAL | - OVS_DB_TABLE_CB_FLAG_INSERT | + OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT | OVS_DB_TABLE_CB_FLAG_MODIFY); } @@ -862,8 +862,8 @@ static int ovs_stats_plugin_init(void) { plugin_name, ovs_stats_cfg.ovs_db_node, ovs_stats_cfg.ovs_db_serv, ovs_stats_cfg.ovs_db_unix); /* connect to OvS DB */ - if ((g_ovs_db = ovs_db_init (ovs_stats_cfg.ovs_db_node, - ovs_stats_cfg.ovs_db_serv, + if ((g_ovs_db = + ovs_db_init(ovs_stats_cfg.ovs_db_node, ovs_stats_cfg.ovs_db_serv, ovs_stats_cfg.ovs_db_unix, &cb)) == NULL) { ERROR("%s: plugin: failed to connect to OvS DB server", plugin_name); return -1; diff --git a/src/perl.c b/src/perl.c index e922badf..d2a00bfd 100644 --- a/src/perl.c +++ b/src/perl.c @@ -424,8 +424,6 @@ static int hv2value_list(pTHX_ HV *hash, value_list_t *vl) { if (NULL != (tmp = hv_fetch(hash, "host", 4, 0))) sstrncpy(vl->host, SvPV_nolen(*tmp), sizeof(vl->host)); - else - sstrncpy(vl->host, hostname_g, sizeof(vl->host)); if (NULL != (tmp = hv_fetch(hash, "plugin", 6, 0))) sstrncpy(vl->plugin, SvPV_nolen(*tmp), sizeof(vl->plugin)); @@ -494,7 +492,8 @@ 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 **ret_meta) { +static int av2notification_meta(pTHX_ AV *array, + notification_meta_t **ret_meta) { notification_meta_t *tail = NULL; int len = av_len(array); @@ -881,9 +880,9 @@ static int oconfig_item2hv(pTHX_ oconfig_item_t *ci, HV *hash) { static char *get_module_name(char *buf, size_t buf_len, const char *module) { int status = 0; if (base_name[0] == '\0') - status = ssnprintf(buf, buf_len, "%s", module); + status = snprintf(buf, buf_len, "%s", module); else - status = ssnprintf(buf, buf_len, "%s::%s", base_name, module); + status = snprintf(buf, buf_len, "%s::%s", base_name, module); if ((status < 0) || ((unsigned int)status >= buf_len)) return NULL; return buf; @@ -1625,18 +1624,19 @@ static void _plugin_register_generic_userdata(pTHX, int type, ret = plugin_register_flush("perl", perl_flush, /* user_data = */ NULL); } - if (0 == ret) + if (0 == ret) { ret = plugin_register_flush(pluginname, perl_flush, &userdata); + } else { + free(userdata.data); + } } else { ret = -1; } if (0 == ret) XSRETURN_YES; - else { - free(userdata.data); + else XSRETURN_EMPTY; - } } /* static void _plugin_register_generic_userdata ( ... ) */ /* @@ -2616,6 +2616,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/postgresql.c b/src/postgresql.c index 45cd001e..3b702aee 100644 --- a/src/postgresql.c +++ b/src/postgresql.c @@ -58,7 +58,7 @@ * is ignored. */ #define C_PSQL_PAR_APPEND(buf, buf_len, parameter, value) \ if ((0 < (buf_len)) && (NULL != (value)) && ('\0' != *(value))) { \ - int s = ssnprintf(buf, buf_len, " %s = '%s'", parameter, value); \ + int s = snprintf(buf, buf_len, " %s = '%s'", parameter, value); \ if (0 < s) { \ buf += s; \ buf_len -= s; \ @@ -327,7 +327,7 @@ static int c_psql_connect(c_psql_database_t *db) { if ((!db) || (!db->database)) return -1; - status = ssnprintf(buf, buf_len, "dbname = '%s'", db->database); + status = snprintf(buf, buf_len, "dbname = '%s'", db->database); if (0 < status) { buf += status; buf_len -= status; @@ -429,9 +429,9 @@ static PGresult *c_psql_exec_query_params(c_psql_database_t *db, udb_query_t *q, params[i] = db->user; break; case C_PSQL_PARAM_INTERVAL: - ssnprintf(interval, sizeof(interval), "%.3f", - (db->interval > 0) ? CDTIME_T_TO_DOUBLE(db->interval) - : plugin_get_interval()); + snprintf(interval, sizeof(interval), "%.3f", + (db->interval > 0) ? CDTIME_T_TO_DOUBLE(db->interval) + : plugin_get_interval()); params[i] = interval; break; case C_PSQL_PARAM_INSTANCE: @@ -443,7 +443,7 @@ static PGresult *c_psql_exec_query_params(c_psql_database_t *db, udb_query_t *q, } return PQexecParams(db->conn, udb_query_get_statement(q), data->params_num, - NULL, (const char *const*)params, NULL, NULL, 0); + NULL, (const char *const *)params, NULL, NULL, 0); } /* c_psql_exec_query_params */ /* db->db_lock must be locked when calling this function */ @@ -636,7 +636,7 @@ static char *values_name_to_sqlarray(const data_set_t *ds, char *string, str_len = string_len; for (size_t i = 0; i < ds->ds_num; ++i) { - int status = ssnprintf(str_ptr, str_len, ",'%s'", ds->ds[i].name); + int status = snprintf(str_ptr, str_len, ",'%s'", ds->ds[i].name); if (status < 1) return NULL; @@ -674,10 +674,10 @@ static char *values_type_to_sqlarray(const data_set_t *ds, char *string, int status; if (store_rates) - status = ssnprintf(str_ptr, str_len, ",'gauge'"); + status = snprintf(str_ptr, str_len, ",'gauge'"); else - status = ssnprintf(str_ptr, str_len, ",'%s'", - DS_TYPE_TO_STRING(ds->ds[i].type)); + status = snprintf(str_ptr, str_len, ",'%s'", + DS_TYPE_TO_STRING(ds->ds[i].type)); if (status < 1) { str_len = 0; @@ -729,7 +729,7 @@ static char *values_to_sqlarray(const data_set_t *ds, const value_list_t *vl, if (ds->ds[i].type == DS_TYPE_GAUGE) status = - ssnprintf(str_ptr, str_len, "," GAUGE_FORMAT, vl->values[i].gauge); + snprintf(str_ptr, str_len, "," GAUGE_FORMAT, vl->values[i].gauge); else if (store_rates) { if (rates == NULL) rates = uc_get_rate(ds, vl); @@ -739,13 +739,13 @@ static char *values_to_sqlarray(const data_set_t *ds, const value_list_t *vl, return NULL; } - status = ssnprintf(str_ptr, str_len, ",%lf", rates[i]); + status = snprintf(str_ptr, str_len, ",%lf", rates[i]); } else if (ds->ds[i].type == DS_TYPE_COUNTER) - status = ssnprintf(str_ptr, str_len, ",%llu", vl->values[i].counter); + status = snprintf(str_ptr, str_len, ",%llu", vl->values[i].counter); else if (ds->ds[i].type == DS_TYPE_DERIVE) - status = ssnprintf(str_ptr, str_len, ",%" PRIi64, vl->values[i].derive); + status = snprintf(str_ptr, str_len, ",%" PRIi64, vl->values[i].derive); else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) - status = ssnprintf(str_ptr, str_len, ",%" PRIu64, vl->values[i].absolute); + status = snprintf(str_ptr, str_len, ",%" PRIu64, vl->values[i].absolute); if (status < 1) { str_len = 0; @@ -943,7 +943,7 @@ static int c_psql_shutdown(void) { if (db->writers_num > 0) { char cb_name[DATA_MAX_NAME_LEN]; - ssnprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->database); + snprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->database); if (!had_flush) { plugin_unregister_flush("postgresql"); @@ -1203,7 +1203,7 @@ static int c_psql_config_database(oconfig_item_t *ci) { } } - ssnprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->instance); + snprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->instance); user_data_t ud = {.data = db, .free_func = c_psql_database_delete}; diff --git a/src/processes.c b/src/processes.c index 82a48590..727ec7fd 100644 --- a/src/processes.c +++ b/src/processes.c @@ -185,6 +185,8 @@ typedef struct process_entry_s { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; _Bool has_io; derive_t cswitch_vol; @@ -209,6 +211,8 @@ typedef struct procstat_entry_s { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; derive_t cswitch_vol; derive_t cswitch_invol; @@ -242,6 +246,8 @@ typedef struct procstat { derive_t io_wchar; derive_t io_syscr; derive_t io_syscw; + derive_t io_diskr; + derive_t io_diskw; derive_t cswitch_vol; derive_t cswitch_invol; @@ -310,6 +316,8 @@ static procstat_t *ps_list_register(const char *name, const char *regexp) { new->io_wchar = -1; new->io_syscr = -1; new->io_syscw = -1; + new->io_diskr = -1; + new->io_diskw = -1; new->cswitch_vol = -1; new->cswitch_invol = -1; @@ -480,6 +488,11 @@ static void ps_list_add(const char *name, const char *cmdline, ps_update_counter(&ps->io_syscw, &pse->io_syscw, entry->io_syscw); } + if ((entry->io_diskr != -1) && (entry->io_diskw != -1)) { + ps_update_counter(&ps->io_diskr, &pse->io_diskr, entry->io_diskr); + ps_update_counter(&ps->io_diskw, &pse->io_diskw, entry->io_diskw); + } + if ((entry->cswitch_vol != -1) && (entry->cswitch_vol != -1)) { ps_update_counter(&ps->cswitch_vol, &pse->cswitch_vol, entry->cswitch_vol); @@ -725,7 +738,7 @@ static void ps_submit_proc_list(procstat_t *ps) { plugin_dispatch_values(&vl); if ((ps->io_rchar != -1) && (ps->io_wchar != -1)) { - sstrncpy(vl.type, "ps_disk_octets", sizeof(vl.type)); + sstrncpy(vl.type, "io_octets", sizeof(vl.type)); vl.values[0].derive = ps->io_rchar; vl.values[1].derive = ps->io_wchar; vl.values_len = 2; @@ -733,13 +746,21 @@ static void ps_submit_proc_list(procstat_t *ps) { } if ((ps->io_syscr != -1) && (ps->io_syscw != -1)) { - sstrncpy(vl.type, "ps_disk_ops", sizeof(vl.type)); + sstrncpy(vl.type, "io_ops", sizeof(vl.type)); vl.values[0].derive = ps->io_syscr; vl.values[1].derive = ps->io_syscw; vl.values_len = 2; plugin_dispatch_values(&vl); } + if ((ps->io_diskr != -1) && (ps->io_diskw != -1)) { + sstrncpy(vl.type, "disk_octets", sizeof(vl.type)); + vl.values[0].derive = ps->io_diskr; + vl.values[1].derive = ps->io_diskw; + vl.values_len = 2; + plugin_dispatch_values(&vl); + } + if (ps->num_fd > 0) { sstrncpy(vl.type, "file_handles", sizeof(vl.type)); vl.values[0].gauge = ps->num_fd; @@ -768,12 +789,13 @@ static void ps_submit_proc_list(procstat_t *ps) { "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; " "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; " "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; " + "io_diskr = %" PRIi64 "; io_diskw = %" PRIi64 "; " "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";", ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->vmem_size, ps->vmem_rss, ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter, ps->cpu_system_counter, - ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->cswitch_vol, - ps->cswitch_invol); + ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->io_diskr, + ps->io_diskw, ps->cswitch_vol, ps->cswitch_invol); } /* void ps_submit_proc_list */ #if KERNEL_LINUX || KERNEL_SOLARIS @@ -805,7 +827,7 @@ static int ps_read_tasks_status(process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id); + snprintf(dirname, sizeof(dirname), "/proc/%li/task", ps->id); if ((dh = opendir(dirname)) == NULL) { DEBUG("Failed to open directory `%s'", dirname); @@ -820,8 +842,12 @@ static int ps_read_tasks_status(process_entry_t *ps) { tpid = ent->d_name; - ssnprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id, - tpid); + if (snprintf(filename, sizeof(filename), "/proc/%li/task/%s/status", ps->id, + tpid) >= sizeof(filename)) { + DEBUG("Filename too long: `%s'", filename); + continue; + } + if ((fh = fopen(filename, "r")) == NULL) { DEBUG("Failed to open file `%s'", filename); continue; @@ -878,7 +904,7 @@ static int ps_read_status(long pid, process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(filename, sizeof(filename), "/proc/%li/status", pid); + snprintf(filename, sizeof(filename), "/proc/%li/status", pid); if ((fh = fopen(filename, "r")) == NULL) return -1; @@ -931,7 +957,7 @@ static int ps_read_io(process_entry_t *ps) { char *fields[8]; int numfields; - ssnprintf(filename, sizeof(filename), "/proc/%li/io", ps->id); + snprintf(filename, sizeof(filename), "/proc/%li/io", ps->id); if ((fh = fopen(filename, "r")) == NULL) { DEBUG("ps_read_io: Failed to open file `%s'", filename); return -1; @@ -950,6 +976,10 @@ static int ps_read_io(process_entry_t *ps) { val = &(ps->io_syscr); else if (strncasecmp(buffer, "syscw:", 6) == 0) val = &(ps->io_syscw); + else if (strncasecmp(buffer, "read_bytes:", 11) == 0) + val = &(ps->io_diskr); + else if (strncasecmp(buffer, "write_bytes:", 12) == 0) + val = &(ps->io_diskw); else continue; @@ -980,7 +1010,7 @@ static int ps_count_fd(int pid) { struct dirent *ent; int count = 0; - ssnprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid); + snprintf(dirname, sizeof(dirname), "/proc/%i/fd", pid); if ((dh = opendir(dirname)) == NULL) { DEBUG("Failed to open directory `%s'", dirname); @@ -1041,7 +1071,7 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ssize_t status; - ssnprintf(filename, sizeof(filename), "/proc/%li/stat", pid); + snprintf(filename, sizeof(filename), "/proc/%li/stat", pid); status = read_file_contents(filename, buffer, sizeof(buffer) - 1); if (status <= 0) @@ -1145,6 +1175,8 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ps->io_wchar = -1; ps->io_syscr = -1; ps->io_syscw = -1; + ps->io_diskr = -1; + ps->io_diskw = -1; ps->cswitch_vol = -1; ps->cswitch_invol = -1; @@ -1165,7 +1197,7 @@ static char *ps_get_cmdline(long pid, char *name, char *buf, size_t buf_len) { if ((pid < 1) || (NULL == buf) || (buf_len < 2)) return NULL; - ssnprintf(file, sizeof(file), "/proc/%li/cmdline", pid); + snprintf(file, sizeof(file), "/proc/%li/cmdline", pid); errno = 0; fd = open(file, O_RDONLY); @@ -1220,7 +1252,7 @@ static char *ps_get_cmdline(long pid, char *name, char *buf, size_t buf_len) { if (NULL == name) return NULL; - ssnprintf(buf, buf_len, "[%s]", name); + snprintf(buf, buf_len, "[%s]", name); return buf; } @@ -1403,6 +1435,8 @@ static int ps_read_process(long pid, process_entry_t *ps, char *state) { ps->io_wchar = myUsage->pr_oublk * chars_per_block; ps->io_syscr = myUsage->pr_sysc; ps->io_syscw = myUsage->pr_sysc; + ps->io_diskr = -1; + ps->io_diskw = -1; /* * TODO: context switch counters for Solaris @@ -1616,6 +1650,8 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* File descriptor count not implemented */ pse.num_fd = 0; @@ -1919,6 +1955,8 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* file descriptor count not implemented */ pse.num_fd = 0; @@ -2058,6 +2096,8 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; /* file descriptor count not implemented */ pse.num_fd = 0; @@ -2221,6 +2261,8 @@ static int ps_read(void) { pse.io_wchar = -1; pse.io_syscr = -1; pse.io_syscw = -1; + pse.io_diskr = -1; + pse.io_diskw = -1; pse.num_fd = 0; diff --git a/src/protocols.c b/src/protocols.c index 32e98243..b63dee9a 100644 --- a/src/protocols.c +++ b/src/protocols.c @@ -156,8 +156,8 @@ static int read_file(const char *path) { if (values_list != NULL) { char match_name[2 * DATA_MAX_NAME_LEN]; - ssnprintf(match_name, sizeof(match_name), "%s:%s", key_buffer, - key_fields[i]); + snprintf(match_name, sizeof(match_name), "%s:%s", key_buffer, + key_fields[i]); if (ignorelist_match(values_list, match_name)) continue; diff --git a/src/python.c b/src/python.c index b106e45c..34cab885 100644 --- a/src/python.c +++ b/src/python.c @@ -784,8 +784,8 @@ static PyObject *cpy_register_write(PyObject *self, PyObject *args, static PyObject *cpy_register_notification(PyObject *self, PyObject *args, PyObject *kwds) { return cpy_register_generic_userdata((void *)plugin_register_notification, - (void *)cpy_notification_callback, - args, kwds); + (void *)cpy_notification_callback, args, + kwds); } static PyObject *cpy_register_flush(PyObject *self, PyObject *args, @@ -944,8 +944,7 @@ static PyObject *cpy_unregister_read(PyObject *self, PyObject *arg) { } static PyObject *cpy_unregister_write(PyObject *self, PyObject *arg) { - return cpy_unregister_generic_userdata(plugin_unregister_write, arg, - "write"); + return cpy_unregister_generic_userdata(plugin_unregister_write, arg, "write"); } static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) { @@ -954,8 +953,7 @@ static PyObject *cpy_unregister_notification(PyObject *self, PyObject *arg) { } static PyObject *cpy_unregister_flush(PyObject *self, PyObject *arg) { - return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, - "flush"); + return cpy_unregister_generic_userdata(plugin_unregister_flush, arg, "flush"); } static PyObject *cpy_unregister_shutdown(PyObject *self, PyObject *arg) { diff --git a/src/redis.c b/src/redis.c index 05225b5b..7c704ab5 100644 --- a/src/redis.c +++ b/src/redis.c @@ -370,7 +370,7 @@ static int redis_db_stats(char *node, char const *info_line) /* {{{ */ char *str; int i; - ssnprintf(field_name, sizeof(field_name), "db%d:keys=", db); + snprintf(field_name, sizeof(field_name), "db%d:keys=", db); str = strstr(info_line, field_name); if (!str) @@ -386,7 +386,7 @@ static int redis_db_stats(char *node, char const *info_line) /* {{{ */ return -1; } - ssnprintf(db_id, sizeof(db_id), "%d", db); + snprintf(db_id, sizeof(db_id), "%d", db); redis_submit(node, "records", db_id, val); } return 0; diff --git a/src/routeros.c b/src/routeros.c index ba92b0b2..9ea82976 100644 --- a/src/routeros.c +++ b/src/routeros.c @@ -89,8 +89,7 @@ static void submit_interface(cr_data_t *rd, /* {{{ */ static int handle_interface(__attribute__((unused)) ros_connection_t *c, /* {{{ */ - const ros_interface_t *i, - void *user_data) { + const ros_interface_t *i, void *user_data) { if ((i == NULL) || (user_data == NULL)) return EINVAL; @@ -142,8 +141,8 @@ static void submit_regtable(cr_data_t *rd, /* {{{ */ return; /*** RX ***/ - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-rx", r->interface, - r->radio_name); + snprintf(type_instance, sizeof(type_instance), "%s-%s-rx", r->interface, + r->radio_name); cr_submit_gauge(rd, "bitrate", type_instance, (gauge_t)(1000000.0 * r->rx_rate)); cr_submit_gauge(rd, "signal_power", type_instance, @@ -151,8 +150,8 @@ static void submit_regtable(cr_data_t *rd, /* {{{ */ cr_submit_gauge(rd, "signal_quality", type_instance, (gauge_t)r->rx_ccq); /*** TX ***/ - ssnprintf(type_instance, sizeof(type_instance), "%s-%s-tx", r->interface, - r->radio_name); + snprintf(type_instance, sizeof(type_instance), "%s-%s-tx", r->interface, + r->radio_name); cr_submit_gauge(rd, "bitrate", type_instance, (gauge_t)(1000000.0 * r->tx_rate)); cr_submit_gauge(rd, "signal_power", type_instance, @@ -160,8 +159,8 @@ static void submit_regtable(cr_data_t *rd, /* {{{ */ cr_submit_gauge(rd, "signal_quality", type_instance, (gauge_t)r->tx_ccq); /*** RX / TX ***/ - ssnprintf(type_instance, sizeof(type_instance), "%s-%s", r->interface, - r->radio_name); + snprintf(type_instance, sizeof(type_instance), "%s-%s", r->interface, + r->radio_name); cr_submit_io(rd, "if_octets", type_instance, (derive_t)r->rx_bytes, (derive_t)r->tx_bytes); cr_submit_gauge(rd, "snr", type_instance, (gauge_t)r->signal_to_noise); @@ -171,8 +170,7 @@ static void submit_regtable(cr_data_t *rd, /* {{{ */ static int handle_regtable(__attribute__((unused)) ros_connection_t *c, /* {{{ */ - const ros_registration_table_t *r, - void *user_data) { + const ros_registration_table_t *r, void *user_data) { if ((r == NULL) || (user_data == NULL)) return EINVAL; @@ -378,18 +376,17 @@ static int cr_config_router(oconfig_item_t *ci) /* {{{ */ } } - ssnprintf(read_name, sizeof(read_name), "routeros/%s", router_data->node); - if (status == 0) - status = plugin_register_complex_read( - /* group = */ NULL, read_name, cr_read, /* interval = */ 0, - &(user_data_t){ - .data = router_data, .free_func = (void *)cr_free_data, - }); - - if (status != 0) + if (status != 0) { cr_free_data(router_data); + return status; + } - return status; + snprintf(read_name, sizeof(read_name), "routeros/%s", router_data->node); + return plugin_register_complex_read( + /* group = */ NULL, read_name, cr_read, /* interval = */ 0, + &(user_data_t){ + .data = router_data, .free_func = (void *)cr_free_data, + }); } /* }}} int cr_config_router */ static int cr_config(oconfig_item_t *ci) { diff --git a/src/rrdcached.c b/src/rrdcached.c index 4efb1f0c..82870135 100644 --- a/src/rrdcached.c +++ b/src/rrdcached.c @@ -75,7 +75,7 @@ static int value_list_to_string(char *buffer, int buffer_len, memset(buffer, '\0', buffer_len); t = CDTIME_T_TO_TIME_T(vl->time); - status = ssnprintf(buffer, buffer_len, "%lu", (unsigned long)t); + status = snprintf(buffer, buffer_len, "%lu", (unsigned long)t); if ((status < 1) || (status >= buffer_len)) return -1; offset = status; @@ -88,17 +88,17 @@ static int value_list_to_string(char *buffer, int buffer_len, return -1; if (ds->ds[i].type == DS_TYPE_COUNTER) { - status = ssnprintf(buffer + offset, buffer_len - offset, ":%llu", - vl->values[i].counter); + status = snprintf(buffer + offset, buffer_len - offset, ":%llu", + vl->values[i].counter); } else if (ds->ds[i].type == DS_TYPE_GAUGE) { - status = ssnprintf(buffer + offset, buffer_len - offset, ":%f", - vl->values[i].gauge); + status = snprintf(buffer + offset, buffer_len - offset, ":%f", + vl->values[i].gauge); } else if (ds->ds[i].type == DS_TYPE_DERIVE) { - status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIi64, - vl->values[i].derive); + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64, + vl->values[i].derive); } else /* if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ { - status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIu64, - vl->values[i].absolute); + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64, + vl->values[i].absolute); } if ((status < 1) || (status >= (buffer_len - offset))) @@ -482,9 +482,9 @@ static int rc_flush(__attribute__((unused)) cdtime_t timeout, /* {{{ */ return EINVAL; if (datadir != NULL) - ssnprintf(filename, sizeof(filename), "%s/%s.rrd", datadir, identifier); + snprintf(filename, sizeof(filename), "%s/%s.rrd", datadir, identifier); else - ssnprintf(filename, sizeof(filename), "%s.rrd", identifier); + snprintf(filename, sizeof(filename), "%s.rrd", identifier); rrd_clear_error(); status = rrdc_connect(daemon_address); diff --git a/src/rrdtool.c b/src/rrdtool.c index 5a71ebe8..2dfa87a0 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; @@ -177,7 +177,7 @@ static int value_list_to_string_multiple(char *buffer, int buffer_len, memset(buffer, '\0', buffer_len); tt = CDTIME_T_TO_TIME_T(vl->time); - status = ssnprintf(buffer, buffer_len, "%u", (unsigned int)tt); + status = snprintf(buffer, buffer_len, "%u", (unsigned int)tt); if ((status < 1) || (status >= buffer_len)) return -1; offset = status; @@ -190,17 +190,17 @@ static int value_list_to_string_multiple(char *buffer, int buffer_len, return -1; if (ds->ds[i].type == DS_TYPE_COUNTER) - status = ssnprintf(buffer + offset, buffer_len - offset, ":%llu", - vl->values[i].counter); + status = snprintf(buffer + offset, buffer_len - offset, ":%llu", + vl->values[i].counter); else if (ds->ds[i].type == DS_TYPE_GAUGE) - status = ssnprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT, - vl->values[i].gauge); + status = snprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT, + vl->values[i].gauge); else if (ds->ds[i].type == DS_TYPE_DERIVE) - status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIi64, - vl->values[i].derive); + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64, + vl->values[i].derive); else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ - status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIu64, - vl->values[i].absolute); + status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64, + vl->values[i].absolute); if ((status < 1) || (status >= (buffer_len - offset))) return -1; @@ -222,20 +222,20 @@ static int value_list_to_string(char *buffer, int buffer_len, tt = CDTIME_T_TO_TIME_T(vl->time); switch (ds->ds[0].type) { case DS_TYPE_DERIVE: - status = ssnprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt, - vl->values[0].derive); + status = snprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt, + vl->values[0].derive); break; case DS_TYPE_GAUGE: - status = ssnprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt, - vl->values[0].gauge); + status = snprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt, + vl->values[0].gauge); break; case DS_TYPE_COUNTER: - status = ssnprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt, - vl->values[0].counter); + status = snprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt, + vl->values[0].counter); break; case DS_TYPE_ABSOLUTE: - status = ssnprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt, - vl->values[0].absolute); + status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt, + vl->values[0].absolute); break; default: return EINVAL; @@ -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, @@ -740,7 +726,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 +863,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 +871,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 +1051,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\". " + "Ajusting \"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/sensors.c b/src/sensors.c index ed87c30c..f4ecda5e 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -176,7 +176,7 @@ static int sensors_snprintf_chip_name(char *buf, size_t buf_size, int status = -1; if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA) { - status = ssnprintf(buf, buf_size, "%s-isa-%04x", chip->prefix, chip->addr); + status = snprintf(buf, buf_size, "%s-isa-%04x", chip->prefix, chip->addr); } else if (chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY) { status = snprintf(buf, buf_size, "%s-%s-%04x", chip->prefix, chip->busname, chip->addr); @@ -436,8 +436,8 @@ static void sensors_submit(const char *plugin_instance, const char *type, value_list_t vl = VALUE_LIST_INIT; - status = ssnprintf(match_key, sizeof(match_key), "%s/%s-%s", plugin_instance, - type, type_instance); + status = snprintf(match_key, sizeof(match_key), "%s/%s-%s", plugin_instance, + type, type_instance); if (status < 1) return; diff --git a/src/sigrok.c b/src/sigrok.c index 44920ada..8a325fe9 100644 --- a/src/sigrok.c +++ b/src/sigrok.c @@ -247,10 +247,10 @@ static int sigrok_init_driver(struct config_device *cfdev, } cfdev->sdi = devlist->data; g_slist_free(devlist); - ssnprintf(hwident, sizeof(hwident), "%s %s %s", - cfdev->sdi->vendor ? cfdev->sdi->vendor : "", - cfdev->sdi->model ? cfdev->sdi->model : "", - cfdev->sdi->version ? cfdev->sdi->version : ""); + snprintf(hwident, sizeof(hwident), "%s %s %s", + cfdev->sdi->vendor ? cfdev->sdi->vendor : "", + cfdev->sdi->model ? cfdev->sdi->model : "", + cfdev->sdi->version ? cfdev->sdi->version : ""); INFO("sigrok plugin: Device \"%s\" is a %s", cfdev->name, hwident); if (sr_dev_open(cfdev->sdi) != SR_OK) diff --git a/src/smart.c b/src/smart.c index 0e4e192c..30680be6 100644 --- a/src/smart.c +++ b/src/smart.c @@ -116,9 +116,9 @@ static void handle_attribute(SkDisk *d, const SkSmartAttributeParsedData *a, sstrncpy(notif.host, hostname_g, sizeof(notif.host)); sstrncpy(notif.plugin_instance, name, sizeof(notif.plugin_instance)); sstrncpy(notif.type_instance, a->name, sizeof(notif.type_instance)); - ssnprintf(notif.message, sizeof(notif.message), - "attribute %s is below allowed threshold (%d < %d)", a->name, - a->current_value, a->threshold); + snprintf(notif.message, sizeof(notif.message), + "attribute %s is below allowed threshold (%d < %d)", a->name, + a->current_value, a->threshold); plugin_dispatch_notification(¬if); } } diff --git a/src/snmp.c b/src/snmp.c index 77349f62..bce820e2 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -130,8 +130,7 @@ static void csnmp_oid_init(oid_t *dst, oid const *src, size_t n) { } static int csnmp_oid_compare(oid_t const *left, oid_t const *right) { - return snmp_oid_compare(left->oid, left->oid_len, right->oid, - right->oid_len); + return snmp_oid_compare(left->oid, left->oid_len, right->oid, right->oid_len); } static int csnmp_oid_suffix(oid_t *dst, oid_t const *src, oid_t const *root) { @@ -155,7 +154,7 @@ static int csnmp_oid_to_string(char *buffer, size_t buffer_size, char *oid_str_ptr[MAX_OID_LEN]; for (size_t i = 0; i < o->oid_len; i++) { - ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]); + snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]); oid_str_ptr[i] = oid_str[i]; } @@ -703,7 +702,7 @@ static int csnmp_config_add_host(oconfig_item_t *ci) { "= %i }", hd->name, hd->address, hd->community, hd->version); - ssnprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name); + snprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name); status = plugin_register_complex_read( /* group = */ NULL, cb_name, csnmp_read_host, hd->interval, @@ -712,7 +711,6 @@ static int csnmp_config_add_host(oconfig_item_t *ci) { }); if (status != 0) { ERROR("snmp plugin: Registering complex read function failed."); - csnmp_host_definition_destroy(hd); return -1; } @@ -997,10 +995,10 @@ static int csnmp_strvbcopy(char *dst, /* {{{ */ else if (vb->type == ASN_BIT_STR) src = (char *)vb->val.bitstring; else if (vb->type == ASN_IPADDRESS) { - return ssnprintf(dst, dst_size, - "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", - (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1], - (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]); + return snprintf(dst, dst_size, + "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", + (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1], + (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]); } else { dst[0] = 0; return EINVAL; @@ -1092,7 +1090,7 @@ static int csnmp_instance_list_add(csnmp_list_instances_t **head, value_t val = csnmp_value_list_to_value( vb, DS_TYPE_COUNTER, /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name); - ssnprintf(il->instance, sizeof(il->instance), "%llu", val.counter); + snprintf(il->instance, sizeof(il->instance), "%llu", val.counter); } /* TODO: Debugging output */ @@ -1222,8 +1220,8 @@ static int csnmp_dispatch_table(host_definition_t *host, if (data->instance_prefix == NULL) sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance)); else - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s", - data->instance_prefix, temp); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s", + data->instance_prefix, temp); } vl.values_len = data->values_len; @@ -1329,8 +1327,6 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { status = 0; while (status == 0) { - int oid_list_todo_num; - req = snmp_pdu_create(SNMP_MSG_GETNEXT); if (req == NULL) { ERROR("snmp plugin: snmp_pdu_create failed."); @@ -1338,13 +1334,17 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { break; } - oid_list_todo_num = 0; + size_t oid_list_todo_num = 0; + size_t var_idx[oid_list_len]; + memset(var_idx, 0, sizeof(var_idx)); + for (i = 0; i < oid_list_len; i++) { /* Do not rerequest already finished OIDs */ if (!oid_list_todo[i]) continue; - oid_list_todo_num++; snmp_add_null_var(req, oid_list[i].oid, oid_list[i].oid_len); + var_idx[oid_list_todo_num] = i; + oid_list_todo_num++; } if (oid_list_todo_num == 0) { @@ -1390,6 +1390,39 @@ static int csnmp_read_table(host_definition_t *host, data_definition_t *data) { break; } + if (res->errstat != SNMP_ERR_NOERROR) { + if (res->errindex != 0) { + /* Find the OID which caused error */ + for (i = 1, vb = res->variables; vb != NULL && i != res->errindex; + vb = vb->next_variable, i++) + /* do nothing */; + } + + if ((res->errindex == 0) || (vb == NULL)) { + ERROR("snmp plugin: host %s; data %s: response error: %s (%li) ", + host->name, data->name, snmp_errstring(res->errstat), + res->errstat); + status = -1; + break; + } + + char oid_buffer[1024] = {0}; + snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, vb->name, + vb->name_length); + NOTICE("snmp plugin: host %s; data %s: OID `%s` failed: %s", host->name, + data->name, oid_buffer, snmp_errstring(res->errstat)); + + /* Get value index from todo list and skip OID found */ + assert(res->errindex <= oid_list_todo_num); + i = var_idx[res->errindex - 1]; + assert(i < oid_list_len); + oid_list_todo[i] = 0; + + snmp_free_pdu(res); + res = NULL; + continue; + } + for (vb = res->variables, i = 0; (vb != NULL); vb = vb->next_variable, i++) { /* Calculate value index from todo list */ diff --git a/src/snmp_agent.c b/src/snmp_agent.c index 0908b4eb..497d157c 100644 --- a/src/snmp_agent.c +++ b/src/snmp_agent.c @@ -98,6 +98,7 @@ static snmp_agent_ctx_t *g_agent = NULL; (_dd->type ? !strcmp(_dd->type, _t) : 0) && \ (_dd->type_instance ? !strcmp(_dd->type_instance, _ti) : 1) +static int snmp_agent_shutdown(void); static void *snmp_agent_thread_run(void *arg); static int snmp_agent_register_oid(oid_t *oid, Netsnmp_Node_Handler *handler); static int snmp_agent_set_vardata(void *dst_buf, size_t *dst_buf_len, @@ -123,7 +124,7 @@ static int snmp_agent_oid_to_string(char *buf, size_t buf_size, char *oid_str_ptr[MAX_OID_LEN]; for (size_t i = 0; i < o->oid_len; i++) { - ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]); + snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]); oid_str_ptr[i] = oid_str[i]; } @@ -282,7 +283,8 @@ static int snmp_agent_validate_data(void) { return 0; } -static void snmp_agent_generate_oid2string(oid_t *oid, size_t offset, char *key) { +static void snmp_agent_generate_oid2string(oid_t *oid, size_t offset, + char *key) { int key_len = oid->oid[offset]; int i; @@ -368,9 +370,9 @@ static int snmp_agent_table_row_remove(table_definition_t *td, .severity = NOTIF_WARNING, .time = cdtime(), .plugin = PLUGIN_NAME}; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); - ssnprintf(n.message, sizeof(n.message), - "Removed data row from table %s instance %s index %d", td->name, - ins, (index != NULL) ? *index : -1); + snprintf(n.message, sizeof(n.message), + "Removed data row from table %s instance %s index %d", td->name, ins, + (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); if (td->index_oid.oid_len) { @@ -420,28 +422,6 @@ static void snmp_agent_free_data(data_definition_t **dd) { for (size_t i = 0; i < (*dd)->oids_len; i++) unregister_mib((*dd)->oids[i].oid, (*dd)->oids[i].oid_len); } - if (!(*dd)->table->index_oid.oid_len) { - char *instance; - - c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->instance_index); - while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) == - 0) { - for (size_t i = 0; i < (*dd)->oids_len; i++) - snmp_agent_unregister_oid_string(&(*dd)->oids[i], instance); - } - c_avl_iterator_destroy(iter); - } else { - /* unregister all table OIDs */ - int *index; - char *value; - - c_avl_iterator_t *iter = c_avl_get_iterator((*dd)->table->index_instance); - while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0) { - for (size_t i = 0; i < (*dd)->oids_len; i++) - snmp_agent_unregister_oid_index(&(*dd)->oids[i], *index); - } - c_avl_iterator_destroy(iter); - } sfree((*dd)->name); sfree((*dd)->plugin); @@ -455,6 +435,43 @@ static void snmp_agent_free_data(data_definition_t **dd) { return; } +static void snmp_agent_free_table_columns(table_definition_t *td) { + if (td->columns == NULL) + return; + + for (llentry_t *de = llist_head(td->columns); de != NULL; de = de->next) { + data_definition_t *dd = de->value; + + if (td->index_oid.oid_len) { + int *index; + char *instance; + + c_avl_iterator_t *iter = c_avl_get_iterator(td->index_instance); + while (c_avl_iterator_next(iter, (void *)&index, (void *)&instance) == + 0) { + for (size_t i = 0; i < dd->oids_len; i++) + snmp_agent_unregister_oid_index(&dd->oids[i], *index); + } + c_avl_iterator_destroy(iter); + } else { + char *instance; + + c_avl_iterator_t *iter = c_avl_get_iterator(dd->table->instance_index); + while (c_avl_iterator_next(iter, (void *)&instance, (void *)&instance) == + 0) { + for (size_t i = 0; i < dd->oids_len; i++) + snmp_agent_unregister_oid_string(&dd->oids[i], instance); + } + c_avl_iterator_destroy(iter); + } + + snmp_agent_free_data(&dd); + } + + llist_destroy(td->columns); + td->columns = NULL; +} /* void snmp_agent_free_table_columns */ + static void snmp_agent_free_table(table_definition_t **td) { if (td == NULL || *td == NULL) @@ -463,23 +480,20 @@ static void snmp_agent_free_table(table_definition_t **td) { if ((*td)->size_oid.oid_len) unregister_mib((*td)->size_oid.oid, (*td)->size_oid.oid_len); + /* Unregister Index OIDs */ if ((*td)->index_oid.oid_len) { int *index; - char *value; + char *instance; c_avl_iterator_t *iter = c_avl_get_iterator((*td)->index_instance); - while (c_avl_iterator_next(iter, (void *)&index, (void *)&value) == 0) + while (c_avl_iterator_next(iter, (void *)&index, (void *)&instance) == 0) snmp_agent_unregister_oid_index(&(*td)->index_oid, *index); c_avl_iterator_destroy(iter); } - for (llentry_t *de = llist_head((*td)->columns); de != NULL; de = de->next) { - data_definition_t *dd = de->value; - snmp_agent_free_data(&dd); - } - - llist_destroy((*td)->columns); + /* Unregister all table columns and their registered OIDs */ + snmp_agent_free_table_columns(*td); void *key = NULL; void *value = NULL; @@ -616,9 +630,9 @@ snmp_agent_table_oid_handler(struct netsnmp_mib_handler_s *handler, if (dd->is_instance) { requests->requestvb->type = ASN_OCTET_STR; - snmp_set_var_typed_value(requests->requestvb, - requests->requestvb->type, (const u_char *)instance, - strlen((instance))); + snmp_set_var_typed_value( + requests->requestvb, requests->requestvb->type, + (const u_char *)instance, strlen((instance))); pthread_mutex_unlock(&g_agent->lock); @@ -1305,9 +1319,9 @@ static int snmp_agent_update_index(table_definition_t *td, .severity = NOTIF_OKAY, .time = cdtime(), .plugin = PLUGIN_NAME}; sstrncpy(n.host, hostname_g, sizeof(n.host)); sstrncpy(n.plugin_instance, ins, sizeof(n.plugin_instance)); - ssnprintf(n.message, sizeof(n.message), - "Data row added to table %s instance %s index %d", td->name, ins, - (index != NULL) ? *index : -1); + snprintf(n.message, sizeof(n.message), + "Data row added to table %s instance %s index %d", td->name, ins, + (index != NULL) ? *index : -1); plugin_dispatch_notification(&n); return 0; @@ -1364,12 +1378,21 @@ static int snmp_agent_preinit(void) { g_agent->tables = llist_create(); g_agent->scalars = llist_create(); + if (g_agent->tables == NULL || g_agent->scalars == NULL) { + ERROR(PLUGIN_NAME ": llist_create() failed"); + llist_destroy(g_agent->scalars); + llist_destroy(g_agent->tables); + return -ENOMEM; + } + int err; /* make us a agentx client. */ err = netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); if (err != 0) { ERROR(PLUGIN_NAME ": Failed to set agent role (%d)", err); + llist_destroy(g_agent->scalars); + llist_destroy(g_agent->tables); return -1; } @@ -1381,6 +1404,8 @@ static int snmp_agent_preinit(void) { err = init_agent(PLUGIN_NAME); if (err != 0) { ERROR(PLUGIN_NAME ": Failed to initialize the agent library (%d)", err); + llist_destroy(g_agent->scalars); + llist_destroy(g_agent->tables); return -1; } @@ -1394,9 +1419,13 @@ static int snmp_agent_preinit(void) { static int snmp_agent_init(void) { int ret; - ret = snmp_agent_preinit(); - if (ret != 0) - return ret; + if (g_agent == NULL || ((llist_head(g_agent->scalars) == NULL) && + (llist_head(g_agent->tables) == NULL))) { + ERROR(PLUGIN_NAME ": snmp_agent_init: plugin not configured"); + return -EINVAL; + } + + plugin_register_shutdown(PLUGIN_NAME, snmp_agent_shutdown); ret = snmp_agent_register_scalar_oids(); if (ret != 0) @@ -1406,13 +1435,6 @@ static int snmp_agent_init(void) { if (ret != 0) return ret; - /* create a second thread to listen for requests from AgentX*/ - ret = pthread_create(&g_agent->thread, NULL, &snmp_agent_thread_run, NULL); - if (ret != 0) { - ERROR(PLUGIN_NAME ": Failed to create a separate thread, err %u", ret); - return ret; - } - ret = pthread_mutex_init(&g_agent->lock, NULL); if (ret != 0) { ERROR(PLUGIN_NAME ": Failed to initialize mutex, err %u", ret); @@ -1425,6 +1447,18 @@ static int snmp_agent_init(void) { return ret; } + /* create a second thread to listen for requests from AgentX*/ + ret = pthread_create(&g_agent->thread, NULL, &snmp_agent_thread_run, NULL); + if (ret != 0) { + ERROR(PLUGIN_NAME ": Failed to create a separate thread, err %u", ret); + return ret; + } + + if (llist_head(g_agent->tables) != NULL) { + plugin_register_write(PLUGIN_NAME, snmp_agent_collect, NULL); + plugin_register_missing(PLUGIN_NAME, snmp_agent_clear_missing, NULL); + } + return 0; } @@ -1570,7 +1604,4 @@ static int snmp_agent_config(oconfig_item_t *ci) { void module_register(void) { plugin_register_init(PLUGIN_NAME, snmp_agent_init); plugin_register_complex_config(PLUGIN_NAME, snmp_agent_config); - plugin_register_write(PLUGIN_NAME, snmp_agent_collect, NULL); - plugin_register_missing(PLUGIN_NAME, snmp_agent_clear_missing, NULL); - plugin_register_shutdown(PLUGIN_NAME, snmp_agent_shutdown); } diff --git a/src/statsd.c b/src/statsd.c index e1b52cbc..51426137 100644 --- a/src/statsd.c +++ b/src/statsd.c @@ -605,8 +605,9 @@ static int statsd_config_timer_percentile(oconfig_item_t *ci) /* {{{ */ return ERANGE; } - tmp = realloc(conf_timer_percentile, sizeof(*conf_timer_percentile) * - (conf_timer_percentile_num + 1)); + tmp = + realloc(conf_timer_percentile, + sizeof(*conf_timer_percentile) * (conf_timer_percentile_num + 1)); if (tmp == NULL) { ERROR("statsd plugin: realloc failed."); return ENOMEM; @@ -731,7 +732,7 @@ static int statsd_metric_submit_unsafe(char const *name, /* Make sure all timer metrics share the *same* timestamp. */ vl.time = cdtime(); - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-average", name); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-average", name); vl.values[0].gauge = have_events ? CDTIME_T_TO_DOUBLE(latency_counter_get_average(metric->latency)) @@ -739,7 +740,7 @@ static int statsd_metric_submit_unsafe(char const *name, plugin_dispatch_values(&vl); if (conf_timer_lower) { - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-lower", name); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-lower", name); vl.values[0].gauge = have_events ? CDTIME_T_TO_DOUBLE(latency_counter_get_min(metric->latency)) @@ -748,7 +749,7 @@ static int statsd_metric_submit_unsafe(char const *name, } if (conf_timer_upper) { - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-upper", name); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-upper", name); vl.values[0].gauge = have_events ? CDTIME_T_TO_DOUBLE(latency_counter_get_max(metric->latency)) @@ -757,7 +758,7 @@ static int statsd_metric_submit_unsafe(char const *name, } if (conf_timer_sum) { - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-sum", name); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-sum", name); vl.values[0].gauge = have_events ? CDTIME_T_TO_DOUBLE(latency_counter_get_sum(metric->latency)) @@ -766,8 +767,8 @@ static int statsd_metric_submit_unsafe(char const *name, } for (size_t i = 0; i < conf_timer_percentile_num; i++) { - ssnprintf(vl.type_instance, sizeof(vl.type_instance), - "%s-percentile-%.0f", name, conf_timer_percentile[i]); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-percentile-%.0f", + name, conf_timer_percentile[i]); vl.values[0].gauge = have_events ? CDTIME_T_TO_DOUBLE(latency_counter_get_percentile( metric->latency, conf_timer_percentile[i])) @@ -779,7 +780,7 @@ static int statsd_metric_submit_unsafe(char const *name, * vl.type's above are implicitly set to "latency". */ if (conf_timer_count) { sstrncpy(vl.type, "gauge", sizeof(vl.type)); - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-count", name); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-count", name); vl.values[0].gauge = latency_counter_get_num(metric->latency); plugin_dispatch_values(&vl); } diff --git a/src/swap.c b/src/swap.c index 746ba51a..78f05c5f 100644 --- a/src/swap.c +++ b/src/swap.c @@ -111,6 +111,7 @@ static int pagesize; static _Bool values_absolute = 1; static _Bool values_percentage = 0; +static _Bool report_io = 1; static int swap_config(oconfig_item_t *ci) /* {{{ */ { @@ -136,6 +137,8 @@ static int swap_config(oconfig_item_t *ci) /* {{{ */ cf_util_get_boolean(child, &values_absolute); else if (strcasecmp("ValuesPercentage", child->key) == 0) cf_util_get_boolean(child, &values_percentage); + else if (strcasecmp("ReportIO", child->key) == 0) + cf_util_get_boolean(child, &report_io); else WARNING("swap plugin: Unknown config option: \"%s\"", child->key); } @@ -406,11 +409,12 @@ static int swap_read(void) /* {{{ */ else swap_read_combined(); - swap_read_io(); + if (report_io) + swap_read_io(); return 0; } /* }}} int swap_read */ - /* #endif KERNEL_LINUX */ +/* #endif KERNEL_LINUX */ /* * Under Solaris, two mechanisms can be used to read swap statistics, swapctl @@ -726,8 +730,11 @@ static int swap_read(void) /* {{{ */ reserved = (gauge_t)(pmemory.pgsp_rsvd * pagesize); swap_submit_usage(NULL, total - free, free, "reserved", reserved); - swap_submit_derive("in", (derive_t)pmemory.pgspins * pagesize); - swap_submit_derive("out", (derive_t)pmemory.pgspouts * pagesize); + + if (report_io) { + swap_submit_derive("in", (derive_t)pmemory.pgspins * pagesize); + swap_submit_derive("out", (derive_t)pmemory.pgspouts * pagesize); + } return 0; } /* }}} int swap_read */ diff --git a/src/synproxy.c b/src/synproxy.c new file mode 100644 index 00000000..6c6b997d --- /dev/null +++ b/src/synproxy.c @@ -0,0 +1,112 @@ +/** + * collectd - src/synproxy.c + * Copyright (C) 2017 Marek Becka + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Marek Becka + **/ + +#include "collectd.h" + +#include "common.h" +#include "plugin.h" + +#if !KERNEL_LINUX +#error "No applicable input method." +#endif + +#define SYNPROXY_FIELDS 6 + +static const char *synproxy_stat_path = "/proc/net/stat/synproxy"; + +static const char *column_names[SYNPROXY_FIELDS] = { + "entries", "syn_received", "invalid", + "valid", "retransmission", "reopened"}; +static const char *column_types[SYNPROXY_FIELDS] = { + "current_connections", "connections", "cookies", "cookies", "cookies", + "connections"}; + +static void synproxy_submit(value_t *results) { + value_list_t vl = VALUE_LIST_INIT; + + /* 1st column (entries) is hardcoded to 0 in kernel code */ + for (size_t n = 1; n < SYNPROXY_FIELDS; n++) { + vl.values = &results[n]; + vl.values_len = 1; + + sstrncpy(vl.plugin, "synproxy", sizeof(vl.plugin)); + sstrncpy(vl.type, column_types[n], sizeof(vl.type)); + sstrncpy(vl.type_instance, column_names[n], sizeof(vl.type_instance)); + + plugin_dispatch_values(&vl); + } +} + +static int synproxy_read(void) { + char buf[1024]; + value_t results[SYNPROXY_FIELDS]; + int is_header = 1, status = 0; + + FILE *fh = fopen(synproxy_stat_path, "r"); + if (fh == NULL) { + ERROR("synproxy plugin: unable to open %s", synproxy_stat_path); + return -1; + } + + memset(results, 0, sizeof(results)); + + while (fgets(buf, sizeof(buf), fh) != NULL) { + char *fields[SYNPROXY_FIELDS], *endprt; + + if (is_header) { + is_header = 0; + continue; + } + + int numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE(fields)); + if (numfields != SYNPROXY_FIELDS) { + ERROR("synproxy plugin: unexpected number of columns in %s", + synproxy_stat_path); + status = -1; + break; + } + + /* 1st column (entries) is hardcoded to 0 in kernel code */ + for (size_t n = 1; n < SYNPROXY_FIELDS; n++) { + char *endptr = NULL; + errno = 0; + + results[n].derive += strtoull(fields[n], &endprt, 16); + if ((endptr == fields[n]) || errno != 0) { + ERROR("synproxy plugin: unable to parse value: %s", fields[n]); + fclose(fh); + return -1; + } + } + } + + fclose(fh); + + if (status == 0) { + synproxy_submit(results); + } + + return status; +} + +void module_register(void) { + plugin_register_read("synproxy", synproxy_read); +} /* void module_register */ diff --git a/src/syslog.c b/src/syslog.c index 8192d6a1..90a97fb5 100644 --- a/src/syslog.c +++ b/src/syslog.c @@ -107,7 +107,7 @@ static int sl_notification(const notification_t *n, #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(&buf[offset], sizeof(buf) - offset, __VA_ARGS__); \ + status = snprintf(&buf[offset], sizeof(buf) - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (sizeof(buf) - offset)) \ diff --git a/src/table.c b/src/table.c index 578e019e..5fb51512 100644 --- a/src/table.c +++ b/src/table.c @@ -55,6 +55,7 @@ typedef struct { typedef struct { char *file; char *sep; + char *plugin_name; char *instance; tbl_result_t *results; @@ -92,6 +93,7 @@ static void tbl_result_clear(tbl_result_t *res) { static void tbl_setup(tbl_t *tbl, char *file) { tbl->file = sstrdup(file); tbl->sep = NULL; + tbl->plugin_name = NULL; tbl->instance = NULL; tbl->results = NULL; @@ -103,6 +105,7 @@ static void tbl_setup(tbl_t *tbl, char *file) { static void tbl_clear(tbl_t *tbl) { sfree(tbl->file); sfree(tbl->sep); + sfree(tbl->plugin_name); sfree(tbl->instance); for (size_t i = 0; i < tbl->results_num; ++i) @@ -256,6 +259,8 @@ static int tbl_config_table(oconfig_item_t *ci) { if (0 == strcasecmp(c->key, "Separator")) tbl_config_set_s(c->key, &tbl->sep, c); + else if (0 == strcasecmp(c->key, "Plugin")) + tbl_config_set_s(c->key, &tbl->plugin_name, c); else if (0 == strcasecmp(c->key, "Instance")) tbl_config_set_s(c->key, &tbl->instance, c); else if (0 == strcasecmp(c->key, "Result")) @@ -367,7 +372,8 @@ static int tbl_result_dispatch(tbl_t *tbl, tbl_result_t *res, char **fields, vl.values = values; vl.values_len = STATIC_ARRAY_SIZE(values); - sstrncpy(vl.plugin, "table", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (tbl->plugin_name != NULL) ? tbl->plugin_name : "table", + sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, tbl->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, res->type, sizeof(vl.type)); diff --git a/src/tail.c b/src/tail.c index 1b720b83..fbba4788 100644 --- a/src/tail.c +++ b/src/tail.c @@ -34,7 +34,8 @@ /* * * - * Instance "exim" + * Plugin "mail" + * Instance "exim" * Interval 60 * * Regex "S=([1-9][0-9]*)" @@ -134,6 +135,7 @@ static int ctail_config_add_match_dstype(ctail_config_match_t *cm, } /* int ctail_config_add_match_dstype */ static int ctail_config_add_match(cu_tail_match_t *tm, + const char *plugin_name, const char *plugin_instance, oconfig_item_t *ci, cdtime_t interval) { ctail_config_match_t cm = {0}; @@ -191,7 +193,8 @@ static int ctail_config_add_match(cu_tail_match_t *tm, if (status == 0) { // TODO(octo): there's nothing "simple" about the latency stuff … status = tail_match_add_match_simple( - tm, cm.regex, cm.excluderegex, cm.flags, "tail", plugin_instance, + tm, cm.regex, cm.excluderegex, cm.flags, + (plugin_name != NULL) ? plugin_name : "tail", plugin_instance, cm.type, cm.type_instance, cm.latency, interval); if (status != 0) @@ -210,6 +213,7 @@ static int ctail_config_add_match(cu_tail_match_t *tm, static int ctail_config_add_file(oconfig_item_t *ci) { cu_tail_match_t *tm; cdtime_t interval = 0; + char *plugin_name = NULL; char *plugin_instance = NULL; int num_matches = 0; @@ -229,12 +233,15 @@ static int ctail_config_add_file(oconfig_item_t *ci) { oconfig_item_t *option = ci->children + i; int status = 0; - if (strcasecmp("Instance", option->key) == 0) + if (strcasecmp("Plugin", option->key) == 0) + status = cf_util_get_string (option, &plugin_name); + else if (strcasecmp("Instance", option->key) == 0) status = cf_util_get_string(option, &plugin_instance); else if (strcasecmp("Interval", option->key) == 0) cf_util_get_cdtime(option, &interval); else if (strcasecmp("Match", option->key) == 0) { - status = ctail_config_add_match(tm, plugin_instance, option, interval); + status = ctail_config_add_match(tm, plugin_name, plugin_instance, option, + interval); if (status == 0) num_matches++; /* Be mild with failed matches.. */ @@ -247,6 +254,7 @@ static int ctail_config_add_file(oconfig_item_t *ci) { break; } /* for (i = 0; i < ci->children_num; i++) */ + sfree(plugin_name); sfree(plugin_instance); if (num_matches == 0) { @@ -309,7 +317,7 @@ static int ctail_init(void) { } for (size_t i = 0; i < tail_match_list_num; i++) { - ssnprintf(str, sizeof(str), "tail-%zu", i); + snprintf(str, sizeof(str), "tail-%zu", i); plugin_register_complex_read(NULL, str, ctail_read, tail_match_list_intervals[i], diff --git a/src/tail_csv.c b/src/tail_csv.c index d512a52e..2e3ac5f0 100644 --- a/src/tail_csv.c +++ b/src/tail_csv.c @@ -44,6 +44,7 @@ struct metric_definition_s { typedef struct metric_definition_s metric_definition_t; struct instance_definition_s { + char *plugin_name; char *instance; char *path; cu_tail_t *tail; @@ -67,7 +68,8 @@ static int tcsv_submit(instance_definition_t *id, metric_definition_t *md, vl.values_len = 1; vl.values = &v; - sstrncpy(vl.plugin, "tail_csv", sizeof(vl.plugin)); + sstrncpy(vl.plugin, (id->plugin_name != NULL) ? id->plugin_name : "tail_csv", + sizeof(vl.plugin)); if (id->instance != NULL) sstrncpy(vl.plugin_instance, id->instance, sizeof(vl.plugin_instance)); sstrncpy(vl.type, md->type, sizeof(vl.type)); @@ -358,6 +360,7 @@ static void tcsv_instance_definition_destroy(void *arg) { cu_tail_destroy(id->tail); id->tail = NULL; + sfree(id->plugin_name); sfree(id->instance); sfree(id->path); sfree(id->metric_list); @@ -420,6 +423,7 @@ static int tcsv_config_add_file(oconfig_item_t *ci) { id = calloc(1, sizeof(*id)); if (id == NULL) return -1; + id->plugin_name = NULL; id->instance = NULL; id->path = NULL; id->metric_list = NULL; @@ -447,6 +451,8 @@ static int tcsv_config_add_file(oconfig_item_t *ci) { cf_util_get_cdtime(option, &id->interval); else if (strcasecmp("TimeFrom", option->key) == 0) status = tcsv_config_get_index(option, &id->time_from); + else if (strcasecmp("Plugin", option->key) == 0) + status = cf_util_get_string(option, &id->plugin_name); else { WARNING("tail_csv plugin: Option `%s' not allowed here.", option->key); status = -1; @@ -475,7 +481,7 @@ static int tcsv_config_add_file(oconfig_item_t *ci) { return -1; } - ssnprintf(cb_name, sizeof(cb_name), "tail_csv/%s", id->path); + snprintf(cb_name, sizeof(cb_name), "tail_csv/%s", id->path); status = plugin_register_complex_read( NULL, cb_name, tcsv_read, id->interval, @@ -484,7 +490,6 @@ static int tcsv_config_add_file(oconfig_item_t *ci) { }); if (status != 0) { ERROR("tail_csv plugin: Registering complex read function failed."); - tcsv_instance_definition_destroy(id); return -1; } diff --git a/src/target_notification.c b/src/target_notification.c index 2041510f..429e256d 100644 --- a/src/target_notification.c +++ b/src/target_notification.c @@ -221,7 +221,7 @@ static int tn_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ char template[DATA_MAX_NAME_LEN]; char value_str[DATA_MAX_NAME_LEN]; - ssnprintf(template, sizeof(template), "%%{ds:%s}", ds->ds[i].name); + snprintf(template, sizeof(template), "%%{ds:%s}", ds->ds[i].name); if (ds->ds[i].type != DS_TYPE_GAUGE) { if ((rates == NULL) && (rates_failed == 0)) { @@ -233,12 +233,12 @@ static int tn_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ /* If this is a gauge value, use the current value. */ if (ds->ds[i].type == DS_TYPE_GAUGE) - ssnprintf(value_str, sizeof(value_str), GAUGE_FORMAT, - (double)vl->values[i].gauge); + snprintf(value_str, sizeof(value_str), GAUGE_FORMAT, + (double)vl->values[i].gauge); /* If it's a counter, try to use the current rate. This may fail, if the * value has been renamed. */ else if (rates != NULL) - ssnprintf(value_str, sizeof(value_str), GAUGE_FORMAT, (double)rates[i]); + snprintf(value_str, sizeof(value_str), GAUGE_FORMAT, (double)rates[i]); /* Since we don't know any better, use the string `unknown'. */ else sstrncpy(value_str, "unknown", sizeof(value_str)); diff --git a/src/target_scale.c b/src/target_scale.c index 8ec53d48..1cc5d793 100644 --- a/src/target_scale.c +++ b/src/target_scale.c @@ -56,12 +56,12 @@ static int ts_invoke_counter(const data_set_t *ds, value_list_t *vl, /* {{{ */ curr_counter = (uint64_t)vl->values[dsrc_index].counter; - ssnprintf(key_prev_counter, sizeof(key_prev_counter), - "target_scale[%p,%i]:prev_counter", (void *)data, dsrc_index); - ssnprintf(key_int_counter, sizeof(key_int_counter), - "target_scale[%p,%i]:int_counter", (void *)data, dsrc_index); - ssnprintf(key_int_fraction, sizeof(key_int_fraction), - "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); + snprintf(key_prev_counter, sizeof(key_prev_counter), + "target_scale[%p,%i]:prev_counter", (void *)data, dsrc_index); + snprintf(key_int_counter, sizeof(key_int_counter), + "target_scale[%p,%i]:int_counter", (void *)data, dsrc_index); + snprintf(key_int_fraction, sizeof(key_int_fraction), + "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); prev_counter = curr_counter; int_counter = 0; @@ -149,12 +149,12 @@ static int ts_invoke_derive(const data_set_t *ds, value_list_t *vl, /* {{{ */ curr_derive = (int64_t)vl->values[dsrc_index].derive; - ssnprintf(key_prev_derive, sizeof(key_prev_derive), - "target_scale[%p,%i]:prev_derive", (void *)data, dsrc_index); - ssnprintf(key_int_derive, sizeof(key_int_derive), - "target_scale[%p,%i]:int_derive", (void *)data, dsrc_index); - ssnprintf(key_int_fraction, sizeof(key_int_fraction), - "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); + snprintf(key_prev_derive, sizeof(key_prev_derive), + "target_scale[%p,%i]:prev_derive", (void *)data, dsrc_index); + snprintf(key_int_derive, sizeof(key_int_derive), + "target_scale[%p,%i]:int_derive", (void *)data, dsrc_index); + snprintf(key_int_fraction, sizeof(key_int_fraction), + "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); prev_derive = curr_derive; int_derive = 0; @@ -232,8 +232,8 @@ static int ts_invoke_absolute(const data_set_t *ds, value_list_t *vl, /* {{{ */ curr_absolute = (uint64_t)vl->values[dsrc_index].absolute; - ssnprintf(key_int_fraction, sizeof(key_int_fraction), - "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); + snprintf(key_int_fraction, sizeof(key_int_fraction), + "target_scale[%p,%i]:int_fraction", (void *)data, dsrc_index); int_fraction = 0.0; diff --git a/src/target_set.c b/src/target_set.c index e3ec2692..33ab96c9 100644 --- a/src/target_set.c +++ b/src/target_set.c @@ -193,7 +193,7 @@ static void ts_subst(char *dest, size_t size, const char *string, /* {{{ */ char *value_str; const char *key = meta_toc[i]; - ssnprintf(meta_name, sizeof(meta_name), "%%{meta:%s}", key); + snprintf(meta_name, sizeof(meta_name), "%%{meta:%s}", key); if (meta_data_as_string(vl->meta, key, &value_str) != 0) continue; diff --git a/src/target_v5upgrade.c b/src/target_v5upgrade.c index 90f8e005..49f09f08 100644 --- a/src/target_v5upgrade.c +++ b/src/target_v5upgrade.c @@ -238,23 +238,23 @@ static int v5_zfs_arc_counts(const data_set_t *ds, value_list_t *vl) /* {{{ */ /* Dispatch new value lists instead of this one */ new_vl.values[0].derive = (derive_t)vl->values[0].counter; - ssnprintf(new_vl.type_instance, sizeof(new_vl.type_instance), - "demand_data-%s", is_hits ? "hit" : "miss"); + snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), "demand_data-%s", + is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[1].counter; - ssnprintf(new_vl.type_instance, sizeof(new_vl.type_instance), - "demand_metadata-%s", is_hits ? "hit" : "miss"); + snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), + "demand_metadata-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[2].counter; - ssnprintf(new_vl.type_instance, sizeof(new_vl.type_instance), - "prefetch_data-%s", is_hits ? "hit" : "miss"); + snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), + "prefetch_data-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); new_vl.values[0].derive = (derive_t)vl->values[3].counter; - ssnprintf(new_vl.type_instance, sizeof(new_vl.type_instance), - "prefetch_metadata-%s", is_hits ? "hit" : "miss"); + snprintf(new_vl.type_instance, sizeof(new_vl.type_instance), + "prefetch_metadata-%s", is_hits ? "hit" : "miss"); plugin_dispatch_values(&new_vl); /* Abort processing */ diff --git a/src/tcpconns.c b/src/tcpconns.c index f12ce5c6..9fdd16e9 100644 --- a/src/tcpconns.c +++ b/src/tcpconns.c @@ -70,7 +70,8 @@ #undef HAVE_SYSCTLBYNAME /* force HAVE_LIBKVM_NLIST path */ #endif -#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_KVM_GETFILES && !HAVE_LIBKVM_NLIST && !KERNEL_AIX +#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_KVM_GETFILES && \ + !HAVE_LIBKVM_NLIST && !KERNEL_AIX #error "No applicable input method." #endif @@ -110,8 +111,8 @@ /* #endif HAVE_SYSCTLBYNAME */ #elif HAVE_KVM_GETFILES -#include #include +#include #define _KERNEL /* for DTYPE_SOCKET */ #include #undef _KERNEL @@ -127,9 +128,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -292,8 +293,8 @@ static void conn_submit_port_entry(port_entry_t *pe) { if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING)) || (pe->flags & PORT_COLLECT_LOCAL)) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), - "%" PRIu16 "-local", pe->port); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), + "%" PRIu16 "-local", pe->port); for (int i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_local[i]; @@ -305,8 +306,8 @@ static void conn_submit_port_entry(port_entry_t *pe) { } if (pe->flags & PORT_COLLECT_REMOTE) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), - "%" PRIu16 "-remote", pe->port); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), + "%" PRIu16 "-remote", pe->port); for (int i = 1; i <= TCP_STATE_MAX; i++) { vl.values[0].gauge = pe->count_remote[i]; @@ -830,8 +831,7 @@ static int conn_read(void) { conn_reset_port_entry(); - kf = kvm_getfiles(kvmd, KERN_FILE_BYFILE, DTYPE_SOCKET, - sizeof(*kf), &fcnt); + kf = kvm_getfiles(kvmd, KERN_FILE_BYFILE, DTYPE_SOCKET, sizeof(*kf), &fcnt); if (kf == NULL) { ERROR("tcpconns plugin: kvm_getfiles failed."); return -1; diff --git a/src/teamspeak2.c b/src/teamspeak2.c index a26d16e3..4d68f61f 100644 --- a/src/teamspeak2.c +++ b/src/teamspeak2.c @@ -333,7 +333,7 @@ static int tss2_select_vserver(FILE *read_fh, FILE *write_fh, int status; /* Send request */ - ssnprintf(command, sizeof(command), "sel %i\r\n", vserver->port); + snprintf(command, sizeof(command), "sel %i\r\n", vserver->port); status = tss2_send_request(write_fh, command); if (status != 0) { @@ -463,8 +463,8 @@ static int tss2_read_vserver(vserver_list_t *vserver) { status = tss2_send_request(write_fh, "gi\r\n"); } else { /* Request server information */ - ssnprintf(plugin_instance, sizeof(plugin_instance), "vserver%i", - vserver->port); + snprintf(plugin_instance, sizeof(plugin_instance), "vserver%i", + vserver->port); /* Select the server */ status = tss2_select_vserver(read_fh, write_fh, vserver); diff --git a/src/thermal.c b/src/thermal.c index 48157552..9da8fa5f 100644 --- a/src/thermal.c +++ b/src/thermal.c @@ -65,14 +65,14 @@ static int thermal_sysfs_device_read(const char __attribute__((unused)) * dir, if (device_list && ignorelist_match(device_list, name)) return -1; - ssnprintf(filename, sizeof(filename), "%s/%s/temp", dirname_sysfs, name); + snprintf(filename, sizeof(filename), "%s/%s/temp", dirname_sysfs, name); if (parse_value_file(filename, &value, DS_TYPE_GAUGE) == 0) { value.gauge /= 1000.0; thermal_submit(name, TEMP, value); success = 1; } - ssnprintf(filename, sizeof(filename), "%s/%s/cur_state", dirname_sysfs, name); + snprintf(filename, sizeof(filename), "%s/%s/cur_state", dirname_sysfs, name); if (parse_value_file(filename, &value, DS_TYPE_GAUGE) == 0) { thermal_submit(name, COOLING_DEV, value); success = 1; @@ -98,8 +98,8 @@ static int thermal_procfs_device_read(const char __attribute__((unused)) * dir, * temperature: 55 C */ - len = ssnprintf(filename, sizeof(filename), "%s/%s/temperature", - dirname_procfs, name); + len = snprintf(filename, sizeof(filename), "%s/%s/temperature", + dirname_procfs, name); if ((len < 0) || ((size_t)len >= sizeof(filename))) return -1; diff --git a/src/threshold.c b/src/threshold.c index 72e922e9..79001334 100644 --- a/src/threshold.c +++ b/src/threshold.c @@ -356,9 +356,9 @@ static int ut_config_host(const threshold_t *th_orig, oconfig_item_t *ci) { return status; } /* int ut_config_host */ - /* - * End of the functions used to configure threshold values. - */ +/* + * End of the functions used to configure threshold values. + */ /* }}} */ /* @@ -424,22 +424,22 @@ static int ut_report_state(const data_set_t *ds, const value_list_t *vl, n.time = vl->time; - status = ssnprintf(buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin); + status = snprintf(buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin); buf += status; bufsize -= status; if (vl->plugin_instance[0] != '\0') { - status = ssnprintf(buf, bufsize, " (instance %s)", vl->plugin_instance); + status = snprintf(buf, bufsize, " (instance %s)", vl->plugin_instance); buf += status; bufsize -= status; } - status = ssnprintf(buf, bufsize, " type %s", vl->type); + status = snprintf(buf, bufsize, " type %s", vl->type); buf += status; bufsize -= status; if (vl->type_instance[0] != '\0') { - status = ssnprintf(buf, bufsize, " (instance %s)", vl->type_instance); + status = snprintf(buf, bufsize, " (instance %s)", vl->type_instance); buf += status; bufsize -= status; } @@ -454,11 +454,11 @@ static int ut_report_state(const data_set_t *ds, const value_list_t *vl, /* Send an okay notification */ if (state == STATE_OKAY) { if (state_old == STATE_MISSING) - ssnprintf(buf, bufsize, ": Value is no longer missing."); + snprintf(buf, bufsize, ": Value is no longer missing."); else - ssnprintf(buf, bufsize, ": All data sources are within range again. " - "Current value of \"%s\" is %f.", - ds->ds[ds_index].name, values[ds_index]); + snprintf(buf, bufsize, ": All data sources are within range again. " + "Current value of \"%s\" is %f.", + ds->ds[ds_index].name, values[ds_index]); } else { double min; double max; @@ -468,21 +468,21 @@ static int ut_report_state(const data_set_t *ds, const value_list_t *vl, if (th->flags & UT_FLAG_INVERT) { if (!isnan(min) && !isnan(max)) { - ssnprintf(buf, bufsize, - ": Data source \"%s\" is currently " - "%f. That is within the %s region of %f%s and %f%s.", - ds->ds[ds_index].name, values[ds_index], - (state == STATE_ERROR) ? "failure" : "warning", min, - ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", max, - ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); + snprintf(buf, bufsize, + ": Data source \"%s\" is currently " + "%f. That is within the %s region of %f%s and %f%s.", + ds->ds[ds_index].name, values[ds_index], + (state == STATE_ERROR) ? "failure" : "warning", min, + ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", max, + ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } else { - ssnprintf(buf, bufsize, ": Data source \"%s\" is currently " - "%f. That is %s the %s threshold of %f%s.", - ds->ds[ds_index].name, values[ds_index], - isnan(min) ? "below" : "above", - (state == STATE_ERROR) ? "failure" : "warning", - isnan(min) ? max : min, - ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); + snprintf(buf, bufsize, ": Data source \"%s\" is currently " + "%f. That is %s the %s threshold of %f%s.", + ds->ds[ds_index].name, values[ds_index], + isnan(min) ? "below" : "above", + (state == STATE_ERROR) ? "failure" : "warning", + isnan(min) ? max : min, + ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : ""); } } else if (th->flags & UT_FLAG_PERCENTAGE) { gauge_t value; @@ -501,21 +501,21 @@ static int ut_report_state(const data_set_t *ds, const value_list_t *vl, else value = 100.0 * values[ds_index] / sum; - ssnprintf(buf, bufsize, - ": Data source \"%s\" is currently " - "%g (%.2f%%). That is %s the %s threshold of %.2f%%.", - ds->ds[ds_index].name, values[ds_index], value, - (value < min) ? "below" : "above", - (state == STATE_ERROR) ? "failure" : "warning", - (value < min) ? min : max); + snprintf(buf, bufsize, + ": Data source \"%s\" is currently " + "%g (%.2f%%). That is %s the %s threshold of %.2f%%.", + ds->ds[ds_index].name, values[ds_index], value, + (value < min) ? "below" : "above", + (state == STATE_ERROR) ? "failure" : "warning", + (value < min) ? min : max); } else /* is not inverted */ { - ssnprintf(buf, bufsize, ": Data source \"%s\" is currently " - "%f. That is %s the %s threshold of %f.", - ds->ds[ds_index].name, values[ds_index], - (values[ds_index] < min) ? "below" : "above", - (state == STATE_ERROR) ? "failure" : "warning", - (values[ds_index] < min) ? min : max); + snprintf(buf, bufsize, ": Data source \"%s\" is currently " + "%f. That is %s the %s threshold of %f.", + ds->ds[ds_index].name, values[ds_index], + (values[ds_index] < min) ? "below" : "above", + (state == STATE_ERROR) ? "failure" : "warning", + (values[ds_index] < min) ? min : max); } } @@ -772,9 +772,9 @@ static int ut_missing(const value_list_t *vl, FORMAT_VL(identifier, sizeof(identifier), vl); NOTIFICATION_INIT_VL(&n, vl); - ssnprintf(n.message, sizeof(n.message), - "%s has not been updated for %.3f seconds.", identifier, - CDTIME_T_TO_DOUBLE(missing_time)); + snprintf(n.message, sizeof(n.message), + "%s has not been updated for %.3f seconds.", identifier, + CDTIME_T_TO_DOUBLE(missing_time)); n.time = now; plugin_dispatch_notification(&n); diff --git a/src/turbostat.c b/src/turbostat.c index 45c8bd70..e4419b85 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 @@ -266,7 +266,7 @@ open_msr(unsigned int cpu, _Bool multiple_read) { } } - ssnprintf(pathname, sizeof(pathname), "/dev/cpu/%d/msr", cpu); + snprintf(pathname, sizeof(pathname), "/dev/cpu/%d/msr", cpu); fd = open(pathname, O_RDONLY); if (fd < 0) { ERROR("turbostat plugin: failed to open %s", pathname); @@ -556,7 +556,7 @@ static int submit_counters(struct thread_data *t, struct core_data *c, DEBUG("turbostat plugin: submit stats for cpu: %d, core: %d, pkg: %d", t->cpu_id, c->core_id, p->package_id); - ssnprintf(name, sizeof(name), "cpu%02d", t->cpu_id); + snprintf(name, sizeof(name), "cpu%02d", t->cpu_id); if (!aperf_mperf_unstable) turbostat_submit(name, "percent", "c0", 100.0 * t->mperf / t->tsc); @@ -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", @@ -585,7 +585,10 @@ static int submit_counters(struct thread_data *t, struct core_data *c, /* If not using logical core numbering, set core id */ if (!config_lcn) { - ssnprintf(name, sizeof(name), "core%02d", c->core_id); + if (topology.num_packages > 1) + snprintf(name, sizeof(name), "pkg%02d-core%02d", p->package_id, c->core_id); + else + snprintf(name, sizeof(name), "core%02d", c->core_id); } if (do_core_cstate & (1 << 3)) @@ -602,7 +605,7 @@ static int submit_counters(struct thread_data *t, struct core_data *c, if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) goto done; - ssnprintf(name, sizeof(name), "pkg%02d", p->package_id); + snprintf(name, sizeof(name), "pkg%02d", p->package_id); if (do_ptm) turbostat_submit(name, "temperature", NULL, p->pkg_temp_c); @@ -1064,8 +1067,8 @@ static int get_threads_on_core(unsigned int cpu) { int matches; char character; - ssnprintf(path, sizeof(path), - "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); + snprintf(path, sizeof(path), + "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); filep = fopen(path, "r"); if (!filep) { ERROR("turbostat plugin: Failed to open '%s'", path); diff --git a/src/types.db b/src/types.db index c9838e16..577d28f1 100644 --- a/src/types.db +++ b/src/types.db @@ -34,6 +34,7 @@ compression_ratio value:GAUGE:0:2 connections value:DERIVE:0:U conntrack value:GAUGE:0:4294967295 contextswitch value:DERIVE:0:U +cookies value:DERIVE:0:U count value:GAUGE:0:U counter value:COUNTER:U:U cpu value:DERIVE:0:U @@ -117,6 +118,7 @@ if_tx_octets value:DERIVE:0:U if_tx_packets value:DERIVE:0:U invocations value:DERIVE:0:U io_octets rx:DERIVE:0:U, tx:DERIVE:0:U +io_ops read:DERIVE:0:U, write:DERIVE:0:U io_packets rx:DERIVE:0:U, tx:DERIVE:0:U ipc value:GAUGE:0:U ipt_bytes value:DERIVE:0:U @@ -189,6 +191,7 @@ ping value:GAUGE:0:65535 ping_droprate value:GAUGE:0:100 ping_stddev value:GAUGE:0:65535 players value:GAUGE:0:1000000 +pools value:GAUGE:0:U power value:GAUGE:U:U pressure value:GAUGE:0:U protocol_counter value:DERIVE:0:U diff --git a/src/uptime.c b/src/uptime.c index 2be9d79d..d51aa391 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -25,8 +25,7 @@ #include "plugin.h" #if KERNEL_LINUX -#define STAT_FILE "/proc/stat" -/* Using /proc filesystem to retrieve the boot time, Linux only. */ +#include /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT @@ -53,8 +52,6 @@ /* * Global variables */ -/* boottime always used, no OS distinction */ -static time_t boottime; #if HAVE_LIBKSTAT extern kstat_ctl_t *kc; @@ -72,8 +69,6 @@ static void uptime_submit(gauge_t value) { plugin_dispatch_values(&vl); } -static int uptime_init(void) /* {{{ */ -{ /* * On most unix systems the uptime is calculated by looking at the boot * time (stored in unix time, since epoch) and the current one. We are @@ -84,48 +79,21 @@ static int uptime_init(void) /* {{{ */ * the boot time, the plugin is unregistered and there is no chance to * try again later. Nevertheless, this is very unlikely to happen. */ - +static time_t uptime_get_sys(void) { /* {{{ */ + time_t result; #if KERNEL_LINUX - unsigned long starttime; - char buffer[1024]; - int ret; - FILE *fh; - - ret = 0; - - fh = fopen(STAT_FILE, "r"); + struct sysinfo info; + int status; - if (fh == NULL) { + status = sysinfo(&info); + if (status != 0) { char errbuf[1024]; - ERROR("uptime plugin: Cannot open " STAT_FILE ": %s", + ERROR("uptime plugin: Error calling sysinfo: %s", sstrerror(errno, errbuf, sizeof(errbuf))); return -1; } - while (fgets(buffer, 1024, fh) != NULL) { - /* look for the btime string and read the value */ - ret = sscanf(buffer, "btime %lu", &starttime); - /* avoid further loops if btime has been found and read - * correctly (hopefully) */ - if (ret == 1) - break; - } - - fclose(fh); - - /* loop done, check if no value has been found/read */ - if (ret != 1) { - ERROR("uptime plugin: No value read from " STAT_FILE ""); - return -1; - } - - boottime = (time_t)starttime; - - if (boottime == 0) { - ERROR("uptime plugin: btime read from " STAT_FILE ", " - "but `boottime' is zero!"); - return -1; - } + result = (time_t)info.uptime; /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT @@ -159,13 +127,13 @@ static int uptime_init(void) /* {{{ */ return -1; } - boottime = (time_t)knp->value.ui32; - - if (boottime == 0) { + if (knp->value.ui32 == 0) { ERROR("uptime plugin: kstat_data_lookup returned success, " "but `boottime' is zero!"); return -1; } + + result = time(NULL) - (time_t)knp->value.ui32; /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYS_SYSCTL_H @@ -186,13 +154,13 @@ static int uptime_init(void) /* {{{ */ return -1; } - boottime = boottv.tv_sec; - - if (boottime == 0) { + if (boottv.tv_sec == 0) { ERROR("uptime plugin: sysctl(3) returned success, " "but `boottime' is zero!"); return -1; } + + result = time(NULL) - boottv.tv_sec; /* #endif HAVE_SYS_SYSCTL_H */ #elif HAVE_PERFSTAT @@ -212,18 +180,18 @@ static int uptime_init(void) /* {{{ */ if (hertz <= 0) hertz = HZ; - boottime = time(NULL) - cputotal.lbolt / hertz; + result = cputotal.lbolt / hertz; #endif /* HAVE_PERFSTAT */ - return 0; -} /* }}} int uptime_init */ + return result; +} /* }}} int uptime_get_sys */ static int uptime_read(void) { gauge_t uptime; time_t elapsed; /* calculate the amount of time elapsed since boot, AKA uptime */ - elapsed = time(NULL) - boottime; + elapsed = uptime_get_sys(); uptime = (gauge_t)elapsed; @@ -233,6 +201,5 @@ static int uptime_read(void) { } void module_register(void) { - plugin_register_init("uptime", uptime_init); plugin_register_read("uptime", uptime_read); } /* void module_register */ diff --git a/src/utils_cmd_putval.c b/src/utils_cmd_putval.c index 718425b0..6f1bc39e 100644 --- a/src/utils_cmd_putval.c +++ b/src/utils_cmd_putval.c @@ -276,10 +276,10 @@ int cmd_create_putval(char *ret, size_t ret_len, /* {{{ */ return status; escape_string(buffer_values, sizeof(buffer_values)); - ssnprintf(ret, ret_len, "PUTVAL %s interval=%.3f %s", buffer_ident, - (vl->interval > 0) ? CDTIME_T_TO_DOUBLE(vl->interval) - : CDTIME_T_TO_DOUBLE(plugin_get_interval()), - buffer_values); + snprintf(ret, ret_len, "PUTVAL %s interval=%.3f %s", buffer_ident, + (vl->interval > 0) ? CDTIME_T_TO_DOUBLE(vl->interval) + : CDTIME_T_TO_DOUBLE(plugin_get_interval()), + buffer_values); return 0; } /* }}} int cmd_create_putval */ diff --git a/src/utils_cmds.c b/src/utils_cmds.c index 97702251..055c987c 100644 --- a/src/utils_cmds.c +++ b/src/utils_cmds.c @@ -26,12 +26,12 @@ * Sebastian 'tokkee' Harl **/ +#include "utils_cmds.h" #include "daemon/common.h" #include "utils_cmd_flush.h" #include "utils_cmd_getval.h" #include "utils_cmd_listval.h" #include "utils_cmd_putval.h" -#include "utils_cmds.h" #include "utils_parse_option.h" #include diff --git a/src/utils_curl_stats.c b/src/utils_curl_stats.c index 2a426646..2a1d9de3 100644 --- a/src/utils_curl_stats.c +++ b/src/utils_curl_stats.c @@ -218,15 +218,15 @@ int curl_stats_dispatch(curl_stats_t *s, CURL *curl, const char *hostname, if (s == NULL) return 0; - if ((curl == NULL) || (hostname == NULL) || (plugin == NULL)) { + if ((curl == NULL) || (plugin == NULL)) { ERROR("curl stats: dispatch() called with missing arguments " - "(curl=%p; hostname=%s; plugin=%s)", - curl, hostname == NULL ? "" : hostname, - plugin == NULL ? "" : plugin); + "(curl=%p; plugin=%s)", + curl, plugin == NULL ? "" : plugin); return -1; } - sstrncpy(vl.host, hostname, sizeof(vl.host)); + if (hostname != NULL) + sstrncpy(vl.host, hostname, sizeof(vl.host)); sstrncpy(vl.plugin, plugin, sizeof(vl.plugin)); if (plugin_instance != NULL) sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); diff --git a/src/utils_dns.c b/src/utils_dns.c index 37fa930f..e7e04f7c 100644 --- a/src/utils_dns.c +++ b/src/utils_dns.c @@ -912,7 +912,7 @@ const char *qtype_str(int t) { return "ANY"; /* ... 255 */ #endif /* __BIND >= 19950621 */ default: - ssnprintf(buf, sizeof(buf), "#%i", t); + snprintf(buf, sizeof(buf), "#%i", t); return buf; } /* switch (t) */ } @@ -931,7 +931,7 @@ const char *opcode_str(int o) { case 5: return "Update"; default: - ssnprintf(buf, sizeof(buf), "Opcode%d", o); + snprintf(buf, sizeof(buf), "Opcode%d", o); return buf; } } @@ -998,7 +998,7 @@ const char *rcode_str(int rcode) { #endif /* RFC2136 rcodes */ #endif /* __BIND >= 19950621 */ default: - ssnprintf(buf, sizeof(buf), "RCode%i", rcode); + snprintf(buf, sizeof(buf), "RCode%i", rcode); return buf; } } /* const char *rcode_str (int rcode) */ diff --git a/src/utils_dpdk.c b/src/utils_dpdk.c index 4f9243ea..77f596eb 100644 --- a/src/utils_dpdk.c +++ b/src/utils_dpdk.c @@ -103,10 +103,10 @@ static void dpdk_helper_config_default(dpdk_helper_ctx_t *phc) { DPDK_HELPER_TRACE(phc->shm_name); - ssnprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf"); - ssnprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1"); - ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s", - DPDK_DEFAULT_RTE_CONFIG); + snprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf"); + snprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1"); + snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s", + DPDK_DEFAULT_RTE_CONFIG); } int dpdk_helper_eal_config_set(dpdk_helper_ctx_t *phc, dpdk_eal_config_t *ec) { @@ -181,7 +181,7 @@ int dpdk_helper_eal_config_parse(dpdk_helper_ctx_t *phc, oconfig_item_t *ci) { status = cf_util_get_string_buffer(child, prefix, sizeof(prefix)); if (status == 0) { - ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, + snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "/var/run/.%s_config", prefix); DEBUG("dpdk_common: EAL:File prefix %s", phc->eal_config.file_prefix); } diff --git a/src/utils_format_graphite.c b/src/utils_format_graphite.c index f124ba10..87cead14 100644 --- a/src/utils_format_graphite.c +++ b/src/utils_format_graphite.c @@ -46,7 +46,7 @@ static int gr_format_values(char *ret, size_t ret_len, int ds_num, #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ + status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ if (status < 1) { \ return -1; \ } else if (((size_t)status) >= (ret_len - offset)) { \ @@ -131,9 +131,9 @@ static int gr_format_name(char *ret, int ret_len, value_list_t const *vl, sizeof(n_type_instance), escape_char, preserve_separator); if (n_plugin_instance[0] != '\0') - ssnprintf(tmp_plugin, sizeof(tmp_plugin), "%s%c%s", n_plugin, - (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-', - n_plugin_instance); + snprintf(tmp_plugin, sizeof(tmp_plugin), "%s%c%s", n_plugin, + (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-', + n_plugin_instance); else sstrncpy(tmp_plugin, n_plugin, sizeof(tmp_plugin)); @@ -141,9 +141,9 @@ static int gr_format_name(char *ret, int ret_len, value_list_t const *vl, if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(n_plugin, n_type) == 0) sstrncpy(tmp_type, n_type_instance, sizeof(tmp_type)); else - ssnprintf(tmp_type, sizeof(tmp_type), "%s%c%s", n_type, - (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-', - n_type_instance); + snprintf(tmp_type, sizeof(tmp_type), "%s%c%s", n_type, + (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-', + n_type_instance); } else sstrncpy(tmp_type, n_type, sizeof(tmp_type)); @@ -152,14 +152,14 @@ static int gr_format_name(char *ret, int ret_len, value_list_t const *vl, if (ds_name != NULL) { if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(tmp_plugin, tmp_type) == 0) - ssnprintf(ret, ret_len, "%s%s%s.%s.%s", prefix, n_host, postfix, - tmp_plugin, ds_name); + snprintf(ret, ret_len, "%s%s%s.%s.%s", prefix, n_host, postfix, + tmp_plugin, ds_name); else - ssnprintf(ret, ret_len, "%s%s%s.%s.%s.%s", prefix, n_host, postfix, - tmp_plugin, tmp_type, ds_name); + snprintf(ret, ret_len, "%s%s%s.%s.%s.%s", prefix, n_host, postfix, + tmp_plugin, tmp_type, ds_name); } else - ssnprintf(ret, ret_len, "%s%s%s.%s.%s", prefix, n_host, postfix, tmp_plugin, - tmp_type); + snprintf(ret, ret_len, "%s%s%s.%s.%s", prefix, n_host, postfix, tmp_plugin, + tmp_type); return 0; } @@ -219,8 +219,8 @@ int format_graphite(char *buffer, size_t buffer_size, data_set_t const *ds, /* Compute the graphite command */ message_len = - (size_t)ssnprintf(message, sizeof(message), "%s %s %u\r\n", key, values, - (unsigned int)CDTIME_T_TO_TIME_T(vl->time)); + (size_t)snprintf(message, sizeof(message), "%s %s %u\r\n", key, values, + (unsigned int)CDTIME_T_TO_TIME_T(vl->time)); if (message_len >= sizeof(message)) { ERROR("format_graphite: message buffer too small: " "Need %zu bytes.", diff --git a/src/utils_format_json.c b/src/utils_format_json.c index 67aebbaf..53a38b89 100644 --- a/src/utils_format_json.c +++ b/src/utils_format_json.c @@ -95,7 +95,7 @@ static int values_to_json(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ int status; \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) { \ sfree(rates); \ return -1; \ @@ -159,7 +159,7 @@ static int dstypes_to_json(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ int status; \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (buffer_size - offset)) \ @@ -193,7 +193,7 @@ static int dsnames_to_json(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ int status; \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (buffer_size - offset)) \ @@ -228,7 +228,7 @@ static int meta_data_keys_to_json(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (buffer_size - offset)) \ @@ -318,7 +318,7 @@ static int value_list_to_json(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (buffer_size - offset)) \ @@ -577,11 +577,12 @@ 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"); diff --git a/src/utils_format_kairosdb.c b/src/utils_format_kairosdb.c index 4378d7ff..0128c575 100644 --- a/src/utils_format_kairosdb.c +++ b/src/utils_format_kairosdb.c @@ -103,7 +103,7 @@ static int values_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ int status; \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) { \ sfree(rates); \ return -1; \ @@ -192,7 +192,7 @@ static int value_list_to_kairosdb(char *buffer, size_t buffer_size, /* {{{ */ #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ + status = snprintf(buffer + offset, buffer_size - offset, __VA_ARGS__); \ if (status < 1) \ return -1; \ else if (((size_t)status) >= (buffer_size - offset)) \ @@ -345,12 +345,9 @@ int format_kairosdb_value_list(char *buffer, /* {{{ */ if (*ret_buffer_free < 3) return -ENOMEM; - return format_kairosdb_value_list_nocheck(buffer, ret_buffer_fill, - ret_buffer_free, ds, vl, - store_rates, - (*ret_buffer_free) - 2, - http_attrs, http_attrs_num, - data_ttl); + return format_kairosdb_value_list_nocheck( + buffer, ret_buffer_fill, ret_buffer_free, ds, vl, store_rates, + (*ret_buffer_free) - 2, http_attrs, http_attrs_num, data_ttl); } /* }}} int format_kairosdb_value_list */ /* vim: set sw=2 sts=2 et fdm=marker : */ diff --git a/src/utils_latency_config.c b/src/utils_latency_config.c index d0832cbc..5eb5b6d9 100644 --- a/src/utils_latency_config.c +++ b/src/utils_latency_config.c @@ -25,8 +25,8 @@ * Pavel Rochnyack */ -#include "common.h" #include "utils_latency_config.h" +#include "common.h" #include "collectd.h" static int latency_config_add_percentile(latency_config_t *conf, @@ -105,6 +105,8 @@ int latency_config(latency_config_t *conf, oconfig_item_t *ci, status = latency_config_add_percentile(conf, child, plugin); else if (strcasecmp("Bucket", child->key) == 0) status = latency_config_add_bucket(conf, child, plugin); + else if (strcasecmp("BucketType", child->key) == 0) + status = cf_util_get_string(child, &conf->bucket_type); else WARNING("%s plugin: \"%s\" is not a valid option within a \"%s\" block.", plugin, child->key, ci->key); @@ -137,6 +139,14 @@ int latency_config_copy(latency_config_t *dst, const latency_config_t src) { return ENOMEM; } + if (src.bucket_type != NULL) { + dst->bucket_type = strdup(src.bucket_type); + if (dst->bucket_type == NULL) { + latency_config_free(*dst); + return ENOMEM; + } + } + memmove(dst->percentile, src.percentile, dst->percentile_num * sizeof(*dst->percentile)); memmove(dst->buckets, src.buckets, dst->buckets_num * sizeof(*dst->buckets)); @@ -147,4 +157,5 @@ int latency_config_copy(latency_config_t *dst, const latency_config_t src) { void latency_config_free(latency_config_t conf) { sfree(conf.percentile); sfree(conf.buckets); + sfree(conf.bucket_type); } /* void latency_config_free */ diff --git a/src/utils_latency_config.h b/src/utils_latency_config.h index 9a7a11af..7008fd00 100644 --- a/src/utils_latency_config.h +++ b/src/utils_latency_config.h @@ -44,6 +44,7 @@ typedef struct { latency_bucket_t *buckets; size_t buckets_num; + char *bucket_type; /* _Bool lower; diff --git a/src/utils_lua.c b/src/utils_lua.c index 4e570ff3..0990472b 100644 --- a/src/utils_lua.c +++ b/src/utils_lua.c @@ -28,8 +28,8 @@ * GCC will complain about the macro definition. */ #define DONT_POISON_SPRINTF_YET -#include "common.h" #include "utils_lua.h" +#include "common.h" static int ltoc_values(lua_State *L, /* {{{ */ const data_set_t *ds, value_t *ret_values) { diff --git a/src/utils_match.c b/src/utils_match.c index df70fbec..d3edb57c 100644 --- a/src/utils_match.c +++ b/src/utils_match.c @@ -294,7 +294,7 @@ void match_value_reset(cu_match_value_t *mv) { /* Reset GAUGE metrics only and except GAUGE_PERSIST. */ if ((mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) && !(mv->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) { - mv->value.gauge = NAN; + mv->value.gauge = (mv->ds_type & UTILS_MATCH_CF_GAUGE_INC) ? 0 : NAN; mv->values_num = 0; } } /* }}} void match_value_reset */ diff --git a/src/utils_mount.c b/src/utils_mount.c index bbc4c209..3d57ca64 100644 --- a/src/utils_mount.c +++ b/src/utils_mount.c @@ -258,7 +258,7 @@ static void uuidcache_init(void) { * (This is useful, if the cdrom on /dev/hdc must not * be accessed.) */ - ssnprintf(device, sizeof(device), "%s/%s", DEVLABELDIR, ptname); + snprintf(device, sizeof(device), "%s/%s", DEVLABELDIR, ptname); if (!get_label_uuid(device, &label, uuid)) { uuidcache_addentry(sstrdup(device), label, uuid); } @@ -527,7 +527,7 @@ static cu_mount_t *cu_mount_gen_getmntent(void) { return first; } /* static cu_mount_t *cu_mount_gen_getmntent (void) */ -/* #endif HAVE_TWO_GETMNTENT || HAVE_GEN_GETMNTENT || HAVE_SUN_GETMNTENT */ + /* #endif HAVE_TWO_GETMNTENT || HAVE_GEN_GETMNTENT || HAVE_SUN_GETMNTENT */ #elif HAVE_SEQ_GETMNTENT #warn "This version of `getmntent' hat not yet been implemented!" diff --git a/src/utils_ovs.c b/src/utils_ovs.c index 2f7baea0..20873247 100644 --- a/src/utils_ovs.c +++ b/src/utils_ovs.c @@ -3,14 +3,17 @@ * * Copyright(c) 2016 Intel Corporation. All rights reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a copy of + * Permission is hereby granted, free of charge, to any person obtaining a copy + *of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do + * of the Software, and to permit persons to whom the Software is furnished to + *do * so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all + * The above copyright notice and this permission notice shall be included in + *all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -314,8 +317,7 @@ static int ovs_db_data_send(const ovs_db_t *pdb, const char *data, size_t len) { */ static yajl_gen_status ovs_yajl_gen_tstring(yajl_gen hander, const char *string) { - return yajl_gen_string(hander, (const unsigned char *)string, - strlen(string)); + return yajl_gen_string(hander, (const unsigned char *)string, strlen(string)); } /* Add YAJL value into YAJL generator handle (JSON object) @@ -1091,7 +1093,7 @@ int ovs_db_send_request(ovs_db_t *pdb, const char *method, const char *params, /* generate id field */ OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "id"); uid = ovs_uid_generate(); - ssnprintf(uid_buff, sizeof(uid_buff), "%" PRIX64, uid); + snprintf(uid_buff, sizeof(uid_buff), "%" PRIX64, uid); OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_buff); OVS_YAJL_CALL(yajl_gen_map_close, jgen); @@ -1177,7 +1179,7 @@ int ovs_db_table_cb_register(ovs_db_t *pdb, const char *tb_name, OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, OVS_DB_DEFAULT_DB_NAME); /* uid string */ - ssnprintf(uid_str, sizeof(uid_str), "%" PRIX64, new_cb->uid); + snprintf(uid_str, sizeof(uid_str), "%" PRIX64, new_cb->uid); OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_str); /* */ diff --git a/src/utils_rrdcreate.c b/src/utils_rrdcreate.c index 86f7f3fb..6cb54463 100644 --- a/src/utils_rrdcreate.c +++ b/src/utils_rrdcreate.c @@ -208,8 +208,8 @@ static int rra_get(char ***ret, const value_list_t *vl, /* {{{ */ if (rra_num >= rra_max) break; - status = ssnprintf(buffer, sizeof(buffer), "RRA:%s:%.10f:%u:%u", - rra_types[j], cfg->xff, cdp_len, cdp_num); + status = snprintf(buffer, sizeof(buffer), "RRA:%s:%.10f:%u:%u", + rra_types[j], cfg->xff, cdp_len, cdp_num); if ((status < 0) || ((size_t)status >= sizeof(buffer))) { ERROR("rra_get: Buffer would have been truncated."); @@ -280,18 +280,18 @@ static int ds_get(char ***ret, /* {{{ */ if (isnan(d->min)) { sstrncpy(min, "U", sizeof(min)); } else - ssnprintf(min, sizeof(min), "%f", d->min); + snprintf(min, sizeof(min), "%f", d->min); if (isnan(d->max)) { sstrncpy(max, "U", sizeof(max)); } else - ssnprintf(max, sizeof(max), "%f", d->max); + snprintf(max, sizeof(max), "%f", d->max); - status = ssnprintf(buffer, sizeof(buffer), "DS:%s:%s:%i:%s:%s", d->name, - type, (cfg->heartbeat > 0) - ? cfg->heartbeat - : (int)CDTIME_T_TO_TIME_T(2 * vl->interval), - min, max); + status = snprintf( + buffer, sizeof(buffer), "DS:%s:%s:%i:%s:%s", d->name, type, + (cfg->heartbeat > 0) ? cfg->heartbeat + : (int)CDTIME_T_TO_TIME_T(2 * vl->interval), + min, max); if ((status < 1) || ((size_t)status >= sizeof(buffer))) break; @@ -369,8 +369,8 @@ static int srrd_create(const char *filename, /* {{{ */ if (last_up == 0) last_up = time(NULL) - 10; - ssnprintf(pdp_step_str, sizeof(pdp_step_str), "%lu", pdp_step); - ssnprintf(last_up_str, sizeof(last_up_str), "%lu", (unsigned long)last_up); + snprintf(pdp_step_str, sizeof(pdp_step_str), "%lu", pdp_step); + snprintf(last_up_str, sizeof(last_up_str), "%lu", (unsigned long)last_up); new_argv[0] = "create"; new_argv[1] = (void *)filename; @@ -497,7 +497,7 @@ static void *srrd_create_thread(void *targs) /* {{{ */ return 0; } - ssnprintf(tmpfile, sizeof(tmpfile), "%s.async", args->filename); + snprintf(tmpfile, sizeof(tmpfile), "%s.async", args->filename); status = srrd_create(tmpfile, args->pdp_step, args->last_up, args->argc, (void *)args->argv); diff --git a/src/utils_tail_match.c b/src/utils_tail_match.c index f046f6b1..65655dcd 100644 --- a/src/utils_tail_match.c +++ b/src/utils_tail_match.c @@ -108,7 +108,6 @@ static int latency_submit_match(cu_match_t *match, void *user_data) { if (match_value == NULL) return -1; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin)); sstrncpy(vl.plugin_instance, data->plugin_instance, sizeof(vl.plugin_instance)); @@ -119,11 +118,11 @@ static int latency_submit_match(cu_match_t *match, void *user_data) { sstrncpy(vl.type, data->type, sizeof(vl.type)); for (size_t i = 0; i < data->latency_config.percentile_num; i++) { if (strlen(data->type_instance) != 0) - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%.0f", - data->type_instance, data->latency_config.percentile[i]); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%.0f", + data->type_instance, data->latency_config.percentile[i]); else - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%.0f", - data->latency_config.percentile[i]); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%.0f", + data->latency_config.percentile[i]); vl.values = &(value_t){ .gauge = @@ -138,7 +137,11 @@ static int latency_submit_match(cu_match_t *match, void *user_data) { } /* Submit buckets */ - sstrncpy(vl.type, "bucket", sizeof(vl.type)); + if (data->latency_config.bucket_type != NULL) + sstrncpy(vl.type, data->latency_config.bucket_type, sizeof(vl.type)); + else + sstrncpy(vl.type, "bucket", sizeof(vl.type)); + for (size_t i = 0; i < data->latency_config.buckets_num; i++) { latency_bucket_t bucket = data->latency_config.buckets[i]; @@ -147,11 +150,11 @@ static int latency_submit_match(cu_match_t *match, void *user_data) { bucket.upper_bound ? CDTIME_T_TO_DOUBLE(bucket.upper_bound) : INFINITY; if (strlen(data->type_instance) != 0) - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s-%g_%g", - data->type, data->type_instance, lower_bound, upper_bound); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s-%g_%g", + data->type, data->type_instance, lower_bound, upper_bound); else - ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%g_%g", - data->type, lower_bound, upper_bound); + snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%g_%g", + data->type, lower_bound, upper_bound); vl.values = &(value_t){ .gauge = diff --git a/src/varnish.c b/src/varnish.c index 1a71d8ce..910d1e77 100644 --- a/src/varnish.c +++ b/src/varnish.c @@ -21,6 +21,7 @@ * Jérôme Renard * Marc Fournier * Florian octo Forster + * Denes Matetelki **/ #include "collectd.h" @@ -69,6 +70,8 @@ struct user_config_s { _Bool collect_sms; #if HAVE_VARNISH_V2 _Bool collect_sm; +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 _Bool collect_sma; #endif _Bool collect_struct; @@ -80,6 +83,11 @@ struct user_config_s { _Bool collect_workers; #if HAVE_VARNISH_V4 _Bool collect_vsm; + _Bool collect_lck; + _Bool collect_mempool; + _Bool collect_mgt; + _Bool collect_smf; + _Bool collect_vbe; #endif }; typedef struct user_config_s user_config_t; /* }}} */ @@ -98,8 +106,8 @@ static int varnish_submit(const char *plugin_instance, /* {{{ */ if (plugin_instance == NULL) plugin_instance = "default"; - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", - plugin_instance, category); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", + plugin_instance, category); sstrncpy(vl.type, type, sizeof(vl.type)); @@ -113,18 +121,20 @@ static int varnish_submit_gauge(const char *plugin_instance, /* {{{ */ const char *category, const char *type, const char *type_instance, uint64_t gauge_value) { - return varnish_submit(plugin_instance, category, type, type_instance, (value_t){ - .gauge=(gauge_t)gauge_value, - }); + return varnish_submit(plugin_instance, category, type, type_instance, + (value_t){ + .gauge = (gauge_t)gauge_value, + }); } /* }}} int varnish_submit_gauge */ static int varnish_submit_derive(const char *plugin_instance, /* {{{ */ const char *category, const char *type, const char *type_instance, uint64_t derive_value) { - return varnish_submit(plugin_instance, category, type, type_instance, (value_t){ - .derive=(derive_t)derive_value, - }); + return varnish_submit(plugin_instance, category, type, type_instance, + (value_t){ + .derive = (derive_t)derive_value, + }); } /* }}} int varnish_submit_derive */ #if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 @@ -172,21 +182,29 @@ static int varnish_monitor(void *priv, if (conf->collect_connections) { if (strcmp(name, "client_conn") == 0) - return varnish_submit_derive(conf->instance, "connections", - "connections", "accepted", val); + return varnish_submit_derive(conf->instance, "connections", "connections", + "accepted", val); else if (strcmp(name, "client_drop") == 0) - return varnish_submit_derive(conf->instance, "connections", - "connections", "dropped", val); + return varnish_submit_derive(conf->instance, "connections", "connections", + "dropped", val); else if (strcmp(name, "client_req") == 0) - return varnish_submit_derive(conf->instance, "connections", - "connections", "received", val); + return varnish_submit_derive(conf->instance, "connections", "connections", + "received", val); +#ifdef HAVE_VARNISH_V4 + else if (strcmp(name, "client_req_400") == 0) + return varnish_submit_derive(conf->instance, "connections", "connections", + "error_400", val); + else if (strcmp(name, "client_req_417") == 0) + return varnish_submit_derive(conf->instance, "connections", "connections", + "error_417", val); +#endif } #ifdef HAVE_VARNISH_V3 if (conf->collect_dirdns) { if (strcmp(name, "dir_dns_lookups") == 0) - return varnish_submit_derive(conf->instance, "dirdns", - "cache_operation", "lookups", val); + return varnish_submit_derive(conf->instance, "dirdns", "cache_operation", + "lookups", val); else if (strcmp(name, "dir_dns_failed") == 0) return varnish_submit_derive(conf->instance, "dirdns", "cache_result", "failed", val); @@ -284,6 +302,20 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "fetch_304") == 0) return varnish_submit_derive(conf->instance, "fetch", "http_requests", "no_body_304", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "fetch_no_thread") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "no_thread", val); + else if (strcmp(name, "fetch_none") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "none", val); + else if (strcmp(name, "busy_sleep") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "busy_sleep", val); + else if (strcmp(name, "busy_wakeup") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "busy_wakeup", val); +#endif } if (conf->collect_hcb) { @@ -329,6 +361,14 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "n_objoverflow") == 0) return varnish_submit_derive(conf->instance, "objects", "total_objects", "workspace_overflow", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "exp_mailed") == 0) + return varnish_submit_derive(conf->instance, "struct", "objects", + "exp_mailed", val); + else if (strcmp(name, "exp_received") == 0) + return varnish_submit_derive(conf->instance, "struct", "objects", + "exp_received", val); +#endif } #if HAVE_VARNISH_V3 @@ -379,6 +419,34 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "bans_dups") == 0) return varnish_submit_derive(conf->instance, "ban", "total_operations", "duplicate", val); + else if (strcmp(name, "bans_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "tested", val); + else if (strcmp(name, "bans_lurker_contention") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_contention", val); + else if (strcmp(name, "bans_lurker_obj_killed") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_obj_killed", val); + else if (strcmp(name, "bans_lurker_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_tested", val); + else if (strcmp(name, "bans_lurker_tests_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_tests_tested", val); + else if (strcmp(name, "bans_obj_killed") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "obj_killed", val); + else if (strcmp(name, "bans_persisted_bytes") == 0) + return varnish_submit_gauge(conf->instance, "ban", "total_bytes", + "persisted_bytes", val); + else if (strcmp(name, "bans_persisted_fragmentation") == 0) + return varnish_submit_gauge(conf->instance, "ban", "total_bytes", + "persisted_fragmentation", val); + else if (strcmp(name, "bans_tests_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "tests_tested", val); + } #endif @@ -413,6 +481,14 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "sess_herd") == 0) return varnish_submit_derive(conf->instance, "session", "total_operations", "herd", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "sess_closed_err") == 0) + return varnish_submit_derive(conf->instance, "session", + "total_operations", "closed_err", val); + else if (strcmp(name, "sess_dropped") == 0) + return varnish_submit_derive(conf->instance, "session", + "total_operations", "dropped_for_thread", val); +#endif } if (conf->collect_shm) { @@ -441,26 +517,26 @@ static int varnish_monitor(void *priv, return varnish_submit_gauge(conf->instance, "sms", "requests", "outstanding", val); else if (strcmp(name, "sms_nbytes") == 0) - return varnish_submit_gauge(conf->instance, "sms", "bytes", - "outstanding", val); + return varnish_submit_gauge(conf->instance, "sms", "bytes", "outstanding", + val); else if (strcmp(name, "sms_balloc") == 0) return varnish_submit_derive(conf->instance, "sms", "total_bytes", "allocated", val); else if (strcmp(name, "sms_bfree") == 0) - return varnish_submit_derive(conf->instance, "sms", "total_bytes", - "free", val); + return varnish_submit_derive(conf->instance, "sms", "total_bytes", "free", + val); } if (conf->collect_struct) { if (strcmp(name, "n_sess_mem") == 0) - return varnish_submit_gauge(conf->instance, "struct", - "current_sessions", "sess_mem", val); + return varnish_submit_gauge(conf->instance, "struct", "current_sessions", + "sess_mem", val); else if (strcmp(name, "n_sess") == 0) - return varnish_submit_gauge(conf->instance, "struct", - "current_sessions", "sess", val); + return varnish_submit_gauge(conf->instance, "struct", "current_sessions", + "sess", val); else if (strcmp(name, "n_object") == 0) - return varnish_submit_gauge(conf->instance, "struct", "objects", - "object", val); + return varnish_submit_gauge(conf->instance, "struct", "objects", "object", + val); else if (strcmp(name, "n_vampireobject") == 0) return varnish_submit_gauge(conf->instance, "struct", "objects", "vampireobject", val); @@ -495,14 +571,14 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "totals", "total_requests", "requests", val); else if (strcmp(name, "s_pipe") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "pipe", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "pipe", val); else if (strcmp(name, "s_pass") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "pass", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "pass", val); else if (strcmp(name, "s_fetch") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "fetches", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "fetches", val); else if (strcmp(name, "s_synth") == 0) return varnish_submit_derive(conf->instance, "totals", "total_bytes", "synth", val); @@ -528,8 +604,8 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "totals", "total_bytes", "pipe_out", val); else if (strcmp(name, "n_purges") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "purges", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "purges", val); else if (strcmp(name, "s_hdrbytes") == 0) return varnish_submit_derive(conf->instance, "totals", "total_bytes", "header-bytes", val); @@ -537,11 +613,11 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "totals", "total_bytes", "body-bytes", val); else if (strcmp(name, "n_gzip") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "gzip", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "gzip", val); else if (strcmp(name, "n_gunzip") == 0) - return varnish_submit_derive(conf->instance, "totals", - "total_operations", "gunzip", val); + return varnish_submit_derive(conf->instance, "totals", "total_operations", + "gunzip", val); } if (conf->collect_uptime) { @@ -558,8 +634,8 @@ static int varnish_monitor(void *priv, return varnish_submit_gauge(conf->instance, "vcl", "vcl", "avail_vcl", val); else if (strcmp(name, "n_vcl_discard") == 0) - return varnish_submit_gauge(conf->instance, "vcl", "vcl", - "discarded_vcl", val); + return varnish_submit_gauge(conf->instance, "vcl", "vcl", "discarded_vcl", + val); else if (strcmp(name, "vmods") == 0) return varnish_submit_gauge(conf->instance, "vcl", "objects", "vmod", val); @@ -600,17 +676,26 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "workers", "total_threads", "dropped", val); else if (strcmp(name, "n_wrk_queue") == 0) - return varnish_submit_derive(conf->instance, "workers", - "total_requests", "queued", val); + return varnish_submit_derive(conf->instance, "workers", "total_requests", + "queued", val); else if (strcmp(name, "n_wrk_overflow") == 0) - return varnish_submit_derive(conf->instance, "workers", - "total_requests", "overflowed", val); + return varnish_submit_derive(conf->instance, "workers", "total_requests", + "overflowed", val); else if (strcmp(name, "n_wrk_queued") == 0) - return varnish_submit_derive(conf->instance, "workers", - "total_requests", "queued", val); + return varnish_submit_derive(conf->instance, "workers", "total_requests", + "queued", val); else if (strcmp(name, "n_wrk_lqueue") == 0) - return varnish_submit_derive(conf->instance, "workers", - "total_requests", "queue_length", val); + return varnish_submit_derive(conf->instance, "workers", "total_requests", + "queue_length", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "pools") == 0) + return varnish_submit_gauge(conf->instance, "workers", "pools", + "pools", val); + else if (strcmp(name, "busy_killed") == 0) + return varnish_submit_derive(conf->instance, "workers", "http_requests", + "busy_killed", val); + +#endif } #if HAVE_VARNISH_V4 @@ -629,6 +714,159 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "vsm", "total_bytes", "overflowed", val); } + + if (conf->collect_vbe) { + /* @TODO figure out the collectd type for bitmap + if (strcmp(name, "happy") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "bitmap", "happy_hprobes", val); + */ + if (strcmp(name, "bereq_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "bereq_hdrbytes", val); + else if (strcmp(name, "bereq_bodybytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "bereq_bodybytes", val); + else if (strcmp(name, "beresp_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "beresp_hdrbytes", val); + else if (strcmp(name, "beresp_bodybytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "beresp_bodybytes", val); + else if (strcmp(name, "pipe_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_hdrbytes", val); + else if (strcmp(name, "pipe_out") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_out", val); + else if (strcmp(name, "pipe_in") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_in", val); + else if (strcmp(name, "conn") == 0) + return varnish_submit_derive(conf->instance, "vbe", "connections", + "c_conns", val); + else if (strcmp(name, "req") == 0) + return varnish_submit_gauge(conf->instance, "vbe", "http_requests", + "b_reqs", val); + } + + /* All Stevedores support these counters */ + if (conf->collect_sma || conf->collect_smf) { + + char category[4]; + if (conf->collect_sma) + strncpy(category, "sma", 4); + else + strncpy(category, "smf", 4); + + if (strcmp(name, "c_req") == 0) + return varnish_submit_derive(conf->instance, category, + "total_operations", "alloc_req", val); + else if (strcmp(name, "c_fail") == 0) + return varnish_submit_derive(conf->instance, category, + "total_operations", "alloc_fail", val); + else if (strcmp(name, "c_bytes") == 0) + return varnish_submit_derive(conf->instance, category, + "total_bytes", "bytes_allocated", val); + else if (strcmp(name, "c_freed") == 0) + return varnish_submit_derive(conf->instance, category, + "total_bytes", "bytes_freed", val); + else if (strcmp(name, "g_alloc") == 0) + return varnish_submit_gauge(conf->instance, category, + "total_operations", "alloc_outstanding", val); + else if (strcmp(name, "g_bytes") == 0) + return varnish_submit_gauge(conf->instance, category, "bytes", + "bytes_outstanding", val); + else if (strcmp(name, "g_space") == 0) + return varnish_submit_gauge(conf->instance, category, "bytes", + "bytes_available", val); + } + + /* No SMA specific counters */ + + if (conf->collect_smf) { + if (strcmp(name, "g_smf") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_struct_smf", val); + else if (strcmp(name, "g_smf_frag") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_small_free_smf", val); + else if (strcmp(name, "g_smf_large") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_large_free_smf", val); + } + + if (conf->collect_mgt) { + if (strcmp(name, "uptime") == 0) + return varnish_submit_gauge(conf->instance, "mgt", "uptime", + "mgt_proc_uptime", val); + else if (strcmp(name, "child_start") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_start", val); + else if (strcmp(name, "child_exit") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_exit", val); + else if (strcmp(name, "child_stop") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_stop", val); + else if (strcmp(name, "child_died") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_died", val); + else if (strcmp(name, "child_dump") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_dump", val); + else if (strcmp(name, "child_panic") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_panic", val); + } + + if (conf->collect_lck) { + if (strcmp(name, "creat") == 0) + return varnish_submit_derive(conf->instance, "lck", "objects", + "created", val); + else if (strcmp(name, "destroy") == 0) + return varnish_submit_derive(conf->instance, "lck", "objects", + "destroyed", val); + else if (strcmp(name, "locks") == 0) + return varnish_submit_derive(conf->instance, "lck", "total_operations", + "lock_ops", val); + } + + if (conf->collect_mempool) { + if (strcmp(name, "live") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "objects", + "in_use", val); + else if (strcmp(name, "pool") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "objects", + "in_pool", val); + else if (strcmp(name, "sz_wanted") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "bytes", + "size_requested", val); + else if (strcmp(name, "sz_actual") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "bytes", + "size_allocated", val); + else if (strcmp(name, "allocs") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "total_operations", "allocations", val); + else if (strcmp(name, "frees") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "total_operations", "frees", val); + else if (strcmp(name, "recycle") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "recycled", val); + else if (strcmp(name, "timeout") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "timed_out", val); + else if (strcmp(name, "toosmall") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "too_small", val); + else if (strcmp(name, "surplus") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "surplus", val); + else if (strcmp(name, "randry") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "ran_dry", val); + } #endif return 0; @@ -1098,6 +1336,8 @@ static int varnish_config_apply_default(user_config_t *conf) /* {{{ */ conf->collect_shm = 1; #if HAVE_VARNISH_V2 conf->collect_sm = 0; +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 conf->collect_sma = 0; #endif conf->collect_sms = 0; @@ -1110,6 +1350,11 @@ static int varnish_config_apply_default(user_config_t *conf) /* {{{ */ conf->collect_workers = 0; #if HAVE_VARNISH_V4 conf->collect_vsm = 0; + conf->collect_lck = 0; + conf->collect_mempool = 0; + conf->collect_mgt = 0; + conf->collect_smf = 0; + conf->collect_vbe = 0; #endif return 0; @@ -1135,9 +1380,10 @@ static int varnish_init(void) /* {{{ */ /* group = */ "varnish", /* name = */ "varnish/localhost", /* callback = */ varnish_read, - /* interval = */ 0, &(user_data_t){ - .data = conf, .free_func = varnish_config_free, - }); + /* interval = */ 0, + &(user_data_t){ + .data = conf, .free_func = varnish_config_free, + }); return 0; } /* }}} int varnish_init */ @@ -1220,11 +1466,11 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ else if (strcasecmp("CollectSMS", child->key) == 0) cf_util_get_boolean(child, &conf->collect_sms); else if (strcasecmp("CollectSMA", child->key) == 0) -#if HAVE_VARNISH_V2 +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 cf_util_get_boolean(child, &conf->collect_sma); #else WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", - child->key, "v2"); + child->key, "v2 and v4"); #endif else if (strcasecmp("CollectSM", child->key) == 0) #if HAVE_VARNISH_V2 @@ -1255,6 +1501,48 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", child->key, "v4"); #endif + else if (strcasecmp("CollectLock", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_lck); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectMempool", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_mempool); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectManagement", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_mgt); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectSMF", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_smf); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectSMF", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_smf); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectVBE", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_vbe); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif else { WARNING("Varnish plugin: Ignoring unknown " "configuration option: \"%s\". Did " @@ -1277,7 +1565,10 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ #endif && !conf->collect_session && !conf->collect_shm && !conf->collect_sms #if HAVE_VARNISH_V2 - && !conf->collect_sma && !conf->collect_sm + && !conf->collect_sm +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 + && !conf->collect_sma #endif && !conf->collect_struct && !conf->collect_totals #if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 @@ -1285,7 +1576,8 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ #endif && !conf->collect_vcl && !conf->collect_workers #if HAVE_VARNISH_V4 - && !conf->collect_vsm + && !conf->collect_vsm && !conf->collect_vbe && !conf->collect_smf + && !conf->collect_mgt && !conf->collect_lck && !conf->collect_mempool #endif ) { WARNING("Varnish plugin: No metric has been configured for " @@ -1295,16 +1587,17 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ return EINVAL; } - ssnprintf(callback_name, sizeof(callback_name), "varnish/%s", - (conf->instance == NULL) ? "localhost" : conf->instance); + snprintf(callback_name, sizeof(callback_name), "varnish/%s", + (conf->instance == NULL) ? "localhost" : conf->instance); plugin_register_complex_read( /* group = */ "varnish", /* name = */ callback_name, /* callback = */ varnish_read, - /* interval = */ 0, &(user_data_t){ - .data = conf, .free_func = varnish_config_free, - }); + /* interval = */ 0, + &(user_data_t){ + .data = conf, .free_func = varnish_config_free, + }); have_instance = 1; diff --git a/src/virt.c b/src/virt.c index 14095df4..ca6e831e 100644 --- a/src/virt.c +++ b/src/virt.c @@ -731,7 +731,7 @@ static void vcpu_submit(derive_t value, virDomainPtr dom, int vcpu_nr, const char *type) { char type_instance[DATA_MAX_NAME_LEN]; - ssnprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr); + snprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr); submit(dom, type, type_instance, &(value_t){.derive = value}, 1); } @@ -752,8 +752,8 @@ static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom, } char flush_type_instance[DATA_MAX_NAME_LEN]; - ssnprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s", - type_instance); + snprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s", + type_instance); if ((binfo->bi.rd_req != -1) && (binfo->bi.wr_req != -1)) submit_derive2("disk_ops", (derive_t)binfo->bi.rd_req, @@ -828,8 +828,8 @@ static void domain_state_submit(virDomainPtr dom, int state, int reason) { const char *reason_str = "N/A"; #endif - ssnprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str, - reason_str); + snprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str, + reason_str); int severity; switch (state) { @@ -1180,8 +1180,7 @@ static void vcpu_pin_submit(virDomainPtr dom, int max_cpus, int vcpu, char type_instance[DATA_MAX_NAME_LEN]; _Bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu) ? 1 : 0; - ssnprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, - cpu); + snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu); submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1); } } @@ -1661,7 +1660,7 @@ static int lv_init_instance(size_t i, plugin_read_cb callback) { memset(lv_ud, 0, sizeof(*lv_ud)); - ssnprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i); + snprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i); inst->id = i; user_data_t *ud = &(lv_ud->ud); @@ -1721,8 +1720,8 @@ static int lv_domain_get_tag(xmlXPathContextPtr xpath_ctx, const char *dom_name, goto done; } - ssnprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()", - METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT); + snprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()", + METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT); xpath_obj = xmlXPathEvalExpression((xmlChar *)xpath_str, xpath_ctx); if (xpath_obj == NULL) { ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed on domain %s", @@ -2157,7 +2156,7 @@ static int ignore_device_match(ignorelist_t *il, const char *domname, ERROR(PLUGIN_NAME " plugin: malloc failed."); return 0; } - ssnprintf(name, n, "%s:%s", domname, devpath); + snprintf(name, n, "%s:%s", domname, devpath); r = ignorelist_match(il, name); sfree(name); return r; diff --git a/src/virt_test.c b/src/virt_test.c index cb3cc254..489a367d 100644 --- a/src/virt_test.c +++ b/src/virt_test.c @@ -22,8 +22,8 @@ * Florian octo Forster **/ -#include "virt.c" /* sic */ #include "testing.h" +#include "virt.c" /* sic */ #include diff --git a/src/vserver.c b/src/vserver.c index a2ca0de5..6f9d46bf 100644 --- a/src/vserver.c +++ b/src/vserver.c @@ -160,7 +160,7 @@ static int vserver_read(void) { if (dent->d_name[0] == '.') continue; - len = ssnprintf(file, sizeof(file), PROCDIR "/%s", dent->d_name); + len = snprintf(file, sizeof(file), PROCDIR "/%s", dent->d_name); if ((len < 0) || (len >= BUFSIZE)) continue; @@ -176,7 +176,7 @@ static int vserver_read(void) { continue; /* socket message accounting */ - len = ssnprintf(file, sizeof(file), PROCDIR "/%s/cacct", dent->d_name); + len = snprintf(file, sizeof(file), PROCDIR "/%s/cacct", dent->d_name); if ((len < 0) || ((size_t)len >= sizeof(file))) continue; @@ -220,7 +220,7 @@ static int vserver_read(void) { } /* thread information and load */ - len = ssnprintf(file, sizeof(file), PROCDIR "/%s/cvirt", dent->d_name); + len = snprintf(file, sizeof(file), PROCDIR "/%s/cvirt", dent->d_name); if ((len < 0) || ((size_t)len >= sizeof(file))) continue; @@ -266,7 +266,7 @@ static int vserver_read(void) { } /* processes and memory usage */ - len = ssnprintf(file, sizeof(file), PROCDIR "/%s/limit", dent->d_name); + len = snprintf(file, sizeof(file), PROCDIR "/%s/limit", dent->d_name); if ((len < 0) || ((size_t)len >= sizeof(file))) continue; diff --git a/src/write_graphite.c b/src/write_graphite.c index 206cdc2d..a8d13206 100644 --- a/src/write_graphite.c +++ b/src/write_graphite.c @@ -545,11 +545,11 @@ static int wg_config_node(oconfig_item_t *ci) { /* FIXME: Legacy configuration syntax. */ if (cb->name == NULL) - ssnprintf(callback_name, sizeof(callback_name), "write_graphite/%s/%s/%s", - cb->node, cb->service, cb->protocol); + snprintf(callback_name, sizeof(callback_name), "write_graphite/%s/%s/%s", + cb->node, cb->service, cb->protocol); else - ssnprintf(callback_name, sizeof(callback_name), "write_graphite/%s", - cb->name); + snprintf(callback_name, sizeof(callback_name), "write_graphite/%s", + cb->name); plugin_register_write(callback_name, wg_write, &(user_data_t){ diff --git a/src/write_http.c b/src/write_http.c index 61b9a0ec..06327edb 100644 --- a/src/write_http.c +++ b/src/write_http.c @@ -190,8 +190,8 @@ static int wh_callback_init(wh_callback_t *cb) /* {{{ */ return -1; } - ssnprintf(cb->credentials, credentials_size, "%s:%s", cb->user, - (cb->pass == NULL) ? "" : cb->pass); + snprintf(cb->credentials, credentials_size, "%s:%s", cb->user, + (cb->pass == NULL) ? "" : cb->pass); curl_easy_setopt(cb->curl, CURLOPT_USERPWD, cb->credentials); #endif curl_easy_setopt(cb->curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY); @@ -369,9 +369,9 @@ static int wh_write_command(const data_set_t *ds, return status; } - command_len = (size_t)ssnprintf(command, sizeof(command), - "PUTVAL %s interval=%.3f %s\r\n", key, - CDTIME_T_TO_DOUBLE(vl->interval), values); + command_len = (size_t)snprintf(command, sizeof(command), + "PUTVAL %s interval=%.3f %s\r\n", key, + CDTIME_T_TO_DOUBLE(vl->interval), values); if (command_len >= sizeof(command)) { ERROR("write_http plugin: Command buffer too small: " "Need %zu bytes.", @@ -791,7 +791,7 @@ static int wh_config_node(oconfig_item_t *ci) /* {{{ */ /* Nulls the buffer and sets ..._free and ..._fill. */ wh_reset_buffer(cb); - ssnprintf(callback_name, sizeof(callback_name), "write_http/%s", cb->name); + snprintf(callback_name, sizeof(callback_name), "write_http/%s", cb->name); DEBUG("write_http: Registering write callback '%s' with URL '%s'", callback_name, cb->location); diff --git a/src/write_kafka.c b/src/write_kafka.c index ca400acb..3c573801 100644 --- a/src/write_kafka.c +++ b/src/write_kafka.c @@ -89,7 +89,7 @@ static uint32_t kafka_hash(const char *keydata, size_t keylen) { #define KAFKA_RANDOM_KEY_BUFFER \ (char[KAFKA_RANDOM_KEY_SIZE]) { "" } static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) { - ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u()); + snprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u()); return buffer; } @@ -398,8 +398,8 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, rd_kafka_topic_conf_set_partitioner_cb(tctx->conf, kafka_partition); rd_kafka_topic_conf_set_opaque(tctx->conf, tctx); - ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s", - tctx->topic_name); + snprintf(callback_name, sizeof(callback_name), "write_kafka/%s", + tctx->topic_name); status = plugin_register_write( callback_name, kafka_write, diff --git a/src/write_mongodb.c b/src/write_mongodb.c index e1fb41fd..46b6d865 100644 --- a/src/write_mongodb.c +++ b/src/write_mongodb.c @@ -96,7 +96,7 @@ static bson_t *wm_create_bson(const data_set_t *ds, /* {{{ */ for (size_t i = 0; i < ds->ds_num; i++) { char key[16]; - ssnprintf(key, sizeof(key), "%zu", i); + snprintf(key, sizeof(key), "%zu", i); if (ds->ds[i].type == DS_TYPE_GAUGE) BSON_APPEND_DOUBLE(&subarray, key, vl->values[i].gauge); @@ -121,7 +121,7 @@ static bson_t *wm_create_bson(const data_set_t *ds, /* {{{ */ for (size_t i = 0; i < ds->ds_num; i++) { char key[16]; - ssnprintf(key, sizeof(key), "%zu", i); + snprintf(key, sizeof(key), "%zu", i); if (store_rates) BSON_APPEND_UTF8(&subarray, key, "gauge"); @@ -134,7 +134,7 @@ static bson_t *wm_create_bson(const data_set_t *ds, /* {{{ */ for (size_t i = 0; i < ds->ds_num; i++) { char key[16]; - ssnprintf(key, sizeof(key), "%zu", i); + snprintf(key, sizeof(key), "%zu", i); BSON_APPEND_UTF8(&subarray, key, ds->ds[i].name); } bson_append_array_end(ret, &subarray); /* }}} dsnames */ @@ -366,9 +366,9 @@ static int wm_config_node(oconfig_item_t *ci) /* {{{ */ } if (status == 0) { - char cb_name[DATA_MAX_NAME_LEN]; + char cb_name[sizeof("write_mongodb/") + DATA_MAX_NAME_LEN]; - ssnprintf(cb_name, sizeof(cb_name), "write_mongodb/%s", node->name); + snprintf(cb_name, sizeof(cb_name), "write_mongodb/%s", node->name); status = plugin_register_write(cb_name, wm_write, diff --git a/src/write_prometheus.c b/src/write_prometheus.c index 52649984..eac0d68e 100644 --- a/src/write_prometheus.c +++ b/src/write_prometheus.c @@ -159,8 +159,8 @@ static char *format_labels(char *buffer, size_t buffer_size, * know that they are sane. */ for (size_t i = 0; i < m->n_label; i++) { char value[LABEL_VALUE_SIZE]; - ssnprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name, - escape_label_value(value, sizeof(value), m->label[i]->value)); + snprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name, + escape_label_value(value, sizeof(value), m->label[i]->value)); } strjoin(buffer, buffer_size, labels, m->n_label, ","); @@ -178,13 +178,13 @@ static void format_text(ProtobufCBuffer *buffer) { while (c_avl_iterator_next(iter, (void *)&unused_name, (void *)&fam) == 0) { char line[1024]; /* 4x DATA_MAX_NAME_LEN? */ - ssnprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help); + snprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help); buffer->append(buffer, strlen(line), (uint8_t *)line); - ssnprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name, - (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE) - ? "gauge" - : "counter"); + snprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name, + (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE) + ? "gauge" + : "counter"); buffer->append(buffer, strlen(line), (uint8_t *)line); for (size_t i = 0; i < fam->n_metric; i++) { @@ -194,17 +194,17 @@ static void format_text(ProtobufCBuffer *buffer) { char timestamp_ms[24] = ""; if (m->has_timestamp_ms) - ssnprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64, - m->timestamp_ms); + snprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64, + m->timestamp_ms); if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE) - ssnprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name, - format_labels(labels, sizeof(labels), m), m->gauge->value, - timestamp_ms); + snprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name, + format_labels(labels, sizeof(labels), m), m->gauge->value, + timestamp_ms); else /* if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__COUNTER) */ - ssnprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name, - format_labels(labels, sizeof(labels), m), m->counter->value, - timestamp_ms); + snprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name, + format_labels(labels, sizeof(labels), m), m->counter->value, + timestamp_ms); buffer->append(buffer, strlen(line), (uint8_t *)line); } @@ -212,8 +212,8 @@ static void format_text(ProtobufCBuffer *buffer) { c_avl_iterator_destroy(iter); char server[1024]; - ssnprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n", - PACKAGE_VERSION, hostname_g); + snprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n", + PACKAGE_VERSION, hostname_g); buffer->append(buffer, strlen(server), (uint8_t *)server); pthread_mutex_unlock(&metrics_lock); @@ -599,8 +599,8 @@ static int metric_family_update(Io__Prometheus__Client__MetricFamily *fam, if (m == NULL) return -1; - return metric_update(m, vl->values[ds_index], ds->ds[ds_index].type, - vl->time, vl->interval); + return metric_update(m, vl->values[ds_index], ds->ds[ds_index].type, vl->time, + vl->interval); } /* metric_family_destroy frees the memory used by a metric family. */ @@ -631,7 +631,7 @@ metric_family_create(char *name, data_set_t const *ds, value_list_t const *vl, msg->name = name; char help[1024]; - ssnprintf( + snprintf( help, sizeof(help), "write_prometheus plugin: '%s' Type: '%s', Dstype: '%s', Dsname: '%s'", vl->plugin, vl->type, DS_TYPE_TO_STRING(ds->ds[ds_index].type), diff --git a/src/write_redis.c b/src/write_redis.c index f7215b50..7dd5029c 100644 --- a/src/write_redis.c +++ b/src/write_redis.c @@ -45,6 +45,7 @@ struct wr_node_s { char *prefix; int database; int max_set_size; + int max_set_duration; _Bool store_rates; redisContext *conn; @@ -70,10 +71,9 @@ static int wr_write(const data_set_t *ds, /* {{{ */ status = FORMAT_VL(ident, sizeof(ident), vl); if (status != 0) return status; - ssnprintf(key, sizeof(key), "%s%s", - (node->prefix != NULL) ? node->prefix : REDIS_DEFAULT_PREFIX, - ident); - ssnprintf(time, sizeof(time), "%.9f", CDTIME_T_TO_DOUBLE(vl->time)); + snprintf(key, sizeof(key), "%s%s", + (node->prefix != NULL) ? node->prefix : REDIS_DEFAULT_PREFIX, ident); + snprintf(time, sizeof(time), "%.9f", CDTIME_T_TO_DOUBLE(vl->time)); value_size = sizeof(value); value_ptr = &value[0]; @@ -126,6 +126,20 @@ static int wr_write(const data_set_t *ds, /* {{{ */ freeReplyObject(rr); } + if (node->max_set_duration > 0) { + /* + * remove element, scored less than 'current-max_set_duration' + * '(%d' indicates 'less than' in redis CLI. + */ + rr = redisCommand(node->conn, "ZREMRANGEBYSCORE %s -1 (%d", key, + (time - node->max_set_duration) + 1); + if (rr == NULL) + WARNING("ZREMRANGEBYSCORE command error. key:%s message:%s", key, + node->conn->errstr); + else + freeReplyObject(rr); + } + /* TODO(octo): This is more overhead than necessary. Use the cache and * metadata to determine if it is a new metric and call SADD only once for * each metric. */ @@ -176,6 +190,7 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */ node->prefix = NULL; node->database = 0; node->max_set_size = -1; + node->max_set_duration = -1; node->store_rates = 1; pthread_mutex_init(&node->lock, /* attr = */ NULL); @@ -206,6 +221,8 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */ status = cf_util_get_int(child, &node->database); } else if (strcasecmp("MaxSetSize", child->key) == 0) { status = cf_util_get_int(child, &node->max_set_size); + } else if (strcasecmp("MaxSetDuration", child->key) == 0) { + status = cf_util_get_int(child, &node->max_set_duration); } else if (strcasecmp("StoreRates", child->key) == 0) { status = cf_util_get_boolean(child, &node->store_rates); } else @@ -217,14 +234,15 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */ } /* for (i = 0; i < ci->children_num; i++) */ if (status == 0) { - char cb_name[DATA_MAX_NAME_LEN]; + char cb_name[sizeof("write_redis/") + DATA_MAX_NAME_LEN]; - ssnprintf(cb_name, sizeof(cb_name), "write_redis/%s", node->name); + snprintf(cb_name, sizeof(cb_name), "write_redis/%s", node->name); - status = plugin_register_write( - cb_name, wr_write, &(user_data_t){ - .data = node, .free_func = wr_config_free, - }); + status = + plugin_register_write(cb_name, wr_write, + &(user_data_t){ + .data = node, .free_func = wr_config_free, + }); } if (status != 0) diff --git a/src/write_riemann.c b/src/write_riemann.c index 5bd0cf43..6db3ef58 100644 --- a/src/write_riemann.c +++ b/src/write_riemann.c @@ -293,18 +293,17 @@ wrr_value_to_event(struct riemann_host const *host, /* {{{ */ vl->type_instance); if (host->always_append_ds || (ds->ds_num > 1)) { if (host->event_service_prefix == NULL) - ssnprintf(service_buffer, sizeof(service_buffer), "%s/%s", - &name_buffer[1], ds->ds[index].name); + snprintf(service_buffer, sizeof(service_buffer), "%s/%s", &name_buffer[1], + ds->ds[index].name); else - ssnprintf(service_buffer, sizeof(service_buffer), "%s%s/%s", - host->event_service_prefix, &name_buffer[1], - ds->ds[index].name); + snprintf(service_buffer, sizeof(service_buffer), "%s%s/%s", + host->event_service_prefix, &name_buffer[1], ds->ds[index].name); } else { if (host->event_service_prefix == NULL) sstrncpy(service_buffer, &name_buffer[1], sizeof(service_buffer)); else - ssnprintf(service_buffer, sizeof(service_buffer), "%s%s", - host->event_service_prefix, &name_buffer[1]); + snprintf(service_buffer, sizeof(service_buffer), "%s%s", + host->event_service_prefix, &name_buffer[1]); } riemann_event_set( @@ -352,8 +351,8 @@ wrr_value_to_event(struct riemann_host const *host, /* {{{ */ if ((ds->ds[index].type != DS_TYPE_GAUGE) && (rates != NULL)) { char ds_type[DATA_MAX_NAME_LEN]; - ssnprintf(ds_type, sizeof(ds_type), "%s:rate", - DS_TYPE_TO_STRING(ds->ds[index].type)); + snprintf(ds_type, sizeof(ds_type), "%s:rate", + DS_TYPE_TO_STRING(ds->ds[index].type)); riemann_event_string_attribute_add(event, "ds_type", ds_type); } else { riemann_event_string_attribute_add(event, "ds_type", @@ -363,7 +362,7 @@ wrr_value_to_event(struct riemann_host const *host, /* {{{ */ { char ds_index[DATA_MAX_NAME_LEN]; - ssnprintf(ds_index, sizeof(ds_index), "%zu", index); + snprintf(ds_index, sizeof(ds_index), "%zu", index); riemann_event_string_attribute_add(event, "ds_index", ds_index); } @@ -802,8 +801,8 @@ static int wrr_config_node(oconfig_item_t *ci) /* {{{ */ return status; } - ssnprintf(callback_name, sizeof(callback_name), "write_riemann/%s", - host->name); + snprintf(callback_name, sizeof(callback_name), "write_riemann/%s", + host->name); user_data_t ud = {.data = host, .free_func = wrr_free}; diff --git a/src/write_sensu.c b/src/write_sensu.c index 56acb638..ce23e654 100644 --- a/src/write_sensu.c +++ b/src/write_sensu.c @@ -420,8 +420,8 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */ // incorporate the data source type if ((ds->ds[index].type != DS_TYPE_GAUGE) && (rates != NULL)) { char ds_type[DATA_MAX_NAME_LEN]; - ssnprintf(ds_type, sizeof(ds_type), "%s:rate", - DS_TYPE_TO_STRING(ds->ds[index].type)); + snprintf(ds_type, sizeof(ds_type), "%s:rate", + DS_TYPE_TO_STRING(ds->ds[index].type)); res = my_asprintf(&temp_str, "%s, \"collectd_data_source_type\": \"%s\"", ret_str, ds_type); free(ret_str); @@ -454,7 +454,7 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */ // incorporate the data source index { char ds_index[DATA_MAX_NAME_LEN]; - ssnprintf(ds_index, sizeof(ds_index), "%zu", index); + snprintf(ds_index, sizeof(ds_index), "%zu", index); res = my_asprintf(&temp_str, "%s, \"collectd_data_source_index\": %s", ret_str, ds_index); free(ret_str); @@ -534,17 +534,17 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */ host->separator); if (host->always_append_ds || (ds->ds_num > 1)) { if (host->event_service_prefix == NULL) - ssnprintf(service_buffer, sizeof(service_buffer), "%s.%s", name_buffer, - ds->ds[index].name); + snprintf(service_buffer, sizeof(service_buffer), "%s.%s", name_buffer, + ds->ds[index].name); else - ssnprintf(service_buffer, sizeof(service_buffer), "%s%s.%s", - host->event_service_prefix, name_buffer, ds->ds[index].name); + snprintf(service_buffer, sizeof(service_buffer), "%s%s.%s", + host->event_service_prefix, name_buffer, ds->ds[index].name); } else { if (host->event_service_prefix == NULL) sstrncpy(service_buffer, name_buffer, sizeof(service_buffer)); else - ssnprintf(service_buffer, sizeof(service_buffer), "%s%s", - host->event_service_prefix, name_buffer); + snprintf(service_buffer, sizeof(service_buffer), "%s%s", + host->event_service_prefix, name_buffer); } // Replace collectd sensor name reserved characters so that time series DB is @@ -1141,7 +1141,7 @@ static int sensu_config_node(oconfig_item_t *ci) /* {{{ */ return -1; } - ssnprintf(callback_name, sizeof(callback_name), "write_sensu/%s", host->name); + snprintf(callback_name, sizeof(callback_name), "write_sensu/%s", host->name); user_data_t ud = {.data = host, .free_func = sensu_free}; diff --git a/src/write_tsdb.c b/src/write_tsdb.c index 1a1cd648..10f636c5 100644 --- a/src/write_tsdb.c +++ b/src/write_tsdb.c @@ -325,7 +325,7 @@ static int wt_format_values(char *ret, size_t ret_len, int ds_num, #define BUFFER_ADD(...) \ do { \ - status = ssnprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ + status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ if (status < 1) { \ sfree(rates); \ return -1; \ @@ -388,36 +388,36 @@ static int wt_format_name(char *ret, int ret_len, const value_list_t *vl, if (ds_name != NULL) { if (vl->plugin_instance[0] == '\0') { if (vl->type_instance[0] == '\0') { - ssnprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, vl->type, - ds_name); + snprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, vl->type, + ds_name); } else { - ssnprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, vl->type, - vl->type_instance, ds_name); + snprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, vl->type, + vl->type_instance, ds_name); } } else { /* vl->plugin_instance != "" */ if (vl->type_instance[0] == '\0') { - ssnprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, - vl->plugin_instance, vl->type, ds_name); + snprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, + vl->plugin_instance, vl->type, ds_name); } else { - ssnprintf(ret, ret_len, "%s%s.%s.%s.%s.%s", prefix, vl->plugin, - vl->plugin_instance, vl->type, vl->type_instance, ds_name); + snprintf(ret, ret_len, "%s%s.%s.%s.%s.%s", prefix, vl->plugin, + vl->plugin_instance, vl->type, vl->type_instance, ds_name); } } } else { /* ds_name == NULL */ if (vl->plugin_instance[0] == '\0') { if (vl->type_instance[0] == '\0') { - ssnprintf(ret, ret_len, "%s%s.%s", prefix, vl->plugin, vl->type); + snprintf(ret, ret_len, "%s%s.%s", prefix, vl->plugin, vl->type); } else { - ssnprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, - vl->type_instance, vl->type); + snprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, + vl->type_instance, vl->type); } } else { /* vl->plugin_instance != "" */ if (vl->type_instance[0] == '\0') { - ssnprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, - vl->plugin_instance, vl->type); + snprintf(ret, ret_len, "%s%s.%s.%s", prefix, vl->plugin, + vl->plugin_instance, vl->type); } else { - ssnprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, - vl->plugin_instance, vl->type, vl->type_instance); + snprintf(ret, ret_len, "%s%s.%s.%s.%s", prefix, vl->plugin, + vl->plugin_instance, vl->type, vl->type_instance); } } } @@ -456,8 +456,8 @@ static int wt_send_message(const char *key, const char *value, cdtime_t time, } status = - ssnprintf(message, sizeof(message), "put %s %.0f %s fqdn=%s %s %s\r\n", - key, CDTIME_T_TO_DOUBLE(time), value, host, tags, host_tags); + snprintf(message, sizeof(message), "put %s %.0f %s fqdn=%s %s %s\r\n", + key, CDTIME_T_TO_DOUBLE(time), value, host, tags, host_tags); sfree(temp); if (status < 0) return -1; @@ -607,9 +607,9 @@ static int wt_config_tsd(oconfig_item_t *ci) { } } - ssnprintf(callback_name, sizeof(callback_name), "write_tsdb/%s/%s", - cb->node != NULL ? cb->node : WT_DEFAULT_NODE, - cb->service != NULL ? cb->service : WT_DEFAULT_SERVICE); + snprintf(callback_name, sizeof(callback_name), "write_tsdb/%s/%s", + cb->node != NULL ? cb->node : WT_DEFAULT_NODE, + cb->service != NULL ? cb->service : WT_DEFAULT_SERVICE); user_data_t user_data = {.data = cb, .free_func = wt_callback_free}; diff --git a/src/xencpu.c b/src/xencpu.c index bf178647..8cba476f 100644 --- a/src/xencpu.c +++ b/src/xencpu.c @@ -112,7 +112,7 @@ static void submit_value(int cpu_num, gauge_t value) { sstrncpy(vl.type_instance, "load", sizeof(vl.type_instance)); if (cpu_num >= 0) { - ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", cpu_num); + snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", cpu_num); } plugin_dispatch_values(&vl); } /* static void submit_value */ diff --git a/src/zfs_arc.c b/src/zfs_arc.c index cf858f8f..e589184c 100644 --- a/src/zfs_arc.c +++ b/src/zfs_arc.c @@ -35,6 +35,10 @@ /* * Global variables */ +static value_to_rate_state_t arc_hits_state; +static value_to_rate_state_t arc_misses_state; +static value_to_rate_state_t l2_hits_state; +static value_to_rate_state_t l2_misses_state; #if defined(KERNEL_LINUX) #include "utils_llist.h" @@ -118,7 +122,7 @@ static long long get_zfs_value(kstat_t *dummy __attribute__((unused)), size_t valuelen = sizeof(value); int rv; - ssnprintf(buffer, sizeof(buffer), "%s%s", zfs_arcstat, name); + snprintf(buffer, sizeof(buffer), "%s%s", zfs_arcstat, name); rv = sysctlbyname(buffer, (void *)&value, &valuelen, /* new value = */ NULL, /* new length = */ (size_t)0); if (rv == 0) @@ -216,12 +220,14 @@ static int za_read(void) { // See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel // module. if (fgets(buffer, sizeof(buffer), fh) == NULL) { - ERROR("zfs_arc plugin: \"%s\" does not contain a single line.", ZOL_ARCSTATS_FILE); + ERROR("zfs_arc plugin: \"%s\" does not contain a single line.", + ZOL_ARCSTATS_FILE); fclose(fh); return -1; } if (fgets(buffer, sizeof(buffer), fh) == NULL) { - ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.", ZOL_ARCSTATS_FILE); + ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.", + ZOL_ARCSTATS_FILE); fclose(fh); return -1; } @@ -311,14 +317,25 @@ static int za_read(void) { za_read_derive(ksp, "mru_hits", "cache_result", "mru-hit"); za_read_derive(ksp, "mru_ghost_hits", "cache_result", "mru_ghost-hit"); + cdtime_t now = cdtime(); + /* Ratios */ - arc_hits = (gauge_t)get_zfs_value(ksp, "hits"); - arc_misses = (gauge_t)get_zfs_value(ksp, "misses"); - l2_hits = (gauge_t)get_zfs_value(ksp, "l2_hits"); - l2_misses = (gauge_t)get_zfs_value(ksp, "l2_misses"); + if ((value_to_rate(&arc_hits, (value_t){.derive = get_zfs_value(ksp, "hits")}, + DS_TYPE_DERIVE, now, &arc_hits_state) == 0) && + (value_to_rate(&arc_misses, + (value_t){.derive = get_zfs_value(ksp, "misses")}, + DS_TYPE_DERIVE, now, &arc_misses_state) == 0)) { + za_submit_ratio("arc", arc_hits, arc_misses); + } - za_submit_ratio("arc", arc_hits, arc_misses); - za_submit_ratio("L2", l2_hits, l2_misses); + if ((value_to_rate(&l2_hits, + (value_t){.derive = get_zfs_value(ksp, "l2_hits")}, + DS_TYPE_DERIVE, now, &l2_hits_state) == 0) && + (value_to_rate(&l2_misses, + (value_t){.derive = get_zfs_value(ksp, "l2_misses")}, + DS_TYPE_DERIVE, now, &l2_misses_state) == 0)) { + za_submit_ratio("L2", l2_hits, l2_misses); + } /* I/O */ value_t l2_io[] = {