Merge branch 'collectd-5.5'
authorFlorian Forster <octo@collectd.org>
Sat, 5 Dec 2015 22:08:22 +0000 (23:08 +0100)
committerFlorian Forster <octo@collectd.org>
Sat, 5 Dec 2015 22:08:22 +0000 (23:08 +0100)
142 files changed:
.gitignore
.travis.yml [new file with mode: 0644]
AUTHORS
README
bindings/java/org/collectd/java/GenericJMXConfConnection.java
bindings/java/org/collectd/java/GenericJMXConfValue.java
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
src/Makefile.am
src/apache.c
src/apcups.c
src/ascent.c
src/barometer.c
src/bind.c
src/ceph.c
src/ceph_test.c
src/collectd-java.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_avltree_test.c
src/daemon/utils_cache.c
src/daemon/utils_cache_mock.c
src/daemon/utils_ignorelist.c
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 [deleted file]
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/notify_nagios.c [new file with mode: 0644]
src/ntpd.c
src/olsrd.c
src/onewire.c
src/openldap.c
src/openvpn.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/redis.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_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_kafka.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
version-gen.sh

index 54eaa97..e8d4953 100644 (file)
@@ -83,9 +83,19 @@ 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
+src/daemon/test_utils_time
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..435669b
--- /dev/null
@@ -0,0 +1,55 @@
+sudo: required
+dist: trusty
+compiler:
+  - gcc
+  - clang
+language: c
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq --no-install-recommends
+      libatasmart-dev
+      libcap-dev
+      libcurl4-gnutls-dev
+      libdbi0-dev
+      libesmtp-dev
+      libganglia1-dev
+      libgcrypt11-dev
+      libglib2.0-dev
+      libhiredis-dev
+      libi2c-dev
+      libldap2-dev
+      libltdl-dev
+      liblvm2-dev
+      libmemcached-dev
+      libmnl-dev
+      libmodbus-dev
+      libmosquitto0-dev
+      libmysqlclient-dev
+      libnotify-dev
+      libopenipmi-dev
+      liboping-dev
+      libow-dev
+      libpcap-dev
+      libperl-dev
+      libpq-dev
+      libprotobuf-c0-dev
+      librabbitmq-dev
+      librdkafka-dev
+      librrd-dev
+      libsensors4-dev
+      libsigrok-dev
+      libsnmp-dev
+      libstatgrab-dev
+      libtokyocabinet-dev
+      libtokyotyrant-dev
+      libudev-dev
+      libupsclient-dev
+      libvarnish-dev
+      libvirt-dev
+      libxml2-dev
+      libyajl-dev
+      linux-libc-dev
+      perl
+      protobuf-c-compiler
+      python-dev
+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 ea0f2fa..aced54b 100644 (file)
@@ -52,7 +52,8 @@ class GenericJMXConfConnection
   private String _host = null;
   private String _instance_prefix = null;
   private String _service_url = null;
-  private MBeanServerConnection _jmx_connection = null;
+  private JMXConnector _jmx_connector = null;
+  private MBeanServerConnection _mbean_connection = null;
   private List<GenericJMXConfMBean> _mbeans = null;
 
   /*
@@ -92,55 +93,72 @@ class GenericJMXConfConnection
     return Collectd.getHostname();
   } /* }}} String getHost */
 
-private void connect () /* {{{ */
-{
-  JMXServiceURL service_url;
-  JMXConnector connector;
-  Map environment;
+  private void connect () /* {{{ */
+  {
+    JMXServiceURL service_url;
+    Map<String,Object> environment;
 
-  if (_jmx_connection != null)
-    return;
+    // already connected
+    if (this._jmx_connector != null) {
+      return;
+    }
 
-  environment = null;
-  if (this._password != null)
-  {
-    String[] credentials;
+    environment = null;
+    if (this._password != null)
+    {
+      String[] credentials;
 
-    if (this._username == null)
-      this._username = new String ("monitorRole");
+      if (this._username == null)
+        this._username = new String ("monitorRole");
 
-    credentials = new String[] { this._username, this._password };
+      credentials = new String[] { this._username, this._password };
 
-    environment = new HashMap ();
-    environment.put (JMXConnector.CREDENTIALS, credentials);
-    environment.put(JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER, this.getClass().getClassLoader());
-  }
+      environment = new HashMap<String,Object> ();
+      environment.put (JMXConnector.CREDENTIALS, credentials);
+      environment.put (JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER, this.getClass().getClassLoader());
+    }
 
-  try
-  {
-    service_url = new JMXServiceURL (this._service_url);
-    connector = JMXConnectorFactory.connect (service_url, environment);
-    _jmx_connection = connector.getMBeanServerConnection ();
-  }
-  catch (Exception e)
+    try
+    {
+      service_url = new JMXServiceURL (this._service_url);
+      this._jmx_connector = JMXConnectorFactory.connect (service_url, environment);
+      this._mbean_connection = _jmx_connector.getMBeanServerConnection ();
+    }
+    catch (Exception e)
+    {
+      Collectd.logError ("GenericJMXConfConnection: "
+          + "Creating MBean server connection failed: " + e);
+      disconnect ();
+      return;
+    }
+  } /* }}} void connect */
+
+  private void disconnect () /* {{{ */
   {
-    Collectd.logError ("GenericJMXConfConnection: "
-        + "Creating MBean server connection failed: " + e);
-    return;
-  }
-} /* }}} void connect */
+    try
+    {
+      this._jmx_connector.close();
+    }
+    catch (Exception e)
+    {
+      // It's fine if close throws an exception
+    }
 
