Merge branch 'collectd-5.5'
authorMarc Fournier <marc.fournier@camptocamp.com>
Sat, 19 Mar 2016 15:44:30 +0000 (16:44 +0100)
committerMarc Fournier <marc.fournier@camptocamp.com>
Sat, 19 Mar 2016 15:44:30 +0000 (16:44 +0100)
165 files changed:
.gitignore
.travis.yml [new file with mode: 0644]
AUTHORS
CONTRIBUTING.md [new file with mode: 0644]
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
build.sh
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/battery.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/collectdmon.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/configfile.h
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_heap_test.c
src/daemon/utils_ignorelist.c
src/daemon/utils_random.c
src/daemon/utils_subst.c
src/daemon/utils_subst.h
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/ipc.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/liboconfig/parser.y
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/nfs.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/sensors.c
src/serial.c
src/sigrok.c
src/smart.c
src/snmp.c
src/statsd.c
src/swap.c
src/syslog.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/thermal.c
src/threshold.c
src/tokyotyrant.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_dns.h
src/utils_format_graphite.c
src/utils_format_json.c
src/utils_latency.c
src/utils_latency_test.c [new file with mode: 0644]
src/utils_mount.c
src/utils_mount.h
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/vserver.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..b14cc7a 100644 (file)
@@ -20,7 +20,6 @@ Makefile
 config.log
 config.status
 libtool
-src/.deps
 src/collectd.conf
 src/config.h
 src/libcollectdclient/libcollectdclient.pc
@@ -31,7 +30,7 @@ src/stamp-h1
 *.lo
 *.o
 .libs/
-src/collectd
+.deps/
 src/collectd-nagios
 src/collectd-tg
 src/collectdctl
@@ -73,19 +72,11 @@ bindings/java/org/collectd/java/*.class
 # python stuff
 *.pyc
 
-# tag stuff
-src/tags
-
 # backup stuff
 *~
-# tests stuff
-src/tests/.deps/
-src/tests/mock/.deps/
-src/tests/.dirstamp
-src/tests/mock/.dirstamp
-test*.log
+# Unit tests
+src/tests/
+test_*
 
-# new daemon repo
-src/daemon/.deps/
-src/daemon/.dirstamp
+# src/daemon/...
 src/daemon/collectd
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..03d9dde
--- /dev/null
@@ -0,0 +1,56 @@
+sudo: required
+dist: trusty
+compiler:
+  - gcc
+  - clang
+language: c
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq --no-install-recommends
+      iptables-dev
+      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 --with-python=/usr/bin/python && make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-python=/usr/bin/python"
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/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..befb76e
--- /dev/null
@@ -0,0 +1,38 @@
+# Thanks !
+
+Thanks for your feedback & contributions to the
+[collectd project](https://collectd.org/) !
+
+## Need help using collectd ?
+
+Please use the
+[collectd mailing list](http://mailman.verplant.org/listinfo/collectd) or the
+[#collectd IRC channel](https://webchat.freenode.net/?channels=#collectd).
+We'd like to keep the github issue tracker for bugreports and patch reviews.
+
+## Found a bug ?
+
+Please mention the exact collectd version you're using, how it was installed
+(built from source, or installed from packages. Where was it downloaded
+from). Which operating system/architecture, distribution and version are you
+running collectd on.
+
+If collectd crashes, try to get a
+[stack trace](https://collectd.org/wiki/index.php/Core_file).
+
+## Fixed a bug ? Want to add a feature ?
+
+Using git/github to submit changes is not mandatory. Sending patches to the
+[mailing-list](http://mailman.verplant.org/listinfo/collectd) is also fine.
+In both cases, take a quick look at the
+[submission guidelines](https://collectd.org/wiki/index.php/Submitting_patches)
+and the [coding style recommendations](https://collectd.org/wiki/index.php/Coding_style).
+
+Please try to submit **bugfixes** to the
+[oldest release branch](https://github.com/collectd/collectd/milestones) on
+which the bug is found, so that it gets included in every future **bugfix
+release**.
+
+Please try to submit **new features** to the master branch (which will become
+the next **feature release**).
+
diff --git a/README b/README
index 3e2c023..f2371cb 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.
 
@@ -889,18 +896,19 @@ Configuring with libjvm
   library checks succeed.
 
   If this doesn't work for you, you have the possibility to specify CPP-flags,
-  C-flags and LD-flags for the ‘Java’ plugin by hand, using the following three
-  (environment) variables:
+  C-flags, LD-flags and LIBS for the ‘Java’ plugin by hand, using the
+  following environment variables:
 
     - JAVA_CPPFLAGS
     - JAVA_CFLAGS
     - JAVA_LDFLAGS
+    - JAVA_LIBS
 
   For example (shortened for demonstration purposes):
 
     ./configure JAVA_CPPFLAGS="-I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
 
-  Adding "-ljvm" to the JAVA_LDFLAGS is done automatically, you don't have to
+  Adding "-ljvm" to JAVA_LIBS is done automatically, you don't have to
   do that.
 
 Generating the configure script
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 20854b1..57f3d44 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -18,7 +18,7 @@ EOF
        done
 }
 
-check_for_application lex yacc autoheader aclocal automake autoconf
+check_for_application lex bison autoheader aclocal automake autoconf
 
 # Actually we don't need the pkg-config executable, but we need the M4 macros.
 # We check for `pkg-config' here and hope that M4 macros will then be
index 9112a91..b1dc31f 100644 (file)
@@ -112,6 +112,10 @@ case $host_os in
        AC_DEFINE([KERNEL_OPENBSD], 1, [True if program is to be compiled for an OpenBSD kernel])
        ac_system="OpenBSD"
        ;;
+       *netbsd*)
+       AC_DEFINE([KERNEL_NETBSD], 1, [True if program is to be compiled for a NetBSD kernel])
+       ac_system="NetBSD"
+       ;;
        *aix*)
        AC_DEFINE([KERNEL_AIX], 1, [True if program is to be compiled for a AIX kernel])
        ac_system="AIX"
@@ -199,6 +203,19 @@ AC_HEADER_STDBOOL
 
 AC_CHECK_HEADERS(stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h endian.h sys/isa_defs.h fnmatch.h libgen.h)
 
+# For entropy plugin on newer NetBSD
+AC_CHECK_HEADERS(sys/rndio.h, [], [],
+[#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+])
+
 # For ping library
 AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
 [#if HAVE_STDINT_H
@@ -413,7 +430,7 @@ AC_CHECK_HEADERS(sys/sysctl.h, [], [],
 AC_MSG_CHECKING([for sysctl kern.cp_times])
 if test -x /sbin/sysctl
 then
-       /sbin/sysctl kern.cp_times 2>/dev/null
+       /sbin/sysctl kern.cp_times >/dev/null 2>&1
        if test $? -eq 0
        then
                AC_MSG_RESULT([yes])
@@ -426,6 +443,22 @@ else
        AC_MSG_RESULT([no])
 fi
 
+AC_MSG_CHECKING([for sysctl kern.cp_time])
+if test -x /sbin/sysctl
+then
+       /sbin/sysctl kern.cp_time >/dev/null 2>&1
+       if test $? -eq 0
+       then
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_SYSCTL_KERN_CP_TIME, 1,
+                       [Define if sysctl supports kern.cp_time])
+       else
+               AC_MSG_RESULT([no])
+       fi
+else
+       AC_MSG_RESULT([no])
+fi
+
 # For hddtemp module
 AC_CHECK_HEADERS(linux/major.h)
 
@@ -444,7 +477,7 @@ else
        have_linux_raid_md_u_h="no"
 fi
 
-# For the swap module
+# For the wireless module
 have_linux_wireless_h="no"
 if test "x$ac_system" = "xLinux"
 then
@@ -651,8 +684,6 @@ AC_CHECK_HEADERS(netinet/if_ether.h, [], [],
 #endif
 ])
 
-AC_CHECK_HEADERS(netinet/ip_compat.h)
-
 have_net_pfvar_h="no"
 AC_CHECK_HEADERS(net/pfvar.h,
                [have_net_pfvar_h="yes"],
@@ -707,13 +738,9 @@ AC_CHECK_HEADERS(sys/capability.h)
 # Checks for typedefs, structures, and compiler characteristics.
 #
 AC_C_CONST
-AC_C_INLINE
-AC_TYPE_OFF_T
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
-AC_TYPE_SSIZE_T
 AC_TYPE_UID_T
-AC_TYPE_UINT32_T
 AC_HEADER_TIME
 
 #
@@ -823,8 +850,6 @@ fi
 if test "x$have_clock_gettime" = "xyes"
 then
        AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if the clock_gettime(2) function is available.])
-else
-       AC_MSG_WARN(cannot find clock_gettime)
 fi
 
 nanosleep_needs_rt="no"
@@ -1452,6 +1477,24 @@ AC_CHECK_MEMBERS([struct kinfo_proc.p_pid, struct kinfo_proc.p_vm_rssize],
 #include <kvm.h>
        ])
 
+
+AC_CHECK_MEMBERS([struct kinfo_proc2.p_pid, struct kinfo_proc2.p_uru_maxrss],
+       [
+               AC_DEFINE(HAVE_STRUCT_KINFO_PROC2_NETBSD, 1,
+                       [Define if struct kinfo_proc2 exists in the NetBSD variant.])
+               have_struct_kinfo_proc2_netbsd="yes"
+       ],
+       [
+               have_struct_kinfo_proc2_netbsd="no"
+       ],
+       [
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+       ])
+
+
+
 AC_CHECK_MEMBERS([struct udphdr.uh_dport, struct udphdr.uh_sport], [], [],
 [#define _BSD_SOURCE
 #define _DEFAULT_SOURCE
@@ -1532,6 +1575,46 @@ if test "x$with_libhal" = "xyes"; then
        fi
 fi
 
+# --with-libpthread {{{
+AC_ARG_WITH(libpthread, [AS_HELP_STRING([--with-libpthread=@<:@=PREFIX@:>@], [Path to libpthread.])],
+[      if test "x$withval" != "xno" \
+               && test "x$withval" != "xyes"
+       then
+               LDFLAGS="$LDFLAGS -L$withval/lib"
+               CPPFLAGS="$CPPFLAGS -I$withval/include"
+               with_libpthread="yes"
+       else
+               if test "x$withval" = "xno"
+               then
+                       with_libpthread="no (disabled)"
+               fi
+       fi
+], [with_libpthread="yes"])
+
+AC_SUBST([PTHREAD_LIBS])
+if test "x$with_libpthread" = "xyes"
+then
+       SAVE_LIBS="$LIBS"
+       AC_CHECK_LIB(pthread, pthread_create, [], [with_libpthread="no (Symbol 'pthread_create' not found)"], [])
+       PTHREAD_LIBS="$LIBS"
+       LIBS="$SAVE_LIBS"
+fi
+
+if test "x$with_libpthread" = "xyes"
+then
+       AC_CHECK_HEADERS(pthread.h,, [with_libpthread="no (pthread.h not found)"])
+fi
+if test "x$with_libpthread" = "xyes"
+then
+       collect_pthread=1
+else
+       collect_pthread=0
+fi
+AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$collect_pthread],
+       [Wether or not to use pthread (POSIX threads) library])
+AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
+# }}}
+
 m4_divert_once([HELP_WITH], [
 collectd additional packages:])
 
@@ -2082,12 +2165,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"
@@ -2206,9 +2283,6 @@ if test "x$with_java_home" = "x"
 then
        with_java_home="/usr/lib/jvm"
 fi
-with_java_vmtype="client"
-with_java_cflags=""
-with_java_libs=""
 JAVAC="$JAVAC"
 JAR="$JAR"
 AC_ARG_WITH(java, [AS_HELP_STRING([--with-java@<:@=PREFIX@:>@], [Path to Java home.])],
@@ -2301,6 +2375,10 @@ if test "x$JAVA_LDFLAGS" != "x"
 then
        AC_MSG_NOTICE([Building with JAVA_LDFLAGS set to: $JAVA_LDFLAGS])
 fi
+if test "x$JAVA_LIBS" != "x"
+then
+       AC_MSG_NOTICE([Building with JAVA_LIBS set to: $JAVA_LIBS])
+fi
 if test "x$JAVAC" = "x"
 then
        with_javac_path="$PATH"
@@ -2341,9 +2419,11 @@ fi
 SAVE_CPPFLAGS="$CPPFLAGS"
 SAVE_CFLAGS="$CFLAGS"
 SAVE_LDFLAGS="$LDFLAGS"
+SAVE_LIBS="$LIBS"
 CPPFLAGS="$CPPFLAGS $JAVA_CPPFLAGS"
 CFLAGS="$CFLAGS $JAVA_CFLAGS"
 LDFLAGS="$LDFLAGS $JAVA_LDFLAGS"
+LIBS="$LIBS $JAVA_LIBS"
 
 if test "x$with_java" = "xyes"
 then
@@ -2353,8 +2433,8 @@ if test "x$with_java" = "xyes"
 then
        AC_CHECK_LIB(jvm, JNI_CreateJavaVM,
        [with_java="yes"],
-       [with_java="no (libjvm not found)"],
-       [$JAVA_LIBS])
+       [with_java="no (Symbol 'JNI_CreateJavaVM' not found)"],
+       [$JAVA_LIBS $PTHREAD_LIBS])
 fi
 if test "x$with_java" = "xyes"
 then
@@ -2365,6 +2445,7 @@ fi
 CPPFLAGS="$SAVE_CPPFLAGS"
 CFLAGS="$SAVE_CFLAGS"
 LDFLAGS="$SAVE_LDFLAGS"
+LIBS="$SAVE_LIBS"
 
 AC_SUBST(JAVA_CPPFLAGS)
 AC_SUBST(JAVA_CFLAGS)
@@ -2436,17 +2517,25 @@ with_liblvm2app_cppflags=""
 with_liblvm2app_ldflags=""
 AC_ARG_WITH(liblvm2app, [AS_HELP_STRING([--with-liblvm2app@<:@=PREFIX@:>@], [Path to liblvm2app.])],
 [
-        if test "x$withval" != "xno" && test "x$withval" != "xyes"
-        then
-                with_liblvm2app_cppflags="-I$withval/include"
-                with_liblvm2app_ldflags="-L$withval/lib"
-                with_liblvm2app="yes"
-        else
-                with_liblvm2app="$withval"
+       if test "x$withval" = "xno"
+       then
+               with_liblvm2app="no"
+       else
+               with_liblvm2app="yes"
+               if test "x$withval" != "xyes"
+               then
+                       with_liblvm2app_cppflags="-I$withval/include"
+                       with_liblvm2app_ldflags="-L$withval/lib"
+               fi
         fi
 ],
 [
-        with_liblvm2app="yes"
+       if test "x$ac_system" = "xLinux"
+       then
+               with_liblvm2app="yes"
+       else
+               with_liblvm2app="no (Linux only library)"
+       fi
 ])
 if test "x$with_liblvm2app" = "xyes"
 then
@@ -2689,6 +2778,55 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBMONGOC, test "x$with_libmongoc" = "xyes")
 # }}}
 
+# --with-libmosquitto {{{
+with_libmosquitto_cppflags=""
+with_libmosquitto_ldflags=""
+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_ldflags="-L$withval/lib"
+               with_libmosquitto="yes"
+       else
+               with_libmosquitto="$withval"
+       fi
+],
+[
+       with_libmosquitto="yes"
+])
+if test "x$with_libmosquitto" = "xyes"
+then
+       SAVE_CPPFLAGS="$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="$LDFLAGS $with_libmosquitto_ldflags"
+       CPPFLAGS="$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_LDFLAGS="$with_libmosquitto_ldflags"
+       BUILD_WITH_LIBMOSQUITTO_LIBS="-lmosquitto"
+       AC_SUBST(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBMOSQUITTO_LDFLAGS)
+       AC_SUBST(BUILD_WITH_LIBMOSQUITTO_LIBS)
+fi
+# }}}
+
 # --with-libmysql {{{
 with_mysql_config="mysql_config"
 with_mysql_cflags=""
@@ -2941,7 +3079,7 @@ then
 
        if test "x$LIBNETAPP_LIBS" = "x"
        then
-               LIBNETAPP_LIBS="-lpthread -lxml -ladt -lssl -lm -lcrypto -lz"
+               LIBNETAPP_LIBS="$PTHREAD_LIBS -lxml -ladt -lssl -lm -lcrypto -lz"
        fi
        AC_MSG_NOTICE([netapp LIBS: $LIBNETAPP_LIBS])
 
@@ -3209,13 +3347,13 @@ fi
 
 # --with-libowcapi {{{
 with_libowcapi_cppflags=""
-with_libowcapi_libs="-lowcapi"
+with_libowcapi_ldflags=""
 AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path to libowcapi.])],
 [
        if test "x$withval" != "xno" && test "x$withval" != "xyes"
        then
                with_libowcapi_cppflags="-I$withval/include"
-               with_libowcapi_libs="-L$withval/lib -lowcapi"
+               with_libowcapi_ldflags="-L$withval/lib"
                with_libowcapi="yes"
        else
                with_libowcapi="$withval"
@@ -3227,7 +3365,7 @@ AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path
 if test "x$with_libowcapi" = "xyes"
 then
        SAVE_CPPFLAGS="$CPPFLAGS"
-       CPPFLAGS="$with_libowcapi_cppflags"
+       CPPFLAGS="$CPPFLAGS $with_libowcapi_cppflags"
 
        AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"])
 
@@ -3237,7 +3375,7 @@ if test "x$with_libowcapi" = "xyes"
 then
        SAVE_LDFLAGS="$LDFLAGS"
        SAVE_CPPFLAGS="$CPPFLAGS"
-       LDFLAGS="$with_libowcapi_libs"
+       LDFLAGS="$LDFLAGS $with_libowcapi_ldflags"
        CPPFLAGS="$with_libowcapi_cppflags"
 
        AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"])
@@ -3248,8 +3386,10 @@ fi
 if test "x$with_libowcapi" = "xyes"
 then
        BUILD_WITH_LIBOWCAPI_CPPFLAGS="$with_libowcapi_cppflags"
-       BUILD_WITH_LIBOWCAPI_LIBS="$with_libowcapi_libs"
+       BUILD_WITH_LIBOWCAPI_LDFLAGS="$with_libowcapi_ldflags"
+       BUILD_WITH_LIBOWCAPI_LIBS="-lowcapi"
        AC_SUBST(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBOWCAPI_LDFLAGS)
        AC_SUBST(BUILD_WITH_LIBOWCAPI_LIBS)
 fi
 # }}}
@@ -3578,41 +3718,6 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
 # }}}
 
-# --with-libpthread {{{
-AC_ARG_WITH(libpthread, [AS_HELP_STRING([--with-libpthread=@<:@=PREFIX@:>@], [Path to libpthread.])],
-[      if test "x$withval" != "xno" \
-               && test "x$withval" != "xyes"
-       then
-               LDFLAGS="$LDFLAGS -L$withval/lib"
-               CPPFLAGS="$CPPFLAGS -I$withval/include"
-               with_libpthread="yes"
-       else
-               if test "x$withval" = "xno"
-               then
-                       with_libpthread="no (disabled)"
-               fi
-       fi
-], [with_libpthread="yes"])
-if test "x$with_libpthread" = "xyes"
-then
-       AC_CHECK_LIB(pthread, pthread_create, [with_libpthread="yes"], [with_libpthread="no (libpthread not found)"], [])
-fi
-
-if test "x$with_libpthread" = "xyes"
-then
-       AC_CHECK_HEADERS(pthread.h,, [with_libpthread="no (pthread.h not found)"])
-fi
-if test "x$with_libpthread" = "xyes"
-then
-       collect_pthread=1
-else
-       collect_pthread=0
-fi
-AC_DEFINE_UNQUOTED(HAVE_LIBPTHREAD, [$collect_pthread],
-       [Wether or not to use pthread (POSIX threads) library])
-AM_CONDITIONAL(BUILD_WITH_LIBPTHREAD, test "x$with_libpthread" = "xyes")
-# }}}
-
 # --with-python {{{
 with_python_prog=""
 with_python_path="$PATH"
@@ -4059,11 +4164,6 @@ then
        SAVE_CPPFLAGS="$CPPFLAGS"
        CPPFLAGS="$CPPFLAGS $with_sensors_cflags"
 
-#      AC_CHECK_HEADERS(sensors/sensors.h,
-#      [
-#              AC_DEFINE(HAVE_SENSORS_SENSORS_H, 1, [Define to 1 if you have the <sensors/sensors.h> header file.])
-#      ],
-#      [with_libsensors="no (sensors/sensors.h not found)"])
        AC_CHECK_HEADERS(sensors/sensors.h, [], [with_libsensors="no (sensors/sensors.h not found)"])
 
        CPPFLAGS="$SAVE_CPPFLAGS"
@@ -4271,6 +4371,7 @@ fi
 if test "x$with_libstatgrab" = "xyes"
 then
   SAVE_CFLAGS="$CFLAGS"
+  SAVE_LDFLAGS="$LDFLAGS"
   SAVE_LIBS="$LIBS"
 
   CFLAGS="$CFLAGS $with_libstatgrab_cflags"
@@ -4719,7 +4820,7 @@ AC_ARG_WITH(mic,[AS_HELP_STRING([--with-mic@<:@=PREFIX@:>@], [Path to Intel MIC
                AC_MSG_NOTICE([Not checking for Intel Mic: Manually configured])
                with_mic_cflags="-I$withval/include"
                with_mic_ldpath="-L$withval/lib/Linux"
-               with_mic_libs="-lMicAccessSDK -lscif -lpthread"
+               with_mic_libs="$PTHREAD_LIBS -lMicAccessSDK -lscif"
                with_mic="yes"
        fi; fi; fi
 ],
@@ -4741,8 +4842,8 @@ then
 
        AC_CHECK_LIB(MicAccessSDK, MicInitAPI,
                        [with_mic_ldpath="$with_mic_ldpath"
-                       with_mic_libs="-lMicAccessSDK -lscif -lpthread"],
-                       [with_mic="no (symbol MicInitAPI not found)"],[-lscif -lpthread])
+                       with_mic_libs="$PTHREAD_LIBS -lMicAccessSDK -lscif"],
+                       [with_mic="no (symbol MicInitAPI not found)"],[$PTHREAD_LIBS -lscif])
 
        CPPFLAGS="$SAVE_CPPFLAGS"
        LDFLAGS="$SAVE_LDFLAGS"
@@ -5099,11 +5200,8 @@ AM_CONDITIONAL(BUILD_WITH_LIBATASMART, test "x$with_libatasmart" = "xyes")
 
 PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
                [with_libnotify="yes"],
-               [if test "x$LIBNOTIFY_PKG_ERRORS" = "x"; then
-                        with_libnotify="no"
-                else
-                        with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"
-                fi])
+               [with_libnotify="no (pkg-config doesn't know libnotify)"]
+)
 
 # Check for enabled/disabled features
 #
@@ -5227,6 +5325,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"
@@ -5277,6 +5376,7 @@ plugin_vmem="no"
 plugin_vserver="no"
 plugin_wireless="no"
 plugin_zfs_arc="no"
+plugin_zone="no"
 plugin_zookeeper="no"
 
 # Linux
@@ -5328,6 +5428,14 @@ then
        plugin_tcpconns="yes"
 fi
 
+if test "x$ac_system" = "xNetBSD"
+then
+       plugin_entropy="yes"
+       plugin_irq="yes"
+       plugin_processes="yes"
+       plugin_disk="yes"
+fi
+
 # Mac OS X devices
 if test "x$with_libiokit" = "xyes"
 then
@@ -5347,6 +5455,7 @@ fi
 
 if test "x$ac_system" = "xFreeBSD"
 then
+       plugin_disk="yes"
        plugin_zfs_arc="yes"
 fi
 
@@ -5375,6 +5484,7 @@ then
        plugin_processes="yes"
        plugin_uptime="yes"
        plugin_zfs_arc="yes"
+       plugin_zone="yes"
 fi
 
 if test "x$with_devinfo$with_kstat" = "xyesyes"
@@ -5387,7 +5497,6 @@ then
 fi
 
 # libi2c-dev
-with_libi2c="no"
 if test "x$ac_system" = "xLinux"
 then
 AC_CHECK_DECL(i2c_smbus_read_i2c_block_data,
@@ -5395,6 +5504,8 @@ AC_CHECK_DECL(i2c_smbus_read_i2c_block_data,
        [with_libi2c="no (symbol i2c_smbus_read_i2c_block_data not found - have you installed libi2c-dev ?)"],
        [[#include <stdlib.h>
        #include <linux/i2c-dev.h>]])
+else
+       with_libi2c="no (Linux only)"
 fi
 
 if test "x$with_libi2c" = "xyes"
@@ -5571,6 +5682,11 @@ then
        plugin_swap="yes"
 fi
 
+if test "x$have_swapctl" = "xyes" && test "x$c_cv_have_swapctl_three_args" = "xyes"
+then
+       plugin_swap="yes"
+fi
+
 if test "x$with_kvm_openfiles$with_kvm_nlist" = "xyesyes"
 then
        plugin_tcpconns="yes"
@@ -5670,6 +5786,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])
@@ -5679,6 +5796,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])
@@ -5745,6 +5863,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
@@ -5896,6 +6015,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
 
@@ -5926,6 +6052,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
@@ -5949,6 +6086,7 @@ Configuration:
     libmnl  . . . . . . . $with_libmnl
     libmodbus . . . . . . $with_libmodbus
     libmongoc . . . . . . $with_libmongoc
+    libmosquitto  . . . . $with_libmosquitto
     libmysql  . . . . . . $with_libmysql
     libnetapp . . . . . . $with_libnetapp
     libnetsnmp  . . . . . $with_libnetsnmp
@@ -6048,6 +6186,7 @@ Configuration:
     memory  . . . . . . . $enable_memory
     mic . . . . . . . . . $enable_mic
     modbus  . . . . . . . $enable_modbus
+    mqtt  . . . . . . . . $enable_mqtt
     multimeter  . . . . . $enable_multimeter
     mysql . . . . . . . . $enable_mysql
     netapp  . . . . . . . $enable_netapp
@@ -6057,6 +6196,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
@@ -6122,6 +6262,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 1a8eb0e..4d4e0aa 100644 (file)
@@ -66,6 +66,7 @@
 %{?el7:%global _has_atasmart 1}
 %{?el7:%global _has_hiredis 1}
 %{?el7:%global _has_asm_msr_index 1}
+%{?el7:%global _has_libmosquitto 1}
 %{?el7:%global _has_libmodbus 1}
 %{?el7:%global _has_xmms 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_kafka 0%{!?_without_write_kafka:0}
 # plugin write_mongodb disabled, requires libmongoc
 %define with_write_mongodb 0%{!?_without_write_mongodb:0}
+# plugin zone disabled, requires Solaris
+%define with_zone 0%{!?_without_zone:0}
 
 Summary:       statistics collection and monitoring daemon
 Name:          collectd
@@ -513,6 +518,16 @@ MySQL querying plugin. This plugin provides data of issued commands, called
 handlers and database traffic.
 %endif
 
+%if %{with_mqtt}
+%package mqtt
+Summary:       mqtt plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: mosquitto-devel
+%description mqtt
+The MQTT plugin publishes and subscribes to MQTT topics.
+%endif
+
 %if %{with_netlink}
 %package netlink
 Summary:       netlink plugin for collectd
@@ -1174,6 +1189,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
@@ -1222,6 +1243,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
@@ -1580,6 +1607,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
@@ -1648,6 +1681,7 @@ Collectd utilities
        %{?_with_mic} \
        %{?_with_modbus} \
        %{?_with_multimeter} \
+       %{?_with_mqtt} \
        %{?_with_mysql} \
        %{?_with_netapp} \
        %{?_with_netlink} \
@@ -1681,6 +1715,7 @@ Collectd utilities
        %{?_with_write_redis} \
        %{?_with_xmms} \
        %{?_with_zfs_arc} \
+       %{?_with_zone} \
        %{?_with_zookeeper} \
        %{?_with_irq} \
        %{?_with_load} \
@@ -1692,6 +1727,7 @@ Collectd utilities
        %{?_with_memory} \
        %{?_with_network} \
        %{?_with_nfs} \
+       %{?_with_notify_nagios} \
        %{?_with_ntpd} \
        %{?_with_numa} \
        %{?_with_olsrd} \
@@ -1958,6 +1994,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
@@ -2205,6 +2244,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
@@ -2349,6 +2393,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 9b845ca..3832bd2 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
@@ -76,7 +97,7 @@ if BUILD_AIX
 collectd_tg_LDADD += -lm
 endif
 if BUILD_WITH_LIBPTHREAD
-collectd_tg_LDADD += -lpthread
+collectd_tg_LDADD += $(PTHREAD_LIBS)
 endif
 collectd_tg_LDADD += libcollectdclient/libcollectdclient.la
 collectd_tg_DEPENDENCIES = libcollectdclient/libcollectdclient.la
@@ -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
@@ -325,21 +349,20 @@ if BUILD_PLUGIN_DNS
 pkglib_LTLIBRARIES += dns.la
 dns_la_SOURCES = dns.c utils_dns.c utils_dns.h
 dns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-dns_la_LIBADD = -lpcap -lpthread
+dns_la_LIBADD = $(PTHREAD_LIBS) -lpcap
 endif
 
 if BUILD_PLUGIN_DRBD
 pkglib_LTLIBRARIES += drbd.la
 drbd_la_SOURCES = drbd.c
 drbd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-drbd_la_LIBADD = -lpthread
 endif
 
 if BUILD_PLUGIN_EMAIL
 pkglib_LTLIBRARIES += email.la
 email_la_SOURCES = email.c
 email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-email_la_LIBADD = -lpthread
+email_la_LIBADD = $(PTHREAD_LIBS)
 endif
 
 if BUILD_PLUGIN_ENTROPY
@@ -355,7 +378,7 @@ exec_la_SOURCES = exec.c \
                  utils_cmd_putval.c utils_cmd_putval.h \
                  utils_parse_option.h utils_parse_option.c
 exec_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-exec_la_LIBADD = -lpthread
+exec_la_LIBADD = $(PTHREAD_LIBS)
 endif
 
 if BUILD_PLUGIN_ETHSTAT
@@ -444,6 +467,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
@@ -460,7 +485,7 @@ java_la_SOURCES = java.c
 java_la_CPPFLAGS = $(AM_CPPFLAGS) $(JAVA_CPPFLAGS)
 java_la_CFLAGS = $(AM_CFLAGS) $(JAVA_CFLAGS)
 java_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(JAVA_LDFLAGS)
-java_la_LIBADD = $(JAVA_LIBS)
+java_la_LIBADD = $(PTHREAD_LIBS) $(JAVA_LIBS)
 endif
 
 if BUILD_PLUGIN_LOAD
@@ -614,6 +639,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_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
+mqtt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMOSQUITTO_LDFLAGS)
+mqtt_la_LIBADD = $(BUILD_WITH_LIBMOSQUITTO_LIBS)
+endif
+
 if BUILD_PLUGIN_MULTIMETER
 pkglib_LTLIBRARIES += multimeter.la
 multimeter_la_SOURCES = multimeter.c
@@ -654,7 +687,7 @@ network_la_SOURCES = network.c network.h \
                     utils_fbhash.c utils_fbhash.h
 network_la_CPPFLAGS = $(AM_CPPFLAGS)
 network_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-network_la_LIBADD = -lpthread
+network_la_LIBADD = $(PTHREAD_LIBS)
 if BUILD_WITH_LIBSOCKET
 network_la_LIBADD += -lsocket
 endif
@@ -701,7 +734,13 @@ if BUILD_PLUGIN_NOTIFY_EMAIL
 pkglib_LTLIBRARIES += notify_email.la
 notify_email_la_SOURCES = notify_email.c
 notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-notify_email_la_LIBADD = -lesmtp -lssl -lcrypto -lpthread
+notify_email_la_LIBADD = $(PTHREAD_LIBS) -lesmtp -lssl -lcrypto
+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
@@ -725,7 +764,7 @@ pkglib_LTLIBRARIES += nut.la
 nut_la_SOURCES = nut.c
 nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
 nut_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-nut_la_LIBADD = -lpthread $(BUILD_WITH_LIBUPSCLIENT_LIBS)
+nut_la_LIBADD = $(PTHREAD_LIBS) $(BUILD_WITH_LIBUPSCLIENT_LIBS)
 endif
 
 if BUILD_PLUGIN_OLSRD
@@ -744,7 +783,7 @@ onewire_la_SOURCES = onewire.c
 onewire_la_CFLAGS = $(AM_CFLAGS)
 onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
 onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
-onewire_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+onewire_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOWCAPI_LDFLAGS)
 endif
 
 if BUILD_PLUGIN_OPENLDAP
@@ -932,16 +971,15 @@ snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
 snmp_la_LIBADD += $(BUILD_WITH_LIBSNMP_LIBS)
 endif
 if BUILD_WITH_LIBPTHREAD
-snmp_la_LIBADD += -lpthread
+snmp_la_LIBADD += $(PTHREAD_LIBS)
 endif
 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 = $(PTHREAD_LIBS) liblatency.la -lm
 endif
 
 if BUILD_PLUGIN_SWAP
@@ -1092,7 +1130,7 @@ unixsock_la_SOURCES = unixsock.c \
                      utils_cmd_putnotif.h utils_cmd_putnotif.c \
                      utils_parse_option.h utils_parse_option.c
 unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-unixsock_la_LIBADD = -lpthread
+unixsock_la_LIBADD = $(PTHREAD_LIBS)
 endif
 
 if BUILD_PLUGIN_UPTIME
@@ -1273,6 +1311,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 +1415,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 c515e3c..38035ca 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..b4bc099 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
@@ -234,7 +220,7 @@ static int net_recv (int *sockfd, char *buf, int buflen)
  * Returns zero on success
  * Returns non-zero on error
  */
