Merge branch 'collectd-5.4' into collectd-5.5
authorFlorian Forster <octo@collectd.org>
Wed, 17 Jun 2015 07:12:26 +0000 (09:12 +0200)
committerFlorian Forster <octo@collectd.org>
Wed, 17 Jun 2015 07:12:26 +0000 (09:12 +0200)
1  2 
README
src/daemon/utils_avltree.c
src/daemon/utils_llist.c
src/liboconfig/oconfig.c
src/liboconfig/scanner.l
src/network.c
src/perl.c
src/target_notification.c
src/utils_rrdcreate.c

diff --combined README
--- 1/README
--- 2/README
+++ b/README
@@@ -16,27 -16,22 +16,27 @@@ Feature
    * collectd is able to collect the following data:
  
      - apache
 -      Apache server utilization: Number of bytes transfered, number of
 +      Apache server utilization: Number of bytes transferred, number of
        requests handled and detailed scoreboard statistics
  
      - apcups
        APC UPS Daemon: UPS charge, load, input/output/battery voltage, etc.
  
      - apple_sensors
 -      Sensors in Macs running Mac OS X / Darwin: Temperature, fanspeed and
 +      Sensors in Macs running Mac OS X / Darwin: Temperature, fan speed and
        voltage sensors.
  
      - aquaero
 -      Various sensors in the Aquaero 5 watercooling board made by Aquacomputer.
 +      Various sensors in the Aquaero 5 water cooling board made by Aquacomputer.
  
      - ascent
        Statistics about Ascent, a free server for the game `World of Warcraft'.
  
 +    - barometer
 +      Reads absolute barometric pressure, air pressure reduced to sea level and
 +      temperature.  Supported sensors are MPL115A2 and MPL3115 from Freescale
 +      and BMP085 from Bosch.
 +
      - battery
        Batterycharge, -current and voltage of ACPI and PMU based laptop
        batteries.
@@@ -45,9 -40,6 +45,9 @@@
        Name server and resolver statistics from the `statistics-channel'
        interface of BIND 9.5, 9,6 and later.
  
 +    - ceph
 +      Statistics from the Ceph distributed storage system.
 +
      - cgroups
        CPU accounting information for process groups under Linux.
  
  
      - dns
        DNS traffic: Query types, response codes, opcodes and traffic/octets
 -      transfered.
 +      transferred.
 +
 +    - drbd
 +      Collect individual drbd resource statistics.
  
      - email
        Email statistics: Count, traffic, spam scores and checks.
        Values gathered by a custom program or script.
        See collectd-exec(5).
  
 +    - fhcount
 +      File handles statistics.
 +
      - filecount
        Count the number of files in directories.
  
        Receive multicast traffic from Ganglia instances.
  
      - hddtemp
 -      Harddisk temperatures using hddtempd.
 +      Hard disk temperatures using hddtempd.
  
      - interface
        Interface traffic: Number of octets, packets and errors for each
        interface.
  
 -    - iptables
 -      Iptables' counters: Number of bytes that were matched by a certain
 -      iptables rule.
 +    - ipc
 +      IPC counters: semaphores used, number of allocated segments in shared
 +      memory and more.
  
      - ipmi
        IPMI (Intelligent Platform Management Interface) sensors information.
  
 +    - iptables
 +      Iptables' counters: Number of bytes that were matched by a certain
 +      iptables rule.
 +
      - ipvs
        IPVS connection statistics (number of connections, octets and packets
        for each service and destination).
        Detailed CPU statistics of the “Logical Partitions” virtualization
        technique built into IBM's POWER processors.
  
 -    - libvirt
 -      CPU, memory, disk and network I/O statistics from virtual machines.
 -
      - lvm
        Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
        “Logical Volume Manager” (LVM).
        interfaces that use the Atheros chipset and the MadWifi driver.
  
      - mbmon
 -      Motherboard sensors: temperature, fanspeed and voltage information,
 +      Motherboard sensors: temperature, fan speed and voltage information,
        using mbmon(1).
  
      - md
      - ntpd
        NTP daemon statistics: Local clock drift, offset to peers, etc.
  
 +    - numa
 +      Information about Non-Uniform Memory Access (NUMA).
 +
      - nut
        Network UPS tools: UPS current, voltage, power, charge, utilisation,
        temperature, etc. See upsd(8).
  
 -    - numa
 -      Information about Non-Uniform Memory Access (NUMA).
 -
      - olsrd
        Queries routing information from the “Optimized Link State Routing”
        daemon.
        Read onewire sensors using the owcapu library of the owfs project.
        Please read in collectd.conf(5) why this plugin is experimental.
  
 +    - openldap
 +      Read monitoring information from OpenLDAP's cn=Monitor subtree.
 +
      - openvpn
        RX and TX of each client in openvpn-status.log (status-version 2).
        <http://openvpn.net/index.php/documentation/howto.html>
        See collectd-python(5) for details.
  
      - redis
 -      The redis plugin gathers information from a redis server, including:
 +      The redis plugin gathers information from a Redis server, including:
        uptime, used memory, total connections etc.
  
      - routeros
        to have its measurements fed to collectd. This includes multimeters,
        sound level meters, thermometers, and much more.
  
 +    - smart
 +      Collect SMART statistics, notably load cycle count, temperature
 +      and bad sectors.
 +
      - snmp
        Read values from SNMP (Simple Network Management Protocol) enabled
        network devices such as switches, routers, thermometers, rack monitoring
        servers, etc. See collectd-snmp(5).
  
 +    - statsd
 +      Acts as a StatsD server, reading values sent over the network from StatsD
 +      clients and calculating rates and other aggregates out of these values.
 +
      - swap
 -      Pages swapped out onto harddisk or whatever is called `swap' by the OS..
 +      Pages swapped out onto hard disk or whatever is called `swap' by the OS..
  
      - table
        Parse table-like structured files.
  
      - tail
 -      Follows (tails) logfiles, parses them by lines and submits matched
 +      Follows (tails) log files, parses them by lines and submits matched
        values.
  
      - tail_csv
        Reads the number of records and file size from a running Tokyo Tyrant
        server.
  
 +    - turbostat
 +      Reads CPU frequency and C-state residency on modern Intel
 +      turbo-capable processors.
 +
      - uptime
        System uptime statistics.
  
      - varnish
        Various statistics from Varnish, an HTTP accelerator.
  
 +    - virt
 +      CPU, memory, disk and network I/O statistics from virtual machines.
 +
      - vmem
        Virtual memory statistics, e. g. the number of page-ins/-outs or the
        number of pagefaults.
      - zfs_arc
        Statistics for ZFS' “Adaptive Replacement Cache” (ARC).
  
 +    - zookeeper
 +      Read data from Zookeeper's MNTR command.
 +
    * Output can be written or sent to various destinations by the following
      plugins:
  
        requests. The transmitted data is either in a form understood by the
        Exec plugin or formatted in JSON.
  
 +    - write_kafka
 +      Sends data to Apache Kafka, a distributed queue.
 +
 +    - write_log
 +      Writes data to the log
 +
      - write_mongodb
        Sends data to MongoDB, a NoSQL database.
  
      - write_riemann
        Sends data to Riemann, a stream processing and monitoring system.
  
 +    - write_sensu
 +      Sends data to Sensu, a stream processing and monitoring system, via the
 +      Sensu client local TCP socket.
 +
 +    - write_tsdb
 +      Sends data OpenTSDB, a scalable no master, no shared state time series
 +      database.
 +
    * Logging is, as everything in collectd, provided by plugins. The following