-/*
- * public methods
- *
- * <Connection>
- *   Host "tomcat0.mycompany"
- *   ServiceURL "service:jmx:rmi:///jndi/rmi://localhost:17264/jmxrmi"
- *   Collect "java.lang:type=GarbageCollector,name=Copy"
- *   Collect "java.lang:type=Memory"
- * </Connection>
- *
- */
+    this._jmx_connector = null;
+    this._mbean_connection = null;
+  } /* }}} void disconnect */
+
+  /*
+   * public methods
+   *
+   * <Connection>
+   *   Host "tomcat0.mycompany"
+   *   ServiceURL "service:jmx:rmi:///jndi/rmi://localhost:17264/jmxrmi"
+   *   Collect "java.lang:type=GarbageCollector,name=Copy"
+   *   Collect "java.lang:type=Memory"
+   * </Connection>
+   *
+   */
   public GenericJMXConfConnection (OConfigItem ci) /* {{{ */
     throws IllegalArgumentException
   {
@@ -217,9 +235,10 @@ private void connect () /* {{{ */
   {
     PluginData pd;
 
+    // try to connect
     connect ();
 
-    if (this._jmx_connection == null)
+    if (this._mbean_connection == null)
       return;
 
     Collectd.logDebug ("GenericJMXConfConnection.query: "
@@ -234,11 +253,11 @@ private void connect () /* {{{ */
     {
       int status;
 
-      status = this._mbeans.get (i).query (this._jmx_connection, pd,
+      status = this._mbeans.get (i).query (this._mbean_connection, pd,
           this._instance_prefix);
       if (status != 0)
       {
-        this._jmx_connection = null;
+        disconnect ();
         return;
       }
     } /* for */
index 4b42c91..25b70d4 100644 (file)
@@ -28,6 +28,7 @@ package org.collectd.java;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Collection;
 import java.util.Set;
 import java.util.Iterator;
 import java.util.ArrayList;
@@ -39,6 +40,7 @@ import javax.management.MBeanServerConnection;
 import javax.management.ObjectName;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
 import javax.management.openmbean.InvalidKeyException;
 
 import org.collectd.api.Collectd;
@@ -68,6 +70,7 @@ class GenericJMXConfValue
   private List<String> _attributes;
   private String _instance_prefix;
   private List<String> _instance_from;
+  private String _plugin_name;
   private boolean _is_table;
 
   /**
@@ -295,6 +298,46 @@ class GenericJMXConfValue
     {
       if (value instanceof CompositeData)
         return (queryAttributeRecursive ((CompositeData) value, attrName));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive ((TabularData) value, attrName));
+      else
+        return (null);
+    }
+  } /* }}} queryAttributeRecursive */
+
+  private Object queryAttributeRecursive (TabularData parent, /* {{{ */
+      List<String> attrName)
+  {
+    String key;
+    Object value = null;
+
+    key = attrName.remove (0);
+
+    TabularData tabularData = (TabularData) parent;
+    Collection<CompositeData> table =
+        (Collection<CompositeData>)tabularData.values();
+    for (CompositeData compositeData : table)
+    {
+      if (key.equals(compositeData.get("key")))
+      {
+        value = compositeData.get("value");
+      }
+    }
+    if (null == value)
+    {
+      return (null);
+    }
+
+    if (attrName.size () == 0)
+    {
+      return (value);
+    }
+    else
+    {
+      if (value instanceof CompositeData)
+        return (queryAttributeRecursive ((CompositeData) value, attrName));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive ((TabularData) value, attrName));
       else
         return (null);
     }
@@ -341,6 +384,8 @@ class GenericJMXConfValue
     {
       if (value instanceof CompositeData)
         return (queryAttributeRecursive((CompositeData) value, attrNameList));
+      else if (value instanceof TabularData)
+        return (queryAttributeRecursive((TabularData) value, attrNameList));
       else if (value instanceof OpenType)
       {
         OpenType ot = (OpenType) value;
@@ -351,7 +396,7 @@ class GenericJMXConfValue
       else
       {
         Collectd.logError ("GenericJMXConfValue: Received object of "
-            + "unknown class.");
+            + "unknown class. " + attrName + " " + ((value == null)?"null":value.getClass().getName()));
         return (null);
       }
     }
@@ -436,6 +481,7 @@ class GenericJMXConfValue
     this._attributes = new ArrayList<String> ();
     this._instance_prefix = null;
     this._instance_from = new ArrayList<String> ();
+    this._plugin_name = null;
     this._is_table = false;
 
     /*
@@ -485,6 +531,12 @@ class GenericJMXConfValue
         if (tmp != null)
           this._instance_from.add (tmp);
       }
+      else if (child.getKey ().equalsIgnoreCase ("PluginName"))
+      {
+        String tmp = getConfigString (child);
+        if (tmp != null)
+          this._plugin_name = tmp;
+      }
       else
         throw (new IllegalArgumentException ("Unknown option: "
               + child.getKey ()));
@@ -538,6 +590,10 @@ class GenericJMXConfValue
 
     vl = new ValueList (pd);
     vl.setType (this._ds_name);
+    if (this._plugin_name != null)
+    {
+      vl.setPlugin (this._plugin_name);
+    }
 
     /*
      * Build the instnace prefix from the fixed string prefix and the
index 5e79d26..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.
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 7fee375..4acd193 100644 (file)
@@ -2065,12 +2065,6 @@ then
        AC_CHECK_LIB(gcrypt, gcry_md_hash_buffer,
                [with_libgcrypt="yes"],
                [with_libgcrypt="no (symbol gcry_md_hash_buffer not found)"])
-
-       if test "$with_libgcrypt" != "no"; then
-               m4_ifdef([AM_PATH_LIBGCRYPT],[AM_PATH_LIBGCRYPT(1:1.2.0,,with_libgcrypt="no (version 1.2.0+ required)")])
-               GCRYPT_CPPFLAGS="$LIBGCRYPT_CPPFLAGS $LIBGCRYPT_CFLAGS"
-               GCRYPT_LIBS="$LIBGCRYPT_LIBS"
-       fi
 fi
 
 CPPFLAGS="$SAVE_CPPFLAGS"
@@ -2672,6 +2666,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=""
@@ -5210,6 +5251,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"
@@ -5260,6 +5302,7 @@ plugin_vmem="no"
 plugin_vserver="no"
 plugin_wireless="no"
 plugin_zfs_arc="no"
+plugin_zone="no"
 plugin_zookeeper="no"
 
 # Linux
@@ -5330,6 +5373,7 @@ fi
 
 if test "x$ac_system" = "xFreeBSD"
 then
+       plugin_disk="yes"
        plugin_zfs_arc="yes"
 fi
 
@@ -5358,6 +5402,7 @@ then
        plugin_processes="yes"
        plugin_uptime="yes"
        plugin_zfs_arc="yes"
+       plugin_zone="yes"
 fi
 
 if test "x$with_devinfo$with_kstat" = "xyesyes"
@@ -5653,6 +5698,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])
@@ -5662,6 +5708,7 @@ AC_PLUGIN([nfs],         [$plugin_nfs],        [NFS statistics])
 AC_PLUGIN([nginx],       [$with_libcurl],      [nginx statistics])
 AC_PLUGIN([notify_desktop], [$with_libnotify], [Desktop notifications])
 AC_PLUGIN([notify_email], [$with_libesmtp],    [Email notifier])
+AC_PLUGIN([notify_nagios], [yes],              [Nagios notification plugin])
 AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
 AC_PLUGIN([numa],        [$plugin_numa],       [NUMA virtual memory statistics])
 AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
@@ -5728,6 +5775,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
@@ -5879,6 +5927,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
 
@@ -5909,6 +5964,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
@@ -5932,6 +5998,7 @@ Configuration:
     libmnl  . . . . . . . $with_libmnl
     libmodbus . . . . . . $with_libmodbus
     libmongoc . . . . . . $with_libmongoc
+    libmosquitto  . . . . $with_libmosquitto
     libmysql  . . . . . . $with_libmysql
     libnetapp . . . . . . $with_libnetapp
     libnetsnmp  . . . . . $with_libnetsnmp
@@ -6031,6 +6098,7 @@ Configuration:
     memory  . . . . . . . $enable_memory
     mic . . . . . . . . . $enable_mic
     modbus  . . . . . . . $enable_modbus
+    mqtt  . . . . . . . . $enable_mqtt
     multimeter  . . . . . $enable_multimeter
     mysql . . . . . . . . $enable_mysql
     netapp  . . . . . . . $enable_netapp
@@ -6040,6 +6108,7 @@ Configuration:
     nginx . . . . . . . . $enable_nginx
     notify_desktop  . . . $enable_notify_desktop
     notify_email  . . . . $enable_notify_email
+    notify_nagios . . . . $enable_notify_nagios
     ntpd  . . . . . . . . $enable_ntpd
     numa  . . . . . . . . $enable_numa
     nut . . . . . . . . . $enable_nut
@@ -6105,6 +6174,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..4dfcc9a 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_nginx 0%{!?_without_nginx:1}
 %define with_notify_desktop 0%{!?_without_notify_desktop:1}
 %define with_notify_email 0%{!?_without_notify_email:1}
+%define with_notify_nagios 0%{!?_without_notify_nagios:1}
 %define with_ntpd 0%{!?_without_ntpd:1}
 %define with_numa 0%{!?_without_numa:1}
 %define with_nut 0%{!?_without_nut: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 +519,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 +1180,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
@@ -1213,6 +1234,12 @@ Collectd utilities
 %define _with_notify_email --disable-notify_email
 %endif
 
+%if %{with_notify_nagios}
+%define _with_notify_nagios --enable-notify_nagios
+%else
+%define _with_notify_nagios --disable-notify_nagios
+%endif
+
 %if %{with_ntpd}
 %define _with_ntpd --enable-ntpd
 %else
@@ -1571,6 +1598,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 +1672,7 @@ Collectd utilities
        %{?_with_mic} \
        %{?_with_modbus} \
        %{?_with_multimeter} \
+       %{?_with_mqtt} \
        %{?_with_mysql} \
        %{?_with_netapp} \
        %{?_with_netlink} \
@@ -1672,6 +1706,7 @@ Collectd utilities
        %{?_with_write_redis} \
        %{?_with_xmms} \
        %{?_with_zfs_arc} \
+       %{?_with_zone} \
        %{?_with_zookeeper} \
        %{?_with_irq} \
        %{?_with_load} \
@@ -1683,6 +1718,7 @@ Collectd utilities
        %{?_with_memory} \
        %{?_with_network} \
        %{?_with_nfs} \
+       %{?_with_notify_nagios} \
        %{?_with_ntpd} \
        %{?_with_numa} \
        %{?_with_olsrd} \
@@ -1949,6 +1985,9 @@ fi
 %if %{with_nfs}
 %{_libdir}/%{name}/nfs.so
 %endif
+%if %{with_notify_nagios}
+%{_libdir}/%{name}/notify_nagios.so
+%endif
 %if %{with_ntpd}
 %{_libdir}/%{name}/ntpd.so
 %endif
@@ -2196,6 +2235,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 +2379,11 @@ fi
 %doc contrib/
 
 %changelog
+#* TODO: next feature release changelog
+#- New upstream version
+#- New plugins enabled by default: mqtt, notify_nagios
+#- 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 d53ec0c..6267a31 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/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/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/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
@@ -316,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
@@ -444,6 +468,8 @@ 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
@@ -614,6 +640,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
@@ -704,6 +738,12 @@ notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 notify_email_la_LIBADD = -lesmtp -lssl -lcrypto -lpthread
 endif
 
+if BUILD_PLUGIN_NOTIFY_NAGIOS
+pkglib_LTLIBRARIES += notify_nagios.la
+notify_nagios_la_SOURCES = notify_nagios.c
+notify_nagios_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
 if BUILD_PLUGIN_NTPD
 pkglib_LTLIBRARIES += ntpd.la
 ntpd_la_SOURCES = ntpd.c
@@ -938,10 +978,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
@@ -1273,6 +1312,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 \
@@ -1370,16 +1416,6 @@ 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
-
 if BUILD_PLUGIN_CEPH
 test_plugin_ceph_SOURCES = ceph_test.c
 test_plugin_ceph_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
index 9c4b496..b306032 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 281bf98..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,26 +107,21 @@ 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];
@@ -179,7 +165,7 @@ static int net_open (char *host, int port)
        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 ("apcups plugin: 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 27164fd..dd49cb2 100644 (file)
@@ -1760,7 +1760,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 251def9..2a85823 100644 (file)
@@ -45,7 +45,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 ae67125..acab179 100644 (file)
@@ -170,11 +170,8 @@ DEF_TEST(parse_keys)
   {
     char got[DATA_MAX_NAME_LEN];
 
-    memset (got, 0, sizeof (got));
-
     CHECK_ZERO (parse_keys (got, sizeof (got), cases[i].str));
-
-    CHECK_ZERO (strcmp (got, cases[i].want));
+    EXPECT_EQ_STR (cases[i].want, got);
   }
 
   return 0;
index aade08a..afa7e48 100644 (file)
@@ -620,6 +620,11 @@ sets the type instance instead. I<(optional)>
 Works like the option of the same name directly beneath the I<MBean> block, but
 sets the type instance instead. I<(optional)>
 
+=item B<PluginName> I<name>
+
+When set, overrides the default setting for the I<plugin> field
+(C<GenericJMX>).
+
 =item B<Table> B<true>|B<false>
 
 Set this to true if the returned attribute is a I<composite type>. If set to
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 729aa03..eb23023 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_NGINX_TRUE@LoadPlugin nginx
 #@BUILD_PLUGIN_NOTIFY_DESKTOP_TRUE@LoadPlugin notify_desktop
 #@BUILD_PLUGIN_NOTIFY_EMAIL_TRUE@LoadPlugin notify_email
+#@BUILD_PLUGIN_NOTIFY_NAGIOS_TRUE@LoadPlugin notify_nagios
 #@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
 #@BUILD_PLUGIN_NUMA_TRUE@LoadPlugin numa
 #@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
 #@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>
 #      </Host>
 #</Plugin>
 
+#<Plugin mqtt>
+#      <Publish "name">
+#              Host "localhost"
+#              Port 1883
+#              ClientId "localhost"
+#              User "user"
+#              Password "secret"
+#              QoS 0
+#              Prefix "collectd"
+#              StoreRates true
+#              Retain false
+#              CACert "/etc/ssl/ca.crt"
+#              CertificateFile "/etc/ssl/client.crt"
+#              CertificateKeyFile "/etc/ssl/client.pem"
+#              TLSProtocol "tlsv1.2"
+#              CipherSuite "ciphers"
+#      </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"
 #      Recipient "email2@domain2.com"
 #</Plugin>
 
+#<Plugin notify_nagios>
+#      CommandFile "/usr/local/nagios/var/rw/nagios.cmd"
+#</Plugin>
+
 #<Plugin ntpd>
 #      Host "localhost"
 #      Port 123
 #  DeleteTimers   false
 #  DeleteGauges   false
 #  DeleteSets     false
+#  CounterSum     false
 #  TimerPercentile 90.0
 #  TimerPercentile 95.0
 #  TimerPercentile 99.0
 #    Host "localhost"
 #    Port "2003"
 #    Protocol "tcp"
+#    ReconnectInterval 0
 #    LogSendErrors true
 #    Prefix "collectd"
 #    Postfix "collectd"
 #              Host "localhost"
 #              Port "6379"
 #              Timeout 1000
+#              Prefix "collectd/"
 #      </Node>
 #</Plugin>
 
index 8189e97..a5af576 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,146 @@ 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.
+
+=item B<CACert> I<file>
+
+Path to the PEM-encoded CA certificate file. Setting this option enables TLS
+communication with the MQTT broker, and as such, B<Port> should be the TLS-enabled
+port of the MQTT broker.
+A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+
+=item B<CertificateFile> I<file>
+
+Path to the PEM-encoded certificate file to use as client certificate when
+connecting to the MQTT broker.
+A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+
+=item B<CertificateKeyFile> I<file>
+
+Path to the unencrypted PEM-encoded key file corresponding to B<CertificateFile>.
+A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+
+=item B<TLSProtocol> I<protocol>
+
+If configured, this specifies the string protocol version (e.g. C<tlsv1>,
+C<tlsv1.2>) to use for the TLS connection to the broker. If not set a default
+version is used which depends on the version of OpenSSL the Mosquitto library
+was linked against.
+
+=item B<CipherSuite> I<ciphersuite>
+
+A string describing the ciphers available for use. See L<ciphers(1)> and the
+C<openssl ciphers> utility for more information. If unset, the default ciphers
+will be used.
+
+
+=back
+
 =head2 Plugin C<mysql>
 
 The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
@@ -4269,6 +4436,21 @@ Default: C<Collectd notify: %s@%s>
 
 =back
 
+=head2 Plugin C<notify_nagios>
+
+The I<notify_nagios> plugin writes notifications to Nagios' I<command file> as
+a I<passive service check result>.
+
+Available configuration options:
+
+=over 4
+
+=item B<CommandFile> I<Path>
+
+Sets the I<command file> to write to. Defaults to F</usr/local/nagios/var/rw/nagios.cmd>.
+
+=back
+
 =head2 Plugin C<ntpd>
 
 =over 4
@@ -4494,6 +4676,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.
@@ -4765,6 +4957,13 @@ Default: B<0.9>
 
 Sets the Time-To-Live of generated ICMP packets.
 
+=item B<Size> I<size>
+
+Sets the size of the data payload in ICMP packet to specified I<size> (it
+will be filled with regular ASCII pattern). If not set, default 56 byte
+long string is used so that the packet size of an ICMPv4 packet is exactly
+64 bytes, similar to the behaviour of normal ping(1) command.
+
 =item B<SourceAddress> I<host>
 
 Sets the source address to use. I<host> may either be a numerical network
@@ -5422,6 +5621,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>
@@ -6036,6 +6239,12 @@ rate of counters and size of sets will be zero, timers report C<NaN> and gauges
 are unchanged. If set to B<True>, the such metrics are not dispatched and
 removed from the internal cache.
 
+=item B<CounterSum> B<false>|B<true>
+
+When enabled, create a C<count> metric which reports the change since the last
+read. This option primarily exists for compatibility with the I<statsd>
+impelemtation by Etsy.
+
 =item B<TimerPercentile> I<Percent>
 
 Calculate and dispatch the configured percentile, i.e. compute the latency, so
@@ -6990,17 +7199,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
 
@@ -7075,6 +7284,14 @@ Service name or port number to connect to. Defaults to C<2003>.
 
 Protocol to use when connecting to I<Graphite>. Defaults to C<tcp>.
 
+=item B<ReconnectInterval> I<Seconds>
+
+When set to non-zero, forces the connection to the Graphite backend to be
+closed and re-opend periodically. This behavior is desirable in environments
+where the connection to the Graphite backend is done through load balancers,
+for example. When set to zero, the default, the connetion is kept open for as
+long as possible.
+
 =item B<LogSendErrors> B<false>|B<true>
 
 If set to B<true> (the default), logs errors when sending data to I<Graphite>.
@@ -7343,6 +7560,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 +7690,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. Additionally, 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
+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.
 
@@ -7511,6 +7738,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>
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 c946250..7f8c985 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -536,11 +536,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);
@@ -554,12 +555,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 0772873..7b513e7 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));
@@ -187,7 +187,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..69d45e3 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>
 
@@ -132,17 +131,11 @@ static size_t cj_curl_callback (void *buf, /* {{{ */
     return (len);
 #endif
 
-  if (status != yajl_status_ok)
-  {
-    unsigned char *msg =
-      yajl_get_error(db->yajl, /* verbose = */ 1,
-          /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
-    ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
-    yajl_free_error(db->yajl, msg);
-    return (0); /* abort write callback */
-  }
-
-  return (len);
+  unsigned char *msg = yajl_get_error(db->yajl, /* verbose = */ 1,
+        /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
+  ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
+  yajl_free_error(db->yajl, msg);
+  return (0); /* abort write callback */
 } /* }}} size_t cj_curl_callback */
 
 static int cj_get_type (cj_key_t *key)
@@ -563,7 +556,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 +648,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 +755,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 +770,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 efaf290..e83ac2d 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++)
@@ -904,8 +904,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);
@@ -1023,7 +1022,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 95fb947..cdd927b 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,21 @@ 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
 
-libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c utils_time_mock.c
+libmetadata_la_SOURCES = meta_data.c meta_data.h
+
+libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c \
+                           utils_time.c utils_time.h
+libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME
+libplugin_mock_la_LIBADD = $(COMMON_LIBS) libcommon.la
 
 collectd_SOURCES = collectd.c collectd.h \
                   configfile.c configfile.h \
@@ -74,7 +76,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
@@ -90,14 +92,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 = 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 = libplugin_mock.la
index ad06999..06125dc 100644 (file)
@@ -32,7 +32,6 @@
 #include "configfile.h"
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <netdb.h>
 
@@ -425,15 +424,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");
 
@@ -442,49 +444,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 fba51ef..dd4f9b1 100644 (file)
@@ -46,7 +46,6 @@
 
 /* for getaddrinfo */
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 #include <poll.h>
@@ -259,8 +258,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);
@@ -300,8 +299,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);
@@ -372,7 +371,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)
@@ -507,8 +506,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);
 