-static int net_send (int *sockfd, char *buff, int len)
+static int net_send (int *sockfd, const char *buff, int len)
 {
        uint16_t packet_size;
 
@@ -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,43 +378,30 @@ 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)
+static void apc_submit_generic (const char *type, const char *type_inst, double value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -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..d38e859 100644 (file)
@@ -32,7 +32,7 @@
 #include <curl/curl.h>
 #include <libxml/parser.h>
 
-static char *races_list[] = /* {{{ */
+static const char *races_list[] = /* {{{ */
 {
   NULL,
   "Human",    /*  1 */
@@ -49,7 +49,7 @@ static char *races_list[] = /* {{{ */
 }; /* }}} */
 #define RACES_LIST_LENGTH STATIC_ARRAY_SIZE (races_list)
 
-static char *classes_list[] = /* {{{ */
+static const char *classes_list[] = /* {{{ */
 {
   NULL,
   "Warrior", /*  1 */
@@ -66,7 +66,7 @@ static char *classes_list[] = /* {{{ */
 }; /* }}} */
 #define CLASSES_LIST_LENGTH STATIC_ARRAY_SIZE (classes_list)
 
-static char *genders_list[] = /* {{{ */
+static const char *genders_list[] = /* {{{ */
 {
   "Male",
   "Female"
@@ -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 aaedd70..0e8deaf 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 c4c050d..b87739a 100644 (file)
@@ -143,7 +143,7 @@ static void submit_capacity (char const *plugin_instance, /* {{{ */
 } /* }}} void submit_capacity */
 
 #if HAVE_IOKIT_PS_IOPOWERSOURCES_H || HAVE_IOKIT_IOKITLIB_H
-static double dict_get_double (CFDictionaryRef dict, char *key_string) /* {{{ */
+static double dict_get_double (CFDictionaryRef dict, const char *key_string) /* {{{ */
 {
        double      val_double;
        long long   val_int;
index 6eac159..b9731ee 100644 (file)
@@ -1758,7 +1758,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 9c53a3e..b1ca3b6 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>
@@ -97,7 +96,7 @@ enum ceph_dset_type_d
 };
 
 /** Valid types for ceph defined in types.db */
-const char * ceph_dset_types [CEPH_DSET_TYPES_NUM] =
+static const char * const ceph_dset_types [CEPH_DSET_TYPES_NUM] =
                                    {"ceph_latency", "ceph_bytes", "ceph_rate"};
 
 /******* ceph_daemon *******/
index ae67125..1141140 100644 (file)
@@ -24,8 +24,8 @@
 
 struct case_s
 {
-  char *key;
-  char *value;
+  const char *key;
+  const char *value;
 };
 typedef struct case_s case_t;
 
@@ -136,11 +136,11 @@ DEF_TEST(traverse_json)
   yajl_handle hndl;
 #if HAVE_YAJL_V2
   hndl = yajl_alloc (&callbacks, NULL, &ctx);
-  CHECK_ZERO (traverse_json ((unsigned char *) json, (uint32_t) strlen (json), hndl));
+  CHECK_ZERO (traverse_json ((const unsigned char *) json, (uint32_t) strlen (json), hndl));
   CHECK_ZERO (yajl_complete_parse (hndl));
 #else
   hndl = yajl_alloc (&callbacks, NULL, NULL, &ctx);
-  CHECK_ZERO (traverse_json ((unsigned char *) json, (uint32_t) strlen (json), hndl));
+  CHECK_ZERO (traverse_json ((const unsigned char *) json, (uint32_t) strlen (json), hndl));
   CHECK_ZERO (yajl_parse_complete (hndl));
 #endif
 
@@ -150,8 +150,8 @@ DEF_TEST(traverse_json)
 DEF_TEST(parse_keys)
 {
   struct {
-    char *str;
-    char *want;
+    const char *str;
+    const char *want;
   } cases[] = {
     {"WBThrottle.bytes_dirtied.description.bytes_wb.description.ios_dirtied.description.ios_wb.type", "WBThrottle.bytesDirtied.description.bytesWb.description.iosDirt"},
     {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
@@ -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..49e84f3 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;
 
@@ -245,6 +245,7 @@ static int match_range (range_t *range, double value)
        return (((ret - range->invert) == 0) ? 0 : 1);
 } /* int match_range */
 
+__attribute__((noreturn))
 static void usage (const char *name)
 {
        fprintf (stderr, "Usage: %s <-s socket> <-n value_spec> <-H hostname> [options]\n"
index 08bb748..53fd3a1 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)
@@ -212,7 +225,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)
@@ -327,7 +340,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);
@@ -400,14 +413,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 36eca9c..20b17b2 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>
 #<Plugin interface>
 #      Interface "eth0"
 #      IgnoreSelected false
+#      UniqueName false
 #</Plugin>
 
 #<Plugin ipmi>
 #      </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
 ##     None of the following option should be set manually
 ##     This plugin automatically detect most optimal options
 ##     Only set values here if:
-##     - The module ask you to
+##     - The module asks you to
 ##     - You want to disable the collection of some data
-##     - Your (intel) CPU is not supported (yet) by the module
-##     - The module generate a lot of errors 'MSR offset 0x... read failed'
+##     - Your (Intel) CPU is not supported (yet) by the module
+##     - The module generates a lot of errors 'MSR offset 0x... read failed'
 ##     In the last two cases, please open a bug request
 #
 #      TCCActivationTemp "100"
 #    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 56bab99..cf7ccd0 100644 (file)
@@ -38,7 +38,7 @@ i.e. a C<E<lt>PluginE<nbsp>...E<gt>> block.
 The syntax of this config file is similar to the config file of the famous
 I<Apache> webserver. Each line contains either an option (a key and a list of
 one or more values) or a section-start or -end. Empty lines and everything
-after a non-quoted hash-symbol (C<#>) is ignored. I<Keys> are unquoted
+after a non-quoted hash-symbol (C<#>) are ignored. I<Keys> are unquoted
 strings, consisting only of alphanumeric characters and the underscore (C<_>)
 character. Keys are handled case insensitive by I<collectd> itself and all
 plugins included with it. I<Values> can either be an I<unquoted string>, a
@@ -70,7 +70,7 @@ C<E<lt>B<Plugin> ...E<gt>> block.
 
 =item B<BaseDir> I<Directory>
 
-Sets the base directory. This is the directory beneath all RRD-files are
+Sets the base directory. This is the directory beneath which all RRD-files are
 created. Possibly more subdirectories are created. This is also the working
 directory for the daemon.
 
@@ -83,7 +83,7 @@ I<collectd> will be mostly useless.
 Only the first B<LoadPlugin> statement or block for a given plugin name has any
 effect. This is useful when you want to split up the configuration into smaller
 files and want each file to be "self contained", i.e. it contains a B<Plugin>
-block I<and> then appropriate B<LoadPlugin> statement. The downside is that if
+block I<and> the appropriate B<LoadPlugin> statement. The downside is that if
 you have multiple conflicting B<LoadPlugin> blocks, e.g. when they specify
 different intervals, only one of them (the first one encountered) will take
 effect and all others will be silently ignored.
@@ -127,8 +127,17 @@ the average user from ever having to deal with this low level linking stuff.
 =item B<Interval> I<Seconds>
 
 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.
+global B<Interval> setting. If a plugin provides its own support for specifying
+an interval, that setting will take precedence.
+
+=item B<FlushInterval> I<Seconds>
+
+Specifies 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
 
@@ -205,7 +214,7 @@ matching C<*.conf> in any subdirectory of C</etc/collectd.d>:
 
 =back
 
-If more than one files are included by a single B<Include> option, the files
+If more than one file is included by a single B<Include> option, the files
 will be included in lexicographical order (as defined by the C<strcmp>
 function). Thus, you can e.E<nbsp>g. use numbered prefixes to specify the
 order in which the files are loaded.
@@ -246,7 +255,7 @@ magic! (Assuming you're using the I<RRDtool> or I<RRDCacheD> plugin.)
 
 =item B<MaxReadInterval> I<Seconds>
 
-Read plugin doubles interval between queries after each failed attempt
+A read plugin doubles the interval between queries after each failed attempt
 to get data.
 
 This options limits the maximum value of the interval. The default value is
@@ -519,7 +528,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
@@ -817,12 +828,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>
@@ -1821,6 +1842,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"
@@ -2000,6 +2022,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
@@ -2530,6 +2557,17 @@ with I<veth> and all interfaces with names starting with I<tun> followed by
 at least one digit.
 
 
+=item B<UniqueName> I<true>|I<false>
+
+Interface name is not unique on Solaris (KSTAT), interface name is unique 
+only within a module/instance. Following tuple is considered unique: 
+   (ks_module, ks_instance, ks_name)
+If this option is set to true, interface name contains above three fields
+separated by an underscore. For more info on KSTAT, visit
+L<http://docs.oracle.com/cd/E23824_01/html/821-1468/kstat-3kstat.html#REFMAN3Ekstat-3kstat>
+
+This option is only available on Solaris.
+
 =back
 
 =head2 Plugin C<ipmi>
@@ -3250,6 +3288,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
@@ -4305,6 +4483,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>
 
 The C<ntpd> plugin collects per-peer ntpd data such as time offset and time
@@ -4542,6 +4735,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.
@@ -4813,6 +5016,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
@@ -5470,6 +5680,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>
@@ -6084,6 +6298,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, creates a C<count> metric which reports the change since the last
+read. This option primarily exists for compatibility with the I<statsd>
+implementation by Etsy.
+
 =item B<TimerPercentile> I<Percent>
 
 Calculate and dispatch the configured percentile, i.e. compute the latency, so
@@ -7038,17 +7258,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
 
@@ -7123,6 +7343,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>.
@@ -7391,6 +7619,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
@@ -7517,14 +7749,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.
 
@@ -7559,6 +7797,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 d019d27..7d3cbce 100644 (file)
@@ -72,6 +72,7 @@
 extern char *optarg;
 extern int   optind;
 
+__attribute__((noreturn))
 static void exit_usage (const char *name, int status) {
   fprintf ((status == 0) ? stdout : stderr,
       "Usage: %s [options] <command> [cmd options]\n\n"
@@ -120,7 +121,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 +230,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 +508,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 +552,14 @@ int main (int argc, char **argv) {
   int status;
 
   while (42) {
-    int n;
+    int opt;
 
-    n = getopt (argc, argv, "s:h");
+    opt = getopt (argc, argv, "s:h");
 
-    if (n == -1)
+    if (opt == -1)
       break;
 
-    switch (n) {
+    switch (opt) {
       case 's':
         snprintf (address, sizeof (address), "unix:%s", optarg);
         address[sizeof (address) - 1] = '\0';
index 33f02b4..2c1d589 100644 (file)
 static int loop    = 0;
 static int restart = 0;
 
-static char  *pidfile      = NULL;
-static pid_t  collectd_pid = 0;
+static const char *pidfile      = NULL;
+static pid_t       collectd_pid = 0;
 
-static void exit_usage (char *name)
+__attribute__((noreturn))
+static void exit_usage (const char *name)
 {
        printf ("Usage: %s <options> [-- <collectd options>]\n"
 
@@ -119,6 +120,7 @@ static int pidfile_delete (void)
 static int daemonize (void)
 {
        struct rlimit rl;
+       int dev_null;
 
        pid_t pid = 0;
        int   i   = 0;
@@ -152,26 +154,30 @@ static int daemonize (void)
        for (i = 0; i < (int)rl.rlim_max; ++i)
                close (i);
 
-       errno = 0;
-       if (open ("/dev/null", O_RDWR) != 0) {
-               syslog (LOG_ERR, "Error: couldn't connect STDIN to /dev/null: %s",
-                               strerror (errno));
+       dev_null = open ("/dev/null", O_RDWR);
+       if (dev_null == -1) {
+               syslog (LOG_ERR, "Error: couldn't failed to open /dev/null: %s", strerror (errno));
                return -1;
        }
 
-       errno = 0;
-       if (dup (0) != 1) {
-               syslog (LOG_ERR, "Error: couldn't connect STDOUT to /dev/null: %s",
-                               strerror (errno));
+       if (dup2 (dev_null, STDIN_FILENO) == -1) {
+               syslog (LOG_ERR, "Error: couldn't connect STDIN to /dev/null: %s", strerror (errno));
                return -1;
        }
 
-       errno = 0;
-       if (dup (0) != 2) {
-               syslog (LOG_ERR, "Error: couldn't connect STDERR to /dev/null: %s",
-                               strerror (errno));
+       if (dup2 (dev_null, STDOUT_FILENO) == -1) {
+               syslog (LOG_ERR, "Error: couldn't connect STDOUT to /dev/null: %s", strerror (errno));
                return -1;
        }
+
+       if (dup2 (dev_null, STDERR_FILENO) == -1) {
+               syslog (LOG_ERR, "Error: couldn't connect STDERR to /dev/null: %s", strerror (errno));
+               return -1;
+       }
+
+       if ((dev_null != STDIN_FILENO) && (dev_null != STDOUT_FILENO) && (dev_null != STDERR_FILENO))
+               close (dev_null);
+
        return 0;
 } /* daemonize */
 
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 448db15..45898c3 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>
 
@@ -646,11 +645,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);
@@ -755,9 +752,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");
@@ -773,7 +767,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);
   }
@@ -867,7 +861,7 @@ static void cj_submit (cj_t *db, cj_key_t *key, value_t *value) /* {{{ */
 static int cj_sock_perform (cj_t *db) /* {{{ */
 {
   char errbuf[1024];
-  struct sockaddr_un sa_unix = {};
+  struct sockaddr_un sa_unix = { 0 };
   sa_unix.sun_family = AF_UNIX;
   sstrncpy (sa_unix.sun_path, db->sock, sizeof (sa_unix.sun_path));
 
index 3ffb71c..39d6fd0 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++)
@@ -903,8 +903,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);
@@ -1022,7 +1021,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 6e625bb..6f29917 100644 (file)
@@ -32,7 +32,6 @@
 #include "configfile.h"
 
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <netdb.h>
 
@@ -270,6 +269,7 @@ static void update_kstat (void)
 /* TODO
  * Remove all settings but `-f' and `-C'
  */
+__attribute__((noreturn))
 static void exit_usage (int status)
 {
        printf ("Usage: "PACKAGE_NAME" [OPTIONS]\n\n"
@@ -425,15 +425,18 @@ static int pidfile_remove (void)
 #ifdef KERNEL_LINUX
 static 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 +445,69 @@ static int notify_upstart (void)
 
 static 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.");
 
-    WARNING ("supervised by systemd, will signal readyness");
-    if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
-        WARNING ("cannot contact systemd socket %s", notifysocket);
+    unsetenv ("NOTIFY_SOCKET");
+
+#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;
 }
@@ -496,7 +519,7 @@ int main (int argc, char **argv)
        struct sigaction sig_term_action;
        struct sigaction sig_usr1_action;
        struct sigaction sig_pipe_action;
-       char *configfile = CONFIGFILE;
+       const char *configfile = CONFIGFILE;
        int test_config  = 0;
        int test_readall = 0;
        const char *basedir;
@@ -616,6 +639,8 @@ int main (int argc, char **argv)
 #endif
        )
        {
+               int status;
+
                if ((pid = fork ()) == -1)
                {
                        /* error */
@@ -644,19 +669,24 @@ int main (int argc, char **argv)
                close (1);
                close (0);
 
-               if (open ("/dev/null", O_RDWR) != 0)
+               status = open ("/dev/null", O_RDWR);
+               if (status != 0)
                {
-                       ERROR ("Error: Could not connect `STDIN' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDIN' to `/dev/null' (status %d)", status);
                        return (1);
                }
-               if (dup (0) != 1)
+
+               status = dup (0);
+               if (status != 1)
                {
-                       ERROR ("Error: Could not connect `STDOUT' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDOUT' to `/dev/null' (status %d)", status);
                        return (1);
                }
-               if (dup (0) != 2)
+
+               status = dup (0);
+               if (status != 2)
                {
-                       ERROR ("Error: Could not connect `STDERR' to `/dev/null'");
+                       ERROR ("Error: Could not connect `STDERR' to `/dev/null', (status %d)", status);
                        return (1);
                }
        } /* if (daemonize) */
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..ca8f15a 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  */
 
-#include "testing.h"
 #include "common.h"
+#include "testing.h"
+
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
 
 DEF_TEST(sstrncpy)
 {
@@ -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..8a7621d 100644 (file)
@@ -72,15 +72,15 @@ typedef struct cf_complex_callback_s
 
 typedef struct cf_value_map_s
 {
-       char *key;
+       const char *key;
        int (*func) (oconfig_item_t *);
 } cf_value_map_t;
 
 typedef struct cf_global_option_s
 {
-       char *key;
+       const char *key;
        char *value;
-       char *def;
+       const char *def;
 } cf_global_option_t;
 
 /*
@@ -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);
                }
        }
 
@@ -376,7 +381,7 @@ static int dispatch_value (oconfig_item_t *ci)
 static int dispatch_block_plugin (oconfig_item_t *ci)
 {
        int i;
-       char *name;
+       const char *name;
 
        cf_complex_callback_t *cb;
 
@@ -1110,7 +1115,7 @@ int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *))
        return (0);
 } /* int cf_register_complex */
 
-int cf_read (char *filename)
+int cf_read (const char *filename)
 {
        oconfig_item_t *conf;
        int i;
index 5bc9b30..648246b 100644 (file)
@@ -87,7 +87,7 @@ int cf_register_complex (const char *type, int (*callback) (oconfig_item_t *));
  *  Returns zero upon success and non-zero otherwise. A error-message will have
  *  been printed in this case.
  */
-int cf_read (char *filename);
+int cf_read (const char *filename);
 
 int global_option_set (const char *option, const char *value);
 const char *global_option_get (const char *option);
diff --git a/src/daemon/meta_data_test.c b/src/daemon/meta_data_test.c
new file mode 100644 (file)
index 0000000..48760d6
--- /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 "common.h" /* for STATIC_ARRAY_SIZE */
+#include "collectd.h"
+#include "testing.h"
+#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 e723af0..e7993f1 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,104 @@ 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)
+{
+       const 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;
+               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 +1462,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 +1486,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 +1640,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)
@@ -2030,8 +2159,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);
        }
@@ -2084,7 +2213,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;
                        }
@@ -2113,7 +2242,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;
        }
@@ -2599,7 +2728,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);
@@ -2706,7 +2839,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 cba298c..a63f5cd 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 4023a8f..eb50bb8 100644 (file)
@@ -102,7 +102,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)
@@ -123,14 +123,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..489d60f 100644 (file)
@@ -24,8 +24,9 @@
  *   Florian octo Forster <octo at collectd.org>
  */
 
-#include "testing.h"
+#include "common.h" /* STATIC_ARRAY_SIZE */
 #include "collectd.h"
+#include "testing.h"
 #include "utils_avltree.h"
 
 static int compare_total_count = 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 45444c7..0756807 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 53d0fba..6ef8047 100644 (file)
@@ -24,8 +24,8 @@
  *   Florian octo Forster <octo at collectd.org>
  */
 
-#include "testing.h"
 #include "collectd.h"
+#include "testing.h"
 #include "utils_heap.h"
 
 static int compare (void const *v0, void const *v1)
index 692a1e5..1268838 100644 (file)
@@ -88,50 +88,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)
 {
        regex_t *re;
-       ignorelist_item_t *item;
+       ignorelist_item_t *entry;
        int status;
 
-       /* create buffer */
        re = malloc (sizeof (*re));
        if (re == NULL)
        {
                ERROR ("ignorelist_append_regex: malloc failed.");
-               return ENOMEM;
+               return (ENOMEM);
        }
        memset (re, 0, sizeof (*re));
 
-       /* compile regex */
-       status = regcomp (re, entry, REG_EXTENDED);
+       status = regcomp (re, re_str, REG_EXTENDED);
        if (status != 0)
        {
                char errbuf[1024];
-
                (void) regerror (status, re, errbuf, sizeof (errbuf));
-               ERROR ("ignorelist_append_regex: Compiling regular expression \"%s\" failed: %s", entry, errbuf);
+               ERROR ("utils_ignorelist: regcomp failed: %s", errbuf);
+               ERROR ("ignorelist_append_regex: Compiling regular expression \"%s\" failed: %s", re_str, errbuf);
                sfree (re);
-               return status;
+               return (status);
        }
 
-       /* create new entry */
-       item = malloc (sizeof (*item));
-       if (item == NULL)
+       entry = malloc (sizeof (*entry));
+       if (entry == NULL)
        {
                ERROR ("ignorelist_append_regex: malloc failed.");
                regfree (re);
                sfree (re);
-               return ENOMEM;
+               return (ENOMEM);
        }
-       memset (item, 0, sizeof (*item));
-       item->rmatch = re;
-
-       /* append new entry */
-       ignorelist_append (il, item);
+       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)
@@ -263,7 +258,7 @@ 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)
 {
index 548d1d8..fee0871 100644 (file)
  *   Florian Forster <octo at collectd.org>
  **/
 
-#include <pthread.h>
-
 #include "collectd.h"
 #include "utils_time.h"
 #include "utils_random.h"
 
+#include <pthread.h>
+
 
 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 static _Bool have_seed = 0;
index 3e55497..cfa1c76 100644 (file)
 #include "common.h"
 #include "utils_subst.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 */
 
@@ -88,7 +115,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;
 
@@ -96,19 +122,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;
 
@@ -142,7 +162,6 @@ char *subst_string (char *buf, size_t buflen, const char *string,
                                i, string, needle, replacement);
        }
 
-       sfree (temp);
        return (buf);
 } /* char *subst_string */
 
index 9085286..50df9c7 100644 (file)
@@ -66,7 +66,7 @@
  *
  * The function returns 'buf' on success, NULL else.
  */
-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);
 
 /*
diff --git a/src/daemon/utils_subst_test.c b/src/daemon/utils_subst_test.c
new file mode 100644 (file)
index 0000000..953ccc4
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * 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 "common.h" /* for STATIC_ARRAY_SIZE */
+#include "collectd.h"
+#include "testing.h"
+#include "utils_subst.h"
+
+#if HAVE_LIBKSTAT
+kstat_ctl_t *kc;
+#endif /* HAVE_LIBKSTAT */
+
+DEF_TEST(subst)
+{
+  struct {
+    const char *str;
+    int off1;
+    int off2;
+    const char *rplmt;
+    const 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 {
+    const char *str;
+    const char *srch;
+    const char *rplmt;
+    const 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..56c250c 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,95 @@ 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 int format_zone (char *buffer, size_t buffer_size, struct tm const *tm) /* {{{ */
+{
+  char tmp[7];
+  size_t sz;
+
+  if ((buffer == NULL) || (buffer_size < 7))
+    return EINVAL;
+
+  sz = strftime (tmp, sizeof (tmp), "%z", tm);
+  if (sz == 0)
+    return ENOMEM;
+  if (sz != 5)
+  {
+    DEBUG ("format_zone: strftime(\"%%z\") = \"%s\", want \"+hhmm\"", tmp);
+    sstrncpy (buffer, tmp, buffer_size);
+    return 0;
+  }
+
+  buffer[0] = tmp[0];
+  buffer[1] = tmp[1];
+  buffer[2] = tmp[2];
+  buffer[3] = ':';
+  buffer[4] = tmp[3];
+  buffer[5] = tmp[4];
+  buffer[6] = 0;
+
+  return 0;
+} /* }}} 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;
+  int status;
 
   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);
+    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;
-  }
+  status = format_zone (zone, sizeof (zone), &t_tm);
+  if (status != 0)
+    return status;
+
+  if (strjoin (buffer, buffer_size, fields, STATIC_ARRAY_SIZE (fields), "") < 0)
+    return ENOMEM;
+  return 0;
+} /* }}} int format_rfc3339 */
+
+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..46faa9c 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);                \
+#define CDTIME_T_TO_TIMEVAL(cdt,tvp) do { \
+  (tvp)->tv_sec = (time_t) ((cdt) >> 30); \
+  (tvp)->tv_usec = (suseconds_t) ((((cdt) & 0x3fffffff) * 1000000 + (1 << 29)) >> 30); \
 } 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);                      \
+#define CDTIME_T_TO_TIMESPEC(cdt,tsp) do { \
+  (tsp)->tv_sec = (time_t) ((cdt) >> 30); \
+  (tsp)->tv_nsec = (long) ((((cdt) & 0x3fffffff) * 1000000000 + (1 << 29)) >> 30); \
 } 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..4d64991
--- /dev/null
@@ -0,0 +1,127 @@
+/**
+ * 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 "collectd.h"
+#include "testing.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}, {1439981150,  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_sec, tv.tv_sec);
+    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_sec, ts.tv_sec);
+    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..b60fefa 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];
@@ -552,7 +681,6 @@ static int disk_read (void)
        {
                char *disk_name;
                char *output_name;
-               char *alt_name;
 
                numfields = strsplit (buffer, fields, 32);
 
@@ -712,13 +840,10 @@ static int disk_read (void)
                output_name = disk_name;
 
 #if HAVE_LIBUDEV
-               alt_name = disk_udev_attr_name (handle_udev, disk_name,
-                               conf_udev_name_attr);
-#else
-               alt_name = NULL;
-#endif
+               char *alt_name = disk_udev_attr_name (handle_udev, disk_name, conf_udev_name_attr);
                if (alt_name != NULL)
                        output_name = alt_name;
+#endif
 
                if ((ds->read_bytes != 0) || (ds->write_bytes != 0))
                        disk_submit (output_name, "disk_octets",
@@ -740,8 +865,10 @@ static int disk_read (void)
                        submit_io_time (output_name, io_time, weighted_time);
                } /* if (is_disk) */
 
+#if HAVE_LIBUDEV
                /* release udev-based alternate name, if allocated */
-               free(alt_name);
+               sfree (alt_name);
+#endif
        } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
 
 #if HAVE_LIBUDEV
index 6a0c0a4..81ae29c 100644 (file)
@@ -50,7 +50,6 @@
 # include <pthread.h>
 #endif
 
-#include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/select.h>
 
@@ -390,8 +389,8 @@ static void *open_connection (void __attribute__((unused)) *arg)
 {
        struct sockaddr_un addr;
 
-       char *path  = (NULL == sock_file) ? SOCK_PATH : sock_file;
-       char *group = (NULL == sock_group) ? COLLECTD_GRP_NAME : sock_group;
+       const char *path  = (NULL == sock_file) ? SOCK_PATH : sock_file;
+       const char *group = (NULL == sock_group) ? COLLECTD_GRP_NAME : sock_group;
 
        /* create UNIX socket */
        errno = 0;
index 2ac9f25..f86d8f7 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)
@@ -496,7 +493,7 @@ static staging_entry_t *staging_entry_get (const char *host, /* {{{ */
 
 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;
@@ -510,7 +507,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..90dc139 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
@@ -98,6 +95,7 @@ static ignorelist_t *ignorelist = NULL;
 extern kstat_ctl_t *kc;
 static kstat_t *ksp[MAX_NUMIF];
 static int numif = 0;
+static _Bool unique_name = 0;
 #endif /* HAVE_LIBKSTAT */
 
 static int interface_config (const char *key, const char *value)
@@ -116,6 +114,15 @@ static int interface_config (const char *key, const char *value)
                        invert = 0;
                ignorelist_set_invert (ignorelist, invert);
        }
+       else if (strcasecmp (key, "UniqueName") == 0)
+       {
+               #ifdef HAVE_LIBKSTAT
+               if (IS_TRUE (value))
+                       unique_name = 1;
+               #else
+                       WARNING ("interface plugin: the \"UniqueName\" option is only valid on Solaris.");
+               #endif /* HAVE_LIBKSTAT */
+       }
        else
        {
                return (-1);
@@ -183,7 +190,7 @@ static int interface_read (void)
        struct ifaddrs *if_list;
        struct ifaddrs *if_ptr;
 
-/* Darin/Mac OS X and possible other *BSDs */
+/* Darwin/Mac OS X and possible other *BSDs */
 #if HAVE_STRUCT_IF_DATA
 #  define IFA_DATA if_data
 #  define IFA_RX_BYTES ifi_ibytes
@@ -279,6 +286,10 @@ static int interface_read (void)
                incoming = atoll (fields[2]);
                outgoing = atoll (fields[10]);
                if_submit (device, "if_errors", incoming, outgoing);
+
+               incoming = atoll (fields[3]);
+               outgoing = atoll (fields[11]);
+               if_submit (device, "if_dropped", incoming, outgoing);
        }
 
        fclose (fh);
@@ -288,6 +299,7 @@ static int interface_read (void)
        int i;
        derive_t rx;
        derive_t tx;
+       char iname[DATA_MAX_NAME_LEN];
 
        if (kc == NULL)
                return (-1);
@@ -297,6 +309,11 @@ static int interface_read (void)
                if (kstat_read (kc, ksp[i], NULL) == -1)
                        continue;
 
+               if (unique_name)
+                       ssnprintf(iname, sizeof(iname), "%s_%d_%s", ksp[i]->ks_module, ksp[i]->ks_instance, ksp[i]->ks_name);
+               else
+                       sstrncpy(iname, ksp[i]->ks_name, sizeof(iname));
+
                /* try to get 64bit counters */
                rx = get_kstat_value (ksp[i], "rbytes64");
                tx = get_kstat_value (ksp[i], "obytes64");
@@ -306,7 +323,7 @@ static int interface_read (void)
                if (tx == -1LL)
                        tx = get_kstat_value (ksp[i], "obytes");
                if ((rx != -1LL) || (tx != -1LL))
-                       if_submit (ksp[i]->ks_name, "if_octets", rx, tx);
+                       if_submit (iname, "if_octets", rx, tx);
 
                /* try to get 64bit counters */
                rx = get_kstat_value (ksp[i], "ipackets64");
@@ -317,13 +334,13 @@ static int interface_read (void)
                if (tx == -1LL)
                        tx = get_kstat_value (ksp[i], "opackets");
                if ((rx != -1LL) || (tx != -1LL))
-                       if_submit (ksp[i]->ks_name, "if_packets", rx, tx);
+                       if_submit (iname, "if_packets", rx, tx);
 
                /* no 64bit error counters yet */
                rx = get_kstat_value (ksp[i], "ierrors");
                tx = get_kstat_value (ksp[i], "oerrors");
                if ((rx != -1LL) || (tx != -1LL))
-                       if_submit (ksp[i]->ks_name, "if_errors", rx, tx);
+                       if_submit (iname, "if_errors", rx, tx);
        }
 /* #endif HAVE_LIBKSTAT */
 
index b403847..645d4b0 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -298,7 +298,7 @@ static int ipc_read_msg (void) /* {{{ */
     msg_alloc_queues++;
     msg_used_space += ipcinfo_msg[i].msg_cbytes;
     msg_qnum += ipcinfo_msg[i].msg_qnum;
-
+  }
   free(ipcinfo_msg);
 
   ipc_submit_g("msg", "count", "queues", msg_alloc_queues);
index 590b693..05e3e24 100644 (file)
@@ -29,8 +29,6 @@
 #include "plugin.h"
 #include "configfile.h"
 
-#include <sys/socket.h>
-
 #include <libiptc/libiptc.h>
 #include <libiptc/libip6tc.h>
 
@@ -63,14 +61,10 @@ typedef struct ip6tc_handle ip6tc_handle_t;
  */
 static const char *config_keys[] =
 {
-       "Chain",
-       "Chain6"
+    "Chain",
+    "Chain6"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-/*
-    Each table/chain combo that will be queried goes into this list
-*/
-
 enum protocol_version_e
 {
     IPV4,
@@ -78,6 +72,9 @@ enum protocol_version_e
 };
 typedef enum protocol_version_e protocol_version_t;
 
+/*
+ * Each table/chain combo that will be queried goes into this list
+ */
 #ifndef XT_TABLE_MAXNAMELEN
 # define XT_TABLE_MAXNAMELEN 32
 #endif
@@ -87,14 +84,14 @@ typedef struct {
     char chain[XT_TABLE_MAXNAMELEN];
     union
     {
-       int   num;
-       char *comment;
+        int   num;
+        char *comment;
     } rule;
     enum
     {
-       RTYPE_NUM,
-       RTYPE_COMMENT,
-       RTYPE_COMMENT_ALL
+        RTYPE_NUM,
+        RTYPE_COMMENT,
+        RTYPE_COMMENT_ALL
     } rule_type;
     char name[64];
 } ip_chain_t;
@@ -104,142 +101,142 @@ static int chain_num = 0;
 
 static int iptables_config (const char *key, const char *value)
 {
-       /* int ip_value; */
-       protocol_version_t ip_version = 0;
-
-       if (strcasecmp (key, "Chain") == 0)
-               ip_version = IPV4;
-       else if (strcasecmp (key, "Chain6") == 0)
-               ip_version = IPV6;
-       else
-               return (1);
-
-       ip_chain_t temp, *final, **list;
-       char *table;
-       int   table_len;
-       char *chain;
-       int   chain_len;
-
-       char *value_copy;
-       char *fields[4];
-       int   fields_num;
-
-       memset (&temp, 0, sizeof (temp));
-
-       value_copy = strdup (value);
-       if (value_copy == NULL)
-       {
-           char errbuf[1024];
-           ERROR ("strdup failed: %s",
-                   sstrerror (errno, errbuf, sizeof (errbuf)));
-           return (1);
-       }
-
-       /*
-        *  Time to fill the temp element
-        *  Examine value string, it should look like:
-        *  Chain[6] <table> <chain> [<comment|num> [name]]
-        */
-
-       /* set IPv4 or IPv6 */
-       temp.ip_version = ip_version;
-
-       /* Chain <table> <chain> [<comment|num> [name]] */
-       fields_num = strsplit (value_copy, fields, 4);
-       if (fields_num < 2)
-       {
-           free (value_copy);
-           return (1);
-       }
-
-       table = fields[0];
-       chain = fields[1];
-
-       table_len = strlen (table) + 1;
-       if ((unsigned int)table_len > sizeof(temp.table))
-       {
-               ERROR ("Table `%s' too long.", table);
-               free (value_copy);
-               return (1);
-       }
-       sstrncpy (temp.table, table, table_len);
-
-       chain_len = strlen (chain) + 1;
-       if ((unsigned int)chain_len > sizeof(temp.chain))
-       {
-               ERROR ("Chain `%s' too long.", chain);
-               free (value_copy);
-               return (1);
-       }
-       sstrncpy (temp.chain, chain, chain_len);
-
-       if (fields_num >= 3)
-       {
-           char *comment = fields[2];
-           int   rule = atoi (comment);
-
-           if (rule)
-           {
-               temp.rule.num = rule;
-               temp.rule_type = RTYPE_NUM;
-           }
-           else
-           {
-               temp.rule.comment = strdup (comment);
-               if (temp.rule.comment == NULL)
-               {
-                   free (value_copy);
-                   return (1);
-               }
-               temp.rule_type = RTYPE_COMMENT;
-           }
-       }
-       else
-       {
-           temp.rule_type = RTYPE_COMMENT_ALL;
-       }
-
-       if (fields_num >= 4)
-           sstrncpy (temp.name, fields[3], sizeof (temp.name));
-
-       free (value_copy);
-       value_copy = NULL;
-       table = NULL;
-       chain = NULL;
-
-       list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
-       if (list == NULL)
-       {
-           char errbuf[1024];
-           ERROR ("realloc failed: %s",
-                   sstrerror (errno, errbuf, sizeof (errbuf)));
-           sfree (temp.rule.comment);
-           return (1);
-       }
-
-       chain_list = list;
-       final = (ip_chain_t *) malloc( sizeof(temp) );
-       if (final == NULL)
-       {
-           char errbuf[1024];
-           ERROR ("malloc failed: %s",
-                   sstrerror (errno, errbuf, sizeof (errbuf)));
-           sfree (temp.rule.comment);
-           return (1);
-       }
-       memcpy (final, &temp, sizeof (temp));
-       chain_list[chain_num] = final;
-       chain_num++;
-
-       DEBUG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain);
-
-       return (0);
+    /* int ip_value; */
+    protocol_version_t ip_version = 0;
+
+    if (strcasecmp (key, "Chain") == 0)
+        ip_version = IPV4;
+    else if (strcasecmp (key, "Chain6") == 0)
+        ip_version = IPV6;
+    else
+        return (1);
+
+    ip_chain_t temp, *final, **list;
+    char *table;
+    int   table_len;
+    char *chain;
+    int   chain_len;
+
+    char *value_copy;
+    char *fields[4];
+    int   fields_num;
+
+    memset (&temp, 0, sizeof (temp));
+
+    value_copy = strdup (value);
+    if (value_copy == NULL)
+    {
+        char errbuf[1024];
+        ERROR ("strdup failed: %s",
+                sstrerror (errno, errbuf, sizeof (errbuf)));
+        return (1);
+    }
+
+    /*
+     *  Time to fill the temp element
+     *  Examine value string, it should look like:
+     *  Chain[6] <table> <chain> [<comment|num> [name]]
+     */
+
+    /* set IPv4 or IPv6 */
+    temp.ip_version = ip_version;
+
+    /* Chain <table> <chain> [<comment|num> [name]] */
+    fields_num = strsplit (value_copy, fields, 4);
+    if (fields_num < 2)
+    {
+        free (value_copy);
+        return (1);
+    }
+
+    table = fields[0];
+    chain = fields[1];
+
+    table_len = strlen (table) + 1;
+    if ((unsigned int)table_len > sizeof(temp.table))
+    {
+        ERROR ("Table `%s' too long.", table);
+        free (value_copy);
+        return (1);
+    }
+    sstrncpy (temp.table, table, table_len);
+
+    chain_len = strlen (chain) + 1;
+    if ((unsigned int)chain_len > sizeof(temp.chain))
+    {
+        ERROR ("Chain `%s' too long.", chain);
+        free (value_copy);
+        return (1);
+    }
+    sstrncpy (temp.chain, chain, chain_len);
+
+    if (fields_num >= 3)
+    {
+        char *comment = fields[2];
+        int   rule = atoi (comment);
+
+        if (rule)
+        {
+            temp.rule.num = rule;
+            temp.rule_type = RTYPE_NUM;
+        }
+        else
+        {
+            temp.rule.comment = strdup (comment);
+            if (temp.rule.comment == NULL)
+            {
+                free (value_copy);
+                return (1);
+            }
+            temp.rule_type = RTYPE_COMMENT;
+        }
+    }
+    else
+    {
+        temp.rule_type = RTYPE_COMMENT_ALL;
+    }
+
+    if (fields_num >= 4)
+        sstrncpy (temp.name, fields[3], sizeof (temp.name));
+
+    free (value_copy);
+    value_copy = NULL;
+    table = NULL;
+    chain = NULL;
+
+    list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
+    if (list == NULL)
+    {
+        char errbuf[1024];
+        ERROR ("realloc failed: %s",
+                sstrerror (errno, errbuf, sizeof (errbuf)));
+        sfree (temp.rule.comment);
+        return (1);
+    }
+
+    chain_list = list;
+    final = (ip_chain_t *) malloc( sizeof(temp) );
+    if (final == NULL)
+    {
+        char errbuf[1024];
+        ERROR ("malloc failed: %s",
+                sstrerror (errno, errbuf, sizeof (errbuf)));
+        sfree (temp.rule.comment);
+        return (1);
+    }
+    memcpy (final, &temp, sizeof (temp));
+    chain_list[chain_num] = final;
+    chain_num++;
+
+    DEBUG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain);
+
+    return (0);
 } /* int iptables_config */
 
 static int submit6_match (const struct ip6t_entry_match *match,
-                const struct ip6t_entry *entry,
-                const ip_chain_t *chain,
-                int rule_num)
+                          const struct ip6t_entry *entry,
+                          const ip_chain_t *chain,
+                          int rule_num)
 {
     int status;
     value_t values[1];
@@ -256,7 +253,7 @@ static int submit6_match (const struct ip6t_entry_match *match,
         if (strcmp (match->u.user.name, "comment") != 0)
             return (0);
         if ((chain->rule_type == RTYPE_COMMENT)
-                && (strcmp (chain->rule.comment, (char *) match->data) != 0))
+             && (strcmp (chain->rule.comment, (char *) match->data) != 0))
             return (0);
     }
 