-     plugins keep up informed about what's going on:
+     plugins keep us informed about what's going on:
  
      - logfile
 -      Writes logmessages to a file or STDOUT/STDERR.
 +      Writes log messages to a file or STDOUT/STDERR.
  
      - perl
        Log messages are propagated to plugins written in Perl as well.
      - syslog
        Logs to the standard UNIX logging mechanism, syslog.
  
 +    - log_logstash
 +      Writes log messages formatted as logstash JSON events.
 +
    * Notifications can be handled by the following plugins:
  
      - notify_desktop
        values are out of bounds. See collectd-threshold(5) for details.
  
      - uuid
 -      Sets the hostname to an unique identifier. This is meant for setups
 +      Sets the hostname to a unique identifier. This is meant for setups
        where each client may migrate to another physical host, possibly going
        through one or more name changes in the process.
  
      time starting up again and again. With the exception of the exec plugin no
      processes are forked. Caching in output plugins, such as the rrdtool and
      network plugins, makes sure your resources are used efficiently. Also,
 -    since collectd is programmed multithreaded it benefits from hyperthreading
 +    since collectd is programmed multithreaded it benefits from hyper-threading
      and multicore processors and makes sure that the daemon isn't idle if only
      one plugin waits for an IO-operation to complete.
  
@@@ -574,7 -521,7 +574,7 @@@ Operatio
  ---------
  
    * collectd's configuration file can be found at `sysconfdir'/collectd.conf.
 -    Run `collectd -h' for a list of builtin defaults. See `collectd.conf(5)'
 +    Run `collectd -h' for a list of built-in defaults. See `collectd.conf(5)'
      for a list of options and a syntax description.
  
    * When the `csv' or `rrdtool' plugins are loaded they'll write the values to
@@@ -618,7 -565,7 +618,7 @@@ Prerequisite
  
    * A POSIX-threads (pthread) implementation.
      Since gathering some statistics is slow (network connections, slow devices,
 -    etc) the collectd is parallelized. The POSIX threads interface is being
 +    etc) collectd is parallelized. The POSIX threads interface is being
      used and should be found in various implementations for hopefully all
      platforms.
  
      particular.
      <http://developer.apple.com/corefoundation/>
  
 +  * libatasmart (optional)
 +    Used by the `smart' plugin.
 +    <http://git.0pointer.de/?p=libatasmart.git>
 +
 +  * libcap (optional)
 +    The `turbostat' plugin can optionally build Linux Capabilities support,
 +    which avoids full privileges requirement (aka. running as root) to read
 +    values.
 +    <http://sites.google.com/site/fullycapable/>
 +
    * libclntsh (optional)
      Used by the `oracle' plugin.
  
 -  * libcredis (optional)
 -    Used by the redis plugin. Please note that you require a 0.2.2 version
 -    or higher. <http://code.google.com/p/credis/>
 +  * libhiredis (optional)
 +    Used by the redis plugin. Please note that you require a 0.10.0 version
 +    or higher. <https://github.com/redis/hiredis>
  
    * libcurl (optional)
 -    If you want to use the `apache', `ascent', `curl', `nginx', or `write_http'
 -    plugin.
 +    If you want to use the `apache', `ascent', `bind', `curl', `curl_json',
 +    `curl_xml', `nginx', or `write_http' plugin.
      <http://curl.haxx.se/>
  
    * libdbi (optional)
      <http://www.gnupg.org/>
  
    * libhal (optional)
 -    If present, the uuid plugin will check for UUID from HAL.
 +    If present, the `uuid' plugin will check for UUID from HAL.
      <http://hal.freedesktop.org/>
  
 +  * libi2c-dev (optional)
 +    Used for the plugin `barometer', provides just the i2c-dev.h header file
 +    for user space i2c development.
 +
    * libiptc (optional)
      For querying iptables counters.
      <http://netfilter.org/>
  
 -    If not found on the system, a version shipped with this distribution can
 -    be used. It requires some Linux headers in /usr/include/linux. You can
 -    force the build system to use the shipped version by specifying
 -      --with-libiptc=shipped
 -    when running the configure script.
 -
    * libjvm (optional)
      Library that encapsulates the `Java Virtual Machine' (JVM). This library is
 -    used by the Java plugin to execute Java bytecode. See “Configuring with
 +    used by the `java' plugin to execute Java bytecode. See “Configuring with
      libjvm” below.
      <http://openjdk.java.net/> (and others)
  
 +  * libldap (optional)
 +    Used by the `openldap' plugin.
 +    <http://www.openldap.org/>
 +
 +  * liblvm2 (optional)
 +    Used by the `lvm' plugin.
 +    <ftp://sources.redhat.com/pub/lvm2/>
 +
    * libmemcached (optional)
      Used by the `memcachec' plugin to connect to a memcache daemon.
      <http://tangent.org/552/libmemcached.html>
      <http://www.netfilter.org/projects/libmnl/>
  
    * libmodbus (optional)
 -    Used by the “modbus” plugin to communicate with Modbus/TCP devices. The
 -    “modbus” plugin works with version 2.0.3 of the library – due to frequent
 +    Used by the `modbus' plugin to communicate with Modbus/TCP devices. The
 +    `modbus' plugin works with version 2.0.3 of the library – due to frequent
      API changes other versions may or may not compile cleanly.
      <http://www.libmodbus.org/>
  
      <http://dev.mysql.com/>
  
    * libnetapp (optional)
 -    Required for the “netapp” plugin.
 +    Required for the `netapp' plugin.
      This library is part of the “Manage ONTAP SDK” published by NetApp.
  
    * libnetsnmp (optional)
      For the `notify_desktop' plugin.
      <http://www.galago-project.org/>
  
 +  * libopenipmi (optional)
 +    Used by the `ipmi' plugin to prove IPMI devices.
 +    <http://openipmi.sourceforge.net/>
 +
    * liboping (optional)
      Used by the `ping' plugin to send and receive ICMP packets.
 -    <http://verplant.org/liboping/>
 +    <http://octo.it/liboping/>
  
    * libowcapi (optional)
      Used by the `onewire' plugin to read values from onewire sensors (or the
  
    * libprotobuf-c, protoc-c (optional)
      Used by the `pinba' plugin to generate a parser for the network packets
 -    sent by the Pinba PHP extension.
 +    sent by the Pinba PHP extension, and by the `write_riemann' plugin to
 +    generate events to be sent to a Riemann server.
      <http://code.google.com/p/protobuf-c/>
  
    * libpython (optional)
      <http://www.python.org/>
  
    * librabbitmq (optional; also called “rabbitmq-c”)
 -    Used by the AMQP plugin for AMQP connections, for example to RabbitMQ.
 +    Used by the `amqp' plugin for AMQP connections, for example to RabbitMQ.
      <http://hg.rabbitmq.com/rabbitmq-c/>
  
 +  * librdkafka (optional; also called “rdkafka”)
 +    Used by the `write_kafka' plugin for producing messages and sending them
 +    to a Kafka broker.
 +    <https://github.com/edenhill/librdkafka>
 +
    * librouteros (optional)
      Used by the `routeros' plugin to connect to a device running `RouterOS'.
 -    <http://verplant.org/librouteros/>
 +    <http://octo.it/librouteros/>
  
    * librrd (optional)
      Used by the `rrdtool' and `rrdcached' plugins. The latter requires RRDtool
      <http://www.lm-sensors.org/>
  
    * libsigrok (optional)
 -    Used by the sigrok plugin. In addition, libsigrok depends on glib,
 +    Used by the `sigrok' plugin. In addition, libsigrok depends on glib,
      libzip, and optionally (depending on which drivers are enabled) on
      libusb, libftdi and libudev.
  
      <http://www.i-scream.org/libstatgrab/>
  
    * libtokyotyrant (optional)
 -    Used by the tokyotyrant plugin.
 +    Used by the `tokyotyrant' plugin.
      <http://1978th.net/tokyotyrant/>
  
    * libupsclient/nut (optional)
      <http://libvirt.org/>
  
    * libxml2 (optional)
 -    Parse XML data. This is needed for the `ascent' and `libvirt' plugins.
 +    Parse XML data. This is needed for the `ascent', `bind', `curl_xml' and
 +    `virt' plugins.
      <http://xmlsoft.org/>
  
    * libxmms (optional)
      <http://www.xmms.org/>
  
    * libyajl (optional)
 -    Parse JSON data. This is needed for the `curl_json' plugin.
 +    Parse JSON data. This is needed for the `ceph', `curl_json' and
 +    `log_logstash' plugins.
      <http://github.com/lloyd/yajl>
  
    * libvarnish (optional)
 -     Fetches statistics from a Varnish instance. This is needed for the Varnish plugin
 +     Fetches statistics from a Varnish instance. This is needed for the
 +     `varnish' plugin.
       <http://varnish-cache.org>
  
  Configuring / Compiling / Installing