@@ -681,8 +680,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);
@@ -962,7 +961,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));
@@ -1165,7 +1164,7 @@ 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;
@@ -1173,9 +1172,10 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
        if ((buffer == NULL) || (vl == NULL) || (ds == NULL))
                return EINVAL;
 
-       i = -1;
+       i = 0;
        dummy = buffer;
        saveptr = NULL;
+       vl->time = 0;
        while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
        {
                dummy = NULL;
@@ -1183,11 +1183,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 ();
@@ -1206,19 +1206,19 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
 
                                vl->time = DOUBLE_TO_CDTIME_T (tmp);
                        }
+
+                       continue;
                }
-               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;
-               }
+
+               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 */
@@ -1380,10 +1380,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
        {
@@ -1488,11 +1487,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)
@@ -1504,50 +1502,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 16e0724..89b0be0 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 e7d4e8d..0919bdf 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
  */
@@ -282,7 +288,7 @@ static int register_callback (llist_t **list, /* {{{ */
                {
                        ERROR ("plugin: register_callback: "
                                        "llentry_create failed.");
-                       free (key);
+                       sfree (key);
                        destroy_callback (cf);
                        return (-1);
                }
@@ -352,9 +358,9 @@ static void log_list_callbacks (llist_t **list, /* {{{ */
                *str = '\0';
                strjoin(str, len, keys, n, "', '");
                INFO("%s ['%s']", comment, str);
-               free(str);
+               sfree (str);
        }
-       free(keys);
+       sfree (keys);
 } /* }}} void log_list_callbacks */
 
 static int create_register_callback (llist_t **list, /* {{{ */
@@ -477,7 +483,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
        {
                read_func_t *rf;
                plugin_ctx_t old_ctx;
+               cdtime_t start;
                cdtime_t now;
+               cdtime_t elapsed;
                int status;
                int rf_type;
                int rc;
@@ -556,6 +564,8 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
 
                DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
 
+               start = cdtime ();
+
                old_ctx = plugin_set_ctx (rf->rf_ctx);
 
                if (rf_type == RF_SIMPLE)
@@ -599,8 +609,22 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                /* update the ``next read due'' field */
                now = cdtime ();
 
+               /* calculate the time spent in the read function */
+               elapsed = (now - start);
+
+               if (elapsed > rf->rf_effective_interval)
+                       WARNING ("plugin_read_thread: read-function of the `%s' plugin took %.3f "
+                               "seconds, which is above its read interval (%.3f seconds). You might "
+                               "want to adjust the `Interval' or `ReadThreads' settings.",
+                               rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed),
+                               CDTIME_T_TO_DOUBLE(rf->rf_effective_interval));
+
+               DEBUG ("plugin_read_thread: read-function of the `%s' plugin took "
+                               "%.6f seconds.",
+                               rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed));
+
                DEBUG ("plugin_read_thread: Effective interval of the "
-                               "%s plugin is %.3f seconds.",
+                               "`%s' plugin is %.3f seconds.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
 
@@ -617,7 +641,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                        rf->rf_next_read = now;
                }
 
-               DEBUG ("plugin_read_thread: Next read of the %s plugin at %.3f.",
+               DEBUG ("plugin_read_thread: Next read of the `%s' plugin at %.3f.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_next_read));
 
@@ -883,7 +907,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 +948,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");
        }
@@ -935,17 +959,17 @@ static void stop_write_threads (void) /* {{{ */
  */
 void plugin_set_dir (const char *dir)
 {
-       if (plugindir != NULL)
-               free (plugindir);
+       sfree (plugindir);
 
        if (dir == NULL)
-               plugindir = NULL;
-       else if ((plugindir = strdup (dir)) == NULL)
        {
-               char errbuf[1024];
-               ERROR ("strdup failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               plugindir = NULL;
+               return;
        }
+
+       plugindir = strdup (dir);
+       if (plugindir == NULL)
+               ERROR ("plugin_set_dir: strdup(\"%s\") failed", dir);
 }
 
 static _Bool plugin_is_loaded (char const *name)
@@ -1083,6 +1107,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 +1272,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 +1293,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 +1324,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 +1463,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))
@@ -1371,7 +1487,7 @@ int plugin_register_data_set (const data_set_t *ds)
                        * ds->ds_num);
        if (ds_copy->ds == NULL)
        {
-               free (ds_copy);
+               sfree (ds_copy);
                return (-1);
        }
 
@@ -1525,7 +1641,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)
@@ -2031,8 +2161,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);
        }
@@ -2085,7 +2215,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
                         * don't get confused.. */
                        if (saved_values != NULL)
                        {
-                               free (vl->values);
+                               sfree (vl->values);
                                vl->values     = saved_values;
                                vl->values_len = saved_values_len;
                        }
@@ -2114,7 +2244,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
         * confused.. */
        if (saved_values != NULL)
        {
-               free (vl->values);
+               sfree (vl->values);
                vl->values     = saved_values;
                vl->values_len = saved_values_len;
        }
@@ -2600,7 +2730,11 @@ int plugin_notification_meta_free (notification_meta_t *n)
 
     if (this->type == NM_TYPE_STRING)
     {
-      free ((char *)this->nm_value.nm_string);
+      /* Assign to a temporary variable to work around nm_string's const
+       * modifier. */
+      void *tmp = (void *) this->nm_value.nm_string;
+
+      sfree (tmp);
       this->nm_value.nm_string = NULL;
     }
     sfree (this);
@@ -2707,7 +2841,7 @@ static void *plugin_thread_start (void *arg)
 
        plugin_set_ctx (plugin_thread->ctx);
 
-       free (plugin_thread);
+       sfree (plugin_thread);
 
        return start_routine (plugin_arg);
 } /* void *plugin_thread_start */
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 f3eefd5..b6efa3a 100644 (file)
 
 #include "plugin.h"
 
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc = NULL;
+#endif /* HAVE_LIBKSTAT */
+
 char hostname_g[] = "example.com";
 
 int plugin_register_complex_config (const char *type, int (*callback) (oconfig_item_t *))
index c0e61c5..cf28c2e 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)
@@ -122,14 +122,18 @@ static void parse_line (char *buf)
   ds->ds_num = fields_num - 1;
   ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
   if (ds->ds == NULL)
+  {
+    sfree (ds);
     return;
+  }
 
   for (i = 0; i < ds->ds_num; i++)
     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);
+      sfree (ds->ds);
+      sfree (ds);
       return;
     }
 
index 2a8244c..6dbafe1 100644 (file)
@@ -27,6 +27,7 @@
 #include "testing.h"
 #include "collectd.h"
 #include "utils_avltree.h"
+#include "common.h" /* STATIC_ARRAY_SIZE */
 
 static int compare_total_count = 0;
 #define RESET_COUNTS() do { compare_total_count = 0; } while (0)