@@ -266,7 +263,7 @@ static int submit6_match (const struct ip6t_entry_match *match,
     sstrncpy (vl.plugin, "ip6tables", sizeof (vl.plugin));
 
     status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
-            "%s-%s", chain->table, chain->chain);
+                        "%s-%s", chain->table, chain->chain);
     if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance)))
         return (0);
 
@@ -278,10 +275,10 @@ static int submit6_match (const struct ip6t_entry_match *match,
     {
         if (chain->rule_type == RTYPE_NUM)
             ssnprintf (vl.type_instance, sizeof (vl.type_instance),
-                    "%i", chain->rule.num);
+                       "%i", chain->rule.num);
         else
             sstrncpy (vl.type_instance, (char *) match->data,
-                    sizeof (vl.type_instance));
+                      sizeof (vl.type_instance));
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
@@ -298,9 +295,9 @@ static int submit6_match (const struct ip6t_entry_match *match,
 
 /* This needs to return `int' for IPT_MATCH_ITERATE to work. */
 static int submit_match (const struct ipt_entry_match *match,
-               const struct ipt_entry *entry,
-               const ip_chain_t *chain,
-               int rule_num) 
+                         const struct ipt_entry *entry,
+                         const ip_chain_t *chain,
+                         int rule_num)
 {
     int status;
     value_t values[1];
@@ -309,16 +306,16 @@ static int submit_match (const struct ipt_entry_match *match,
     /* Select the rules to collect */
     if (chain->rule_type == RTYPE_NUM)
     {
-       if (chain->rule.num != rule_num)
-           return (0);
+        if (chain->rule.num != rule_num)
+            return (0);
     }
     else
     {
-       if (strcmp (match->u.user.name, "comment") != 0)
-           return (0);
-       if ((chain->rule_type == RTYPE_COMMENT)
-               && (strcmp (chain->rule.comment, (char *) match->data) != 0))
-           return (0);
+        if (strcmp (match->u.user.name, "comment") != 0)
+            return (0);
+        if ((chain->rule_type == RTYPE_COMMENT)
+             && (strcmp (chain->rule.comment, (char *) match->data) != 0))
+            return (0);
     }
 
     vl.values = values;
@@ -327,22 +324,22 @@ static int submit_match (const struct ipt_entry_match *match,
     sstrncpy (vl.plugin, "iptables", sizeof (vl.plugin));
 
     status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
-           "%s-%s", chain->table, chain->chain);
+                        "%s-%s", chain->table, chain->chain);
     if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance)))