@@@ -903,23 -821,6 +903,23 @@@ Configuring with libjv
    Adding "-ljvm" to the JAVA_LDFLAGS is done automatically, you don't have to
    do that.
  
 +Generating the configure script
 +-------------------------------
 +
 +Collectd ships with a `build.sh' script to generate the `configure'
 +script shipped with releases.
 +
 +To generate the `configure` script, you'll need the following dependencies:
 +
 +- autoconf
 +- automake
 +- flex
 +- bison
 +- libtool
 +- libtool-ltdl
 +
 +The `build.sh' script takes no arguments.
 +
  Crosscompiling
  --------------
  
@@@ -956,7 -857,7 +956,7 @@@ Contac
  
    For questions, bug reports, development information and basically all other
    concerns please send an email to collectd's mailing list at
 -  <collectd at verplant.org>.
 +  <list at collectd.org>.
  
    For live discussion and more personal contact visit us in IRC, we're in
    channel #collectd on freenode.
  Author
  ------
  
 -  Florian octo Forster <octo at verplant.org>,
 +  Florian octo Forster <octo at collectd.org>,
    Sebastian tokkee Harl <sh at tokkee.org>,
    and many contributors (see `AUTHORS').
  
index 04e5403,0000000..da793b3
mode 100644,000000..100644
--- /dev/null
@@@ -1,730 -1,0 +1,738 @@@
-               int height_left  = (n->left  == NULL) ? 0 : n->left->height;
-               int height_right = (n->right == NULL) ? 0 : n->right->height;
 +/**
 + * collectd - src/utils_avltree.c
 + * Copyright (C) 2006,2007  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 "config.h"
 +
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <assert.h>
 +
 +#include "utils_avltree.h"
 +
 +#define BALANCE(n) ((((n)->left == NULL) ? 0 : (n)->left->height) \
 +              - (((n)->right == NULL) ? 0 : (n)->right->height))
 +
 +/*
 + * private data types
 + */
 +struct c_avl_node_s
 +{
 +      void *key;
 +      void *value;
 +
 +      int height;
 +      struct c_avl_node_s *left;
 +      struct c_avl_node_s *right;
 +      struct c_avl_node_s *parent;
 +};
 +typedef struct c_avl_node_s c_avl_node_t;
 +
 +struct c_avl_tree_s
 +{
 +      c_avl_node_t *root;
 +      int (*compare) (const void *, const void *);
 +      int size;
 +};
 +
 +struct c_avl_iterator_s
 +{
 +      c_avl_tree_t *tree;
 +      c_avl_node_t *node;
 +};
 +
 +/*
 + * private functions
 + */
 +#if 0
 +static void verify_tree (c_avl_node_t *n)
 +{
 +      if (n == NULL)
 +              return;
 +
 +      verify_tree (n->left);
 +      verify_tree (n->right);
 +
 +      assert ((BALANCE (n) >= -1) && (BALANCE (n) <= 1));
 +      assert ((n->parent == NULL) || (n->parent->right == n) || (n->parent->left == n));
 +} /* void verify_tree */
 +#else
 +# define verify_tree(n) /**/
 +#endif
 +
 +static void free_node (c_avl_node_t *n)
 +{
 +      if (n == NULL)
 +              return;
 +
 +      if (n->left != NULL)
 +              free_node (n->left);
 +      if (n->right != NULL)
 +              free_node (n->right);
 +
 +      free (n);
 +}
 +
 +static int calc_height (c_avl_node_t *n)
 +{
 +      int height_left;
 +      int height_right;
 +
 +      if (n == NULL)
 +              return (0);
 +
 +      height_left  = (n->left == NULL)  ? 0 : n->left->height;
 +      height_right = (n->right == NULL) ? 0 : n->right->height;
 +
 +      return (((height_left > height_right)
 +                              ? height_left
 +                              : height_right) + 1);
 +} /* int calc_height */
 +
 +static c_avl_node_t *search (c_avl_tree_t *t, const void *key)
 +{
 +      c_avl_node_t *n;
 +      int cmp;
 +
 +      n = t->root;
 +      while (n != NULL)
 +      {
 +              cmp = t->compare (key, n->key);
 +              if (cmp == 0)
 +                      return (n);
 +              else if (cmp < 0)
 +                      n = n->left;
 +              else
 +                      n = n->right;
 +      }
 +
 +      return (NULL);
 +}
 +
 +/*         (x)             (y)
 + *        /   \           /   \
 + *     (y)    /\         /\    (x)
 + *    /   \  /_c\  ==>  / a\  /   \
 + *   /\   /\           /____\/\   /\
 + *  / a\ /_b\               /_b\ /_c\
 + * /____\
 + */
 +static c_avl_node_t *rotate_right (c_avl_tree_t *t, c_avl_node_t *x)
 +{
 +      c_avl_node_t *p;
 +      c_avl_node_t *y;
 +      c_avl_node_t *b;
 +
 +      p = x->parent;
 +      y = x->left;
 +      b = y->right;
 +
 +      x->left = b;
 +      if (b != NULL)
 +              b->parent = x;
 +
 +      x->parent = y;
 +      y->right = x;
 +
 +      y->parent = p;
 +      assert ((p == NULL) || (p->left == x) || (p->right == x));
 +      if (p == NULL)
 +              t->root = y;
 +      else if (p->left == x)
 +              p->left = y;
 +      else
 +              p->right = y;
 +
 +      x->height = calc_height (x);
 +      y->height = calc_height (y);
 +
 +      return (y);
 +} /* void rotate_left */
 +
 +/*
 + *    (x)                   (y)
 + *   /   \                 /   \
 + *  /\    (y)           (x)    /\
 + * /_a\  /   \   ==>   /   \  / c\
 + *      /\   /\       /\   /\/____\
 + *     /_b\ / c\     /_a\ /_b\
 + *         /____\
 + */
 +static c_avl_node_t *rotate_left (c_avl_tree_t *t, c_avl_node_t *x)
 +{
 +      c_avl_node_t *p;
 +      c_avl_node_t *y;
 +      c_avl_node_t *b;
 +
 +      p = x->parent;
 +      y = x->right;
 +      b = y->left;
 +
 +      x->right = b;
 +      if (b != NULL)
 +              b->parent = x;
 +
 +      x->parent = y;
 +      y->left = x;
 +
 +      y->parent = p;
 +      assert ((p == NULL) || (p->left == x) || (p->right == x));
 +      if (p == NULL)
 +              t->root = y;
 +      else if (p->left == x)
 +              p->left = y;
 +      else
 +              p->right = y;
 +
 +      x->height = calc_height (x);
 +      y->height = calc_height (y);
 +
 +      return (y);
 +} /* void rotate_left */
 +
 +static c_avl_node_t *rotate_left_right (c_avl_tree_t *t, c_avl_node_t *x)
 +{
 +      rotate_left (t, x->left);
 +      return (rotate_right (t, x));
 +} /* void rotate_left_right */
 +
 +static c_avl_node_t *rotate_right_left (c_avl_tree_t *t, c_avl_node_t *x)
 +{
 +      rotate_right (t, x->right);
 +      return (rotate_left (t, x));
 +} /* void rotate_right_left */
 +
 +static void rebalance (c_avl_tree_t *t, c_avl_node_t *n)
 +{
 +      int b_top;
 +      int b_bottom;
 +
 +      while (n != NULL)
 +      {
 +              b_top = BALANCE (n);
 +              assert ((b_top >= -2) && (b_top <= 2));
 +
 +              if (b_top == -2)
 +              {
 +                      assert (n->right != NULL);
 +                      b_bottom = BALANCE (n->right);
 +                      assert ((b_bottom >= -1) || (b_bottom <= 1));
 +                      if (b_bottom == 1)
 +                              n = rotate_right_left (t, n);
 +                      else
 +                              n = rotate_left (t, n);
 +              }
 +              else if (b_top == 2)
 +              {
 +                      assert (n->left != NULL);
 +                      b_bottom = BALANCE (n->left);
 +                      assert ((b_bottom >= -1) || (b_bottom <= 1));
 +                      if (b_bottom == -1)
 +                              n = rotate_left_right (t, n);
 +                      else
 +                              n = rotate_right (t, n);
 +              }
 +              else
 +              {
 +                      int height = calc_height (n);
 +                      if (height == n->height)
 +                              break;
 +                      n->height = height;
 +              }
 +
 +              assert (n->height == calc_height (n));
 +
 +              n = n->parent;
 +      } /* while (n != NULL) */
 +} /* void rebalance */
 +
 +static c_avl_node_t *c_avl_node_next (c_avl_node_t *n)
 +{
 +      c_avl_node_t *r; /* return node */
 +
 +      if (n == NULL)
 +      {
 +              return (NULL);
 +      }
 +
 +      /* If we can't descent any further, we have to backtrack to the first
 +       * parent that's bigger than we, i. e. who's _left_ child we are. */
 +      if (n->right == NULL)
 +      {
 +              r = n->parent;
 +              while ((r != NULL) && (r->parent != NULL))
 +              {
 +                      if (r->left == n)
 +                              break;
 +                      n = r;
 +                      r = n->parent;
 +              }
 +
 +              /* n->right == NULL && r == NULL => t is root and has no next
 +               * r->left != n => r->right = n => r->parent == NULL */
 +              if ((r == NULL) || (r->left != n))
 +              {
 +                      assert ((r == NULL) || (r->parent == NULL));
 +                      return (NULL);
 +              }
 +              else
 +              {
 +                      assert (r->left == n);
 +                      return (r);
 +              }
 +      }
 +      else
 +      {
 +              r = n->right;
 +              while (r->left != NULL)
 +                      r = r->left;
 +      }
 +
 +      return (r);
 +} /* c_avl_node_t *c_avl_node_next */
 +
 +static c_avl_node_t *c_avl_node_prev (c_avl_node_t *n)
 +{
 +      c_avl_node_t *r; /* return node */
 +
 +      if (n == NULL)
 +      {
 +              return (NULL);
 +      }
 +
 +      /* If we can't descent any further, we have to backtrack to the first
 +       * parent that's smaller than we, i. e. who's _right_ child we are. */
 +      if (n->left == NULL)
 +      {
 +              r = n->parent;
 +              while ((r != NULL) && (r->parent != NULL))
 +              {
 +                      if (r->right == n)
 +                              break;
 +                      n = r;
 +                      r = n->parent;
 +              }
 +
 +              /* n->left == NULL && r == NULL => t is root and has no next
 +               * r->right != n => r->left = n => r->parent == NULL */
 +              if ((r == NULL) || (r->right != n))
 +              {
 +                      assert ((r == NULL) || (r->parent == NULL));
 +                      return (NULL);
 +              }
 +              else
 +              {
 +                      assert (r->right == n);
 +                      return (r);
 +              }
 +      }
 +      else
 +      {
 +              r = n->left;
 +              while (r->right != NULL)
 +                      r = r->right;
 +      }
 +
 +      return (r);
 +} /* c_avl_node_t *c_avl_node_prev */
 +
 +static int _remove (c_avl_tree_t *t, c_avl_node_t *n)
 +{
 +      assert ((t != NULL) && (n != NULL));
 +
 +      if ((n->left != NULL) && (n->right != NULL))
 +      {
 +              c_avl_node_t *r; /* replacement node */
 +              if (BALANCE (n) > 0) /* left subtree is higher */
 +              {
 +                      assert (n->left != NULL);
 +                      r = c_avl_node_prev (n);
 +                      
 +              }
 +              else /* right subtree is higher */
 +              {
 +                      assert (n->right != NULL);
 +                      r = c_avl_node_next (n);
 +              }
 +
 +              assert ((r->left == NULL) || (r->right == NULL));
 +
 +              /* copy content */
 +              n->key   = r->key;
 +              n->value = r->value;
 +
 +              n = r;
 +      }
 +
 +      assert ((n->left == NULL) || (n->right == NULL));
 +
 +      if ((n->left == NULL) && (n->right == NULL))
 +      {
 +              /* Deleting a leave is easy */
 +              if (n->parent == NULL)
 +              {
 +                      assert (t->root == n);
 +                      t->root = NULL;
 +              }
 +              else
 +              {
 +                      assert ((n->parent->left == n)
 +                                      || (n->parent->right == n));
 +                      if (n->parent->left == n)
 +                              n->parent->left = NULL;
 +                      else
 +                              n->parent->right = NULL;
 +
 +                      rebalance (t, n->parent);
 +              }
 +
 +              free_node (n);
 +      }
 +      else if (n->left == NULL)
 +      {
 +              assert (BALANCE (n) == -1);
 +              assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
 +              if (n->parent == NULL)
 +              {
 +                      assert (t->root == n);
 +                      t->root = n->right;
 +              }
 +              else if (n->parent->left == n)
 +              {
 +                      n->parent->left = n->right;
 +              }
 +              else
 +              {
 +                      n->parent->right = n->right;
 +              }
 +              n->right->parent = n->parent;
 +
 +              if (n->parent != NULL)
 +                      rebalance (t, n->parent);
 +
 +              n->right = NULL;
 +              free_node (n);
 +      }
 +      else if (n->right == NULL)
 +      {
 +              assert (BALANCE (n) == 1);
 +              assert ((n->parent == NULL) || (n->parent->left == n) || (n->parent->right == n));
 +              if (n->parent == NULL)
 +              {
 +                      assert (t->root == n);
 +                      t->root = n->left;
 +              }
 +              else if (n->parent->left == n)
 +              {
 +                      n->parent->left = n->left;
 +              }
 +              else
 +              {
 +                      n->parent->right = n->left;
 +              }
 +              n->left->parent = n->parent;
 +
 +              if (n->parent != NULL)
 +                      rebalance (t, n->parent);
 +
 +              n->left = NULL;
 +              free_node (n);
 +      }
 +      else
 +      {
 +              assert (0);
 +      }
 +
 +      return (0);
 +} /* void *_remove */
 +
 +/*
 + * public functions
 + */
 +c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *))
 +{
 +      c_avl_tree_t *t;
 +
 +      if (compare == NULL)
 +              return (NULL);
 +
 +      if ((t = (c_avl_tree_t *) malloc (sizeof (c_avl_tree_t))) == NULL)
 +              return (NULL);
 +
 +      t->root = NULL;
 +      t->compare = compare;
 +      t->size = 0;
 +
 +      return (t);
 +}
 +
 +void c_avl_destroy (c_avl_tree_t *t)
 +{
 +      if (t == NULL)
 +              return;
 +      free_node (t->root);
 +      free (t);
 +}
 +
 +int c_avl_insert (c_avl_tree_t *t, void *key, void *value)
 +{
 +      c_avl_node_t *new;
 +      c_avl_node_t *nptr;
 +      int cmp;
 +
 +      if ((new = (c_avl_node_t *) malloc (sizeof (c_avl_node_t))) == NULL)
 +              return (-1);
 +
 +      new->key = key;
 +      new->value = value;
 +      new->height = 1;
 +      new->left = NULL;
 +      new->right = NULL;
 +
 +      if (t->root == NULL)
 +      {
 +              new->parent = NULL;
 +              t->root = new;
 +              t->size = 1;
 +              return (0);
 +      }
 +
 +      nptr = t->root;
 +      while (42)
 +      {
 +              cmp = t->compare (nptr->key, new->key);
 +              if (cmp == 0)
 +              {
 +                      free_node (new);
 +                      return (1);
 +              }
 +              else if (cmp < 0)
 +              {
 +                      /* nptr < new */
 +                      if (nptr->right == NULL)
 +                      {
 +                              nptr->right = new;
 +                              new->parent = nptr;
 +                              rebalance (t, nptr);
 +                              break;
 +                      }
 +                      else
 +                      {
 +                              nptr = nptr->right;
 +                      }
 +              }
 +              else /* if (cmp > 0) */
 +              {
 +                      /* nptr > new */
 +                      if (nptr->left == NULL)
 +                      {
 +                              nptr->left = new;
 +                              new->parent = nptr;
 +                              rebalance (t, nptr);
 +                              break;
 +                      }
 +                      else
 +                      {
 +                              nptr = nptr->left;
 +                      }
 +              }
 +      } /* while (42) */
 +
 +      verify_tree (t->root);
 +      ++t->size;
 +      return (0);
 +} /* int c_avl_insert */
 +
 +int c_avl_remove (c_avl_tree_t *t, const void *key, void **rkey, void **rvalue)
 +{
 +      c_avl_node_t *n;
 +      int status;
 +
 +      assert (t != NULL);
 +
 +      n = search (t, key);
 +      if (n == NULL)
 +              return (-1);
 +
 +      if (rkey != NULL)
 +              *rkey = n->key;
 +      if (rvalue != NULL)
 +              *rvalue = n->value;
 +
 +      status = _remove (t, n);
 +      verify_tree (t->root);
 +      --t->size;
 +      return (status);
 +} /* void *c_avl_remove */
 +
 +int c_avl_get (c_avl_tree_t *t, const void *key, void **value)
 +{
 +      c_avl_node_t *n;
 +
 +      assert (t != NULL);
 +
 +      n = search (t, key);
 +      if (n == NULL)
 +              return (-1);
 +
 +      if (value != NULL)
 +              *value = n->value;
 +
 +      return (0);
 +}
 +
 +int c_avl_pick (c_avl_tree_t *t, void **key, void **value)
 +{
 +      c_avl_node_t *n;
 +      c_avl_node_t *p;
 +
 +      if ((key == NULL) || (value == NULL))
 +              return (-1);
 +      if (t->root == NULL)
 +              return (-1);
 +
 +      n = t->root;
 +      while ((n->left != NULL) || (n->right != NULL))
 +      {
-               if (height_left > height_right)
++              if (n->left == NULL)
++              {
++                      n = n->right;
++                      continue;
++              }
++              else if (n->right == NULL)
++              {
++                      n = n->left;
++                      continue;
++              }
 +
++              if (n->left->height > n->right->height)
 +                      n = n->left;
 +              else
 +                      n = n->right;
 +      }
 +
 +      p = n->parent;
 +      if (p == NULL)
 +              t->root = NULL;
 +      else if (p->left == n)
 +              p->left = NULL;
 +      else
 +              p->right = NULL;
 +
 +      *key   = n->key;
 +      *value = n->value;
 +
 +      free_node (n);
 +      rebalance (t, p);
 +
 +      return (0);
 +} /* int c_avl_pick */
 +
 +c_avl_iterator_t *c_avl_get_iterator (c_avl_tree_t *t)
 +{
 +      c_avl_iterator_t *iter;
 +
 +      if (t == NULL)
 +              return (NULL);
 +
 +      iter = (c_avl_iterator_t *) malloc (sizeof (c_avl_iterator_t));
 +      if (iter == NULL)
 +              return (NULL);
 +      memset (iter, '\0', sizeof (c_avl_iterator_t));
 +      iter->tree = t;
 +
 +      return (iter);
 +} /* c_avl_iterator_t *c_avl_get_iterator */
 +
 +int c_avl_iterator_next (c_avl_iterator_t *iter, void **key, void **value)
 +{
 +      c_avl_node_t *n;
 +
 +      if ((iter == NULL) || (key == NULL) || (value == NULL))
 +              return (-1);
 +
 +      if (iter->node == NULL)
 +      {
 +              for (n = iter->tree->root; n != NULL; n = n->left)
 +                      if (n->left == NULL)
 +                              break;
 +              iter->node = n;
 +      }
 +      else
 +      {
 +              n = c_avl_node_next (iter->node);
 +      }
 +
 +      if (n == NULL)
 +              return (-1);
 +
 +      iter->node = n;
 +      *key = n->key;
 +      *value = n->value;
 +
 +      return (0);
 +} /* int c_avl_iterator_next */
 +
 +int c_avl_iterator_prev (c_avl_iterator_t *iter, void **key, void **value)
 +{
 +      c_avl_node_t *n;
 +
 +      if ((iter == NULL) || (key == NULL) || (value == NULL))
 +              return (-1);
 +
 +      if (iter->node == NULL)
 +      {
 +              for (n = iter->tree->root; n != NULL; n = n->left)
 +                      if (n->right == NULL)
 +                              break;
 +              iter->node = n;
 +      }
 +      else
 +      {
 +              n = c_avl_node_prev (iter->node);
 +      }
 +
 +      if (n == NULL)
 +              return (-1);
 +
 +      iter->node = n;
 +      *key = n->key;
 +      *value = n->value;
 +
 +      return (0);
 +} /* int c_avl_iterator_prev */
 +
 +void c_avl_iterator_destroy (c_avl_iterator_t *iter)
 +{
 +      free (iter);
 +}
 +
 +int c_avl_size (c_avl_tree_t *t)
 +{
 +      if (t == NULL)
 +              return (0);
 +      return (t->size);
 +}