@@ -42,30 +43,99 @@ static int compare_callback (void const *v0, void const *v1)
 
 DEF_TEST(success)
 {
+  struct {
+    char *key;
+    char *value;
+  } cases[] = {
+    {"Eeph7chu", "vai1reiV"},
+    {"igh3Paiz", "teegh1Ee"},
+    {"caip6Uu8", "ooteQu8n"},
+    {"Aech6vah", "AijeeT0l"},
+    {"Xah0et2L", "gah8Taep"},
+    {"BocaeB8n", "oGaig8io"},
+    {"thai8AhM", "ohjeFo3f"},
+    {"ohth6ieC", "hoo8ieWo"},
+    {"aej7Woow", "phahuC2s"},
+    {"Hai8ier2", "Yie6eimi"},
+    {"phuXi3Li", "JaiF7ieb"},
+    {"Shaig5ef", "aihi5Zai"},
+    {"voh6Aith", "Oozaeto0"},
+    {"zaiP5kie", "seep5veM"},
+    {"pae7ba7D", "chie8Ojo"},
+    {"Gou2ril3", "ouVoo0ha"},
+    {"lo3Thee3", "ahDu4Zuj"},
+    {"Rah8kohv", "ieShoc7E"},
+    {"ieN5engi", "Aevou1ah"},
+    {"ooTe4OhP", "aingai5Y"},
+  };
+
   c_avl_tree_t *t;
-  char key_orig[] = "foo";
-  char value_orig[] = "bar";
-  char *key_ret = NULL;
-  char *value_ret = NULL;
+  size_t i;
 
   RESET_COUNTS ();
-  t = c_avl_create (compare_callback);
-  OK (t != NULL);
+  CHECK_NOT_NULL (t = c_avl_create (compare_callback));
+
+  /* insert */
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++)
+  {
+    char *key;
+    char *value;
 
-  OK (c_avl_insert (t, key_orig, value_orig) == 0);
-  OK (c_avl_size (t) == 1);
+    CHECK_NOT_NULL (key = strdup (cases[i].key));
+    CHECK_NOT_NULL (value = strdup (cases[i].value));
+
+    CHECK_ZERO (c_avl_insert (t, key, value));
+    EXPECT_EQ_INT ((int) (i + 1), c_avl_size (t));
+  }
 
   /* Key already exists. */
-  OK (c_avl_insert (t, "foo", "qux") > 0);
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++)
+    EXPECT_EQ_INT (1, c_avl_insert (t, cases[i].key, cases[i].value));
+
+  /* get */
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++)
+  {
+    char *value_ret = NULL;
+
+    CHECK_ZERO (c_avl_get (t, cases[i].key, (void *) &value_ret));
+    EXPECT_EQ_STR (cases[i].value, value_ret);
+  }
+
+  /* remove half */
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases) / 2; i++)
+  {
+    char *key = NULL;
+    char *value = NULL;
+
+    int expected_size = (int) (STATIC_ARRAY_SIZE (cases) - (i + 1));
+
+    CHECK_ZERO (c_avl_remove (t, cases[i].key, (void *) &key, (void *) &value));
+
+    EXPECT_EQ_STR (cases[i].key, key);
+    EXPECT_EQ_STR (cases[i].value, value);
+
+    free (key);
+    free (value);
+
+    EXPECT_EQ_INT (expected_size, c_avl_size (t));
+  }
+
+  /* pick the other half */
+  for (i = STATIC_ARRAY_SIZE (cases) / 2; i < STATIC_ARRAY_SIZE (cases); i++)
+  {
+    char *key = NULL;
+    char *value = NULL;
+
+    int expected_size = (int) (STATIC_ARRAY_SIZE (cases) - (i + 1));
+
+    EXPECT_EQ_INT (expected_size + 1, c_avl_size (t));
+    EXPECT_EQ_INT (0, c_avl_pick (t, (void *) &key, (void *) &value));
 
-  OK (c_avl_get (t, "foo", (void *) &value_ret) == 0);
-  OK (value_ret == &value_orig[0]);
+    free (key);
+    free (value);
 
-  key_ret = value_ret = NULL;
-  OK (c_avl_remove (t, "foo", (void *) &key_ret, (void *) &value_ret) == 0);
-  OK (key_ret == &key_orig[0]);
-  OK (value_ret == &value_orig[0]);
-  OK (c_avl_size (t) == 0);
+    EXPECT_EQ_INT (expected_size, c_avl_size (t));
+  }
 
   c_avl_destroy (t);
 
index 00de85a..e2c6426 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);
   }
 
@@ -375,7 +375,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)
   {
@@ -413,23 +413,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;
@@ -443,9 +427,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));
@@ -467,7 +449,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. */
@@ -567,7 +549,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);
 }
index 7b1c7d2..a8ca7db 100644 (file)
@@ -89,69 +89,45 @@ static inline void ignorelist_append (ignorelist_t *il, ignorelist_item_t *item)
 }
 
 #if HAVE_REGEX_H
-static int ignorelist_append_regex(ignorelist_t *il, const char *entry)
+static int ignorelist_append_regex(ignorelist_t *il, const char *re_str)
 {
-       int rcompile;
-       regex_t *regtemp;
-       int errsize;
-       char *regerr = NULL;
-       ignorelist_item_t *new;
+       regex_t *re;
+       ignorelist_item_t *entry;
+       int status;
 
-       /* create buffer */
-       if ((regtemp = malloc(sizeof(regex_t))) == NULL)
+       re = malloc (sizeof (*re));
+       if (re == NULL)
        {
-               ERROR ("cannot allocate new config entry");
-               return (1);
+               ERROR ("utils_ignorelist: malloc failed");
+               return (ENOMEM);
        }
-       memset (regtemp, '\0', sizeof(regex_t));
+       memset (re, 0, sizeof (*re));
 
-       /* compile regex */
-       if ((rcompile = regcomp (regtemp, entry, REG_EXTENDED)) != 0)
+       status = regcomp (re, re_str, REG_EXTENDED);
+       if (status != 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);
+               char errbuf[1024] = "";
+               regerror (status, re, errbuf, sizeof (errbuf));
+               ERROR ("utils_ignorelist: regcomp failed: %s", errbuf);
+               regfree (re);
+               sfree (re);
+               return (status);
        }
-       DEBUG("regex compiled: %s - %i", entry, rcompile);
 
-       /* create new entry */
-       if ((new = malloc(sizeof(ignorelist_item_t))) == NULL)
+       entry = malloc (sizeof (*entry));
+       if (entry == NULL)
        {
-               ERROR ("cannot allocate new config entry");
-               regfree (regtemp);
-               sfree (regtemp);
-               return (1);
+               ERROR ("utils_ignorelist: malloc failed");
+               regfree (re);
+               sfree (re);
+               return (ENOMEM);
        }
-       memset (new, '\0', sizeof(ignorelist_item_t));
-       new->rmatch = regtemp;
-
-       /* append new entry */
-       ignorelist_append (il, new);
+       memset (entry, 0, sizeof (*entry));
+       entry->rmatch = re;
 
+       ignorelist_append (il, entry);
        return (0);
-} /* int ignorelist_append_regex(ignorelist_t *il, const char *entry) */
+} /* int ignorelist_append_regex */
 #endif
 
 static int ignorelist_append_string(ignorelist_t *il, const char *entry)
@@ -282,11 +258,10 @@ void ignorelist_set_invert (ignorelist_t *il, int invert)
 
 /*
  * append entry into ignorelist_t
- * return 1 for success
+ * return 0 for success
  */
 int ignorelist_add (ignorelist_t *il, const char *entry)
 {
-       int ret;
        size_t entry_len;
 
        if (il == NULL)
@@ -310,24 +285,20 @@ int ignorelist_add (ignorelist_t *il, const char *entry)
        {
                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);
 
-               DEBUG("I'm about to add regex entry: %s", entry_copy);
-               ret = ignorelist_append_regex(il, entry_copy);
+               status = ignorelist_append_regex(il, entry_copy);
                sfree (entry_copy);
+               return status;
        }
-       else
 #endif
-       {
-               DEBUG("to add entry: %s", entry);
-               ret = ignorelist_append_string(il, entry);
-       }
 
-       return (ret);
+       return ignorelist_append_string(il, entry);
 } /* int ignorelist_add (ignorelist_t *il, const char *entry) */
 
 /*
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..7f482da 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_time.c
- * Copyright (C) 2010       Florian octo Forster
+ * 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>
  **/
 
 #include "collectd.h"
 #include "plugin.h"
 #include "common.h"
 
-#if HAVE_CLOCK_GETTIME
+#ifndef DEFAULT_MOCK_TIME
+# define DEFAULT_MOCK_TIME 1542455354518929408ULL
+#endif
+
+#ifdef MOCK_TIME
+cdtime_t cdtime_mock = (cdtime_t) MOCK_TIME;
+
+cdtime_t cdtime (void)
+{
+  return cdtime_mock;
+}
+#else /* !MOCK_TIME */
+# if HAVE_CLOCK_GETTIME
 cdtime_t cdtime (void) /* {{{ */
 {
   int status;
@@ -46,7 +58,7 @@ cdtime_t cdtime (void) /* {{{ */
 
   return (TIMESPEC_TO_CDTIME_T (&ts));
 } /* }}} cdtime_t cdtime */
-#else
+# else /* !HAVE_CLOCK_GETTIME */
 /* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
 cdtime_t cdtime (void) /* {{{ */
 {
@@ -64,41 +76,88 @@ cdtime_t cdtime (void) /* {{{ */
 
   return (TIMEVAL_TO_CDTIME_T (&tv));
 } /* }}} cdtime_t cdtime */
+# endif
 #endif
 
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */
+/* format_zone reads time zone information from "extern long timezone", exported
+ * by <time.h>, and formats it according to RFC 3339. This differs from
+ * strftime()'s "%z" format by including a colon between hour and minute. */
+static void format_zone (char *buffer, size_t buffer_size) /* {{{ */
+{
+  _Bool east = 0;
+  long hours;
+  long minutes;
+
+  minutes = timezone / 60;
+  if (minutes == 0) {
+    sstrncpy (buffer, "Z", buffer_size);
+    return;
+  }
+
+  if (minutes < 0)
+  {
+    east = 1;
+    minutes = minutes * (-1);
+  }
+
+  hours = minutes / 60;
+  minutes = minutes % 60;
+
+  ssnprintf (buffer, buffer_size, "%s%02ld:%02ld",
+             (east ? "+" : "-"), hours, minutes);
+} /* }}} int format_zone */
+
+static int format_rfc3339 (char *buffer, size_t buffer_size, cdtime_t t, _Bool print_nano) /* {{{ */
 {
   struct timespec t_spec;
   struct tm t_tm;
-
+  char base[20]; /* 2006-01-02T15:04:05 */
+  char nano[11]; /* .999999999 */
+  char zone[7];  /* +00:00 */
+  char *fields[] = {base, nano, zone};
   size_t len;
 
   CDTIME_T_TO_TIMESPEC (t, &t_spec);
   NORMALIZE_TIMESPEC (t_spec);
 
-  if (localtime_r ((time_t *)&t_spec.tv_sec, &t_tm) == NULL) {
+  if (localtime_r (&t_spec.tv_sec, &t_tm) == NULL) {
     char errbuf[1024];
-    ERROR ("cdtime_to_iso8601: localtime_r failed: %s",
-        sstrerror (errno, errbuf, sizeof (errbuf)));
-    return (0);
+    int status = errno;
+    ERROR ("format_rfc3339: localtime_r failed: %s",
+        sstrerror (status, errbuf, sizeof (errbuf)));
+    return (status);
   }
 
-  len = strftime (s, max, "%Y-%m-%dT%H:%M:%S", &t_tm);
+  len = strftime (base, sizeof (base), "%Y-%m-%dT%H:%M:%S", &t_tm);
   if (len == 0)
-    return 0;
+    return ENOMEM;
 
-  if (max - len > 2) {
-    int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec);
-    len += (n < max - len) ? n : max - len;
-  }
+  if (print_nano)
+    ssnprintf (nano, sizeof (nano), ".%09ld", (long) t_spec.tv_nsec);
+  else
+    sstrncpy (nano, "", sizeof (nano));
 
-  if (max - len > 3) {
-    int n = strftime (s + len, max - len, "%z", &t_tm);
-    len += (n < max - len) ? n : max - len;
-  }
+  format_zone (zone, sizeof (zone));
+
+  if (strjoin (buffer, buffer_size, fields, STATIC_ARRAY_SIZE (fields), "") < 0)
+    return ENOMEM;
+  return 0;
+} /* }}} int cdtime_to_rfc3339nano */
+
+int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339_SIZE)
+    return ENOMEM;
+
+  return format_rfc3339 (buffer, buffer_size, t, 0);
+} /* }}} size_t cdtime_to_rfc3339 */
+
+int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339NANO_SIZE)
+    return ENOMEM;
 