-       return (0);
+        return (0);
 
     if (chain->name[0] != '\0')
     {
-       sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
+        sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
     }
     else
     {
-       if (chain->rule_type == RTYPE_NUM)
-           ssnprintf (vl.type_instance, sizeof (vl.type_instance),
-                   "%i", chain->rule.num);
-       else
-           sstrncpy (vl.type_instance, (char *) match->data,
-                   sizeof (vl.type_instance));
+        if (chain->rule_type == RTYPE_NUM)
+            ssnprintf (vl.type_instance, sizeof (vl.type_instance),
+                       "%i", chain->rule.num);
+        else
+            sstrncpy (vl.type_instance, (char *) match->data,
+                      sizeof (vl.type_instance));
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
@@ -358,7 +355,7 @@ static int submit_match (const struct ipt_entry_match *match,
 
 
 /* ipv6 submit_chain */
-static void submit6_chain( ip6tc_handle_t *handle, ip_chain_t *chain )
+static void submit6_chain (ip6tc_handle_t *handle, ip_chain_t *chain)
 {
     const struct ip6t_entry *entry;
     int rule_num;
@@ -390,33 +387,33 @@ static void submit6_chain( ip6tc_handle_t *handle, ip_chain_t *chain )
 
 
 /* ipv4 submit_chain */
-static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain )
+static void submit_chain (iptc_handle_t *handle, ip_chain_t *chain)
 {
     const struct ipt_entry *entry;
     int rule_num;
 
-    /* Find first rule for chain and use the iterate macro */    
+    /* Find first rule for chain and use the iterate macro */
     entry = iptc_first_rule( chain->chain, handle );
     if (entry == NULL)
     {
-       DEBUG ("iptc_first_rule failed: %s", iptc_strerror (errno));
-       return;
+        DEBUG ("iptc_first_rule failed: %s", iptc_strerror (errno));
+        return;
     }
 
     rule_num = 1;
     while (entry)
     {
-       if (chain->rule_type == RTYPE_NUM)
-       {
-           submit_match (NULL, entry, chain, rule_num);
-       }
-       else
-       {
-           IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num );
-       }
-
-       entry = iptc_next_rule( entry, handle );
-       rule_num++;
+        if (chain->rule_type == RTYPE_NUM)
+        {
+            submit_match (NULL, entry, chain, rule_num);
+        }
+        else
+        {
+            IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num );
+        }
+
+        entry = iptc_next_rule( entry, handle );
+        rule_num++;
     } /* while (entry) */
 }
 