diff --combined src/daemon/utils_llist.c
index 09c9834,0000000..4265286
mode 100644,000000..100644
--- /dev/null
@@@ -1,190 -1,0 +1,193 @@@
 +/**
 + * collectd - src/utils_llist.c
 + * Copyright (C) 2006       Florian Forster <octo at collectd.org>
 + *
 + * 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 Forster <octo at collectd.org>
 + */
 +
 +#include "config.h"
 +
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#include "utils_llist.h"
 +
 +/*
 + * Private data types
 + */
 +struct llist_s
 +{
 +      llentry_t *head;
 +      llentry_t *tail;
 +      int size;
 +};
 +
 +/*
 + * Public functions
 + */
 +llist_t *llist_create (void)
 +{
 +      llist_t *ret;
 +
 +      ret = (llist_t *) malloc (sizeof (llist_t));
 +      if (ret == NULL)
 +              return (NULL);
 +
 +      memset (ret, '\0', sizeof (llist_t));
 +
 +      return (ret);
 +}
 +
 +void llist_destroy (llist_t *l)
 +{
 +      llentry_t *e_this;
 +      llentry_t *e_next;
 +
 +      if (l == NULL)
 +              return;
 +
 +      for (e_this = l->head; e_this != NULL; e_this = e_next)
 +      {
 +              e_next = e_this->next;
 +              llentry_destroy (e_this);
 +      }
 +
 +      free (l);
 +}
 +
 +llentry_t *llentry_create (char *key, void *value)
 +{
 +      llentry_t *e;
 +
 +      e = (llentry_t *) malloc (sizeof (llentry_t));
 +      if (e)
 +      {
 +              e->key   = key;
 +              e->value = value;
 +              e->next  = NULL;
 +      }
 +
 +      return (e);
 +}
 +
 +void llentry_destroy (llentry_t *e)
 +{
 +      free (e);
 +}
 +
 +void llist_append (llist_t *l, llentry_t *e)
 +{
 +      e->next = NULL;
 +
 +      if (l->tail == NULL)
 +              l->head = e;
 +      else
 +              l->tail->next = e;
 +
 +      l->tail = e;
 +
 +      ++(l->size);
 +}
 +
 +void llist_prepend (llist_t *l, llentry_t *e)
 +{
 +      e->next = l->head;
 +      l->head = e;
 +
 +      if (l->tail == NULL)
 +              l->tail = e;
 +
 +      ++(l->size);
 +}
 +
 +void llist_remove (llist_t *l, llentry_t *e)
 +{
 +      llentry_t *prev;
 +
++      if ((l == NULL) || (e == NULL))
++              return;
++
 +      prev = l->head;
 +      while ((prev != NULL) && (prev->next != e))
 +              prev = prev->next;
 +
 +      if (prev != NULL)
 +              prev->next = e->next;
 +      if (l->head == e)
 +              l->head = e->next;
 +      if (l->tail == e)
 +              l->tail = prev;
 +
 +      --(l->size);
 +}
 +
 +int llist_size (llist_t *l)
 +{
 +      return (l ? l->size : 0);
 +}
 +
 +static int llist_strcmp (llentry_t *e, void *ud)
 +{
 +      if ((e == NULL) || (ud == NULL))
 +              return (-1);
 +      return (strcmp (e->key, (const char *)ud));
 +}
 +
 +llentry_t *llist_search (llist_t *l, const char *key)
 +{
 +      return (llist_search_custom (l, llist_strcmp, (void *)key));
 +}
 +
 +llentry_t *llist_search_custom (llist_t *l,
 +              int (*compare) (llentry_t *, void *), void *user_data)
 +{
 +      llentry_t *e;
 +
 +      if (l == NULL)
 +              return (NULL);
 +
 +      e = l->head;
 +      while (e != NULL) {
 +              llentry_t *next = e->next;
 +
 +              if (compare (e, user_data) == 0)
 +                      break;
 +
 +              e = next;
 +      }
 +
 +      return (e);
 +}
 +
 +llentry_t *llist_head (llist_t *l)
 +{
 +      if (l == NULL)
 +              return (NULL);
 +      return (l->head);
 +}
 +
 +llentry_t *llist_tail (llist_t *l)
 +{
 +      if (l == NULL)
 +              return (NULL);
 +      return (l->tail);
 +}