-  s[max - 1] = '\0';
-  return len;
-} /* }}} size_t cdtime_to_iso8601 */
+  return format_rfc3339 (buffer, buffer_size, t, 1);
+} /* }}} size_t cdtime_to_rfc3339nano */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
index 9b08e8e..9e98040 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
 
 #include "collectd.h"
 
+#ifdef TESTING_H
+/* cdtime_mock is the time returned by cdtime() when build with
+ * -DMOCK_TIME */
+extern cdtime_t cdtime_mock;
+#endif
+
 /*
  * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
  * resolution, i.e. the most significant 34 bit are used to store the time in
 /* 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);
 
-/* format a cdtime_t value in ISO 8601 format:
- * returns the number of characters written to the string (not including the
- * terminating null byte or 0 on error; the function ensures that the string
- * is null terminated */
-size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t);
+#define RFC3339_SIZE     26
+#define RFC3339NANO_SIZE 36
+
+/* rfc3339 formats a cdtime_t time in RFC 3339 format with second precision. */
+int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t);
+
+/* rfc3339nano formats a cdtime_t time in RFC 3339 format with nanosecond
+ * precision. */
+int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t);
 
 #endif /* UTILS_TIME_H */
 /* vim: set sw=2 sts=2 et : */
diff --git a/src/daemon/utils_time_mock.c b/src/daemon/utils_time_mock.c
deleted file mode 100644 (file)
index 5edfe6f..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * collectd - src/tests/mock/utils_time.c
- * Copyright (C) 2013       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 "utils_time.h"
-
-cdtime_t cdtime (void)
-{
-  return (0);
-}
-
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 590b693..027a232 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 0f56bd2..77819c2 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 a3b8fdf..7a866ee 100644 (file)
@@ -89,6 +89,7 @@ static int server_close_socket (lcc_server_t *srv) /* {{{ */
     return (0);
 
   close (srv->fd);
+  srv->fd = -1;
   free (srv->sa);
   srv->sa = NULL;
   srv->sa_len = 0;
@@ -107,12 +108,6 @@ static void int_server_destroy (lcc_server_t *srv) /* {{{ */
 
   next = srv->next;
 
-  if (srv->fd >= 0)
-  {
-    close (srv->fd);
-    srv->fd = -1;
-  }
-
   free (srv->node);
   free (srv->service);
   free (srv->username);
@@ -397,7 +392,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))
@@ -425,7 +420,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;
 
@@ -461,8 +456,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 7987378..d0b2f83 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 d650f02..d7578b6 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 97b98b7..d2b0a53 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);
@@ -1020,18 +1020,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..8bc412c
--- /dev/null
@@ -0,0 +1,810 @@
+/**
+ * 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>
+ *   Jan-Piet Mens <jpmens at gmail.com>
+ **/
+
+// 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
+#ifndef SSL_VERIFY_PEER
+# define SSL_VERIFY_PEER  1
+#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;
+    char                *cacertificatefile;
+    char                *certificatefile;
+    char                *certificatekeyfile;
+    char                *tlsprotocol;
+    char                *ciphersuite;
+
+    /* 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) {
+        DEBUG ("mqtt plugin: message has empty payload");
+        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 = malloc (msg->payloadlen+1);
+    if (payload == NULL)
+    {
+        ERROR ("mqtt plugin: malloc for payload buffer failed.");
+        sfree (vl.values);
+        return;
+    }
+    memmove (payload, msg->payload, msg->payloadlen);
+    payload[msg->payloadlen] = 0;
+
+    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 LIBMOSQUITTO_MAJOR != 0
+    if (conf->cacertificatefile) {
+        status = mosquitto_tls_set(conf->mosq, conf->cacertificatefile, NULL,
+                                  conf->certificatefile, conf->certificatekeyfile, /* pw_callback */NULL);
+        if (status != MOSQ_ERR_SUCCESS) {
+            ERROR ("mqtt plugin: cannot mosquitto_tls_set: %s", mosquitto_strerror(status));
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            return (-1);
+        }
+
+        status = mosquitto_tls_opts_set(conf->mosq, SSL_VERIFY_PEER, conf->tlsprotocol, conf->ciphersuite);
+        if (status != MOSQ_ERR_SUCCESS) {
+            ERROR ("mqtt plugin: cannot mosquitto_tls_opts_set: %s", mosquitto_strerror(status));
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            return (-1);
+        }
+
+        status = mosquitto_tls_insecure_set(conf->mosq, false);
+        if (status != MOSQ_ERR_SUCCESS) {
+            ERROR ("mqtt plugin: cannot mosquitto_tls_insecure_set: %s", mosquitto_strerror(status));
+            mosquitto_destroy (conf->mosq);
+            conf->mosq = NULL;
+            return (-1);
+        }
+    }
+#endif
+
+    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
+ *   CACert "ca.pem"                   Enables TLS if set
+ *   CertificateFile "client-cert.pem"         optional
+ *   CertificateKeyFile "client-key.pem"               optional
+ *   TLSProtocol "tlsv1.2"             optional
+ * </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 if (strcasecmp ("CACert", child->key) == 0)
+            cf_util_get_string (child, &conf->cacertificatefile);
+        else if (strcasecmp ("CertificateFile", child->key) == 0)
+            cf_util_get_string (child, &conf->certificatefile);
+        else if (strcasecmp ("CertificateKeyFile", child->key) == 0)
+            cf_util_get_string (child, &conf->certificatekeyfile);
+        else if (strcasecmp ("TLSProtocol", child->key) == 0)
+            cf_util_get_string (child, &conf->tlsprotocol);
+        else if (strcasecmp ("CipherSuite", child->key) == 0)
+            cf_util_get_string (child, &conf->ciphersuite);
+        else
+            ERROR ("mqtt plugin: Unknown config option: %s", child->key);
+    }
+
+    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/#"
+ * </Subscribe>
+ */
+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 + 1) );
+    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
 
diff --git a/src/notify_nagios.c b/src/notify_nagios.c
new file mode 100644 (file)
index 0000000..1f4182b
--- /dev/null
@@ -0,0 +1,170 @@
+/**
+ * collectd - src/notify_nagios.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 "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "configfile.h"
+
+#define NAGIOS_OK       0
+#define NAGIOS_WARNING  1
+#define NAGIOS_CRITICAL 2
+#define NAGIOS_UNKNOWN  3
+
+#ifndef NAGIOS_COMMAND_FILE
+# define NAGIOS_COMMAND_FILE "/usr/local/nagios/var/rw/nagios.cmd"
+#endif
+
+static char *nagios_command_file;
+
+static int nagios_config (oconfig_item_t *ci) /* {{{ */
+{
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("CommandFile", child->key) == 0)
+      cf_util_get_string (child, &nagios_command_file);
+    else
+      WARNING ("notify_nagios plugin: Ignoring unknown config option \"%s\".",
+          child->key);
+  }
+
+  return 0;
+} /* }}} nagios_config */
+
+static int nagios_print (char const *buffer) /* {{{ */
+{
+  char const *file = NAGIOS_COMMAND_FILE;
+  int fd;
+  int status;
+  struct flock lock;
+
+  if (nagios_command_file != NULL)
+    file = nagios_command_file;
+
+  fd = open (file, O_WRONLY | O_APPEND);
+  if (fd < 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Opening \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    return status;
+  }
+
+  memset (&lock, 0, sizeof (lock));
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_END;
+  lock.l_start = 0;
+  lock.l_len = 0; /* to end of file */
+
+  status = fcntl (fd, F_GETLK, &lock);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Failed to acquire write lock on \"%s\": %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  status = (int) lseek (fd, 0, SEEK_END);
+  if (status == -1)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Seeking to end of \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  status = (int) swrite (fd, buffer, strlen (buffer));
+  if (status != 0)
+  {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("notify_nagios plugin: Writing to \"%s\" failed: %s",
+        file, sstrerror (status, errbuf, sizeof (errbuf)));
+    close (fd);
+    return status;
+  }
+
+  close (fd);
+  return status;
+} /* }}} int nagios_print */
+
+static int nagios_notify (const notification_t *n, /* {{{ */
+    __attribute__((unused)) user_data_t *user_data)
+{
+  char svc_description[4 * DATA_MAX_NAME_LEN];
+  char buffer[4096];
+  int code;
+  int status;
+
+  status = format_name (svc_description, (int) sizeof (svc_description),
+      /* host */ "", n->plugin, n->plugin_instance, n->type, n->type_instance);
+  if (status != 0)
+  {
+    ERROR ("notify_nagios plugin: Formatting service name failed.");
+    return status;
+  }
+
+  switch (n->severity)
+  {
+    case NOTIF_OKAY:
+      code = NAGIOS_OK;
+      break;
+    case NOTIF_WARNING:
+      code = NAGIOS_WARNING;
+      break;
+    case NOTIF_FAILURE:
+      code = NAGIOS_CRITICAL;
+      break;
+    default:
+      code = NAGIOS_UNKNOWN;
+      break;
+  }
+
+  ssnprintf (buffer, sizeof (buffer),
+      "[%.0f] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
+      CDTIME_T_TO_DOUBLE (n->time), n->host, &svc_description[1], code,
+      n->message);
+
+  return nagios_print (buffer);
+} /* }}} int nagios_notify */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("notify_nagios", nagios_config);
+  plugin_register_notification ("notify_nagios", nagios_notify, NULL);
+} /* void module_register (void) */
+
+/* vim: set sw=2 sts=2 ts=8 et : */
index ceb1442..ee2c048 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 663a82d..93c8f1b 100644 (file)
@@ -697,6 +697,14 @@ static int openvpn_config (const char *key, const char *value)
 
                /* create a new vpn element since file, version and name are ok */
                temp = (vpn_status_t *) malloc (sizeof (vpn_status_t));