@@ -427,65 +424,64 @@ static int iptables_read (void)
     int num_failures = 0;
     ip_chain_t *chain;
 
-    /* Init the iptc handle structure and query the correct table */    
+    /* Init the iptc handle structure and query the correct table */
     for (i = 0; i < chain_num; i++)
     {
-       chain = chain_list[i];
-       
-       if (!chain)
-       {
-           DEBUG ("iptables plugin: chain == NULL");
-           continue;
-       }
-
-       if ( chain->ip_version == IPV4 )
+        chain = chain_list[i];
+
+        if (!chain)
+        {
+            DEBUG ("iptables plugin: chain == NULL");
+            continue;
+        }
+
+        if ( chain->ip_version == IPV4 )
         {
 #ifdef HAVE_IPTC_HANDLE_T
-               iptc_handle_t _handle;
-               iptc_handle_t *handle = &_handle;
+            iptc_handle_t _handle;
+            iptc_handle_t *handle = &_handle;
 
-               *handle = iptc_init (chain->table);
+            *handle = iptc_init (chain->table);
 #else
-               iptc_handle_t *handle;
-                handle = iptc_init (chain->table);
+            iptc_handle_t *handle;
+            handle = iptc_init (chain->table);
 #endif
 
-                if (!handle)
-                {
-                        ERROR ("iptables plugin: iptc_init (%s) failed: %s",
-                                chain->table, iptc_strerror (errno));
-                        num_failures++;
-                        continue;
-                }
+            if (!handle)
+            {
+                ERROR ("iptables plugin: iptc_init (%s) failed: %s",
+                        chain->table, iptc_strerror (errno));
+                num_failures++;
+                continue;
+            }
 
-                submit_chain (handle, chain);
-                iptc_free (handle);
+            submit_chain (handle, chain);
+            iptc_free (handle);
         }
         else if ( chain->ip_version == IPV6 )
         {
 #ifdef HAVE_IP6TC_HANDLE_T
-               ip6tc_handle_t _handle;
-               ip6tc_handle_t *handle = &_handle;
+            ip6tc_handle_t _handle;
+            ip6tc_handle_t *handle = &_handle;
 
-               *handle = ip6tc_init (chain->table);
+            *handle = ip6tc_init (chain->table);
 #else
-                ip6tc_handle_t *handle;
-                handle = ip6tc_init (chain->table);
+            ip6tc_handle_t *handle;
+            handle = ip6tc_init (chain->table);
 #endif
-
-                if (!handle)
-                {
-                        ERROR ("iptables plugin: ip6tc_init (%s) failed: %s",
-                                chain->table, ip6tc_strerror (errno));
-                        num_failures++;
-                        continue;
-                }
-
-                submit6_chain (handle, chain);
-                ip6tc_free (handle);
+            if (!handle)
+            {
+                ERROR ("iptables plugin: ip6tc_init (%s) failed: %s",
+                        chain->table, ip6tc_strerror (errno));
+                num_failures++;
+                continue;
+            }
+
+            submit6_chain (handle, chain);
+            ip6tc_free (handle);
         }
-        else num_failures++;
-
+        else
+            num_failures++;
     } /* for (i = 0 .. chain_num) */
 
     return ((num_failures < chain_num) ? 0 : -1);
@@ -497,11 +493,9 @@ static int iptables_shutdown (void)
 
     for (i = 0; i < chain_num; i++)
     {
-       if ((chain_list[i] != NULL) && (chain_list[i]->rule_type == RTYPE_COMMENT))
-       {
-           sfree (chain_list[i]->rule.comment);
-       }
-       sfree (chain_list[i]);
+        if ((chain_list[i] != NULL) && (chain_list[i]->rule_type == RTYPE_COMMENT))
+            sfree (chain_list[i]->rule.comment);
+        sfree (chain_list[i]);
     }
     sfree (chain_list);
 
@@ -511,11 +505,8 @@ static int iptables_shutdown (void)
 void module_register (void)
 {
     plugin_register_config ("iptables", iptables_config,
-           config_keys, config_keys_num);
+                             config_keys, config_keys_num);
     plugin_register_read ("iptables", iptables_read);
     plugin_register_shutdown ("iptables", iptables_shutdown);
 } /* void module_register */
 
-/*
- * vim:shiftwidth=4:softtabstop=4:tabstop=8
- */
index cbb5542..760aa3c 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,14 +217,15 @@ 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;
        }
        return 0;
 } /* get_ti */
 
-static void cipvs_submit_connections (char *pi, char *ti, derive_t value)
+static void cipvs_submit_connections (const char *pi, const char *ti,
+               derive_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -248,7 +246,7 @@ static void cipvs_submit_connections (char *pi, char *ti, derive_t value)
        return;
 } /* cipvs_submit_connections */
 