diff --combined src/liboconfig/oconfig.c
@@@ -1,28 -1,20 +1,28 @@@
  /**
 - * oconfig - src/oconfig.c
 - * Copyright (C) 2006,2007  Florian octo Forster <octo at verplant.org>
 + * collectd - src/liboconfig/oconfig.c
 + * Copyright (C) 2006,2007  Florian Forster
   *
 - * 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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 - */
 + * 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 Forster <octo at collectd.org>
 + **/
  
  #include <stdlib.h>
  #include <stdio.h>
@@@ -33,6 -25,7 +33,7 @@@
  #include "oconfig.h"
  
  extern FILE *yyin;
+ extern int yyparse (void);
  
  oconfig_item_t *ci_root;
  const char     *c_file;
diff --combined src/liboconfig/scanner.l
@@@ -1,32 -1,29 +1,38 @@@
  /**
 - * oconfig - src/scanner.l
 - * Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
 - * Copyright (C) 2008  Sebastian tokkee Harl <sh at tokkee.org>
 + * collectd - src/liboconfig/scanner.l
 + * Copyright (C) 2007  Florian Forster
 + * Copyright (C) 2008  Sebastian Harl
   *
 - * 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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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 Forster <octo at collectd.org>
 + *   Sebastian Harl <sh at tokkee.org>
   */
  
  %{
+ /* lex and yacc do some weird stuff, so turn off some warnings. */
+ #if defined(__clang__)
+ # pragma clang diagnostic ignored "-Wunused-function"
+ # pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
+ #endif
  #include <stdlib.h>
  #include "oconfig.h"
  #include "aux_types.h"
@@@ -65,20 -62,9 +71,20 @@@ BOOL_TRUE (true|yes|on
  BOOL_FALSE (false|no|off)
  COMMENT #.*
  PORT (6(5(5(3[0-5]|[0-2][0-9])|[0-4][0-9][0-9])|[0-4][0-9][0-9][0-9])|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9]?[0-9]?[0-9]?)
 +
  IP_BYTE (2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])
  IPV4_ADDR {IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}\.{IP_BYTE}(:{PORT})?
  
 +/* IPv6 address according to http://www.ietf.org/rfc/rfc2373.txt
 + * This supports embedded IPv4 addresses as well but does not strictly check
 + * for the right prefix (::0:<v4> or ::FFFF:<v4>) because there are too many
 + * ways to correctly represent the zero bytes. It's up to the user to check
 + * for valid addresses. */
 +HEX16 ([0-9A-Fa-f]{1,4})
 +V6_PART ({HEX16}:{HEX16}|{IPV4_ADDR})
 +IPV6_BASE ({HEX16}:){6}{V6_PART}|::({HEX16}:){5}{V6_PART}|({HEX16})?::({HEX16}:){4}{V6_PART}|(({HEX16}:){0,1}{HEX16})?::({HEX16}:){3}{V6_PART}|(({HEX16}:){0,2}{HEX16})?::({HEX16}:){2}{V6_PART}|(({HEX16}:){0,3}{HEX16})?::{HEX16}:{V6_PART}|(({HEX16}:){0,4}{HEX16})?::{V6_PART}|(({HEX16}:){0,5}{HEX16})?::{HEX16}|(({HEX16}:){0,6}{HEX16})?::
 +IPV6_ADDR ({IPV6_BASE})|(\[{IPV6_BASE}\](:{PORT})?)
 +
  %%
  {WHITE_SPACE}         |
  {COMMENT}             {/* ignore */}