+               if (temp == NULL)
+               {
+                       char errbuf[1024];
+                       ERROR ("openvpn plugin: malloc failed: %s",
+                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       sfree (status_file);
+                       return (1);
+               }
                temp->file = status_file;
                temp->version = status_version;
                temp->name = status_name;
@@ -705,7 +713,7 @@ static int openvpn_config (const char *key, const char *value)
                if (vpn_list == NULL)
                {
                        char errbuf[1024];
-                       ERROR ("openvpn plugin: malloc failed: %s",
+                       ERROR ("openvpn plugin: realloc failed: %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
 
                        sfree (temp->file);
index 1ce09f4..14a7a8d 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)
@@ -1208,7 +1199,10 @@ static void c_ithread_destructor (void *arg)
 
        /* the ithread no longer exists */
        if (NULL == t)
+       {
+               pthread_mutex_unlock (&perl_threads->mutex);
                return;
+       }
 
        c_ithread_destroy (ithread);
 
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 e94ad8f..d13d047 100644 (file)
@@ -29,7 +29,6 @@
 #include "configfile.h"
 
 #include <pthread.h>
-#include <sys/socket.h>
 #include <netdb.h>
 #include <poll.h>
 
index d669aa9..8542164 100644 (file)
@@ -73,6 +73,7 @@ static char  *ping_source = NULL;
 #ifdef HAVE_OPING_1_3
 static char  *ping_device = NULL;
 #endif
+static char  *ping_data = NULL;
 static int    ping_ttl = PING_DEF_TTL;
 static double ping_interval = 1.0;
 static double ping_timeout = 0.9;
@@ -91,6 +92,7 @@ static const char *config_keys[] =
 #ifdef HAVE_OPING_1_3
   "Device",
 #endif
+  "Size",
   "TTL",
   "Interval",
   "Timeout",
@@ -210,7 +212,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
@@ -279,6 +282,9 @@ static void *ping_thread (void *arg) /* {{{ */
   ping_setopt (pingobj, PING_OPT_TIMEOUT, (void *) &ping_timeout);
   ping_setopt (pingobj, PING_OPT_TTL, (void *) &ping_ttl);
 
+  if (ping_data != NULL)
+    ping_setopt (pingobj, PING_OPT_DATA, (void *) ping_data);
+
   /* Add all the hosts to the ping object. */
   count = 0;
   for (hl = hostlist_head; hl != NULL; hl = hl->next)
@@ -536,6 +542,39 @@ static int ping_config (const char *key, const char *value) /* {{{ */
       WARNING ("ping plugin: Ignoring invalid interval %g (%s)",
           tmp, value);
   }
+  else if (strcasecmp (key, "Size") == 0) {
+    size_t size = (size_t) atoi (value);
+
+    /* Max IP packet size - (IPv6 + ICMP) = 65535 - (40 + 8) = 65487 */
+    if (size <= 65487)
+    {
+      size_t i;
+
+      sfree (ping_data);
+      ping_data = malloc (size + 1);
+      if (ping_data == NULL)
+      {
+        ERROR ("ping plugin: malloc failed.");
+        return (1);
+      }
+
+      /* Note: By default oping is using constant string
+       * "liboping -- ICMP ping library <http://octo.it/liboping/>"
+       * which is exactly 56 bytes.
+       *
+       * Optimally we would follow the ping(1) behaviour, but we
+       * cannot use byte 00 or start data payload at exactly same
+       * location, due to oping library limitations. */
+      for (i = 0; i < size; i++) /* {{{ */
+      {
+        /* This restricts data pattern to be only composed of easily
+         * printable characters, and not NUL character. */
+        ping_data[i] = ('0' + i % 64);
+      }  /* }}} for (i = 0; i < size; i++) */
+      ping_data[size] = 0;
+    } else
+      WARNING ("ping plugin: Ignoring invalid Size %zu.", size);
+  }
   else if (strcasecmp (key, "Timeout") == 0)
   {
     double tmp;
@@ -687,6 +726,11 @@ static int ping_shutdown (void) /* {{{ */
     hl = hl_next;
   }
 
+  if (ping_data != NULL) {
+    free (ping_data);
+    ping_data = NULL;
+  }
+
   return (0);
 } /* }}} int ping_shutdown */
 
index 73d590a..8093eb1 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;
@@ -829,7 +826,7 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
 {
        c_psql_database_t *db;
 
-       char time_str[32];
+       char time_str[RFC3339NANO_SIZE];
        char values_name_str[1024];
        char values_type_str[1024];
        char values_str[1024];
@@ -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.");
@@ -848,8 +845,8 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
        assert (db->database != NULL);
        assert (db->writers != NULL);
 
-       if (cdtime_to_iso8601 (time_str, sizeof (time_str), vl->time) == 0) {
-               log_err ("c_psql_write: Failed to convert time to ISO 8601 format");
+       if (rfc3339nano (time_str, sizeof (time_str), vl->time) != 0) {
+               log_err ("c_psql_write: Failed to convert time to RFC 3339 format");
                return -1;
        }
 
@@ -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 c9e9359..0400f3d 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 e437209..fac4778 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;
@@ -279,8 +287,8 @@ static void ps_list_register (const char *name, const char *regexp)
                if (status != 0)
                {
                        DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
-                       sfree(new->re);
-                       sfree(new);
+                       sfree (new->re);
+                       sfree (new);
                        return;
                }
        }
@@ -399,6 +407,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;
@@ -413,6 +423,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))
                {
@@ -509,6 +522,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;
@@ -593,6 +608,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 "
@@ -742,19 +761,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
@@ -779,42 +815,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;
 
-/* Read advanced virtual memory data from /proc/pid/status */
-static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
+       return (ps);
+} /* int *ps_read_tasks_status */
+
+/* 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;
 
@@ -824,10 +917,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,
@@ -838,7 +932,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)
@@ -853,6 +947,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) */
 
@@ -865,6 +963,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 */
@@ -932,9 +1032,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;
@@ -945,14 +1045,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
@@ -1007,11 +1109,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;
        }
 
@@ -1044,14 +1151,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;
@@ -1069,6 +1168,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 (...) */
@@ -1220,16 +1331,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);
        }
@@ -1326,6 +1437,12 @@ static int ps_read_process(long pid, procstat_t *ps, char *state)
        ps->io_syscr = myUsage->pr_sysc;
        ps->io_syscw = myUsage->pr_sysc;
 
+       /*
+        * TODO: context switch counters for Solaris
+   */
+       ps->cswitch_vol   = -1;
+       ps->cswitch_invol = -1;
+
 
        /*
         * TODO: Find way of setting BLOCKED and PAGING status
@@ -1563,6 +1680,10 @@ static int ps_read (void)
 
                                pse.cpu_user_counter = task_absolutetime_info.total_user;
                                pse.cpu_system_counter = task_absolutetime_info.total_system;
+
+                               /* context switch counters not implemented */
+                               pse.cswitch_vol   = -1;
+                               pse.cswitch_invol = -1;
                        }
 
                        status = task_threads (task_list[task], &thread_list,
@@ -1768,6 +1889,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,6 +2037,10 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
+                       /* context switch counters not implemented */
+                       pse.cswitch_vol   = -1;
+                       pse.cswitch_invol = -1;
+
                        ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse);
 
                        switch (procs[i].ki_stat)
@@ -2046,7 +2174,8 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
-                       pse.cswitch_vol = -1;
+                       /* context switch counters not implemented */
+                       pse.cswitch_vol   = -1;
                        pse.cswitch_invol = -1;
 
                        ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
@@ -2195,6 +2324,9 @@ static int ps_read (void)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
 
+                       pse.cswitch_vol   = -1;
+                       pse.cswitch_invol = -1;
+
                        ps_list_add (cmdline, cargs, &pse);
                } /* for (i = 0 .. nprocs) */
 
index e7795c7..210d785 100644 (file)
@@ -342,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;
@@ -355,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);
@@ -566,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;
@@ -653,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;
@@ -675,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 7864ead..a40d2cd 100644 (file)
@@ -141,7 +141,7 @@ static redis_query_t *redis_config_query (oconfig_item_t *ci) /* {{{ */
      * Default to a gauge type.
      */
     (void)strncpy(rq->type, "gauge", sizeof(rq->type));
-    (void)strncpy(rq->instance, rq->query, sizeof(rq->instance));
+    (void)sstrncpy(rq->instance, rq->query, sizeof(rq->instance));
     replace_special(rq->instance, sizeof(rq->instance));
 
     for (i = 0; i < ci->children_num; i++) {
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 9b5723a..26d1638 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 cf7d975..3ccf60c 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)
@@ -781,11 +780,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.");
@@ -1055,6 +1051,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)
 {
@@ -1062,6 +1062,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;
 
@@ -1071,23 +1073,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)
 {
@@ -1099,6 +1106,14 @@ static int csnmp_strvbcopy (char *dst, /* {{{ */
     src = (char *) vb->val.string;
   else if (vb->type == ASN_BIT_STR)
     src = (char *) vb->val.bitstring;
+  else if (vb->type == ASN_IPADDRESS)
+  {
+    return ssnprintf (dst, dst_size, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"",
+          (uint8_t) vb->val.string[0],
+          (uint8_t) vb->val.string[1],
+          (uint8_t) vb->val.string[2],
+          (uint8_t) vb->val.string[3]);
+  }
   else
   {
     dst[0] = 0;
@@ -1117,8 +1132,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,
@@ -1160,7 +1179,7 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
   }
 
   /* Get instance name */
-  if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
+  if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR) || (vb->type == ASN_IPADDRESS))
   {
     char *ptr;
 
@@ -1226,7 +1245,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;
 
@@ -1241,7 +1260,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++)
@@ -1379,12 +1398,12 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
 {
   struct snmp_pdu *req;
-  struct snmp_pdu *res;
+  struct snmp_pdu *res = NULL;
   struct variable_list *vb;
 
   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];
@@ -1393,8 +1412,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
@@ -1422,7 +1440,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);
   }
@@ -1435,8 +1453,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,
@@ -1468,13 +1486,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)
@@ -1570,7 +1588,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;
@@ -1582,7 +1600,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;
@@ -1666,7 +1684,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);
@@ -1686,7 +1704,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);
   }
@@ -1774,8 +1792,6 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 static int csnmp_read_host (user_data_t *ud)
 {
   host_definition_t *host;
-  cdtime_t time_start;
-  cdtime_t time_end;
   int status;
   int success;
   int i;
@@ -1785,8 +1801,6 @@ static int csnmp_read_host (user_data_t *ud)
   if (host->interval == 0)
     host->interval = plugin_get_interval ();
 
-  time_start = cdtime ();
-
   if (host->sess_handle == NULL)
     csnmp_host_open_session (host);
 
@@ -1807,16 +1821,6 @@ static int csnmp_read_host (user_data_t *ud)
       success++;
   }
 
-  time_end = cdtime ();
-  if ((time_end - time_start) > host->interval)
-  {
-    WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
-        "seconds, but reading all values takes %.3f seconds.",
-        host->name,
-        CDTIME_T_TO_DOUBLE (host->interval),
-        CDTIME_T_TO_DOUBLE (time_end - time_start));
-  }
-
   if (success == 0)
     return (-1);
 
index d12cb0d..d0a677e 100644 (file)
@@ -35,7 +35,6 @@
 #include <pthread.h>
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <netdb.h>
 #include <poll.h>
 
