Merge branch 'GPSd'
authorNicolas JOURDEN <nicolas.jourden@laposte.net>
Tue, 17 Nov 2015 14:12:47 +0000 (15:12 +0100)
committerNicolas JOURDEN <nicolas.jourden@laposte.net>
Tue, 17 Nov 2015 14:12:47 +0000 (15:12 +0100)
137 files changed:
.gitignore
.travis.yml [new file with mode: 0644]
AUTHORS
README
bindings/perl/lib/Collectd/Unixsock.pm
bindings/perl/t/01_methods.t
configure.ac
contrib/README
contrib/collectd.service [deleted file]
contrib/fedora/collectd.spec [deleted file]
contrib/fedora/init.d-collectd [deleted file]
contrib/redhat/collectd.spec
contrib/systemd.collectd.service
src/Makefile.am
src/apache.c
src/apcups.c
src/ascent.c
src/barometer.c
src/bind.c
src/ceph.c
src/collectd-exec.pod
src/collectd-nagios.c
src/collectd-tg.c
src/collectd.conf.in
src/collectd.conf.pod
src/collectdctl.c
src/cpu.c
src/csv.c
src/curl.c
src/curl_json.c
src/curl_xml.c
src/daemon/Makefile.am
src/daemon/collectd.c
src/daemon/collectd.h
src/daemon/common.c
src/daemon/common.h
src/daemon/common_test.c
src/daemon/configfile.c
src/daemon/meta_data_test.c [new file with mode: 0644]
src/daemon/plugin.c
src/daemon/plugin.h
src/daemon/plugin_mock.c
src/daemon/types_list.c
src/daemon/utils_cache.c
src/daemon/utils_cache_mock.c
src/daemon/utils_ignorelist.c [new file with mode: 0644]
src/daemon/utils_ignorelist.h [new file with mode: 0644]
src/daemon/utils_subst.c
src/daemon/utils_subst_test.c [new file with mode: 0644]
src/daemon/utils_time.c
src/daemon/utils_time.h
src/daemon/utils_time_mock.c
src/daemon/utils_time_test.c [new file with mode: 0644]
src/dbi.c
src/disk.c
src/email.c
src/gmond.c
src/hddtemp.c
src/interface.c
src/iptables.c
src/ipvs.c
src/java.c
src/libcollectdclient/Makefile.am
src/libcollectdclient/client.c
src/libcollectdclient/network.c
src/liboconfig/oconfig.c
src/madwifi.c
src/match_empty_counter.c
src/match_value.c
src/mbmon.c
src/memcached.c
src/memory.c
src/modbus.c
src/mqtt.c [new file with mode: 0644]
src/mysql.c
src/netapp.c
src/netlink.c
src/network.c
src/nginx.c
src/ntpd.c
src/olsrd.c
src/onewire.c
src/openldap.c
src/perl.c
src/pf.c
src/pinba.c
src/ping.c
src/postgresql.c
src/powerdns.c
src/processes.c
src/python.c
src/pyvalues.c
src/routeros.c
src/rrdcached.c
src/rrdtool.c
src/serial.c
src/snmp.c
src/statsd.c
src/table.c
src/tail.c
src/tail_csv.c
src/target_notification.c
src/target_replace.c
src/target_scale.c
src/tcpconns.c
src/teamspeak2.c
src/ted.c
src/testing.h
src/threshold.c
src/types.db
src/unixsock.c
src/utils_cmd_flush.c
src/utils_cmd_getval.c
src/utils_db_query.c
src/utils_dns.c
src/utils_format_graphite.c
src/utils_format_json.c
src/utils_ignorelist.c [deleted file]
src/utils_ignorelist.h [deleted file]
src/utils_latency_test.c [new file with mode: 0644]
src/utils_mount_test.c
src/utils_rrdcreate.c
src/utils_vl_lookup.c
src/utils_vl_lookup_test.c
src/varnish.c
src/virt.c
src/write_graphite.c
src/write_http.c
src/write_log.c
src/write_redis.c
src/write_riemann.c
src/write_riemann_threshold.c
src/write_sensu.c
src/write_tsdb.c
src/zfs_arc.c
src/zone.c [new file with mode: 0644]
src/zookeeper.c

index 54eaa97..cf4ad15 100644 (file)
@@ -83,9 +83,18 @@ src/tests/.deps/
 src/tests/mock/.deps/
 src/tests/.dirstamp
 src/tests/mock/.dirstamp
+src/test_utils_latency
+src/test_utils_mount
+src/test_utils_vl_lookup
 test*.log
+*.trs
 
 # new daemon repo
 src/daemon/.deps/
 src/daemon/.dirstamp
 src/daemon/collectd
+src/daemon/test_common
+src/daemon/test_meta_data
+src/daemon/test_utils_avltree
+src/daemon/test_utils_heap
+src/daemon/test_utils_subst
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..09adb4d
--- /dev/null
@@ -0,0 +1,25 @@
+sudo: false
+compiler:
+  - gcc
+  - clang
+addons:
+  apt:
+    packages:
+      - iptables-dev
+      - libcap-dev
+      - libdbi-dev
+      - libhiredis-dev
+      - libnfnetlink-dev
+      - libnotify-dev
+      - libpcap-dev
+      - libperl-dev
+      - libprotobuf-c0-dev
+      - librrd-dev
+      - libsnmp-dev
+      - libudev-dev
+      - libvarnishapi-dev
+      - libyajl-dev
+      - linux-libc-dev
+      - protobuf-c-compiler
+language: c
+script: sh build.sh && ./configure && make distcheck
diff --git a/AUTHORS b/AUTHORS
index 3f63c3d..02b1256 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -78,6 +78,9 @@ Christophe Kalt <collectd at klb.taranis.org>
 Cyril Feraudet <cyril at feraudet.com>
  - ethstat plugin.
 
+Dagobert Michelsen <dam at opencsw.org>
+ - zone plugin.
+
 Dan Berrange <berrange at redhat.com>
  - uuid plugin.
 
@@ -174,6 +177,9 @@ Marco Chiappero <marco at absence.it>
  - ip6tables support in the iptables plugin.
  - openvpn plugin (support for more status file formats)
 
+Mathijs Möhlmann <collectd at mmrc.nl>
+ - zone plugin.
+
 Michael Hanselmann <public at hansmi.ch>
  - md plugin.
 
diff --git a/README b/README
index 3e2c023..ad5b667 100644 (file)
--- a/README
+++ b/README
@@ -191,6 +191,9 @@ Features
       Reads values from Modbus/TCP enabled devices. Supports reading values
       from multiple "slaves" so gateway devices can be used.
 
+    - mqtt
+      Publishes and subscribes to MQTT topics.
+
     - multimeter
       Information provided by serial multimeters, such as the `Metex
       M-4650CR'.
@@ -385,6 +388,10 @@ Features
     - zfs_arc
       Statistics for ZFS' “Adaptive Replacement Cache” (ARC).
 
+    - zone
+      Measures the percentage of cpu load per container (zone) under Solaris 10
+      and higher
+
     - zookeeper
       Read data from Zookeeper's MNTR command.
 
index 5c6a5f9..d927d13 100644 (file)
@@ -137,13 +137,13 @@ sub _parse_identifier
 
 sub _escape_argument
 {
-       local $_ = shift;
+    my $arg = shift;
 
-       return $_ if /^\w+$/;
+       return $arg if $arg =~ /^\w+$/;
 
-       s#\\#\\\\#g;
-       s#"#\\"#g;
-       return "\"$_\"";
+       $arg =~ s#\\#\\\\#g;
+       $arg =~ s#"#\\"#g;
+       return "\"$arg\"";
 }
 
 # Send a command on a socket, including any required argument escaping.
@@ -262,10 +262,11 @@ sub getthreshold # {{{
     $self->_socket_chat($msg, sub {
             local $_ = shift;
             my $ret = shift;
-                   /^\s*([^:]+):\s*(.*)/ and do {
-                           $1 =~ s/\s*$//;
-                           $ret->{$1} = $2;
-                   };
+            my ( $key, $val );
+            ( $key, $val ) = /^\s*([^:]+):\s*(.*)/ and do {
+                  $key =~ s/\s*$//;
+                  $ret->{$key} = $val;
+            };
         }, $ret
     );
        return $ret;
index 2f7818b..4e94f8e 100644 (file)
@@ -16,7 +16,7 @@ sub test_query {
     my ($nresults, $resultdata) = @$results;
     my $r = $s->getval(%{Collectd::Unixsock::_parse_identifier($attr)});
     is(ref $r, 'HASH', "Got a result for $attr");
-    is(scalar keys $r, $nresults, "$nresults result result for $attr");
+    is(scalar keys %$r, $nresults, "$nresults result result for $attr");
     is_deeply($r, $resultdata, "Data or $attr matches");
 }
 
index 7a81145..08496dc 100644 (file)
@@ -2719,6 +2719,53 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBMONGOC, test "x$with_libmongoc" = "xyes")
 # }}}
 
+# --with-libmosquitto {{{
+with_libmosquitto_cppflags=""
+with_libmosquitto_libs="-lmosquitto"
+AC_ARG_WITH(libmosquitto, [AS_HELP_STRING([--with-libmosquitto@<:@=PREFIX@:>@], [Path to libmosquitto.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               with_libmosquitto_cppflags="-I$withval/include"
+               with_libmosquitto_libs="-L$withval/lib -lmosquitto"
+               with_libmosquitto="yes"
+       else
+               with_libmosquitto="$withval"
+       fi
+],
+[
+       with_libmosquitto="yes"
+])
+if test "x$with_libmosquitto" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$with_libmosquitto_cppflags"
+
+       AC_CHECK_HEADERS(mosquitto.h, [with_libmosquitto="yes"], [with_libmosquitto="no (mosquitto.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libmosquitto" = "xyes"
+then
+       SAVE_LDFLAGS="$LDFLAGS"
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       LDFLAGS="$with_libmosquitto_libs"
+       CPPFLAGS="$with_libmosquitto_cppflags"
+
+       AC_CHECK_LIB(mosquitto, mosquitto_connect, [with_libmosquitto="yes"], [with_libmosquitto="no (libmosquitto not found)"])
+
+       LDFLAGS="$SAVE_LDFLAGS"
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libmosquitto" = "xyes"
+then
+       BUILD_WITH_LIBMOSQUITTO_CPPFLAGS="$with_libmosquitto_cppflags"
+       BUILD_WITH_LIBMOSQUITTO_LIBS="$with_libmosquitto_libs"
+       AC_SUBST(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBMOSQUITTO_LIBS)
+fi
+# }}}
+
 # --with-libmysql {{{
 with_mysql_config="mysql_config"
 with_mysql_cflags=""
@@ -5257,6 +5304,7 @@ collectd features:])
 AC_COLLECTD([debug],     [enable],  [feature], [debugging])
 AC_COLLECTD([daemon],    [disable], [feature], [daemon mode])
 AC_COLLECTD([getifaddrs],[enable],  [feature], [getifaddrs under Linux])
+AC_COLLECTD([werror],    [disable], [feature], [building with -Werror])
 
 dependency_warning="no"
 dependency_error="no"
@@ -5308,6 +5356,7 @@ plugin_vmem="no"
 plugin_vserver="no"
 plugin_wireless="no"
 plugin_zfs_arc="no"
+plugin_zone="no"
 plugin_zookeeper="no"
 
 # Linux
@@ -5378,6 +5427,7 @@ fi
 
 if test "x$ac_system" = "xFreeBSD"
 then
+       plugin_disk="yes"
        plugin_zfs_arc="yes"
 fi
 
@@ -5406,6 +5456,7 @@ then
        plugin_processes="yes"
        plugin_uptime="yes"
        plugin_zfs_arc="yes"
+       plugin_zone="yes"
 fi
 
 if test "x$with_devinfo$with_kstat" = "xyesyes"
@@ -5702,6 +5753,7 @@ AC_PLUGIN([memcached],   [yes],                [memcached statistics])
 AC_PLUGIN([memory],      [$plugin_memory],     [Memory usage])
 AC_PLUGIN([mic],         [$with_mic],          [Intel Many Integrated Core stats])
 AC_PLUGIN([modbus],      [$with_libmodbus],    [Modbus plugin])
+AC_PLUGIN([mqtt],        [$with_libmosquitto], [MQTT output plugin])
 AC_PLUGIN([multimeter],  [$plugin_multimeter], [Read multimeter values])
 AC_PLUGIN([mysql],       [$with_libmysql],     [MySQL statistics])
 AC_PLUGIN([netapp],      [$with_libnetapp],    [NetApp plugin])
@@ -5777,6 +5829,7 @@ AC_PLUGIN([write_sensu], [yes],                [Sensu output plugin])
 AC_PLUGIN([write_tsdb],  [yes],                [TSDB output plugin])
 AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
 AC_PLUGIN([zfs_arc],     [$plugin_zfs_arc],    [ZFS ARC statistics])
+AC_PLUGIN([zone],        [$plugin_zone],       [Solaris container statistics])
 AC_PLUGIN([zookeeper],   [yes],               [Zookeeper statistics])
 
 dnl Default configuration file
@@ -5928,6 +5981,13 @@ AC_SUBST(LCC_VERSION_STRING)
 
 AC_CONFIG_FILES(src/libcollectdclient/collectd/lcc_features.h)
 
+AM_CFLAGS="-Wall"
+if test "x$enable_werror" != "xno"
+then
+        AM_CFLAGS="$AM_CFLAGS -Werror"
+fi
+AC_SUBST([AM_CFLAGS])
+
 AC_CONFIG_FILES([Makefile src/Makefile src/daemon/Makefile src/collectd.conf src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile bindings/java/Makefile])
 AC_OUTPUT
 
@@ -5958,6 +6018,17 @@ fi
 cat <<EOF;
 
 Configuration:
+  Build:
+    Platform  . . . . . . $ac_system
+    CC  . . . . . . . . . $CC
+    CFLAGS  . . . . . . . $AM_CFLAGS $CFLAGS
+    CPP . . . . . . . . . $CPP
+    CPPFLAGS  . . . . . . $CPPFLAGS
+    LD  . . . . . . . . . $LD
+    LDFLAGS . . . . . . . $LDFLAGS
+    YACC  . . . . . . . . $YACC
+    YFLAGS  . . . . . . . $YFLAGS
+
   Libraries:
     intel mic . . . . . . $with_mic
     libaquaero5 . . . . . $with_libaquaero5
@@ -5982,6 +6053,7 @@ Configuration:
     libmnl  . . . . . . . $with_libmnl
     libmodbus . . . . . . $with_libmodbus
     libmongoc . . . . . . $with_libmongoc
+    libmosquitto  . . . . $with_libmosquitto
     libmysql  . . . . . . $with_libmysql
     libnetapp . . . . . . $with_libnetapp
     libnetsnmp  . . . . . $with_libnetsnmp
@@ -6082,6 +6154,7 @@ Configuration:
     memory  . . . . . . . $enable_memory
     mic . . . . . . . . . $enable_mic
     modbus  . . . . . . . $enable_modbus
+    mqtt  . . . . . . . . $enable_mqtt
     multimeter  . . . . . $enable_multimeter
     mysql . . . . . . . . $enable_mysql
     netapp  . . . . . . . $enable_netapp
@@ -6156,6 +6229,7 @@ Configuration:
     write_tsdb  . . . . . $enable_write_tsdb
     xmms  . . . . . . . . $enable_xmms
     zfs_arc . . . . . . . $enable_zfs_arc
+    zone  . . . . . . . . $enable_zone
     zookeeper . . . . . . $enable_zookeeper
 
 EOF
index 1ebf1f1..897d619 100644 (file)
@@ -65,11 +65,6 @@ file. That is very handy when you realise that you have bundled up DSes in one
 RRD-file that should have been in multiple RRD-files instead. Is is used by
 `migrate-3-4.px' to split up the cpu-, nfs-, swap-files and possibly others.
 
-fedora/
--------
-  Init-script and Spec-file that can be used when creating RPM-packages for
-Fedora.
-
 GenericJMX.conf
 ---------------
   Example configuration file for the ‘GenericJMX’ Java plugin. Please read the
diff --git a/contrib/collectd.service b/contrib/collectd.service
deleted file mode 100644 (file)
index ee4d596..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=statistics collection daemon
-Documentation=man:collectd(1)
-After=local-fs.target network.target
-Requires=local-fs.target network.target
-
-[Service]
-ExecStart=/usr/sbin/collectd -C /etc/collectd/collectd.conf -f
-Restart=always
-RestartSec=10
-StandardOutput=syslog
-StandardError=syslog
-
-[Install]
-WantedBy=multi-user.target
diff --git a/contrib/fedora/collectd.spec b/contrib/fedora/collectd.spec
deleted file mode 100644 (file)
index a35923c..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-Summary:       Statistics collection daemon for filling RRD files.
-Name:           collectd
-Version:       4.2.0
-Release:       1.fc6
-Source:                http://collectd.org/files/%{name}-%{version}.tar.gz
-License:       GPL
-Group:         System Environment/Daemons
-BuildRoot:     %{_tmppath}/%{name}-%{version}-root
-BuildPrereq:   lm_sensors-devel
-BuildPrereq:   mysql-devel
-BuildPrereq:   rrdtool-devel
-BuildPrereq:   net-snmp-devel
-Requires:      rrdtool
-Requires:      perl-Regexp-Common
-Packager:      Florian octo Forster <octo@verplant.org>
-Vendor:                Florian octo Forster <octo@verplant.org>
-
-%description
-collectd is a small daemon written in C for performance.  It reads various
-system  statistics  and updates  RRD files,  creating  them if neccessary.
-Since the daemon doesn't need to startup every time it wants to update the
-files it's very fast and easy on the system. Also, the statistics are very
-fine grained since the files are updated every 10 seconds.
-
-%package apache
-Summary:       apache-plugin for collectd.
-Group:         System Environment/Daemons
-Requires:      collectd = %{version}, curl
-%description apache
-This plugin collectd data provided by Apache's `mod_status'.
-
-%package email
-Summary:       email-plugin for collectd.
-Group:         System Environment/Daemons
-Requires:      collectd = %{version}, spamassassin
-%description email
-This plugin collectd data provided by spamassassin.
-
-%package mysql
-Summary:       mysql-module for collectd.
-Group:         System Environment/Daemons
-Requires:      collectd = %{version}, mysql
-%description mysql
-MySQL  querying  plugin.  This plugins  provides data of  issued commands,
-called handlers and database traffic.
-
-%package sensors
-Summary:       libsensors-module for collectd.
-Group:         System Environment/Daemons
-Requires:      collectd = %{version}, lm_sensors
-%description sensors
-This  plugin  for  collectd  provides  querying  of sensors  supported  by
-lm_sensors.
-
-%prep
-rm -rf $RPM_BUILD_ROOT
-%setup
-
-%build
-./configure --prefix=%{_prefix} --sbindir=%{_sbindir} --mandir=%{_mandir} --libdir=%{_libdir} --sysconfdir=%{_sysconfdir}
-make
-
-%install
-make install DESTDIR=$RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
-mkdir -p $RPM_BUILD_ROOT/var/www/cgi-bin
-cp src/collectd.conf $RPM_BUILD_ROOT/etc/collectd.conf
-cp contrib/fedora/init.d-collectd $RPM_BUILD_ROOT/etc/rc.d/init.d/collectd
-cp contrib/collection.cgi $RPM_BUILD_ROOT/var/www/cgi-bin
-cp contrib/collection.conf $RPM_BUILD_ROOT/etc/collection.conf
-mkdir -p $RPM_BUILD_ROOT/var/lib/collectd
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post
-/sbin/chkconfig --add collectd
-/sbin/chkconfig collectd on
-
-%preun
-if [ "$1" = 0 ]; then
-   /sbin/chkconfig collectd off
-   /etc/init.d/collectd stop
-   /sbin/chkconfig --del collectd
-fi
-exit 0
-
-%postun
-if [ "$1" -ge 1 ]; then
-    /etc/init.d/collectd restart
-fi
-exit 0
-
-%files
-%defattr(-,root,root)
-%doc AUTHORS COPYING ChangeLog INSTALL NEWS README
-%attr(0644,root,root) %config(noreplace) /etc/collectd.conf
-%attr(0644,root,root) %config(noreplace) /etc/collection.conf
-%attr(0755,root,root) /etc/rc.d/init.d/collectd
-%attr(0755,root,root) /var/www/cgi-bin/collection.cgi
-%attr(0755,root,root) %{_sbindir}/collectd
-%attr(0755,root,root) %{_bindir}/collectd-nagios
-%attr(0644,root,root) %{_mandir}/man1/*
-%attr(0644,root,root) %{_mandir}/man5/*
-
-%attr(0644,root,root) /usr/lib/perl5/5.8.8/i386-linux-thread-multi/perllocal.pod
-%attr(0644,root,root) /usr/lib/perl5/site_perl/5.8.8/Collectd.pm
-%attr(0644,root,root) /usr/lib/perl5/site_perl/5.8.8/Collectd/Unixsock.pm
-%attr(0644,root,root) /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/auto/Collectd/.packlist
-%attr(0644,root,root) %{_mandir}/man3/Collectd::Unixsock.3pm.gz
-
-%attr(0644,root,root) %{_libdir}/%{name}/apcups.so*
-%attr(0644,root,root) %{_libdir}/%{name}/apcups.la
-
-# FIXME!!!
-#%attr(0644,root,root) %{_libdir}/%{name}/apple_sensors.so*
-#%attr(0644,root,root) %{_libdir}/%{name}/apple_sensors.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/battery.so*
-%attr(0644,root,root) %{_libdir}/%{name}/battery.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/conntrack.so*
-%attr(0644,root,root) %{_libdir}/%{name}/conntrack.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/cpufreq.so*
-%attr(0644,root,root) %{_libdir}/%{name}/cpufreq.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/cpu.so*
-%attr(0644,root,root) %{_libdir}/%{name}/cpu.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/csv.so*
-%attr(0644,root,root) %{_libdir}/%{name}/csv.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/df.so*
-%attr(0644,root,root) %{_libdir}/%{name}/df.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/disk.so*
-%attr(0644,root,root) %{_libdir}/%{name}/disk.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/dns.so*
-%attr(0644,root,root) %{_libdir}/%{name}/dns.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/entropy.so*
-%attr(0644,root,root) %{_libdir}/%{name}/entropy.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/exec.so*
-%attr(0644,root,root) %{_libdir}/%{name}/exec.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/hddtemp.so*
-%attr(0644,root,root) %{_libdir}/%{name}/hddtemp.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/interface.so*
-%attr(0644,root,root) %{_libdir}/%{name}/interface.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/iptables.so*
-%attr(0644,root,root) %{_libdir}/%{name}/iptables.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/irq.so*
-%attr(0644,root,root) %{_libdir}/%{name}/irq.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/load.so*
-%attr(0644,root,root) %{_libdir}/%{name}/load.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/logfile.so*
-%attr(0644,root,root) %{_libdir}/%{name}/logfile.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/mbmon.so*
-%attr(0644,root,root) %{_libdir}/%{name}/mbmon.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/memcached.so*
-%attr(0644,root,root) %{_libdir}/%{name}/memcached.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/memory.so*
-%attr(0644,root,root) %{_libdir}/%{name}/memory.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/multimeter.so*
-%attr(0644,root,root) %{_libdir}/%{name}/multimeter.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/network.so*
-%attr(0644,root,root) %{_libdir}/%{name}/network.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/nfs.so*
-%attr(0644,root,root) %{_libdir}/%{name}/nfs.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/nginx.so*
-%attr(0644,root,root) %{_libdir}/%{name}/nginx.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/ntpd.so*
-%attr(0644,root,root) %{_libdir}/%{name}/ntpd.la
-
-# FIXME!!!
-#%attr(0644,root,root) %{_libdir}/%{name}/nut.so*
-#%attr(0644,root,root) %{_libdir}/%{name}/nut.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/perl.so*
-%attr(0644,root,root) %{_libdir}/%{name}/perl.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/ping.so*
-%attr(0644,root,root) %{_libdir}/%{name}/ping.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/processes.so*
-%attr(0644,root,root) %{_libdir}/%{name}/processes.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/rrdtool.so*
-%attr(0644,root,root) %{_libdir}/%{name}/rrdtool.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/serial.so*
-%attr(0644,root,root) %{_libdir}/%{name}/serial.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/swap.so*
-%attr(0644,root,root) %{_libdir}/%{name}/swap.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/snmp.so*
-%attr(0644,root,root) %{_libdir}/%{name}/snmp.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/syslog.so*
-%attr(0644,root,root) %{_libdir}/%{name}/syslog.la
-
-# FIXME!!!
-#%attr(0644,root,root) %{_libdir}/%{name}/tape.so*
-#%attr(0644,root,root) %{_libdir}/%{name}/tape.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/tcpconns.so*
-%attr(0644,root,root) %{_libdir}/%{name}/tcpconns.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/unixsock.so*
-%attr(0644,root,root) %{_libdir}/%{name}/unixsock.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/users.so*
-%attr(0644,root,root) %{_libdir}/%{name}/users.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/vserver.so*
-%attr(0644,root,root) %{_libdir}/%{name}/vserver.la
-
-%attr(0644,root,root) %{_libdir}/%{name}/wireless.so*
-%attr(0644,root,root) %{_libdir}/%{name}/wireless.la
-
-%attr(0644,root,root) %{_datadir}/%{name}/types.db
-
-%dir /var/lib/collectd
-
-%files apache
-%attr(0644,root,root) %{_libdir}/%{name}/apache.so*
-%attr(0644,root,root) %{_libdir}/%{name}/apache.la
-
-%files email
-%attr(0644,root,root) %{_libdir}/%{name}/email.so*
-%attr(0644,root,root) %{_libdir}/%{name}/email.la
-
-%files mysql
-%attr(0644,root,root) %{_libdir}/%{name}/mysql.so*
-%attr(0644,root,root) %{_libdir}/%{name}/mysql.la
-
-%files sensors
-%attr(0644,root,root) %{_libdir}/%{name}/sensors.so*
-%attr(0644,root,root) %{_libdir}/%{name}/sensors.la
-
-%changelog
-* Wed Oct 31 2007 Iain Lea <iain@bricbrac.de> 4.2.0
-- New major release
-- Changes to support 4.2.0 (ie. contrib/collection.conf)
-
-* Mon Aug 06 2007 Kjell Randa <Kjell.Randa@broadpark.no> 4.0.6
-- New upstream version
-
-* Wed Jul 25 2007 Kjell Randa <Kjell.Randa@broadpark.no> 4.0.5
-- New major release
-- Changes to support 4.0.5 
-
-* Wed Jan 11 2007 Iain Lea <iain@bricbrac.de> 3.11.0-0
-- fixed spec file to build correctly on fedora core
-- added improved init.d script to work with chkconfig
-- added %post and %postun to call chkconfig automatically
-
-* Sun Jul 09 2006 Florian octo Forster <octo@verplant.org> 3.10.0-1
-- New upstream version
-
-* Tue Jun 25 2006 Florian octo Forster <octo@verplant.org> 3.9.4-1
-- New upstream version
-
-* Tue Jun 01 2006 Florian octo Forster <octo@verplant.org> 3.9.3-1
-- New upstream version
-
-* Tue May 09 2006 Florian octo Forster <octo@verplant.org> 3.9.2-1
-- New upstream version
-
-* Tue May 09 2006 Florian octo Forster <octo@verplant.org> 3.8.5-1
-- New upstream version
-
-* Fri Apr 21 2006 Florian octo Forster <octo@verplant.org> 3.9.1-1
-- New upstream version
-
-* Fri Apr 14 2006 Florian octo Forster <octo@verplant.org> 3.9.0-1
-- New upstream version
-- Added the `apache' package.
-
-* Thu Mar 14 2006 Florian octo Forster <octo@verplant.org> 3.8.2-1
-- New upstream version
-
-* Thu Mar 13 2006 Florian octo Forster <octo@verplant.org> 3.8.1-1
-- New upstream version
-
-* Thu Mar 09 2006 Florian octo Forster <octo@verplant.org> 3.8.0-1
-- New upstream version
-
-* Sat Feb 18 2006 Florian octo Forster <octo@verplant.org> 3.7.2-1
-- Include `tape.so' so the build doesn't terminate because of missing files..
-- New upstream version
-
-* Sat Feb 04 2006 Florian octo Forster <octo@verplant.org> 3.7.1-1
-- New upstream version
-
-* Mon Jan 30 2006 Florian octo Forster <octo@verplant.org> 3.7.0-1
-- New upstream version
-- Removed the extra `hddtemp' package
-
-* Tue Jan 24 2006 Florian octo Forster <octo@verplant.org> 3.6.2-1
-- New upstream version
-
-* Fri Jan 20 2006 Florian octo Forster <octo@verplant.org> 3.6.1-1
-- New upstream version
-
-* Fri Jan 20 2006 Florian octo Forster <octo@verplant.org> 3.6.0-1
-- New upstream version
-- Added config file, `collectd.conf(5)', `df.so'
-- Added package `collectd-mysql', dependency on `mysqlclient10 | mysql'
-
-* Wed Dec 07 2005 Florian octo Forster <octo@verplant.org> 3.5.0-1
-- New upstream version
-
-* Sat Nov 26 2005 Florian octo Forster <octo@verplant.org> 3.4.0-1
-- New upstream version
-
-* Sat Nov 05 2005 Florian octo Forster <octo@verplant.org> 3.3.0-1
-- New upstream version
-
-* Tue Oct 26 2005 Florian octo Forster <octo@verplant.org> 3.2.0-1
-- New upstream version
-- Added statement to remove the `*.la' files. This fixes a problem when
-  `Unpackaged files terminate build' is in effect.
-- Added `processes.so*' to the main package
-
-* Fri Oct 14 2005 Florian octo Forster <octo@verplant.org> 3.1.0-1
-- New upstream version
-- Added package `collectd-hddtemp'
-
-* Fri Sep 30 2005 Florian octo Forster <octo@verplant.org> 3.0.0-1
-- New upstream version
-- Split the package into `collectd' and `collectd-sensors'
-
-* Fri Sep 16 2005 Florian octo Forster <octo@verplant.org> 2.1.0-1
-- New upstream version
-
-* Mon Sep 10 2005 Florian octo Forster <octo@verplant.org> 2.0.0-1
-- New upstream version
-
-* Mon Aug 29 2005 Florian octo Forster <octo@verplant.org> 1.8.0-1
-- New upstream version
-
-* Sun Aug 25 2005 Florian octo Forster <octo@verplant.org> 1.7.0-1
-- New upstream version
-
-* Sun Aug 21 2005 Florian octo Forster <octo@verplant.org> 1.6.0-1
-- New upstream version
-
-* Sun Jul 17 2005 Florian octo Forster <octo@verplant.org> 1.5.1-1
-- New upstream version
-
-* Sun Jul 17 2005 Florian octo Forster <octo@verplant.org> 1.5-1
-- New upstream version
-
-* Mon Jul 11 2005 Florian octo Forster <octo@verplant.org> 1.4.2-1
-- New upstream version
-
-* Sat Jul 09 2005 Florian octo Forster <octo@verplant.org> 1.4-1
-- Built on RedHat 7.3
diff --git a/contrib/fedora/init.d-collectd b/contrib/fedora/init.d-collectd
deleted file mode 100644 (file)
index ea8662a..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/bin/bash
-#
-# collectd    Startup script for the Collectd statistics gathering daemon
-# chkconfig: - 86 15
-# description: Collectd is a statistics gathering daemon used to collect \
-#   system information ie. cpu, memory, disk, network
-# processname: collectd
-# config: /etc/collectd.conf
-# config: /etc/sysconfig/collectd
-# pidfile: /var/run/collectd.pid
-
-# Source function library.
-. /etc/init.d/functions
-
-RETVAL=0
-ARGS=""
-prog="collectd"
-CONFIG=/etc/collectd.conf
-
-if [ -r /etc/default/$prog ]; then
-       . /etc/default/$prog
-fi
-
-start () {
-       echo -n $"Starting $prog: "
-       if [ -r "$CONFIG" ]
-       then
-               daemon /usr/sbin/collectd -C "$CONFIG"
-               RETVAL=$?
-               echo
-               [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
-       fi
-}
-stop () {
-       echo -n $"Stopping $prog: "
-       killproc $prog
-       RETVAL=$?
-       echo
-       [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
-}
-# See how we were called.
-case "$1" in
-  start)
-       start
-       ;;
-  stop)
-       stop
-       ;;
-  status)
-       status $prog
-       ;;
-  restart|reload)
-       stop
-       start
-       ;;
-  condrestart)
-       [ -f /var/lock/subsys/$prog ] && stop && start || :
-       ;;
-  *)
-       echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
-       exit 1
-esac
-
-exit $?
-
-# vim:syntax=sh
index 9d491ff..2252181 100644 (file)
@@ -68,6 +68,7 @@
 %{?el7:%global _has_atasmart 1}
 %{?el7:%global _has_hiredis 1}
 %{?el7:%global _has_asm_msr_index 1}
+%{?el7:%global _has_libmosquitto 1}
 
 # plugins enabled by default
 %define with_aggregation 0%{!?_without_aggregation:1}
 %define with_memory 0%{!?_without_memory:1}
 %define with_multimeter 0%{!?_without_multimeter:1}
 %define with_modbus 0%{!?_without_modbus:0%{?_has_libmodbus}}
+%define with_mqtt 0%{!?_without_mqtt:0%{?_has_libmosquitto}}
 %define with_mysql 0%{!?_without_mysql:1}
 %define with_netlink 0%{!?_without_netlink:0%{?_has_iproute}}
 %define with_network 0%{!?_without_network:1}
 %define with_write_mongodb 0%{!?_without_write_mongodb:0}
 # plugin xmms disabled, requires xmms
 %define with_xmms 0%{!?_without_xmms:0}
+# plugin zone disabled, requires Solaris
+%define with_zone 0%{!?_without_zone:0}
 
 Summary:       statistics collection and monitoring daemon
 Name:          collectd
@@ -514,6 +518,16 @@ MySQL querying plugin. This plugin provides data of issued commands, called
 handlers and database traffic.
 %endif
 
+%if %{with_mqtt}
+%package mqtt
+Summary:       mqtt plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: mosquitto-devel
+%description mqtt
+The MQTT plugin publishes and subscribes to MQTT topics.
+%endif
+
 %if %{with_netlink}
 %package netlink
 Summary:       netlink plugin for collectd
@@ -1165,6 +1179,12 @@ Collectd utilities
 %define _with_multimeter --disable-multimeter
 %endif
 
+%if %{with_mqtt}
+%define _with_mqtt --enable-mqtt
+%else
+%define _with_mqtt --disable-mqtt
+%endif
+
 %if %{with_mysql}
 %define _with_mysql --enable-mysql
 %else
@@ -1571,6 +1591,12 @@ Collectd utilities
 %define _with_zfs_arc --disable-zfs_arc
 %endif
 
+%if %{with_zone}
+%define _with_zone --enable-zone
+%else
+%define _with_zone --disable-zone
+%endif
+
 %if %{with_zookeeper}
 %define _with_zookeeper --enable-zookeeper
 %else
@@ -1639,6 +1665,7 @@ Collectd utilities
        %{?_with_mic} \
        %{?_with_modbus} \
        %{?_with_multimeter} \
+       %{?_with_mqtt} \
        %{?_with_mysql} \
        %{?_with_netapp} \
        %{?_with_netlink} \
@@ -1672,6 +1699,7 @@ Collectd utilities
        %{?_with_write_redis} \
        %{?_with_xmms} \
        %{?_with_zfs_arc} \
+       %{?_with_zone} \
        %{?_with_zookeeper} \
        %{?_with_irq} \
        %{?_with_load} \
@@ -2196,6 +2224,11 @@ fi
 %{_libdir}/%{name}/modbus.so
 %endif
 
+%if %{with_mqtt}
+%files mqtt
+%{_libdir}/%{name}/mqtt.so
+%endif
+
 %if %{with_mysql}
 %files mysql
 %{_libdir}/%{name}/mysql.so
@@ -2335,6 +2368,11 @@ fi
 %doc contrib/
 
 %changelog
+#* TODO: next feature release changelog
+#- New upstream version
+#- New plugins enabled by default: mqtt
+#- New plugins disabled by default: zone
+#
 * Wed May 27 2015 Marc Fournier <marc.fournier@camptocamp.com> 5.5.0-1
 - New upstream version
 - New plugins enabled by default: ceph, drbd, log_logstash, write_tsdb, smart,
index b046192..0e758e4 100644 (file)
@@ -5,19 +5,26 @@ Requires=local-fs.target network.target
 
 [Service]
 ExecStart=/usr/sbin/collectd
+EnvironmentFile=-/etc/sysconfig/collectd
+EnvironmentFile=-/etc/default/collectd
+ProtectSystem=full
+ProtectHome=true
+
+# drop all capabilities:
+CapabilityBoundingSet=
+# use this instead if you use the dns or ping plugin
+#CapabilityBoundingSet=CAP_NET_RAW
+# turn this on if you use the iptables next to the dns or ping plugin
+#CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
+
+NoNewPrivileges=true
 
 # Tell systemd it will receive a notification from collectd over it's control
 # socket once the daemon is ready. See systemd.service(5) for more details.
 Type=notify
-NotifyAccess=main
 
 # Restart the collectd daemon after a 10 seconds delay, in case it crashes.
-Restart=always
-RestartSec=10
-
-# Send all console messages to syslog.
-StandardOutput=syslog
-StandardError=syslog
+Restart=on-failure
 
 [Install]
 WantedBy=multi-user.target
index 2848ebd..fa3f473 100644 (file)
@@ -6,10 +6,6 @@ SUBDIRS += daemon
 
 PLUGIN_LDFLAGS = -module -avoid-version -export-symbols-regex '\<module_register\>'
 
-if COMPILER_IS_GCC
-AM_CFLAGS = -Wall -Werror
-endif
-
 AM_CPPFLAGS = -I$(srcdir)/daemon
 AM_CPPFLAGS += -DPREFIX='"${prefix}"'
 AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
@@ -23,13 +19,37 @@ AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
 
 AUTOMAKE_OPTIONS = subdir-objects
 
-noinst_LTLIBRARIES = libmount.la liblookup.la
+noinst_LTLIBRARIES =
+check_PROGRAMS =
+TESTS =
 
-libmount_la_SOURCES = utils_mount.c utils_mount.h
-libmount_la_LIBADD = daemon/libcommon.la
+noinst_LTLIBRARIES += liblatency.la
+liblatency_la_SOURCES = utils_latency.c utils_latency.h
+check_PROGRAMS += test_utils_latency
+TESTS += test_utils_latency
+test_utils_latency_SOURCES = utils_latency_test.c testing.h
+test_utils_latency_LDADD = liblatency.la daemon/libcommon.la daemon/libplugin_mock.la -lm
 
+noinst_LTLIBRARIES += liblookup.la
 liblookup_la_SOURCES = utils_vl_lookup.c utils_vl_lookup.h
-liblookup_la_LIBADD = daemon/libavltree.la daemon/libcommon.la
+liblookup_la_LIBADD = daemon/libavltree.la
+check_PROGRAMS += test_utils_vl_lookup
+TESTS += test_utils_vl_lookup
+test_utils_vl_lookup_SOURCES = utils_vl_lookup_test.c testing.h
+test_utils_vl_lookup_LDADD = liblookup.la daemon/libcommon.la daemon/libplugin_mock.la
+if BUILD_WITH_LIBKSTAT
+test_utils_vl_lookup_LDADD += -lkstat
+endif
+
+noinst_LTLIBRARIES += libmount.la
+libmount_la_SOURCES = utils_mount.c utils_mount.h
+check_PROGRAMS += test_utils_mount
+TESTS += test_utils_mount
+test_utils_mount_SOURCES = utils_mount_test.c testing.h
+test_utils_mount_LDADD = libmount.la daemon/libcommon.la daemon/libplugin_mock.la
+if BUILD_WITH_LIBKSTAT
+test_utils_mount_LDADD += -lkstat
+endif
 
 sbin_PROGRAMS = collectdmon
 bin_PROGRAMS = collectd-nagios collectdctl collectd-tg
@@ -64,7 +84,8 @@ collectdctl_LDADD += libcollectdclient/libcollectdclient.la
 collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
 
 collectd_tg_SOURCES = collectd-tg.c
-collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/libcollectdclient/collectd -I$(top_builddir)/src/libcollectdclient/collectd
+collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) \
+                      -I$(top_srcdir)/src/libcollectdclient/collectd -I$(top_builddir)/src/libcollectdclient/collectd
 collectd_tg_LDADD = daemon/libheap.la
 if BUILD_WITH_LIBSOCKET
 collectd_tg_LDADD += -lsocket
@@ -190,8 +211,7 @@ endif
 
 if BUILD_PLUGIN_CGROUPS
 pkglib_LTLIBRARIES += cgroups.la
-cgroups_la_SOURCES = cgroups.c \
-                    utils_ignorelist.c utils_ignorelist.h
+cgroups_la_SOURCES = cgroups.c
 cgroups_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 cgroups_la_LIBADD = libmount.la
 endif
@@ -290,16 +310,14 @@ endif
 
 if BUILD_PLUGIN_DF
 pkglib_LTLIBRARIES += df.la
-df_la_SOURCES = df.c \
-               utils_ignorelist.c utils_ignorelist.h
+df_la_SOURCES = df.c
 df_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 df_la_LIBADD = libmount.la
 endif
 
 if BUILD_PLUGIN_DISK
 pkglib_LTLIBRARIES += disk.la
-disk_la_SOURCES = disk.c \
-                 utils_ignorelist.c utils_ignorelist.h
+disk_la_SOURCES = disk.c
 disk_la_CFLAGS = $(AM_CFLAGS)
 disk_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 disk_la_LIBADD =
@@ -319,6 +337,9 @@ endif
 if BUILD_WITH_LIBUDEV
 disk_la_LIBADD += -ludev
 endif
+if BUILD_FREEBSD
+disk_la_LIBADD += -ldevstat -lgeom
+endif
 if BUILD_WITH_PERFSTAT
 disk_la_LIBADD += -lperfstat
 endif
@@ -407,8 +428,7 @@ endif
 
 if BUILD_PLUGIN_INTERFACE
 pkglib_LTLIBRARIES += interface.la
-interface_la_SOURCES = interface.c \
-                      utils_ignorelist.c utils_ignorelist.h
+interface_la_SOURCES = interface.c
 interface_la_CFLAGS = $(AM_CFLAGS)
 interface_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 interface_la_LIBADD =
@@ -445,8 +465,7 @@ endif
 
 if BUILD_PLUGIN_IPMI
 pkglib_LTLIBRARIES += ipmi.la
-ipmi_la_SOURCES = ipmi.c \
-                 utils_ignorelist.c utils_ignorelist.h
+ipmi_la_SOURCES = ipmi.c
 ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
 ipmi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
@@ -457,14 +476,15 @@ pkglib_LTLIBRARIES += ipvs.la
 ipvs_la_SOURCES = ipvs.c
 if IP_VS_H_NEEDS_KERNEL_CFLAGS
 ipvs_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
+else
+ipvs_la_CFLAGS = $(AM_CFLAGS)
 endif
 ipvs_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
 if BUILD_PLUGIN_IRQ
 pkglib_LTLIBRARIES += irq.la
-irq_la_SOURCES = irq.c \
-                utils_ignorelist.c utils_ignorelist.h
+irq_la_SOURCES = irq.c
 irq_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
@@ -523,8 +543,7 @@ endif
 
 if BUILD_PLUGIN_MADWIFI
 pkglib_LTLIBRARIES += madwifi.la
-madwifi_la_SOURCES = madwifi.c madwifi.h \
-                    utils_ignorelist.c utils_ignorelist.h
+madwifi_la_SOURCES = madwifi.c madwifi.h
 madwifi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
@@ -570,8 +589,7 @@ endif
 
 if BUILD_PLUGIN_MD
 pkglib_LTLIBRARIES += md.la
-md_la_SOURCES = md.c \
-               utils_ignorelist.c utils_ignorelist.h
+md_la_SOURCES = md.c
 md_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
@@ -616,8 +634,7 @@ endif
 
 if BUILD_PLUGIN_MIC
 pkglib_LTLIBRARIES += mic.la
-mic_la_SOURCES = mic.c \
-                utils_ignorelist.c utils_ignorelist.h
+mic_la_SOURCES = mic.c
 mic_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_MIC_LIBPATH)
 mic_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
 mic_la_LIBADD = $(BUILD_WITH_MIC_LDADD)
@@ -631,6 +648,14 @@ modbus_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMODBUS_CFLAGS)
 modbus_la_LIBADD = $(BUILD_WITH_LIBMODBUS_LIBS)
 endif
 
+if BUILD_PLUGIN_MQTT
+pkglib_LTLIBRARIES += mqtt.la
+mqtt_la_SOURCES = mqtt.c
+mqtt_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+mqtt_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
+mqtt_la_LIBADD = $(BUILD_WITH_LIBMOSQUITTO_LIBS)
+endif
+
 if BUILD_PLUGIN_MULTIMETER
 pkglib_LTLIBRARIES += multimeter.la
 multimeter_la_SOURCES = multimeter.c
@@ -651,8 +676,7 @@ endif
 
 if BUILD_PLUGIN_NETAPP
 pkglib_LTLIBRARIES += netapp.la
-netapp_la_SOURCES = netapp.c \
-                   utils_ignorelist.c utils_ignorelist.h
+netapp_la_SOURCES = netapp.c
 netapp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBNETAPP_CPPFLAGS)
 netapp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBNETAPP_LDFLAGS)
 netapp_la_LIBADD = $(LIBNETAPP_LIBS)
@@ -758,8 +782,7 @@ endif
 
 if BUILD_PLUGIN_ONEWIRE
 pkglib_LTLIBRARIES += onewire.la
-onewire_la_SOURCES = onewire.c \
-                    utils_ignorelist.c utils_ignorelist.h
+onewire_la_SOURCES = onewire.c
 onewire_la_CFLAGS = $(AM_CFLAGS)
 onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
 onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
@@ -872,8 +895,7 @@ endif
 
 if BUILD_PLUGIN_PROTOCOLS
 pkglib_LTLIBRARIES += protocols.la
-protocols_la_SOURCES = protocols.c \
-                      utils_ignorelist.c utils_ignorelist.h
+protocols_la_SOURCES = protocols.c
 protocols_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
@@ -911,8 +933,7 @@ endif
 
 if BUILD_PLUGIN_SENSORS
 pkglib_LTLIBRARIES += sensors.la
-sensors_la_SOURCES = sensors.c \
-                    utils_ignorelist.c utils_ignorelist.h
+sensors_la_SOURCES = sensors.c
 sensors_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSENSORS_CFLAGS)
 sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBSENSORS_LDFLAGS)
 sensors_la_LIBADD = -lsensors
@@ -935,8 +956,7 @@ endif
 if BUILD_PLUGIN_SMART
 if BUILD_WITH_LIBUDEV
 pkglib_LTLIBRARIES += smart.la
-smart_la_SOURCES = smart.c \
-                  utils_ignorelist.c utils_ignorelist.h
+smart_la_SOURCES = smart.c
 smart_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBATASMART_CPPFLAGS)
 smart_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBATASMART_LDFLAGS)
 smart_la_LIBADD = $(BUILD_WITH_LIBATASMART_LIBS) -ludev
@@ -960,10 +980,9 @@ endif
 
 if BUILD_PLUGIN_STATSD
 pkglib_LTLIBRARIES += statsd.la
-statsd_la_SOURCES = statsd.c \
-                    utils_latency.h utils_latency.c
+statsd_la_SOURCES = statsd.c
 statsd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-statsd_la_LIBADD = -lpthread -lm
+statsd_la_LIBADD = liblatency.la -lpthread -lm
 endif
 
 if BUILD_PLUGIN_SWAP
@@ -1076,8 +1095,7 @@ endif
 
 if BUILD_PLUGIN_THERMAL
 pkglib_LTLIBRARIES += thermal.la
-thermal_la_SOURCES = thermal.c \
-                    utils_ignorelist.c utils_ignorelist.h
+thermal_la_SOURCES = thermal.c
 thermal_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
@@ -1162,8 +1180,7 @@ endif
 
 if BUILD_PLUGIN_VIRT
 pkglib_LTLIBRARIES += virt.la
-virt_la_SOURCES = virt.c \
-                 utils_ignorelist.c utils_ignorelist.h
+virt_la_SOURCES = virt.c
 virt_la_CFLAGS = $(AM_CFLAGS) \
                $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
 virt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
@@ -1297,6 +1314,13 @@ endif
 
 BUILT_SOURCES += $(dist_man_MANS)
 
+if BUILD_PLUGIN_ZONE
+pkglib_LTLIBRARIES += zone.la
+zone_la_SOURCES = zone.c
+zone_la_CFLAGS = $(AM_CFLAGS)
+zone_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
 dist_man_MANS = collectd.1 \
                collectd.conf.5 \
                collectd-email.5 \
@@ -1390,12 +1414,4 @@ uninstall-hook:
        rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
        rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
 
-check_PROGRAMS = test_utils_mount test_utils_vl_lookup
-
-test_utils_mount_SOURCES = utils_mount_test.c testing.h
-test_utils_mount_LDADD = libmount.la daemon/libplugin_mock.la
-
-test_utils_vl_lookup_SOURCES = utils_vl_lookup_test.c testing.h
-test_utils_vl_lookup_LDADD = liblookup.la daemon/libplugin_mock.la
 
-TESTS = test_utils_mount test_utils_vl_lookup
index 8910675..41b807a 100644 (file)
@@ -255,7 +255,7 @@ static int config_add (oconfig_item_t *ci)
                status = plugin_register_complex_read (/* group = */ NULL,
                                /* name      = */ callback_name,
                                /* callback  = */ apache_read_host,
-                               /* interval  = */ NULL,
+                               /* interval  = */ 0,
                                /* user_data = */ &ud);
        }
 
@@ -383,8 +383,7 @@ static int init_host (apache_t *st) /* {{{ */
        if (st->timeout >= 0)
                curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) st->timeout);
        else
-               curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS,
-                               CDTIME_T_TO_MS(plugin_get_interval()));
+               curl_easy_setopt (st->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
        return (0);
index be7673c..29d58c3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * collectd - src/apcups.c
- * Copyright (C) 2006-2012  Florian octo Forster
+ * Copyright (C) 2006-2015  Florian octo Forster
  * Copyright (C) 2006       Anthony Gialluca <tonyabg at charter.net>
  * Copyright (C) 2000-2004  Kern Sibbald
  * Copyright (C) 1996-1999  Andre M. Hedrick <andre at suse.com>
@@ -32,9 +32,6 @@
 #if HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NETDB_H
 # include <netdb.h>
 #endif
 # include <netinet/in.h>
 #endif
 
-#define NISPORT 3551
-#define MAXSTRING               256
-#define MODULE_NAME "apcups"
+#ifndef APCUPS_DEFAULT_NODE
+# define APCUPS_DEFAULT_NODE "localhost"
+#endif
 
-#define APCUPS_DEFAULT_HOST "localhost"
+#ifndef APCUPS_DEFAULT_SERVICE
+# define APCUPS_DEFAULT_SERVICE "3551"
+#endif
 
 /*
  * Private data types
@@ -68,24 +67,16 @@ struct apc_detail_s
  * Private variables
  */
 /* Default values for contacting daemon */
-static char *conf_host = NULL;
-static int   conf_port = NISPORT;
+static char *conf_node = NULL;
+static char *conf_service = NULL;
 /* Defaults to false for backwards compatibility. */
 static _Bool conf_report_seconds = 0;
+static _Bool conf_persistent_conn = 1;
 
 static int global_sockfd = -1;
 
 static int count_retries = 0;
 static int count_iterations = 0;
-static _Bool close_socket = 0;
-
-static const char *config_keys[] =
-{
-       "Host",
-       "Port",
-       "ReportSeconds"
-};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 static int net_shutdown (int *fd)
 {
@@ -116,30 +107,25 @@ static int apcups_shutdown (void)
  * Returns -1 on error
  * Returns socket file descriptor otherwise
  */
-static int net_open (char *host, int port)
+static int net_open (char const *node, char const *service)
 {
        int              sd;
        int              status;
-       char             port_str[8];
        struct addrinfo  ai_hints;
        struct addrinfo *ai_return;
        struct addrinfo *ai_list;
 
-       assert ((port > 0x00000000) && (port <= 0x0000FFFF));
-
-       /* Convert the port to a string */
-       ssnprintf (port_str, sizeof (port_str), "%i", port);
-
        /* Resolve name */
-       memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
-       ai_hints.ai_family   = AF_INET; /* XXX: Change this to `AF_UNSPEC' if apcupsd can handle IPv6 */
+       memset (&ai_hints, 0, sizeof (ai_hints));
+       /* TODO: Change this to `AF_UNSPEC' if apcupsd can handle IPv6 */
+       ai_hints.ai_family   = AF_INET;
        ai_hints.ai_socktype = SOCK_STREAM;
 
-       status = getaddrinfo (host, port_str, &ai_hints, &ai_return);
+       status = getaddrinfo (node, service, &ai_hints, &ai_return);
        if (status != 0)
        {
                char errbuf[1024];
-               INFO ("getaddrinfo failed: %s",
+               INFO ("apcups plugin: getaddrinfo failed: %s",
                                (status == EAI_SYSTEM)
                                ? sstrerror (errno, errbuf, sizeof (errbuf))
                                : gai_strerror (status));
@@ -158,7 +144,7 @@ static int net_open (char *host, int port)
 
        if (sd < 0)
        {
-               DEBUG ("Unable to open a socket");
+               DEBUG ("apcups plugin: Unable to open a socket");
                freeaddrinfo (ai_return);
                return (-1);
        }
@@ -170,16 +156,16 @@ static int net_open (char *host, int port)
        if (status != 0) /* `connect(2)' failed */
        {
                char errbuf[1024];
-               INFO ("connect failed: %s",
+               INFO ("apcups plugin: connect failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                close (sd);
                return (-1);
        }
 
-       DEBUG ("Done opening a socket %i", sd);
+       DEBUG ("apcups plugin: Done opening a socket %i", sd);
 
        return (sd);
-} /* int net_open (char *host, char *service, int port) */
+} /* int net_open */
 
 /*
  * Receive a message from the other end. Each message consists of
@@ -263,7 +249,7 @@ static int net_send (int *sockfd, char *buff, int len)
 }
 
 /* Get and print status from apcupsd NIS server */
-static int apc_query_server (char *host, int port,
+static int apc_query_server (char const *node, char const *service,
                struct apc_detail_s *apcups_detail)
 {
        int     n;
@@ -285,7 +271,7 @@ static int apc_query_server (char *host, int port,
        {
                if (global_sockfd < 0)
                {
-                       global_sockfd = net_open (host, port);
+                       global_sockfd = net_open (node, service);
                        if (global_sockfd < 0)
                        {
                                ERROR ("apcups plugin: Connecting to the "
@@ -325,17 +311,20 @@ static int apc_query_server (char *host, int port,
                                "first %i iterations. Will close the socket "
                                "in future iterations.",
                                count_retries, count_iterations);
-               close_socket = 1;
+               conf_persistent_conn = 0;
        }
 
        while ((n = net_recv (&global_sockfd, recvline, sizeof (recvline) - 1)) > 0)
        {
-               assert ((unsigned int)n < sizeof (recvline));
-               recvline[n] = '\0';
+               assert ((size_t)n < sizeof (recvline));
+               recvline[n] = 0;
 #if APCMAIN
                printf ("net_recv = `%s';\n", recvline);
 #endif /* if APCMAIN */
 
+               if (strncmp ("END APC", recvline, strlen ("END APC")) == 0)
+                       break;
+
                toksaveptr = NULL;
                tokptr = strtok_r (recvline, " :\t", &toksaveptr);
                while (tokptr != NULL)
@@ -375,7 +364,7 @@ static int apc_query_server (char *host, int port,
        }
        status = errno; /* save errno, net_shutdown() may re-set it. */
 
-       if (close_socket)
+       if (!conf_persistent_conn)
                net_shutdown (&global_sockfd);
 
        if (n < 0)
@@ -389,41 +378,28 @@ static int apc_query_server (char *host, int port,
        return (0);
 }
 
-static int apcups_config (const char *key, const char *value)
+static int apcups_config (oconfig_item_t *ci)
 {
-       if (strcasecmp (key, "host") == 0)
-       {
-               if (conf_host != NULL)
-               {
-                       free (conf_host);
-                       conf_host = NULL;
-               }
-               if ((conf_host = strdup (value)) == NULL)
-                       return (1);
-       }
-       else if (strcasecmp (key, "Port") == 0)
-       {
-               int port_tmp = atoi (value);
-               if (port_tmp < 1 || port_tmp > 65535)
-               {
-                       WARNING ("apcups plugin: Invalid port: %i", port_tmp);
-                       return (1);
-               }
-               conf_port = port_tmp;
-       }
-       else if (strcasecmp (key, "ReportSeconds") == 0)
+       int i;
+
+       for (i = 0; i < ci->children_num; i++)
        {
-               if (IS_TRUE (value))
-                       conf_report_seconds = 1;
+               oconfig_item_t *child = ci->children + i;
+
+               if (strcasecmp (child->key, "Host") == 0)
+                       cf_util_get_string (child, &conf_node);
+               else if (strcasecmp (child->key, "Port") == 0)
+                       cf_util_get_service (child, &conf_service);
+               else if (strcasecmp (child->key, "ReportSeconds") == 0)
+                       cf_util_get_boolean (child, &conf_report_seconds);
+               else if (strcasecmp (child->key, "PersistentConnection") == 0)
+                       cf_util_get_boolean (child, &conf_persistent_conn);
                else
-                       conf_report_seconds = 0;
-       }
-       else
-       {
-               return (-1);
+                       ERROR ("apcups plugin: Unknown config option \"%s\".", child->key);
        }
+
        return (0);
-}
+} /* int apcups_config */
 
 static void apc_submit_generic (char *type, char *type_inst, double value)
 {
@@ -469,10 +445,9 @@ static int apcups_read (void)
        apcups_detail.itemp    = -300.0;
        apcups_detail.linefreq =   -1.0;
 
-       status = apc_query_server (conf_host == NULL
-                       ? APCUPS_DEFAULT_HOST
-                       : conf_host,
-                       conf_port, &apcups_detail);
+       status = apc_query_server ((conf_node == NULL) ? APCUPS_DEFAULT_NODE : conf_node,
+                       (conf_service == NULL) ? APCUPS_DEFAULT_SERVICE : conf_service,
+                       &apcups_detail);
 
        /*
         * if we did not connect then do not bother submitting
@@ -480,11 +455,10 @@ static int apcups_read (void)
         */
        if (status != 0)
        {
-               DEBUG ("apc_query_server (%s, %i) = %i",
-                               conf_host == NULL
-                               ? APCUPS_DEFAULT_HOST
-                               : conf_host,
-                               conf_port, status);
+               DEBUG ("apcups plugin: apc_query_server (%s, %s) = %i",
+                               (conf_node == NULL) ? APCUPS_DEFAULT_NODE : conf_node,
+                               (conf_service == NULL) ? APCUPS_DEFAULT_SERVICE : conf_service,
+                               status);
                return (-1);
        }
 
@@ -495,8 +469,7 @@ static int apcups_read (void)
 
 void module_register (void)
 {
-       plugin_register_config ("apcups", apcups_config, config_keys,
-                       config_keys_num);
+       plugin_register_complex_config ("apcups", apcups_config);
        plugin_register_read ("apcups", apcups_read);
        plugin_register_shutdown ("apcups", apcups_shutdown);
 } /* void module_register */
index 11175af..2ba3c77 100644 (file)
@@ -594,8 +594,7 @@ static int ascent_init (void) /* {{{ */
   if (timeout != NULL)
     curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, atol(timeout));
   else
-    curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS,
-       CDTIME_T_TO_MS(plugin_get_interval()));
+    curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
   return (0);
index a6d9835..c5e7f77 100644 (file)
@@ -407,7 +407,7 @@ static int get_reference_temperature(double * result)
 
     gauge_t * values = NULL;   /**< rate values */
     size_t    values_num = 0;  /**< number of rate values */
-    int i;
+    size_t i;
 
     gauge_t values_history[REF_TEMP_AVG_NUM];
 
@@ -447,9 +447,8 @@ static int get_reference_temperature(double * result)
 
             for(i=0; i<values_num; ++i)
             {
-                DEBUG ("barometer: get_reference_temperature - rate %d: %lf **",
-                       i,
-                       values[i]);
+                DEBUG ("barometer: get_reference_temperature - rate %zu: %lf **",
+                       i, values[i]);
                 if(!isnan(values[i]))
                 {
                     avg_sum += values[i];
@@ -477,9 +476,8 @@ static int get_reference_temperature(double * result)
             
         for(i=0; i<REF_TEMP_AVG_NUM*list->num_values; ++i)
         {
-            DEBUG ("barometer: get_reference_temperature - history %d: %lf",
-                   i,
-                   values_history[i]);
+            DEBUG ("barometer: get_reference_temperature - history %zu: %lf",
+                   i, values_history[i]);
             if(!isnan(values_history[i]))
             {
                 avg_sum += values_history[i];
@@ -503,9 +501,8 @@ static int get_reference_temperature(double * result)
 
             for(i=0; i<values_num; ++i)
             {
-                DEBUG ("barometer: get_reference_temperature - rate last %d: %lf **",
-                       i,
-                       values[i]);
+                DEBUG ("barometer: get_reference_temperature - rate last %zu: %lf **",
+                       i, values[i]);
                 if(!isnan(values[i]))
                 {
                     avg_sum += values[i];
index 32b0f16..06b4ace 100644 (file)
@@ -1759,7 +1759,7 @@ static int bind_init (void) /* {{{ */
   curl_easy_setopt (curl, CURLOPT_MAXREDIRS, 50L);
 #ifdef HAVE_CURLOPT_TIMEOUT_MS
   curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (timeout >= 0) ?
-      (long) timeout : CDTIME_T_TO_MS(plugin_get_interval()));
+      (long) timeout : (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
 
index d928a7b..419ca6e 100644 (file)
@@ -43,7 +43,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
-#include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/un.h>
index 10f9f61..0e4cd53 100644 (file)
@@ -17,7 +17,7 @@ collectd-exec - Documentation of collectd's C<exec plugin>
 
 =head1 DESCRIPTION
 
-The C<exec plugin> forks of an executable either to receive values or to
+The C<exec plugin> forks off an executable either to receive values or to
 dispatch notifications to the outside world. The syntax of the configuration is
 explained in L<collectd.conf(5)> but summarized in the above synopsis.
 
@@ -42,7 +42,7 @@ time and continuously write values to C<STDOUT>.
 See L<EXEC DATA FORMAT> below for a description of the output format expected
 from these programs.
 
-B<Warning:> If the executable only writes one value and then exits I will be
+B<Warning:> If the executable only writes one value and then exits it will be
 executed every I<Interval> seconds. If I<Interval> is short (the default is 10
 seconds) this may result in serious system load.
 
index 8b0f867..b17e47e 100644 (file)
@@ -104,7 +104,7 @@ static int consolitation_g = CON_NONE;
 static _Bool nan_is_error_g = 0;
 
 static char **match_ds_g = NULL;
-static int    match_ds_num_g = 0;
+static size_t match_ds_num_g = 0;
 
 /* `strdup' is an XSI extension. I don't want to pull in all of XSI just for
  * that, so here's an own implementation.. It's easy enough. The GCC attributes
@@ -148,7 +148,7 @@ static int filter_ds (size_t *values_num,
                return (RET_UNKNOWN);
        }
 
-       for (i = 0; i < (size_t) match_ds_num_g; i++)
+       for (i = 0; i < match_ds_num_g; i++)
        {
                size_t j;
 
index 45e788c..9bd65bc 100644 (file)
 # include "config.h"
 #endif
 
-#ifndef _ISOC99_SOURCE
-# define _ISOC99_SOURCE
-#endif
-
-#ifndef _POSIX_C_SOURCE
-# define _POSIX_C_SOURCE 200809L
-#endif
-
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 700
-#endif
-
 #if !__GNUC__
 # define __attribute__(x) /**/
 #endif
@@ -51,6 +39,8 @@
 #include <time.h>
 #include <signal.h>
 #include <errno.h>
+#include <math.h>
+#include <sys/time.h>
 
 #include "utils_heap.h"
 
@@ -111,6 +101,29 @@ static void signal_handler (int signal) /* {{{ */
   loop = 0;
 } /* }}} void signal_handler */
 
+#if HAVE_CLOCK_GETTIME
+static double dtime (void) /* {{{ */
+{
+  struct timespec ts = { 0 };
+
+  if (clock_gettime (CLOCK_MONOTONIC, &ts) != 0)
+    perror ("clock_gettime");
+
+  return ((double) ts.tv_sec) + (((double) ts.tv_nsec) / 1e9);
+} /* }}} double dtime */
+#else
+/* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
+static double dtime (void) /* {{{ */
+{
+  struct timeval tv = { 0 };
+
+  if (gettimeofday (&tv, /* timezone = */ NULL) != 0)
+    perror ("gettimeofday");
+
+  return ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1e6);
+} /* }}} double dtime */
+#endif
+
 static int compare_time (const void *v0, const void *v1) /* {{{ */
 {
   const lcc_value_list_t *vl0 = v0;
@@ -173,7 +186,7 @@ static lcc_value_list_t *create_value_list (void) /* {{{ */
   host_num = get_boundet_random (0, conf_num_hosts);
 
   vl->interval = conf_interval;
-  vl->time = 1.0 + time (NULL)
+  vl->time = 1.0 + dtime ()
     + (host_num % (1 + (int) vl->interval));
 
   if (get_boundet_random (0, 2) == 0)
@@ -211,7 +224,7 @@ static int send_value (lcc_value_list_t *vl) /* {{{ */
   if (vl->values_types[0] == LCC_TYPE_GAUGE)
     vl->values[0].gauge = 100.0 * ((gauge_t) random ()) / (((gauge_t) RAND_MAX) + 1.0);
   else
-    vl->values[0].derive += get_boundet_random (0, 100);
+    vl->values[0].derive += (derive_t) get_boundet_random (0, 100);
 
   status = lcc_network_values_send (net, vl);
   if (status != 0)
@@ -326,7 +339,7 @@ static int read_options (int argc, char **argv) /* {{{ */
 int main (int argc, char **argv) /* {{{ */
 {
   int i;
-  time_t last_time;
+  double last_time;
   int values_sent = 0;
 
   read_options (argc, argv);
@@ -399,14 +412,18 @@ int main (int argc, char **argv) /* {{{ */
       printf ("%i values have been sent.\n", values_sent);
 
       /* Check if we need to sleep */
-      time_t now = time (NULL);
+      double now = dtime ();
 
       while (now < vl->time)
       {
         /* 1 / 100 second */
         struct timespec ts = { 0, 10000000 };
+
+        ts.tv_sec = (time_t) now;
+        ts.tv_nsec = (long) ((now - ((double) ts.tv_sec)) * 1e9);
+
         nanosleep (&ts, /* remaining = */ NULL);
-        now = time (NULL);
+        now = dtime ();
 
         if (!loop)
           break;
index 38a0534..61c01f9 100644 (file)
 @BUILD_PLUGIN_MEMORY_TRUE@@BUILD_PLUGIN_MEMORY_TRUE@LoadPlugin memory
 #@BUILD_PLUGIN_MIC_TRUE@LoadPlugin mic
 #@BUILD_PLUGIN_MODBUS_TRUE@LoadPlugin modbus
+#@BUILD_PLUGIN_MQTT_TRUE@LoadPlugin mqtt
 #@BUILD_PLUGIN_MULTIMETER_TRUE@LoadPlugin multimeter
 #@BUILD_PLUGIN_MYSQL_TRUE@LoadPlugin mysql
 #@BUILD_PLUGIN_NETAPP_TRUE@LoadPlugin netapp
 #@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
 #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
 #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
+#@BUILD_PLUGIN_ZONE_TRUE@LoadPlugin zone
 #@BUILD_PLUGIN_ZOOKEEPER_TRUE@LoadPlugin zookeeper
 
 ##############################################################################
 #      Host "localhost"
 #      Port "3551"
 #      ReportSeconds true
+#      PersistentConnection true
 #</Plugin>
 
 #<Plugin aquaero>
 
 #<Plugin "battery">
 #  ValuesPercentage false
-#  ReportDegraded
+#  ReportDegraded false
 #</Plugin>
 
 #<Plugin "bind">
 #      </Host>
 #</Plugin>
 
+#<Plugin mqtt>
+#      <Publish "name">
+#              Host "localhost"
+#              Port 1883
+#              ClientId "localhost"
+#              User "user"
+#              Password "secret"
+#              QoS 0
+#              Prefix "collectd"
+#              StoreRates true
+#              Retain false
+#      </Publish>
+#      <Subscribe "name">
+#              Host "localhost"
+#              Port 1883
+#              ClientId "localhost"
+#              User "user"
+#              Password "secret"
+#              QoS 2
+#              Topic "collectd/#"
+#              CleanSession true
+#      </Subscribe>
+#</Plugin>
+
 #<Plugin mysql>
 #      <Database db_name>
 #              Host "database.serv.er"
 #              Host "localhost"
 #              Port "6379"
 #              Timeout 1000
+#              Prefix "collectd/"
 #      </Node>
 #</Plugin>
 
index b840e6c..8a50808 100644 (file)
@@ -130,6 +130,15 @@ Sets a plugin-specific interval for collecting metrics. This overrides the
 global B<Interval> setting. If a plugin provides own support for specifying an
 interval, that setting will take precedence.
 
+=item B<FlushInterval> I<Seconds>
+
+Specifies the the interval, in seconds, to call the flush callback if it's
+defined in this plugin. By default, this is disabled
+
+=item B<FlushTimeout> I<Seconds>
+
+Specifies the value of the timeout argument of the flush callback.
+
 =back
 
 =item B<AutoLoadPlugin> B<false>|B<true>
@@ -504,7 +513,9 @@ are disabled by default.
 The I<AMQP plugin> can be used to communicate with other instances of
 I<collectd> or third party applications using an AMQP message broker. Values
 are sent to or received from the broker, which handles routing, queueing and
-possibly filtering or messages.
+possibly filtering out messages.
+
+B<Synopsis:>
 
  <Plugin "amqp">
    # Send values to an AMQP broker
@@ -802,12 +813,22 @@ B<apcupsd> can handle it.
 
 TCP-Port to connect to. Defaults to B<3551>.
 
-=item B<ReportSeconds> B<true|false>
+=item B<ReportSeconds> B<true>|B<false>
 
 If set to B<true>, the time reported in the C<timeleft> metric will be
 converted to seconds. This is the recommended setting. If set to B<false>, the
 default for backwards compatibility, the time will be reported in minutes.
 
+=item B<PersistentConnection> B<true>|B<false>
+
+By default, the plugin will try to keep the connection to UPS open between
+reads. Since this appears to be somewhat brittle (I<apcupsd> appears to close
+the connection due to inactivity quite quickly), the plugin will try to detect
+this problem and switch to an open-read-close mode in such cases.
+
+You can instruct the plugin to close the connection after each read by setting
+this option to B<false>.
+
 =back
 
 =head2 Plugin C<aquaero>
@@ -1806,6 +1827,7 @@ than those of other plugins. It usually looks something like this:
     </Query>
     <Database "product_information">
       Driver "mysql"
+      Interval 120
       DriverOption "host" "localhost"
       DriverOption "username" "collectd"
       DriverOption "password" "aZo6daiw"
@@ -1985,6 +2007,11 @@ the daemon. Other than that, that name is not used.
 
 =over 4
 
+=item B<Interval> I<Interval>
+
+Sets the interval (in seconds) in which the values will be collected from this
+database. By default the global B<Interval> setting will be used.
+
 =item B<Driver> I<Driver>
 
 Specifies the driver to use to connect to the database. In many cases those
@@ -3214,6 +3241,114 @@ B<Collect> option is mandatory.
 
 =back
 
+=head2 Plugin C<mqtt>
+
+The I<MQTT plugin> can send metrics to MQTT (B<Publish> blocks) and receive
+values from MQTT (B<Subscribe> blocks).
+
+B<Synopsis:>
+
+ <Plugin mqtt>
+   <Publish "name">
+     Host "mqtt.example.com"
+     Prefix "collectd"
+   </Publish>
+   <Subscribe "name">
+     Host "mqtt.example.com"
+     Topic "collectd/#"
+   </Subscribe>
+ </Plugin>
+
+The plugin's configuration is in B<Publish> and/or B<Subscribe> blocks,
+configuring the sending and receiving direction respectively. The plugin will
+register a write callback named C<mqtt/I<name>> where I<name> is the string
+argument given to the B<Publish> block. Both types of blocks share many but not
+all of the following options. If an option is valid in only one of the blocks,
+it will be mentioned explicitly.
+
+B<Options:>
+
+=over 4
+
+=item B<Host> I<Hostname>
+
+Hostname of the MQTT broker to connect to.
+
+=item B<Port> I<Service>
+
+Port number or service name of the MQTT broker to connect to.
+
+=item B<User> I<UserName>
+
+Username used when authenticating to the MQTT broker.
+
+=item B<Password> I<Password>
+
+Password used when authenticating to the MQTT broker.
+
+=item B<ClientId> I<ClientId>
+
+MQTT client ID to use. Defaults to the hostname used by I<collectd>.
+
+=item B<QoS> [B<0>-B<2>]
+
+Sets the I<Quality of Service>, with the values C<0>, C<1> and C<2> meaning:
+
+=over 4
+
+=item B<0>
+
+At most once
+
+=item B<1>
+
+At least once
+
+=item B<2>
+
+Exactly once
+
+=back
+
+In B<Publish> blocks, this option determines the QoS flag set on outgoing
+messages and defaults to B<0>. In B<Subscribe> blocks, determines the maximum
+QoS setting the client is going to accept and defaults to B<2>. If the QoS flag
+on a message is larger than the maximum accepted QoS of a subscriber, the
+message's QoS will be downgraded.
+
+=item B<Prefix> I<Prefix> (Publish only)
+
+This plugin will use one topic per I<value list> which will looks like a path.
+I<Prefix> is used as the first path element and defaults to B<collectd>.
+
+An example topic name would be:
+
+ collectd/cpu-0/cpu-user
+
+=item B<Retain> B<false>|B<true> (Publish only)
+
+Controls whether the MQTT broker will retain (keep a copy of) the last message
+sent to each topic and deliver it to new subscribers. Defaults to B<false>.
+
+=item B<StoreRates> B<true>|B<false> (Publish only)
+
+Controls whether C<DERIVE> and C<COUNTER> metrics are converted to a I<rate>
+before sending. Defaults to B<true>.
+
+=item B<CleanSession> B<true>|B<false> (Subscribe only)
+
+Controls whether the MQTT "cleans" the session up after the subscriber
+disconnects or if it maintains the subscriber's subscriptions and all messages
+that arrive while the subscriber is disconnected. Defaults to B<true>.
+
+=item B<Topic> I<TopicName> (Subscribe only)
+
+Configures the topic(s) to subscribe to. You can use the single level C<+> and
+multi level C<#> wildcards. Defaults to B<collectd/#>, i.e. all topics beneath
+the B<collectd> branch.
+
+=back
+
 =head2 Plugin C<mysql>
 
 The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
@@ -4494,6 +4629,16 @@ The following options are accepted within each B<Instance> block:
 Sets the URL to use to connect to the I<OpenLDAP> server. This option is
 I<mandatory>.
 
+=item B<BindDN> I<BindDN>
+
+Name in the form of an LDAP distinguished name intended to be used for 
+authentication. Defaults to empty string to establish an anonymous authorization.
+
+=item B<Password> I<Password>
+
+Password for simple bind authentication. If this option is not set, 
+unauthenticated bind operation is used.
+
 =item B<StartTLS> B<true|false>
 
 Defines whether TLS must be used when connecting to the I<OpenLDAP> server.
@@ -5422,6 +5567,10 @@ dispatched to the daemon using the specified I<name> as an identifier. This
 allows to "group" several processes together. I<name> must not contain
 slashes.
 
+=item B<CollectContextSwitch> I<Boolean>
+
+Collect context switch of the process.
+
 =back
 
 =head2 Plugin C<protocols>
@@ -6990,17 +7139,17 @@ setting B<name>.
 B<address> means use the interface's mac address. This is useful since the
 interface path might change between reboots of a guest or across migrations.
 
-=item B<PluginInstanceFormat> B<name|uuid>
+=item B<PluginInstanceFormat> B<name|uuid|none>
 
 When the virt plugin logs data, it sets the plugin_instance of the collected
-data according to this setting. The default is to use the guest name as provided
-by the hypervisor, which is equal to setting B<name>.
+data according to this setting. The default is to not set the plugin_instance.
 
+B<name> means use the guest's name as provided by the hypervisor.
 B<uuid> means use the guest's UUID.
 
-You can also specify combinations of these fields. For example B<name uuid>
-means to concatenate the guest name and UUID (with a literal colon character
-between, thus I<"foo:1234-1234-1234-1234">).
+You can also specify combinations of the B<name> and B<uuid> fields.
+For example B<name uuid> means to concatenate the guest name and UUID
+(with a literal colon character between, thus I<"foo:1234-1234-1234-1234">).
 
 =back
 
@@ -7343,6 +7492,10 @@ complete. When this limit is reached, the POST operation will be aborted, and
 all the data in the current send buffer will probably be lost. Defaults to 0,
 which means the connection never times out.
 
+=item B<LogHttpError> B<false>|B<true>
+
+Enables printing of HTTP error code to log. Turned off by default.
+
 The C<write_http> plugin regularly submits the collected values to the HTTP
 server. How frequently this happens depends on how much data you are collecting
 and the size of B<BufferSize>. The optimal value to set B<Timeout> to is
@@ -7469,14 +7622,20 @@ Synopsis:
         Host "localhost"
         Port "6379"
         Timeout 1000
+        Prefix "collectd/"
+        Database 1
+        MaxSetSize -1
+        StoreRates true
     </Node>
   </Plugin>
 
 Values are submitted to I<Sorted Sets>, using the metric name as the key, and
 the timestamp as the score. Retrieving a date range can then be done using the
-C<ZRANGEBYSCORE> I<Redis> command. Additionnally, all the identifiers of these
-I<Sorted Sets> are kept in a I<Set> called C<collectd/values> and can be
-retrieved using the C<SMEMBERS> I<Redis> command. See
+C<ZRANGEBYSCORE> I<Redis> command. Additionally, all the identifiers of these
+I<Sorted Sets> are kept in a I<Set> called C<collectd/values> (or
+C<${prefix}/values> if the B<Prefix> option was specified) and can be retrieved
+using the C<SMEMBERS> I<Redis> command. You can specify the database to use
+with the B<Database> parameter (default is C<0>). See
 L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
 details.
 
@@ -7492,9 +7651,9 @@ options are available:
 =item B<Node> I<Nodename>
 
 The B<Node> block identifies a new I<Redis> node, that is a new I<Redis>
-instance running in an specified host and port. The name for node is a
+instance running on a specified host and port. The node name is a
 canonical identifier which is used as I<plugin instance>. It is limited to
-64E<nbsp>characters in length.
+51E<nbsp>characters in length.
 
 =item B<Host> I<Hostname>
 
@@ -7511,6 +7670,28 @@ that numerical port numbers must be given as a string, too.
 
 The B<Timeout> option sets the socket connection timeout, in milliseconds.
 
+=item B<Prefix> I<Prefix>
+
+Prefix used when constructing the name of the I<Sorted Sets> and the I<Set>
+containing all metrics. Defaults to C<collectd/>, so metrics will have names
+like C<collectd/cpu-0/cpu-user>. When setting this to something different, it
+is recommended but not required to include a trailing slash in I<Prefix>.
+
+=item B<Database> I<Index>
+
+This index selects the redis database to use for writing operations. Defaults
+to C<0>.
+
+=item B<MaxSetSize> I<Items>
+
+The B<MaxSetSize> option limits the number of items that the I<Sorted Sets> can
+hold. Negative values for I<Items> sets no limit, which is the default behavior.
+
+=item B<StoreRates> B<true>|B<false>
+
+If set to B<true> (the default), convert counter values to rates. If set to
+B<false> counter values are stored as is, i.e. as an increasing integer number.
+
 =back
 
 =head2 Plugin C<write_riemann>
@@ -7590,7 +7771,7 @@ C<ds_type:derive:rate>.
 
 =item B<AlwaysAppendDS> B<false>|B<true>
 
-If set the B<true>, append the name of the I<Data Source> (DS) to the
+If set to B<true>, append the name of the I<Data Source> (DS) to the
 "service", i.e. the field that, together with the "host" field, uniquely
 identifies a metric in I<Riemann>. If set to B<false> (the default), this is
 only done when there is more than one DS.
index 8357ce8..febc998 100644 (file)
@@ -120,7 +120,7 @@ static int count_chars (const char *str, char chr) {
   return count;
 } /* count_chars */
 
-static int array_grow (void **array, int *array_len, size_t elem_size)
+static int array_grow (void **array, size_t *array_len, size_t elem_size)
 {
   void *tmp;
 
@@ -229,10 +229,10 @@ static int flush (lcc_connection_t *c, int argc, char **argv)
   int timeout = -1;
 
   lcc_identifier_t *identifiers = NULL;
-  int identifiers_num = 0;
+  size_t identifiers_num = 0;
 
   char **plugins = NULL;
-  int plugins_num = 0;
+  size_t plugins_num = 0;
 
   int status;
   int i;
@@ -507,7 +507,7 @@ static int putval (lcc_connection_t *c, int argc, char **argv)
           values_types[values_len] = LCC_TYPE_GAUGE;
         }
         else { /* integer */
-          values[values_len].counter = strtol (value, &endptr, 0);
+          values[values_len].counter = (counter_t) strtoull (value, &endptr, 0);
           values_types[values_len] = LCC_TYPE_COUNTER;
         }
         ++values_len;
@@ -551,14 +551,14 @@ int main (int argc, char **argv) {
   int status;
 
   while (42) {
-    int c;
+    int opt;
 
-    c = getopt (argc, argv, "s:h");
+    opt = getopt (argc, argv, "s:h");
 
-    if (c == -1)
+    if (opt == -1)
       break;
 
-    switch (c) {
+    switch (opt) {
       case 's':
         snprintf (address, sizeof (address), "unix:%s", optarg);
         address[sizeof (address) - 1] = '\0';
index 2a2a4a9..bcaea38 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -526,11 +526,12 @@ static void cpu_commit (void) /* {{{ */
 /* Adds a derive value to the internal state. This should be used by each read
  * function for each state. At the end of the iteration, the read function
  * should call cpu_commit(). */
-static int cpu_stage (size_t cpu_num, size_t state, derive_t value, cdtime_t now) /* {{{ */
+static int cpu_stage (size_t cpu_num, size_t state, derive_t d, cdtime_t now) /* {{{ */
 {
        int status;
        cpu_state_t *s;
-       value_t v;
+       gauge_t rate = NAN;
+       value_t val = {.derive = d};
 
        if (state >= COLLECTD_CPU_STATE_ACTIVE)
                return (EINVAL);
@@ -544,12 +545,11 @@ static int cpu_stage (size_t cpu_num, size_t state, derive_t value, cdtime_t now
 
        s = get_cpu_state (cpu_num, state);
 
-       v.gauge = NAN;
-       status = value_to_rate (&v, value, &s->conv, DS_TYPE_DERIVE, now);
+       status = value_to_rate (&rate, val, DS_TYPE_DERIVE, now, &s->conv);
        if (status != 0)
                return (status);
 
-       s->rate = v.gauge;
+       s->rate = rate;
        s->has_value = 1;
        return (0);
 } /* }}} int cpu_stage */
index b6e535e..15494f4 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
@@ -45,7 +45,7 @@ static int value_list_to_string (char *buffer, int buffer_len,
 {
        int offset;
        int status;
-       int i;
+       size_t i;
        gauge_t *rates = NULL;
 
        assert (0 == strcmp (ds->type, vl->type));
@@ -184,7 +184,7 @@ static int value_list_to_filename (char *buffer, size_t buffer_size,
 static int csv_create_file (const char *filename, const data_set_t *ds)
 {
        FILE *csv;
-       int i;
+       size_t i;
 
        if (check_create_dir (filename))
                return (-1);
index ac4cc51..16ae3ab 100644 (file)
@@ -418,8 +418,7 @@ static int cc_page_init_curl (web_page_t *wp) /* {{{ */
   if (wp->timeout >= 0)
     curl_easy_setopt (wp->curl, CURLOPT_TIMEOUT_MS, (long) wp->timeout);
   else
-    curl_easy_setopt (wp->curl, CURLOPT_TIMEOUT_MS,
-       CDTIME_T_TO_MS(plugin_get_interval()));
+    curl_easy_setopt (wp->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
   return (0);
index 3ba5560..510d9b6 100644 (file)
@@ -28,7 +28,6 @@
 #include "utils_avltree.h"
 #include "utils_complain.h"
 
-#include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
 
@@ -563,7 +562,7 @@ static int cj_config_add_key (cj_t *db, /* {{{ */
       if (*ptr == '/')
       {
         c_avl_tree_t *value;
-        int len;
+        size_t len;
 
         len = ptr-name;
         if (len == 0)
@@ -655,11 +654,9 @@ static int cj_init_curl (cj_t *db) /* {{{ */
   if (db->timeout >= 0)
     curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS, (long) db->timeout);
   else if (db->interval > 0)
-    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS,
-        CDTIME_T_TO_MS(db->timeout));
+    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(db->timeout));
   else
-    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS,
-        CDTIME_T_TO_MS(plugin_get_interval()));
+    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
   return (0);
@@ -764,9 +761,6 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
   {
     user_data_t ud;
     char *cb_name;
-    struct timespec interval = { 0, 0 };
-
-    CDTIME_T_TO_TIMESPEC (db->interval, &interval);
 
     if (db->instance == NULL)
       db->instance = strdup("default");
@@ -782,7 +776,7 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
                db->instance, db->url ? db->url : db->sock);
 
     plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
-                                  /* interval = */ (db->interval > 0) ? &interval : NULL,
+                                  /* interval = */ db->interval,
                                   &ud);
     sfree (cb_name);
   }
index 37a3686..5a1f2ba 100644 (file)
@@ -50,7 +50,7 @@ struct cx_xpath_s /* {{{ */
   char *path;
   char *type;
   cx_values_t *values;
-  int values_len;
+  size_t values_len;
   char *instance_prefix;
   char *instance;
   int is_table;
@@ -240,7 +240,7 @@ static int cx_check_type (const data_set_t *ds, cx_xpath_t *xpath) /* {{{ */
 
   if (ds->ds_num != xpath->values_len)
   {
-    WARNING ("curl_xml plugin: DataSet `%s' requires %i values, but config talks about %i",
+    WARNING ("curl_xml plugin: DataSet `%s' requires %zu values, but config talks about %zu",
         xpath->type, ds->ds_num, xpath->values_len);
     return (-1);
   }
@@ -356,7 +356,7 @@ static int cx_handle_all_value_xpaths (xmlXPathContextPtr xpath_ctx, /* {{{ */
 {
   value_t values[xpath->values_len];
   int status;
-  int i;
+  size_t i;
 
   assert (xpath->values_len > 0);
   assert (xpath->values_len == vl->values_len);
@@ -689,7 +689,7 @@ static int cx_config_add_values (const char *name, cx_xpath_t *xpath, /* {{{ */
   xpath->values = (cx_values_t *) malloc (sizeof (cx_values_t) * ci->values_num);
   if (xpath->values == NULL)
     return (-1);
-  xpath->values_len = ci->values_num;
+  xpath->values_len = (size_t) ci->values_num;
 
   /* populate cx_values_t structure */
   for (i = 0; i < ci->values_num; i++)
@@ -897,8 +897,7 @@ static int cx_init_curl (cx_t *db) /* {{{ */
   if (db->timeout >= 0)
     curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS, (long) db->timeout);
   else
-    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS,
-       CDTIME_T_TO_MS(plugin_get_interval()));
+    curl_easy_setopt (db->curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
 #endif
 
   return (0);
@@ -1016,7 +1015,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
 
     cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
     plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
-                                  /* interval = */ NULL, &ud);
+                                  /* interval = */ 0, &ud);
     sfree (cb_name);
   }
   else
index 99dc158..3d50029 100644 (file)
@@ -1,7 +1,3 @@
-if COMPILER_IS_GCC
-AM_CFLAGS = -Wall -Werror
-endif
-
 AM_CPPFLAGS = -I$(top_srcdir)/src
 AM_CPPFLAGS += -DPREFIX='"${prefix}"'
 AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
@@ -41,15 +37,19 @@ AUTOMAKE_OPTIONS = subdir-objects
 
 sbin_PROGRAMS = collectd
 
-noinst_LTLIBRARIES = libavltree.la libcommon.la libheap.la libplugin_mock.la
+noinst_LTLIBRARIES = libavltree.la libcommon.la libheap.la libmetadata.la libplugin_mock.la
 
 libavltree_la_SOURCES = utils_avltree.c utils_avltree.h
 
 libcommon_la_SOURCES = common.c common.h
+libcommon_la_LIBADD = $(COMMON_LIBS)
 
 libheap_la_SOURCES = utils_heap.c utils_heap.h
 
+libmetadata_la_SOURCES = meta_data.c meta_data.h
+
 libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c utils_time_mock.c
+libplugin_mock_la_LIBADD = $(COMMON_LIBS)
 
 collectd_SOURCES = collectd.c collectd.h \
                   configfile.c configfile.h \
@@ -58,6 +58,7 @@ collectd_SOURCES = collectd.c collectd.h \
                   plugin.c plugin.h \
                   utils_cache.c utils_cache.h \
                   utils_complain.c utils_complain.h \
+                  utils_ignorelist.c utils_ignorelist.h \
                   utils_llist.c utils_llist.h \
                   utils_random.c utils_random.h \
                   utils_tail_match.c utils_tail_match.h \
@@ -73,7 +74,7 @@ collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
 collectd_CFLAGS = $(AM_CFLAGS)
 collectd_LDFLAGS = -export-dynamic
 collectd_LDADD = libavltree.la libcommon.la libheap.la -lm $(COMMON_LIBS)
-collectd_DEPENDENCIES = libavltree.la libcommon.la libheap.la
+collectd_DEPENDENCIES = libavltree.la libcommon.la libheap.la libmetadata.la
 
 # The daemon needs to call sg_init, so we need to link it against libstatgrab,
 # too. -octo
@@ -89,14 +90,23 @@ else
 collectd_LDADD += -loconfig
 endif
 
-check_PROGRAMS = test_common test_utils_avltree test_utils_heap
-TESTS = test_common test_utils_avltree test_utils_heap
+check_PROGRAMS = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_time test_utils_subst
+TESTS          = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_time test_utils_subst
 
 test_common_SOURCES = common_test.c ../testing.h
-test_common_LDADD = libcommon.la libplugin_mock.la $(COMMON_LIBS)
+test_common_LDADD = libcommon.la libplugin_mock.la
+
+test_meta_data_SOURCES = meta_data_test.c ../testing.h
+test_meta_data_LDADD = libmetadata.la libplugin_mock.la
 
 test_utils_avltree_SOURCES = utils_avltree_test.c ../testing.h
 test_utils_avltree_LDADD = libavltree.la $(COMMON_LIBS)
 
 test_utils_heap_SOURCES = utils_heap_test.c ../testing.h
 test_utils_heap_LDADD = libheap.la $(COMMON_LIBS)
+
+test_utils_time_SOURCES = utils_time_test.c ../testing.h
+
+test_utils_subst_SOURCES = utils_subst_test.c ../testing.h \
+                          utils_subst.c utils_subst.h
+test_utils_subst_LDADD = libcommon.la libplugin_mock.la
index 88c38ac..fc52933 100644 (file)
@@ -32,7 +32,6 @@
 #include "configfile.h"
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <netdb.h>
 
@@ -420,15 +419,18 @@ static int pidfile_remove (void)
 #ifdef KERNEL_LINUX
 int notify_upstart (void)
 {
-    const char  *upstart_job = getenv("UPSTART_JOB");
+    char const *upstart_job = getenv("UPSTART_JOB");
 
     if (upstart_job == NULL)
         return 0;
 
     if (strcmp(upstart_job, "collectd") != 0)
+    {
+        WARNING ("Environment specifies unexpected UPSTART_JOB=\"%s\", expected \"collectd\". Ignoring the variable.", upstart_job);
         return 0;
+    }
 
-    WARNING ("supervised by upstart, will stop to signal readyness");
+    NOTICE("Upstart detected, stopping now to signal readyness.");
     raise(SIGSTOP);
     unsetenv("UPSTART_JOB");
 
@@ -437,49 +439,69 @@ int notify_upstart (void)
 
 int notify_systemd (void)
 {
-    int                  fd = -1;
-    const char          *notifysocket = getenv("NOTIFY_SOCKET");
+    int                  fd;
+    const char          *notifysocket;
     struct sockaddr_un   su;
-    struct iovec         iov;
-    struct msghdr        hdr;
+    size_t               su_size;
+    char                 buffer[] = "READY=1\n";
 
+    notifysocket = getenv ("NOTIFY_SOCKET");
     if (notifysocket == NULL)
         return 0;
 
-    if ((strchr("@/", notifysocket[0])) == NULL ||
-        strlen(notifysocket) < 2)
+    if ((strlen (notifysocket) < 2)
+        || ((notifysocket[0] != '@') && (notifysocket[0] != '/')))
+    {
+        ERROR ("invalid notification socket NOTIFY_SOCKET=\"%s\": path must be absolute", notifysocket);
         return 0;
+    }
+    NOTICE ("Systemd detected, trying to signal readyness.");
+
+    unsetenv ("NOTIFY_SOCKET");
 
-    WARNING ("supervised by systemd, will signal readyness");
-    if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
-        WARNING ("cannot contact systemd socket %s", notifysocket);
+#if defined(SOCK_CLOEXEC)
+    fd = socket (AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, /* protocol = */ 0);
+#else
+    fd = socket (AF_UNIX, SOCK_DGRAM, /* protocol = */ 0);
+#endif
+    if (fd < 0) {
+        char errbuf[1024];
+        ERROR ("creating UNIX socket failed: %s",
+                 sstrerror (errno, errbuf, sizeof (errbuf)));
         return 0;
     }
 
-    bzero(&su, sizeof(su));
+    memset (&su, 0, sizeof (su));
     su.sun_family = AF_UNIX;
-    sstrncpy (su.sun_path, notifysocket, sizeof(su.sun_path));
-
-    if (notifysocket[0] == '@')
+    if (notifysocket[0] != '@')
+    {
+        /* regular UNIX socket */
+        sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path));
+        su_size = sizeof (su);
+    }
+    else
+    {
+        /* Linux abstract namespace socket: specify address as "\0foo", i.e.
+         * start with a null byte. Since null bytes have no special meaning in
+         * that case, we have to set su_size correctly to cover only the bytes
+         * that are part of the address. */
+        sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path));
         su.sun_path[0] = 0;
+        su_size = sizeof (sa_family_t) + strlen (notifysocket);
+        if (su_size > sizeof (su))
+            su_size = sizeof (su);
+    }
 
-    bzero(&iov, sizeof(iov));
-    iov.iov_base = "READY=1";
-    iov.iov_len = strlen("READY=1");
-
-    bzero(&hdr, sizeof(hdr));
-    hdr.msg_name = &su;
-    hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
-        strlen(notifysocket);
-    hdr.msg_iov = &iov;
-    hdr.msg_iovlen = 1;
-
-    unsetenv("NOTIFY_SOCKET");
-    if (sendmsg(fd, &hdr, MSG_NOSIGNAL) < 0) {
-        WARNING ("cannot send notification to systemd");
+    if (sendto (fd, buffer, strlen (buffer), MSG_NOSIGNAL, (void *) &su, (socklen_t) su_size) < 0)
+    {
+        char errbuf[1024];
+        ERROR ("sendto(\"%s\") failed: %s", notifysocket,
+                 sstrerror (errno, errbuf, sizeof (errbuf)));
         close(fd);
         return 0;
     }
+
+    unsetenv ("NOTIFY_SOCKET");
     close(fd);
     return 1;
 }
index 80b753c..66b4856 100644 (file)
@@ -95,6 +95,9 @@
 #  include <time.h>
 # endif
 #endif
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
 
 #if HAVE_ASSERT_H
 # include <assert.h>
index b244808..8f22011 100644 (file)
@@ -46,7 +46,6 @@
 
 /* for getaddrinfo */
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 #if HAVE_NETINET_IN_H
@@ -257,8 +256,8 @@ ssize_t sread (int fd, void *buf, size_t count)
 
                assert ((0 > status) || (nleft >= (size_t)status));
 
-               nleft = nleft - status;
-               ptr   = ptr   + status;
+               nleft = nleft - ((size_t) status);
+               ptr   = ptr   + ((size_t) status);
        }
 
        return (0);
@@ -284,8 +283,8 @@ ssize_t swrite (int fd, const void *buf, size_t count)
                if (status < 0)
                        return (status);
 
-               nleft = nleft - status;
-               ptr   = ptr   + status;
+               nleft = nleft - ((size_t) status);
+               ptr   = ptr   + ((size_t) status);
        }
 
        return (0);
@@ -356,7 +355,7 @@ int strjoin (char *buffer, size_t buffer_size,
        }
 
        assert (buffer[buffer_size - 1] == 0);
-       return (strlen (buffer));
+       return ((int) strlen (buffer));
 }
 
 int strsubstitute (char *str, char c_from, char c_to)
@@ -491,8 +490,8 @@ size_t strstripnewline (char *buffer)
 
 int escape_slashes (char *buffer, size_t buffer_size)
 {
-       int i;
        size_t buffer_len;
+       size_t i;
 
        buffer_len = strlen (buffer);
 
@@ -665,8 +664,8 @@ int check_create_dir (const char *file_orig)
                 * Join the components together again
                 */
                dir[0] = '/';
-               if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
-                                       fields, i + 1, "/") < 0)
+               if (strjoin (dir + path_is_absolute, (size_t) (dir_len - path_is_absolute),
+                                       fields, (size_t) (i + 1), "/") < 0)
                {
                        ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
                        return (-1);
@@ -946,7 +945,7 @@ int format_values (char *ret, size_t ret_len, /* {{{ */
 {
         size_t offset = 0;
         int status;
-        int i;
+        size_t i;
         gauge_t *rates = NULL;
 
         assert (0 == strcmp (ds->type, vl->type));
@@ -1149,14 +1148,15 @@ int parse_value (const char *value_orig, value_t *ret_value, int ds_type)
 
 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
 {
-       int i;
+       size_t i;
        char *dummy;
        char *ptr;
        char *saveptr;
 
-       i = -1;
+       i = 0;
        dummy = buffer;
        saveptr = NULL;
+       vl->time = 0;
        while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
        {
                dummy = NULL;
@@ -1164,11 +1164,11 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
                if (i >= vl->values_len)
                {
                        /* Make sure i is invalid. */
-                       i = vl->values_len + 1;
+                       i = 0;
                        break;
                }
 
-               if (i == -1)
+               if (vl->time == 0)
                {
                        if (strcmp ("N", ptr) == 0)
                                vl->time = cdtime ();
@@ -1187,19 +1187,19 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
 
                                vl->time = DOUBLE_TO_CDTIME_T (tmp);
                        }
-               }
-               else
-               {
-                       if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
-                               vl->values[i].gauge = NAN;
-                       else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
-                               return -1;
+
+                       continue;
                }
 
+               if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
+                       vl->values[i].gauge = NAN;
+               else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
+                       return -1;
+
                i++;
        } /* while (strtok_r) */
 
-       if ((ptr != NULL) || (i != vl->values_len))
+       if ((ptr != NULL) || (i == 0))
                return (-1);
        return (0);
 } /* int parse_values */
@@ -1361,10 +1361,9 @@ counter_t counter_diff (counter_t old_value, counter_t new_value)
        if (old_value > new_value)
        {
                if (old_value <= 4294967295U)
-                       diff = (4294967295U - old_value) + new_value;
+                       diff = (4294967295U - old_value) + new_value + 1;
                else
-                       diff = (18446744073709551615ULL - old_value)
-                               + new_value;
+                       diff = (18446744073709551615ULL - old_value) + new_value + 1;
        }
        else
        {
@@ -1469,11 +1468,10 @@ int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */
        return (0);
 } /* }}} value_t rate_to_value */
 
-int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
-               value_to_rate_state_t *state,
-               int ds_type, cdtime_t t)
+int value_to_rate (gauge_t *ret_rate, /* {{{ */
+               value_t value, int ds_type, cdtime_t t, value_to_rate_state_t *state)
 {
-       double interval;
+       gauge_t interval;
 
        /* Another invalid state: The time is not increasing. */
        if (t <= state->last_time)
@@ -1485,50 +1483,39 @@ int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
        interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
 
        /* Previous value is invalid. */
-       if (state->last_time == 0) /* {{{ */
+       if (state->last_time == 0)
        {
-               if (ds_type == DS_TYPE_DERIVE)
-               {
-                       state->last_value.derive = value;
-               }
-               else if (ds_type == DS_TYPE_COUNTER)
-               {
-                       state->last_value.counter = (counter_t) value;
-               }
-               else if (ds_type == DS_TYPE_ABSOLUTE)
-               {
-                       state->last_value.absolute = (absolute_t) value;
-               }
-               else
-               {
-                       assert (23 == 42);
-               }
-
+               state->last_value = value;
                state->last_time = t;
                return (EAGAIN);
-       } /* }}} */
+       }
 
-       if (ds_type == DS_TYPE_DERIVE)
-       {
-               ret_rate->gauge = (value - state->last_value.derive) / interval;
-               state->last_value.derive = value;
+       switch (ds_type) {
+       case DS_TYPE_DERIVE: {
+               derive_t diff = value.derive - state->last_value.derive;
+               *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
+               break;
        }
-       else if (ds_type == DS_TYPE_COUNTER)
-       {
-               ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
-               state->last_value.counter = (counter_t) value;
+       case DS_TYPE_GAUGE: {
+               *ret_rate = value.gauge;
+               break;
        }
-       else if (ds_type == DS_TYPE_ABSOLUTE)
-       {
-               ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval;
-               state->last_value.absolute = (absolute_t) value;
+       case DS_TYPE_COUNTER: {
+               counter_t diff = counter_diff (state->last_value.counter, value.counter);
+               *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
+               break;
        }
-       else
-       {
-               assert (23 == 42);
+       case DS_TYPE_ABSOLUTE: {
+               absolute_t diff = value.absolute;
+               *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
+               break;
+       }
+       default:
+               return EINVAL;
        }
 
-        state->last_time = t;
+       state->last_value = value;
+       state->last_time = t;
        return (0);
 } /* }}} value_t rate_to_value */
 
index da21cad..c3f7f54 100644 (file)
@@ -357,8 +357,8 @@ counter_t counter_diff (counter_t old_value, counter_t new_value);
 int rate_to_value (value_t *ret_value, gauge_t rate,
                rate_to_value_state_t *state, int ds_type, cdtime_t t);
 
-int value_to_rate (value_t *ret_rate, derive_t value,
-               value_to_rate_state_t *state, int ds_type, cdtime_t t);
+int value_to_rate (gauge_t *ret_rate, value_t value, int ds_type, cdtime_t t,
+               value_to_rate_state_t *state);
 
 /* Converts a service name (a string) to a port number
  * (in the range [1-65535]). Returns less than zero on error. */
index 1fa8f32..399f8b5 100644 (file)
 #include "testing.h"
 #include "common.h"
 
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
 DEF_TEST(sstrncpy)
 {
   char buffer[16] = "";
@@ -38,18 +42,18 @@ DEF_TEST(sstrncpy)
 
   ret = sstrncpy (ptr, "foobar", 8);
   OK(ret == ptr);
-  STREQ ("foobar", ptr);
+  EXPECT_EQ_STR ("foobar", ptr);
   OK(buffer[3] == buffer[12]);
 
   ret = sstrncpy (ptr, "abc", 8);
   OK(ret == ptr);
-  STREQ ("abc", ptr);
+  EXPECT_EQ_STR ("abc", ptr);
   OK(buffer[3] == buffer[12]);
 
   ret = sstrncpy (ptr, "collectd", 8);
   OK(ret == ptr);
   OK(ptr[7] == 0);
-  STREQ ("collect", ptr);
+  EXPECT_EQ_STR ("collect", ptr);
   OK(buffer[3] == buffer[12]);
 
   return (0);
@@ -66,12 +70,12 @@ DEF_TEST(ssnprintf)
 
   status = ssnprintf (ptr, 8, "%i", 1337);
   OK(status == 4);
-  STREQ ("1337", ptr);
+  EXPECT_EQ_STR ("1337", ptr);
 
   status = ssnprintf (ptr, 8, "%s", "collectd");
   OK(status == 8);
   OK(ptr[7] == 0);
-  STREQ ("collect", ptr);
+  EXPECT_EQ_STR ("collect", ptr);
   OK(buffer[3] == buffer[12]);
 
   return (0);
@@ -83,7 +87,7 @@ DEF_TEST(sstrdup)
 
   ptr = sstrdup ("collectd");
   OK(ptr != NULL);
-  STREQ ("collectd", ptr);
+  EXPECT_EQ_STR ("collectd", ptr);
 
   sfree(ptr);
   OK(ptr == NULL);
@@ -103,40 +107,40 @@ DEF_TEST(strsplit)
   strncpy (buffer, "foo bar", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 2);
-  STREQ ("foo", fields[0]);
-  STREQ ("bar", fields[1]);
+  EXPECT_EQ_STR ("foo", fields[0]);
+  EXPECT_EQ_STR ("bar", fields[1]);
 
   strncpy (buffer, "foo \t bar", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 2);
-  STREQ ("foo", fields[0]);
-  STREQ ("bar", fields[1]);
+  EXPECT_EQ_STR ("foo", fields[0]);
+  EXPECT_EQ_STR ("bar", fields[1]);
 
   strncpy (buffer, "one two\tthree\rfour\nfive", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 5);
-  STREQ ("one", fields[0]);
-  STREQ ("two", fields[1]);
-  STREQ ("three", fields[2]);
-  STREQ ("four", fields[3]);
-  STREQ ("five", fields[4]);
+  EXPECT_EQ_STR ("one", fields[0]);
+  EXPECT_EQ_STR ("two", fields[1]);
+  EXPECT_EQ_STR ("three", fields[2]);
+  EXPECT_EQ_STR ("four", fields[3]);
+  EXPECT_EQ_STR ("five", fields[4]);
 
   strncpy (buffer, "\twith trailing\n", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 2);
-  STREQ ("with", fields[0]);
-  STREQ ("trailing", fields[1]);
+  EXPECT_EQ_STR ("with", fields[0]);
+  EXPECT_EQ_STR ("trailing", fields[1]);
 
   strncpy (buffer, "1 2 3 4 5 6 7 8 9 10 11 12 13", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 8);
-  STREQ ("7", fields[6]);
-  STREQ ("8", fields[7]);
+  EXPECT_EQ_STR ("7", fields[6]);
+  EXPECT_EQ_STR ("8", fields[7]);
 
   strncpy (buffer, "single", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
   OK(status == 1);
-  STREQ ("single", fields[0]);
+  EXPECT_EQ_STR ("single", fields[0]);
 
   strncpy (buffer, "", sizeof (buffer));
   status = strsplit (buffer, fields, 8);
@@ -158,26 +162,26 @@ DEF_TEST(strjoin)
 
   status = strjoin (buffer, sizeof (buffer), fields, 2, "!");
   OK(status == 7);
-  STREQ ("foo!bar", buffer);
+  EXPECT_EQ_STR ("foo!bar", buffer);
 
   status = strjoin (buffer, sizeof (buffer), fields, 1, "!");
   OK(status == 3);
-  STREQ ("foo", buffer);
+  EXPECT_EQ_STR ("foo", buffer);
 
   status = strjoin (buffer, sizeof (buffer), fields, 0, "!");
   OK(status < 0);
 
   status = strjoin (buffer, sizeof (buffer), fields, 2, "rcht");
   OK(status == 10);
-  STREQ ("foorchtbar", buffer);
+  EXPECT_EQ_STR ("foorchtbar", buffer);
 
   status = strjoin (buffer, sizeof (buffer), fields, 4, "");
   OK(status == 12);
-  STREQ ("foobarbazqux", buffer);
+  EXPECT_EQ_STR ("foobarbazqux", buffer);
 
   status = strjoin (buffer, sizeof (buffer), fields, 4, "!");
   OK(status == 15);
-  STREQ ("foo!bar!baz!qux", buffer);
+  EXPECT_EQ_STR ("foo!bar!baz!qux", buffer);
 
   fields[0] = "0123";
   fields[1] = "4567";
@@ -189,6 +193,57 @@ DEF_TEST(strjoin)
   return (0);
 }
 
+DEF_TEST(escape_slashes)
+{
+  struct {
+    char *str;
+    char *want;
+  } cases[] = {
+    {"foo/bar/baz", "foo_bar_baz"},
+    {"/like/a/path", "like_a_path"},
+    {"trailing/slash/", "trailing_slash_"},
+    {"foo//bar", "foo__bar"},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    char buffer[32];
+
+    strncpy (buffer, cases[i].str, sizeof (buffer));
+    OK(escape_slashes (buffer, sizeof (buffer)) == 0);
+    EXPECT_EQ_STR(cases[i].want, buffer);
+  }
+
+  return 0;
+}
+
+DEF_TEST(escape_string)
+{
+  struct {
+    char *str;
+    char *want;
+  } cases[] = {
+    {"foobar", "foobar"},
+    {"f00bar", "f00bar"},
+    {"foo bar", "\"foo bar\""},
+    {"foo \"bar\"", "\"foo \\\"bar\\\"\""},
+    {"012345678901234", "012345678901234"},
+    {"012345 78901234", "\"012345 789012\""},
+    {"012345 78901\"34", "\"012345 78901\""},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    char buffer[16];
+
+    strncpy (buffer, cases[i].str, sizeof (buffer));
+    OK(escape_string (buffer, sizeof (buffer)) == 0);
+    EXPECT_EQ_STR(cases[i].want, buffer);
+  }
+
+  return 0;
+}
+
 DEF_TEST(strunescape)
 {
   char buffer[16];
@@ -197,23 +252,23 @@ DEF_TEST(strunescape)
   strncpy (buffer, "foo\\tbar", sizeof (buffer));
   status = strunescape (buffer, sizeof (buffer));
   OK(status == 0);
-  STREQ ("foo\tbar", buffer);
+  EXPECT_EQ_STR ("foo\tbar", buffer);
 
   strncpy (buffer, "\\tfoo\\r\\n", sizeof (buffer));
   status = strunescape (buffer, sizeof (buffer));
   OK(status == 0);
-  STREQ ("\tfoo\r\n", buffer);
+  EXPECT_EQ_STR ("\tfoo\r\n", buffer);
 
   strncpy (buffer, "With \\\"quotes\\\"", sizeof (buffer));
   status = strunescape (buffer, sizeof (buffer));
   OK(status == 0);
-  STREQ ("With \"quotes\"", buffer);
+  EXPECT_EQ_STR ("With \"quotes\"", buffer);
 
   /* Backslash before null byte */
   strncpy (buffer, "\\tbackslash end\\", sizeof (buffer));
   status = strunescape (buffer, sizeof (buffer));
   OK(status != 0);
-  STREQ ("\tbackslash end", buffer);
+  EXPECT_EQ_STR ("\tbackslash end", buffer);
   return (0);
 
   /* Backslash at buffer end */
@@ -231,6 +286,100 @@ DEF_TEST(strunescape)
   return (0);
 }
 
+DEF_TEST(parse_values)
+{
+  struct {
+    char buffer[64];
+    int status;
+    gauge_t value;
+  } cases[] = {
+    {"1435044576:42",     0, 42.0},
+    {"1435044576:42:23", -1,  NAN},
+    {"1435044576:U",      0,  NAN},
+    {"N:12.3",            0, 12.3},
+    {"N:42.0:23",        -1,  NAN},
+    {"N:U",               0,  NAN},
+    {"T:42.0",           -1,  NAN},
+  };
+
+  size_t i;
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++)
+  {
+    data_source_t dsrc = {
+      .name = "value",
+      .type = DS_TYPE_GAUGE,
+      .min = 0.0,
+      .max = NAN,
+    };
+    data_set_t ds = {
+      .type = "example",
+      .ds_num = 1,
+      .ds = &dsrc,
+    };
+
+    value_t v = {
+      .gauge = NAN,
+    };
+    value_list_t vl = {
+      .values = &v,
+      .values_len = 1,
+      .time = 0,
+      .interval = 0,
+      .host = "example.com",
+      .plugin = "common_test",
+      .type = "example",
+      .meta = NULL,
+    };
+
+    int status = parse_values (cases[i].buffer, &vl, &ds);
+    EXPECT_EQ_INT (cases[i].status, status);
+    if (status != 0)
+      continue;
+
+    EXPECT_EQ_DOUBLE (cases[i].value, vl.values[0].gauge);
+  }
+
+  return (0);
+}
+
+DEF_TEST(value_to_rate)
+{
+  struct {
+    time_t t0;
+    time_t t1;
+    int ds_type;
+    value_t v0;
+    value_t v1;
+    gauge_t want;
+  } cases[] = {
+    { 0, 10, DS_TYPE_DERIVE,  {.derive  =    0}, {.derive = 1000},   NAN},
+    {10, 20, DS_TYPE_DERIVE,  {.derive  = 1000}, {.derive = 2000}, 100.0},
+    {20, 30, DS_TYPE_DERIVE,  {.derive  = 2000}, {.derive = 1800}, -20.0},
+    { 0, 10, DS_TYPE_COUNTER, {.counter =    0}, {.counter = 1000},   NAN},
+    {10, 20, DS_TYPE_COUNTER, {.counter = 1000}, {.counter = 5000}, 400.0},
+    /* 32bit wrap-around. */
+    {20, 30, DS_TYPE_COUNTER, {.counter = 4294967238ULL}, {.counter =   42}, 10.0},
+    /* 64bit wrap-around. */
+    {30, 40, DS_TYPE_COUNTER, {.counter = 18446744073709551558ULL}, {.counter =   42}, 10.0},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    value_to_rate_state_t state = { cases[i].v0, TIME_T_TO_CDTIME_T (cases[i].t0) };
+    gauge_t got;
+
+    if (cases[i].t0 == 0) {
+      OK(value_to_rate (&got, cases[i].v1, cases[i].ds_type, TIME_T_TO_CDTIME_T(cases[i].t1), &state) == EAGAIN);
+      continue;
+    }
+
+    OK(value_to_rate (&got, cases[i].v1, cases[i].ds_type, TIME_T_TO_CDTIME_T(cases[i].t1), &state) == 0);
+    EXPECT_EQ_DOUBLE(cases[i].want, got);
+  }
+
+  return 0;
+}
+
 int main (void)
 {
   RUN_TEST(sstrncpy);
@@ -238,7 +387,11 @@ int main (void)
   RUN_TEST(sstrdup);
   RUN_TEST(strsplit);
   RUN_TEST(strjoin);
+  RUN_TEST(escape_slashes);
+  RUN_TEST(escape_string);
   RUN_TEST(strunescape);
+  RUN_TEST(parse_values);
+  RUN_TEST(value_to_rate);
 
   END_TEST;
 }
index ae3e798..ae9ab3a 100644 (file)
@@ -290,20 +290,25 @@ static int dispatch_loadplugin (oconfig_item_t *ci)
        /* default to the global interval set before loading this plugin */
        memset (&ctx, 0, sizeof (ctx));
        ctx.interval = cf_get_default_interval ();
+       ctx.flush_interval = 0;
+       ctx.flush_timeout = 0;
 
-       for (i = 0; i < ci->children_num; ++i) {
-               if (strcasecmp("Globals", ci->children[i].key) == 0)
-                       cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
-               else if (strcasecmp ("Interval", ci->children[i].key) == 0) {
-                       if (cf_util_get_cdtime (ci->children + i, &ctx.interval) != 0) {
-                               /* cf_util_get_cdtime will log an error */
-                               continue;
-                       }
-               }
+       for (i = 0; i < ci->children_num; ++i)
+       {
+               oconfig_item_t *child = ci->children + i;
+
+               if (strcasecmp("Globals", child->key) == 0)
+                       cf_util_get_flag (child, &flags, PLUGIN_FLAGS_GLOBAL);
+               else if (strcasecmp ("Interval", child->key) == 0)
+                       cf_util_get_cdtime (child, &ctx.interval);
+               else if (strcasecmp ("FlushInterval", child->key) == 0)
+                       cf_util_get_cdtime (child, &ctx.flush_interval);
+               else if (strcasecmp ("FlushTimeout", child->key) == 0)
+                       cf_util_get_cdtime (child, &ctx.flush_timeout);
                else {
                        WARNING("Ignoring unknown LoadPlugin option \"%s\" "
                                        "for plugin \"%s\"",
-                                       ci->children[i].key, ci->values[0].value.string);
+                                       child->key, ci->values[0].value.string);
                }
        }
 
diff --git a/src/daemon/meta_data_test.c b/src/daemon/meta_data_test.c
new file mode 100644 (file)
index 0000000..b4c0e27
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * collectd - src/daemon/meta_data_test.c
+ * Copyright (C) 2015       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 <octo at collectd.org>
+ */
+
+#include "testing.h"
+#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
+#include "meta_data.h"
+
+DEF_TEST(base)
+{
+  meta_data_t *m;
+
+  char *s;
+  int64_t si;
+  uint64_t ui;
+  double d;
+  _Bool b;
+
+  CHECK_NOT_NULL (m = meta_data_create ());
+
+  /* all of these are absent */
+  OK(meta_data_get_string (m, "string", &s) != 0);
+  OK(meta_data_get_signed_int (m, "signed_int", &si) != 0);
+  OK(meta_data_get_unsigned_int (m, "unsigned_int", &ui) != 0);
+  OK(meta_data_get_double (m, "double", &d) != 0);
+  OK(meta_data_get_boolean (m, "boolean", &b) != 0);
+
+  /* populate structure */
+  CHECK_ZERO (meta_data_add_string (m, "string", "foobar"));
+  OK(meta_data_exists (m, "string"));
+  OK(meta_data_type (m, "string") == MD_TYPE_STRING);
+
+  CHECK_ZERO (meta_data_add_signed_int (m, "signed_int", -1));
+  OK(meta_data_exists (m, "signed_int"));
+  OK(meta_data_type (m, "signed_int") == MD_TYPE_SIGNED_INT);
+
+  CHECK_ZERO (meta_data_add_unsigned_int (m, "unsigned_int", 1));
+  OK(meta_data_exists (m, "unsigned_int"));
+  OK(meta_data_type (m, "unsigned_int") == MD_TYPE_UNSIGNED_INT);
+
+  CHECK_ZERO (meta_data_add_double (m, "double", 47.11));
+  OK(meta_data_exists (m, "double"));
+  OK(meta_data_type (m, "double") == MD_TYPE_DOUBLE);
+
+  CHECK_ZERO (meta_data_add_boolean (m, "boolean", 1));
+  OK(meta_data_exists (m, "boolean"));
+  OK(meta_data_type (m, "boolean") == MD_TYPE_BOOLEAN);
+
+  /* retrieve and check all values */
+  CHECK_ZERO (meta_data_get_string (m, "string", &s));
+  EXPECT_EQ_STR ("foobar", s);
+  sfree (s);
+
+  CHECK_ZERO (meta_data_get_signed_int (m, "signed_int", &si));
+  EXPECT_EQ_INT (-1, (int) si);
+
+  CHECK_ZERO (meta_data_get_unsigned_int (m, "unsigned_int", &ui));
+  EXPECT_EQ_INT (1, (int) ui);
+
+  CHECK_ZERO (meta_data_get_double (m, "double", &d));
+  EXPECT_EQ_DOUBLE (47.11, d);
+
+  CHECK_ZERO (meta_data_get_boolean (m, "boolean", &b));
+  OK1 (b, "b evaluates to true");
+
+  /* retrieving the wrong type always fails */
+  EXPECT_EQ_INT (-2, meta_data_get_boolean (m, "string", &b));
+  EXPECT_EQ_INT (-2, meta_data_get_string (m, "signed_int", &s));
+  EXPECT_EQ_INT (-2, meta_data_get_string (m, "unsigned_int", &s));
+  EXPECT_EQ_INT (-2, meta_data_get_string (m, "double", &s));
+  EXPECT_EQ_INT (-2, meta_data_get_string (m, "boolean", &s));
+
+  /* replace existing keys */
+  CHECK_ZERO (meta_data_add_signed_int (m, "string", 666));
+  OK(meta_data_type (m, "string") == MD_TYPE_SIGNED_INT);
+
+  CHECK_ZERO (meta_data_add_signed_int (m, "signed_int", 666));
+  CHECK_ZERO (meta_data_get_signed_int (m, "signed_int", &si));
+  EXPECT_EQ_INT (666, (int) si);
+
+  /* deleting keys */
+  CHECK_ZERO (meta_data_delete (m, "signed_int"));
+  EXPECT_EQ_INT (-2, meta_data_delete (m, "doesnt exist"));
+
+  meta_data_destroy (m);
+  return 0;
+}
+
+int main (void)
+{
+  RUN_TEST(base);
+
+  END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
index 3da8ecc..831e3fb 100644 (file)
@@ -80,6 +80,12 @@ struct write_queue_s
        write_queue_t *next;
 };
 
+struct flush_callback_s {
+       char *name;
+       cdtime_t timeout;
+};
+typedef struct flush_callback_s flush_callback_t;
+
 /*
  * Private variables
  */
@@ -883,7 +889,7 @@ static void start_write_threads (size_t num) /* {{{ */
 static void stop_write_threads (void) /* {{{ */
 {
        write_queue_t *q;
-       int i;
+       size_t i;
 
        if (write_threads == NULL)
                return;
@@ -924,7 +930,7 @@ static void stop_write_threads (void) /* {{{ */
 
        if (i > 0)
        {
-               WARNING ("plugin: %i value list%s left after shutting down "
+               WARNING ("plugin: %zu value list%s left after shutting down "
                                "the write threads.",
                                i, (i == 1) ? " was" : "s were");
        }
@@ -1083,6 +1089,7 @@ int plugin_load (char const *plugin_name, uint32_t flags)
                        /* success */
                        plugin_mark_loaded (plugin_name);
                        ret = 0;
+                       INFO ("plugin_load: plugin \"%s\" successfully loaded.", plugin_name);
                        break;
                }
                else
@@ -1247,7 +1254,7 @@ int plugin_register_read (const char *name,
 
 int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
-               const struct timespec *interval,
+               cdtime_t interval,
                user_data_t *user_data)
 {
        read_func_t *rf;
@@ -1268,10 +1275,7 @@ int plugin_register_complex_read (const char *group, const char *name,
                rf->rf_group[0] = '\0';
        rf->rf_name = strdup (name);
        rf->rf_type = RF_COMPLEX;
-       if (interval != NULL)
-               rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
-       else
-               rf->rf_interval = plugin_get_interval ();
+       rf->rf_interval = (interval != 0) ? interval : plugin_get_interval ();
 
        /* Set user data */
        if (user_data == NULL)
@@ -1302,11 +1306,105 @@ int plugin_register_write (const char *name,
                                (void *) callback, ud));
 } /* int plugin_register_write */
 
+static int plugin_flush_timeout_callback (user_data_t *ud)
+{
+       flush_callback_t *cb = ud->data;
+
+       return plugin_flush (cb->name, cb->timeout, /* identifier = */ NULL);
+} /* static int plugin_flush_callback */
+
+static void plugin_flush_timeout_callback_free (void *data)
+{
+       flush_callback_t *cb = data;
+
+       if (cb == NULL) return;
+
+       sfree(cb->name);
+       sfree(cb);
+} /* static void plugin_flush_callback_free */
+
+static char *plugin_flush_callback_name (const char *name)
+{
+       char *flush_prefix = "flush/";
+       size_t prefix_size;
+       char *flush_name;
+       size_t name_size;
+
+       prefix_size = strlen(flush_prefix);
+       name_size = strlen(name);
+
+       flush_name = malloc (sizeof(char) * (name_size + prefix_size + 1));
+       if (flush_name == NULL)
+       {
+               ERROR ("plugin_flush_callback_name: malloc failed.");
+               return (NULL);
+       }
+
+       sstrncpy (flush_name, flush_prefix, prefix_size + 1);
+       sstrncpy (flush_name + prefix_size, name, name_size + 1);
+
+       return flush_name;
+} /* static char *plugin_flush_callback_name */
+
 int plugin_register_flush (const char *name,
                plugin_flush_cb callback, user_data_t *ud)
 {
-       return (create_register_callback (&list_flush, name,
-                               (void *) callback, ud));
+       int status;
+       plugin_ctx_t ctx = plugin_get_ctx ();
+
+       status = create_register_callback (&list_flush, name,
+               (void *) callback, ud);
+       if (status != 0)
+               return status;
+
+       if (ctx.flush_interval != 0)
+       {
+               char *flush_name;
+               user_data_t ud;
+               flush_callback_t *cb;
+
+               flush_name = plugin_flush_callback_name (name);
+               if (flush_name == NULL)
+                       return (-1);
+
+               cb = malloc(sizeof(flush_callback_t));
+               if (cb == NULL)
+               {
+                       ERROR ("plugin_register_flush: malloc failed.");
+                       sfree(flush_name);
+                       return (-1);
+               }
+
+               cb->name = strdup (name);
+               if (cb->name == NULL)
+               {
+                       ERROR ("plugin_register_flush: strdup failed.");
+                       sfree(cb);
+                       sfree(flush_name);
+                       return (-1);
+               }
+               cb->timeout = ctx.flush_timeout;
+
+               ud.data = cb;
+               ud.free_func = plugin_flush_timeout_callback_free;
+
+               status = plugin_register_complex_read (
+                       /* group     = */ "flush",
+                       /* name      = */ flush_name,
+                       /* callback  = */ plugin_flush_timeout_callback,
+                       /* interval  = */ ctx.flush_interval,
+                       /* user data = */ &ud);
+
+               sfree(flush_name);
+               if (status != 0)
+               {
+                       sfree(cb->name);
+                       sfree(cb);
+                       return status;
+               }
+       }
+
+       return 0;
 } /* int plugin_register_flush */
 
 int plugin_register_missing (const char *name,
@@ -1347,7 +1445,7 @@ static void plugin_free_data_sets (void)
 int plugin_register_data_set (const data_set_t *ds)
 {
        data_set_t *ds_copy;
-       int i;
+       size_t i;
 
        if ((data_sets != NULL)
                        && (c_avl_get (data_sets, ds->type, NULL) == 0))
@@ -1525,7 +1623,21 @@ int plugin_unregister_write (const char *name)
 
 int plugin_unregister_flush (const char *name)
 {
-       return (plugin_unregister (list_flush, name));
+       plugin_ctx_t ctx = plugin_get_ctx ();
+
+       if (ctx.flush_interval != 0)
+       {
+               char *flush_name;
+
+               flush_name = plugin_flush_callback_name (name);
+               if (flush_name != NULL)
+               {
+                       plugin_unregister_read(flush_name);
+                       sfree(flush_name);
+               }
+       }
+
+       return plugin_unregister (list_flush, name);
 }
 
 int plugin_unregister_missing (const char *name)
@@ -1613,8 +1725,6 @@ void plugin_init_all (void)
                write_threads_num = 5;
        }
 
-       start_write_threads ((size_t) write_threads_num);
-
        if ((list_init == NULL) && (read_heap == NULL))
                return;
 
@@ -1650,6 +1760,8 @@ void plugin_init_all (void)
                le = le->next;
        }
 
+       start_write_threads ((size_t) write_threads_num);
+
        max_read_interval = global_option_get_time ("MaxReadInterval",
                        DEFAULT_MAX_READ_INTERVAL);
 
@@ -2031,8 +2143,8 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
        if (ds->ds_num != vl->values_len)
        {
                ERROR ("plugin_dispatch_values: ds->type = %s: "
-                               "(ds->ds_num = %i) != "
-                               "(vl->values_len = %i)",
+                               "(ds->ds_num = %zu) != "
+                               "(vl->values_len = %zu)",
                                ds->type, ds->ds_num, vl->values_len);
                return (-1);
        }
index 70a2232..b1adb52 100644 (file)
@@ -97,7 +97,7 @@ typedef union value_u value_t;
 struct value_list_s
 {
        value_t *values;
-       int      values_len;
+       size_t   values_len;
        cdtime_t time;
        cdtime_t interval;
        char     host[DATA_MAX_NAME_LEN];
@@ -125,7 +125,7 @@ typedef struct data_source_s data_source_t;
 struct data_set_s
 {
        char           type[DATA_MAX_NAME_LEN];
-       int            ds_num;
+       size_t         ds_num;
        data_source_t *ds;
 };
 typedef struct data_set_s data_set_t;
@@ -177,6 +177,8 @@ typedef struct user_data_s user_data_t;
 struct plugin_ctx_s
 {
        cdtime_t interval;
+       cdtime_t flush_interval;
+       cdtime_t flush_timeout;
 };
 typedef struct plugin_ctx_s plugin_ctx_t;
 
@@ -293,7 +295,7 @@ int plugin_register_read (const char *name,
  * "plugin_register_complex_read" returns an error (non-zero). */
 int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
-               const struct timespec *interval,
+               cdtime_t interval,
                user_data_t *user_data);
 int plugin_register_write (const char *name,
                plugin_write_cb callback, user_data_t *user_data);
index 8652880..f7bf1c0 100644 (file)
 
 #include "plugin.h"
 
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc = NULL;
+#endif /* HAVE_LIBKSTAT */
+
 void plugin_log (int level, char const *format, ...)
 {
   char buffer[1024];
index c0e61c5..75a980a 100644 (file)
@@ -101,7 +101,7 @@ static void parse_line (char *buf)
   char  *fields[64];
   size_t fields_num;
   data_set_t *ds;
-  int i;
+  size_t i;
 
   fields_num = strsplit (buf, fields, 64);
   if (fields_num < 2)
@@ -128,7 +128,7 @@ static void parse_line (char *buf)
     if (parse_ds (ds->ds + i, fields[i + 1], strlen (fields[i + 1])) != 0)
     {
       sfree (ds->ds);
-      ERROR ("types_list: parse_line: Cannot parse data source #%i "
+      ERROR ("types_list: parse_line: Cannot parse data source #%zu "
          "of data set %s", i, ds->type);
       return;
     }
index 7621395..3f7a596 100644 (file)
@@ -37,7 +37,7 @@
 typedef struct cache_entry_s
 {
        char name[6 * DATA_MAX_NAME_LEN];
-       int        values_num;
+       size_t     values_num;
        gauge_t   *values_gauge;
        value_t   *values_raw;
        /* Time contained in the package
@@ -79,7 +79,7 @@ static int cache_compare (const cache_entry_t *a, const cache_entry_t *b)
   return (strcmp (a->name, b->name));
 } /* int cache_compare */
 
-static cache_entry_t *cache_alloc (int values_num)
+static cache_entry_t *cache_alloc (size_t values_num)
 {
   cache_entry_t *ce;
 
@@ -128,7 +128,7 @@ static void cache_free (cache_entry_t *ce)
 
 static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
 {
-  int i;
+  size_t i;
 
   for (i = 0; i < ds->ds_num; i++)
   {
@@ -144,9 +144,9 @@ static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
 static int uc_insert (const data_set_t *ds, const value_list_t *vl,
     const char *key)
 {
-  int i;
   char *key_copy;
   cache_entry_t *ce;
+  size_t i;
 
   /* `cache_lock' has been locked by `uc_update' */
 
@@ -161,7 +161,7 @@ static int uc_insert (const data_set_t *ds, const value_list_t *vl,
   if (ce == NULL)
   {
     sfree (key_copy);
-    ERROR ("uc_insert: cache_alloc (%i) failed.", ds->ds_num);
+    ERROR ("uc_insert: cache_alloc (%zu) failed.", ds->ds_num);
     return (-1);
   }
 
@@ -374,7 +374,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
   char name[6 * DATA_MAX_NAME_LEN];
   cache_entry_t *ce = NULL;
   int status;
-  int i;
+  size_t i;
 
   if (FORMAT_VL (name, sizeof (name), vl) != 0)
   {
@@ -412,23 +412,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
     {
       case DS_TYPE_COUNTER:
        {
-         counter_t diff;
-
-         /* check if the counter has wrapped around */
-         if (vl->values[i].counter < ce->values_raw[i].counter)
-         {
-           if (ce->values_raw[i].counter <= 4294967295U)
-             diff = (4294967295U - ce->values_raw[i].counter)
-               + vl->values[i].counter;
-           else
-             diff = (18446744073709551615ULL - ce->values_raw[i].counter)
-               + vl->values[i].counter;
-         }
-         else /* counter has NOT wrapped around */
-         {
-           diff = vl->values[i].counter - ce->values_raw[i].counter;
-         }
-
+         counter_t diff = counter_diff (ce->values_raw[i].counter, vl->values[i].counter);
          ce->values_gauge[i] = ((double) diff)
            / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
          ce->values_raw[i].counter = vl->values[i].counter;
@@ -442,9 +426,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
 
       case DS_TYPE_DERIVE:
        {
-         derive_t diff;
-
-         diff = vl->values[i].derive - ce->values_raw[i].derive;
+         derive_t diff = vl->values[i].derive - ce->values_raw[i].derive;
 
          ce->values_gauge[i] = ((double) diff)
            / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
@@ -466,7 +448,7 @@ int uc_update (const data_set_t *ds, const value_list_t *vl)
        return (-1);
     } /* switch (ds->ds[i].type) */
 
-    DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]);
+    DEBUG ("uc_update: %s: ds[%zu] = %lf", name, i, ce->values_gauge[i]);
   } /* for (i) */
 
   /* Update the history if it exists. */
@@ -566,7 +548,7 @@ gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
    * values are returned. */
   if (ret_num != (size_t) ds->ds_num)
   {
-    ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
+    ERROR ("utils_cache: uc_get_rate: ds[%s] has %zu values, "
        "but uc_get_rate_by_name returned %zu.",
        ds->type, ds->ds_num, ret_num);
     sfree (ret);
index 6c78d64..37f21ed 100644 (file)
@@ -26,7 +26,8 @@
 
 #include "utils_cache.h"
 
-gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
+gauge_t *uc_get_rate (__attribute((unused)) data_set_t const *ds,
+                      __attribute((unused)) value_list_t const *vl)
 {
   return (NULL);
 }
diff --git a/src/daemon/utils_ignorelist.c b/src/daemon/utils_ignorelist.c
new file mode 100644 (file)
index 0000000..a8ca7db
--- /dev/null
@@ -0,0 +1,338 @@
+/**
+ * collectd - src/utils_ignorelist.c
+ * Copyright (C) 2006 Lubos Stanek <lubek at users.sourceforge.net>
+ * Copyright (C) 2008 Florian Forster <octo at collectd.org>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; either
+ * version 2 of the Licence, or any later version.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ *   Lubos Stanek <lubek at users.sourceforge.net>
+ *   Florian Forster <octo at collectd.org>
+ **/
+/**
+ * ignorelist handles plugin's list of configured collectable
+ * entries with global ignore action
+ **/
+/**
+ * Usage:
+ * 
+ * Define plugin's global pointer variable of type ignorelist_t:
+ *   ignorelist_t *myconfig_ignore;
+ * If you know the state of the global ignore (IgnoreSelected),
+ * allocate the variable with:
+ *   myconfig_ignore = ignorelist_create (YourKnownIgnore);
+ * If you do not know the state of the global ignore,
+ * initialize the global variable and set the ignore flag later:
+ *   myconfig_ignore = ignorelist_init ();
+ * Append single entries in your cf_register'ed callback function:
+ *   ignorelist_add (myconfig_ignore, newentry);
+ * When you hit the IgnoreSelected config option,
+ * offer it to the list:
+ *   ignorelist_ignore (myconfig_ignore, instantly_got_value_of_ignore);
+ * That is all for the ignorelist initialization.
+ * Later during read and write (plugin's registered functions) get
+ * the information whether this entry would be collected or not:
+ *   if (ignorelist_match (myconfig_ignore, thisentry))
+ *     return;
+ **/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "common.h"
+#include "plugin.h"
+#include "utils_ignorelist.h"
+
+/*
+ * private prototypes
+ */
+struct ignorelist_item_s
+{
+#if HAVE_REGEX_H
+       regex_t *rmatch;        /* regular expression entry identification */
+#endif
+       char *smatch;           /* string entry identification */
+       struct ignorelist_item_s *next;
+};
+typedef struct ignorelist_item_s ignorelist_item_t;
+
+struct ignorelist_s
+{
+       int ignore;             /* ignore entries */
+       ignorelist_item_t *head;        /* pointer to the first entry */
+};
+
+/* *** *** *** ********************************************* *** *** *** */
+/* *** *** *** *** *** ***   private functions   *** *** *** *** *** *** */
+/* *** *** *** ********************************************* *** *** *** */
+
+static inline void ignorelist_append (ignorelist_t *il, ignorelist_item_t *item)
+{
+       assert ((il != NULL) && (item != NULL));
+
+       item->next = il->head;
+       il->head = item;
+}
+
+#if HAVE_REGEX_H
+static int ignorelist_append_regex(ignorelist_t *il, const char *re_str)
+{
+       regex_t *re;
+       ignorelist_item_t *entry;
+       int status;
+
+       re = malloc (sizeof (*re));
+       if (re == NULL)
+       {
+               ERROR ("utils_ignorelist: malloc failed");
+               return (ENOMEM);
+       }
+       memset (re, 0, sizeof (*re));
+
+       status = regcomp (re, re_str, REG_EXTENDED);
+       if (status != 0)
+       {
+               char errbuf[1024] = "";
+               regerror (status, re, errbuf, sizeof (errbuf));
+               ERROR ("utils_ignorelist: regcomp failed: %s", errbuf);
+               regfree (re);
+               sfree (re);
+               return (status);
+       }
+
+       entry = malloc (sizeof (*entry));
+       if (entry == NULL)
+       {
+               ERROR ("utils_ignorelist: malloc failed");
+               regfree (re);
+               sfree (re);
+               return (ENOMEM);
+       }
+       memset (entry, 0, sizeof (*entry));
+       entry->rmatch = re;
+
+       ignorelist_append (il, entry);
+       return (0);
+} /* int ignorelist_append_regex */
+#endif
+
+static int ignorelist_append_string(ignorelist_t *il, const char *entry)
+{
+       ignorelist_item_t *new;
+
+       /* create new entry */
+       if ((new = malloc(sizeof(ignorelist_item_t))) == NULL )
+       {
+               ERROR ("cannot allocate new entry");
+               return (1);
+       }
+       memset (new, '\0', sizeof(ignorelist_item_t));
+       new->smatch = sstrdup(entry);
+
+       /* append new entry */
+       ignorelist_append (il, new);
+
+       return (0);
+} /* int ignorelist_append_string(ignorelist_t *il, const char *entry) */
+
+#if HAVE_REGEX_H
+/*
+ * check list for entry regex match
+ * return 1 if found
+ */
+static int ignorelist_match_regex (ignorelist_item_t *item, const char *entry)
+{
+       assert ((item != NULL) && (item->rmatch != NULL)
+                       && (entry != NULL) && (strlen (entry) > 0));
+
+       /* match regex */
+       if (regexec (item->rmatch, entry, 0, NULL, 0) == 0)
+               return (1);
+
+       return (0);
+} /* int ignorelist_match_regex (ignorelist_item_t *item, const char *entry) */
+#endif
+
+/*
+ * check list for entry string match
+ * return 1 if found
+ */
+static int ignorelist_match_string (ignorelist_item_t *item, const char *entry)
+{
+       assert ((item != NULL) && (item->smatch != NULL)
+                       && (entry != NULL) && (strlen (entry) > 0));
+
+       if (strcmp (entry, item->smatch) == 0)
+               return (1);
+
+       return (0);
+} /* int ignorelist_match_string (ignorelist_item_t *item, const char *entry) */
+
+
+/* *** *** *** ******************************************** *** *** *** */
+/* *** *** *** *** *** ***   public functions   *** *** *** *** *** *** */
+/* *** *** *** ******************************************** *** *** *** */
+
+/*
+ * create the ignorelist_t with known ignore state
+ * return pointer to ignorelist_t
+ */
+ignorelist_t *ignorelist_create (int invert)
+{
+       ignorelist_t *il;
+
+       /* smalloc exits if it failes */
+       il = (ignorelist_t *) smalloc (sizeof (ignorelist_t));
+       memset (il, '\0', sizeof (ignorelist_t));
+
+       /*
+        * ->ignore == 0  =>  collect
+        * ->ignore == 1  =>  ignore
+        */
+       il->ignore = invert ? 0 : 1;
+
+       return (il);
+} /* ignorelist_t *ignorelist_create (int ignore) */
+
+/*
+ * free memory used by ignorelist_t
+ */
+void ignorelist_free (ignorelist_t *il)
+{
+       ignorelist_item_t *this;
+       ignorelist_item_t *next;
+
+       if (il == NULL)
+               return;
+
+       for (this = il->head; this != NULL; this = next)
+       {
+               next = this->next;
+#if HAVE_REGEX_H
+               if (this->rmatch != NULL)
+               {
+                       regfree (this->rmatch);
+                       sfree (this->rmatch);
+                       this->rmatch = NULL;
+               }
+#endif
+               if (this->smatch != NULL)
+               {
+                       sfree (this->smatch);
+                       this->smatch = NULL;
+               }
+               sfree (this);
+       }
+
+       sfree (il);
+       il = NULL;
+} /* void ignorelist_destroy (ignorelist_t *il) */
+
+/*
+ * set ignore state of the ignorelist_t
+ */
+void ignorelist_set_invert (ignorelist_t *il, int invert)
+{
+       if (il == NULL)
+       {
+               DEBUG("ignore call with ignorelist_t == NULL");
+               return;
+       }
+
+       il->ignore = invert ? 0 : 1;
+} /* void ignorelist_set_invert (ignorelist_t *il, int ignore) */
+
+/*
+ * append entry into ignorelist_t
+ * return 0 for success
+ */
+int ignorelist_add (ignorelist_t *il, const char *entry)
+{
+       size_t entry_len;
+
+       if (il == NULL)
+       {
+               DEBUG ("add called with ignorelist_t == NULL");
+               return (1);
+       }
+
+       entry_len = strlen (entry);
+
+       /* append nothing */
+       if (entry_len == 0)
+       {
+               DEBUG("not appending: empty entry");
+               return (1);
+       }
+
+#if HAVE_REGEX_H
+       /* regex string is enclosed in "/.../" */
+       if ((entry_len > 2) && (entry[0] == '/') && entry[entry_len - 1] == '/')
+       {
+               char *entry_copy;
+               size_t entry_copy_size;
+               int status;
+
+               /* We need to copy `entry' since it's const */
+               entry_copy_size = entry_len - 1;
+               entry_copy = smalloc (entry_copy_size);
+               sstrncpy (entry_copy, entry + 1, entry_copy_size);
+
+               status = ignorelist_append_regex(il, entry_copy);
+               sfree (entry_copy);
+               return status;
+       }
+#endif
+
+       return ignorelist_append_string(il, entry);
+} /* int ignorelist_add (ignorelist_t *il, const char *entry) */
+
+/*
+ * check list for entry
+ * return 1 for ignored entry
+ */
+int ignorelist_match (ignorelist_t *il, const char *entry)
+{
+       ignorelist_item_t *traverse;
+
+       /* if no entries, collect all */
+       if ((il == NULL) || (il->head == NULL))
+               return (0);
+
+       if ((entry == NULL) || (strlen (entry) == 0))
+               return (0);
+
+       /* traverse list and check entries */
+       for (traverse = il->head; traverse != NULL; traverse = traverse->next)
+       {
+#if HAVE_REGEX_H
+               if (traverse->rmatch != NULL)
+               {
+                       if (ignorelist_match_regex (traverse, entry))
+                               return (il->ignore);
+               }
+               else
+#endif
+               {
+                       if (ignorelist_match_string (traverse, entry))
+                               return (il->ignore);
+               }
+       } /* for traverse */
+
+       return (1 - il->ignore);
+} /* int ignorelist_match (ignorelist_t *il, const char *entry) */
+
diff --git a/src/daemon/utils_ignorelist.h b/src/daemon/utils_ignorelist.h
new file mode 100644 (file)
index 0000000..b47b55a
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * collectd - src/utils_ignorelist.h
+ * Copyright (C) 2006 Lubos Stanek <lubek at users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/
+ * or modify it under the terms of the GNU General Public Li-
+ * cence as published by the Free Software Foundation; either
+ * version 2 of the Licence, or any later version.
+ *
+ * This program is distributed in the hope that it will be use-
+ * ful, but WITHOUT ANY WARRANTY; without even the implied war-
+ * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * Licence along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * Authors:
+ *   Lubos Stanek <lubek at users.sourceforge.net>
+ **/
+/**
+ * ignorelist handles plugin's list of configured collectable
+ * entries with global ignore action
+ **/
+
+#ifndef UTILS_IGNORELIST_H
+#define UTILS_IGNORELIST_H 1
+
+#include "collectd.h"
+
+#if HAVE_REGEX_H
+# include <regex.h>
+#endif
+
+/* public prototypes */
+
+struct ignorelist_s;
+typedef struct ignorelist_s ignorelist_t;
+
+/*
+ * create the ignorelist_t with known ignore state
+ * return pointer to ignorelist_t
+ */
+ignorelist_t *ignorelist_create (int invert);
+
+/*
+ * free memory used by ignorelist_t
+ */
+void ignorelist_free (ignorelist_t *il);
+
+/*
+ * set ignore state of the ignorelist_t
+ */
+void ignorelist_set_invert (ignorelist_t *il, int invert);
+
+/*
+ * append entry to ignorelist_t
+ * returns zero on success, non-zero upon failure.
+ */
+int ignorelist_add (ignorelist_t *il, const char *entry);
+
+/*
+ * check list for entry
+ * return 1 for ignored entry
+ */
+int ignorelist_match (ignorelist_t *il, const char *entry);
+
+#endif /* UTILS_IGNORELIST_H */
index 2f28eb9..43634df 100644 (file)
 #include "collectd.h"
 #include "common.h"
 
-char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
+char *subst (char *buf, size_t buflen, const char *string, size_t off1, size_t off2,
                const char *replacement)
 {
-       char  *buf_ptr = buf;
-       size_t len     = buflen;
+       char *out = buf;
 
-       if ((NULL == buf) || (0 >= buflen) || (NULL == string)
-                       || (0 > off1) || (0 > off2) || (off1 > off2)
-                       || (NULL == replacement))
+       char const *front;
+       char const *back;
+       size_t front_len;
+       size_t replacement_len;
+       size_t back_len;
+
+       if ((NULL == buf) || (0 == buflen) || (NULL == string) || (NULL == replacement))
                return NULL;
 
-       sstrncpy (buf_ptr, string,
-                       ((size_t)off1 + 1 > buflen) ? buflen : (size_t)off1 + 1);
-       buf_ptr += off1;
-       len     -= off1;
+       size_t string_len = strlen (string);
+       if ((off1 > string_len) || (off2 > string_len) || (off1 > off2))
+               return NULL;
 
-       if (0 >= len)
-               return buf;
+       front = string;
+       back = string + off2;
+       front_len = off1;
+       replacement_len = strlen (replacement);
+       back_len = strlen (back);
+
+       if (front_len >= buflen) {
+               front_len = buflen - 1;
+               replacement_len = 0;
+               back_len = 0;
+       } else if ((front_len + replacement_len) >= buflen) {
+               replacement_len = buflen - (front_len + 1);
+               back_len = 0;
+       } else if ((front_len + replacement_len + back_len) >= buflen) {
+               back_len = buflen - (front_len + replacement_len + 1);
+       } else {
+               buflen = front_len + replacement_len + back_len + 1;
+       }
+       assert ((front_len + replacement_len + back_len) == (buflen - 1));
 
-       sstrncpy (buf_ptr, replacement, len);
-       buf_ptr += strlen (replacement);
-       len     -= strlen (replacement);
+       if (front_len != 0) {
+               sstrncpy (out, front, front_len + 1);
+               out += front_len;
+       }
 
-       if (0 >= len)
-               return buf;
+       if (replacement_len != 0) {
+               sstrncpy (out, replacement, replacement_len + 1);
+               out += replacement_len;
+       }
 
-       sstrncpy (buf_ptr, string + off2, len);
+       if (back_len != 0) {
+               sstrncpy (out, back, back_len + 1);
+               out += back_len;
+       }
+
+       out[0] = 0;
        return buf;
 } /* subst */
 
@@ -87,7 +114,6 @@ char *asubst (const char *string, int off1, int off2, const char *replacement)
 char *subst_string (char *buf, size_t buflen, const char *string,
                const char *needle, const char *replacement)
 {
-       char *temp;
        size_t needle_len;
        size_t i;
 
@@ -95,19 +121,13 @@ char *subst_string (char *buf, size_t buflen, const char *string,
                        || (needle == NULL) || (replacement == NULL))
                return (NULL);
 
-       temp = (char *) malloc (buflen);
-       if (temp == NULL)
-       {
-               ERROR ("subst_string: malloc failed.");
-               return (NULL);
-       }
-
        needle_len = strlen (needle);
-       strncpy (buf, string, buflen);
+       sstrncpy (buf, string, buflen);
 
        /* Limit the loop to prevent endless loops. */
        for (i = 0; i < buflen; i++)
        {
+               char temp[buflen];
                char *begin_ptr;
                size_t begin;
 
@@ -141,7 +161,6 @@ char *subst_string (char *buf, size_t buflen, const char *string,
                                i, string, needle, replacement);
        }
 
-       sfree (temp);
        return (buf);
 } /* char *subst_string */
 
diff --git a/src/daemon/utils_subst_test.c b/src/daemon/utils_subst_test.c
new file mode 100644 (file)
index 0000000..c12aa10
--- /dev/null
@@ -0,0 +1,133 @@
+/**
+ * collectd - src/daemon/utils_subst_test.c
+ * Copyright (C) 2015       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 <octo at collectd.org>
+ */
+
+#include "testing.h"
+#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
+#include "utils_subst.h"
+
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
+DEF_TEST(subst)
+{
+  struct {
+    char *str;
+    int off1;
+    int off2;
+    char *rplmt;
+    char *want;
+  } cases[] = {
+    {"foo_____bar", 3, 8, " - ", "foo - bar"}, /* documentation example */
+    {"foo bar", 0, 2, "m",     "mo bar"},    /* beginning, shorten */
+    {"foo bar", 0, 1, "m",     "moo bar"},   /* beginning, same length */
+    {"foo bar", 0, 3, "milk",  "milk bar"},  /* beginning, extend */
+    {"foo bar", 3, 6, "de",    "fooder"},    /* center, shorten */
+    {"foo bar", 2, 6, "rste",  "forster"},   /* center, same length */
+    {"foo bar", 1, 3, "ish",   "fish bar"},  /* center, extend */
+    {"foo bar", 2, 7, "ul",    "foul"},      /* end, shorten */
+    {"foo bar", 3, 7, "lish",  "foolish"},   /* end, same length */
+    {"foo bar", 3, 7, "dwear", "foodwear"},  /* end, extend */
+    /* truncation (buffer is 16 chars) */
+    {"01234567890123",        8, 8,    "", "01234567890123"},
+    {"01234567890123",        8, 8,   "*", "01234567*890123"},
+    {"01234567890123",        8, 8,  "**", "01234567**89012"},
+    /* input > buffer */
+    {"012345678901234----",   0,  0,   "", "012345678901234"},
+    {"012345678901234----",  17, 18,   "", "012345678901234"},
+    {"012345678901234----",   0,  3,   "", "345678901234---"},
+    {"012345678901234----",   0,  4,   "", "45678901234----"},
+    {"012345678901234----",   0,  5,   "", "5678901234----"},
+    {"012345678901234----",   8,  8,  "#", "01234567#890123"},
+    {"012345678901234----",  12, 12, "##", "012345678901##2"},
+    {"012345678901234----",  13, 13, "##", "0123456789012##"},
+    {"012345678901234----",  14, 14, "##", "01234567890123#"},
+    {"012345678901234----",  15, 15, "##", "012345678901234"},
+    {"012345678901234----",  16, 16, "##", "012345678901234"},
+    /* error cases */
+    {NULL,       3,  4, "_",  NULL}, /* no input */
+    {"foo bar",  3, 10, "_",  NULL}, /* offset exceeds input */
+    {"foo bar", 10, 13, "_",  NULL}, /* offset exceeds input */
+    {"foo bar",  4,  3, "_",  NULL}, /* off1 > off2 */
+    {"foo bar",  3,  4, NULL, NULL}, /* no replacement */
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    char buffer[16] = "!!!!!!!!!!!!!!!";
+
+    if (cases[i].want == NULL) {
+      OK(subst (buffer, sizeof (buffer), cases[i].str, cases[i].off1, cases[i].off2, cases[i].rplmt) == NULL);
+      continue;
+    }
+
+    OK(subst (buffer, sizeof (buffer), cases[i].str, cases[i].off1, cases[i].off2, cases[i].rplmt) == &buffer[0]);
+    EXPECT_EQ_STR(cases[i].want, buffer);
+  }
+
+  return 0;
+}
+
+DEF_TEST(subst_string)
+{
+  struct {
+    char *str;          char *srch; char *rplmt; char *want;
+  } cases[] = {
+    {"Hello %{name}",    "%{name}", "world", "Hello world"},
+    {"abcccccc",         "abc",     "cab",   "ccccccab"},
+    {"(((()(())))())",   "()",      "",      ""},
+    {"food booth",       "oo",      "ee",    "feed beeth"},
+    {"foo bar",          "baz",     "qux",   "foo bar"},
+    {"foo bar",          "oo",      "oo",    "foo bar"},
+    {"sixteen chars",    "chars",   "characters", "sixteen charact"},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    char buffer[16];
+
+    if (cases[i].want == NULL) {
+      OK(subst_string (buffer, sizeof (buffer), cases[i].str, cases[i].srch, cases[i].rplmt) == NULL);
+      continue;
+    }
+
+    OK(subst_string (buffer, sizeof (buffer), cases[i].str, cases[i].srch, cases[i].rplmt) == buffer);
+    EXPECT_EQ_STR(cases[i].want, buffer);
+  }
+
+  return 0;
+}
+
+int main (void)
+{
+  RUN_TEST(subst);
+  RUN_TEST(subst_string);
+
+  END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
index 6603c15..5d905d9 100644 (file)
@@ -89,11 +89,13 @@ size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */
 
   if (max - len > 2) {
     int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec);
-    len += (n < max - len) ? n : max - len;
+    len += (n < 0) ? 0
+      : (((size_t) n) < (max - len)) ? ((size_t) n)
+      : (max - len);
   }
 
   if (max - len > 3) {
-    int n = strftime (s + len, max - len, "%z", &t_tm);
+    size_t n = strftime (s + len, max - len, "%z", &t_tm);
     len += (n < max - len) ? n : max - len;
   }
 
index 9b08e8e..6566a73 100644 (file)
@@ -1,6 +1,6 @@
 /**
- * collectd - src/utils_time.h
- * Copyright (C) 2010       Florian octo Forster
+ * collectd - src/daemon/utils_time.h
+ * Copyright (C) 2010-2015  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"),
@@ -21,7 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *   Florian octo Forster <ff at octo.it>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #ifndef UTILS_TIME_H
 /* typedef uint64_t cdtime_t; */
 
 /* 2^30 = 1073741824 */
-#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) * 1073741824)
-#define CDTIME_T_TO_TIME_T(t) ((time_t) ((t) / 1073741824))
+#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) << 30)
+
+#define MS_TO_CDTIME_T(ms) (((((cdtime_t) (ms)) / 1000) << 30) | \
+    ((((((cdtime_t) (ms)) % 1000) << 30) + 500) / 1000))
+#define US_TO_CDTIME_T(us) (((((cdtime_t) (us)) / 1000000) << 30) | \
+    ((((((cdtime_t) (us)) % 1000000) << 30) + 500000) / 1000000))
+#define NS_TO_CDTIME_T(ns) (((((cdtime_t) (ns)) / 1000000000) << 30) | \
+    ((((((cdtime_t) (ns)) % 1000000000) << 30) + 500000000) / 1000000000))
+
+#define CDTIME_T_TO_TIME_T(t) ((time_t) (((t) + (1 << 29)) >> 30))
+#define CDTIME_T_TO_MS(t)  ((uint64_t) ((((t) >> 30) * 1000) + \
+  ((((t) & 0x3fffffff) * 1000 + (1 << 29)) >> 30)))
+#define CDTIME_T_TO_US(t)  ((uint64_t) ((((t) >> 30) * 1000000) + \
+  ((((t) & 0x3fffffff) * 1000000 + (1 << 29)) >> 30)))
+#define CDTIME_T_TO_NS(t)  ((uint64_t) ((((t) >> 30) * 1000000000) + \
+  ((((t) & 0x3fffffff) * 1000000000 + (1 << 29)) >> 30)))
 
 #define CDTIME_T_TO_DOUBLE(t) (((double) (t)) / 1073741824.0)
 #define DOUBLE_TO_CDTIME_T(d) ((cdtime_t) ((d) * 1073741824.0))
 
-#define MS_TO_CDTIME_T(ms) ((cdtime_t)    (((double) (ms)) * 1073741.824))
-#define CDTIME_T_TO_MS(t)  ((long)        (((double) (t))  / 1073741.824))
-#define US_TO_CDTIME_T(us) ((cdtime_t)    (((double) (us)) * 1073.741824))
-#define CDTIME_T_TO_US(t)  ((suseconds_t) (((double) (t))  / 1073.741824))
-#define NS_TO_CDTIME_T(ns) ((cdtime_t)    (((double) (ns)) * 1.073741824))
-#define CDTIME_T_TO_NS(t)  ((long)        (((double) (t))  / 1.073741824))
-
 #define CDTIME_T_TO_TIMEVAL(cdt,tvp) do {                                    \
         (tvp)->tv_sec = CDTIME_T_TO_TIME_T (cdt);                            \
-        (tvp)->tv_usec = CDTIME_T_TO_US ((cdt) % 1073741824);                \
+        (tvp)->tv_usec = (suseconds_t) CDTIME_T_TO_US ((cdt) & 0x3fffffff);  \
 } while (0)
-#define TIMEVAL_TO_CDTIME_T(tv) (TIME_T_TO_CDTIME_T ((tv)->tv_sec)           \
-    + US_TO_CDTIME_T ((tv)->tv_usec))
+#define TIMEVAL_TO_CDTIME_T(tv) US_TO_CDTIME_T(1000000 * (tv)->tv_sec + (tv)->tv_usec)
 
 #define CDTIME_T_TO_TIMESPEC(cdt,tsp) do {                                   \
   (tsp)->tv_sec = CDTIME_T_TO_TIME_T (cdt);                                  \
-  (tsp)->tv_nsec = CDTIME_T_TO_NS ((cdt) % 1073741824);                      \
+  (tsp)->tv_nsec = (long) CDTIME_T_TO_NS ((cdt) & 0x3fffffff);               \
 } while (0)
-#define TIMESPEC_TO_CDTIME_T(ts) (TIME_T_TO_CDTIME_T ((ts)->tv_sec)           \
-    + NS_TO_CDTIME_T ((ts)->tv_nsec))
+#define TIMESPEC_TO_CDTIME_T(ts) NS_TO_CDTIME_T(1000000000ULL * (ts)->tv_sec + (ts)->tv_nsec)
 
 cdtime_t cdtime (void);
 
index 5edfe6f..217515e 100644 (file)
@@ -28,6 +28,6 @@
 
 cdtime_t cdtime (void)
 {
-  return (0);
+  return ((cdtime_t) 1542455354518929408ULL);
 }
 
diff --git a/src/daemon/utils_time_test.c b/src/daemon/utils_time_test.c
new file mode 100644 (file)
index 0000000..8eac0b6
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+ * collectd - src/daemon/utils_time_test.c
+ * Copyright (C) 2015       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 <octo at collectd.org>
+ */
+
+#define DBL_PRECISION 1e-3
+
+#include "testing.h"
+#include "collectd.h"
+#include "utils_time.h"
+
+DEF_TEST(conversion)
+{
+  struct {
+    cdtime_t t;
+    double d;
+    time_t tt;
+    uint64_t ms;
+    struct timeval tv;
+    struct timespec ts;
+  } cases[] = {
+  /*              cdtime          double      time_t   milliseconds               timeval                 timespec */
+    {                     0,          0.0  ,          0,                0, {         0,      0}, {         0,         0}},
+    {        10737418240ULL,         10.0  ,         10,            10000, {        10,      0}, {        10,         0}},
+    {1542908534771941376ULL, 1436945549.0  , 1436945549, 1436945549000ULL, {1436945549,      0}, {1436945549,         0}},
+    {1542908535540740522ULL, 1436945549.716, 1436945550, 1436945549716ULL, {1436945549, 716000}, {1436945549, 716000000}},
+    // 1426076671.123 * 2^30 = 1531238166015458148.352
+    {1531238166015458148ULL, 1426076671.123, 1426076671, 1426076671123ULL, {1426076671, 123000}, {1426076671, 123000000}},
+    // 1426076681.234 * 2^30 = 1531238176872061730.816
+    {1531238176872061731ULL, 1426076681.234, 1426076681, 1426076681234ULL, {1426076681, 234000}, {1426076681, 234000000}},
+    // 1426083986.314 * 2^30 = 1531246020641985396.736
+    {1531246020641985397ULL, 1426083986.314, 1426083986, 1426083986314ULL, {1426083986, 314000}, {1426083986, 314000000}},
+    // 1426083986.494142531 * 2^30 = 1531246020835411966.5
+    {1531246020835411967ULL, 1426083986.494, 1426083986, 1426083986494ULL, {1426083986, 494143}, {1426083986, 494142531}},
+    // 1426083986.987410814 * 2^30 = 1531246021365054752.4
+    {1531246021365054752ULL, 1426083986.987, 1426083987, 1426083986987ULL, {1426083986, 987411}, {1426083986, 987410814}},
+
+    /* These cases test the cdtime_t -> ns conversion rounds correctly. */
+    // 1546167635576736987 / 2^30 = 1439980823.1524536265...
+    {1546167635576736987ULL, 1439980823.152, 1439980823, 1439980823152ULL, {1439980823, 152454}, {1439980823, 152453627}},
+    // 1546167831554815222 / 2^30 = 1439981005.6712620165...
+    {1546167831554815222ULL, 1439981005.671, 1439981006, 1439981005671ULL, {1439981005, 671262}, {1439981005, 671262017}},
+    // 1546167986577716567 / 2^30 = 1439981150.0475896215...
+    {1546167986577716567ULL, 1439981150.048, 1439981150, 1439981150048ULL, {1439981150,  47590}, {1439981005,  47589622}},
+  };
+  size_t i;
+
+  for (i = 0; i < (sizeof (cases) / sizeof (cases[0])); i++) {
+    struct timeval tv;
+    struct timespec ts;
+
+    // cdtime -> s
+    EXPECT_EQ_UINT64 (cases[i].tt, CDTIME_T_TO_TIME_T (cases[i].t));
+
+    // cdtime -> ms
+    EXPECT_EQ_UINT64(cases[i].ms, CDTIME_T_TO_MS (cases[i].t));
+
+    // cdtime -> us
+    CDTIME_T_TO_TIMEVAL (cases[i].t, &tv);
+    EXPECT_EQ_UINT64 (cases[i].tv.tv_usec, tv.tv_usec);
+
+    // cdtime -> ns
+    CDTIME_T_TO_TIMESPEC (cases[i].t, &ts);
+    EXPECT_EQ_UINT64 (cases[i].ts.tv_nsec, ts.tv_nsec);
+
+    // cdtime -> double
+    EXPECT_EQ_DOUBLE (cases[i].d, CDTIME_T_TO_DOUBLE (cases[i].t));
+  }
+
+  return 0;
+}
+
+/* These cases test the ns -> cdtime_t conversion rounds correctly. */
+DEF_TEST(ns_to_cdtime)
+{
+  struct {
+    uint64_t ns;
+    cdtime_t want;
+  } cases[] = {
+    // 1439981652801860766 * 2^30 / 10^9 = 1546168526406004689.4
+    {1439981652801860766ULL, 1546168526406004689ULL},
+    // 1439981836985281914 * 2^30 / 10^9 = 1546168724171447263.4
+    {1439981836985281914ULL, 1546168724171447263ULL},
+    // 1439981880053705608 * 2^30 / 10^9 = 1546168770415815077.4
+    {1439981880053705608ULL, 1546168770415815077ULL},
+  };
+  size_t i;
+
+  for (i = 0; i < (sizeof (cases) / sizeof (cases[0])); i++) {
+    EXPECT_EQ_UINT64 (cases[i].want, NS_TO_CDTIME_T (cases[i].ns));
+  }
+
+  return 0;
+}
+
+int main (void)
+{
+  RUN_TEST(conversion);
+  RUN_TEST(ns_to_cdtime);
+
+  END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
index a7963ea..94d0762 100644 (file)
--- a/src/dbi.c
+++ b/src/dbi.c
@@ -64,6 +64,8 @@ struct cdbi_database_s /* {{{ */
   char *name;
   char *select_db;
 
+  cdtime_t interval;
+
   char *driver;
   char *host;
   cdbi_driver_option_t *driver_options;
@@ -215,6 +217,7 @@ static void cdbi_database_free (cdbi_database_t *db) /* {{{ */
  *     
  *   <Database "plugin_instance1">
  *     Driver "mysql"
+ *     Interval 120
  *     DriverOption "hostname" "localhost"
  *     ...
  *     Query "plugin_instance0"
@@ -322,6 +325,8 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
           &db->queries, &db->queries_num);
     else if (strcasecmp ("Host", child->key) == 0)
       status = cf_util_get_string (child, &db->host);
+    else if (strcasecmp ("Interval", child->key) == 0)
+      status = cf_util_get_cdtime(child, &db->interval);
     else
     {
       WARNING ("dbi plugin: Option `%s' not allowed here.", child->key);
@@ -351,6 +356,7 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
 
   while ((status == 0) && (db->queries_num > 0))
   {
+    size_t j;
     db->q_prep_areas = (udb_query_preparation_area_t **) calloc (
         db->queries_num, sizeof (*db->q_prep_areas));
 
@@ -361,12 +367,12 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
       break;
     }
 
-    for (i = 0; i < db->queries_num; ++i)
+    for (j = 0; j < db->queries_num; ++j)
     {
-      db->q_prep_areas[i]
-        = udb_query_allocate_preparation_area (db->queries[i]);
+      db->q_prep_areas[j]
+        = udb_query_allocate_preparation_area (db->queries[j]);
 
-      if (db->q_prep_areas[i] == NULL)
+      if (db->q_prep_areas[j] == NULL)
       {
         WARNING ("dbi plugin: udb_query_allocate_preparation_area failed");
         status = -1;
@@ -406,7 +412,7 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
       plugin_register_complex_read (/* group = */ NULL,
           /* name = */ name ? name : db->name,
           /* callback = */ cdbi_read_database,
-          /* interval = */ NULL,
+          /* interval = */ (db->interval > 0) ? db->interval : 0,
           /* user_data = */ &ud);
       free (name);
     }
@@ -596,7 +602,7 @@ static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */
 
   udb_query_prepare_result (q, prep_area, (db->host ? db->host : hostname_g),
       /* plugin = */ "dbi", db->name,
-      column_names, column_num, /* interval = */ 0);
+      column_names, column_num, /* interval = */ (db->interval > 0) ? db->interval : 0);
 
   /* 0 = error; 1 = success; */
   status = dbi_result_first_row (res); /* {{{ */
index 1c3dd98..8f8f370 100644 (file)
 #if HAVE_IOKIT_IOBSD_H
 #  include <IOKit/IOBSD.h>
 #endif
+#if KERNEL_FREEBSD
+#include <devstat.h>
+#include <libgeom.h>
+#endif
 
 #if HAVE_LIMITS_H
 # include <limits.h>
@@ -107,6 +111,9 @@ typedef struct diskstats
 
 static diskstats_t *disklist;
 /* #endif KERNEL_LINUX */
+#elif KERNEL_FREEBSD
+static struct gmesh geom_tree;
+/* #endif KERNEL_FREEBSD */
 
 #elif HAVE_LIBKSTAT
 #define MAX_NUMDISK 1024
@@ -222,6 +229,21 @@ static int disk_init (void)
        /* do nothing */
 /* #endif KERNEL_LINUX */
 
+#elif KERNEL_FREEBSD
+       int rv;
+
+       rv = geom_gettree(&geom_tree);
+       if (rv != 0) {
+               ERROR ("geom_gettree() failed, returned %d", rv);
+               return (-1);
+       }
+       rv = geom_stats_open();
+       if (rv != 0) {
+               ERROR ("geom_stats_open() failed, returned %d", rv);
+               return (-1);
+       }
+/* #endif KERNEL_FREEBSD */
+
 #elif HAVE_LIBKSTAT
        kstat_t *ksp_chain;
 
@@ -505,6 +527,113 @@ static int disk_read (void)
        IOObjectRelease (disk_list);
 /* #endif HAVE_IOKIT_IOKITLIB_H */
 
+#elif KERNEL_FREEBSD
+       int retry, dirty;
+
+       void *snap = NULL;
+       struct devstat *snap_iter;
+
+       struct gident *geom_id;
+
+       const char *disk_name;
+       long double read_time, write_time;
+
+       for (retry = 0, dirty = 1; retry < 5 && dirty == 1; retry++) {
+               if (snap != NULL)
+                       geom_stats_snapshot_free(snap);
+
+               /* Get a fresh copy of stats snapshot */
+               snap = geom_stats_snapshot_get();
+               if (snap == NULL) {
+                       ERROR("disk plugin: geom_stats_snapshot_get() failed.");
+                       return (-1);
+               }
+
+               /* Check if we have dirty read from this snapshot */
+               dirty = 0;
+               geom_stats_snapshot_reset(snap);
+               while ((snap_iter = geom_stats_snapshot_next(snap)) != NULL) {
+                       if (snap_iter->id == NULL)
+                               continue;
+                       geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+
+                       /* New device? refresh GEOM tree */
+                       if (geom_id == NULL) {
+                               geom_deletetree(&geom_tree);
+                               if (geom_gettree(&geom_tree) != 0) {
+                                       ERROR("disk plugin: geom_gettree() failed");
+                                       geom_stats_snapshot_free(snap);
+                                       return (-1);
+                               }
+                               geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+                       }
+                       /*
+                        * This should be rare: the device come right before we take the
+                        * snapshot and went away right after it.  We will handle this
+                        * case later, so don't mark dirty but silently ignore it.
+                        */
+                       if (geom_id == NULL)
+                               continue;
+
+                       /* Only collect PROVIDER data */
+                       if (geom_id->lg_what != ISPROVIDER)
+                               continue;
+
+                       /* Only collect data when rank is 1 (physical devices) */
+                       if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1)
+                               continue;
+
+                       /* Check if this is a dirty read quit for another try */
+                       if (snap_iter->sequence0 != snap_iter->sequence1) {
+                               dirty = 1;
+                               break;
+                       }
+               }
+       }
+
+       /* Reset iterator */
+       geom_stats_snapshot_reset(snap);
+       for (;;) {
+               snap_iter = geom_stats_snapshot_next(snap);
+               if (snap_iter == NULL)
+                       break;
+
+               if (snap_iter->id == NULL)
+                       continue;
+               geom_id = geom_lookupid(&geom_tree, snap_iter->id);
+               if (geom_id == NULL)
+                       continue;
+               if (geom_id->lg_what != ISPROVIDER)
+                       continue;
+               if (((struct gprovider *)(geom_id->lg_ptr))->lg_geom->lg_rank != 1)
+                       continue;
+               /* Skip dirty reads, if present */
+               if (dirty && (snap_iter->sequence0 != snap_iter->sequence1))
+                       continue;
+
+               disk_name = ((struct gprovider *)geom_id->lg_ptr)->lg_name;
+
+               if ((snap_iter->bytes[DEVSTAT_READ] != 0) || (snap_iter->bytes[DEVSTAT_WRITE] != 0)) {
+                       disk_submit(disk_name, "disk_octets",
+                                       (derive_t)snap_iter->bytes[DEVSTAT_READ],
+                                       (derive_t)snap_iter->bytes[DEVSTAT_WRITE]);
+               }
+
+               if ((snap_iter->operations[DEVSTAT_READ] != 0) || (snap_iter->operations[DEVSTAT_WRITE] != 0)) {
+                       disk_submit(disk_name, "disk_ops",
+                                       (derive_t)snap_iter->operations[DEVSTAT_READ],
+                                       (derive_t)snap_iter->operations[DEVSTAT_WRITE]);
+               }
+
+               read_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_READ], NULL);
+               write_time = devstat_compute_etime(&snap_iter->duration[DEVSTAT_WRITE], NULL);
+               if ((read_time != 0) || (write_time != 0)) {
+                       disk_submit (disk_name, "disk_time",
+                                       (derive_t)(read_time*1000), (derive_t)(write_time*1000));
+               }
+       }
+       geom_stats_snapshot_free(snap);
+
 #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
index 365af27..1bf9add 100644 (file)
@@ -50,7 +50,6 @@
 # include <pthread.h>
 #endif
 
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/select.h>
 
index 336fbb9..c778d48 100644 (file)
@@ -33,9 +33,6 @@
 #if HAVE_PTHREAD_H
 # include <pthread.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NETDB_H
 # include <netdb.h>
 #endif
@@ -83,12 +80,12 @@ typedef struct staging_entry_s staging_entry_t;
 
 struct metric_map_s
 {
-  char *ganglia_name;
-  char *type;
-  char *type_instance;
-  char *ds_name;
-  int   ds_type;
-  int   ds_index;
+  char  *ganglia_name;
+  char  *type;
+  char  *type_instance;
+  char  *ds_name;
+  int    ds_type;
+  size_t ds_index;
 };
 typedef struct metric_map_s metric_map_t;
 
@@ -166,7 +163,7 @@ static metric_map_t *metric_lookup (const char *key) /* {{{ */
     return (NULL);
 
   /* Look up the DS type and ds_index. */
-  if ((map[i].ds_type < 0) || (map[i].ds_index < 0)) /* {{{ */
+  if (map[i].ds_type < 0) /* {{{ */
   {
     const data_set_t *ds;
 
@@ -191,7 +188,7 @@ static metric_map_t *metric_lookup (const char *key) /* {{{ */
     }
     else
     {
-      int j;
+      size_t j;
 
       for (j = 0; j < ds->ds_num; j++)
         if (strcasecmp (ds->ds[j].name, map[i].ds_name) == 0)
@@ -511,7 +508,7 @@ static int staging_entry_submit (const char *host, const char *name, /* {{{ */
 
 static int staging_entry_update (const char *host, const char *name, /* {{{ */
     const char *type, const char *type_instance,
-    int ds_index, int ds_type, value_t value)
+    size_t ds_index, int ds_type, value_t value)
 {
   const data_set_t *ds;
   staging_entry_t *se;
@@ -525,7 +522,7 @@ static int staging_entry_update (const char *host, const char *name, /* {{{ */
 
   if (ds->ds_num <= ds_index)
   {
-    ERROR ("gmond plugin: Invalid index %i: %s has only %i data source(s).",
+    ERROR ("gmond plugin: Invalid index %zu: %s has only %zu data source(s).",
         ds_index, ds->type, ds->ds_num);
     return (-1);
   }
index 82c158c..3de18fd 100644 (file)
@@ -35,7 +35,6 @@
 #include "configfile.h"
 
 # include <netdb.h>
-# include <sys/socket.h>
 # include <netinet/in.h>
 # include <netinet/tcp.h>
 # include <libgen.h> /* for basename */
index df8ffb4..e17711e 100644 (file)
@@ -31,9 +31,6 @@
 #if HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-#  include <sys/socket.h>
-#endif
 
 /* One cannot include both. This sucks. */
 #if HAVE_LINUX_IF_H
index 606b24d..806b7a4 100644 (file)
@@ -29,8 +29,6 @@
 #include "plugin.h"
 #include "configfile.h"
 
-#include <sys/socket.h>
-
 #include <libiptc/libiptc.h>
 #include <libiptc/libip6tc.h>
 
index cbb5542..4345a46 100644 (file)
@@ -37,9 +37,6 @@
 #if HAVE_ARPA_INET_H
 # include <arpa/inet.h>
 #endif /* HAVE_ARPA_INET_H */
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif /* HAVE_SYS_SOCKET_H */
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif /* HAVE_NETINET_IN_H */
@@ -197,7 +194,7 @@ static int get_pi (struct ip_vs_service_entry *se, char *pi, size_t size)
                        (se->protocol == IPPROTO_TCP) ? "TCP" : "UDP",
                        ntohs (se->port));
 
-       if ((0 > len) || (size <= len)) {
+       if ((0 > len) || (size <= ((size_t) len))) {
                log_err ("plugin instance truncated: %s", pi);
                return -1;
        }
@@ -220,7 +217,7 @@ static int get_ti (struct ip_vs_dest_entry *de, char *ti, size_t size)
        len = ssnprintf (ti, size, "%s_%u", inet_ntoa (addr),
                        ntohs (de->port));
 
-       if ((0 > len) || (size <= len)) {
+       if ((0 > len) || (size <= ((size_t) len))) {
                log_err ("type instance truncated: %s", ti);
                return -1;
        }
@@ -292,7 +289,7 @@ static void cipvs_submit_service (struct ip_vs_service_entry *se)
 
        char pi[DATA_MAX_NAME_LEN];
 
-       int i = 0;
+       size_t i;
 
        if (0 != get_pi (se, pi, sizeof (pi)))
        {
@@ -314,7 +311,7 @@ static void cipvs_submit_service (struct ip_vs_service_entry *se)
 static int cipvs_read (void)
 {
        struct ip_vs_get_services *services = NULL;
-       int i = 0;
+       size_t i;
 
        if (sockfd < 0)
                return (-1);
index c74fe6c..6b92f54 100644 (file)
@@ -618,7 +618,7 @@ static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */
   jmethodID m_add;
   jobject o_type;
   jobject o_dataset;
-  int i;
+  size_t i;
 
   /* Look up the org/collectd/api/DataSet class */
   c_dataset = (*jvm_env)->FindClass (jvm_env, "org/collectd/api/DataSet");
@@ -763,7 +763,7 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
   jmethodID m_valuelist_constructor;
   jobject o_valuelist;
   int status;
-  int i;
+  size_t i;
 
   /* First, create a new ValueList instance..
    * Look up the class.. */
@@ -1438,7 +1438,7 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
   ud.free_func = cjni_callback_info_destroy;
 
   plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read,
-      /* interval = */ NULL, &ud);
+      /* interval = */ 0, &ud);
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_read);
 
index 5abee2f..e81a594 100644 (file)
@@ -1,9 +1,5 @@
 AUTOMAKE_OPTIONS = foreign no-dependencies
 
-if COMPILER_IS_GCC
-AM_CFLAGS = -Wall -Werror
-endif
-
 pkginclude_HEADERS = collectd/client.h collectd/network.h collectd/network_buffer.h collectd/lcc_features.h
 lib_LTLIBRARIES = libcollectdclient.la
 nodist_pkgconfig_DATA = libcollectdclient.pc
index a97dc50..eaee9c0 100644 (file)
@@ -287,7 +287,7 @@ static int lcc_receive (lcc_connection_t *c, /* {{{ */
    * beginning of the message. */
   ptr = NULL;
   errno = 0;
-  res.status = strtol (buffer, &ptr, 0);
+  res.status = (int) strtol (buffer, &ptr, 0);
   if ((errno != 0) || (ptr == &buffer[0]))
   {
     lcc_set_errno (c, errno);
index c390a1c..0539cd0 100644 (file)
@@ -393,7 +393,7 @@ int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */
 
 int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ */
 {
-  int if_index;
+  unsigned int if_index;
   int status;
 
   if ((srv == NULL) || (interface == NULL))
@@ -421,7 +421,7 @@ int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ *
       memset (&mreq, 0, sizeof (mreq));
       mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
       mreq.imr_address.s_addr = ntohl (INADDR_ANY);
-      mreq.imr_ifindex = if_index;
+      mreq.imr_ifindex = (int) if_index;
 #else
       struct ip_mreq mreq;
 
@@ -457,8 +457,8 @@ int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ *
 
   /* else: Not a multicast interface. */
 #if defined(SO_BINDTODEVICE)
-  status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE,
-      interface, strlen (interface) + 1);
+  status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE, interface,
+      (socklen_t) (strlen (interface) + 1));
   if (status != 0)
     return (-1);
 #endif
index f422f5a..d01c79d 100644 (file)
@@ -53,11 +53,9 @@ oconfig_item_t *oconfig_parse_fh (FILE *fh)
   yyset_in (fh);
 
   if (NULL == c_file) {
-    int status;
-
     status = snprintf (file, sizeof (file), "<fd#%d>", fileno (fh));
 
-    if ((status < 0) || (status >= sizeof (file))) {
+    if ((status < 0) || (((size_t) status) >= sizeof (file))) {
       c_file = "<unknown>";
     }
     else {
@@ -131,8 +129,8 @@ oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig)
   {
     int i;
 
-    ci_copy->values = (oconfig_value_t *) calloc (ci_orig->values_num,
-       sizeof (*ci_copy->values));
+    ci_copy->values = (oconfig_value_t *) calloc ((size_t) ci_orig->values_num,
+        sizeof (*ci_copy->values));
     if (ci_copy->values == NULL)
     {
       fprintf (stderr, "calloc failed.\n");
@@ -147,18 +145,17 @@ oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig)
        ci_copy->values[i].type = ci_orig->values[i].type;
        if (ci_copy->values[i].type == OCONFIG_TYPE_STRING)
        {
-        ci_copy->values[i].value.string
-          = strdup (ci_orig->values[i].value.string);
-        if (ci_copy->values[i].value.string == NULL)
-        {
-          fprintf (stderr, "strdup failed.\n");
-          oconfig_free (ci_copy);
-          return (NULL);
-        }
+         ci_copy->values[i].value.string = strdup (ci_orig->values[i].value.string);
+         if (ci_copy->values[i].value.string == NULL)
+         {
+           fprintf (stderr, "strdup failed.\n");
+           oconfig_free (ci_copy);
+           return (NULL);
+         }
        }
        else /* ci_copy->values[i].type != OCONFIG_TYPE_STRING) */
        {
-        ci_copy->values[i].value = ci_orig->values[i].value;
+         ci_copy->values[i].value = ci_orig->values[i].value;
        }
     }
   } /* }}} if (ci_orig->values_num > 0) */
@@ -167,8 +164,8 @@ oconfig_item_t *oconfig_clone (const oconfig_item_t *ci_orig)
   {
     int i;
 
-    ci_copy->children = (oconfig_item_t *) calloc (ci_orig->children_num,
-       sizeof (*ci_copy->children));
+    ci_copy->children = (oconfig_item_t *) calloc ((size_t) ci_orig->children_num,
+        sizeof (*ci_copy->children));
     if (ci_copy->children == NULL)
     {
       fprintf (stderr, "calloc failed.\n");
index 13301ff..bb33b15 100644 (file)
@@ -96,7 +96,6 @@
 
 #include <dirent.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
 
 #if !KERNEL_LINUX
 # error "No applicable input method."
@@ -368,14 +367,14 @@ static int init_state = 0;
 static inline int item_watched(int i)
 {
        assert (i >= 0);
-       assert (i < ((STATIC_ARRAY_SIZE (watch_items) + 1) * 32));
+       assert (((size_t) i) < ((STATIC_ARRAY_SIZE (watch_items) + 1) * 32));
        return watch_items[i / 32] & FLAG (i);
 }
 
 static inline int item_summed(int i)
 {
        assert (i >= 0);
-       assert (i < ((STATIC_ARRAY_SIZE (misc_items) + 1) * 32));
+       assert (((size_t) i) < ((STATIC_ARRAY_SIZE (misc_items) + 1) * 32));
        return misc_items[i / 32] & FLAG (i);
 }
 
@@ -420,8 +419,8 @@ static int watchitem_find (const char *name)
 
 static int madwifi_real_init (void)
 {
-       int max = STATIC_ARRAY_SIZE (specs);
-       int i;
+       size_t max = STATIC_ARRAY_SIZE (specs);
+       size_t i;
 
        for (i = 0; i < STATIC_ARRAY_SIZE (bounds); i++)
                bounds[i] = 0;
@@ -618,7 +617,7 @@ process_stat_struct (int which, const void *ptr, const char *dev, const char *ma
        int i;
 
        assert (which >= 1);
-       assert (which < STATIC_ARRAY_SIZE (bounds));
+       assert (((size_t) which) < STATIC_ARRAY_SIZE (bounds));
 
        for (i = bounds[which - 1]; i < bounds[which]; i++)
        {
@@ -754,7 +753,8 @@ process_stations (int sk, const char *dev)
        uint8_t buf[24*1024];
        struct iwreq iwr;
        uint8_t *cp;
-       int len, nodes;
+       int nodes;
+       size_t len;
        int status;
 
        memset (&iwr, 0, sizeof (iwr));
index abde2b3..e30ff91 100644 (file)
@@ -80,7 +80,7 @@ static int mec_match (const data_set_t __attribute__((unused)) *ds, /* {{{ */
 {
   int num_counters;
   int num_empty;
-  int i;
+  size_t i;
 
   if ((user_data == NULL) || (*user_data == NULL))
     return (-1);
index 4d49984..9ffceca 100644 (file)
@@ -58,7 +58,7 @@ struct mv_match_s
  */
 static void mv_free_match (mv_match_t *m) /* {{{ */
 {
-  int i;
+  size_t i;
   
   if (m == NULL)
     return;
@@ -277,7 +277,7 @@ static int mv_match (const data_set_t *ds, const value_list_t *vl, /* {{{ */
   mv_match_t *m;
   gauge_t *values;
   int status;
-  int i;
+  size_t i;
 
   if ((user_data == NULL) || (*user_data == NULL))
     return (-1);
index d23062d..5e87f00 100644 (file)
@@ -29,7 +29,6 @@
 #include "configfile.h"
 
 #include <netdb.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 
index f6af4fc..f684abf 100644 (file)
@@ -34,7 +34,6 @@
 #include "configfile.h"
 
 #include <netdb.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
@@ -566,7 +565,7 @@ static int memcached_add_read_callback (memcached_t *st)
   status = plugin_register_complex_read (/* group = */ "memcached",
       /* name      = */ callback_name,
       /* callback  = */ memcached_read,
-      /* interval  = */ NULL,
+      /* interval  = */ 0,
       /* user_data = */ &ud);
   return (status);
 } /* int memcached_add_read_callback */
index fb2f3d3..ea16ce3 100644 (file)
@@ -76,6 +76,7 @@ static vm_size_t pagesize;
 #elif HAVE_LIBKSTAT
 static int pagesize;
 static kstat_t *ksp;
+static kstat_t *ksz;
 /* #endif HAVE_LIBKSTAT */
 
 #elif HAVE_SYSCTL
@@ -137,6 +138,12 @@ static int memory_init (void)
                ksp = NULL;
                return (-1);
        }
+       if (get_kstat (&ksz, "zfs", 0, "arcstats") != 0)
+       {
+               ksz = NULL;
+               return (-1);
+       }
+
 /* #endif HAVE_LIBKSTAT */
 
 #elif HAVE_SYSCTL
@@ -371,6 +378,8 @@ static int memory_read_internal (value_list_t *vl)
        long long mem_lock;
        long long mem_kern;
        long long mem_unus;
+       long long arcsize;
+
 
        long long pp_kernel;
        long long physmem;
@@ -378,17 +387,20 @@ static int memory_read_internal (value_list_t *vl)
 
        if (ksp == NULL)
                return (-1);
+       if (ksz == NULL)
+               return (-1);
 
        mem_used = get_kstat_value (ksp, "pagestotal");
        mem_free = get_kstat_value (ksp, "pagesfree");
        mem_lock = get_kstat_value (ksp, "pageslocked");
-       mem_kern = 0;
-       mem_unus = 0;
-
+       arcsize = get_kstat_value (ksz, "size");
        pp_kernel = get_kstat_value (ksp, "pp_kernel");
        physmem = get_kstat_value (ksp, "physmem");
        availrmem = get_kstat_value (ksp, "availrmem");
 
+       mem_kern = 0;
+       mem_unus = 0;
+
        if ((mem_used < 0LL) || (mem_free < 0LL) || (mem_lock < 0LL))
        {
                WARNING ("memory plugin: one of used, free or locked is negative.");
@@ -431,11 +443,14 @@ static int memory_read_internal (value_list_t *vl)
        mem_lock *= pagesize; /* some? ;) */
        mem_kern *= pagesize; /* it's 2011 RAM is cheap */
        mem_unus *= pagesize;
+       mem_kern -= arcsize;
+
 
        MEMORY_SUBMIT ("used",     (gauge_t) mem_used,
                       "free",     (gauge_t) mem_free,
                       "locked",   (gauge_t) mem_lock,
                       "kernel",   (gauge_t) mem_kern,
+                      "arc",      (gauge_t) arcsize,
                       "unusable", (gauge_t) mem_unus);
 /* #endif HAVE_LIBKSTAT */
 
index 08871a2..cfc6331 100644 (file)
@@ -440,7 +440,7 @@ static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */
 
   if (ds->ds_num != 1)
   {
-    ERROR ("Modbus plugin: The type \"%s\" has %i data sources. "
+    ERROR ("Modbus plugin: The type \"%s\" has %zu data sources. "
         "I can only handle data sets with only one data source.",
         data->type, ds->ds_num);
     return (-1);
@@ -1014,18 +1014,15 @@ static int mb_config_add_host (oconfig_item_t *ci) /* {{{ */
   {
     user_data_t ud;
     char name[1024];
-    struct timespec interval = { 0, 0 };
 
     ud.data = host;
     ud.free_func = host_free;
 
     ssnprintf (name, sizeof (name), "modbus-%s", host->host);
 
-    CDTIME_T_TO_TIMESPEC (host->interval, &interval);
-
     plugin_register_complex_read (/* group = */ NULL, name,
         /* callback = */ mb_read,
-        /* interval = */ (host->interval > 0) ? &interval : NULL,
+        /* interval = */ host->interval,
         &ud);
   }
   else
diff --git a/src/mqtt.c b/src/mqtt.c
new file mode 100644 (file)
index 0000000..1b71d42
--- /dev/null
@@ -0,0 +1,748 @@
+/**
+ * collectd - src/mqtt.c
+ * Copyright (C) 2014       Marc Falzon
+ * Copyright (C) 2014,2015  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:
+ *   Marc Falzon <marc at baha dot mu>
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+// Reference: http://mosquitto.org/api/files/mosquitto-h.html
+
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_cache.h"
+#include "utils_complain.h"
+
+#include <pthread.h>
+
+#include <mosquitto.h>
+
+#define MQTT_MAX_TOPIC_SIZE         1024
+#define MQTT_MAX_MESSAGE_SIZE       MQTT_MAX_TOPIC_SIZE + 1024
+#define MQTT_DEFAULT_HOST           "localhost"
+#define MQTT_DEFAULT_PORT           1883
+#define MQTT_DEFAULT_TOPIC_PREFIX   "collectd"
+#define MQTT_DEFAULT_TOPIC          "collectd/#"
+#ifndef MQTT_KEEPALIVE
+# define MQTT_KEEPALIVE 60
+#endif
+
+
+/*
+ * Data types
+ */
+struct mqtt_client_conf
+{
+    _Bool               publish;
+    char               *name;
+
+    struct mosquitto   *mosq;
+    _Bool               connected;
+
+    char               *host;
+    int                 port;
+    char               *client_id;
+    char               *username;
+    char               *password;
+    int                 qos;
+
+    /* For publishing */
+    char               *topic_prefix;
+    _Bool               store_rates;
+    _Bool               retain;
+
+    /* For subscribing */
+    pthread_t           thread;
+    _Bool               loop;
+    char               *topic;
+    _Bool               clean_session;
+
+    c_complain_t        complaint_cantpublish;
+    pthread_mutex_t     lock;
+};
+typedef struct mqtt_client_conf mqtt_client_conf_t;
+
+static mqtt_client_conf_t **subscribers = NULL;
+static size_t subscribers_num = 0;
+
+/*
+ * Functions
+ */
+#if LIBMOSQUITTO_MAJOR == 0
+static char const *mosquitto_strerror (int code)
+{
+    switch (code)
+    {
+        case MOSQ_ERR_SUCCESS: return "MOSQ_ERR_SUCCESS";
+        case MOSQ_ERR_NOMEM: return "MOSQ_ERR_NOMEM";
+        case MOSQ_ERR_PROTOCOL: return "MOSQ_ERR_PROTOCOL";
+        case MOSQ_ERR_INVAL: return "MOSQ_ERR_INVAL";
+        case MOSQ_ERR_NO_CONN: return "MOSQ_ERR_NO_CONN";
+        case MOSQ_ERR_CONN_REFUSED: return "MOSQ_ERR_CONN_REFUSED";
+        case MOSQ_ERR_NOT_FOUND: return "MOSQ_ERR_NOT_FOUND";
+        case MOSQ_ERR_CONN_LOST: return "MOSQ_ERR_CONN_LOST";
+        case MOSQ_ERR_SSL: return "MOSQ_ERR_SSL";
+        case MOSQ_ERR_PAYLOAD_SIZE: return "MOSQ_ERR_PAYLOAD_SIZE";
+        case MOSQ_ERR_NOT_SUPPORTED: return "MOSQ_ERR_NOT_SUPPORTED";
+        case MOSQ_ERR_AUTH: return "MOSQ_ERR_AUTH";
+        case MOSQ_ERR_ACL_DENIED: return "MOSQ_ERR_ACL_DENIED";
+        case MOSQ_ERR_UNKNOWN: return "MOSQ_ERR_UNKNOWN";
+        case MOSQ_ERR_ERRNO: return "MOSQ_ERR_ERRNO";
+    }
+
+    return "UNKNOWN ERROR CODE";
+}
+#else
+/* provided by libmosquitto */
+#endif
+
+static void mqtt_free (mqtt_client_conf_t *conf)
+{
+    if (conf == NULL)
+        return;
+
+    if (conf->connected)
+        (void) mosquitto_disconnect (conf->mosq);
+    conf->connected = 0;
+    (void) mosquitto_destroy (conf->mosq);
+
+    sfree (conf->host);
+    sfree (conf->username);
+    sfree (conf->password);
+    sfree (conf->client_id);
+    sfree (conf->topic_prefix);
+    sfree (conf);
+}
+
+static char *strip_prefix (char *topic)
+{
+    size_t num;
+    size_t i;
+
+    num = 0;
+    for (i = 0; topic[i] != 0; i++)
+        if (topic[i] == '/')
+            num++;
+
+    if (num < 2)
+        return (NULL);
+
+    while (num > 2)
+    {
+        char *tmp = strchr (topic, '/');
+        if (tmp == NULL)
+            return (NULL);
+        topic = tmp + 1;
+        num--;
+    }
+
+    return (topic);
+}
+
+static void on_message (
+#if LIBMOSQUITTO_MAJOR == 0
+#else
+        __attribute__((unused)) struct mosquitto *m,
+#endif
+        __attribute__((unused)) void *arg,
+        const struct mosquitto_message *msg)
+{
+    value_list_t vl = VALUE_LIST_INIT;
+    data_set_t const *ds;
+    char *topic;
+    char *name;
+    char *payload;
+    int status;
+
+    if ((msg->payloadlen <= 0)
+            || (((uint8_t *) msg->payload)[msg->payloadlen - 1] != 0))
+        return;
+
+    topic = strdup (msg->topic);
+    name = strip_prefix (topic);
+
+    status = parse_identifier_vl (name, &vl);
+    if (status != 0)
+    {
+        ERROR ("mqtt plugin: Unable to parse topic \"%s\".", topic);
+        sfree (topic);
+        return;
+    }
+    sfree (topic);
+
+    ds = plugin_get_ds (vl.type);
+    if (ds == NULL)
+    {
+        ERROR ("mqtt plugin: Unknown type: \"%s\".", vl.type);
+        return;
+    }
+
+    vl.values = calloc (ds->ds_num, sizeof (*vl.values));
+    if (vl.values == NULL)
+    {
+        ERROR ("mqtt plugin: calloc failed.");
+        return;
+    }
+    vl.values_len = ds->ds_num;
+
+    payload = strdup ((void *) msg->payload);
+    DEBUG ("mqtt plugin: payload = \"%s\"", payload);
+    status = parse_values (payload, &vl, ds);
+    if (status != 0)
+    {
+        ERROR ("mqtt plugin: Unable to parse payload \"%s\".", payload);
+        sfree (payload);
+        sfree (vl.values);
+        return;
+    }
+    sfree (payload);
+
+    plugin_dispatch_values (&vl);
+    sfree (vl.values);
+} /* void on_message */
+
+/* must hold conf->lock when calling. */
+static int mqtt_reconnect (mqtt_client_conf_t *conf)
+{
+    int status;
+
+    if (conf->connected)
+        return (0);
+
+    status = mosquitto_reconnect (conf->mosq);
+    if (status != MOSQ_ERR_SUCCESS)
+    {
+        char errbuf[1024];
+        ERROR ("mqtt_connect_broker: mosquitto_connect failed: %s",
+                (status == MOSQ_ERR_ERRNO)
+                ? sstrerror(errno, errbuf, sizeof (errbuf))
+                : mosquitto_strerror (status));
+        return (-1);
+    }
+
+    conf->connected = 1;
+
+    c_release (LOG_INFO,
+            &conf->complaint_cantpublish,
+            "mqtt plugin: successfully reconnected to broker \"%s:%d\"",
+            conf->host, conf->port);
+
+    return (0);
+} /* mqtt_reconnect */
+
+/* must hold conf->lock when calling. */
+static int mqtt_connect (mqtt_client_conf_t *conf)
+{
+    char const *client_id;
+    int status;
+
+    if (conf->mosq != NULL)
+        return mqtt_reconnect (conf);
+
+    if (conf->client_id)
+        client_id = conf->client_id;
+    else
+        client_id = hostname_g;
+
+#if LIBMOSQUITTO_MAJOR == 0
+    conf->mosq = mosquitto_new (client_id, /* user data = */ conf);
+#else
+    conf->mosq = mosquitto_new (client_id, conf->clean_session, /* user data = */ conf);
+#endif
+    if (conf->mosq == NULL)
+    {
+        ERROR ("mqtt plugin: mosquitto_new failed");
+        return (-1);
+    }
+
+    if (conf->username && conf->password)
+    {
+        status = mosquitto_username_pw_set (conf->mosq, conf->username, conf->password);
+        if (status != MOSQ_ERR_SUCCESS)
+        {
+            char errbuf[1024];
+            ERROR ("mqtt plugin: mosquitto_username_pw_set failed: %s",
+                    (status == MOSQ_ERR_ERRNO)
+                    ? sstrerror (errno, errbuf, sizeof (errbuf))
+                    : mosquitto_strerror (status));
+
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            return (-1);
+        }
+    }
+
+#if LIBMOSQUITTO_MAJOR == 0
+    status = mosquitto_connect (conf->mosq, conf->host, conf->port,
+            /* keepalive = */ MQTT_KEEPALIVE, /* clean session = */ conf->clean_session);
+#else
+    status = mosquitto_connect (conf->mosq, conf->host, conf->port, MQTT_KEEPALIVE);
+#endif
+    if (status != MOSQ_ERR_SUCCESS)
+    {
+        char errbuf[1024];
+        ERROR ("mqtt plugin: mosquitto_connect failed: %s",
+                (status == MOSQ_ERR_ERRNO)
+                ? sstrerror (errno, errbuf, sizeof (errbuf))
+                : mosquitto_strerror (status));
+
+        mosquitto_destroy (conf->mosq);
+        conf->mosq = NULL;
+        return (-1);
+    }
+
+    if (!conf->publish)
+    {
+        mosquitto_message_callback_set (conf->mosq, on_message);
+
+        status = mosquitto_subscribe (conf->mosq,
+                /* message_id = */ NULL,
+                conf->topic, conf->qos);
+        if (status != MOSQ_ERR_SUCCESS)
+        {
+            ERROR ("mqtt plugin: Subscribing to \"%s\" failed: %s",
+                    conf->topic, mosquitto_strerror (status));
+
+            mosquitto_disconnect (conf->mosq);
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            return (-1);
+        }
+    }
+
+    conf->connected = 1;
+    return (0);
+} /* mqtt_connect */
+
+static void *subscribers_thread (void *arg)
+{
+    mqtt_client_conf_t *conf = arg;
+    int status;
+
+    conf->loop = 1;
+
+    while (conf->loop)
+    {
+        status = mqtt_connect (conf);
+        if (status != 0)
+        {
+            sleep (1);
+            continue;
+        }
+
+        /* The documentation says "0" would map to the default (1000ms), but
+         * that does not work on some versions. */
+#if LIBMOSQUITTO_MAJOR == 0
+        status = mosquitto_loop (conf->mosq, /* timeout = */ 1000 /* ms */);
+#else
+        status = mosquitto_loop (conf->mosq,
+                /* timeout[ms] = */ 1000,
+                /* max_packets = */  100);
+#endif
+        if (status == MOSQ_ERR_CONN_LOST)
+        {
+            conf->connected = 0;
+            continue;
+        }
+        else if (status != MOSQ_ERR_SUCCESS)
+        {
+            ERROR ("mqtt plugin: mosquitto_loop failed: %s",
+                    mosquitto_strerror (status));
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            conf->connected = 0;
+            continue;
+        }
+
+        DEBUG ("mqtt plugin: mosquitto_loop succeeded.");
+    } /* while (conf->loop) */
+
+    pthread_exit (0);
+} /* void *subscribers_thread */
+
+static int publish (mqtt_client_conf_t *conf, char const *topic,
+    void const *payload, size_t payload_len)
+{
+    int status;
+
+    pthread_mutex_lock (&conf->lock);
+
+    status = mqtt_connect (conf);
+    if (status != 0) {
+        pthread_mutex_unlock (&conf->lock);
+        ERROR ("mqtt plugin: unable to reconnect to broker");
+        return (status);
+    }
+
+    status = mosquitto_publish(conf->mosq, /* message_id */ NULL, topic,
+#if LIBMOSQUITTO_MAJOR == 0
+            (uint32_t) payload_len, payload,
+#else
+            (int) payload_len, payload,
+#endif
+            conf->qos, conf->retain);
+    if (status != MOSQ_ERR_SUCCESS)
+    {
+        char errbuf[1024];
+        c_complain (LOG_ERR,
+            &conf->complaint_cantpublish,
+            "mqtt plugin: mosquitto_publish failed: %s",
+            (status == MOSQ_ERR_ERRNO)
+            ? sstrerror(errno, errbuf, sizeof (errbuf))
+            : mosquitto_strerror(status));
+        /* Mark our connection "down" regardless of the error as a safety
+         * measure; we will try to reconnect the next time we have to publish a
+         * message */
+        conf->connected = 0;
+
+        pthread_mutex_unlock (&conf->lock);
+        return (-1);
+    }
+
+    pthread_mutex_unlock (&conf->lock);
+    return (0);
+} /* int publish */
+
+static int format_topic (char *buf, size_t buf_len,
+    data_set_t const *ds, value_list_t const *vl,
+    mqtt_client_conf_t *conf)
+{
+    char name[MQTT_MAX_TOPIC_SIZE];
+    int status;
+
+    if ((conf->topic_prefix == NULL) || (conf->topic_prefix[0] == 0))
+        return (FORMAT_VL (buf, buf_len, vl));
+
+    status = FORMAT_VL (name, sizeof (name), vl);
+    if (status != 0)
+        return (status);
+
+    status = ssnprintf (buf, buf_len, "%s/%s", conf->topic_prefix, name);
+    if ((status < 0) || (((size_t) status) >= buf_len))
+        return (ENOMEM);
+
+    return (0);
+} /* int format_topic */
+
+static int mqtt_write (const data_set_t *ds, const value_list_t *vl,
+    user_data_t *user_data)
+{
+    mqtt_client_conf_t *conf;
+    char topic[MQTT_MAX_TOPIC_SIZE];
+    char payload[MQTT_MAX_MESSAGE_SIZE];
+    int status = 0;
+
+    if ((user_data == NULL) || (user_data->data == NULL))
+        return (EINVAL);
+    conf = user_data->data;
+
+    status = format_topic (topic, sizeof (topic), ds, vl, conf);
+    if (status != 0)
+    {
+        ERROR ("mqtt plugin: format_topic failed with status %d.", status);
+        return (status);
+    }
+
+    status = format_values (payload, sizeof (payload),
+            ds, vl, conf->store_rates);
+    if (status != 0)
+    {
+        ERROR ("mqtt plugin: format_values failed with status %d.", status);
+        return (status);
+    }
+
+    status = publish (conf, topic, payload, strlen (payload) + 1);
+    if (status != 0)
+    {
+        ERROR ("mqtt plugin: publish failed: %s", mosquitto_strerror (status));
+        return (status);
+    }
+
+    return (status);
+} /* mqtt_write */
+
+/*
+ * <Publish "name">
+ *   Host "example.com"
+ *   Port 1883
+ *   ClientId "collectd"
+ *   User "guest"
+ *   Password "secret"
+ *   Prefix "collectd"
+ *   StoreRates true
+ *   Retain false
+ *   QoS 0
+ * </Publish>
+ */
+static int mqtt_config_publisher (oconfig_item_t *ci)
+{
+    mqtt_client_conf_t *conf;
+    char cb_name[1024];
+    user_data_t user_data;
+    int status;
+    int i;
+
+    conf = calloc (1, sizeof (*conf));
+    if (conf == NULL)
+    {
+        ERROR ("mqtt plugin: malloc failed.");
+        return (-1);
+    }
+    conf->publish = 1;
+
+    conf->name = NULL;
+    status = cf_util_get_string (ci, &conf->name);
+    if (status != 0)
+    {
+        mqtt_free (conf);
+        return (status);
+    }
+
+    conf->host = strdup (MQTT_DEFAULT_HOST);
+    conf->port = MQTT_DEFAULT_PORT;
+    conf->client_id = NULL;
+    conf->qos = 0;
+    conf->topic_prefix = strdup (MQTT_DEFAULT_TOPIC_PREFIX);
+    conf->store_rates = 1;
+
+    status = pthread_mutex_init (&conf->lock, NULL);
+    if (status != 0)
+    {
+      mqtt_free (conf);
+      return (status);
+    }
+
+    C_COMPLAIN_INIT (&conf->complaint_cantpublish);
+
+    for (i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+        if (strcasecmp ("Host", child->key) == 0)
+            cf_util_get_string (child, &conf->host);
+        else if (strcasecmp ("Port", child->key) == 0)
+        {
+            int tmp = cf_util_get_port_number (child);
+            if (tmp < 0)
+                ERROR ("mqtt plugin: Invalid port number.");
+            else
+                conf->port = tmp;
+        }
+        else if (strcasecmp ("ClientId", child->key) == 0)
+            cf_util_get_string (child, &conf->client_id);
+        else if (strcasecmp ("User", child->key) == 0)
+            cf_util_get_string (child, &conf->username);
+        else if (strcasecmp ("Password", child->key) == 0)
+            cf_util_get_string (child, &conf->password);
+        else if (strcasecmp ("QoS", child->key) == 0)
+        {
+            int tmp = -1;
+            status = cf_util_get_int (child, &tmp);
+            if ((status != 0) || (tmp < 0) || (tmp > 2))
+                ERROR ("mqtt plugin: Not a valid QoS setting.");
+            else
+                conf->qos = tmp;
+        }
+        else if (strcasecmp ("Prefix", child->key) == 0)
+            cf_util_get_string (child, &conf->topic_prefix);
+        else if (strcasecmp ("StoreRates", child->key) == 0)
+            cf_util_get_boolean (child, &conf->store_rates);
+        else if (strcasecmp ("Retain", child->key) == 0)
+            cf_util_get_boolean (child, &conf->retain);
+        else
+            ERROR ("mqtt plugin: Unknown config option: %s", child->key);
+    }
+
+    ssnprintf (cb_name, sizeof (cb_name), "mqtt/%s", conf->name);
+    memset (&user_data, 0, sizeof (user_data));
+    user_data.data = conf;
+
+    plugin_register_write (cb_name, mqtt_write, &user_data);
+    return (0);
+} /* mqtt_config_publisher */
+
+/*
+ * <Subscribe "name">
+ *   Host "example.com"
+ *   Port 1883
+ *   ClientId "collectd"
+ *   User "guest"
+ *   Password "secret"
+ *   Topic "collectd/#"
+ * </Publish>
+ */
+static int mqtt_config_subscriber (oconfig_item_t *ci)
+{
+    mqtt_client_conf_t **tmp;
+    mqtt_client_conf_t *conf;
+    int status;
+    int i;
+
+    conf = calloc (1, sizeof (*conf));
+    if (conf == NULL)
+    {
+        ERROR ("mqtt plugin: malloc failed.");
+        return (-1);
+    }
+    conf->publish = 0;
+
+    conf->name = NULL;
+    status = cf_util_get_string (ci, &conf->name);
+    if (status != 0)
+    {
+        mqtt_free (conf);
+        return (status);
+    }
+
+    conf->host = strdup (MQTT_DEFAULT_HOST);
+    conf->port = MQTT_DEFAULT_PORT;
+    conf->client_id = NULL;
+    conf->qos = 2;
+    conf->topic = strdup (MQTT_DEFAULT_TOPIC);
+    conf->clean_session = 1;
+
+    status = pthread_mutex_init (&conf->lock, NULL);
+    if (status != 0)
+    {
+      mqtt_free (conf);
+      return (status);
+    }
+
+    C_COMPLAIN_INIT (&conf->complaint_cantpublish);
+
+    for (i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+        if (strcasecmp ("Host", child->key) == 0)
+            cf_util_get_string (child, &conf->host);
+        else if (strcasecmp ("Port", child->key) == 0)
+        {
+            int tmp = cf_util_get_port_number (child);
+            if (tmp < 0)
+                ERROR ("mqtt plugin: Invalid port number.");
+            else
+                conf->port = tmp;
+        }
+        else if (strcasecmp ("ClientId", child->key) == 0)
+            cf_util_get_string (child, &conf->client_id);
+        else if (strcasecmp ("User", child->key) == 0)
+            cf_util_get_string (child, &conf->username);
+        else if (strcasecmp ("Password", child->key) == 0)
+            cf_util_get_string (child, &conf->password);
+        else if (strcasecmp ("QoS", child->key) == 0)
+        {
+            int tmp = -1;
+            status = cf_util_get_int (child, &tmp);
+            if ((status != 0) || (tmp < 0) || (tmp > 2))
+                ERROR ("mqtt plugin: Not a valid QoS setting.");
+            else
+                conf->qos = tmp;
+        }
+        else if (strcasecmp ("Topic", child->key) == 0)
+            cf_util_get_string (child, &conf->topic);
+        else if (strcasecmp ("CleanSession", child->key) == 0)
+            cf_util_get_boolean (child, &conf->clean_session);
+        else
+            ERROR ("mqtt plugin: Unknown config option: %s", child->key);
+    }
+
+    tmp = realloc (subscribers, sizeof (*subscribers) * subscribers_num);
+    if (tmp == NULL)
+    {
+        ERROR ("mqtt plugin: realloc failed.");
+        mqtt_free (conf);
+        return (-1);
+    }
+    subscribers = tmp;
+    subscribers[subscribers_num] = conf;
+    subscribers_num++;
+
+    return (0);
+} /* mqtt_config_subscriber */
+
+/*
+ * <Plugin mqtt>
+ *   <Publish "name">
+ *     # ...
+ *   </Publish>
+ *   <Subscribe "name">
+ *     # ...
+ *   </Subscribe>
+ * </Plugin>
+ */
+static int mqtt_config (oconfig_item_t *ci)
+{
+    int i;
+
+    for (i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+
+        if (strcasecmp ("Publish", child->key) == 0)
+            mqtt_config_publisher (child);
+        else if (strcasecmp ("Subscribe", child->key) == 0)
+            mqtt_config_subscriber (child);
+        else
+            ERROR ("mqtt plugin: Unknown config option: %s", child->key);
+    }
+
+    return (0);
+} /* int mqtt_config */
+
+static int mqtt_init (void)
+{
+    size_t i;
+
+    mosquitto_lib_init ();
+
+    for (i = 0; i < subscribers_num; i++)
+    {
+        int status;
+
+        if (subscribers[i]->loop)
+            continue;
+
+        status = plugin_thread_create (&subscribers[i]->thread,
+                /* attrs = */ NULL,
+                /* func  = */ subscribers_thread,
+                /* args  = */ subscribers[i]);
+        if (status != 0)
+        {
+            char errbuf[1024];
+            ERROR ("mqtt plugin: pthread_create failed: %s",
+                    sstrerror (errno, errbuf, sizeof (errbuf)));
+            continue;
+        }
+    }
+
+    return (0);
+} /* mqtt_init */
+
+void module_register (void)
+{
+    plugin_register_complex_config ("mqtt", mqtt_config);
+    plugin_register_init ("mqtt", mqtt_init);
+} /* void module_register */
+
+/* vim: set sw=4 sts=4 et fdm=marker : */
index eaa0371..a8a8e86 100644 (file)
@@ -213,7 +213,7 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
 
                plugin_register_complex_read (/* group = */ NULL, cb_name,
                                              mysql_read,
-                                             /* interval = */ NULL, &ud);
+                                             /* interval = */ 0, &ud);
        }
        else
        {
index f446d59..020bfba 100644 (file)
@@ -2906,7 +2906,6 @@ static int cna_read (user_data_t *ud);
 static int cna_register_host (host_config_t *host) /* {{{ */
 {
        char cb_name[256];
-       struct timespec interval;
        user_data_t ud;
 
        if (host->vfiler)
@@ -2915,15 +2914,13 @@ static int cna_register_host (host_config_t *host) /* {{{ */
        else
                ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
 
-       CDTIME_T_TO_TIMESPEC (host->interval, &interval);
-
        memset (&ud, 0, sizeof (ud));
        ud.data = host;
        ud.free_func = (void (*) (void *)) free_host_config;
 
        plugin_register_complex_read (/* group = */ NULL, cb_name,
                        /* callback  = */ cna_read,
-                       /* interval  = */ (host->interval > 0) ? &interval : NULL,
+                       /* interval  = */ host->interval,
                        /* user data = */ &ud);
 
        return (0);
index aa9760f..e1f378d 100644 (file)
@@ -30,7 +30,6 @@
 #include "common.h"
 
 #include <asm/types.h>
-#include <sys/socket.h>
 
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
index af24911..9169000 100644 (file)
@@ -39,9 +39,6 @@
 #if HAVE_PTHREAD_H
 # include <pthread.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NETDB_H
 # include <netdb.h>
 #endif
@@ -283,8 +280,8 @@ typedef struct receive_list_entry_s receive_list_entry_t;
 static int network_config_ttl = 0;
 /* Ethernet - (IPv6 + UDP) = 1500 - (40 + 8) = 1452 */
 static size_t network_config_packet_size = 1452;
-static int network_config_forward = 0;
-static int network_config_stats = 0;
+static _Bool network_config_forward = 0;
+static _Bool network_config_stats = 0;
 
 static sockent_t *sending_sockets = NULL;
 
@@ -310,6 +307,7 @@ static pthread_t dispatch_thread_id;
 static char            *send_buffer;
 static char            *send_buffer_ptr;
 static int              send_buffer_fill;
+static cdtime_t         send_buffer_last_update;
 static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
 static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -353,7 +351,7 @@ static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
   _Bool received = 0;
   int status;
 
-  if (network_config_forward != 0)
+  if (network_config_forward)
     return (1);
 
   if (vl->meta == NULL)
@@ -771,7 +769,7 @@ static int write_part_string (char **ret_buffer, int *ret_buffer_len,
 } /* int write_part_string */
 
 static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
-               value_t **ret_values, int *ret_num_values)
+               value_t **ret_values, size_t *ret_num_values)
 {
        char *buffer = *ret_buffer;
        size_t buffer_len = *ret_buffer_len;
@@ -875,7 +873,7 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
 
        *ret_buffer     = buffer;
        *ret_buffer_len = buffer_len - pkg_length;
-       *ret_num_values = pkg_numval;
+       *ret_num_values = (size_t) pkg_numval;
        *ret_values     = pkg_values;
 
        sfree (pkg_types);
@@ -2442,7 +2440,7 @@ static int network_receive (void) /* {{{ */
        char buffer[network_config_packet_size];
        int  buffer_len;
 
-       int i;
+       size_t i;
        int status = 0;
 
        receive_list_entry_t *private_list_head;
@@ -2583,6 +2581,7 @@ static void network_init_buffer (void)
        memset (send_buffer, 0, network_config_packet_size);
        send_buffer_ptr = send_buffer;
        send_buffer_fill = 0;
+       send_buffer_last_update = 0;
 
        memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 } /* int network_init_buffer */
@@ -2922,6 +2921,7 @@ static int network_write (const data_set_t *ds, const value_list_t *vl,
                /* status == bytes added to the buffer */
                send_buffer_fill += status;
                send_buffer_ptr  += status;
+               send_buffer_last_update = cdtime();
 
                stats_values_sent++;
        }
@@ -2958,58 +2958,13 @@ static int network_write (const data_set_t *ds, const value_list_t *vl,
        return ((status < 0) ? -1 : 0);
 } /* int network_write */
 
-static int network_config_set_boolean (const oconfig_item_t *ci, /* {{{ */
-    int *retval)
-{
-  if ((ci->values_num != 1)
-      || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN)
-        && (ci->values[0].type != OCONFIG_TYPE_STRING)))
-  {
-    ERROR ("network plugin: The `%s' config option needs "
-        "exactly one boolean argument.", ci->key);
-    return (-1);
-  }
-
-  if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
-  {
-    if (ci->values[0].value.boolean)
-      *retval = 1;
-    else
-      *retval = 0;
-  }
-  else
-  {
-    char *str = ci->values[0].value.string;
-
-    if (IS_TRUE (str))
-      *retval = 1;
-    else if (IS_FALSE (str))
-      *retval = 0;
-    else
-    {
-      ERROR ("network plugin: Cannot parse string value `%s' of the `%s' "
-          "option as boolean value.",
-          str, ci->key);
-      return (-1);
-    }
-  }
-
-  return (0);
-} /* }}} int network_config_set_boolean */
-
 static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
 {
-  int tmp;
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("network plugin: The `TimeToLive' config option needs exactly "
-        "one numeric argument.");
-    return (-1);
-  }
+  int tmp = 0;
 
-  tmp = (int) ci->values[0].value.number;
-  if ((tmp > 0) && (tmp <= 255))
+  if (cf_util_get_int (ci, &tmp) != 0)
+    return (-1);
+  else if ((tmp > 0) && (tmp <= 255))
     network_config_ttl = tmp;
   else {
     WARNING ("network plugin: The `TimeToLive' must be between 1 and 255.");
@@ -3022,63 +2977,30 @@ static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
 static int network_config_set_interface (const oconfig_item_t *ci, /* {{{ */
     int *interface)
 {
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("network plugin: The `Interface' config option needs exactly "
-        "one string argument.");
-    return (-1);
-  }
+  char if_name[256];
 
-  if (interface == NULL)
+  if (cf_util_get_string_buffer (ci, if_name, sizeof (if_name)) != 0)
     return (-1);
 
-  *interface = if_nametoindex (ci->values[0].value.string);
-
+  *interface = if_nametoindex (if_name);
   return (0);
 } /* }}} int network_config_set_interface */
 
 static int network_config_set_buffer_size (const oconfig_item_t *ci) /* {{{ */
 {
-  int tmp;
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
-  {
-    WARNING ("network plugin: The `MaxPacketSize' config option needs exactly "
-        "one numeric argument.");
-    return (-1);
-  }
+  int tmp = 0;
 
-  tmp = (int) ci->values[0].value.number;
-  if ((tmp >= 1024) && (tmp <= 65535))
+  if (cf_util_get_int (ci, &tmp) != 0)
+    return (-1);
+  else if ((tmp >= 1024) && (tmp <= 65535))
     network_config_packet_size = tmp;
-
-  return (0);
-} /* }}} int network_config_set_buffer_size */
-
-#if HAVE_LIBGCRYPT
-static int network_config_set_string (const oconfig_item_t *ci, /* {{{ */
-    char **ret_string)
-{
-  char *tmp;
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("network plugin: The `%s' config option needs exactly "
-        "one string argument.", ci->key);
+  else {
+    WARNING ("network plugin: The `MaxPacketSize' must be between 1024 and 65535.");
     return (-1);
   }
 
-  tmp = strdup (ci->values[0].value.string);
-  if (tmp == NULL)
-    return (-1);
-
-  sfree (*ret_string);
-  *ret_string = tmp;
-
   return (0);
-} /* }}} int network_config_set_string */
-#endif /* HAVE_LIBGCRYPT */
+} /* }}} int network_config_set_buffer_size */
 
 #if HAVE_LIBGCRYPT
 static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */
@@ -3142,15 +3064,14 @@ static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */
 
 #if HAVE_LIBGCRYPT
     if (strcasecmp ("AuthFile", child->key) == 0)
-      network_config_set_string (child, &se->data.server.auth_file);
+      cf_util_get_string (child, &se->data.server.auth_file);
     else if (strcasecmp ("SecurityLevel", child->key) == 0)
       network_config_set_security_level (child,
           &se->data.server.security_level);
     else
 #endif /* HAVE_LIBGCRYPT */
     if (strcasecmp ("Interface", child->key) == 0)
-      network_config_set_interface (child,
-          &se->interface);
+      network_config_set_interface (child, &se->interface);
     else
     {
       WARNING ("network plugin: Option `%s' is not allowed here.",
@@ -3181,7 +3102,7 @@ static int network_config_add_listen (const oconfig_item_t *ci) /* {{{ */
   status = sockent_server_listen (se);
   if (status != 0)
   {
-    ERROR ("network plugin: network_config_add_server: sockent_server_listen failed.");
+    ERROR ("network plugin: network_config_add_listen: sockent_server_listen failed.");
     sockent_destroy (se);
     return (-1);
   }
@@ -3229,19 +3150,18 @@ static int network_config_add_server (const oconfig_item_t *ci) /* {{{ */
 
 #if HAVE_LIBGCRYPT
     if (strcasecmp ("Username", child->key) == 0)
-      network_config_set_string (child, &se->data.client.username);
+      cf_util_get_string (child, &se->data.client.username);
     else if (strcasecmp ("Password", child->key) == 0)
-      network_config_set_string (child, &se->data.client.password);
+      cf_util_get_string (child, &se->data.client.password);
     else if (strcasecmp ("SecurityLevel", child->key) == 0)
       network_config_set_security_level (child,
           &se->data.client.security_level);
     else
 #endif /* HAVE_LIBGCRYPT */
     if (strcasecmp ("Interface", child->key) == 0)
-      network_config_set_interface (child,
-          &se->interface);
-               else if (strcasecmp ("ResolveInterval", child->key) == 0)
-                       cf_util_get_cdtime(child, &se->data.client.resolve_interval);
+      network_config_set_interface (child, &se->interface);
+    else if (strcasecmp ("ResolveInterval", child->key) == 0)
+      cf_util_get_cdtime(child, &se->data.client.resolve_interval);
     else
     {
       WARNING ("network plugin: Option `%s' is not allowed here.",
@@ -3310,9 +3230,9 @@ static int network_config (oconfig_item_t *ci) /* {{{ */
     else if (strcasecmp ("MaxPacketSize", child->key) == 0)
       network_config_set_buffer_size (child);
     else if (strcasecmp ("Forward", child->key) == 0)
-      network_config_set_boolean (child, &network_config_forward);
+      cf_util_get_boolean (child, &network_config_forward);
     else if (strcasecmp ("ReportStats", child->key) == 0)
-      network_config_set_boolean (child, &network_config_stats);
+      cf_util_get_boolean (child, &network_config_stats);
     else
     {
       WARNING ("network plugin: Option `%s' is not allowed here.",
@@ -3533,7 +3453,7 @@ static int network_init (void)
        network_init_gcrypt ();
 #endif
 
-       if (network_config_stats != 0)
+       if (network_config_stats)
                plugin_register_read ("network", network_stats_read);
 
        plugin_register_shutdown ("network", network_shutdown);
@@ -3611,15 +3531,25 @@ static int network_init (void)
  * just send the buffer if `flush'  is called - if the requested value was in
  * there, good. If not, well, then there is nothing to flush.. -octo
  */
-static int network_flush (__attribute__((unused)) cdtime_t timeout,
+static int network_flush (cdtime_t timeout,
                __attribute__((unused)) const char *identifier,
                __attribute__((unused)) user_data_t *user_data)
 {
        pthread_mutex_lock (&send_buffer_lock);
 
        if (send_buffer_fill > 0)
-         flush_buffer ();
-
+       {
+               if (timeout > 0)
+               {
+                       cdtime_t now = cdtime ();
+                       if ((send_buffer_last_update + timeout) > now)
+                       {
+                               pthread_mutex_unlock (&send_buffer_lock);
+                               return (0);
+                       }
+               }
+               flush_buffer ();
+       }
        pthread_mutex_unlock (&send_buffer_lock);
 
        return (0);
index 4e4ce3b..69ec06d 100644 (file)
@@ -188,8 +188,7 @@ static int init (void)
   }
   else
   {
-    curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS,
-       CDTIME_T_TO_MS(plugin_get_interval()));
+    curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS, (long) CDTIME_T_TO_MS(plugin_get_interval()));
   }
 #endif
 
index 5fdfef3..dbde660 100644 (file)
@@ -38,9 +38,6 @@
 #if HAVE_NETDB_H
 # include <netdb.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif
@@ -265,7 +262,7 @@ static char *refclock_names[] =
        "JJY",        "TT_IRIG",      "GPS_ZYFER",  "GPS_RIPENCC", /* 40-43 */
        "NEOCLK4X"                                                 /* 44    */
 };
-static int refclock_names_num = STATIC_ARRAY_SIZE (refclock_names);
+static size_t refclock_names_num = STATIC_ARRAY_SIZE (refclock_names);
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * End of the copied stuff..                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -868,7 +865,7 @@ static int ntpd_get_name_refclock (char *buffer, size_t buffer_size,
        uint32_t refclock_id = ntpd_get_refclock_id (peer_info);
        uint32_t unit_id = ntohl (peer_info->srcadr) & 0x00FF;
 
-       if (refclock_id >= refclock_names_num)
+       if (((size_t) refclock_id) >= refclock_names_num)
                return (ntpd_get_name_from_address (buffer, buffer_size,
                                        peer_info,
                                        /* do_reverse_lookup = */ 0));
index 6d0576c..bbf387f 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <sys/types.h>
 #include <netdb.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 
index 51e6407..58c35e1 100644 (file)
@@ -590,7 +590,6 @@ static int cow_shutdown (void)
 static int cow_init (void)
 {
   int status;
-  struct timespec cb_interval;
 
   if (device_g == NULL)
   {
@@ -606,11 +605,8 @@ static int cow_init (void)
     return (1);
   }
 
-  CDTIME_T_TO_TIMESPEC (ow_interval, &cb_interval);
-
   plugin_register_complex_read (/* group = */ NULL, "onewire", cow_read,
-      (ow_interval != 0) ? &cb_interval : NULL,
-      /* user data = */ NULL);
+      ow_interval, /* user data = */ NULL);
   plugin_register_shutdown ("onewire", cow_shutdown);
 
   return (0);
index 8667058..ffcdb94 100644 (file)
@@ -38,6 +38,8 @@ struct cldap_s /* {{{ */
 {
        char *name;
 
+       char *binddn;
+       char *password;
        char *cacert;
        char *host;
        int   state;
@@ -56,6 +58,8 @@ static void cldap_free (cldap_t *st) /* {{{ */
        if (st == NULL)
                return;
 
+       sfree (st->binddn);
+       sfree (st->password);
        sfree (st->cacert);
        sfree (st->host);
        sfree (st->name);
@@ -110,10 +114,19 @@ static int cldap_init_host (cldap_t *st) /* {{{ */
        }
 
        struct berval cred;
-       cred.bv_val = "";
-       cred.bv_len = 0;
+       if (st->password != NULL)
+       {
+               cred.bv_val = st->password;
+               cred.bv_len = strlen (st->password);
+       }
+       else
+       {
+               cred.bv_val = "";
+               cred.bv_len = 0;
+       }
 
-       rc = ldap_sasl_bind_s (st->ld, NULL, NULL, &cred, NULL, NULL, NULL);
+       rc = ldap_sasl_bind_s (st->ld, st->binddn, LDAP_SASL_SIMPLE, &cred, 
+                       NULL, NULL, NULL);
        if (rc != LDAP_SUCCESS)
        {
                ERROR ("openldap plugin: Failed to bind to %s: %s",
@@ -559,7 +572,11 @@ static int cldap_config_add (oconfig_item_t *ci) /* {{{ */
        {
                oconfig_item_t *child = ci->children + i;
 
-               if (strcasecmp ("CACert", child->key) == 0)
+               if (strcasecmp ("BindDN", child->key) == 0)
+                       status = cf_util_get_string (child, &st->binddn);
+               else if (strcasecmp ("Password", child->key) == 0)
+                       status = cf_util_get_string (child, &st->password);
+               else if (strcasecmp ("CACert", child->key) == 0)
                        status = cf_util_get_string (child, &st->cacert);
                else if (strcasecmp ("StartTLS", child->key) == 0)
                        status = cf_util_get_boolean (child, &st->starttls);
@@ -630,7 +647,7 @@ static int cldap_config_add (oconfig_item_t *ci) /* {{{ */
                status = plugin_register_complex_read (/* group = */ NULL,
                                /* name      = */ callback_name,
                                /* callback  = */ cldap_read_host,
-                               /* interval  = */ NULL,
+                               /* interval  = */ 0,
                                /* user_data = */ &ud);
        }
 
index a964cce..0a98684 100644 (file)
@@ -301,33 +301,32 @@ static int hv2data_source (pTHX_ HV *hash, data_source_t *ds)
        return 0;
 } /* static int hv2data_source (HV *, data_source_t *) */
 
-static int av2value (pTHX_ char *name, AV *array, value_t *value, int len)
+/* av2value converts at most "len" elements from "array" to "value". Returns the
+ * number of elements converted or zero on error. */
+static size_t av2value (pTHX_ char *name, AV *array, value_t *value, size_t array_len)
 {
        const data_set_t *ds;
+       size_t i;
 
-       int i = 0;
-
-       if ((NULL == name) || (NULL == array) || (NULL == value))
-               return -1;
-
-       if (av_len (array) < len - 1)
-               len = av_len (array) + 1;
-
-       if (0 >= len)
-               return -1;
+       if ((NULL == name) || (NULL == array) || (NULL == value) || (array_len == 0))
+               return 0;
 
        ds = plugin_get_ds (name);
        if (NULL == ds) {
                log_err ("av2value: Unknown dataset \"%s\"", name);
-               return -1;
+               return 0;
        }
 
-       if (ds->ds_num < len) {
-               log_warn ("av2value: Value length exceeds data set length.");
-               len = ds->ds_num;
+       if (array_len < ds->ds_num) {
+               log_warn ("av2value: array does not contain enough elements for type \"%s\": got %zu, want %zu",
+                               name, array_len, ds->ds_num);
+               return 0;
+       } else if (array_len > ds->ds_num) {
+               log_warn ("av2value: array contains excess elements for type \"%s\": got %zu, want %zu",
+                               name, array_len, ds->ds_num);
        }
 
-       for (i = 0; i < len; ++i) {
+       for (i = 0; i < ds->ds_num; ++i) {
                SV **tmp = av_fetch (array, i, 0);
 
                if (NULL != tmp) {
@@ -341,11 +340,12 @@ static int av2value (pTHX_ char *name, AV *array, value_t *value, int len)
                                value[i].absolute = SvIV (*tmp);
                }
                else {
-                       return -1;
+                       return 0;
                }
        }
-       return len;
-} /* static int av2value (char *, AV *, value_t *, int) */
+
+       return ds->ds_num;
+} /* static size_t av2value (char *, AV *, value_t *, size_t) */
 
 /*
  * value list:
@@ -380,16 +380,14 @@ static int hv2value_list (pTHX_ HV *hash, value_list_t *vl)
 
        {
                AV  *array = (AV *)SvRV (*tmp);
-               int len    = av_len (array) + 1;
-
-               if (len <= 0)
+               /* av_len returns the highest index, not the actual length. */
+               size_t array_len = (size_t) (av_len (array) + 1);
+               if (array_len == 0)
                        return -1;
 
-               vl->values     = (value_t *)smalloc (len * sizeof (value_t));
-               vl->values_len = av2value (aTHX_ vl->type, (AV *)SvRV (*tmp),
-                               vl->values, len);
-
-               if (-1 == vl->values_len) {
+               vl->values     = calloc (array_len, sizeof (*vl->values));
+               vl->values_len = av2value (aTHX_ vl->type, (AV *)SvRV (*tmp), vl->values, array_len);
+               if (vl->values_len == 0) {
                        sfree (vl->values);
                        return -1;
                }
@@ -604,7 +602,7 @@ static int hv2notification (pTHX_ HV *hash, notification_t *n)
 
 static int data_set2av (pTHX_ data_set_t *ds, AV *array)
 {
-       int i = 0;
+       size_t i;
 
        if ((NULL == ds) || (NULL == array))
                return -1;
@@ -640,24 +638,17 @@ static int data_set2av (pTHX_ data_set_t *ds, AV *array)
 static int value_list2hv (pTHX_ value_list_t *vl, data_set_t *ds, HV *hash)
 {
        AV *values = NULL;
-
-       int i   = 0;
-       int len = 0;
+       size_t i;
 
        if ((NULL == vl) || (NULL == ds) || (NULL == hash))
                return -1;
 
-       len = vl->values_len;
-
-       if (ds->ds_num < len) {
-               log_warn ("value2av: Value length exceeds data set length.");
-               len = ds->ds_num;
-       }
-
        values = newAV ();
-       av_extend (values, len - 1);
+       /* av_extend takes the last *index* to which the array should be extended. */
+       av_extend (values, vl->values_len - 1);
 
-       for (i = 0; i < len; ++i) {
+       assert (ds->ds_num == vl->values_len);
+       for (i = 0; i < vl->values_len; ++i) {
                SV *val = NULL;
 
                if (DS_TYPE_COUNTER == ds->ds[i].type)
index 112e28f..a2bd549 100644 (file)
--- a/src/pf.c
+++ b/src/pf.c
@@ -26,9 +26,6 @@
 #if HAVE_SYS_IOCTL_H
 # include <sys/ioctl.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NET_IF_H
 # include <net/if.h>
 #endif
index 9f0a800..b6e7b15 100644 (file)
@@ -29,7 +29,6 @@
 #include "configfile.h"
 
 #include <pthread.h>
-#include <sys/socket.h>
 #include <netdb.h>
 #include <poll.h>
 
index d669aa9..df2f6da 100644 (file)
@@ -210,7 +210,8 @@ static int ping_dispatch_all (pingobj_t *pingobj) /* {{{ */
       hl->pkg_missed++;
 
     /* if the host did not answer our last N packages, trigger a resolv. */
-    if (ping_max_missed >= 0 && hl->pkg_missed >= ping_max_missed)
+    if ((ping_max_missed >= 0)
+        && (hl->pkg_missed >= ((uint32_t) ping_max_missed)))
     { /* {{{ */
       /* we reset the missed package counter here, since we only want to
        * trigger a resolv every N packages and not every package _AFTER_ N
index 54c856d..bef3490 100644 (file)
@@ -615,7 +615,7 @@ static int c_psql_read (user_data_t *ud)
        c_psql_database_t *db;
 
        int success = 0;
-       int i;
+       size_t i;
 
        if ((ud == NULL) || (ud->data == NULL)) {
                log_err ("c_psql_read: Invalid user data.");
@@ -663,8 +663,7 @@ static char *values_name_to_sqlarray (const data_set_t *ds,
 {
        char  *str_ptr;
        size_t str_len;
-
-       int i;
+       size_t i;
 
        str_ptr = string;
        str_len = string_len;
@@ -702,8 +701,7 @@ static char *values_type_to_sqlarray (const data_set_t *ds,
 {
        char  *str_ptr;
        size_t str_len;
-
-       int i;
+       size_t i;
 
        str_ptr = string;
        str_len = string_len;
@@ -751,8 +749,7 @@ static char *values_to_sqlarray (const data_set_t *ds, const value_list_t *vl,
        size_t str_len;
 
        gauge_t *rates = NULL;
-
-       int i;
+       size_t i;
 
        str_ptr = string;
        str_len = string_len;
@@ -837,7 +834,7 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
        const char *params[9];
 
        int success = 0;
-       int i;
+       size_t i;
 
        if ((ud == NULL) || (ud->data == NULL)) {
                log_err ("c_psql_write: Invalid user data.");
@@ -1196,7 +1193,6 @@ static int c_psql_config_database (oconfig_item_t *ci)
        c_psql_database_t *db;
 
        char cb_name[DATA_MAX_NAME_LEN];
-       struct timespec cb_interval = { 0, 0 };
        user_data_t ud;
 
        static _Bool have_flush = 0;
@@ -1291,12 +1287,9 @@ static int c_psql_config_database (oconfig_item_t *ci)
        ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
 
        if (db->queries_num > 0) {
-               CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
-
                ++db->ref_cnt;
                plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
-                               /* interval = */ (db->interval > 0) ? &cb_interval : NULL,
-                               &ud);
+                               /* interval = */ db->interval, &ud);
        }
        if (db->writers_num > 0) {
                ++db->ref_cnt;
index f9f291a..1050e7f 100644 (file)
@@ -37,7 +37,6 @@
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 
 #ifndef UNIX_PATH_MAX
@@ -83,42 +82,65 @@ struct statname_lookup_s
 typedef struct statname_lookup_s statname_lookup_t;
 
 /* Description of statistics returned by the recursor: {{{
-all-outqueries      counts the number of outgoing UDP queries since starting
-answers0-1          counts the number of queries answered within 1 millisecond
-answers100-1000     counts the number of queries answered within 1 second
-answers10-100       counts the number of queries answered within 100 milliseconds
-answers1-10         counts the number of queries answered within 10 milliseconds
-answers-slow        counts the number of queries answered after 1 second
-cache-entries       shows the number of entries in the cache
-cache-hits          counts the number of cache hits since starting
-cache-misses        counts the number of cache misses since starting
-chain-resends       number of queries chained to existing outstanding query
-client-parse-errors counts number of client packets that could not be parsed
-concurrent-queries  shows the number of MThreads currently running
-dlg-only-drops      number of records dropped because of delegation only setting
-negcache-entries    shows the number of entries in the Negative answer cache
-noerror-answers     counts the number of times it answered NOERROR since starting
-nsspeeds-entries    shows the number of entries in the NS speeds map
-nsset-invalidations number of times an nsset was dropped because it no longer worked
-nxdomain-answers    counts the number of times it answered NXDOMAIN since starting
-outgoing-timeouts   counts the number of timeouts on outgoing UDP queries since starting
-qa-latency          shows the current latency average
-questions           counts all End-user initiated queries with the RD bit set
-resource-limits     counts number of queries that could not be performed because of resource limits
-server-parse-errors counts number of server replied packets that could not be parsed
-servfail-answers    counts the number of times it answered SERVFAIL since starting
-spoof-prevents      number of times PowerDNS considered itself spoofed, and dropped the data
-sys-msec            number of CPU milliseconds spent in 'system' mode
-tcp-client-overflow number of times an IP address was denied TCP access because it already had too many connections
-tcp-outqueries      counts the number of outgoing TCP queries since starting
-tcp-questions       counts all incoming TCP queries (since starting)
-throttled-out       counts the number of throttled outgoing UDP queries since starting
-throttle-entries    shows the number of entries in the throttle map
-unauthorized-tcp    number of TCP questions denied because of allow-from restrictions
-unauthorized-udp    number of UDP questions denied because of allow-from restrictions
-unexpected-packets  number of answers from remote servers that were unexpected (might point to spoofing)
-uptime              number of seconds process has been running (since 3.1.5)
-user-msec           number of CPU milliseconds spent in 'user' mode
+all-outqueries        counts the number of outgoing UDP queries since starting
+answers-slow          counts the number of queries answered after 1 second
+answers0-1            counts the number of queries answered within 1 millisecond
+answers1-10           counts the number of queries answered within 10 milliseconds
+answers10-100         counts the number of queries answered within 100 milliseconds
+answers100-1000       counts the number of queries answered within 1 second
+cache-bytes           size of the cache in bytes (since 3.3.1)
+cache-entries         shows the number of entries in the cache
+cache-hits            counts the number of cache hits since starting, this does not include hits that got answered from the packet-cache
+cache-misses          counts the number of cache misses since starting
+case-mismatches       counts the number of mismatches in character case since starting
+chain-resends         number of queries chained to existing outstanding query
+client-parse-errors   counts number of client packets that could not be parsed
+concurrent-queries    shows the number of MThreads currently running
+dlg-only-drops        number of records dropped because of delegation only setting
+dont-outqueries       number of outgoing queries dropped because of 'dont-query' setting (since 3.3)
+edns-ping-matches     number of servers that sent a valid EDNS PING respons
+edns-ping-mismatches  number of servers that sent an invalid EDNS PING response
+failed-host-entries   number of servers that failed to resolve
+ipv6-outqueries       number of outgoing queries over IPv6
+ipv6-questions        counts all End-user initiated queries with the RD bit set, received over IPv6 UDP
+malloc-bytes          returns the number of bytes allocated by the process (broken, always returns 0)
+max-mthread-stack     maximum amount of thread stack ever used
+negcache-entries      shows the number of entries in the Negative answer cache
+no-packet-error       number of errorneous received packets
+noedns-outqueries     number of queries sent out without EDNS
+noerror-answers       counts the number of times it answered NOERROR since starting
+noping-outqueries     number of queries sent out without ENDS PING
+nsset-invalidations   number of times an nsset was dropped because it no longer worked
+nsspeeds-entries      shows the number of entries in the NS speeds map
+nxdomain-answers      counts the number of times it answered NXDOMAIN since starting
+outgoing-timeouts     counts the number of timeouts on outgoing UDP queries since starting
+over-capacity-drops   questions dropped because over maximum concurrent query limit (since 3.2)
+packetcache-bytes     size of the packet cache in bytes (since 3.3.1)
+packetcache-entries   size of packet cache (since 3.2)
+packetcache-hits      packet cache hits (since 3.2)
+packetcache-misses    packet cache misses (since 3.2)
+policy-drops          packets dropped because of (Lua) policy decision
+qa-latency            shows the current latency average
+questions             counts all end-user initiated queries with the RD bit set
+resource-limits       counts number of queries that could not be performed because of resource limits
+security-status       security status based on security polling
+server-parse-errors   counts number of server replied packets that could not be parsed
+servfail-answers      counts the number of times it answered SERVFAIL since starting
+spoof-prevents        number of times PowerDNS considered itself spoofed, and dropped the data
+sys-msec              number of CPU milliseconds spent in 'system' mode
+tcp-client-overflow   number of times an IP address was denied TCP access because it already had too many connections
+tcp-clients           counts the number of currently active TCP/IP clients
+tcp-outqueries        counts the number of outgoing TCP queries since starting
+tcp-questions         counts all incoming TCP queries (since starting)
+throttle-entries      shows the number of entries in the throttle map
+throttled-out         counts the number of throttled outgoing UDP queries since starting
+throttled-outqueries  idem to throttled-out
+unauthorized-tcp      number of TCP questions denied because of allow-from restrictions
+unauthorized-udp      number of UDP questions denied because of allow-from restrictions
+unexpected-packets    number of answers from remote servers that were unexpected (might point to spoofing)
+unreachables          number of times nameservers were unreachable since starting
+uptime                number of seconds process has been running (since 3.1.5)
+user-msec             number of CPU milliseconds spent in 'user' mode
 }}} */
 
 const char* const default_server_fields[] = /* {{{ */
@@ -157,8 +179,13 @@ statname_lookup_t lookup_table[] = /* {{{ */
   {"udp-answers-bytes",      "total_bytes",  "udp-answers-bytes"},
 
   /* Cache stuff */
+  {"cache-bytes",            "cache_size",   "cache-bytes"},
+  {"packetcache-bytes",      "cache_size",   "packet-bytes"},
+  {"packetcache-entries",    "cache_size",   "packet-entries"},
   {"packetcache-hit",        "cache_result", "packet-hit"},
+  {"packetcache-hits",       "cache_result", "packet-hit"},
   {"packetcache-miss",       "cache_result", "packet-miss"},
+  {"packetcache-misses",     "cache_result", "packet-miss"},
   {"packetcache-size",       "cache_size",   "packet"},
   {"key-cache-size",         "cache_size",   "key"},
   {"meta-cache-size",        "cache_size",   "meta"},
@@ -179,6 +206,7 @@ statname_lookup_t lookup_table[] = /* {{{ */
   {"corrupt-packets",        "ipt_packets",  "corrupt"},
   {"deferred-cache-inserts", "counter",      "cache-deferred_insert"},
   {"deferred-cache-lookup",  "counter",      "cache-deferred_lookup"},
+  {"dont-outqueries",        "dns_question", "dont-outqueries"},
   {"qsize-a",                "cache_size",   "answers"},
   {"qsize-q",                "cache_size",   "questions"},
   {"servfail-packets",       "ipt_packets",  "servfail"},
@@ -195,52 +223,67 @@ statname_lookup_t lookup_table[] = /* {{{ */
    * Recursor statistics *
    ***********************/
   /* Answers by return code */
-  {"noerror-answers",     "dns_rcode",    "NOERROR"},
-  {"nxdomain-answers",    "dns_rcode",    "NXDOMAIN"},
-  {"servfail-answers",    "dns_rcode",    "SERVFAIL"},
+  {"noerror-answers",      "dns_rcode",    "NOERROR"},
+  {"nxdomain-answers",     "dns_rcode",    "NXDOMAIN"},
+  {"servfail-answers",     "dns_rcode",    "SERVFAIL"},
 
   /* CPU utilization */
-  {"sys-msec",            "cpu",          "system"},
-  {"user-msec",           "cpu",          "user"},
+  {"sys-msec",             "cpu",          "system"},
+  {"user-msec",            "cpu",          "user"},
 
   /* Question-to-answer latency */
-  {"qa-latency",          "latency",      NULL},
+  {"qa-latency",           "latency",      NULL},
 
   /* Cache */
-  {"cache-entries",       "cache_size",   NULL},
-  {"cache-hits",          "cache_result", "hit"},
-  {"cache-misses",        "cache_result", "miss"},
+  {"cache-entries",        "cache_size",   NULL},
+  {"cache-hits",           "cache_result", "hit"},
+  {"cache-misses",         "cache_result", "miss"},
 
   /* Total number of questions.. */
-  {"questions",           "dns_qtype",    "total"},
+  {"questions",            "dns_qtype",    "total"},
 
   /* All the other stuff.. */
-  {"all-outqueries",      "dns_question", "outgoing"},
-  {"answers0-1",          "dns_answer",   "0_1"},
-  {"answers1-10",         "dns_answer",   "1_10"},
-  {"answers10-100",       "dns_answer",   "10_100"},
-  {"answers100-1000",     "dns_answer",   "100_1000"},
-  {"answers-slow",        "dns_answer",   "slow"},
-  {"chain-resends",       "dns_question", "chained"},
-  {"client-parse-errors", "counter",      "drops-client_parse_error"},
-  {"concurrent-queries",  "dns_question", "concurrent"},
-  {"dlg-only-drops",      "counter",      "drops-delegation_only"},
-  {"negcache-entries",    "cache_size",   "negative"},
-  {"nsspeeds-entries",    "gauge",        "entries-ns_speeds"},
-  {"nsset-invalidations", "counter",      "ns_set_invalidation"},
-  {"outgoing-timeouts",   "counter",      "drops-timeout_outgoing"},
-  {"resource-limits",     "counter",      "drops-resource_limit"},
-  {"server-parse-errors", "counter",      "drops-server_parse_error"},
-  {"spoof-prevents",      "counter",      "drops-spoofed"},
-  {"tcp-client-overflow", "counter",      "denied-client_overflow_tcp"},
-  {"tcp-outqueries",      "dns_question", "outgoing-tcp"},
-  {"tcp-questions",       "dns_question", "incoming-tcp"},
-  {"throttled-out",       "dns_question", "outgoing-throttled"},
-  {"throttle-entries",    "gauge",        "entries-throttle"},
-  {"unauthorized-tcp",    "counter",      "denied-unauthorized_tcp"},
-  {"unauthorized-udp",    "counter",      "denied-unauthorized_udp"},
-  {"unexpected-packets",  "dns_answer",   "unexpected"},
-  {"uptime",              "uptime",       NULL}
+  {"all-outqueries",       "dns_question", "outgoing"},
+  {"answers0-1",           "dns_answer",   "0_1"},
+  {"answers1-10",          "dns_answer",   "1_10"},
+  {"answers10-100",        "dns_answer",   "10_100"},
+  {"answers100-1000",      "dns_answer",   "100_1000"},
+  {"answers-slow",         "dns_answer",   "slow"},
+  {"case-mismatches",      "counter",      "case_mismatches"},
+  {"chain-resends",        "dns_question", "chained"},
+  {"client-parse-errors",  "counter",      "drops-client_parse_error"},
+  {"concurrent-queries",   "dns_question", "concurrent"},
+  {"dlg-only-drops",       "counter",      "drops-delegation_only"},
+  {"edns-ping-matches",    "counter",      "edns-ping_matches"},
+  {"edns-ping-mismatches", "counter",      "edns-ping_mismatches"},
+  {"failed-host-entries",  "counter",      "entries-failed_host"},
+  {"ipv6-outqueries",      "dns_question", "outgoing-ipv6"},
+  {"ipv6-questions",       "dns_question", "incoming-ipv6"},
+  {"malloc-bytes",         "gauge",        "malloc_bytes"},
+  {"max-mthread-stack",    "gauge",        "max_mthread_stack"},
+  {"no-packet-error",      "gauge",        "no_packet_error"},
+  {"noedns-outqueries",    "dns_question", "outgoing-noedns"},
+  {"noping-outqueries",    "dns_question", "outgoing-noping"},
+  {"over-capacity-drops",  "dns_question", "incoming-over_capacity"},
+  {"negcache-entries",     "cache_size",   "negative"},
+  {"nsspeeds-entries",     "gauge",        "entries-ns_speeds"},
+  {"nsset-invalidations",  "counter",      "ns_set_invalidation"},
+  {"outgoing-timeouts",    "counter",      "drops-timeout_outgoing"},
+  {"policy-drops",         "counter",      "drops-policy"},
+  {"resource-limits",      "counter",      "drops-resource_limit"},
+  {"server-parse-errors",  "counter",      "drops-server_parse_error"},
+  {"spoof-prevents",       "counter",      "drops-spoofed"},
+  {"tcp-client-overflow",  "counter",      "denied-client_overflow_tcp"},
+  {"tcp-clients",          "gauge",        "clients-tcp"},
+  {"tcp-outqueries",       "dns_question", "outgoing-tcp"},
+  {"tcp-questions",        "dns_question", "incoming-tcp"},
+  {"throttled-out",        "dns_question", "outgoing-throttled"},
+  {"throttle-entries",     "gauge",        "entries-throttle"},
+  {"throttled-outqueries", "dns_question", "outgoing-throttle"},
+  {"unauthorized-tcp",     "counter",      "denied-unauthorized_tcp"},
+  {"unauthorized-udp",     "counter",      "denied-unauthorized_udp"},
+  {"unexpected-packets",   "dns_answer",   "unexpected"},
+  {"uptime",               "uptime",       NULL}
 }; /* }}} */
 int lookup_table_length = STATIC_ARRAY_SIZE (lookup_table);
 
@@ -250,14 +293,12 @@ static llist_t *list = NULL;
 static char *local_sockpath = NULL;
 
 /* TODO: Do this before 4.4:
- * - Recursor:
- *   - Complete list of known pdns -> collectd mappings.
  * - Update the collectd.conf(5) manpage.
  *
  * -octo
  */
 
-/* <http://doc.powerdns.com/recursor-stats.html> */
+/* <https://doc.powerdns.com/md/recursor/stats/> */
 static void submit (const char *plugin_instance, /* {{{ */
     const char *pdns_type, const char *value)
 {
@@ -298,7 +339,7 @@ static void submit (const char *plugin_instance, /* {{{ */
 
   if (ds->ds_num != 1)
   {
-    ERROR ("powerdns plugin: type `%s' has %i data sources, "
+    ERROR ("powerdns plugin: type `%s' has %zu data sources, "
         "but I can only handle one.",
         type, ds->ds_num);
     return;
@@ -650,12 +691,12 @@ static int powerdns_update_recursor_command (list_item_t *li) /* {{{ */
       return (-1);
     }
     buffer[sizeof (buffer) - 1] = 0;
-    int i = strlen (buffer);
-    if (i < sizeof (buffer) - 2)
+    size_t len = strlen (buffer);
+    if (len < sizeof (buffer) - 2)
     {
-      buffer[i++] = ' ';
-      buffer[i++] = '\n';
-      buffer[i++] = '\0';
+      buffer[len++] = ' ';
+      buffer[len++] = '\n';
+      buffer[len++] = '\0';
     }
   }
 
index fde96f8..d094e73 100644 (file)
@@ -180,6 +180,9 @@ typedef struct procstat_entry_s
        derive_t io_syscr;
        derive_t io_syscw;
 
+       derive_t cswitch_vol;
+       derive_t cswitch_invol;
+
        struct procstat_entry_s *next;
 } procstat_entry_t;
 
@@ -211,12 +214,17 @@ typedef struct procstat
        derive_t io_syscr;
        derive_t io_syscw;
 
+       derive_t cswitch_vol;
+       derive_t cswitch_invol;
+
        struct procstat   *next;
        struct procstat_entry_s *instances;
 } procstat_t;
 
 static procstat_t *list_head_g = NULL;
 
+static _Bool report_ctx_switch = 0;
+
 #if HAVE_THREAD_INFO
 static mach_port_t port_host_self;
 static mach_port_t port_task_self;
@@ -398,6 +406,8 @@ static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t
                pse->io_wchar   = entry->io_wchar;
                pse->io_syscr   = entry->io_syscr;
                pse->io_syscw   = entry->io_syscw;
+               pse->cswitch_vol   = entry->cswitch_vol;
+               pse->cswitch_invol = entry->cswitch_invol;
 
                ps->num_proc   += pse->num_proc;
                ps->num_lwp    += pse->num_lwp;
@@ -412,6 +422,9 @@ static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t
                ps->io_syscr   += ((pse->io_syscr == -1)?0:pse->io_syscr);
                ps->io_syscw   += ((pse->io_syscw == -1)?0:pse->io_syscw);
 
+               ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
+               ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
+
                if ((entry->vmem_minflt_counter == 0)
                                && (entry->vmem_majflt_counter == 0))
                {
@@ -508,6 +521,8 @@ static void ps_list_reset (void)
                ps->io_wchar = -1;
                ps->io_syscr = -1;
                ps->io_syscw = -1;
+               ps->cswitch_vol   = -1;
+               ps->cswitch_invol = -1;
 
                pse_prev = NULL;
                pse = ps->instances;
@@ -592,6 +607,10 @@ static int ps_config (oconfig_item_t *ci)
                        ps_list_register (c->values[0].value.string,
                                        c->values[1].value.string);
                }
+               else if (strcasecmp (c->key, "CollectContextSwitch") == 0)
+               {
+                       cf_util_get_boolean (c, &report_ctx_switch);
+               }
                else
                {
                        ERROR ("processes plugin: The `%s' configuration option is not "
@@ -741,19 +760,36 @@ static void ps_submit_proc_list (procstat_t *ps)
                plugin_dispatch_values (&vl);
        }
 
+       if ( report_ctx_switch )
+       {
+               sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
+               sstrncpy (vl.type_instance, "voluntary", sizeof (vl.type_instance));
+               vl.values[0].derive = ps->cswitch_vol;
+               vl.values_len = 1;
+               plugin_dispatch_values (&vl);
+
+               sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
+               sstrncpy (vl.type_instance, "involuntary", sizeof (vl.type_instance));
+               vl.values[0].derive = ps->cswitch_invol;
+               vl.values_len = 1;
+               plugin_dispatch_values (&vl);
+       }
+
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
                        "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
                        "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
                        "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
                        "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; "
-                       "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";",
+                       "io_syscr = %"PRIi64"; io_syscw = %"PRIi64"; "
+                       "cswitch_vol = %"PRIi64"; cswitch_invol = %"PRIi64";",
                        ps->name, ps->num_proc, ps->num_lwp,
                        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->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw,
+                       ps->cswitch_vol, ps->cswitch_invol);
 } /* void ps_submit_proc_list */
 
 #if KERNEL_LINUX || KERNEL_SOLARIS
@@ -778,42 +814,99 @@ static void ps_submit_fork_rate (derive_t value)
 
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
-static int ps_read_tasks (int pid)
+static procstat_t *ps_read_tasks_status (int pid, procstat_t *ps)
 {
        char           dirname[64];
        DIR           *dh;
+       char           filename[64];
+       FILE          *fh;
        struct dirent *ent;
-       int count = 0;
+       derive_t cswitch_vol = 0;
+       derive_t cswitch_invol = 0;
+       char buffer[1024];
+       char *fields[8];
+       int numfields;
 
        ssnprintf (dirname, sizeof (dirname), "/proc/%i/task", pid);
 
        if ((dh = opendir (dirname)) == NULL)
        {
                DEBUG ("Failed to open directory `%s'", dirname);
-               return (-1);
+               return (NULL);
        }
 
        while ((ent = readdir (dh)) != NULL)
        {
+               char *tpid;
+
                if (!isdigit ((int) ent->d_name[0]))
                        continue;
-               else
-                       count++;
+
+               tpid = ent->d_name;
+
+               ssnprintf (filename, sizeof (filename), "/proc/%i/task/%s/status", pid, tpid);
+               if ((fh = fopen (filename, "r")) == NULL)
+               {
+                       DEBUG ("Failed to open file `%s'", filename);
+                       continue;
+               }
+
+               while (fgets (buffer, sizeof(buffer), fh) != NULL)
+               {
+                       derive_t tmp;
+                       char *endptr;
+
+                       if (strncmp (buffer, "voluntary_ctxt_switches", 23) != 0
+                               && strncmp (buffer, "nonvoluntary_ctxt_switches", 26) != 0)
+                               continue;
+
+                       numfields = strsplit (buffer, fields,
+                               STATIC_ARRAY_SIZE (fields));
+
+                       if (numfields < 2)
+                               continue;
+
+                       errno = 0;
+                       endptr = NULL;
+                       tmp = (derive_t) strtoll (fields[1], &endptr, /* base = */ 10);
+                       if ((errno == 0) && (endptr != fields[1]))
+                       {
+                               if (strncmp (buffer, "voluntary_ctxt_switches", 23) == 0)
+                               {
+                                       cswitch_vol += tmp;
+                               }
+                               else if (strncmp (buffer, "nonvoluntary_ctxt_switches", 26) == 0)
+                               {
+                                       cswitch_invol += tmp;
+                               }
+                       }
+               } /* while (fgets) */
+
+               if (fclose (fh))
+               {
+                       char errbuf[1024];
+                               WARNING ("processes: fclose: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               }
        }
        closedir (dh);
 
-       return ((count >= 1) ? count : 1);
-} /* int *ps_read_tasks */
+       ps->cswitch_vol = cswitch_vol;
+       ps->cswitch_invol = cswitch_invol;
+
+       return (ps);
+} /* int *ps_read_tasks_status */
 
-/* Read advanced virtual memory data from /proc/pid/status */
-static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
+/* Read data from /proc/pid/status */
+static procstat_t *ps_read_status (int pid, procstat_t *ps)
 {
        FILE *fh;
        char buffer[1024];
        char filename[64];
-       unsigned long long lib = 0;
-       unsigned long long exe = 0;
-       unsigned long long data = 0;
+       unsigned long lib = 0;
+       unsigned long exe = 0;
+       unsigned long data = 0;
+       unsigned long threads = 0;
        char *fields[8];
        int numfields;
 
@@ -823,10 +916,11 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
 
        while (fgets (buffer, sizeof(buffer), fh) != NULL)
        {
-               long long tmp;
+               unsigned long tmp;
                char *endptr;
 
-               if (strncmp (buffer, "Vm", 2) != 0)
+               if (strncmp (buffer, "Vm", 2) != 0
+                               && strncmp (buffer, "Threads", 7) != 0)
                        continue;
 
                numfields = strsplit (buffer, fields,
@@ -837,7 +931,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
 
                errno = 0;
                endptr = NULL;
-               tmp = strtoll (fields[1], &endptr, /* base = */ 10);
+               tmp = strtoul (fields[1], &endptr, /* base = */ 10);
                if ((errno == 0) && (endptr != fields[1]))
                {
                        if (strncmp (buffer, "VmData", 6) == 0)
@@ -852,6 +946,10 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
                        {
                                exe = tmp;
                        }
+                       else if  (strncmp(buffer, "Threads", 7) == 0)
+                       {
+                               threads = tmp;
+                       }
                }
        } /* while (fgets) */
 
@@ -864,6 +962,8 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
 
        ps->vmem_data = data * 1024;
        ps->vmem_code = (exe + lib) * 1024;
+       if (threads != 0)
+               ps->num_lwp = threads;
 
        return (ps);
 } /* procstat_t *ps_read_vmem */
@@ -931,9 +1031,9 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        char *fields[64];
        char  fields_len;
 
-       int   buffer_len;
+       size_t buffer_len;
 
-       char *buffer_ptr;
+       char  *buffer_ptr;
        size_t name_start_pos;
        size_t name_end_pos;
        size_t name_len;
@@ -944,14 +1044,16 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        long long unsigned vmem_rss;
        long long unsigned stack_size;
 
+       ssize_t status;
+
        memset (ps, 0, sizeof (procstat_t));
 
        ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
 
-       buffer_len = read_file_contents (filename,
-                       buffer, sizeof(buffer) - 1);
-       if (buffer_len <= 0)
+       status = read_file_contents (filename, buffer, sizeof(buffer) - 1);
+       if (status <= 0)
                return (-1);
+       buffer_len = (size_t) status;
        buffer[buffer_len] = 0;
 
        /* The name of the process is enclosed in parens. Since the name can
@@ -1006,11 +1108,16 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        }
        else
        {
-               if ( (ps->num_lwp = ps_read_tasks (pid)) == -1 )
+               ps->num_lwp = strtoul (fields[17], /* endptr = */ NULL, /* base = */ 10);
+               if ((ps_read_status(pid, ps)) == NULL)
                {
-                       /* returns -1 => kernel 2.4 */
-                       ps->num_lwp = 1;
+                       /* No VMem data */
+                       ps->vmem_data = -1;
+                       ps->vmem_code = -1;
+                       DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
                }
+               if (ps->num_lwp <= 0)
+                       ps->num_lwp = 1;
                ps->num_proc = 1;
        }
 
@@ -1043,14 +1150,6 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
        cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
        vmem_rss = vmem_rss * pagesize_g;
 
-       if ( (ps_read_vmem(pid, ps)) == NULL)
-       {
-               /* No VMem data */
-               ps->vmem_data = -1;
-               ps->vmem_code = -1;
-               DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
-       }
-
        ps->cpu_user_counter = cpu_user_counter;
        ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
@@ -1068,6 +1167,18 @@ int ps_read_process (int pid, procstat_t *ps, char *state)
                DEBUG("ps_read_process: not get io data for pid %i",pid);
        }
 
+       if ( report_ctx_switch )
+       {
+               if ( (ps_read_tasks_status(pid, ps)) == NULL)
+               {
+                       ps->cswitch_vol = -1;
+                       ps->cswitch_invol = -1;
+
+                       DEBUG("ps_read_tasks_status: not get context "
+                                       "switch data for pid %i",pid);
+               }
+       }
+
        /* success */
        return (0);
 } /* int ps_read_process (...) */
@@ -1219,16 +1330,16 @@ static const char *ps_get_cmdline (long pid, /* {{{ */
 {
        char path[PATH_MAX];
        psinfo_t info;
-       int status;
+       ssize_t status;
 
        snprintf(path, sizeof (path), "/proc/%li/psinfo", pid);
 
        status = read_file_contents (path, (void *) &info, sizeof (info));
-       if (status != sizeof (info))
+       if ((status < 0) || (((size_t) status) != sizeof (info)))
        {
                ERROR ("processes plugin: Unexpected return value "
                                "while reading \"%s\": "
-                               "Returned %i but expected %zu.",
+                               "Returned %zd but expected %zu.",
                                path, status, buffer_size);
                return (NULL);
        }
@@ -1767,6 +1878,9 @@ static int ps_read (void)
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
 
+               pse.cswitch_vol = ps.cswitch_vol;
+               pse.cswitch_invol = ps.cswitch_invol;
+
                switch (state)
                {
                        case 'R': running++;  break;
@@ -1913,18 +2027,18 @@ static int ps_read (void)
                        pse.io_syscw = -1;
 
                        ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse);
-               } /* if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid)) */
 
-               switch (procs[i].ki_stat)
-               {
-                       case SSTOP:     stopped++;      break;
-                       case SSLEEP:    sleeping++;     break;
-                       case SRUN:      running++;      break;
-                       case SIDL:      idle++;         break;
-                       case SWAIT:     wait++;         break;
-                       case SLOCK:     blocked++;      break;
-                       case SZOMB:     zombies++;      break;
-               }
+                       switch (procs[i].ki_stat)
+                       {
+                               case SSTOP:     stopped++;      break;
+                               case SSLEEP:    sleeping++;     break;
+                               case SRUN:      running++;      break;
+                               case SIDL:      idle++;         break;
+                               case SWAIT:     wait++;         break;
+                               case SLOCK:     blocked++;      break;
+                               case SZOMB:     zombies++;      break;
+                       }
+               } /* if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid)) */
        }
 
        kvm_close(kd);
@@ -2049,18 +2163,18 @@ static int ps_read (void)
                        pse.cswitch_invol = -1;
 
                        ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
-               } /* if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid)) */
 
-               switch (procs[i].p_stat)
-               {
-                       case SSTOP:     stopped++;      break;
-                       case SSLEEP:    sleeping++;     break;
-                       case SRUN:      running++;      break;
-                       case SIDL:      idle++;         break;
-                       case SONPROC:   onproc++;       break;
-                       case SDEAD:     dead++;         break;
-                       case SZOMB:     zombies++;      break;
-               }
+                       switch (procs[i].p_stat)
+                       {
+                               case SSTOP:     stopped++;      break;
+                               case SSLEEP:    sleeping++;     break;
+                               case SRUN:      running++;      break;
+                               case SIDL:      idle++;         break;
+                               case SONPROC:   onproc++;       break;
+                               case SDEAD:     dead++;         break;
+                               case SZOMB:     zombies++;      break;
+                       }
+               } /* if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid)) */
        }
 
        kvm_close(kd);
index 8b378a2..210d785 100644 (file)
@@ -302,7 +302,7 @@ void cpy_log_exception(const char *context) {
                Py_XDECREF(traceback);
                return;
        }
-       list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. */
+       list = PyObject_CallFunction(cpy_format_exception, "NNN", type, value, traceback); /* New reference. Steals references from "type", "value" and "traceback". */
        if (list)
                l = PyObject_Length(list);
        for (i = 0; i < l; ++i) {
@@ -322,9 +322,6 @@ void cpy_log_exception(const char *context) {
        }
        Py_XDECREF(list);
        PyErr_Clear();
-       Py_DECREF(type);
-       Py_XDECREF(value);
-       Py_XDECREF(traceback);
 }
 
 static int cpy_read_callback(user_data_t *data) {
@@ -345,7 +342,7 @@ static int cpy_read_callback(user_data_t *data) {
 }
 
 static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
-       int i;
+       size_t i;
        cpy_callback_t *c = data->data;
        PyObject *ret, *list, *temp, *dict = NULL;
        Values *v;
@@ -358,22 +355,13 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
                }
                for (i = 0; i < value_list->values_len; ++i) {
                        if (ds->ds[i].type == DS_TYPE_COUNTER) {
-                               if ((long) value_list->values[i].counter == value_list->values[i].counter)
-                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
-                               else
-                                       PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
+                               PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
                        } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
                                PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
                        } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
-                               if ((long) value_list->values[i].derive == value_list->values[i].derive)
-                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
-                               else
-                                       PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
+                               PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
                        } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
-                               if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
-                                       PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
-                               else
-                                       PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
+                               PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
                        } else {
                                Py_BEGIN_ALLOW_THREADS
                                ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
@@ -569,7 +557,7 @@ static PyObject *float_or_none(float number) {
 }
 
 static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
-       int i;
+       size_t i;
        char *name;
        const data_set_t *ds;
        PyObject *list, *tuple;
@@ -656,7 +644,6 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
        double interval = 0;
        char *name = NULL;
        PyObject *callback = NULL, *data = NULL;
-       struct timespec ts;
        static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
        
        if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
@@ -678,10 +665,8 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
        user_data = malloc(sizeof(*user_data));
        user_data->free_func = cpy_destroy_user_data;
        user_data->data = c;
-       ts.tv_sec = interval;
-       ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
        plugin_register_complex_read(/* group = */ NULL, buf,
-                       cpy_read_callback, &ts, user_data);
+                       cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), user_data);
        return cpy_string_to_unicode_or_bytes(buf);
 }
 
index 78e6cf9..4417601 100644 (file)
@@ -502,9 +502,9 @@ static meta_data_t *cpy_build_meta(PyObject *meta) {
 }
 
 static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
-       int i, ret;
+       int ret;
        const data_set_t *ds;
-       int size;
+       size_t size, i;
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
        PyObject *values = self->values, *meta = self->meta;
@@ -542,15 +542,15 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
                PyErr_Format(PyExc_TypeError, "meta must be a dict");
                return NULL;
        }
-       size = (int) PySequence_Length(values);
+       size = (size_t) PySequence_Length(values);
        if (size != ds->ds_num) {
-               PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
+               PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size);
                return NULL;
        }
-       value = malloc(size * sizeof(*value));
+       value = calloc(size, sizeof(*value));
        for (i = 0; i < size; ++i) {
                PyObject *item, *num;
-               item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
+               item = PySequence_Fast_GET_ITEM(values, (int) i); /* Borrowed reference. */
                if (ds->ds->type == DS_TYPE_COUNTER) {
                        num = PyNumber_Long(item); /* New reference. */
                        if (num != NULL) {
@@ -611,9 +611,9 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
 }
 
 static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
-       int i, ret;
+       int ret;
        const data_set_t *ds;
-       int size;
+       size_t size, i;
        value_t *value;
        value_list_t value_list = VALUE_LIST_INIT;
        PyObject *values = self->values, *meta = self->meta;
@@ -646,12 +646,12 @@ static PyObject *Values_write(Values *self, PyObject *args, PyObject *kwds) {
                PyErr_Format(PyExc_TypeError, "values must be list or tuple");
                return NULL;
        }
-       size = (int) PySequence_Length(values);
+       size = (size_t) PySequence_Length(values);
        if (size != ds->ds_num) {
-               PyErr_Format(PyExc_RuntimeError, "type %s needs %d values, got %i", value_list.type, ds->ds_num, size);
+               PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu", value_list.type, ds->ds_num, size);
                return NULL;
        }
-       value = malloc(size * sizeof(*value));
+       value = calloc(size, sizeof(*value));
        for (i = 0; i < size; ++i) {
                PyObject *item, *num;
                item = PySequence_Fast_GET_ITEM(values, i); /* Borrowed reference. */
index 4863d7c..667c2fa 100644 (file)
@@ -414,7 +414,7 @@ static int cr_config_router (oconfig_item_t *ci) /* {{{ */
   user_data.free_func = (void *) cr_free_data;
   if (status == 0)
     status = plugin_register_complex_read (/* group = */ NULL, read_name,
-       cr_read, /* interval = */ NULL, &user_data);
+       cr_read, /* interval = */ 0, &user_data);
 
   if (status != 0)
     cr_free_data (router_data);
index 645032c..5d98de8 100644 (file)
@@ -69,7 +69,7 @@ static int value_list_to_string (char *buffer, int buffer_len,
 {
   int offset;
   int status;
-  int i;
+  size_t i;
   time_t t;
 
   assert (0 == strcmp (ds->type, vl->type));
index 8497a24..764d6d6 100644 (file)
@@ -204,7 +204,7 @@ static int value_list_to_string_multiple (char *buffer, int buffer_len,
        int offset;
        int status;
        time_t tt;
-       int i;
+       size_t i;
 
        memset (buffer, '\0', buffer_len);
 
index 4300822..0878d3c 100644 (file)
@@ -54,13 +54,6 @@ static int serial_read (void)
        FILE *fh;
        char buffer[1024];
 
-       derive_t rx = 0;
-       derive_t tx = 0;
-       
-       char *fields[16];
-       int i, numfields;
-       int len;
-
        /* there are a variety of names for the serial device */
        if ((fh = fopen ("/proc/tty/driver/serial", "r")) == NULL &&
                (fh = fopen ("/proc/tty/driver/ttyS", "r")) == NULL)
@@ -73,10 +66,16 @@ static int serial_read (void)
 
        while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
-               int have_rx = 0, have_tx = 0;
+               derive_t rx = 0;
+               derive_t tx = 0;
+               _Bool have_rx = 0, have_tx = 0;
+               size_t len;
 
-               numfields = strsplit (buffer, fields, 16);
+               char *fields[16];
+               int numfields;
+               int i;
 
+               numfields = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
                if (numfields < 6)
                        continue;
 
@@ -84,12 +83,12 @@ static int serial_read (void)
                 * 0: uart:16550A port:000003F8 irq:4 tx:0 rx:0
                 * 1: uart:16550A port:000002F8 irq:3 tx:0 rx:0
                 */
-               len = strlen (fields[0]) - 1;
-               if (len < 1)
+               len = strlen (fields[0]);
+               if (len < 2)
                        continue;
-               if (fields[0][len] != ':')
+               if (fields[0][len - 1] != ':')
                        continue;
-               fields[0][len] = '\0';
+               fields[0][len - 1] = 0;
 
                for (i = 1; i < numfields; i++)
                {
@@ -99,20 +98,18 @@ static int serial_read (void)
 
                        if (strncmp (fields[i], "tx:", 3) == 0)
                        {
-                               tx = atoll (fields[i] + 3);
-                               have_tx++;
+                               if (strtoderive (fields[i] + 3, &tx) == 0)
+                                       have_tx = 1;
                        }
                        else if (strncmp (fields[i], "rx:", 3) == 0)
                        {
-                               rx = atoll (fields[i] + 3);
-                               have_rx++;
+                               if (strtoderive (fields[i] + 3, &rx) == 0)
+                                       have_rx = 1;
                        }
                }
 
-               if ((have_rx == 0) || (have_tx == 0))
-                       continue;
-
-               serial_submit (fields[0], rx, tx);
+               if (have_rx && have_tx)
+                       serial_submit (fields[0], rx, tx);
        }
 
        fclose (fh);
index cb0b70f..6a03a19 100644 (file)
@@ -61,7 +61,7 @@ struct data_definition_s
   instance_t instance;
   char *instance_prefix;
   oid_t *values;
-  int values_len;
+  size_t values_len;
   double scale;
   double shift;
   struct data_definition_s *next;
@@ -313,7 +313,7 @@ static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *
   dd->values = (oid_t *) malloc (sizeof (oid_t) * ci->values_num);
   if (dd->values == NULL)
     return (-1);
-  dd->values_len = ci->values_num;
+  dd->values_len = (size_t) ci->values_num;
 
   for (i = 0; i < ci->values_num; i++)
   {
@@ -459,7 +459,7 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
     return (-1);
   }
 
-  DEBUG ("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = %i }",
+  DEBUG ("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = %zu }",
       dd->name, dd->type, (dd->is_table != 0) ? "true" : "false", dd->values_len);
 
   if (data_head == NULL)
@@ -645,7 +645,6 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   /* Registration stuff. */
   char cb_name[DATA_MAX_NAME_LEN];
   user_data_t cb_data;
-  struct timespec cb_interval;
 
   hd = (host_definition_t *) malloc (sizeof (host_definition_t));
   if (hd == NULL)
@@ -778,11 +777,8 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   cb_data.data = hd;
   cb_data.free_func = csnmp_host_definition_destroy;
 
-  CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
-
   status = plugin_register_complex_read (/* group = */ NULL, cb_name,
-      csnmp_read_host, /* interval = */ &cb_interval,
-      /* user_data = */ &cb_data);
+      csnmp_read_host, hd->interval, /* user_data = */ &cb_data);
   if (status != 0)
   {
     ERROR ("snmp plugin: Registering complex read function failed.");
@@ -928,8 +924,7 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
     tmp_unsigned = (uint32_t) *vl->val.integer;
     tmp_signed = (int32_t) *vl->val.integer;
 
-    if ((vl->type == ASN_INTEGER)
-        || (vl->type == ASN_GAUGE))
+    if (vl->type == ASN_INTEGER)
       prefer_signed = 1;
 
     DEBUG ("snmp plugin: Parsed int32 value is %"PRIu64".", tmp_unsigned);
@@ -1053,6 +1048,10 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
   return (ret);
 } /* value_t csnmp_value_list_to_value */
 
+/* csnmp_strvbcopy_hexstring converts the bit string contained in "vb" to a hex
+ * representation and writes it to dst. Returns zero on success and ENOMEM if
+ * dst is not large enough to hold the string. dst is guaranteed to be
+ * nul-terminated. */
 static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */
     const struct variable_list *vb, size_t dst_size)
 {
@@ -1060,6 +1059,8 @@ static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */
   size_t buffer_free;
   size_t i;
 
+  dst[0] = 0;
+
   buffer_ptr = dst;
   buffer_free = dst_size;
 
@@ -1069,23 +1070,28 @@ static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */
 
     status = snprintf (buffer_ptr, buffer_free,
         (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
+    assert (status >= 0);
 
-    if (status >= buffer_free)
+    if (((size_t) status) >= buffer_free) /* truncated */
     {
-      buffer_ptr += (buffer_free - 1);
-      *buffer_ptr = 0;
-      return (dst_size + (buffer_free - status));
+      dst[dst_size - 1] = 0;
+      return ENOMEM;
     }
     else /* if (status < buffer_free) */
     {
-      buffer_ptr += status;
-      buffer_free -= status;
+      buffer_ptr  += (size_t) status;
+      buffer_free -= (size_t) status;
     }
   }
 
-  return ((int) (dst_size - buffer_free));
+  return 0;
 } /* }}} int csnmp_strvbcopy_hexstring */
 
+/* csnmp_strvbcopy copies the octet string or bit string contained in vb to
+ * dst. If non-printable characters are detected, it will switch to a hex
+ * representation of the string. Returns zero on success, EINVAL if vb does not
+ * contain a string and ENOMEM if dst is not large enough to contain the
+ * string. */
 static int csnmp_strvbcopy (char *dst, /* {{{ */
     const struct variable_list *vb, size_t dst_size)
 {
@@ -1115,8 +1121,12 @@ static int csnmp_strvbcopy (char *dst, /* {{{ */
     dst[i] = src[i];
   }
   dst[num_chars] = 0;
+  dst[dst_size - 1] = 0;
 
-  return ((int) vb->val_len);
+  if (dst_size <= vb->val_len)
+    return ENOMEM;
+
+  return 0;
 } /* }}} int csnmp_strvbcopy */
 
 static int csnmp_instance_list_add (csnmp_list_instances_t **head,
@@ -1224,7 +1234,7 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
   csnmp_list_instances_t *instance_list_ptr;
   csnmp_table_values_t **value_table_ptr;
 
-  int i;
+  size_t i;
   _Bool have_more;
   oid_t current_suffix;
 
@@ -1239,7 +1249,7 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 
   instance_list_ptr = instance_list;
 
-  value_table_ptr = calloc ((size_t) data->values_len, sizeof (*value_table_ptr));
+  value_table_ptr = calloc (data->values_len, sizeof (*value_table_ptr));
   if (value_table_ptr == NULL)
     return (-1);
   for (i = 0; i < data->values_len; i++)
@@ -1382,7 +1392,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
 
   const data_set_t *ds;
 
-  uint32_t oid_list_len = (uint32_t) (data->values_len + 1);
+  size_t oid_list_len = data->values_len + 1;
   /* Holds the last OID returned by the device. We use this in the GETNEXT
    * request to proceed. */
   oid_t oid_list[oid_list_len];
@@ -1391,8 +1401,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   _Bool oid_list_todo[oid_list_len];
 
   int status;
-  int i;
-  uint32_t j;
+  size_t i;
 
   /* `value_list_head' and `value_list_tail' implement a linked list for each
    * value. `instance_list_head' and `instance_list_tail' implement a linked list of
@@ -1420,7 +1429,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
 
   if (ds->ds_num != data->values_len)
   {
-    ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+    ERROR ("snmp plugin: DataSet `%s' requires %zu values, but config talks about %zu",
         data->type, ds->ds_num, data->values_len);
     return (-1);
   }
@@ -1433,8 +1442,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   else /* no InstanceFrom option specified. */
     oid_list_len--;
 
-  for (j = 0; j < oid_list_len; j++)
-    oid_list_todo[j] = 1;
+  for (i = 0; i < oid_list_len; i++)
+    oid_list_todo[i] = 1;
 
   /* We're going to construct n linked lists, one for each "value".
    * value_list_head will contain pointers to the heads of these linked lists,
@@ -1466,13 +1475,13 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     }
 
     oid_list_todo_num = 0;
-    for (j = 0; j < oid_list_len; j++)
+    for (i = 0; i < oid_list_len; i++)
     {
       /* Do not rerequest already finished OIDs */
-      if (!oid_list_todo[j])
+      if (!oid_list_todo[i])
         continue;
       oid_list_todo_num++;
-      snmp_add_null_var (req, oid_list[j].oid, oid_list[j].oid_len);
+      snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
     }
 
     if (oid_list_todo_num == 0)
@@ -1568,7 +1577,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
         ret = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
         if (ret != 0)
         {
-          DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+          DEBUG ("snmp plugin: host = %s; data = %s; i = %zu; "
               "Value probably left its subtree.",
               host->name, data->name, i);
           oid_list_todo[i] = 0;
@@ -1580,7 +1589,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
         if ((value_list_tail[i] != NULL)
             && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0))
         {
-          DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+          DEBUG ("snmp plugin: host = %s; data = %s; i = %zu; "
               "Suffix is not increasing.",
               host->name, data->name, i);
           oid_list_todo[i] = 0;
@@ -1664,7 +1673,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
   value_list_t vl = VALUE_LIST_INIT;
 
   int status;
-  int i;
+  size_t i;
 
   DEBUG ("snmp plugin: csnmp_read_value (host = %s, data = %s)",
       host->name, data->name);
@@ -1684,7 +1693,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 
   if (ds->ds_num != data->values_len)
   {
-    ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
+    ERROR ("snmp plugin: DataSet `%s' requires %zu values, but config talks about %zu",
         data->type, ds->ds_num, data->values_len);
     return (-1);
   }
index 5b0bdd6..3ec1d9e 100644 (file)
@@ -35,7 +35,6 @@
 #include <pthread.h>
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <netdb.h>
 #include <poll.h>
 
@@ -851,8 +850,19 @@ static int statsd_metric_submit_unsafe (char const *name, /* {{{ */
     else
       values[0].gauge = (gauge_t) c_avl_size (metric->set);
   }
-  else
-    values[0].derive = (derive_t) metric->value;
+  else { /* STATSD_COUNTER */
+      /*
+       * Expand a single value to two metrics:
+       *
+       * - The absolute counter, as a gauge
+       * - A derived rate for this counter
+       */
+      values[0].derive = (derive_t) metric->value;
+      plugin_dispatch_values(&vl);
+
+      sstrncpy(vl.type, "gauge", sizeof (vl.type));
+      values[0].gauge = (gauge_t) metric->value;
+  }
 
   return (plugin_dispatch_values (&vl));
 } /* }}} int statsd_metric_submit_unsafe */
index beded1a..b0bc95f 100644 (file)
  */
 
 typedef struct {
-       char  *type;
-       char  *instance_prefix;
-       int   *instances;
-       size_t instances_num;
-       int   *values;
-       size_t values_num;
+       char   *type;
+       char   *instance_prefix;
+       size_t *instances;
+       size_t  instances_num;
+       size_t *values;
+       size_t  values_num;
 
        const data_set_t *ds;
 } tbl_result_t;
@@ -139,11 +139,11 @@ static int tbl_config_set_s (char *name, char **var, oconfig_item_t *ci)
        return 0;
 } /* tbl_config_set_separator */
 
-static int tbl_config_append_array_i (char *name, int **var, size_t *len,
+static int tbl_config_append_array_i (char *name, size_t **var, size_t *len,
                oconfig_item_t *ci)
 {
-       int *tmp;
-
+       size_t *tmp;
+       size_t num;
        size_t i;
 
        if (1 > ci->values_num) {
@@ -151,26 +151,28 @@ static int tbl_config_append_array_i (char *name, int **var, size_t *len,
                return 1;
        }
 
-       for (i = 0; i < ci->values_num; ++i) {
+       num = (size_t) ci->values_num;
+       for (i = 0; i < num; ++i) {
                if (OCONFIG_TYPE_NUMBER != ci->values[i].type) {
                        log_err ("\"%s\" expects numerical arguments only.", name);
                        return 1;
                }
        }
 
-       *len += ci->values_num;
-       tmp = (int *)realloc (*var, *len * sizeof (**var));
+       tmp = realloc (*var, ((*len) + num) * sizeof (**var));
        if (NULL == tmp) {
                char errbuf[1024];
                log_err ("realloc failed: %s.",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                return -1;
        }
-
        *var = tmp;
 
-       for (i = *len - ci->values_num; i < *len; ++i)
-               (*var)[i] = (int)ci->values[i].value.number;
+       for (i = 0; i < num; ++i) {
+               (*var)[*len] = (size_t) ci->values[i].value.number;
+               (*len)++;
+       }
+
        return 0;
 } /* tbl_config_append_array_s */
 
@@ -179,7 +181,7 @@ static int tbl_config_result (tbl_t *tbl, oconfig_item_t *ci)
        tbl_result_t *res;
 
        int status = 0;
-       size_t i;
+       int i;
 
        if (0 != ci->values_num) {
                log_err ("<Result> does not expect any arguments.");
@@ -266,7 +268,7 @@ static int tbl_config_table (oconfig_item_t *ci)
        tbl = tables + tables_num - 1;
        tbl_setup (tbl, ci->values[0].value.string);
 
-       for (i = 0; i < ci->children_num; ++i) {
+       for (i = 0; i < ((size_t) ci->children_num); ++i) {
                oconfig_item_t *c = ci->children + i;
 
                if (0 == strcasecmp (c->key, "Separator"))
@@ -321,7 +323,7 @@ static int tbl_config_table (oconfig_item_t *ci)
 
 static int tbl_config (oconfig_item_t *ci)
 {
-       size_t i;
+       int i;
 
        for (i = 0; i < ci->children_num; ++i) {
                oconfig_item_t *c = ci->children + i;
@@ -352,9 +354,9 @@ static int tbl_prepare (tbl_t *tbl)
                        return -1;
                }
 
-               if (res->values_num != (size_t)res->ds->ds_num) {
+               if (res->values_num != res->ds->ds_num) {
                        log_err ("Invalid type \"%s\". Expected %zu data source%s, "
-                                       "got %i.", res->type, res->values_num,
+                                       "got %zu.", res->type, res->values_num,
                                        (1 == res->values_num) ? "" : "s",
                                        res->ds->ds_num);
                        return -1;
index 3904f1b..751243b 100644 (file)
@@ -330,7 +330,6 @@ static int ctail_read (user_data_t *ud)
 
 static int ctail_init (void)
 {
-  struct timespec cb_interval;
   char str[255];
   user_data_t ud;
   size_t i;
@@ -347,8 +346,7 @@ static int ctail_init (void)
   {
     ud.data = (void *)tail_match_list[i];
     ssnprintf(str, sizeof(str), "tail-%zu", i);
-    CDTIME_T_TO_TIMESPEC (tail_match_list_intervals[i], &cb_interval);
-    plugin_register_complex_read (NULL, str, ctail_read, &cb_interval, &ud);
+    plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i], &ud);
   }
 
   return (0);
index c3efcc9..bb9b58a 100644 (file)
 #include <string.h>
 
 struct metric_definition_s {
-    char *name;
-    char *type;
-    char *instance;
-    int data_source_type;
-    int value_from;
+    char   *name;
+    char   *type;
+    char   *instance;
+    int     data_source_type;
+    ssize_t value_from;
     struct metric_definition_s *next;
 };
 typedef struct metric_definition_s metric_definition_t;
 
 struct instance_definition_s {
-    char *instance;
-    char *path;
-    cu_tail_t *tail;
+    char                 *instance;
+    char                 *path;
+    cu_tail_t            *tail;
     metric_definition_t **metric_list;
-    size_t metric_list_len;
-    cdtime_t interval;
-    int time_from;
+    size_t                metric_list_len;
+    cdtime_t              interval;
+    ssize_t               time_from;
     struct instance_definition_s *next;
 };
 typedef struct instance_definition_s instance_definition_t;
@@ -100,37 +100,37 @@ static int tcsv_read_metric (instance_definition_t *id,
         char **fields, size_t fields_num)
 {
     value_t v;
-    cdtime_t t;
+    cdtime_t t = 0;
     int status;
 
     if (md->data_source_type == -1)
         return (EINVAL);
 
-    if (md->value_from >= fields_num)
+    assert (md->value_from >= 0);
+    if (((size_t) md->value_from) >= fields_num)
         return (EINVAL);
 
-    if (id->time_from >= 0 && (id->time_from >= fields_num))
-        return (EINVAL);
-
-    t = 0;
-    if (id->time_from >= 0)
-        t = parse_time (fields[id->time_from]);
-
     status = parse_value (fields[md->value_from], &v, md->data_source_type);
     if (status != 0)
         return (status);
 
+    if (id->time_from >= 0) {
+        if (((size_t) id->time_from) >= fields_num)
+            return (EINVAL);
+        t = parse_time (fields[id->time_from]);
+    }
+
     return (tcsv_submit (id, md, v, t));
 }
 
-static _Bool tcsv_check_index (int index, size_t fields_num, char const *name)
+static _Bool tcsv_check_index (ssize_t index, size_t fields_num, char const *name)
 {
     if (index < 0)
         return 1;
     else if (((size_t) index) < fields_num)
         return 1;
 
-    ERROR ("tail_csv plugin: Metric \"%s\": Request for index %i when "
+    ERROR ("tail_csv plugin: Metric \"%s\": Request for index %zd when "
             "only %zu fields are available.",
             name, index, fields_num);
     return (0);
@@ -267,30 +267,27 @@ static void tcsv_metric_definition_destroy(void *arg){
     tcsv_metric_definition_destroy (next);
 }
 
-static int tcsv_config_get_index(oconfig_item_t *ci, int *ret_index) {
-    int index;
-
+static int tcsv_config_get_index(oconfig_item_t *ci, ssize_t *ret_index) {
     if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)){
         WARNING("tail_csv plugin: The \"%s\" config option needs exactly one "
                 "integer argument.", ci->key);
         return (-1);
     }
 
-    index = (int) ci->values[0].value.number;
-    if (index < 0) {
+    if (ci->values[0].value.number < 0) {
         WARNING("tail_csv plugin: The \"%s\" config option must be positive "
                 "(or zero).", ci->key);
         return (-1);
     }
 
-    *ret_index = index;
+    *ret_index = (ssize_t) ci->values[0].value.number;
     return (0);
 }
 
 /* Parse metric  */
 static int tcsv_config_add_metric(oconfig_item_t *ci){
     metric_definition_t *md;
-    int status = 0;
+    int status;
     int i;
 
     md = (metric_definition_t *)malloc(sizeof(*md));
@@ -428,7 +425,6 @@ static int tcsv_config_add_file(oconfig_item_t *ci)
     /* Registration variables */
     char cb_name[DATA_MAX_NAME_LEN];
     user_data_t cb_data;
-    struct timespec cb_interval;
 
     id = malloc(sizeof(*id));
     if (id == NULL)
@@ -493,8 +489,7 @@ static int tcsv_config_add_file(oconfig_item_t *ci)
     memset(&cb_data, 0, sizeof(cb_data));
     cb_data.data = id;
     cb_data.free_func = tcsv_instance_definition_destroy;
-    CDTIME_T_TO_TIMESPEC(id->interval, &cb_interval);
-    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, &cb_interval, &cb_data);
+    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &cb_data);
 
     if (status != 0){
         ERROR("tail_csv plugin: Registering complex read function failed.");
@@ -544,7 +539,7 @@ static int tcsv_init(void) { /* {{{ */
         }
         else if (ds->ds_num != 1)
         {
-            ERROR ("tail_csv plugin: The type \"%s\" has %i data sources. "
+            ERROR ("tail_csv plugin: The type \"%s\" has %zu data sources. "
                     "Only types with a single data soure are supported.",
                     ds->type, ds->ds_num);
             continue;
index ceb454e..14fb541 100644 (file)
@@ -199,7 +199,7 @@ static int tn_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
   gauge_t *rates;
   int rates_failed;
 
-  int i;
+  size_t i;
 
   if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
     return (-EINVAL);
index a85eced..bd8f9e5 100644 (file)
@@ -190,7 +190,7 @@ static int tr_action_invoke (tr_action_t *act_head, /* {{{ */
     }
 
     subst_status = subst (temp, sizeof (temp), buffer,
-        matches[0].rm_so, matches[0].rm_eo, act->replacement);
+        (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo, act->replacement);
     if (subst_status == NULL)
     {
       ERROR ("Target `replace': subst (buffer = %s, start = %zu, end = %zu, "
index b29a02b..6169fa0 100644 (file)
@@ -89,22 +89,11 @@ static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */
 
        if (failure == 0)
        {
-               uint64_t difference;
+               uint64_t diff;
                double rate;
 
-               /* Calcualte the rate */
-               if (prev_counter > curr_counter) /* => counter overflow */
-               {
-                       if (prev_counter <= 4294967295UL) /* 32 bit overflow */
-                               difference = (4294967295UL - prev_counter) + curr_counter;
-                       else /* 64 bit overflow */
-                               difference = (18446744073709551615ULL - prev_counter) + curr_counter;
-               }
-               else /* no overflow */
-               {
-                       difference = curr_counter - prev_counter;
-               }
-               rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
+               diff = (uint64_t) counter_diff (prev_counter, curr_counter);
+               rate = ((double) diff) / CDTIME_T_TO_DOUBLE (vl->interval);
 
                /* Modify the rate. */
                if (!isnan (data->factor))
@@ -114,9 +103,9 @@ static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */
 
                /* Calculate the internal counter. */
                int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
-               difference = (uint64_t) int_fraction;
-               int_fraction -= ((double) difference);
-               int_counter  += difference;
+               diff = (uint64_t) int_fraction;
+               int_fraction -= ((double) diff);
+               int_counter  += diff;
 
                assert (int_fraction >= 0.0);
                assert (int_fraction <  1.0);
@@ -458,7 +447,7 @@ static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
                notification_meta_t __attribute__((unused)) **meta, void **user_data)
 {
        ts_data_t *data;
-       int i;
+       size_t i;
 
        if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
                return (-EINVAL);
index 5d4bb69..8f40be6 100644 (file)
 
 #if KERNEL_LINUX
 # include <asm/types.h>
-/* sys/socket.h is necessary to compile when using netlink on older systems. */
-# include <sys/socket.h>
 # include <linux/netlink.h>
 #if HAVE_LINUX_INET_DIAG_H
 # include <linux/inet_diag.h>
 #endif
-# include <sys/socket.h>
 # include <arpa/inet.h>
 /* #endif KERNEL_LINUX */
 
@@ -90,9 +87,6 @@
 #if HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NET_IF_H
 # include <net/if.h>
 #endif
 /* This is for OpenBSD and NetBSD. */
 #elif HAVE_LIBKVM_NLIST
 # include <sys/queue.h>
-# include <sys/socket.h>
 # include <net/route.h>
 # include <netinet/in.h>
 # include <netinet/in_systm.h>
index 201e182..56e8d14 100644 (file)
@@ -28,7 +28,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 /*
index 5dd75bc..e76b3c9 100644 (file)
--- a/src/ted.c
+++ b/src/ted.c
@@ -147,7 +147,7 @@ static int ted_read_value(double *ret_power, double *ret_voltage)
             WARNING ("ted plugin: Received EOF from file descriptor.");
             return (-1);
         }
-        else if (receive_buffer_length > sizeof (receive_buffer))
+        else if (((size_t) receive_buffer_length) > sizeof (receive_buffer))
         {
             ERROR ("ted plugin: read(2) returned invalid value %zi.",
                     receive_buffer_length);
index 5df1b83..0c415e4 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/tests/macros.h
- * Copyright (C) 2013       Florian octo Forster
+ * Copyright (C) 2013-2015  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"),
  *   Florian octo Forster <octo at collectd.org>
  */
 
+#include <inttypes.h>
+
 static int fail_count__ = 0;
 static int check_count__ = 0;
 
+#ifndef DBL_PRECISION
+# define DBL_PRECISION 1e-12
+#endif
+
 #define DEF_TEST(func) static int test_##func ()
 
 #define RUN_TEST(func) do { \
@@ -42,16 +48,54 @@ static int check_count__ = 0;
 #define OK1(cond, text) do { \
   _Bool result = (cond); \
   printf ("%s %i - %s\n", result ? "ok" : "not ok", ++check_count__, text); \
+  if (!result) { return -1; } \
 } while (0)
 #define OK(cond) OK1(cond, #cond)
 
-#define STREQ(expect, actual) do { \
+#define EXPECT_EQ_STR(expect, actual) do { \
   if (strcmp (expect, actual) != 0) { \
-    printf ("not ok %i - %s incorrect: expected \"%s\", got \"%s\"\n", \
-        ++check_count__, #actual, expect, actual); \
+    printf ("not ok %i - %s = \"%s\", want \"%s\"\n", \
+        ++check_count__, #actual, actual, expect); \
+    return (-1); \
+  } \
+  printf ("ok %i - %s = \"%s\"\n", ++check_count__, #actual, actual); \
+} while (0)
+
+#define EXPECT_EQ_INT(expect, actual) do { \
+  int want__ = (int) expect; \
+  int got__  = (int) actual; \
+  if (got__ != want__) { \
+    printf ("not ok %i - %s = %d, want %d\n", \
+        ++check_count__, #actual, got__, want__); \
+    return (-1); \
+  } \
+  printf ("ok %i - %s = %d\n", ++check_count__, #actual, got__); \
+} while (0)
+
+#define EXPECT_EQ_UINT64(expect, actual) do { \
+  uint64_t want__ = (uint64_t) expect; \
+  uint64_t got__  = (uint64_t) actual; \
+  if (got__ != want__) { \
+    printf ("not ok %i - %s = %"PRIu64", want %"PRIu64"\n", \
+        ++check_count__, #actual, got__, want__); \
+    return (-1); \
+  } \
+  printf ("ok %i - %s = %"PRIu64"\n", ++check_count__, #actual, got__); \
+} while (0)
+
+#define EXPECT_EQ_DOUBLE(expect, actual) do { \
+  double want__ = (double) expect; \
+  double got__  = (double) actual; \
+  if (isnan (want__) && !isnan (got__)) { \
+    printf ("not ok %i - %s = %.15g, want %.15g\n", \
+        ++check_count__, #actual, got__, want__); \
+    return (-1); \
+  } else if (!isnan (want__) && (((want__-got__) < -DBL_PRECISION) || ((want__-got__) > DBL_PRECISION))) { \
+    printf ("not ok %i - %s = %.15g, want %.15g\n", \
+        ++check_count__, #actual, got__, want__); \
     return (-1); \
   } \
-  printf ("ok %i - %s evaluates to \"%s\"\n", ++check_count__, #actual, expect); \
+  printf ("ok %i - %s = %.15g\n", ++check_count__, #actual, got__); \
 } while (0)
 
 #define CHECK_NOT_NULL(expr) do { \
index 8dcb711..38c7efb 100644 (file)
@@ -553,7 +553,7 @@ static int ut_report_state (const data_set_t *ds,
     {
       gauge_t value;
       gauge_t sum;
-      int i;
+      size_t i;
 
       sum = 0.0;
       for (i = 0; i < vl->values_len; i++)
@@ -701,7 +701,7 @@ static int ut_check_one_threshold (const data_set_t *ds,
 { /* {{{ */
   int ret = -1;
   int ds_index = -1;
-  int i;
+  size_t i;
   gauge_t values_copy[ds->ds_num];
 
   memcpy (values_copy, values, sizeof (values_copy));
index bfe660e..a47e8ca 100644 (file)
@@ -14,7 +14,8 @@ cache_eviction                value:DERIVE:0:U
 cache_operation                value:DERIVE:0:U
 cache_ratio            value:GAUGE:0:100
 cache_result           value:DERIVE:0:U
-cache_size             value:GAUGE:0:U
+cache_size             value:GAUGE:0:1125899906842623
+capacity       value:GAUGE:0:U
 ceph_bytes             value:GAUGE:U:U
 ceph_latency   value:GAUGE:U:U
 ceph_rate                      value:DERIVE:0:U
index 664c018..e6c75a6 100644 (file)
@@ -39,7 +39,6 @@
 /* Folks without pthread will need to disable this plugin. */
 #include <pthread.h>
 
-#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/un.h>
 
index f19835e..8b34a75 100644 (file)
@@ -124,7 +124,7 @@ int handle_flush (FILE *fh, char *buffer)
        for (i = 0; (i == 0) || (i < plugins_num); i++)
        {
                char *plugin = NULL;
-               int j;
+               size_t j;
 
                if (plugins_num != 0)
                        plugin = plugins[i];
index 196b45e..8cbb9b2 100644 (file)
@@ -131,18 +131,18 @@ int handle_getval (FILE *fh, char *buffer)
     return (-1);
   }
 
-  if ((size_t) ds->ds_num != values_num)
+  if (ds->ds_num != values_num)
   {
-    ERROR ("ds[%s]->ds_num = %i, "
-       "but uc_get_rate_by_name returned %u values.",
-       ds->type, ds->ds_num, (unsigned int) values_num);
+    ERROR ("ds[%s]->ds_num = %zu, "
+       "but uc_get_rate_by_name returned %zu values.",
+       ds->type, ds->ds_num, values_num);
     print_to_socket (fh, "-1 Error reading value from cache.\n");
     sfree (values);
     sfree (identifier_copy);
     return (-1);
   }
 
-  print_to_socket (fh, "%u Value%s found\n", (unsigned int) values_num,
+  print_to_socket (fh, "%zu Value%s found\n", values_num,
       (values_num == 1) ? "" : "s");
   for (i = 0; i < values_num; i++)
   {
index 9c84937..d2b8117 100644 (file)
@@ -371,10 +371,10 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     BAIL_OUT (-1);
   }
 
-  if (((size_t) prep_area->ds->ds_num) != r->values_num)
+  if (prep_area->ds->ds_num != r->values_num)
   {
     ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
-        "requires exactly %i value%s, but the configuration specifies %zu.",
+        "requires exactly %zu value%s, but the configuration specifies %zu.",
         r->type,
         prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
         r->values_num);
index 6abfde1..4c763a1 100644 (file)
 #include "plugin.h"
 #include "common.h"
 
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-
 #if HAVE_NET_IF_ARP_H
 # include <net/if_arp.h>
 #endif
@@ -305,7 +301,7 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
     if (ns <= 0)
        return 4;               /* probably compression loop */
     do {
-       if ((*off) >= sz)
+       if ((*off) >= ((off_t) sz))
            break;
        c = *(buf + (*off));
        if (c > 191) {
@@ -317,11 +313,11 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
            s = ntohs(s);
            (*off) += sizeof(s);
            /* Sanity check */
-           if ((*off) >= sz)
+           if ((*off) >= ((off_t) sz))
                return 1;       /* message too short */
            ptr = s & 0x3FFF;
            /* Make sure the pointer is inside this message */
-           if (ptr >= sz)
+           if (ptr >= ((off_t) sz))
                return 2;       /* bad compression ptr */
            if (ptr < DNS_MSG_HDR_SZ)
                return 2;       /* bad compression ptr */
@@ -355,7 +351,7 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
     if (no > 0)
        *(name + no - 1) = '\0';
     /* make sure we didn't allow someone to overflow the name buffer */
-    assert(no <= ns);
+    assert(no <= ((off_t) ns));
     return 0;
 }
 
index 023f7a4..eb5b4b3 100644 (file)
@@ -188,7 +188,7 @@ int format_graphite (char *buffer, size_t buffer_size,
     unsigned int flags)
 {
     int status = 0;
-    int i;
+    size_t i;
     int buffer_pos = 0;
 
     gauge_t *rates = NULL;
index 10a5343..122c7f8 100644 (file)
@@ -81,7 +81,7 @@ static int values_to_json (char *buffer, size_t buffer_size, /* {{{ */
                 const data_set_t *ds, const value_list_t *vl, int store_rates)
 {
   size_t offset = 0;
-  int i;
+  size_t i;
   gauge_t *rates = NULL;
 
   memset (buffer, 0, buffer_size);
@@ -160,7 +160,7 @@ static int dstypes_to_json (char *buffer, size_t buffer_size, /* {{{ */
                 const data_set_t *ds)
 {
   size_t offset = 0;
-  int i;
+  size_t i;
 
   memset (buffer, 0, buffer_size);
 
@@ -197,7 +197,7 @@ static int dsnames_to_json (char *buffer, size_t buffer_size, /* {{{ */
                 const data_set_t *ds)
 {
   size_t offset = 0;
-  int i;
+  size_t i;
 
   memset (buffer, 0, buffer_size);
 
diff --git a/src/utils_ignorelist.c b/src/utils_ignorelist.c
deleted file mode 100644 (file)
index 7b1c7d2..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/**
- * collectd - src/utils_ignorelist.c
- * Copyright (C) 2006 Lubos Stanek <lubek at users.sourceforge.net>
- * Copyright (C) 2008 Florian Forster <octo at collectd.org>
- *
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
- *
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- * Authors:
- *   Lubos Stanek <lubek at users.sourceforge.net>
- *   Florian Forster <octo at collectd.org>
- **/
-/**
- * ignorelist handles plugin's list of configured collectable
- * entries with global ignore action
- **/
-/**
- * Usage:
- * 
- * Define plugin's global pointer variable of type ignorelist_t:
- *   ignorelist_t *myconfig_ignore;
- * If you know the state of the global ignore (IgnoreSelected),
- * allocate the variable with:
- *   myconfig_ignore = ignorelist_create (YourKnownIgnore);
- * If you do not know the state of the global ignore,
- * initialize the global variable and set the ignore flag later:
- *   myconfig_ignore = ignorelist_init ();
- * Append single entries in your cf_register'ed callback function:
- *   ignorelist_add (myconfig_ignore, newentry);
- * When you hit the IgnoreSelected config option,
- * offer it to the list:
- *   ignorelist_ignore (myconfig_ignore, instantly_got_value_of_ignore);
- * That is all for the ignorelist initialization.
- * Later during read and write (plugin's registered functions) get
- * the information whether this entry would be collected or not:
- *   if (ignorelist_match (myconfig_ignore, thisentry))
- *     return;
- **/
-
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "common.h"
-#include "plugin.h"
-#include "utils_ignorelist.h"
-
-/*
- * private prototypes
- */
-struct ignorelist_item_s
-{
-#if HAVE_REGEX_H
-       regex_t *rmatch;        /* regular expression entry identification */
-#endif
-       char *smatch;           /* string entry identification */
-       struct ignorelist_item_s *next;
-};
-typedef struct ignorelist_item_s ignorelist_item_t;
-
-struct ignorelist_s
-{
-       int ignore;             /* ignore entries */
-       ignorelist_item_t *head;        /* pointer to the first entry */
-};
-
-/* *** *** *** ********************************************* *** *** *** */
-/* *** *** *** *** *** ***   private functions   *** *** *** *** *** *** */
-/* *** *** *** ********************************************* *** *** *** */
-
-static inline void ignorelist_append (ignorelist_t *il, ignorelist_item_t *item)
-{
-       assert ((il != NULL) && (item != NULL));
-
-       item->next = il->head;
-       il->head = item;
-}
-
-#if HAVE_REGEX_H
-static int ignorelist_append_regex(ignorelist_t *il, const char *entry)
-{
-       int rcompile;
-       regex_t *regtemp;
-       int errsize;
-       char *regerr = NULL;
-       ignorelist_item_t *new;
-
-       /* create buffer */
-       if ((regtemp = malloc(sizeof(regex_t))) == NULL)
-       {
-               ERROR ("cannot allocate new config entry");
-               return (1);
-       }
-       memset (regtemp, '\0', sizeof(regex_t));
-
-       /* compile regex */
-       if ((rcompile = regcomp (regtemp, entry, REG_EXTENDED)) != 0)
-       {
-               /* prepare message buffer */
-               errsize = regerror(rcompile, regtemp, NULL, 0);
-               if (errsize)
-                       regerr = smalloc(errsize);
-               /* get error message */
-               if (regerror (rcompile, regtemp, regerr, errsize))
-               {
-                       fprintf (stderr, "Cannot compile regex %s: %i/%s",
-                                       entry, rcompile, regerr);
-                       ERROR ("Cannot compile regex %s: %i/%s",
-                                       entry, rcompile, regerr);
-               }
-               else
-               {
-                       fprintf (stderr, "Cannot compile regex %s: %i",
-                                       entry, rcompile);
-                       ERROR ("Cannot compile regex %s: %i",
-                                       entry, rcompile);
-               }
-
-               if (errsize)
-                       sfree (regerr);
-               regfree (regtemp);
-               sfree (regtemp);
-               return (1);
-       }
-       DEBUG("regex compiled: %s - %i", entry, rcompile);
-
-       /* create new entry */
-       if ((new = malloc(sizeof(ignorelist_item_t))) == NULL)
-       {
-               ERROR ("cannot allocate new config entry");
-               regfree (regtemp);
-               sfree (regtemp);
-               return (1);
-       }
-       memset (new, '\0', sizeof(ignorelist_item_t));
-       new->rmatch = regtemp;
-
-       /* append new entry */
-       ignorelist_append (il, new);
-
-       return (0);
-} /* int ignorelist_append_regex(ignorelist_t *il, const char *entry) */
-#endif
-
-static int ignorelist_append_string(ignorelist_t *il, const char *entry)
-{
-       ignorelist_item_t *new;
-
-       /* create new entry */
-       if ((new = malloc(sizeof(ignorelist_item_t))) == NULL )
-       {
-               ERROR ("cannot allocate new entry");
-               return (1);
-       }
-       memset (new, '\0', sizeof(ignorelist_item_t));
-       new->smatch = sstrdup(entry);
-
-       /* append new entry */
-       ignorelist_append (il, new);
-
-       return (0);
-} /* int ignorelist_append_string(ignorelist_t *il, const char *entry) */
-
-#if HAVE_REGEX_H
-/*
- * check list for entry regex match
- * return 1 if found
- */
-static int ignorelist_match_regex (ignorelist_item_t *item, const char *entry)
-{
-       assert ((item != NULL) && (item->rmatch != NULL)
-                       && (entry != NULL) && (strlen (entry) > 0));
-
-       /* match regex */
-       if (regexec (item->rmatch, entry, 0, NULL, 0) == 0)
-               return (1);
-
-       return (0);
-} /* int ignorelist_match_regex (ignorelist_item_t *item, const char *entry) */
-#endif
-
-/*
- * check list for entry string match
- * return 1 if found
- */
-static int ignorelist_match_string (ignorelist_item_t *item, const char *entry)
-{
-       assert ((item != NULL) && (item->smatch != NULL)
-                       && (entry != NULL) && (strlen (entry) > 0));
-
-       if (strcmp (entry, item->smatch) == 0)
-               return (1);
-
-       return (0);
-} /* int ignorelist_match_string (ignorelist_item_t *item, const char *entry) */
-
-
-/* *** *** *** ******************************************** *** *** *** */
-/* *** *** *** *** *** ***   public functions   *** *** *** *** *** *** */
-/* *** *** *** ******************************************** *** *** *** */
-
-/*
- * create the ignorelist_t with known ignore state
- * return pointer to ignorelist_t
- */
-ignorelist_t *ignorelist_create (int invert)
-{
-       ignorelist_t *il;
-
-       /* smalloc exits if it failes */
-       il = (ignorelist_t *) smalloc (sizeof (ignorelist_t));
-       memset (il, '\0', sizeof (ignorelist_t));
-
-       /*
-        * ->ignore == 0  =>  collect
-        * ->ignore == 1  =>  ignore
-        */
-       il->ignore = invert ? 0 : 1;
-
-       return (il);
-} /* ignorelist_t *ignorelist_create (int ignore) */
-
-/*
- * free memory used by ignorelist_t
- */
-void ignorelist_free (ignorelist_t *il)
-{
-       ignorelist_item_t *this;
-       ignorelist_item_t *next;
-
-       if (il == NULL)
-               return;
-
-       for (this = il->head; this != NULL; this = next)
-       {
-               next = this->next;
-#if HAVE_REGEX_H
-               if (this->rmatch != NULL)
-               {
-                       regfree (this->rmatch);
-                       sfree (this->rmatch);
-                       this->rmatch = NULL;
-               }
-#endif
-               if (this->smatch != NULL)
-               {
-                       sfree (this->smatch);
-                       this->smatch = NULL;
-               }
-               sfree (this);
-       }
-
-       sfree (il);
-       il = NULL;
-} /* void ignorelist_destroy (ignorelist_t *il) */
-
-/*
- * set ignore state of the ignorelist_t
- */
-void ignorelist_set_invert (ignorelist_t *il, int invert)
-{
-       if (il == NULL)
-       {
-               DEBUG("ignore call with ignorelist_t == NULL");
-               return;
-       }
-
-       il->ignore = invert ? 0 : 1;
-} /* void ignorelist_set_invert (ignorelist_t *il, int ignore) */
-
-/*
- * append entry into ignorelist_t
- * return 1 for success
- */
-int ignorelist_add (ignorelist_t *il, const char *entry)
-{
-       int ret;
-       size_t entry_len;
-
-       if (il == NULL)
-       {
-               DEBUG ("add called with ignorelist_t == NULL");
-               return (1);
-       }
-
-       entry_len = strlen (entry);
-
-       /* append nothing */
-       if (entry_len == 0)
-       {
-               DEBUG("not appending: empty entry");
-               return (1);
-       }
-
-#if HAVE_REGEX_H
-       /* regex string is enclosed in "/.../" */
-       if ((entry_len > 2) && (entry[0] == '/') && entry[entry_len - 1] == '/')
-       {
-               char *entry_copy;
-               size_t entry_copy_size;
-
-               /* We need to copy `entry' since it's const */
-               entry_copy_size = entry_len - 1;
-               entry_copy = smalloc (entry_copy_size);
-               sstrncpy (entry_copy, entry + 1, entry_copy_size);
-
-               DEBUG("I'm about to add regex entry: %s", entry_copy);
-               ret = ignorelist_append_regex(il, entry_copy);
-               sfree (entry_copy);
-       }
-       else
-#endif
-       {
-               DEBUG("to add entry: %s", entry);
-               ret = ignorelist_append_string(il, entry);
-       }
-
-       return (ret);
-} /* int ignorelist_add (ignorelist_t *il, const char *entry) */
-
-/*
- * check list for entry
- * return 1 for ignored entry
- */
-int ignorelist_match (ignorelist_t *il, const char *entry)
-{
-       ignorelist_item_t *traverse;
-
-       /* if no entries, collect all */
-       if ((il == NULL) || (il->head == NULL))
-               return (0);
-
-       if ((entry == NULL) || (strlen (entry) == 0))
-               return (0);
-
-       /* traverse list and check entries */
-       for (traverse = il->head; traverse != NULL; traverse = traverse->next)
-       {
-#if HAVE_REGEX_H
-               if (traverse->rmatch != NULL)
-               {
-                       if (ignorelist_match_regex (traverse, entry))
-                               return (il->ignore);
-               }
-               else
-#endif
-               {
-                       if (ignorelist_match_string (traverse, entry))
-                               return (il->ignore);
-               }
-       } /* for traverse */
-
-       return (1 - il->ignore);
-} /* int ignorelist_match (ignorelist_t *il, const char *entry) */
-
diff --git a/src/utils_ignorelist.h b/src/utils_ignorelist.h
deleted file mode 100644 (file)
index b47b55a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * collectd - src/utils_ignorelist.h
- * Copyright (C) 2006 Lubos Stanek <lubek at users.sourceforge.net>
- *
- * This program is free software; you can redistribute it and/
- * or modify it under the terms of the GNU General Public Li-
- * cence as published by the Free Software Foundation; either
- * version 2 of the Licence, or any later version.
- *
- * This program is distributed in the hope that it will be use-
- * ful, but WITHOUT ANY WARRANTY; without even the implied war-
- * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public Licence for more details.
- *
- * You should have received a copy of the GNU General Public
- * Licence along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- * Authors:
- *   Lubos Stanek <lubek at users.sourceforge.net>
- **/
-/**
- * ignorelist handles plugin's list of configured collectable
- * entries with global ignore action
- **/
-
-#ifndef UTILS_IGNORELIST_H
-#define UTILS_IGNORELIST_H 1
-
-#include "collectd.h"
-
-#if HAVE_REGEX_H
-# include <regex.h>
-#endif
-
-/* public prototypes */
-
-struct ignorelist_s;
-typedef struct ignorelist_s ignorelist_t;
-
-/*
- * create the ignorelist_t with known ignore state
- * return pointer to ignorelist_t
- */
-ignorelist_t *ignorelist_create (int invert);
-
-/*
- * free memory used by ignorelist_t
- */
-void ignorelist_free (ignorelist_t *il);
-
-/*
- * set ignore state of the ignorelist_t
- */
-void ignorelist_set_invert (ignorelist_t *il, int invert);
-
-/*
- * append entry to ignorelist_t
- * returns zero on success, non-zero upon failure.
- */
-int ignorelist_add (ignorelist_t *il, const char *entry);
-
-/*
- * check list for entry
- * return 1 for ignored entry
- */
-int ignorelist_match (ignorelist_t *il, const char *entry);
-
-#endif /* UTILS_IGNORELIST_H */
diff --git a/src/utils_latency_test.c b/src/utils_latency_test.c
new file mode 100644 (file)
index 0000000..5769ec9
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * collectd - src/utils_latency_test.c
+ * Copyright (C) 2015       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 <octo at collectd.org>
+ */
+
+#define DBL_PRECISION 1e-9
+
+#include "testing.h"
+#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
+#include "utils_time.h"
+#include "utils_latency.h"
+
+DEF_TEST(simple)
+{
+  struct {
+    double val;
+    double min;
+    double max;
+    double sum;
+    double avg;
+  } cases[] = {
+  /* val  min  max  sum   avg */
+    {0.5, 0.5, 0.5, 0.5,  0.5},
+    {0.3, 0.3, 0.5, 0.8,  0.4},
+    {0.7, 0.3, 0.7, 1.5,  0.5},
+    {2.5, 0.3, 2.5, 4.0,  1.0},
+    { 99, 0.3,  99, 103, 20.6},
+    /* { -1, 0.3,  99, 103, 20.6}, see issue #1139 */
+  };
+  size_t i;
+  latency_counter_t *l;
+
+  CHECK_NOT_NULL (l = latency_counter_create ());
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    printf ("# case %zu: DOUBLE_TO_CDTIME_T(%g) = %"PRIu64"\n",
+        i, cases[i].val, DOUBLE_TO_CDTIME_T (cases[i].val));
+    latency_counter_add (l, DOUBLE_TO_CDTIME_T (cases[i].val));
+
+    EXPECT_EQ_DOUBLE (cases[i].min, CDTIME_T_TO_DOUBLE (latency_counter_get_min (l)));
+    EXPECT_EQ_DOUBLE (cases[i].max, CDTIME_T_TO_DOUBLE (latency_counter_get_max (l)));
+    EXPECT_EQ_DOUBLE (cases[i].sum, CDTIME_T_TO_DOUBLE (latency_counter_get_sum (l)));
+    EXPECT_EQ_DOUBLE (cases[i].avg, CDTIME_T_TO_DOUBLE (latency_counter_get_average (l)));
+  }
+
+  latency_counter_destroy (l);
+  return 0;
+}
+
+DEF_TEST(percentile)
+{
+  size_t i;
+  latency_counter_t *l;
+
+  CHECK_NOT_NULL (l = latency_counter_create ());
+
+  for (i = 0; i < 100; i++) {
+    latency_counter_add (l, TIME_T_TO_CDTIME_T (((time_t) i) + 1));
+  }
+
+  EXPECT_EQ_DOUBLE (  1.0, CDTIME_T_TO_DOUBLE (latency_counter_get_min (l)));
+  EXPECT_EQ_DOUBLE (100.0, CDTIME_T_TO_DOUBLE (latency_counter_get_max (l)));
+  EXPECT_EQ_DOUBLE (100.0 * 101.0 / 2.0, CDTIME_T_TO_DOUBLE (latency_counter_get_sum (l)));
+  EXPECT_EQ_DOUBLE ( 50.5, CDTIME_T_TO_DOUBLE (latency_counter_get_average (l)));
+
+  EXPECT_EQ_DOUBLE (50.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 50.0)));
+  EXPECT_EQ_DOUBLE (80.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 80.0)));
+  EXPECT_EQ_DOUBLE (95.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 95.0)));
+  EXPECT_EQ_DOUBLE (99.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 99.0)));
+
+  CHECK_ZERO (latency_counter_get_percentile (l, -1.0));
+  CHECK_ZERO (latency_counter_get_percentile (l, 101.0));
+
+  latency_counter_destroy (l);
+  return 0;
+}
+
+int main (void)
+{
+  RUN_TEST(simple);
+  RUN_TEST(percentile);
+
+  END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
index c5ffbfb..b4cb432 100644 (file)
 #include "collectd.h"
 #include "utils_mount.h"
 
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
 DEF_TEST(cu_mount_checkoption)
 {
   char line_opts[] = "foo=one,bar=two,qux=three";
@@ -77,14 +81,14 @@ DEF_TEST(cu_mount_getoptionvalue)
   char line_opts[] = "foo=one,bar=two,qux=three";
   char line_bool[] = "one,two,three";
 
-  STREQ ("one", cu_mount_getoptionvalue (line_opts, "foo="));
-  STREQ ("two", cu_mount_getoptionvalue (line_opts, "bar="));
-  STREQ ("three", cu_mount_getoptionvalue (line_opts, "qux="));
+  EXPECT_EQ_STR ("one", cu_mount_getoptionvalue (line_opts, "foo="));
+  EXPECT_EQ_STR ("two", cu_mount_getoptionvalue (line_opts, "bar="));
+  EXPECT_EQ_STR ("three", cu_mount_getoptionvalue (line_opts, "qux="));
   OK (NULL == cu_mount_getoptionvalue (line_opts, "unknown="));
 
-  STREQ ("", cu_mount_getoptionvalue (line_bool, "one"));
-  STREQ ("", cu_mount_getoptionvalue (line_bool, "two"));
-  STREQ ("", cu_mount_getoptionvalue (line_bool, "three"));
+  EXPECT_EQ_STR ("", cu_mount_getoptionvalue (line_bool, "one"));
+  EXPECT_EQ_STR ("", cu_mount_getoptionvalue (line_bool, "two"));
+  EXPECT_EQ_STR ("", cu_mount_getoptionvalue (line_bool, "three"));
   OK (NULL == cu_mount_getoptionvalue (line_bool, "four"));
 
   return (0);
index 5add323..39f42b2 100644 (file)
@@ -284,7 +284,7 @@ static int ds_get (char ***ret, /* {{{ */
     const rrdcreate_config_t *cfg)
 {
   char **ds_def;
-  int ds_num;
+  size_t ds_num;
 
   char min[32];
   char max[32];
index f0f0b46..f85910e 100644 (file)
 #include "utils_vl_lookup.h"
 #include "utils_avltree.h"
 
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
 #if BUILD_TEST
 # define sstrncpy strncpy
 # define plugin_log(s, ...) do { \
index 6a2676a..41cc0a4 100644 (file)
@@ -65,7 +65,7 @@ static void *lookup_class_callback (data_set_t const *ds,
   identifier_t *class = user_class;
   identifier_t *obj;
 
-  OK(expect_new_obj);
+  assert (expect_new_obj);
 
   memcpy (&last_class_ident, class, sizeof (last_class_ident));
   
@@ -81,7 +81,7 @@ static void *lookup_class_callback (data_set_t const *ds,
   return ((void *) obj);
 }
 
-static void checked_lookup_add (lookup_t *obj, /* {{{ */
+static int checked_lookup_add (lookup_t *obj, /* {{{ */
     char const *host,
     char const *plugin, char const *plugin_instance,
     char const *type, char const *type_instance,
@@ -101,7 +101,8 @@ static void checked_lookup_add (lookup_t *obj, /* {{{ */
   memmove (user_class, &ident, sizeof (ident));
 
   OK(lookup_add (obj, &ident, group_by, user_class) == 0);
-} /* }}} void test_add */
+  return 0;
+} /* }}} int checked_lookup_add */
 
 static int checked_lookup_search (lookup_t *obj,
     char const *host,
@@ -129,20 +130,11 @@ static int checked_lookup_search (lookup_t *obj,
   return (status);
 }
 
-static lookup_t *checked_lookup_create (void)
-{
-  lookup_t *obj = lookup_create (
-      lookup_class_callback,
-      lookup_obj_callback,
-      (void *) free,
-      (void *) free);
-  OK(obj != NULL);
-  return (obj);
-}
-
 DEF_TEST(group_by_specific_host)
 {
-  lookup_t *obj = checked_lookup_create ();
+  lookup_t *obj;
+  CHECK_NOT_NULL (obj = lookup_create (
+        lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
 
   checked_lookup_add (obj, "/.*/", "test", "", "test", "/.*/", LU_GROUP_BY_HOST);
   checked_lookup_search (obj, "host0", "test", "", "test", "0",
@@ -160,7 +152,9 @@ DEF_TEST(group_by_specific_host)
 
 DEF_TEST(group_by_any_host)
 {
-  lookup_t *obj = checked_lookup_create ();
+  lookup_t *obj;
+  CHECK_NOT_NULL (obj = lookup_create (
+        lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
 
   checked_lookup_add (obj, "/.*/", "/.*/", "/.*/", "test", "/.*/", LU_GROUP_BY_HOST);
   checked_lookup_search (obj, "host0", "plugin0", "", "test", "0",
@@ -186,9 +180,12 @@ DEF_TEST(group_by_any_host)
 
 DEF_TEST(multiple_lookups)
 {
-  lookup_t *obj = checked_lookup_create ();
+  lookup_t *obj;
   int status;
 
+  CHECK_NOT_NULL (obj = lookup_create (
+        lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
+
   checked_lookup_add (obj, "/.*/", "plugin0", "", "test", "/.*/", LU_GROUP_BY_HOST);
   checked_lookup_add (obj, "/.*/", "/.*/", "", "test", "ti0", LU_GROUP_BY_HOST);
 
@@ -211,7 +208,9 @@ DEF_TEST(multiple_lookups)
 
 DEF_TEST(regex)
 {
-  lookup_t *obj = checked_lookup_create ();
+  lookup_t *obj;
+  CHECK_NOT_NULL (obj = lookup_create (
+        lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
 
   checked_lookup_add (obj, "/^db[0-9]\\./", "cpu", "/.*/", "cpu", "/.*/",
       LU_GROUP_BY_TYPE_INSTANCE);
index 1089222..c6c4df0 100644 (file)
@@ -749,7 +749,7 @@ static int varnish_init (void) /* {{{ */
        plugin_register_complex_read (/* group = */ "varnish",
                        /* name      = */ "varnish/localhost",
                        /* callback  = */ varnish_read,
-                       /* interval  = */ NULL,
+                       /* interval  = */ 0,
                        /* user data = */ &ud);
 
        return (0);
@@ -911,7 +911,7 @@ static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
        plugin_register_complex_read (/* group = */ "varnish",
                        /* name      = */ callback_name,
                        /* callback  = */ varnish_read,
-                       /* interval  = */ NULL,
+                       /* interval  = */ 0,
                        /* user data = */ &ud);
 
        have_instance = 1;
index 663555b..6824b13 100644 (file)
@@ -128,7 +128,7 @@ enum plginst_field {
 };
 
 static enum plginst_field plugin_instance_format[PLGINST_MAX_FIELDS] =
-    { plginst_name };
+    { plginst_none };
 
 /* InterfaceFormat. */
 enum if_field {
@@ -449,7 +449,10 @@ lv_config (const char *key, const char *value)
         }
 
         for (i = 0; i < n; ++i) {
-            if (strcasecmp (fields[i], "name") == 0)
+            if (strcasecmp (fields[i], "none") == 0) {
+                plugin_instance_format[i] = plginst_none;
+                break;
+            } else if (strcasecmp (fields[i], "name") == 0)
                 plugin_instance_format[i] = plginst_name;
             else if (strcasecmp (fields[i], "uuid") == 0)
                 plugin_instance_format[i] = plginst_uuid;
index 41451a8..7fc9eb9 100644 (file)
 /* Folks without pthread will need to disable this plugin. */
 #include <pthread.h>
 
-#include <sys/socket.h>
 #include <netdb.h>
 
-#ifndef WG_DEFAULT_NODE
-# define WG_DEFAULT_NODE "localhost"
-#endif
-
-#ifndef WG_DEFAULT_SERVICE
-# define WG_DEFAULT_SERVICE "2003"
-#endif
-
-#ifndef WG_DEFAULT_PROTOCOL
-# define WG_DEFAULT_PROTOCOL "tcp"
-#endif
-
-#ifndef WG_DEFAULT_LOG_SEND_ERRORS
-# define WG_DEFAULT_LOG_SEND_ERRORS 1
-#endif
-
-#ifndef WG_DEFAULT_ESCAPE
-# define WG_DEFAULT_ESCAPE '_'
-#endif
+#define WG_DEFAULT_NODE "localhost"
+#define WG_DEFAULT_SERVICE "2003"
+#define WG_DEFAULT_PROTOCOL "tcp"
+#define WG_DEFAULT_LOG_SEND_ERRORS 1
+#define WG_DEFAULT_ESCAPE '_'
 
 /* Ethernet - (IPv6 + TCP) = 1500 - (40 + 32) = 1428 */
-#ifndef WG_SEND_BUF_SIZE
-# define WG_SEND_BUF_SIZE 1428
-#endif
+#define WG_SEND_BUF_SIZE 1428
 
-#ifndef WG_MIN_RECONNECT_INTERVAL
-# define WG_MIN_RECONNECT_INTERVAL TIME_T_TO_CDTIME_T (1)
-#endif
+#define WG_MIN_RECONNECT_INTERVAL TIME_T_TO_CDTIME_T (1)
 
 /*
  * Private variables
@@ -134,13 +115,11 @@ static int wg_send_buffer (struct wg_callback *cb)
     status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf));
     if (status < 0)
     {
-        const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
-
         if (cb->log_send_errors)
         {
             char errbuf[1024];
             ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)",
-                    cb->node, cb->service, protocol,
+                    cb->node, cb->service, cb->protocol,
                     status, sstrerror (errno, errbuf, sizeof (errbuf)));
         }
 
@@ -193,10 +172,6 @@ static int wg_callback_init (struct wg_callback *cb)
     cdtime_t now;
     int status;
 
-    const char *node = cb->node ? cb->node : WG_DEFAULT_NODE;
-    const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
-    const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
-
     char connerr[1024] = "";
 
     if (cb->sock_fd > 0)
@@ -215,18 +190,18 @@ static int wg_callback_init (struct wg_callback *cb)
 #endif
     ai_hints.ai_family = AF_UNSPEC;
 
-    if (0 == strcasecmp ("tcp", protocol))
+    if (0 == strcasecmp ("tcp", cb->protocol))
         ai_hints.ai_socktype = SOCK_STREAM;
     else
         ai_hints.ai_socktype = SOCK_DGRAM;
 
     ai_list = NULL;
 
-    status = getaddrinfo (node, service, &ai_hints, &ai_list);
+    status = getaddrinfo (cb->node, cb->service, &ai_hints, &ai_list);
     if (status != 0)
     {
         ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s",
-                node, service, protocol, gai_strerror (status));
+                cb->node, cb->service, cb->protocol, gai_strerror (status));
         return (-1);
     }
 
@@ -265,14 +240,14 @@ static int wg_callback_init (struct wg_callback *cb)
             sstrerror (errno, connerr, sizeof (connerr));
         c_complain (LOG_ERR, &cb->init_complaint,
                   "write_graphite plugin: Connecting to %s:%s via %s failed. "
-                  "The last error was: %s", node, service, protocol, connerr);
+                  "The last error was: %s", cb->node, cb->service, cb->protocol, connerr);
         return (-1);
     }
     else
     {
         c_release (LOG_INFO, &cb->init_complaint,
                 "write_graphite plugin: Successfully connected to %s:%s via %s.",
-                node, service, protocol);
+                cb->node, cb->service, cb->protocol);
     }
 
     wg_reset_buffer (cb);
@@ -383,9 +358,7 @@ static int wg_send_message (char const *message, struct wg_callback *cb)
     cb->send_buf_free -= message_len;
 
     DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"",
-            cb->node,
-            cb->service,
-            cb->protocol,
+            cb->node, cb->service, cb->protocol,
             cb->send_buf_fill, sizeof (cb->send_buf),
             100.0 * ((double) cb->send_buf_fill) / ((double) sizeof (cb->send_buf)),
             message);
@@ -486,9 +459,9 @@ static int wg_config_node (oconfig_item_t *ci)
     memset (cb, 0, sizeof (*cb));
     cb->sock_fd = -1;
     cb->name = NULL;
-    cb->node = NULL;
-    cb->service = NULL;
-    cb->protocol = NULL;
+    cb->node = strdup (WG_DEFAULT_NODE);
+    cb->service = strdup (WG_DEFAULT_SERVICE);
+    cb->protocol = strdup (WG_DEFAULT_PROTOCOL);
     cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS;
     cb->prefix = NULL;
     cb->postfix = NULL;
@@ -566,9 +539,7 @@ 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 != NULL ? cb->node : WG_DEFAULT_NODE,
-                cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE,
-                cb->protocol != NULL ? cb->protocol : WG_DEFAULT_PROTOCOL);
+                cb->node, cb->service, cb->protocol);
     else
         ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
                 cb->name);
index ed596bb..868bca8 100644 (file)
@@ -59,6 +59,7 @@ struct wh_callback_s
         char *clientkeypass;
         long sslversion;
         _Bool store_rates;
+        _Bool log_http_error;
         int   low_speed_limit;
         time_t low_speed_time;
         int timeout;
@@ -80,6 +81,19 @@ struct wh_callback_s
 };
 typedef struct wh_callback_s wh_callback_t;
 
+static void wh_log_http_error (wh_callback_t *cb)
+{
+        if (!cb->log_http_error)
+                return;
+
+        long http_code = 0;
+
+        curl_easy_getinfo (cb->curl, CURLINFO_RESPONSE_CODE, &http_code);
+
+        if (http_code != 200)
+                INFO ("write_http plugin: HTTP Error code: %lu", http_code);
+}
+
 static void wh_reset_buffer (wh_callback_t *cb)  /* {{{ */
 {
         memset (cb->send_buffer, 0, cb->send_buffer_size);
@@ -101,6 +115,9 @@ static int wh_send_buffer (wh_callback_t *cb) /* {{{ */
 
         curl_easy_setopt (cb->curl, CURLOPT_POSTFIELDS, cb->send_buffer);
         status = curl_easy_perform (cb->curl);
+
+        wh_log_http_error (cb);
+
         if (status != CURLE_OK)
         {
                 ERROR ("write_http plugin: curl_easy_perform failed with "
@@ -538,6 +555,7 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
         cb->sslversion = CURL_SSLVERSION_DEFAULT;
         cb->low_speed_limit = 0;
         cb->timeout = 0;
+        cb->log_http_error = 0;
 
         pthread_mutex_init (&cb->send_lock, /* attr = */ NULL);
 
@@ -609,6 +627,8 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
                         cf_util_get_int (child, &cb->low_speed_limit);
                 else if (strcasecmp ("Timeout", child->key) == 0)
                         cf_util_get_int (child, &cb->timeout);
+                else if (strcasecmp ("LogHttpError", child->key) == 0)
+                        cf_util_get_boolean (child, &cb->log_http_error);
                 else
                 {
                         ERROR ("write_http plugin: Invalid configuration "
index e37aae9..ebf0e12 100644 (file)
@@ -35,7 +35,6 @@
 /* Folks without pthread will need to disable this plugin. */
 #include <pthread.h>
 
-#include <sys/socket.h>
 #include <netdb.h>
 
 #define WL_BUF_SIZE 8192
index 2a6f912..1eb082f 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/write_redis.c
- * Copyright (C) 2010       Florian Forster
+ * Copyright (C) 2010-2015  Florian Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #include <sys/time.h>
 #include <hiredis/hiredis.h>
 
+#ifndef REDIS_DEFAULT_PREFIX
+# define REDIS_DEFAULT_PREFIX "collectd/"
+#endif
+
 struct wr_node_s
 {
   char name[DATA_MAX_NAME_LEN];
@@ -40,6 +44,10 @@ struct wr_node_s
   char *host;
   int port;
   struct timeval timeout;
+  char *prefix;
+  int database;
+  int max_set_size;
+  _Bool store_rates;
 
   redisContext *conn;
   pthread_mutex_t lock;
@@ -62,51 +70,19 @@ static int wr_write (const data_set_t *ds, /* {{{ */
   char *value_ptr;
   int status;
   redisReply   *rr;
-  int i;
 
   status = FORMAT_VL (ident, sizeof (ident), vl);
   if (status != 0)
     return (status);
-  ssnprintf (key, sizeof (key), "collectd/%s", ident);
+  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));
 
   memset (value, 0, sizeof (value));
   value_size = sizeof (value);
   value_ptr = &value[0];
-
-#define APPEND(...) do {                                             \
-  status = snprintf (value_ptr, value_size, __VA_ARGS__);            \
-  if (((size_t) status) > value_size)                                \
-  {                                                                  \
-    value_ptr += value_size;                                         \
-    value_size = 0;                                                  \
-  }                                                                  \
-  else                                                               \
-  {                                                                  \
-    value_ptr += status;                                             \
-    value_size -= status;                                            \
-  }                                                                  \
-} while (0)
-
-  APPEND ("%s:", time);
-
-  for (i = 0; i < ds->ds_num; i++)
-  {
-    if (ds->ds[i].type == DS_TYPE_COUNTER)
-      APPEND ("%llu", vl->values[i].counter);
-    else if (ds->ds[i].type == DS_TYPE_GAUGE)
-      APPEND (GAUGE_FORMAT, vl->values[i].gauge);
-    else if (ds->ds[i].type == DS_TYPE_DERIVE)
-      APPEND ("%"PRIi64, vl->values[i].derive);
-    else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
-      APPEND ("%"PRIu64, vl->values[i].absolute);
-    else
-      assert (23 == 42);
-  }
-
-#undef APPEND
-
-  status = format_values (value_ptr, value_size, ds, vl, /* store rates = */ 0);
+  status = format_values (value_ptr, value_size, ds, vl, node->store_rates);
   pthread_mutex_lock (&node->lock);
   if (status != 0)
     return (status);
@@ -131,6 +107,12 @@ static int wr_write (const data_set_t *ds, /* {{{ */
       pthread_mutex_unlock (&node->lock);
       return (-1);
     }
+
+    rr = redisCommand(node->conn, "SELECT %d", node->database);
+    if (rr == NULL)
+      WARNING("SELECT command error. database:%d message:%s", node->database, node->conn->errstr);
+    else
+      freeReplyObject (rr);
   }
 
   rr = redisCommand (node->conn, "ZADD %s %s %s", key, time, value);
@@ -139,10 +121,21 @@ static int wr_write (const data_set_t *ds, /* {{{ */
   else
     freeReplyObject (rr);
 
+  if (node->max_set_size >= 0)
+  {
+    rr = redisCommand (node->conn, "ZREMRANGEBYRANK %s %d %d", key, 0, (-1 * node->max_set_size) - 1);
+    if (rr == NULL)
+      WARNING("ZREMRANGEBYRANK 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. */
-  rr = redisCommand (node->conn, "SADD collectd/values %s", ident);
+  rr = redisCommand (node->conn, "SADD %svalues %s",
+      (node->prefix != NULL) ? node->prefix : REDIS_DEFAULT_PREFIX,
+      ident);
   if (rr==NULL)
     WARNING("SADD command error. ident:%s message:%s", ident, node->conn->errstr);
   else
@@ -186,6 +179,10 @@ static int wr_config_node (oconfig_item_t *ci) /* {{{ */
   node->timeout.tv_sec = 0;
   node->timeout.tv_usec = 1000;
   node->conn = NULL;
+  node->prefix = NULL;
+  node->database = 0;
+  node->max_set_size = -1;
+  node->store_rates = 1;
   pthread_mutex_init (&node->lock, /* attr = */ NULL);
 
   status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name));
@@ -214,6 +211,18 @@ static int wr_config_node (oconfig_item_t *ci) /* {{{ */
       status = cf_util_get_int (child, &timeout);
       if (status == 0) node->timeout.tv_usec = timeout;
     }
+    else if (strcasecmp ("Prefix", child->key) == 0) {
+      status = cf_util_get_string (child, &node->prefix);
+    }
+    else if (strcasecmp ("Database", child->key) == 0) {
+      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 ("StoreRates", child->key) == 0) {
+      status = cf_util_get_boolean (child, &node->store_rates);
+    }
     else
       WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".",
           child->key);
index a09c723..73d202c 100644 (file)
@@ -33,7 +33,6 @@
 #include "utils_cache.h"
 #include "riemann.pb-c.h"
 
-#include <sys/socket.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <netdb.h>
@@ -365,7 +364,7 @@ static Msg *riemann_notification_to_protobuf(struct riemann_host *host, /* {{{ *
        char service_buffer[6 * DATA_MAX_NAME_LEN];
        char const *severity;
        notification_meta_t *meta;
-       int i;
+       size_t i;
 
        msg = malloc (sizeof (*msg));
        if (msg == NULL)
@@ -474,7 +473,7 @@ static Event *riemann_value_to_protobuf(struct riemann_host const *host, /* {{{
        char name_buffer[5 * DATA_MAX_NAME_LEN];
        char service_buffer[6 * DATA_MAX_NAME_LEN];
        double ttl;
-       int i;
+       size_t i;
 
        event = malloc (sizeof (*event));
        if (event == NULL)
@@ -619,7 +618,7 @@ static Msg *riemann_value_list_to_protobuf (struct riemann_host const *host, /*
        msg__init (msg);
 
        /* Set up events. First, the list of pointers. */
-       msg->n_events = (size_t) vl->values_len;
+       msg->n_events = vl->values_len;
        msg->events = calloc (msg->n_events, sizeof (*msg->events));
        if (msg->events == NULL)
        {
@@ -744,8 +743,8 @@ static int riemann_batch_add_value_list (struct riemann_host *host, /* {{{ */
 
        len = msg__get_packed_size(host->batch_msg);
     ret = 0;
-    if (len >= host->batch_max) {
-        ret = riemann_batch_flush_nolock(0, host);
+    if ((host->batch_max < 0) || (((size_t) host->batch_max) <= len)) {
+           ret = riemann_batch_flush_nolock(0, host);
     }
 
     pthread_mutex_unlock(&host->lock);
@@ -778,35 +777,35 @@ static int riemann_notification(const notification_t *n, user_data_t *ud) /* {{{
 } /* }}} int riemann_notification */
 
 static int riemann_write(const data_set_t *ds, /* {{{ */
-             const value_list_t *vl,
-             user_data_t *ud)
+               const value_list_t *vl,
+               user_data_t *ud)
 {
        int                      status = 0;
        int                      statuses[vl->values_len];
        struct riemann_host     *host = ud->data;
-       Msg                     *msg;
-
-       if (host->check_thresholds)
-               write_riemann_threshold_check(ds, vl, statuses);
-
-    if (host->use_tcp == 1 && host->batch_mode) {
-
-        riemann_batch_add_value_list (host, ds, vl, statuses);
 
+       if (host->check_thresholds) {
+               status = write_riemann_threshold_check(ds, vl, statuses);
+               if (status != 0)
+                       return status;
+       } else {
+               memset (statuses, 0, sizeof (statuses));
+       }
 
-    } else {
+       if (host->use_tcp == 1 && host->batch_mode) {
+               riemann_batch_add_value_list (host, ds, vl, statuses);
+       } else {
+               Msg *msg = riemann_value_list_to_protobuf (host, ds, vl, statuses);
+               if (msg == NULL)
+                       return (-1);
 
-        msg = riemann_value_list_to_protobuf (host, ds, vl, statuses);
-        if (msg == NULL)
-            return (-1);
+               status = riemann_send (host, msg);
+               if (status != 0)
+                       ERROR ("write_riemann plugin: riemann_send failed with status %i", status);
 
-        status = riemann_send (host, msg);
-        if (status != 0)
-            ERROR ("write_riemann plugin: riemann_send failed with status %i",
-                   status);
+               riemann_msg_protobuf_free (msg);
+       }
 
-        riemann_msg_protobuf_free (msg);
-    }
        return status;
 } /* }}} int riemann_write */
 
index 6d5af03..5c8559e 100644 (file)
@@ -133,7 +133,7 @@ static int ut_check_one_threshold (const data_set_t *ds,
     int *statuses)
 { /* {{{ */
   int ret = -1;
-  int i;
+  size_t i;
   int status;
   gauge_t values_copy[ds->ds_num];
 
@@ -202,7 +202,9 @@ int write_riemann_threshold_check (const data_set_t *ds, const value_list_t *vl,
   gauge_t *values;
   int status;
 
+  assert (vl->values_len > 0);
   memset(statuses, 0, vl->values_len * sizeof(*statuses));
+
   if (threshold_tree == NULL)
          return 0;
 
index f7803e8..67c0496 100644 (file)
@@ -29,7 +29,6 @@
 #include "common.h"
 #include "configfile.h"
 #include "utils_cache.h"
-#include <sys/socket.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <netdb.h>
@@ -329,7 +328,7 @@ static char *sensu_value_to_json(struct sensu_host const *host, /* {{{ */
 {
        char name_buffer[5 * DATA_MAX_NAME_LEN];
        char service_buffer[6 * DATA_MAX_NAME_LEN];
-       int i;
+       size_t i;
        char *ret_str;
        char *temp_str;
        char *value_str;
@@ -641,7 +640,7 @@ static char *sensu_notification_to_json(struct sensu_host *host, /* {{{ */
        char *ret_str;
        char *temp_str;
        int status;
-       int i;
+       size_t i;
        int res;
        // add the severity/status
        switch (n->severity) {
@@ -883,7 +882,7 @@ static int sensu_write(const data_set_t *ds, /* {{{ */
        int statuses[vl->values_len];
        struct sensu_host       *host = ud->data;
        gauge_t *rates = NULL;
-       int i;
+       size_t i;
        char *msg;
 
        pthread_mutex_lock(&host->lock);
@@ -897,7 +896,7 @@ static int sensu_write(const data_set_t *ds, /* {{{ */
                        return -1;
                }
        }
-       for (i = 0; i < (size_t) vl->values_len; i++) {
+       for (i = 0; i < vl->values_len; i++) {
                msg = sensu_value_to_json(host, ds, vl, (int) i, rates, statuses[i]);
                if (msg == NULL) {
                        sfree(rates);
index 27ea473..4a62614 100644 (file)
@@ -49,7 +49,6 @@
 #include "utils_cache.h"
 
 #include <pthread.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 #ifndef WT_DEFAULT_NODE
@@ -411,7 +410,7 @@ static int wt_send_message (const char* key, const char* value,
                             const char* host, meta_data_t *md)
 {
     int status;
-    int message_len;
+    size_t message_len;
     char *temp = NULL;
     char *tags = "";
     char message[1024];
@@ -436,7 +435,7 @@ static int wt_send_message (const char* key, const char* value,
         }
     }
 
-    message_len = ssnprintf (message,
+    status = ssnprintf (message,
                              sizeof(message),
                              "put %s %.0f %s fqdn=%s %s %s\r\n",
                              key,
@@ -445,12 +444,14 @@ static int wt_send_message (const char* key, const char* value,
                              host,
                              tags,
                              host_tags);
-
     sfree(temp);
+    if (status < 0)
+        return -1;
+    message_len = (size_t) status;
 
     if (message_len >= sizeof(message)) {
         ERROR("write_tsdb plugin: message buffer too small: "
-              "Need %d bytes.", message_len + 1);
+              "Need %zu bytes.", message_len + 1);
         return -1;
     }
 
@@ -506,7 +507,8 @@ static int wt_write_messages(const data_set_t *ds, const value_list_t *vl,
     char key[10*DATA_MAX_NAME_LEN];
     char values[512];
 
-    int status, i;
+    int status;
+    size_t i;
 
     if (0 != strcmp(ds->type, vl->type))
     {
index f0d2323..dd633d5 100644 (file)
@@ -251,6 +251,9 @@ static int za_read (void)
 
        /* Sizes */
        za_read_gauge (ksp, "size",    "cache_size", "arc");
+       za_read_gauge (ksp, "c",    "cache_size", "c");
+       za_read_gauge (ksp, "c_min",    "cache_size", "c_min");
+       za_read_gauge (ksp, "c_max",    "cache_size", "c_max");
 
        /* The "l2_size" value has disappeared from Solaris some time in
         * early 2013, and has only reappeared recently in Solaris 11.2.
diff --git a/src/zone.c b/src/zone.c
new file mode 100644 (file)
index 0000000..15eae6a
--- /dev/null
@@ -0,0 +1,214 @@
+/**
+ * collectd - src/zone.c
+ * Copyright (C) 2011       Mathijs Mohlmann
+ *
+ * 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:
+ *   Mathijs Mohlmann
+ *   Dagobert Michelsen (forward-porting)
+ **/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+# undef HAVE_CONFIG_H
+#endif
+/* avoid procfs.h error "Cannot use procfs in the large file compilation environment" */
+#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
+#  undef _FILE_OFFSET_BITS
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/vm_usage.h>
+#include <procfs.h>
+#include <zone.h>
+
+#include "utils_avltree.h"
+
+#define        MAX_PROCFS_PATH 40
+#define FRC2PCT(pp)(((float)(pp))/0x8000*100)
+
+typedef struct zone_stats {
+       ushort_t      pctcpu;
+       ushort_t      pctmem;
+} zone_stats_t;
+
+static long pagesize;
+
+static int zone_init (void)
+{
+       pagesize = sysconf(_SC_PAGESIZE);
+       return (0);
+}
+
+static int
+zone_compare(const zoneid_t *a, const zoneid_t *b)
+{
+       if (*a == *b)
+               return(0);
+       if (*a < *b)
+               return(-1);
+       return(1);
+}
+
+static int
+zone_read_procfile(char const *pidstr, char const *name, void *buf, size_t bufsize)
+{
+       int fd;
+
+       char procfile[MAX_PROCFS_PATH];
+       (void)snprintf(procfile, sizeof(procfile), "/proc/%s/%s", pidstr, name);
+       if ((fd = open(procfile, O_RDONLY)) == -1) {
+               return (1);
+       }
+
+       if (sread(fd, buf, bufsize) != 0) {
+               char errbuf[1024];
+               ERROR ("zone plugin: Reading \"%s\" failed: %s", procfile,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               close(fd);
+               return (1);
+       }
+
+       close(fd);
+       return (0);
+}
+
+static int
+zone_submit_value(char *zone, gauge_t value)
+{
+       value_list_t vl = VALUE_LIST_INIT;
+       value_t      values[1];
+
+       values[0].gauge = value;
+
+       vl.values = values;
+       vl.values_len = 1; /*STATIC_ARRAY_SIZE (values);*/
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "zone", sizeof (vl.plugin));
+       sstrncpy (vl.type, "percent", sizeof (vl.type));
+       sstrncpy (vl.type_instance, zone, sizeof (vl.type_instance));
+
+       return(plugin_dispatch_values (&vl));
+}
+
+static zone_stats_t *
+zone_find_stats(c_avl_tree_t *tree, zoneid_t zoneid)
+{
+       zone_stats_t *ret = NULL;
+       zoneid_t     *key = NULL;
+
+       if (c_avl_get(tree, (void **)&zoneid, (void **)&ret)) {
+               if (!(ret = malloc(sizeof(zone_stats_t)))) {
+                       WARNING("zone plugin: no memory");
+                       return(NULL);
+               }
+               if (!(key = malloc(sizeof(zoneid_t)))) {
+                       WARNING("zone plugin: no memory");
+                       return(NULL);
+               }
+               *key = zoneid;
+               if (c_avl_insert(tree, key, ret)) {
+                       WARNING("zone plugin: error inserting into tree");
+                       return(NULL);
+               }
+       }
+       return(ret);
+}
+
+static void
+zone_submit_values(c_avl_tree_t *tree)
+{
+       char          zonename[ZONENAME_MAX];
+       zoneid_t     *zoneid = NULL;
+       zone_stats_t *stats  = NULL;
+
+       while (c_avl_pick (tree, (void **)&zoneid, (void **)&stats) == 0)
+       {
+               if (getzonenamebyid(*zoneid, zonename, sizeof( zonename )) == -1) {
+                       WARNING("zone plugin: error retreiving zonename");
+               } else {
+                       zone_submit_value(zonename, (gauge_t)FRC2PCT(stats->pctcpu));
+               }
+               free(stats);
+               free(zoneid);
+       }
+       c_avl_destroy(tree);
+}
+
+static c_avl_tree_t *
+zone_scandir(DIR *procdir)
+{
+       pid_t         pid;
+       dirent_t     *direntp;
+       psinfo_t      psinfo;
+       c_avl_tree_t *tree;
+       zone_stats_t *stats;
+
+       if (!(tree=c_avl_create((void *) zone_compare))) {
+               WARNING("zone plugin: Failed to create tree");
+               return(NULL);
+       }
+
+       rewinddir(procdir);
+       while ((direntp = readdir(procdir))) {
+               char const *pidstr = direntp->d_name;
+               if (pidstr[0] == '.')   /* skip "." and ".."  */
+                       continue;
+
+               pid = atoi(pidstr);
+               if (pid == 0 || pid == 2 || pid == 3)
+                       continue;       /* skip sched, pageout and fsflush */
+
+               if (zone_read_procfile(pidstr, "psinfo", &psinfo, sizeof(psinfo_t)) != 0)
+                       continue;
+
+               stats = zone_find_stats(tree, psinfo.pr_zoneid);
+               if( stats ) {
+                       stats->pctcpu += psinfo.pr_pctcpu;
+                       stats->pctmem += psinfo.pr_pctmem;
+               }
+       }
+       return(tree);
+}
+
+static int zone_read (void)
+{
+       DIR          *procdir;
+       c_avl_tree_t *tree;
+
+       if ((procdir = opendir("/proc")) == NULL) {
+               ERROR("zone plugin: cannot open /proc directory\n");
+               return (-1);
+       }
+
+       tree=zone_scandir(procdir);
+       closedir(procdir);
+       if (tree == NULL) {
+               return (-1);
+       }
+       zone_submit_values(tree); /* this also frees tree */
+       return (0);
+}
+
+void module_register (void)
+{
+       plugin_register_init ("zone", zone_init);
+       plugin_register_read ("zone", zone_read);
+} /* void module_register */
index 63ee6c9..abdbf20 100644 (file)
@@ -29,7 +29,6 @@
 #include "plugin.h"
 
 #include <netdb.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>