@@@ -93,7 -79,6 +99,7 @@@
  {BOOL_FALSE}          {yylval.boolean = 0; return (BFALSE);}
  
  {IPV4_ADDR}           {yylval.string = yytext; return (UNQUOTED_STRING);}
 +{IPV6_ADDR}           {yylval.string = yytext; return (UNQUOTED_STRING);}
  
  {NUMBER}              {yylval.number = strtod (yytext, NULL); return (NUMBER);}
  
diff --combined src/network.c
@@@ -22,7 -22,6 +22,7 @@@
   *   Aman Gupta <aman at tmm1.net>
   **/
  
 +#define _DEFAULT_SOURCE
  #define _BSD_SOURCE /* For struct ip_mreq */
  
  #include "collectd.h"
@@@ -120,8 -119,6 +120,8 @@@ struct sockent_clien
        gcry_cipher_hd_t cypher;
        unsigned char password_hash[32];
  #endif
 +      cdtime_t next_resolve_reconnect;
 +      cdtime_t resolve_interval;
  };
  
  struct sockent_server
@@@ -924,19 -921,15 +924,19 @@@ static int parse_part_number (void **re
  } /* int parse_part_number */
  
  static int parse_part_string (void **ret_buffer, size_t *ret_buffer_len,
 -              char *output, int output_len)
 +              char *output, size_t const output_len)
  {
        char *buffer = *ret_buffer;
        size_t buffer_len = *ret_buffer_len;
  
        uint16_t tmp16;
 -      size_t header_size = 2 * sizeof (uint16_t);
 +      size_t const header_size = 2 * sizeof (uint16_t);
  
        uint16_t pkg_length;
 +      size_t payload_size;
 +
 +      if (output_len <= 0)
 +              return (EINVAL);
  
        if (buffer_len < header_size)
        {
        memcpy ((void *) &tmp16, buffer, sizeof (tmp16));
        buffer += sizeof (tmp16);
        pkg_length = ntohs (tmp16);
 +      payload_size = ((size_t) pkg_length) - header_size;
  
        /* Check that packet fits in the input buffer */
        if (pkg_length > buffer_len)
        /* Check that the package data fits into the output buffer.
         * The previous if-statement ensures that:
         * `pkg_length > header_size' */
 -      if ((output_len < 0)
 -                      || ((size_t) output_len < ((size_t) pkg_length - header_size)))
 +      if (output_len < payload_size)
        {
                WARNING ("network plugin: parse_part_string: "
 -                              "Output buffer too small.");
 +                              "Buffer too small: "
 +                              "Output buffer holds %zu bytes, "
 +                              "which is too small to hold the received "
 +                              "%zu byte string.",
 +                              output_len, payload_size);
                return (-1);
        }
  
        /* All sanity checks successfull, let's copy the data over */
 -      output_len = pkg_length - header_size;
 -      memcpy ((void *) output, (void *) buffer, output_len);
 -      buffer += output_len;
 +      memcpy ((void *) output, (void *) buffer, payload_size);
 +      buffer += payload_size;
  
        /* For some very weird reason '\0' doesn't do the trick on SPARC in
         * this statement. */
 -      if (output[output_len - 1] != 0)
 +      if (output[payload_size - 1] != 0)
        {
                WARNING ("network plugin: parse_part_string: "
                                "Received string does not end "
@@@ -2027,6 -2017,7 +2027,7 @@@ static sockent_t *sockent_create (int t
        if (type == SOCKENT_TYPE_SERVER)
        {
                se->data.server.fd = NULL;
+               se->data.server.fd_num = 0;
  #if HAVE_LIBGCRYPT
                se->data.server.security_level = SECURITY_LEVEL_NONE;
                se->data.server.auth_file = NULL;
        {
                se->data.client.fd = -1;
                se->data.client.addr = NULL;
 +              se->data.client.resolve_interval = 0;
 +              se->data.client.next_resolve_reconnect = 0;
  #if HAVE_LIBGCRYPT
                se->data.client.security_level = SECURITY_LEVEL_NONE;
                se->data.client.username = NULL;
@@@ -2106,26 -2095,6 +2107,26 @@@ static int sockent_init_crypto (sockent
        return (0);
  } /* }}} int sockent_init_crypto */
  
 +static int sockent_client_disconnect (sockent_t *se) /* {{{ */
 +{
 +      struct sockent_client *client;
 +
 +      if ((se == NULL) || (se->type != SOCKENT_TYPE_CLIENT))
 +              return (EINVAL);
 +
 +      client = &se->data.client;
 +      if (client->fd >= 0) /* connected */
 +      {
 +              close (client->fd);
 +              client->fd = -1;
 +      }
 +
 +      sfree (client->addr);
 +      client->addrlen = 0;
 +
 +      return (0);
 +} /* }}} int sockent_client_disconnect */
 +
  static int sockent_client_connect (sockent_t *se) /* {{{ */
  {
        static c_complain_t complaint = C_COMPLAIN_INIT_STATIC;
        struct addrinfo  ai_hints;
        struct addrinfo *ai_list = NULL, *ai_ptr;
        int status;
 +      _Bool reconnect = 0;
 +      cdtime_t now;
  
        if ((se == NULL) || (se->type != SOCKENT_TYPE_CLIENT))
                return (EINVAL);
  
        client = &se->data.client;
 -      if (client->fd >= 0) /* already connected */
 +
 +      now = cdtime ();
 +      if (client->resolve_interval != 0 && client->next_resolve_reconnect < now) {
 +              DEBUG("network plugin: Reconnecting socket, resolve_interval = %lf, next_resolve_reconnect = %lf",
 +                      CDTIME_T_TO_DOUBLE(client->resolve_interval), CDTIME_T_TO_DOUBLE(client->next_resolve_reconnect));
 +              reconnect = 1;
 +      }
 +
 +      if (client->fd >= 0 && !reconnect) /* already connected and not stale*/
                return (0);
  
        memset (&ai_hints, 0, sizeof (ai_hints));
  
        for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
        {
 +              if (client->fd >= 0) /* when we reconnect */
 +                      sockent_client_disconnect(se);
 +
                client->fd = socket (ai_ptr->ai_family,
                                ai_ptr->ai_socktype,
                                ai_ptr->ai_protocol);
        freeaddrinfo (ai_list);
        if (client->fd < 0)
                return (-1);
 -      return (0);
 -} /* }}} int sockent_client_connect */
 -
 -static int sockent_client_disconnect (sockent_t *se) /* {{{ */
 -{
 -      struct sockent_client *client;
 -
 -      if ((se == NULL) || (se->type != SOCKENT_TYPE_CLIENT))
 -              return (EINVAL);
 -
 -      client = &se->data.client;
 -      if (client->fd >= 0) /* connected */
 -      {
 -              close (client->fd);
 -              client->fd = -1;
 -      }
 -
 -      sfree (client->addr);
 -      client->addrlen = 0;
  
 +      if (client->resolve_interval > 0)
 +              client->next_resolve_reconnect = now + client->resolve_interval;
        return (0);
 -} /* }}} int sockent_client_disconnect */
 +} /* }}} int sockent_client_connect */
  
  /* Open the file descriptors for a initialized sockent structure. */
  static int sockent_server_listen (sockent_t *se) /* {{{ */
        if (se == NULL)
                return (-1);
  
+       assert (se->data.server.fd == NULL);
+       assert (se->data.server.fd_num == 0);
          node = se->node;
          service = se->service;
  
@@@ -3007,7 -2983,7 +3011,7 @@@ static int network_config_set_ttl (cons
      network_config_ttl = tmp;
    else {
      WARNING ("network plugin: The `TimeToLive' must be between 1 and 255.");
 -    return (-1);    
 +    return (-1);
    }
  
    return (0);
@@@ -3234,8 -3210,6 +3238,8 @@@ static int network_config_add_server (c
      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);
      else
      {
        WARNING ("network plugin: Option `%s' is not allowed here.",
diff --combined src/perl.c
@@@ -2,25 -2,20 +2,25 @@@
   * collectd - src/perl.c
   * Copyright (C) 2007-2009  Sebastian Harl
   *
 - * 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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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.
   *
 - * Author:
 + * Authors:
   *   Sebastian Harl <sh at tokkee.org>
   **/
  
@@@ -46,7 -41,6 +46,7 @@@
  #include <perl.h>
  
  #if defined(COLLECT_DEBUG) && COLLECT_DEBUG && defined(__GNUC__) && __GNUC__
 +# undef sprintf
  # pragma GCC poison sprintf
  #endif
  
@@@ -516,7 -510,6 +516,6 @@@ static int av2notification_meta (pTHX_ 
                if (NULL == (tmp = hv_fetch (hash, "value", 5, 0))) {
                        log_warn ("av2notification_meta: Skipping invalid "
                                        "meta information.");
-                       free ((*m)->name);
                        free (*m);
                        continue;
                }
@@@ -1,27 -1,22 +1,27 @@@
  /**
   * collectd - src/target_notification.c
 - * Copyright (C) 2008  Florian Forster
 + * Copyright (C) 2008       Florian Forster
   *
 - * 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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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 Forster <octo at verplant.org>
 + *   Florian Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -181,7 -176,7 +181,7 @@@ static int tn_create (const oconfig_ite
  
    if (status != 0)
    {
-     tn_destroy ((void *) data);
+     tn_destroy ((void *) &data);
      return (status);
    }
  
diff --combined src/utils_rrdcreate.c
@@@ -2,23 -2,18 +2,23 @@@
   * collectd - src/utils_rrdcreate.c
   * Copyright (C) 2006-2013  Florian octo Forster
   *
 - * 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.
 + * 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:
   *
 - * 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.
 + * The above copyright notice and this permission notice shall be included in
 + * all copies or substantial portions of the Software.
   *
 - * 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
 + * 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>
@@@ -709,18 -704,32 +709,32 @@@ int cu_rrd_create_file (const char *fil
    }
    else /* synchronous */
    {
-     status = srrd_create (filename, stepsize, last_up,
-         argc, (const char **) argv);
+     status = lock_file (filename);
      if (status != 0)
      {
-       WARNING ("cu_rrd_create_file: srrd_create (%s) returned status %i.",
-           filename, status);
+       if (status == EEXIST)
+         NOTICE ("cu_rrd_create_file: File \"%s\" is already being created.",
+             filename);
+       else
+         ERROR ("cu_rrd_create_file: Unable to lock file \"%s\".",
+             filename);
      }
      else
      {
-       DEBUG ("cu_rrd_create_file: Successfully created RRD file \"%s\".",
-           filename);
+       status = srrd_create (filename, stepsize, last_up,
+           argc, (const char **) argv);
+       if (status != 0)
+       {
+         WARNING ("cu_rrd_create_file: srrd_create (%s) returned status %i.",
+             filename, status);
+       }
+       else
+       {
+         DEBUG ("cu_rrd_create_file: Successfully created RRD file \"%s\".",
+             filename);
+       }
+       unlock_file (filename);
      }
    }