@@ -65,6 +64,7 @@ struct statsd_metric_s
 {
   metric_type_t type;
   double value;
+  derive_t counter;
   latency_counter_t *latency;
   c_avl_tree_t *set;
   unsigned long updates_num;
@@ -89,6 +89,7 @@ static _Bool conf_delete_sets     = 0;
 static double *conf_timer_percentile = NULL;
 static size_t  conf_timer_percentile_num = 0;
 
+static _Bool conf_counter_sum     = 0;
 static _Bool conf_timer_lower     = 0;
 static _Bool conf_timer_upper     = 0;
 static _Bool conf_timer_sum       = 0;
@@ -262,6 +263,8 @@ static int statsd_handle_counter (char const *name, /* {{{ */
   if (status != 0)
     return (status);
 
+  /* Changes to the counter are added to (statsd_metric_t*)->value. ->counter is
+   * only updated in statsd_metric_submit_unsafe(). */
   return (statsd_metric_add (name, (double) (value.gauge / scale.gauge),
         STATSD_COUNTER));
 } /* }}} int statsd_handle_counter */
@@ -686,6 +689,8 @@ static int statsd_config (oconfig_item_t *ci) /* {{{ */
       cf_util_get_boolean (child, &conf_delete_gauges);
     else if (strcasecmp ("DeleteSets", child->key) == 0)
       cf_util_get_boolean (child, &conf_delete_sets);
+    else if (strcasecmp ("CounterSum", child->key) == 0)
+      cf_util_get_boolean (child, &conf_counter_sum);
     else if (strcasecmp ("TimerLower", child->key) == 0)
       cf_util_get_boolean (child, &conf_timer_lower);
     else if (strcasecmp ("TimerUpper", child->key) == 0)
@@ -756,8 +761,7 @@ static int statsd_metric_clear_set_unsafe (statsd_metric_t *metric) /* {{{ */
 } /* }}} int statsd_metric_clear_set_unsafe */
 
 /* Must hold metrics_lock when calling this function. */
-static int statsd_metric_submit_unsafe (char const *name, /* {{{ */
-    statsd_metric_t const *metric)
+static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metric) /* {{{ */
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
@@ -853,17 +857,28 @@ static int statsd_metric_submit_unsafe (char const *name, /* {{{ */
       values[0].gauge = (gauge_t) c_avl_size (metric->set);
   }
   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;
+    gauge_t delta = nearbyint (metric->value);
+
+    /* Etsy's statsd writes counters as two metrics: a rate and the change since
+     * the last write. Since collectd does not reset its DERIVE metrics to zero,
+     * this makes little sense, but we're dispatching a "count" metric here
+     * anyway - if requested by the user - for compatibility reasons. */
+    if (conf_counter_sum)
+    {
+      sstrncpy (vl.type, "count", sizeof (vl.type));
+      values[0].gauge = delta;
+      plugin_dispatch_values (&vl);
+
+      /* restore vl.type */
+      sstrncpy (vl.type, "derive", sizeof (vl.type));
+    }
+
+    /* Rather than resetting value to zero, subtract delta so we correctly keep
+     * track of residuals. */
+    metric->value   -= delta;
+    metric->counter += (derive_t) delta;
+
+    values[0].derive = metric->counter;
   }
 
   return (plugin_dispatch_values (&vl));
index fcbac4f..aebf0bb 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;
@@ -456,7 +458,7 @@ static int tbl_parse_line (tbl_t *tbl, char *line, size_t len)
        }
 
        if (i <= tbl->max_colnum) {
-               log_err ("Not enough columns in line "
+               log_warn ("Not enough columns in line "
                                "(expected at least %zu, got %zu).",
                                tbl->max_colnum + 1, i);
                return -1;
@@ -488,11 +490,11 @@ static int tbl_read_table (tbl_t *tbl)
        while (NULL != fgets (buf, sizeof (buf), fh)) {
                if ('\0' != buf[sizeof (buf) - 1]) {
                        buf[sizeof (buf) - 1] = '\0';
-                       log_err ("Table %s: Truncated line: %s", tbl->file, buf);
+                       log_warn ("Table %s: Truncated line: %s", tbl->file, buf);
                }
 
                if (0 != tbl_parse_line (tbl, buf, sizeof (buf))) {
-                       log_err ("Table %s: Failed to parse line: %s", tbl->file, buf);
+                       log_warn ("Table %s: Failed to parse line: %s", tbl->file, buf);
                        continue;
                }
        }
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 0e683ce..058eb7c 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..c0a9e88 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>
  */
 
+#ifndef TESTING_H
+#define TESTING_H 1
+
+#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 +51,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 evaluates to \"%s\"\n", ++check_count__, #actual, expect); \
+  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 = %.15g\n", ++check_count__, #actual, got__); \
 } while (0)
 
 #define CHECK_NOT_NULL(expr) do { \
@@ -65,3 +112,5 @@ static int check_count__ = 0;
   status_ = (long) (expr); \
   OK1(status_ == 0L, #expr); \
 } while (0)
+
+#endif /* TESTING_H */
index a5e50a2..b753d37 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 c605f56..5847218 100644 (file)
@@ -14,7 +14,7 @@ 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
index e62ed6c..54a1e20 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_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 a138d18..aee7247 100644 (file)
@@ -793,6 +793,7 @@ static int varnish_read (user_data_t *ud) /* {{{ */
 {
        struct VSM_data *vd;
        const c_varnish_stats_t *stats;
+       _Bool ok;
 
        user_config_t *conf;
 
@@ -822,10 +823,11 @@ static int varnish_read (user_data_t *ud) /* {{{ */
        }
 
 #if HAVE_VARNISH_V3
-       if (VSC_Open (vd, /* diag = */ 1))
+       ok = (VSC_Open (vd, /* diag = */ 1) == 0);
 #else /* if HAVE_VARNISH_V4 */
-       if (VSM_Open (vd))
+       ok = (VSM_Open (vd) == 0);
 #endif
+       if (!ok)
        {
                VSM_Delete (vd);
                ERROR ("varnish plugin: Unable to open connection.");
@@ -957,7 +959,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);
@@ -1121,7 +1123,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 a7eef3f..6baace1 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
@@ -113,8 +94,36 @@ struct wg_callback
     pthread_mutex_t send_lock;
     c_complain_t init_complaint;
     cdtime_t last_connect_time;
+
+    /* Force reconnect useful for load balanced environments */
+    cdtime_t last_reconnect_time;
+    cdtime_t reconnect_interval;
+    _Bool reconnect_interval_reached;
 };
 
+/* wg_force_reconnect_check closes cb->sock_fd when it was open for longer
+ * than cb->reconnect_interval. Must hold cb->send_lock when calling. */
+static void wg_force_reconnect_check (struct wg_callback *cb)
+{
+    cdtime_t now;
+
+    if (cb->reconnect_interval == 0)
+        return;
+
+    /* check if address changes if addr_timeout */
+    now = cdtime ();
+    if ((now - cb->last_reconnect_time) < cb->reconnect_interval)
+        return;
+
+    /* here we should close connection on next */
+    close (cb->sock_fd);
+    cb->sock_fd = -1;
+    cb->last_reconnect_time = now;
+    cb->reconnect_interval_reached = 1;
+
+    INFO ("write_graphite plugin: Connection closed after %.3f seconds.",
+          CDTIME_T_TO_DOUBLE (now - cb->last_reconnect_time));
+}
 
 /*
  * Functions
@@ -134,13 +143,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 +200,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 +218,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,17 +268,23 @@ 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);
+    /* wg_force_reconnect_check does not flush the buffer before closing a
+     * sending socket, so only call wg_reset_buffer() if the socket was closed
+     * for a different reason (tracked in cb->reconnect_interval_reached). */
+    if (!cb->reconnect_interval_reached || (cb->send_buf_free == 0))
+        wg_reset_buffer (cb);
+    else
+        cb->reconnect_interval_reached = 0;
 
     return (0);
 }
@@ -351,6 +360,8 @@ static int wg_send_message (char const *message, struct wg_callback *cb)
 
     pthread_mutex_lock (&cb->send_lock);
 
+    wg_force_reconnect_check (cb);
+
     if (cb->sock_fd < 0)
     {
         status = wg_callback_init (cb);
@@ -383,9 +394,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 +495,12 @@ 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->last_reconnect_time = cdtime();
+    cb->reconnect_interval = 0;
+    cb->reconnect_interval_reached = 0;
     cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS;
     cb->prefix = NULL;
     cb->postfix = NULL;
@@ -529,6 +541,8 @@ static int wg_config_node (oconfig_item_t *ci)
                 status = -1;
             }
         }
+        else if (strcasecmp ("ReconnectInterval", child->key) == 0)
+            cf_util_get_cdtime (child, &cb->reconnect_interval);
         else if (strcasecmp ("LogSendErrors", child->key) == 0)
             cf_util_get_boolean (child, &cb->log_send_errors);
         else if (strcasecmp ("Prefix", child->key) == 0)
@@ -566,9 +580,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 775e2e0..a5977ab 100644 (file)
@@ -44,7 +44,7 @@ struct kafka_topic_context {
 #define KAFKA_FORMAT_JSON        0
 #define KAFKA_FORMAT_COMMAND     1
 #define KAFKA_FORMAT_GRAPHITE    2
-    uint8_t                     format;
+    uint8_t                      format;
     unsigned int                 graphite_flags;
     _Bool                        store_rates;
     rd_kafka_topic_conf_t       *conf;
@@ -52,12 +52,12 @@ struct kafka_topic_context {
     rd_kafka_conf_t             *kafka_conf;
     rd_kafka_t                  *kafka;
     int                          has_key;
-    uint32_t                    key;
+    uint32_t                     key;
     char                        *prefix;
     char                        *postfix;
     char                         escape_char;
     char                        *topic_name;
-    pthread_mutex_t            lock;
+    pthread_mutex_t              lock;
 };
 
 static int kafka_handle(struct kafka_topic_context *);
@@ -81,7 +81,7 @@ static int32_t kafka_partition(const rd_kafka_topic_t *rkt,
 {
     uint32_t key = *((uint32_t *)keydata );
     uint32_t target = key % partition_cnt;
-    int32_t   i = partition_cnt;
+    int32_t  i = partition_cnt;
 
     while (--i > 0 && !rd_kafka_topic_partition_available(rkt, target)) {
         target = (target + 1) % partition_cnt;
@@ -106,37 +106,37 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */
 
         if ((ctx->kafka = rd_kafka_new(RD_KAFKA_PRODUCER, conf,
                                     errbuf, sizeof(errbuf))) == NULL) {
-               ERROR("write_kafka plugin: cannot create kafka handle.");
-               return 1;
+            ERROR("write_kafka plugin: cannot create kafka handle.");
+            return 1;
         }
 
-       rd_kafka_conf_destroy(ctx->kafka_conf);
-       ctx->kafka_conf = NULL;
+        rd_kafka_conf_destroy(ctx->kafka_conf);
+        ctx->kafka_conf = NULL;
 
-       INFO ("write_kafka plugin: created KAFKA handle : %s", rd_kafka_name(ctx->kafka));
+        INFO ("write_kafka plugin: created KAFKA handle : %s", rd_kafka_name(ctx->kafka));
 
 #ifdef HAVE_LIBRDKAFKA_LOGGER
-       rd_kafka_set_logger(ctx->kafka, kafka_log);
+        rd_kafka_set_logger(ctx->kafka, kafka_log);
 #endif
     }
 
     if (ctx->topic == NULL ) {
-       if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) {
+        if ((topic_conf = rd_kafka_topic_conf_dup(ctx->conf)) == NULL) {
             ERROR("write_kafka plugin: cannot duplicate kafka topic config");
             return 1;
-       }
+        }
 
-       if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
-                                                       topic_conf)) == NULL) {
-               ERROR("write_kafka plugin: cannot create topic : %s\n", 
-                       rd_kafka_err2str(rd_kafka_errno2err(errno)));
-               return errno;
-       }
+        if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
+                                            topic_conf)) == NULL) {
+            ERROR("write_kafka plugin: cannot create topic : %s\n",
+            rd_kafka_err2str(rd_kafka_errno2err(errno)));
+            return errno;
+        }
 