-static void cipvs_submit_if (char *pi, char *t, char *ti,
+static void cipvs_submit_if (const char *pi, const char *t, const char *ti,
                derive_t rx, derive_t tx)
 {
        value_t values[2];
@@ -271,7 +269,8 @@ static void cipvs_submit_if (char *pi, char *t, char *ti,
        return;
 } /* cipvs_submit_if */
 
-static void cipvs_submit_dest (char *pi, struct ip_vs_dest_entry *de) {
+static void cipvs_submit_dest (const char *pi, struct ip_vs_dest_entry *de)
+{
        struct ip_vs_stats_user stats = de->stats;
 
        char ti[DATA_MAX_NAME_LEN];
@@ -292,7 +291,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 +313,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 420471d..7a866ee 100644 (file)
@@ -392,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))
@@ -420,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;
 
@@ -456,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 5d2c5b2..89ccdec 100644 (file)
@@ -55,7 +55,7 @@ oconfig_item_t *oconfig_parse_fh (FILE *fh)
   if (NULL == c_file) {
     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 {
@@ -129,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");
@@ -145,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) */
@@ -165,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 f0e886c..803eec2 100644 (file)
@@ -225,7 +225,7 @@ entire_file:
 %%
 static int yyerror (const char *s)
 {
-       char *text;
+       const char *text;
 
        if (*yytext == '\n')
                text = "<newline>";
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..2d6d77e 100644 (file)
@@ -29,7 +29,6 @@
 #include "configfile.h"
 
 #include <netdb.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 
@@ -261,8 +260,8 @@ static int mbmon_read (void)
                double value;
                char *nextc;
 
-               char *type;
-               char *inst;
+               const char *type;
+               const char *inst;
 
                *t++ = '\0';
                trim_spaces (s);
index d650f02..2c01a57 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>
@@ -99,8 +98,8 @@ static int memcached_connect_unix (memcached_t *st)
 
 static int memcached_connect_inet (memcached_t *st)
 {
-  char *host;
-  char *port;
+  const char *host;
+  const char *port;
 
   struct addrinfo  ai_hints;
   struct addrinfo *ai_list, *ai_ptr;
@@ -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..3d8a867 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
@@ -230,7 +237,7 @@ static int memory_read_internal (value_list_t *vl)
         * vm.stats.vm.v_inactive_count: 113730
         * vm.stats.vm.v_cache_count: 10809
         */
-       char *sysctl_keys[8] =
+       const char *sysctl_keys[8] =
        {
                "vm.stats.vm.v_page_size",
                "vm.stats.vm.v_page_count",
@@ -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 c04b308..d538fb3 100644 (file)
@@ -444,7 +444,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);
@@ -1024,18 +1024,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..4977f68
--- /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)
+        {
+            status = cf_util_get_port_number (child);
+            if (status < 0)
+                ERROR ("mqtt plugin: Invalid port number.");
+            else
+                conf->port = status;
+        }
+        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 qos = -1;
+            status = cf_util_get_int (child, &qos);
+            if ((status != 0) || (qos < 0) || (qos > 2))
+                ERROR ("mqtt plugin: Not a valid QoS setting.");
+            else
+                conf->qos = qos;
+        }
+        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..db38a4b 100644 (file)
@@ -66,7 +66,7 @@ typedef struct mysql_database_s mysql_database_t; /* }}} */
 static int mysql_read (user_data_t *ud);
 
 void mysql_read_default_options(struct st_mysql_options *options,
-               const char *filename,const char *group);
+               const char *filename, const char *group);
 
 static void mysql_database_free (void *arg) /* {{{ */
 {
@@ -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
        {
@@ -403,8 +403,8 @@ static int mysql_read_master_stats (mysql_database_t *db, MYSQL *con)
        MYSQL_RES *res;
        MYSQL_ROW  row;
 
-       char *query;
-       int   field_num;
+       const char *query;
+       int         field_num;
        unsigned long long position;
 
        query = "SHOW MASTER STATUS";
@@ -449,8 +449,8 @@ static int mysql_read_slave_stats (mysql_database_t *db, MYSQL *con)
        MYSQL_RES *res;
        MYSQL_ROW  row;
 
-       char *query;
-       int   field_num;
+       const char *query;
+       int         field_num;
 
        /* WTF? libmysqlclient does not seem to provide any means to
         * translate a column name to a column index ... :-/ */
@@ -572,84 +572,84 @@ static int mysql_read_innodb_stats (mysql_database_t *db, MYSQL *con)
        MYSQL_RES *res;
        MYSQL_ROW  row;
 
-       char *query;
-    struct {
-        char *key;
-        char *type;
-        int ds_type;
-    } metrics[] = {
-        { "metadata_mem_pool_size",         "bytes",        DS_TYPE_GAUGE },
-        { "lock_deadlocks",                 "mysql_locks",  DS_TYPE_DERIVE },
-        { "lock_timeouts",                  "mysql_locks",  DS_TYPE_DERIVE },
-        { "lock_row_lock_current_waits",    "mysql_locks",  DS_TYPE_DERIVE },
-        { "buffer_pool_size",               "bytes",        DS_TYPE_GAUGE },
-
-        { "buffer_pool_reads",              "operations",   DS_TYPE_DERIVE },
-        { "buffer_pool_read_requests",      "operations",   DS_TYPE_DERIVE },
-        { "buffer_pool_write_requests",     "operations",   DS_TYPE_DERIVE },
-        { "buffer_pool_wait_free",          "operations",   DS_TYPE_DERIVE },
-        { "buffer_pool_read_ahead",         "operations",   DS_TYPE_DERIVE },
-        { "buffer_pool_read_ahead_evicted", "operations",   DS_TYPE_DERIVE },
-
-        { "buffer_pool_pages_total",        "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_pages_misc",         "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_pages_data",         "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_bytes_data",         "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_pages_dirty",        "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_bytes_dirty",        "gauge",        DS_TYPE_GAUGE },
-        { "buffer_pool_pages_free",         "gauge",        DS_TYPE_GAUGE },
-
-        { "buffer_pages_created",           "operations",   DS_TYPE_DERIVE },
-        { "buffer_pages_written",           "operations",   DS_TYPE_DERIVE },
-        { "buffer_pages_read",              "operations",   DS_TYPE_DERIVE },
-        { "buffer_data_reads",              "operations",   DS_TYPE_DERIVE },
-        { "buffer_data_written",            "operations",   DS_TYPE_DERIVE },
-
-        { "os_data_reads",                  "operations",   DS_TYPE_DERIVE },
-        { "os_data_writes",                 "operations",   DS_TYPE_DERIVE },
-        { "os_data_fsyncs",                 "operations",   DS_TYPE_DERIVE },
-        { "os_log_bytes_written",           "operations",   DS_TYPE_DERIVE },
-        { "os_log_fsyncs",                  "operations",   DS_TYPE_DERIVE },
-        { "os_log_pending_fsyncs",          "operations",   DS_TYPE_DERIVE },
-        { "os_log_pending_writes",          "operations",   DS_TYPE_DERIVE },
-
-        { "trx_rseg_history_len",           "gauge",        DS_TYPE_GAUGE },
-
-        { "log_waits",                      "operations",   DS_TYPE_DERIVE },
-        { "log_write_requests",             "operations",   DS_TYPE_DERIVE },
-        { "log_writes",                     "operations",   DS_TYPE_DERIVE },
-        { "adaptive_hash_searches",         "operations",   DS_TYPE_DERIVE },
-
-        { "file_num_open_files",            "gauge",        DS_TYPE_GAUGE },
-
-        { "ibuf_merges_insert",             "operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_delete_mark",        "operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_delete",             "operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_discard_insert",     "operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_discard_delete_mark","operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_discard_delete",     "operations",   DS_TYPE_DERIVE },
-        { "ibuf_merges_discard_merges",     "operations",   DS_TYPE_DERIVE },
-        { "ibuf_size",                      "bytes",        DS_TYPE_GAUGE },
-
-        { "innodb_activity_count",          "gauge",        DS_TYPE_GAUGE },
-        { "innodb_dblwr_writes",            "operations",   DS_TYPE_DERIVE },
-        { "innodb_dblwr_pages_written",     "operations",   DS_TYPE_DERIVE },
-        { "innodb_dblwr_page_size",         "gauge",        DS_TYPE_GAUGE },
-
-        { "innodb_rwlock_s_spin_waits",     "operations",   DS_TYPE_DERIVE },
-        { "innodb_rwlock_x_spin_waits",     "operations",   DS_TYPE_DERIVE },
-        { "innodb_rwlock_s_spin_rounds",    "operations",   DS_TYPE_DERIVE },
-        { "innodb_rwlock_x_spin_rounds",    "operations",   DS_TYPE_DERIVE },
-        { "innodb_rwlock_s_os_waits",       "operations",   DS_TYPE_DERIVE },
-        { "innodb_rwlock_x_os_waits",       "operations",   DS_TYPE_DERIVE },
-
-        { "dml_reads",                      "operations",   DS_TYPE_DERIVE },
-        { "dml_inserts",                    "operations",   DS_TYPE_DERIVE },
-        { "dml_deletes",                    "operations",   DS_TYPE_DERIVE },
-        { "dml_updates",                    "operations",   DS_TYPE_DERIVE },
-
-        { NULL,                     NULL,           0}
-    };
+       const char *query;
+       struct {
+               const char *key;
+               const char *type;
+               int ds_type;
+       } metrics[] = {
+               { "metadata_mem_pool_size",          "bytes",        DS_TYPE_GAUGE },
+               { "lock_deadlocks",                  "mysql_locks",  DS_TYPE_DERIVE },
+               { "lock_timeouts",                   "mysql_locks",  DS_TYPE_DERIVE },
+               { "lock_row_lock_current_waits",     "mysql_locks",  DS_TYPE_DERIVE },
+               { "buffer_pool_size",                "bytes",        DS_TYPE_GAUGE },
+
+               { "buffer_pool_reads",               "operations",   DS_TYPE_DERIVE },
+               { "buffer_pool_read_requests",       "operations",   DS_TYPE_DERIVE },
+               { "buffer_pool_write_requests",      "operations",   DS_TYPE_DERIVE },
+               { "buffer_pool_wait_free",           "operations",   DS_TYPE_DERIVE },
+               { "buffer_pool_read_ahead",          "operations",   DS_TYPE_DERIVE },
+               { "buffer_pool_read_ahead_evicted",  "operations",   DS_TYPE_DERIVE },
+
+               { "buffer_pool_pages_total",         "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_pages_misc",          "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_pages_data",          "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_bytes_data",          "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_pages_dirty",         "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_bytes_dirty",         "gauge",        DS_TYPE_GAUGE },
+               { "buffer_pool_pages_free",          "gauge",        DS_TYPE_GAUGE },
+
+               { "buffer_pages_created",            "operations",   DS_TYPE_DERIVE },
+               { "buffer_pages_written",            "operations",   DS_TYPE_DERIVE },
+               { "buffer_pages_read",               "operations",   DS_TYPE_DERIVE },
+               { "buffer_data_reads",               "operations",   DS_TYPE_DERIVE },
+               { "buffer_data_written",             "operations",   DS_TYPE_DERIVE },
+
+               { "os_data_reads",                   "operations",   DS_TYPE_DERIVE },
+               { "os_data_writes",                  "operations",   DS_TYPE_DERIVE },
+               { "os_data_fsyncs",                  "operations",   DS_TYPE_DERIVE },
+               { "os_log_bytes_written",            "operations",   DS_TYPE_DERIVE },
+               { "os_log_fsyncs",                   "operations",   DS_TYPE_DERIVE },
+               { "os_log_pending_fsyncs",           "operations",   DS_TYPE_DERIVE },
+               { "os_log_pending_writes",           "operations",   DS_TYPE_DERIVE },
+
+               { "trx_rseg_history_len",            "gauge",        DS_TYPE_GAUGE },
+
+               { "log_waits",                       "operations",   DS_TYPE_DERIVE },
+               { "log_write_requests",              "operations",   DS_TYPE_DERIVE },
+               { "log_writes",                      "operations",   DS_TYPE_DERIVE },
+               { "adaptive_hash_searches",          "operations",   DS_TYPE_DERIVE },
+
+               { "file_num_open_files",             "gauge",        DS_TYPE_GAUGE },
+
+               { "ibuf_merges_insert",              "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_delete_mark",         "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_delete",              "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_discard_insert",      "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_discard_delete_mark", "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_discard_delete",      "operations",   DS_TYPE_DERIVE },
+               { "ibuf_merges_discard_merges",      "operations",   DS_TYPE_DERIVE },
+               { "ibuf_size",                       "bytes",        DS_TYPE_GAUGE },
+
+               { "innodb_activity_count",           "gauge",        DS_TYPE_GAUGE },
+               { "innodb_dblwr_writes",             "operations",   DS_TYPE_DERIVE },
+               { "innodb_dblwr_pages_written",      "operations",   DS_TYPE_DERIVE },
+               { "innodb_dblwr_page_size",          "gauge",        DS_TYPE_GAUGE },
+
+               { "innodb_rwlock_s_spin_waits",      "operations",   DS_TYPE_DERIVE },
+               { "innodb_rwlock_x_spin_waits",      "operations",   DS_TYPE_DERIVE },
+               { "innodb_rwlock_s_spin_rounds",     "operations",   DS_TYPE_DERIVE },
+               { "innodb_rwlock_x_spin_rounds",     "operations",   DS_TYPE_DERIVE },
+               { "innodb_rwlock_s_os_waits",        "operations",   DS_TYPE_DERIVE },
+               { "innodb_rwlock_x_os_waits",        "operations",   DS_TYPE_DERIVE },
+
+               { "dml_reads",                       "operations",   DS_TYPE_DERIVE },
+               { "dml_inserts",                     "operations",   DS_TYPE_DERIVE },
+               { "dml_deletes",                     "operations",   DS_TYPE_DERIVE },
+               { "dml_updates",                     "operations",   DS_TYPE_DERIVE },
+
+               { NULL,                              NULL,           0}
+       };
 
        query = "SELECT name, count, type FROM information_schema.innodb_metrics WHERE status = 'enabled'";
 
@@ -659,45 +659,43 @@ static int mysql_read_innodb_stats (mysql_database_t *db, MYSQL *con)
 
        while ((row = mysql_fetch_row (res)))
        {
-        int i;
+               int i;
                char *key;
                unsigned long long val;
 
                key = row[0];
                val = atoll (row[1]);
 
-        for (i = 0;
-             metrics[i].key != NULL && strcmp(metrics[i].key, key) != 0;
-             i++)
-            ;
-
-        if (metrics[i].key == NULL)
-            continue;
-
-        switch (metrics[i].ds_type) {
-        case DS_TYPE_COUNTER:
-            counter_submit(metrics[i].type, key, (counter_t)val, db);
-            break;
-        case DS_TYPE_GAUGE:
-            gauge_submit(metrics[i].type, key, (gauge_t)val, db);
-            break;
-        case DS_TYPE_DERIVE:
-            derive_submit(metrics[i].type, key, (derive_t)val, db);
-            break;
-        }
-    }
-
-    mysql_free_result(res);
-    return (0);
+               for (i = 0; metrics[i].key != NULL && strcmp(metrics[i].key, key) != 0; i++)
+                       ;
+
+               if (metrics[i].key == NULL)
+                       continue;
+
+               switch (metrics[i].ds_type) {
+                       case DS_TYPE_COUNTER:
+                               counter_submit(metrics[i].type, key, (counter_t)val, db);
+                               break;
+                       case DS_TYPE_GAUGE:
+                               gauge_submit(metrics[i].type, key, (gauge_t)val, db);
+                               break;
+                       case DS_TYPE_DERIVE:
+                               derive_submit(metrics[i].type, key, (derive_t)val, db);
+                               break;
+               }
+       }
+
+       mysql_free_result(res);
+       return (0);
 }
 
 static int mysql_read (user_data_t *ud)
 {
        mysql_database_t *db;
-       MYSQL     *con;
-       MYSQL_RES *res;
-       MYSQL_ROW  row;
-       char      *query;
+       MYSQL      *con;
+       MYSQL_RES  *res;
+       MYSQL_ROW   row;
+       const char *query;
 
        derive_t qcache_hits          = 0;
        derive_t qcache_inserts       = 0;
@@ -712,7 +710,7 @@ static int mysql_read (user_data_t *ud)
 
        unsigned long long traffic_incoming = 0ULL;
        unsigned long long traffic_outgoing = 0ULL;
-    unsigned long mysql_version = 0ULL;
+       unsigned long mysql_version = 0ULL;
 
        if ((ud == NULL) || (ud->data == NULL))
        {
@@ -726,7 +724,7 @@ static int mysql_read (user_data_t *ud)
        if ((con = getconnection (db)) == NULL)
                return (-1);
 
-  mysql_version = mysql_get_server_version(con);
+       mysql_version = mysql_get_server_version(con);
 
        query = "SHOW STATUS";
        if (mysql_version >= 50002)
@@ -940,7 +938,7 @@ static int mysql_read (user_data_t *ud)
        traffic_submit  (traffic_incoming, traffic_outgoing, db);
 
        if (mysql_version >= 50600 && db->innodb_stats)
-        mysql_read_innodb_stats (db, con);
+               mysql_read_innodb_stats (db, con);
 
        if (db->master_stats)
                mysql_read_master_stats (db, con);
index f761e29..8a8a7fe 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..d4661ce 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>
@@ -471,7 +470,7 @@ static int qos_filter_cb (const struct nlmsghdr *nlh, void *args)
   const char *kind = NULL;
 
   /* char *type_instance; */
-  char *tc_type;
+  const char *tc_type;
   char tc_inst[DATA_MAX_NAME_LEN];
 
   _Bool stats_submitted = 0;
index af24911..439b0ce 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,18 +769,18 @@ 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;
 
        uint16_t tmp16;
        size_t exp_size;
-       int   i;
+       size_t i;
 
        uint16_t pkg_length;
        uint16_t pkg_type;
-       uint16_t pkg_numval;
+       size_t pkg_numval;
 
        uint8_t *pkg_types;
        value_t *pkg_values;
@@ -804,7 +802,7 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
 
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
-       pkg_numval = ntohs (tmp16);
+       pkg_numval = (size_t) ntohs (tmp16);
 
        assert (pkg_type == TYPE_VALUES);
 
@@ -819,6 +817,7 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
                                exp_size, buffer_len);
                return (-1);
        }
+       assert (pkg_numval <= ((buffer_len - 6) / 9));
 
        if (pkg_length != exp_size)
        {
@@ -828,20 +827,20 @@ static int parse_part_values (void **ret_buffer, size_t *ret_buffer_len,
                return (-1);
        }
 
-       pkg_types = (uint8_t *) malloc (pkg_numval * sizeof (uint8_t));
-       pkg_values = (value_t *) malloc (pkg_numval * sizeof (value_t));
+       pkg_types = calloc (pkg_numval, sizeof (*pkg_types));
+       pkg_values = calloc (pkg_numval, sizeof (*pkg_values));
        if ((pkg_types == NULL) || (pkg_values == NULL))
        {
                sfree (pkg_types);
                sfree (pkg_values);
-               ERROR ("network plugin: parse_part_values: malloc failed.");
+               ERROR ("network plugin: parse_part_values: calloc failed.");
                return (-1);
        }
 
-       memcpy ((void *) pkg_types, (void *) buffer, pkg_numval * sizeof (uint8_t));
-       buffer += pkg_numval * sizeof (uint8_t);
-       memcpy ((void *) pkg_values, (void *) buffer, pkg_numval * sizeof (value_t));
-       buffer += pkg_numval * sizeof (value_t);
+       memcpy (pkg_types, buffer, pkg_numval * sizeof (*pkg_types));
+       buffer += pkg_numval * sizeof (*pkg_types);
+       memcpy (pkg_values, buffer, pkg_numval * sizeof (*pkg_values));
+       buffer += pkg_numval * sizeof (*pkg_values);
 
        for (i = 0; i < pkg_numval; i++)
        {
@@ -2442,7 +2441,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 +2582,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 +2922,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 +2959,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 +2978,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 +3065,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 +3103,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 +3151,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 +3231,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 +3454,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 +3532,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 be82372..a921a17 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -554,7 +554,7 @@ static int nfs_submit_nfs4_client (const char *instance, char **fields,
        return (0);
 }
 
-static void nfs_read_linux (FILE *fh, char *inst)
+static void nfs_read_linux (FILE *fh, const char *inst)
 {
        char buffer[1024];
 
@@ -603,7 +603,7 @@ static void nfs_read_linux (FILE *fh, char *inst)
 #endif /* KERNEL_LINUX */
 
 #if HAVE_LIBKSTAT
-static int nfs_read_kstat (kstat_t *ksp, int nfs_version, char *inst,
+static int nfs_read_kstat (kstat_t *ksp, int nfs_version, const char *inst,
                char const **proc_names, size_t proc_names_num)
 {
        char plugin_instance[DATA_MAX_NAME_LEN];
index 4e4ce3b..e493cc9 100644 (file)
@@ -188,15 +188,14 @@ 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
 
   return (0);
 } /* void init */
 
-static void submit (char *type, char *inst, long long value)
+static void submit (const char *type, const char *inst, long long value)
 {
   value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
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 ce54e02..4a31e45 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
@@ -250,7 +247,7 @@ struct info_kernel
 };
 
 /* List of reference clock names */
-static char *refclock_names[] =
+static const char *refclock_names[] =
 {
        "UNKNOWN",    "LOCAL",        "GPS_TRAK",   "WWV_PST",     /*  0- 3 */
        "SPECTRACOM", "TRUETIME",     "IRIG_AUDIO", "CHU_AUDIO",   /*  4- 7 */
@@ -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..                                         *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -310,7 +307,7 @@ static int ntpd_config (const char *key, const char *value)
        return (0);
 }
 
-static void ntpd_submit (char *type, char *type_inst, gauge_t value)
+static void ntpd_submit (const char *type, const char *type_inst, gauge_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -331,8 +328,8 @@ static void ntpd_submit (char *type, char *type_inst, gauge_t value)
 /* Each time a peer is polled, ntpd shifts the reach register to the left and
  * sets the LSB based on whether the peer was reachable. If the LSB is zero,
  * the values are out of date. */
-static void ntpd_submit_reach (char *type, char *type_inst, uint8_t reach,
-               gauge_t value)
+static void ntpd_submit_reach (const char *type, const char *type_inst,
+               uint8_t reach, gauge_t value)
 {
        if (!(reach & 1))
                value = NAN;
@@ -342,8 +339,8 @@ static void ntpd_submit_reach (char *type, char *type_inst, uint8_t reach,
 
 static int ntpd_connect (void)
 {
-       char *host;
-       char *port;
+       const char *host;
+       const char *port;
 
        struct addrinfo  ai_hints;
        struct addrinfo *ai_list;
@@ -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..3c441ec 100644 (file)
@@ -415,11 +415,11 @@ static int cow_read_ds2409 (const char *path)
   int status;
 
   status = ssnprintf (subpath, sizeof (subpath), "%s/main", path);
-  if ((status > 0) && (status < sizeof (subpath)))
+  if ((status > 0) && (status < (int) sizeof (subpath)))
     cow_read_bus (subpath);
 
   status = ssnprintf (subpath, sizeof (subpath), "%s/aux", path);
-  if ((status > 0) && (status < sizeof (subpath)))
+  if ((status > 0) && (status < (int) sizeof (subpath)))
     cow_read_bus (subpath);
 
   return (0);
@@ -459,7 +459,7 @@ static int cow_read_bus (const char *path)
     else
       status = ssnprintf (subpath, sizeof (subpath), "%s/%s",
           path, buffer_ptr);
-    if ((status <= 0) || (status >= sizeof (subpath)))
+    if ((status <= 0) || (status >= (int) sizeof (subpath)))
       continue;
 
     for (i = 0; i < ow_family_features_num; i++)
@@ -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 bd79b26..0a86d52 100644 (file)
@@ -43,6 +43,8 @@ struct cldap_s /* {{{ */
 {
        char *name;
 
+       char *binddn;
+       char *password;
        char *cacert;
        char *host;
        int   state;
@@ -61,6 +63,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);
@@ -115,10 +119,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",
@@ -564,7 +577,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);
@@ -635,7 +652,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 93c8f1b..8bccce3 100644 (file)
@@ -95,7 +95,8 @@ static int openvpn_strsplit (char *string, char **fields, size_t size)
 } /* int openvpn_strsplit */
 
 /* dispatches number of users */
-static void numusers_submit (char *pinst, char *tinst, gauge_t value)
+static void numusers_submit (const char *pinst, const char *tinst,
+               gauge_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -115,8 +116,10 @@ static void numusers_submit (char *pinst, char *tinst, gauge_t value)
        plugin_dispatch_values (&vl);
 } /* void numusers_submit */
 
-/* dispatches stats about traffic (TCP or UDP) generated by the tunnel per single endpoint */
-static void iostats_submit (char *pinst, char *tinst, derive_t rx, derive_t tx)
+/* dispatches stats about traffic (TCP or UDP) generated by the tunnel
+ * per single endpoint */
+static void iostats_submit (const char *pinst, const char *tinst,
+               derive_t rx, derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
@@ -145,7 +148,7 @@ static void iostats_submit (char *pinst, char *tinst, derive_t rx, derive_t tx)
 } /* void traffic_submit */
 
 /* dispatches stats about data compression shown when in single mode */
-static void compression_submit (char *pinst, char *tinst,
+static void compression_submit (const char *pinst, const char *tinst,
                derive_t uncompressed, derive_t compressed)
 {
        value_t values[2];
@@ -168,7 +171,7 @@ static void compression_submit (char *pinst, char *tinst,
        plugin_dispatch_values (&vl);
 } /* void compression_submit */
 
-static int single_read (char *name, FILE *fh)
+static int single_read (const char *name, FILE *fh)
 {
        char buffer[1024];
        char *fields[4];
@@ -261,7 +264,7 @@ static int single_read (char *name, FILE *fh)
 } /* int single_read */
 
 /* for reading status version 1 */
-static int multi1_read (char *name, FILE *fh)
+static int multi1_read (const char *name, FILE *fh)
 {
        char buffer[1024];
        char *fields[10];
@@ -324,7 +327,7 @@ static int multi1_read (char *name, FILE *fh)
 } /* int multi1_read */
 
 /* for reading status version 2 */
-static int multi2_read (char *name, FILE *fh)
+static int multi2_read (const char *name, FILE *fh)
 {
        char buffer[1024];
        char *fields[10];
@@ -386,7 +389,7 @@ static int multi2_read (char *name, FILE *fh)
 } /* int multi2_read */
 
 /* for reading status version 3 */
-static int multi3_read (char *name, FILE *fh)
+static int multi3_read (const char *name, FILE *fh)
 {
        char buffer[1024];
        char *fields[15];
@@ -451,7 +454,7 @@ static int multi3_read (char *name, FILE *fh)
 } /* int multi3_read */
 
 /* for reading status version 4 */
-static int multi4_read (char *name, FILE *fh)
+static int multi4_read (const char *name, FILE *fh)
 {
        char buffer[1024];
        char *fields[11];
index 19ac08d..c25bfe8 100644 (file)
@@ -301,33 +301,32 @@ static int hv2data_source (pTHX_ HV *hash, data_source_t *ds)
        return 0;
 } /* static int hv2data_source (HV *, data_source_t *) */
 
-static int av2value (pTHX_ char *name, AV *array, value_t *value, int len)
+/* av2value converts at most "len" elements from "array" to "value". Returns the
+ * number of elements converted or zero on error. */
+static size_t av2value (pTHX_ char *name, AV *array, value_t *value, size_t array_len)
 {
        const data_set_t *ds;
+       size_t i;
 
-       int i = 0;
-
-       if ((NULL == name) || (NULL == array) || (NULL == value))
-               return -1;
-
-       if (av_len (array) < len - 1)
-               len = av_len (array) + 1;
-
-       if (0 >= len)
-               return -1;
+       if ((NULL == name) || (NULL == array) || (NULL == value) || (array_len == 0))
+               return 0;
 
        ds = plugin_get_ds (name);
        if (NULL == ds) {
                log_err ("av2value: Unknown dataset \"%s\"", name);
-               return -1;
+               return 0;
        }
 
-       if (ds->ds_num < len) {
-               log_warn ("av2value: Value length exceeds data set length.");
-               len = ds->ds_num;
+       if (array_len < ds->ds_num) {
+               log_warn ("av2value: array does not contain enough elements for type \"%s\": got %zu, want %zu",
+                               name, array_len, ds->ds_num);
+               return 0;
+       } else if (array_len > ds->ds_num) {
+               log_warn ("av2value: array contains excess elements for type \"%s\": got %zu, want %zu",
+                               name, array_len, ds->ds_num);
        }
 
-       for (i = 0; i < len; ++i) {
+       for (i = 0; i < ds->ds_num; ++i) {
                SV **tmp = av_fetch (array, i, 0);
 
                if (NULL != tmp) {
@@ -341,11 +340,12 @@ static int av2value (pTHX_ char *name, AV *array, value_t *value, int len)
                                value[i].absolute = SvIV (*tmp);
                }
                else {
-                       return -1;
+                       return 0;
                }
        }
-       return len;
-} /* static int av2value (char *, AV *, value_t *, int) */
+
+       return ds->ds_num;
+} /* static size_t av2value (char *, AV *, value_t *, size_t) */
 
 /*
  * value list:
@@ -380,16 +380,14 @@ static int hv2value_list (pTHX_ HV *hash, value_list_t *vl)
 
        {
                AV  *array = (AV *)SvRV (*tmp);
-               int len    = av_len (array) + 1;
-
-               if (len <= 0)
+               /* av_len returns the highest index, not the actual length. */
+               size_t array_len = (size_t) (av_len (array) + 1);
+               if (array_len == 0)
                        return -1;
 
-               vl->values     = (value_t *)smalloc (len * sizeof (value_t));
-               vl->values_len = av2value (aTHX_ vl->type, (AV *)SvRV (*tmp),
-                               vl->values, len);
-
-               if (-1 == vl->values_len) {
+               vl->values     = calloc (array_len, sizeof (*vl->values));
+               vl->values_len = av2value (aTHX_ vl->type, (AV *)SvRV (*tmp), vl->values, array_len);
+               if (vl->values_len == 0) {
                        sfree (vl->values);
                        return -1;
                }
@@ -604,7 +602,7 @@ static int hv2notification (pTHX_ HV *hash, notification_t *n)
 
 static int data_set2av (pTHX_ data_set_t *ds, AV *array)
 {
-       int i = 0;
+       size_t i;
 
        if ((NULL == ds) || (NULL == array))
                return -1;
@@ -640,24 +638,17 @@ static int data_set2av (pTHX_ data_set_t *ds, AV *array)
 static int value_list2hv (pTHX_ value_list_t *vl, data_set_t *ds, HV *hash)
 {
        AV *values = NULL;
-
-       int i   = 0;
-       int len = 0;
+       size_t i;
 
        if ((NULL == vl) || (NULL == ds) || (NULL == hash))
                return -1;
 
-       len = vl->values_len;
-
-       if (ds->ds_num < len) {
-               log_warn ("value2av: Value length exceeds data set length.");
-               len = ds->ds_num;
-       }
-
        values = newAV ();
-       av_extend (values, len - 1);
+       /* av_extend takes the last *index* to which the array should be extended. */
+       av_extend (values, vl->values_len - 1);
 
-       for (i = 0; i < len; ++i) {
+       assert (ds->ds_num == vl->values_len);
+       for (i = 0; i < vl->values_len; ++i) {
                SV *val = NULL;
 
                if (DS_TYPE_COUNTER == ds->ds[i].type)
index 112e28f..a2bd549 100644 (file)
--- a/src/pf.c
+++ b/src/pf.c
@@ -26,9 +26,6 @@
 #if HAVE_SYS_IOCTL_H
 # include <sys/ioctl.h>
 #endif
-#if HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
 #if HAVE_NET_IF_H
 # include <net/if.h>
 #endif
index 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 c97571b..da63d3a 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)
@@ -538,6 +544,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;
@@ -689,6 +728,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 23c4af3..7922683 100644 (file)
@@ -154,7 +154,7 @@ typedef struct {
        int ref_cnt;
 } c_psql_database_t;
 
-static char *def_queries[] = {
+static const char *const def_queries[] = {
        "backends",
        "transactions",
        "queries",
@@ -429,9 +429,9 @@ static PGresult *c_psql_exec_query_noparams (c_psql_database_t *db,
 static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
                udb_query_t *q, c_psql_user_data_t *data)
 {
-       char *params[db->max_params_num];
-       char  interval[64];
-       int   i;
+       const char *params[db->max_params_num];
+       char        interval[64];
+       int         i;
 
        if ((data == NULL) || (data->params_num == 0))
                return (c_psql_exec_query_noparams (db, q));
@@ -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..ab62dcf 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
@@ -76,52 +75,75 @@ struct list_item_s
 
 struct statname_lookup_s
 {
-  char *name;
-  char *type;
-  char *type_instance;
+  const char *name;
+  const char *type;
+  const char *type_instance;
 };
 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[] = /* {{{ */
+static const char* const default_server_fields[] = /* {{{ */
 {
   "latency",
   "packetcache-hit",
@@ -136,9 +158,9 @@ const char* const default_server_fields[] = /* {{{ */
   "udp-answers",
   "udp-queries",
 }; /* }}} */
-int default_server_fields_num = STATIC_ARRAY_SIZE (default_server_fields);
+static int default_server_fields_num = STATIC_ARRAY_SIZE (default_server_fields);
 
-statname_lookup_t lookup_table[] = /* {{{ */
+static statname_lookup_t lookup_table[] = /* {{{ */
 {
   /*********************
    * Server statistics *
@@ -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,54 +223,69 @@ 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);
+static int lookup_table_length = STATIC_ARRAY_SIZE (lookup_table);
 
 static llist_t *list = NULL;
 
@@ -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 90d4d79..d0d7361 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;
                }
        }
@@ -353,6 +361,31 @@ static int ps_list_match (const char *name, const char *cmdline, procstat_t *ps)
        return (0);
 } /* int ps_list_match */
 
+static void ps_update_counter (
+        _Bool init,
+        derive_t *group_counter,
+        derive_t *curr_counter, unsigned long *curr_value,
+        derive_t new_counter, unsigned long new_value) {
+    if (init)
+    {
+        *curr_value = new_value;
+        *curr_counter += new_value;
+        *group_counter += new_value;
+        return;
+    }
+
+    if (new_counter < *curr_counter)
+    {
+        *curr_value = new_counter + (ULONG_MAX - *curr_counter);
+    }
+    else
+    {
+        *curr_value = new_counter - *curr_counter;
+    }
+    *curr_counter = new_counter;
+    *group_counter += *curr_value;
+}
+
 /* add process entry to 'instances' of process 'name' (or refresh it) */
 static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t *entry)
 {
@@ -364,6 +397,8 @@ static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t
 
        for (ps = list_head_g; ps != NULL; ps = ps->next)
        {
+        _Bool want_init;
+
                if ((ps_list_match (name, cmdline, ps)) == 0)
                        continue;
 
@@ -401,6 +436,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;
@@ -415,79 +452,30 @@ 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);
 
-               if ((entry->vmem_minflt_counter == 0)
-                               && (entry->vmem_majflt_counter == 0))
-               {
-                       pse->vmem_minflt_counter += entry->vmem_minflt;
-                       pse->vmem_minflt = entry->vmem_minflt;
-
-                       pse->vmem_majflt_counter += entry->vmem_majflt;
-                       pse->vmem_majflt = entry->vmem_majflt;
-               }
-               else
-               {
-                       if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
-                       {
-                               pse->vmem_minflt = entry->vmem_minflt_counter
-                                       + (ULONG_MAX - pse->vmem_minflt_counter);
-                       }
-                       else
-                       {
-                               pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
-                       }
-                       pse->vmem_minflt_counter = entry->vmem_minflt_counter;
-
-                       if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
-                       {
-                               pse->vmem_majflt = entry->vmem_majflt_counter
-                                       + (ULONG_MAX - pse->vmem_majflt_counter);
-                       }
-                       else
-                       {
-                               pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
-                       }
-                       pse->vmem_majflt_counter = entry->vmem_majflt_counter;
-               }
-
-               ps->vmem_minflt_counter += pse->vmem_minflt;
-               ps->vmem_majflt_counter += pse->vmem_majflt;
-
-               if ((entry->cpu_user_counter == 0)
-                               && (entry->cpu_system_counter == 0))
-               {
-                       pse->cpu_user_counter += entry->cpu_user;
-                       pse->cpu_user = entry->cpu_user;
-
-                       pse->cpu_system_counter += entry->cpu_system;
-                       pse->cpu_system = entry->cpu_system;
-               }
-               else
-               {
-                       if (entry->cpu_user_counter < pse->cpu_user_counter)
-                       {
-                               pse->cpu_user = entry->cpu_user_counter
-                                       + (ULONG_MAX - pse->cpu_user_counter);
-                       }
-                       else
-                       {
-                               pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
-                       }
-                       pse->cpu_user_counter = entry->cpu_user_counter;
-
-                       if (entry->cpu_system_counter < pse->cpu_system_counter)
-                       {
-                               pse->cpu_system = entry->cpu_system_counter
-                                       + (ULONG_MAX - pse->cpu_system_counter);
-                       }
-                       else
-                       {
-                               pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
-                       }
-                       pse->cpu_system_counter = entry->cpu_system_counter;
-               }
-
-               ps->cpu_user_counter   += pse->cpu_user;
-               ps->cpu_system_counter += pse->cpu_system;
+               ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
+               ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
+
+               want_init = (entry->vmem_minflt_counter == 0)
+                               && (entry->vmem_majflt_counter == 0);
+               ps_update_counter (want_init,
+                               &ps->vmem_minflt_counter,
+                               &pse->vmem_minflt_counter, &pse->vmem_minflt,
+                               entry->vmem_minflt_counter, entry->vmem_minflt);
+               ps_update_counter (want_init,
+                               &ps->vmem_majflt_counter,
+                               &pse->vmem_majflt_counter, &pse->vmem_majflt,
+                               entry->vmem_majflt_counter, entry->vmem_majflt);
+
+               want_init = (entry->cpu_user_counter == 0)
+                               && (entry->cpu_system_counter == 0);
+               ps_update_counter (want_init,
+                               &ps->cpu_user_counter,
+                               &pse->cpu_user_counter, &pse->cpu_user,
+                               entry->cpu_user_counter, entry->cpu_user);
+               ps_update_counter (want_init,
+                               &ps->cpu_system_counter,
+                               &pse->cpu_system_counter, &pse->cpu_system,
+                               entry->cpu_system_counter, entry->cpu_system);
        }
 }
 
@@ -511,6 +499,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;
@@ -595,6 +585,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 "
@@ -744,19 +738,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
@@ -781,42 +792,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 (long pid)
+static procstat_t *ps_read_tasks_status (long 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/%li/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/%li/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 (long pid, procstat_t *ps)
+       return (ps);
+} /* int *ps_read_tasks_status */
+
+/* Read data from /proc/pid/status */
+static procstat_t *ps_read_status (long 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;
 
@@ -826,10 +894,11 @@ static procstat_t *ps_read_vmem (long 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,
@@ -840,7 +909,7 @@ static procstat_t *ps_read_vmem (long 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)
@@ -855,6 +924,10 @@ static procstat_t *ps_read_vmem (long pid, procstat_t *ps)
                        {
                                exe = tmp;
                        }
+                       else if  (strncmp(buffer, "Threads", 7) == 0)
+                       {
+                               threads = tmp;
+                       }
                }
        } /* while (fgets) */
 
@@ -867,6 +940,8 @@ static procstat_t *ps_read_vmem (long 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 */
@@ -934,9 +1009,9 @@ static int ps_read_process (long 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;
@@ -947,14 +1022,16 @@ static int ps_read_process (long 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/%li/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
@@ -1009,11 +1086,16 @@ static int ps_read_process (long 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 %li", pid);
                }
+               if (ps->num_lwp <= 0)
+                       ps->num_lwp = 1;
                ps->num_proc = 1;
        }
 
@@ -1046,14 +1128,6 @@ static int ps_read_process (long 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 %li", pid);
-       }
-
        ps->cpu_user_counter = cpu_user_counter;
        ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
@@ -1071,6 +1145,18 @@ static int ps_read_process (long pid, procstat_t *ps, char *state)
                DEBUG("ps_read_process: not get io data for pid %li", 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 %li", pid);
+               }
+       }
+
        /* success */
        return (0);
 } /* int ps_read_process (...) */
@@ -1221,16 +1307,16 @@ static char *ps_get_cmdline (long pid, char *name __attribute__((unused)), /* {{
 {
        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);
        }
@@ -1327,6 +1413,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
@@ -1358,7 +1450,7 @@ static int ps_read_process(long pid, procstat_t *ps, char *state)
  * are retrieved from kstat (module cpu, name sys, class misc, stat nthreads).
  * The result is the sum for all the threads created on each cpu
  */
-static int read_fork_rate()
+static int read_fork_rate (void)
 {
        extern kstat_ctl_t *kc;
        kstat_t *ksp_chain = NULL;
@@ -1564,6 +1656,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,
@@ -1769,6 +1865,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;
@@ -1914,6 +2013,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)
@@ -2047,7 +2150,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);
@@ -2196,6 +2300,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 c752414..b909024 100644 (file)
@@ -355,7 +355,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;
@@ -368,22 +368,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);
@@ -584,7 +575,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;
@@ -678,7 +669,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;
@@ -707,11 +697,8 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
        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 = */ "python", 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..1097f7f 100644 (file)
@@ -106,19 +106,19 @@ static PyObject *cpy_common_repr(PyObject *s) {
        return ret;
 }
 
-static char time_doc[] = "This is the Unix timestap of the time this value was read.\n"
+static char time_doc[] = "This is the Unix timestamp of the time this value was read.\n"
                "For dispatching values this can be set to 0 which means \"now\".\n"
                "This means the time the value is actually dispatched, not the time\n"
                "it was set to 0.";
 
 static char host_doc[] = "The hostname of the host this value was read from.\n"
                "For dispatching this can be set to an empty string which means\n"
-               "the local hostname as defined in the collectd.conf.";
+               "the local hostname as defined in collectd.conf.";
 
 static char type_doc[] = "The type of this value. This type has to be defined\n"
-               "in your types.db. Attempting to set it to any other value will\n"
-               "raise a TypeError exception.\n"
-               "Assigning a type is mandetory, calling dispatch without doing\n"
+               "in the types.db file. Attempting to set it to any other value\n"
+               "will raise a TypeError exception.\n"
+               "Assigning a type is mandatory, calling dispatch without doing\n"
                "so will raise a RuntimeError exception.";
 
 static char type_instance_doc[] = "";
@@ -129,7 +129,7 @@ static char plugin_doc[] = "The name of the plugin that read the data. Setting t
 static char plugin_instance_doc[] = "";
 
 static char PluginData_doc[] = "This is an internal class that is the base for Values\n"
-               "and Notification. It is pretty useless by itself and was therefore not\n"
+               "and Notification. It is pretty useless by itself and is therefore not\n"
                "exported to the collectd module.";
 
 static PyObject *PluginData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
@@ -312,8 +312,8 @@ static char interval_doc[] = "The interval is the timespan in seconds between tw
 static char values_doc[] = "These are the actual values that get dispatched to collectd.\n"
                "It has to be a sequence (a tuple or list) of numbers.\n"
                "The size of the sequence and the type of its content depend on the type\n"
-               "member your types.db file. For more information on this read the types.db\n"
-               "man page.\n"
+               "member in the types.db file. For more information on this read the\n"
+               "types.db man page.\n"
                "\n"
                "If the sequence does not have the correct size upon dispatch a RuntimeError\n"
                "exception will be raised. If the content of the sequence is not a number,\n"
@@ -322,7 +322,7 @@ static char values_doc[] = "These are the actual values that get dispatched to c
 static char meta_doc[] = "These are the meta data for this Value object.\n"
                "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
                "strings. int and long objects will be dispatched as signed integers unless\n"
-               "they are between 2**63 and 2**64-1, which will result in a unsigned integer.\n"
+               "they are between 2**63 and 2**64-1, which will result in an unsigned integer.\n"
                "You can force one of these storage classes by using the classes\n"
                "collectd.Signed and collectd.Unsigned. A meta object received by a write\n"
                "callback will always contain Signed or Unsigned objects.";
@@ -340,7 +340,7 @@ static char dispatch_doc[] = "dispatch([type][, values][, plugin_instance][, typ
 static char write_doc[] = "write([destination][, type][, values][, plugin_instance][, type_instance]"
                "[, plugin][, host][, time][, interval]) -> None.  Dispatch a value list.\n"
                "\n"
-               "Write this instance to a single plugin or all plugins if 'destination' is obmitted.\n"
+               "Write this instance to a single plugin or all plugins if 'destination' is omitted.\n"
                "This will bypass the main collectd process and all filtering and caching.\n"
                "Other than that it works similar to 'dispatch'. In most cases 'dispatch' should be\n"
                "used instead of 'write'.\n";
@@ -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 2586ca0..4e3de56 100644 (file)
@@ -304,7 +304,7 @@ static int redis_handle_info (char *node, char const *info_line, char const *typ
     int i;
 
     str += strlen (field_name) + 1; /* also skip the ':' */
-    for(i=0;(*str && (isdigit(*str) || *str == '.'));i++,str++)
+    for(i=0;(*str && (isdigit((unsigned char)*str) || *str == '.'));i++,str++)
       buf[i] = *str;
     buf[i] ='\0';
 
@@ -432,9 +432,14 @@ static int redis_read (void) /* {{{ */
     redis_handle_info (rn->name, rr->str, "total_connections", NULL, "total_connections_received", DS_TYPE_DERIVE);
     redis_handle_info (rn->name, rr->str, "total_operations", NULL, "total_commands_processed", DS_TYPE_DERIVE);
     redis_handle_info (rn->name, rr->str, "expired_keys", NULL, "expired_keys", DS_TYPE_DERIVE);
+    redis_handle_info (rn->name, rr->str, "evicted_keys", NULL, "evicted_keys", DS_TYPE_DERIVE);
     redis_handle_info (rn->name, rr->str, "pubsub", "channels", "pubsub_channels", DS_TYPE_GAUGE);
     redis_handle_info (rn->name, rr->str, "pubsub", "patterns", "pubsub_patterns", DS_TYPE_GAUGE);
     redis_handle_info (rn->name, rr->str, "current_connections", "slaves", "connected_slaves", DS_TYPE_GAUGE);
+    redis_handle_info (rn->name, rr->str, "cache_result", "hits", "keyspace_hits", DS_TYPE_DERIVE);
+    redis_handle_info (rn->name, rr->str, "cache_result", "misses", "keyspace_misses", DS_TYPE_DERIVE);
+    redis_handle_info (rn->name, rr->str, "total_bytes", "input", "total_net_input_bytes", DS_TYPE_DERIVE);
+    redis_handle_info (rn->name, rr->str, "total_bytes", "output", "total_net_output_bytes", DS_TYPE_DERIVE);
 
     for (rq = rn->queries; rq != NULL; rq = rq->next)
         redis_handle_query(rh, rn, rq);
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 7cfdae6..fd5fb56 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 dc6a210..c678dec 100644 (file)
@@ -176,7 +176,7 @@ static char *conffile = NULL;
        "as bug."
 #endif
 
-featurelist_t *first_feature = NULL;
+static featurelist_t *first_feature = NULL;
 static ignorelist_t *sensor_list;
 
 #if SENSORS_API_VERSION < 0x400
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 487f31a..ad5c70c 100644 (file)
@@ -136,9 +136,9 @@ static int sigrok_config(oconfig_item_t *ci)
        return 0;
 }
 
-static char *sigrok_value_type(const struct sr_datafeed_analog *analog)
+static const char *sigrok_value_type(const struct sr_datafeed_analog *analog)
 {
-       char *s;
+       const char *s;
 
        if (analog->mq == SR_MQ_VOLTAGE)
                s = "voltage";
index 2207bd6..7b39aae 100644 (file)
@@ -68,7 +68,8 @@ static int smart_config (const char *key, const char *value)
   return (0);
 } /* int smart_config */
 
-static void smart_submit (const char *dev, char *type, char *type_inst, double value)
+static void smart_submit (const char *dev, const char *type,
+               const char *type_inst, double value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
index ae41d03..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++)
@@ -1384,7 +1403,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
 
   const data_set_t *ds;
 
-  uint32_t oid_list_len = (uint32_t) (data->values_len + 1);
+  size_t oid_list_len = data->values_len + 1;
   /* Holds the last OID returned by the device. We use this in the GETNEXT
    * request to proceed. */
   oid_t oid_list[oid_list_len];
@@ -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 e4c5d24..d714b5f 100644 (file)
@@ -82,6 +82,10 @@ static derive_t pagesize;
 static _Bool report_by_device = 0;
 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
 
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS
+/* No global variables */
+/* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS */
+
 #elif defined(VM_SWAPUSAGE)
 /* No global variables */
 /* #endif defined(VM_SWAPUSAGE) */
index 3f73178..849f7d1 100644 (file)
@@ -90,7 +90,7 @@ static int sl_notification (const notification_t *n,
        char  buf[1024] = "";
        size_t offset = 0;
        int log_severity;
-       char *severity_string;
+       const char *severity_string;
        int status;
 
        if (n->severity > notif_severity)
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 708cd2a..ffdba8a 100644 (file)
@@ -56,9 +56,9 @@ struct ctail_config_match_s
 };
 typedef struct ctail_config_match_s ctail_config_match_t;
 
-cu_tail_match_t **tail_match_list = NULL;
-size_t tail_match_list_num = 0;
-cdtime_t tail_match_list_intervals[255];
+static cu_tail_match_t **tail_match_list = NULL;
+static size_t tail_match_list_num = 0;
+static cdtime_t tail_match_list_intervals[255];
 
 static int ctail_config_add_match_dstype (ctail_config_match_t *cm,
     oconfig_item_t *ci)
@@ -332,7 +332,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;
@@ -349,8 +348,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..5b47ff5 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>
@@ -290,7 +283,7 @@ static uint32_t count_total[TCP_STATE_MAX + 1];
 static uint32_t sequence_number = 0;
 #endif
 
-enum
+static enum
 {
   SRC_DUNNO,
   SRC_NETLINK,
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..37ab85d 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);
@@ -263,7 +263,7 @@ static int ted_open_device (void)
     return (0);
 } /* int ted_open_device */
 
-static void ted_submit (char *type, double value)
+static void ted_submit (const char *type, double value)
 {
     value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
index 5df1b83..2e4bf05 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;
 
-#define DEF_TEST(func) static int test_##func ()
+#ifndef DBL_PRECISION
+# define DBL_PRECISION 1e-12
+#endif
+
+#define DEF_TEST(func) static int test_##func (void)
 
 #define RUN_TEST(func) do { \
   int status; \
@@ -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 27c92bc..54311a6 100644 (file)
@@ -35,8 +35,8 @@ static const char *config_keys[] = {
        "ForceUseProcfs"
 };
 
-const char *const dirname_sysfs = "/sys/class/thermal";
-const char *const dirname_procfs = "/proc/acpi/thermal_zone";
+static const char *const dirname_sysfs = "/sys/class/thermal";
+static const char *const dirname_procfs = "/proc/acpi/thermal_zone";
 
 static _Bool force_procfs = 0;
 static ignorelist_t *device_list;
index 45ee3b4..ed83129 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 f04a5fc..befbd50 100644 (file)
@@ -106,8 +106,8 @@ static void tt_submit (gauge_t val, const char* type)
 
 static void tt_open_db (void)
 {
-       char* host = NULL;
-       int   port = DEFAULT_PORT;
+       const char *host;
+       int         port = DEFAULT_PORT;
 
        if (rdb != NULL)
                return;
index 303f605..d5034e9 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
@@ -68,6 +68,7 @@ email_count           value:GAUGE:0:U
 email_size             value:GAUGE:0:U
 entropy                        value:GAUGE:0:4294967295
 expired_keys    value:DERIVE:0:U
+evicted_keys    value:DERIVE:0:U
 fanspeed               value:GAUGE:0:U
 file_handles           value:GAUGE:0:U
 file_size              value:GAUGE:0:U
index e62ed6c..795f7ab 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>
 
@@ -152,7 +151,7 @@ static int us_open_socket (void)
 
        do
        {
-               char *grpname;
+               const char *grpname;
                struct group *g;
                struct group sg;
                char grbuf[2048];
index a01d234..4106166 100644 (file)
@@ -125,7 +125,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 2d16222..4d679f0 100644 (file)
@@ -132,18 +132,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 36181ee..c7be9f0 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..2c7a59d 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
@@ -66,9 +62,6 @@
 #if HAVE_NETINET_IP6_H
 # include <netinet/ip6.h>
 #endif
-#if HAVE_NETINET_IP_COMPAT_H
-# include <netinet/ip_compat.h>
-#endif
 #if HAVE_NETINET_IF_ETHER_H
 # include <netinet/if_ether.h>
 #endif
@@ -163,9 +156,6 @@ typedef int (printer)(const char *, ...);
 /*
  * Global variables
  */
-int qtype_counts[T_MAX];
-int opcode_counts[OP_MAX];
-int qclass_counts[C_MAX];
 
 #if HAVE_PCAP_H
 static pcap_t *pcap_obj = NULL;
@@ -305,7 +295,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 +307,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 +345,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;
 }
 
@@ -425,11 +415,6 @@ handle_dns(const char *buf, int len)
 
     qh.length = (uint16_t) len;
 
-    /* gather stats */
-    qtype_counts[qh.qtype]++;
-    qclass_counts[qh.qclass]++;
-    opcode_counts[qh.opcode]++;
-
     if (Callback != NULL)
            Callback (&qh);
 
index 83f0ea4..ef7de0a 100644 (file)
@@ -48,8 +48,6 @@
 #define DNS_MSG_HDR_SZ 12
 
 #define T_MAX 65536
-#define OP_MAX 16
-#define C_MAX 65536
 #define MAX_QNAME_SZ 512
 
 struct rfc1035_header_s {
@@ -75,10 +73,6 @@ struct rfc1035_header_s {
 };
 typedef struct rfc1035_header_s rfc1035_header_t;
 
-extern int qtype_counts[T_MAX];
-extern int opcode_counts[OP_MAX];
-extern int qclass_counts[C_MAX];
-
 #if HAVE_PCAP_H
 void dnstop_set_pcap_obj (pcap_t *po);
 #endif
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 020d80b..2c0e4cd 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);
 
index 7a607e4..ca7d5fa 100644 (file)
  *   Florian Forster <ff at octo.it>
  **/
 
-#include <math.h>
-#include <limits.h>
-
 #include "collectd.h"
 #include "plugin.h"
 #include "utils_latency.h"
 #include "common.h"
 
+#include <math.h>
+#include <limits.h>
+
 #ifndef LLONG_MAX
 # define LLONG_MAX 9223372036854775807LL
 #endif
diff --git a/src/utils_latency_test.c b/src/utils_latency_test.c
new file mode 100644 (file)
index 0000000..f275813
--- /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 "common.h" /* for STATIC_ARRAY_SIZE */
+#include "collectd.h"
+#include "testing.h"
+#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 4ec5fb7..c329ba4 100644 (file)
@@ -757,7 +757,7 @@ void cu_mount_freelist (cu_mount_t *list)
 } /* void cu_mount_freelist(cu_mount_t *list) */
 
 char *
-cu_mount_checkoption(char *line, char *keyword, int full)
+cu_mount_checkoption(char *line, const char *keyword, int full)
 {
        char *line2, *l2, *p1, *p2;
        int l;
@@ -798,7 +798,7 @@ cu_mount_checkoption(char *line, char *keyword, int full)
 } /* char *cu_mount_checkoption(char *line, char *keyword, int full) */
 
 char *
-cu_mount_getoptionvalue(char *line, char *keyword)
+cu_mount_getoptionvalue(char *line, const char *keyword)
 {
        char *r;
 
@@ -820,7 +820,7 @@ cu_mount_getoptionvalue(char *line, char *keyword)
                }
        }
        return r;
-} /* char *cu_mount_getoptionvalue(char *line, char *keyword) */
+} /* char *cu_mount_getoptionvalue(char *line, const char *keyword) */
 
 int
 cu_mount_type(const char *type)
index 7518188..0a5c980 100644 (file)
@@ -113,7 +113,7 @@ void cu_mount_freelist(cu_mount_t *list);
        allocated by *list and *list itself as well.
 */
 
-char *cu_mount_checkoption(char *line, char *keyword, int full);
+char *cu_mount_checkoption(char *line, const char *keyword, int full);
 /*
   DESCRIPTION
        The cu_mount_checkoption() function is a replacement of
@@ -153,7 +153,7 @@ char *cu_mount_checkoption(char *line, char *keyword, int full);
        maybe you might want to try cu_mount_getoptionvalue()...
 */
 
-char *cu_mount_getoptionvalue(char *line, char *keyword);
+char *cu_mount_getoptionvalue(char *line, const char *keyword);
 /*
   DESCRIPTION
        The cu_mount_getoptionvalue() function can be used to grab
index c5ffbfb..d9d685a 100644 (file)
  *   Florian octo Forster <octo at collectd.org>
  */
 
-#include "testing.h"
 #include "collectd.h"
+#include "testing.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..06e4f21 100644 (file)
@@ -62,7 +62,7 @@ static int rra_timespans[] =
 };
 static int rra_timespans_num = STATIC_ARRAY_SIZE (rra_timespans);
 
-static char *rra_types[] =
+static const char *const rra_types[] =
 {
   "AVERAGE",
   "MIN",
@@ -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];
@@ -305,7 +305,7 @@ static int ds_get (char ***ret, /* {{{ */
   for (ds_num = 0; ds_num < ds->ds_num; ds_num++)
   {
     data_source_t *d = ds->ds + ds_num;
-    char *type;
+    const char *type;
     int status;
 
     ds_def[ds_num] = NULL;
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..6d23c8c 100644 (file)
@@ -24,8 +24,8 @@
  *   Florian Forster <octo at collectd.org>
  **/
 
-#include "testing.h"
 #include "collectd.h"
+#include "testing.h"
 #include "utils_vl_lookup.h"
 
 static _Bool expect_new_obj = 0;
@@ -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 c9355c4..79d4682 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;
@@ -830,7 +833,7 @@ refresh_lists (void)
 }
 
 static void
-free_domains ()
+free_domains (void)
 {
     int i;
 
@@ -863,7 +866,7 @@ add_domain (virDomainPtr dom)
 }
 
 static void
-free_block_devices ()
+free_block_devices (void)
 {
     int i;
 
@@ -903,7 +906,7 @@ add_block_device (virDomainPtr dom, const char *path)
 }
 
 static void
-free_interface_devices ()
+free_interface_devices (void)
 {
     int i;
 
index bd2e867..6c09f43 100644 (file)
@@ -215,7 +215,7 @@ static int vserver_read (void)
                {
                        derive_t rx;
                        derive_t tx;
-                       char *type_instance;
+                       const char *type_instance;
 
                        if (strsplit (buffer, cols, 4) < 4)
                                continue;
@@ -265,7 +265,7 @@ static int vserver_read (void)
 
                        if (2 == n)
                        {
-                               char   *type_instance;
+                               const char *type_instance;
                                gauge_t value;
 
                                if (0 == strcmp (cols[0], "nr_threads:"))
@@ -314,8 +314,8 @@ static int vserver_read (void)
 
                while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
                {
-                       char *type = "vs_memory";
-                       char *type_instance;
+                       const char *type = "vs_memory";
+                       const char *type_instance;
                        gauge_t value;
 
                        if (strsplit (buffer, cols, 2) < 2)
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..361c39e 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 "
@@ -523,6 +540,7 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
         int buffer_size = 0;
         user_data_t user_data;
         char callback_name[DATA_MAX_NAME_LEN];
+        int status = 0;
         int i;
 
         cb = malloc (sizeof (*cb));
@@ -538,6 +556,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);
 
@@ -552,30 +571,32 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
                 oconfig_item_t *child = ci->children + i;
 
                 if (strcasecmp ("URL", child->key) == 0)
-                        cf_util_get_string (child, &cb->location);
+                        status = cf_util_get_string (child, &cb->location);
                 else if (strcasecmp ("User", child->key) == 0)
-                        cf_util_get_string (child, &cb->user);
+                        status = cf_util_get_string (child, &cb->user);
                 else if (strcasecmp ("Password", child->key) == 0)
-                        cf_util_get_string (child, &cb->pass);
+                        status = cf_util_get_string (child, &cb->pass);
                 else if (strcasecmp ("VerifyPeer", child->key) == 0)
-                        cf_util_get_boolean (child, &cb->verify_peer);
+                        status = cf_util_get_boolean (child, &cb->verify_peer);
                 else if (strcasecmp ("VerifyHost", child->key) == 0)
-                        cf_util_get_boolean (child, &cb->verify_host);
+                        status = cf_util_get_boolean (child, &cb->verify_host);
                 else if (strcasecmp ("CACert", child->key) == 0)
-                        cf_util_get_string (child, &cb->cacert);
+                        status = cf_util_get_string (child, &cb->cacert);
                 else if (strcasecmp ("CAPath", child->key) == 0)
-                        cf_util_get_string (child, &cb->capath);
+                        status = cf_util_get_string (child, &cb->capath);
                 else if (strcasecmp ("ClientKey", child->key) == 0)
-                        cf_util_get_string (child, &cb->clientkey);
+                        status = cf_util_get_string (child, &cb->clientkey);
                 else if (strcasecmp ("ClientCert", child->key) == 0)
-                        cf_util_get_string (child, &cb->clientcert);
+                        status = cf_util_get_string (child, &cb->clientcert);
                 else if (strcasecmp ("ClientKeyPass", child->key) == 0)
-                        cf_util_get_string (child, &cb->clientkeypass);
+                        status = cf_util_get_string (child, &cb->clientkeypass);
                 else if (strcasecmp ("SSLVersion", child->key) == 0)
                 {
                         char *value = NULL;
 
-                        cf_util_get_string (child, &value);
+                        status = cf_util_get_string (child, &value);
+                        if (status != 0)
+                                break;
 
                         if (value == NULL || strcasecmp ("default", value) == 0)
                                 cb->sslversion = CURL_SSLVERSION_DEFAULT;
@@ -594,26 +615,41 @@ static int wh_config_node (oconfig_item_t *ci) /* {{{ */
                                 cb->sslversion = CURL_SSLVERSION_TLSv1_2;
 #endif
                         else
+                        {
                                 ERROR ("write_http plugin: Invalid SSLVersion "
                                                 "option: %s.", value);
+                                status = EINVAL;
+                        }
 
                         sfree(value);
                 }
                 else if (strcasecmp ("Format", child->key) == 0)
-                        config_set_format (cb, child);
+                        status = config_set_format (cb, child);
                 else if (strcasecmp ("StoreRates", child->key) == 0)
-                        cf_util_get_boolean (child, &cb->store_rates);
+                        status = cf_util_get_boolean (child, &cb->store_rates);
                 else if (strcasecmp ("BufferSize", child->key) == 0)
-                        cf_util_get_int (child, &buffer_size);
+                        status = cf_util_get_int (child, &buffer_size);
                 else if (strcasecmp ("LowSpeedLimit", child->key) == 0)
-                        cf_util_get_int (child, &cb->low_speed_limit);
+                        status = cf_util_get_int (child, &cb->low_speed_limit);
                 else if (strcasecmp ("Timeout", child->key) == 0)
-                        cf_util_get_int (child, &cb->timeout);
+                        status = cf_util_get_int (child, &cb->timeout);
+                else if (strcasecmp ("LogHttpError", child->key) == 0)
+                        status = cf_util_get_boolean (child, &cb->log_http_error);
                 else
                 {
                         ERROR ("write_http plugin: Invalid configuration "
                                         "option: %s.", child->key);
+                        status = EINVAL;
                 }
+
+                if (status != 0)
+                        break;
+        }
+
+        if (status != 0)
+        {
+                wh_callback_free (cb);
+                return (status);
         }
 
         if (cb->location == NULL)
index 775e2e0..a5371d4 100644 (file)
@@ -44,20 +44,19 @@ 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;
     rd_kafka_topic_t            *topic;
     rd_kafka_conf_t             *kafka_conf;
     rd_kafka_t                  *kafka;
-    int                          has_key;
-    uint32_t                    key;
+    char                        *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 +80,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 +105,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 +143,17 @@ 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;
+    void    *key;
+    size_t   keylen = 0;
+    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);
@@ -200,27 +199,23 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
         return -1;
     }
 
-    /*
-     * We partition our stream by metric name
-     */
-    if (ctx->has_key)
-        key = ctx->key;
-    else
-        key = rand();
+    key = ctx->key;
+    if (key != NULL)
+        keylen = strlen (key);
 
     rd_kafka_produce(ctx->topic, RD_KAFKA_PARTITION_UA,
                      RD_KAFKA_MSG_F_COPY, buffer, blen,
-                     &key, sizeof(key), NULL);
+                     key, keylen, 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 +241,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,48 +285,36 @@ 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;
-            status = cf_util_get_string(child, &tmp_buf);
-            if (status != 0) {
-                WARNING("write_kafka plugin: invalid key supplied");
-                break;
             }
 
-            if (strcasecmp(tmp_buf, "Random") != 0) {
-                tctx->has_key = 1;
-                tctx->key = crc32_buffer((u_char *)tmp_buf, strlen(tmp_buf));
-            }
-            sfree(tmp_buf);
-
+        } else if (strcasecmp ("Key", child->key) == 0)  {
+            cf_util_get_string (child, &tctx->key);
         } else if (strcasecmp ("Format", child->key) == 0) {
             status = cf_util_get_string(child, &key);
             if (status != 0)
@@ -397,11 +380,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 +397,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 +413,52 @@ 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.");
+                sfree(key);
                 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);
+                sfree(key);
+                sfree(val);
                 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 +467,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 231738c..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,13 +74,15 @@ 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);
+  status = format_values (value_ptr, value_size, ds, vl, node->store_rates);
   if (status != 0)
     return (status);
 
@@ -98,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);
@@ -106,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
@@ -153,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));
@@ -181,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 58611a9..6a47ba3 100644 (file)
@@ -26,7 +26,6 @@
  *   Florian octo Forster <octo at collectd.org>
  */
 
-#include <sys/socket.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <netdb.h>
@@ -364,7 +363,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)
@@ -473,7 +472,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)
@@ -618,7 +617,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)
        {
@@ -743,8 +742,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);
@@ -777,35 +776,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 b1f7297..8567288 100644 (file)
@@ -134,7 +134,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];
 
@@ -203,7 +203,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 0d568fe..aae5d8b 100644 (file)
@@ -31,7 +31,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>
@@ -284,7 +283,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;
@@ -596,7 +595,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) {
@@ -840,7 +839,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);
@@ -854,7 +853,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..c562596 100644 (file)
@@ -49,7 +49,6 @@
 #include "utils_cache.h"
 
 #include <pthread.h>
-#include <sys/socket.h>
 #include <netdb.h>
 
 #ifndef WT_DEFAULT_NODE
@@ -347,7 +346,7 @@ static int wt_format_name(char *ret, int ret_len,
 {
     int status;
     char *temp = NULL;
-    char *prefix = "";
+    const char *prefix = "";
     const char *meta_prefix = "tsdb_prefix";
 
     if (vl->meta) {
@@ -410,11 +409,11 @@ 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 = "";
+    const char *tags = "";
     char message[1024];
-    char *host_tags = cb->host_tags ? cb->host_tags : "";
+    const char *host_tags = cb->host_tags ? cb->host_tags : "";
     const char *meta_tsdb = "tsdb_tags";
 
     /* skip if value is NaN */
@@ -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 8feb31d..e1c3937 100644 (file)
 
 typedef        llist_t kstat_t;
 
-static long long get_zfs_value(kstat_t *zfs_stats  __attribute__((unused)),
-               char *name)
+static int put_zfs_value (kstat_t *ksp, char const *k, value_t v)
 {
        llentry_t *e;
+       char *k_copy;
+       value_t *v_copy;
 
-       e = llist_search (zfs_stats, name);
+       k_copy = strdup (k);
+       if (k_copy == NULL)
+               return ENOMEM;
+
+       v_copy = malloc (sizeof (*v_copy));
+       if (v_copy == NULL)
+       {
+               sfree (k_copy);
+               return ENOMEM;
+       }
+       *v_copy = v;
+
+       e = llentry_create (k_copy, v_copy);
        if (e == NULL)
        {
-               ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", name);
+               sfree (v_copy);
+               sfree (k_copy);
+               return ENOMEM;
+       }
+
+       llist_append (ksp, e);
+       return 0;
+}
+
+static long long get_zfs_value(kstat_t *ksp, const char *key)
+{
+       llentry_t *e;
+       value_t *v;
+
+       e = llist_search (ksp, key);
+       if (e == NULL)
+       {
+               ERROR ("zfs_arc plugin: `llist_search` failed for key: '%s'.", key);
                return (-1);
        }
 
-       return (*(long long int*)e->value);
+       v = e->value;
+       return ((long long) v->derive);
+}
+
+static void free_zfs_values (kstat_t *ksp)
+{
+       llentry_t *e;
+
+       if (ksp == NULL)
+               return;
+
+       for (e = llist_head (ksp); e != NULL; e = e->next)
+       {
+               sfree (e->key);
+               sfree (e->value);
+       }
+
+       llist_destroy (ksp);
 }
 
 #elif !defined(__FreeBSD__) // Solaris
@@ -173,79 +220,45 @@ static int za_read (void)
        kstat_t  *ksp   = NULL;
 
 #if KERNEL_LINUX
-       long long int *llvalues = NULL;
-       char file_contents[1024 * 10];
-       char *fields[3];
-       int numfields;
-       ssize_t len;
+       FILE *fh;
+       char buffer[1024];
+
+       fh = fopen (ZOL_ARCSTATS_FILE, "r");
+       if (fh == NULL)
+       {
+               char errbuf[1024];
+               ERROR ("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE,
+                      sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
 
        ksp = llist_create ();
        if (ksp == NULL)
        {
                ERROR ("zfs_arc plugin: `llist_create' failed.");
+               fclose (fh);
                return (-1);
        }
 
-       len = read_file_contents (ZOL_ARCSTATS_FILE, file_contents, sizeof(file_contents) - 1);
-       if (len > 1)
+       while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
+               char *fields[3];
+               value_t v;
+               int status;
+
+               status = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
+               if (status != 3)
+                       continue;
 
-               int i=0;
-               char *pnl = file_contents;
-               char *pnnl;
-
-               file_contents[len] = '\0';
-
-               while (pnl != NULL)
-               {
-                       pnl = strchr(pnl, '\n');
-                       i++;
-                       if (pnl && (*pnl != '\0'))
-                               pnl++;
-               }
-
-               if (i > 0)
-               {
-                       llentry_t *e;
-                       llvalues = malloc(sizeof(long long int) * i);
-                       if (llvalues == NULL)
-                       {
-                               ERROR ("zfs_arc plugin: `malloc' failed.");
-                               llist_destroy (ksp);
-                               return (-1);
-                       }
-                       int j = 0;
-
-                       pnl = file_contents;
-                       while (pnl != NULL)
-                       {
-                               pnnl = strchr(pnl, '\n');
-                               if (pnnl != NULL)
-                                       *pnnl = '\0';
-
-                               numfields = strsplit (pnl, fields, 4);
-                               if (numfields == 3)
-                               {
-                                       llvalues[j] = atoll (fields[2]);
-
-                                       e = llentry_create (fields[0], &llvalues[j]);
-                                       if (e == NULL)
-                                       {
-                                               ERROR ("zfs_arc plugin: `llentry_create' failed.");
-                                       }
-                                       else
-                                       {
-                                               llist_append (ksp, e);
-                                       }
-                                       j++;
-                               }
-                               pnl = pnnl;
-                               if (pnl != NULL)
-                                       pnl ++;
-                       }
-               }
+               status = parse_value (fields[2], &v, DS_TYPE_DERIVE);
+               if (status != 0)
+                       continue;
+
+               put_zfs_value (ksp, fields[0], v);
        }
 
+       fclose (fh);
+
 #elif !defined(__FreeBSD__) // Solaris
        get_kstat (&ksp, "zfs", 0, "arcstats");
        if (ksp == NULL)
@@ -257,6 +270,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.
@@ -311,14 +327,7 @@ static int za_read (void)
        za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
 
 #if defined(KERNEL_LINUX)
-       if (llvalues != NULL)
-       {
-               free(llvalues);
-       }
-       if (ksp != NULL)
-       {
-               llist_destroy (ksp);
-       }
+       free_zfs_values (ksp);
 #endif
 
        return (0);
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..1eed1fb 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>
@@ -109,8 +108,8 @@ static int zookeeper_connect (void)
        struct addrinfo ai_hints;
        struct addrinfo *ai;
        struct addrinfo *ai_list;
-       char *host;
-       char *port;
+       const char *host;
+       const char *port;
 
        memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
        ai_hints.ai_family   = AF_UNSPEC;
index e0ad124..d7c6a76 100755 (executable)
@@ -2,12 +2,12 @@
 
 DEFAULT_VERSION="5.5.1.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"