-       rd_kafka_topic_conf_destroy(ctx->conf);
-       ctx->conf = NULL;
+        rd_kafka_topic_conf_destroy(ctx->conf);
+        ctx->conf = NULL;
 
-       INFO ("write_kafka plugin: handle created for topic : %s", rd_kafka_topic_name(ctx->topic));
+        INFO ("write_kafka plugin: handle created for topic : %s", rd_kafka_topic_name(ctx->topic));
     }
 
     return(0);
@@ -144,16 +144,16 @@ static int kafka_handle(struct kafka_topic_context *ctx) /* {{{ */
 } /* }}} int kafka_handle */
 
 static int kafka_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;
-    uint32_t    key;
-    char         buffer[8192];
-    size_t bfree = sizeof(buffer);
-    size_t bfill = 0;
-    size_t blen = 0;
-       struct kafka_topic_context      *ctx = ud->data;
+    int      status = 0;
+    uint32_t key;
+    char     buffer[8192];
+    size_t   bfree = sizeof(buffer);
+    size_t   bfill = 0;
+    size_t   blen = 0;
+    struct   kafka_topic_context  *ctx = ud->data;
 
     if ((ds == NULL) || (vl == NULL) || (ctx == NULL))
         return EINVAL;
@@ -177,7 +177,6 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
         blen = strlen(buffer);
         break;
     case KAFKA_FORMAT_JSON:
-
         format_json_initialize(buffer, &bfill, &bfree);
         format_json_value_list(buffer, &bfill, &bfree, ds, vl,
                                ctx->store_rates);
@@ -212,15 +211,15 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
                      RD_KAFKA_MSG_F_COPY, buffer, blen,
                      &key, sizeof(key), NULL);
 
-       return status;
+    return status;
 } /* }}} int kafka_write */
 
 static void kafka_topic_context_free(void *p) /* {{{ */
 {
-       struct kafka_topic_context *ctx = p;
+    struct kafka_topic_context *ctx = p;
 
-       if (ctx == NULL)
-               return;
+    if (ctx == NULL)
+        return;
 
     if (ctx->topic_name != NULL)
         sfree(ctx->topic_name);
@@ -246,13 +245,13 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     char                         callback_name[DATA_MAX_NAME_LEN];
     char                         errbuf[1024];
     user_data_t                  ud;
-       oconfig_item_t              *child;
+    oconfig_item_t              *child;
     rd_kafka_conf_res_t          ret;
 
-       if ((tctx = calloc(1, sizeof (*tctx))) == NULL) {
-               ERROR ("write_kafka plugin: calloc failed.");
+    if ((tctx = calloc(1, sizeof (*tctx))) == NULL) {
+        ERROR ("write_kafka plugin: calloc failed.");
         return;
-       }
+    }
 
     tctx->escape_char = '.';
     tctx->store_rates = 1;
@@ -290,33 +289,33 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
         goto errout;
     }
 
-       for (i = 0; i < ci->children_num; i++) {
-               /*
-                * The code here could be simplified but makes room
-                * for easy adding of new options later on.
-                */
-               child = &ci->children[i];
-               status = 0;
-
-               if (strcasecmp ("Property", child->key) == 0) {
-                       if (child->values_num != 2) {
-                               WARNING("kafka properties need both a key and a value.");
+    for (i = 0; i < ci->children_num; i++) {
+        /*
+         * The code here could be simplified but makes room
+         * for easy adding of new options later on.
+         */
+        child = &ci->children[i];
+        status = 0;
+
+        if (strcasecmp ("Property", child->key) == 0) {
+            if (child->values_num != 2) {
+                WARNING("kafka properties need both a key and a value.");
                 goto errout;
-                       }
-                       if (child->values[0].type != OCONFIG_TYPE_STRING ||
-                           child->values[1].type != OCONFIG_TYPE_STRING) {
-                               WARNING("kafka properties needs string arguments.");
+            }
+            if (child->values[0].type != OCONFIG_TYPE_STRING ||
+                child->values[1].type != OCONFIG_TYPE_STRING) {
+                WARNING("kafka properties needs string arguments.");
                 goto errout;
-                       }
+            }
             key = child->values[0].value.string;
             val = child->values[1].value.string;
             ret = rd_kafka_topic_conf_set(tctx->conf,key, val,
                                           errbuf, sizeof(errbuf));
             if (ret != RD_KAFKA_CONF_OK) {
-                               WARNING("cannot set kafka topic property %s to %s: %s.",
+                WARNING("cannot set kafka topic property %s to %s: %s.",
                         key, val, errbuf);
                 goto errout;
-                       }
+            }
 
         } else if (strcasecmp ("Key", child->key) == 0)  {
             char *tmp_buf = NULL;
@@ -397,11 +396,11 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     ud.data = tctx;
     ud.free_func = kafka_topic_context_free;
 
-       status = plugin_register_write (callback_name, kafka_write, &ud);
-       if (status != 0) {
-               WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
-                               "failed with status %i.",
-                               callback_name, status);
+    status = plugin_register_write (callback_name, kafka_write, &ud);
+    if (status != 0) {
+        WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
+                "failed with status %i.",
+                callback_name, status);
         goto errout;
     }
 
@@ -414,14 +413,14 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     if (tctx->conf != NULL)
         rd_kafka_topic_conf_destroy(tctx->conf);
     if (tctx->kafka_conf != NULL)
-               rd_kafka_conf_destroy(tctx->kafka_conf);
+        rd_kafka_conf_destroy(tctx->kafka_conf);
     sfree(tctx);
 } /* }}} int kafka_config_topic */
 
 static int kafka_config(oconfig_item_t *ci) /* {{{ */
 {
-       int                          i;
-       oconfig_item_t              *child;
+    int                          i;
+    oconfig_item_t              *child;
     rd_kafka_conf_t             *conf;
     rd_kafka_conf_res_t          ret;
     char                         errbuf[1024];
@@ -430,49 +429,49 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */
         WARNING("cannot allocate kafka configuration.");
         return -1;
     }
-       for (i = 0; i < ci->children_num; i++)  {
-               child = &ci->children[i];
+    for (i = 0; i < ci->children_num; i++)  {
+        child = &ci->children[i];
 
-               if (strcasecmp("Topic", child->key) == 0) {
-                       kafka_config_topic (conf, child);
-               } else if (strcasecmp(child->key, "Property") == 0) {
-                       char *key = NULL;
-                       char *val = NULL;
+        if (strcasecmp("Topic", child->key) == 0) {
+            kafka_config_topic (conf, child);
+        } else if (strcasecmp(child->key, "Property") == 0) {
+            char *key = NULL;
+            char *val = NULL;
 
-                       if (child->values_num != 2) {
-                               WARNING("kafka properties need both a key and a value.");
+            if (child->values_num != 2) {
+                WARNING("kafka properties need both a key and a value.");
                 goto errout;
-                       }
-                       if (child->values[0].type != OCONFIG_TYPE_STRING ||
-                           child->values[1].type != OCONFIG_TYPE_STRING) {
-                               WARNING("kafka properties needs string arguments.");
+            }
+            if (child->values[0].type != OCONFIG_TYPE_STRING ||
+                child->values[1].type != OCONFIG_TYPE_STRING) {
+                WARNING("kafka properties needs string arguments.");
                 goto errout;
-                       }
-                       if ((key = strdup(child->values[0].value.string)) == NULL) {
-                               WARNING("cannot allocate memory for attribute key.");
+            }
+            if ((key = strdup(child->values[0].value.string)) == NULL) {
+                WARNING("cannot allocate memory for attribute key.");
                 goto errout;
-                       }
-                       if ((val = strdup(child->values[1].value.string)) == NULL) {
-                               WARNING("cannot allocate memory for attribute value.");
+            }
+            if ((val = strdup(child->values[1].value.string)) == NULL) {
+                WARNING("cannot allocate memory for attribute value.");
                 goto errout;
-                       }
+            }
             ret = rd_kafka_conf_set(conf, key, val, errbuf, sizeof(errbuf));
             if (ret != RD_KAFKA_CONF_OK) {
                 WARNING("cannot set kafka property %s to %s: %s",
                         key, val, errbuf);
                 goto errout;
             }
-                       sfree(key);
-                       sfree(val);
-               } else {
-                       WARNING ("write_kafka plugin: Ignoring unknown "
-                                "configuration option \"%s\" at top level.",
-                                child->key);
-               }
-       }
+            sfree(key);
+            sfree(val);
+        } else {
+            WARNING ("write_kafka plugin: Ignoring unknown "
+                 "configuration option \"%s\" at top level.",
+                 child->key);
+        }
+    }
     if (conf != NULL)
         rd_kafka_conf_destroy(conf);
-       return (0);
+    return (0);
  errout:
     if (conf != NULL)
         rd_kafka_conf_destroy(conf);
@@ -481,7 +480,6 @@ static int kafka_config(oconfig_item_t *ci) /* {{{ */
 
 void module_register(void)
 {
-       plugin_register_complex_config ("write_kafka", kafka_config);
+    plugin_register_complex_config ("write_kafka", kafka_config);
 }
 
-/* vim: set sw=8 sts=8 ts=8 noet : */
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 da5b7bb..4bfcc73 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;
@@ -66,17 +74,20 @@ static int wr_write (const data_set_t *ds, /* {{{ */
   status = FORMAT_VL (ident, sizeof (ident), vl);
   if (status != 0)
     return (status);
-  ssnprintf (key, sizeof (key), "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];
-  status = format_values (value_ptr, value_size, ds, vl, /* store rates = */ 0);
-  pthread_mutex_lock (&node->lock);
+  status = format_values (value_ptr, value_size, ds, vl, node->store_rates);
   if (status != 0)
     return (status);
 
+  pthread_mutex_lock (&node->lock);
+
   if (node->conn == NULL)
   {
     node->conn = redisConnectWithTimeout ((char *)node->host, node->port, node->timeout);
@@ -97,6 +108,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);
@@ -105,10 +122,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
@@ -152,6 +180,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));
@@ -180,6 +212,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 328341e..5c59c92 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 507018f..2336541 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) {
@@ -885,7 +884,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);
@@ -899,7 +898,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 ee4db23..2ed4389 100644 (file)
@@ -49,7 +49,6 @@
 #include "utils_cache.h"
 
 #include <pthread.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 #ifndef WT_DEFAULT_NODE
@@ -410,7 +409,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];
@@ -435,7 +434,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,
@@ -444,12 +443,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;
     }
 
@@ -505,7 +506,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 86e7d4c..41a89b1 100644 (file)
@@ -256,6 +256,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 5aa94e3..539795c 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>
index b09be8e..493a6eb 100755 (executable)
@@ -2,12 +2,12 @@
 
 DEFAULT_VERSION="5.5.0.git"
 
-VERSION="`git describe 2> /dev/null | grep collectd | sed -e 's/^collectd-//'`"
+if [ -d .git ]; then
+       VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"
+fi
 
 if test -z "$VERSION"; then
        VERSION="$DEFAULT_VERSION"
 fi
 
-VERSION="`echo \"$VERSION\" | sed -e 's/-/./g'`"
-
 printf "%s" "$VERSION"