Merge branch 'collectd-4.10' into collectd-5.0
authorFlorian Forster <octo@collectd.org>
Sat, 26 Mar 2011 18:01:26 +0000 (11:01 -0700)
committerFlorian Forster <octo@collectd.org>
Sat, 26 Mar 2011 18:01:26 +0000 (11:01 -0700)
Conflicts:
ChangeLog
src/libvirt.c
src/plugin.c
src/plugin.h
version-gen.sh

1  2 
ChangeLog
src/libvirt.c
src/plugin.c
src/plugin.h

diff --combined ChangeLog
+++ b/ChangeLog
@@@ -1,73 -1,21 +1,91 @@@
 +yyyy-mm-dd, Version 5.0.0
 +      * collectd: The "FQDNLookup" option is now enabled by default.
 +      * collectd: The internal representation of time has been changed to
 +        allow a higher accuracy than one second.
 +      * collectdcmd: This new command line utility can send various commands
 +        to collectd using the UnixSock plugin. Thanks to Håkon Dugstad
 +        Johnsen and Sebastian Harl for their code.
 +      * collectd-nagios: The "-m" option has been implemented (treat NaNs as
 +        critical).
 +      * collectd-tg: Traffic generator creating bogus network traffic
 +        compatible to the Network plugin. This utility can be used to
 +        stress-test new write plugins and collectd in general.
 +      * libcollectdclient: Creating and sending network packets has been
 +        added to the collectd client library.
 +      * All data sets: The data source name of all data sets with exactly
 +        one data source has been changed to "value".
 +      * All plugins: All "counter" data sources have been converted to
 +        "derive" data sources. All plugins now use "derive" by default, but
 +        plugins such as the network plugin can still handle "counter", of
 +        course. The minimum value of all derive data sources is zero, the
 +        maximum value is unspecified.
 +      * amqp plugin: The new AMQP plugin can send data to and receive data
 +        from an AMQP broker. Thanks to Sebastien Pahl for his code.
 +      * apache plugin: Backwards compatibility code has been removed.
 +        Support for the IBM HTTP Server has been added. Thanks to Manuel
 +        Luis Sanmartín Rozada for his patch.
 +      * contextswitch plugin: Support for sysctlbyname(3) has been added.
 +        Thanks to Kimo Rosenbaum for his patch.
 +      * df plugin: The default behavior has been changed to be equivalent to
 +        the "ReportReserved" behavior of v4.
 +      * dns plugin: Improved RFC 1035 name parsing has been imported from
 +        "dnstop".
 +      * exec plugin: Backwards compatibility code has been removed.
 +      * GenericJMX plugin: The "InstancePrefix" option has been added to
 +        "Connection" blocks.
 +      * hddtemp plugin: The "TranslateDevicename" config option has been
 +        removed.
 +      * interface plugin: Use the "plugin instance" to store the interface
 +        value.
 +      * libvirt plugin: The "InterfaceFormat" option has been added. Thanks
 +        to Ruben Kerkhof for his patch.
 +      * lpar plugin: New plugins for "logical partitions", a virtualization
 +        technique of POWER CPUs. Thanks to Aurélien Reynaud for his code and
 +        patience.
 +      * modbus plugin: Support for libmodbus 2.9.2 has been added and the
 +        license has been changes to LGPLv2.1.
 +      * mysql plugin: Backwards compatibility code has been removed. The
 +        data sets used have been improved.
 +      * network plugin: The default buffer size has been increased to
 +        1452 bytes.
 +      * perl plugin: Backwards compatibility code has been removed.
 +      * postgresql plugin: Backwards compatibility code has been removed.
 +      * redis plugin: Plugin for collecting statistics from Redis, a key-
 +        value store, has been added. Thanks to Andres J. Diaz for his code.
 +      * swap plugin: Implement collection of physical and virtual memory
 +        statistics under Solaris. The new default is collecting physical
 +        memory. Thanks to Aurélien Reynaud for his patches.
 +      * threshold plugin: The threshold configuration has been moved into
 +        this separate plugin.
 +      * unixsock plugin: The "DeleteSocket" option has been added.
 +      * varnish plugin: The new Varnish plugin reads statistics from
 +        Varnish, a web accelerator. Thanks to Jérôme Renard and Marc
 +        Fournier for their contributions.
 +      * write_redis: New plugin for writing data to Redis, a key-value
 +        store.
 +      * zfs_arc plugin: The data sets have been replaced by more elegant
 +        alternatives.
 +      * v5upgrade target: Target for converting v4 data sets to the v5
 +        schema.
 +
+ 2011-03-26, Version 4.10.3
+       * Documentation: Several updates and additions. Thanks to Sebastian Harl.
+       * collectd: Build issues (compiler warnings) have been fixed. Thanks to
+         Bruno Prémont.
+       * collectd: Threshold subsection: Handling of NAN values in the
+         percentage calculation has been fixed.
+       * collectd, java plugin, ntpd plugin: Several diagnostic messages have
+         been improved.
+       * curl_json plugin: Handling of arrays has been fixed.
+       * libvirt plugin: A bug in reading the virtual CPU statistics has been
+         fixed. Thanks to “JLPC” for reporting this problem.
+       * modbus plugin: Compatibility with libmodbus 2.0.3 has been restored.
+       * processes plugin: Potentially erroneous behavior has been fixed in an
+         error handling case.
+       * python plugin: Fix dispatching of values from Python scripts to
+         collectd. Thanks to Gregory Szorc for finding and fixing this
+         problem.
  2010-11-27, Version 4.10.2
        * Documentation: Various documentation fixes.
        * collectd: If including one configuration file fails, continue with
        * regex match: The "Invert" option has been added. Thanks to Julien
          Ammous for his patch.
  
+ 2011-03-26, Version 4.9.5
+       * Documentation: Several updates and additions. Thanks to Sebastian Harl.
+       * collectd: Build issues (compiler warnings) have been fixed. Thanks to
+         Bruno Prémont.
+       * collectd: Threshold subsection: Handling of NAN values in the
+         percentage calculation has been fixed.
+       * collectd, java plugin, ntpd plugin: Several diagnostic messages have
+         been improved.
+       * libvirt plugin: A bug in reading the virtual CPU statistics has been
+         fixed. Thanks to “JLPC” for reporting this problem.
+       * processes plugin: Potentially erroneous behavior has been fixed in an
+         error handling case.
+       * python plugin: Fix dispatching of values from Python scripts to
+         collectd. Thanks to Gregory Szorc for finding and fixing this
+         problem.
  2010-11-27, Version 4.9.4
        * Documentation: Various documentation fixes.
        * collectd: If including one configuration file fails, continue with
diff --combined src/libvirt.c
@@@ -43,7 -43,6 +43,7 @@@ static const char *config_keys[] = 
      "IgnoreSelected",
  
      "HostnameFormat",
 +    "InterfaceFormat",
  
      NULL
  };
@@@ -90,14 -89,13 +90,14 @@@ static int add_block_device (virDomainP
  struct interface_device {
      virDomainPtr dom;           /* domain */
      char *path;                 /* name of interface device */
 +    char *address;              /* mac address of interface device */
  };
  
  static struct interface_device *interface_devices = NULL;
  static int nr_interface_devices = 0;
  
  static void free_interface_devices (void);
 -static int add_interface_device (virDomainPtr dom, const char *path);
 +static int add_interface_device (virDomainPtr dom, const char *path, const char *address);
  
  /* HostnameFormat. */
  #define HF_MAX_FIELDS 3
@@@ -112,19 -110,22 +112,19 @@@ enum hf_field 
  static enum hf_field hostname_format[HF_MAX_FIELDS] =
      { hf_name };
  
 +/* InterfaceFormat. */
 +enum if_field {
 +    if_address,
 +    if_name
 +};
 +
 +static enum if_field interface_format = if_name;
 +
  /* Time that we last refreshed. */
  static time_t last_refresh = (time_t) 0;
  
  static int refresh_lists (void);
  
 -/* Submit functions. */
 -static void cpu_submit (unsigned long long cpu_time,
 -                        time_t t,
 -                        virDomainPtr dom, const char *type);
 -static void vcpu_submit (unsigned long long cpu_time,
 -                         time_t t,
 -                         virDomainPtr dom, int vcpu_nr, const char *type);
 -static void submit_counter2 (const char *type, counter_t v0, counter_t v1,
 -             time_t t,
 -             virDomainPtr dom, const char *devname);
 -
  /* ERROR(...) macro for virterrors. */
  #define VIRT_ERROR(conn,s) do {                 \
          virErrorPtr err;                        \
          if (err) ERROR ("%s: %s", (s), err->message);                   \
      } while(0)
  
 +static void
 +init_value_list (value_list_t *vl, virDomainPtr dom)
 +{
 +    int i, n;
 +    const char *name;
 +    char uuid[VIR_UUID_STRING_BUFLEN];
 +    char  *host_ptr;
 +    size_t host_len;
 +
 +    vl->interval = interval_g;
 +
 +    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
 +
 +    vl->host[0] = '\0';
 +    host_ptr = vl->host;
 +    host_len = sizeof (vl->host);
 +
 +    /* Construct the hostname field according to HostnameFormat. */
 +    for (i = 0; i < HF_MAX_FIELDS; ++i) {
 +        if (hostname_format[i] == hf_none)
 +            continue;
 +
 +        n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
 +
 +        if (i > 0 && n >= 1) {
 +            strncat (vl->host, ":", 1);
 +            n--;
 +        }
 +
 +        switch (hostname_format[i]) {
 +        case hf_none: break;
 +        case hf_hostname:
 +            strncat (vl->host, hostname_g, n);
 +            break;
 +        case hf_name:
 +            name = virDomainGetName (dom);
 +            if (name)
 +                strncat (vl->host, name, n);
 +            break;
 +        case hf_uuid:
 +            if (virDomainGetUUIDString (dom, uuid) == 0)
 +                strncat (vl->host, uuid, n);
 +            break;
 +        }
 +    }
 +
 +    vl->host[sizeof (vl->host) - 1] = '\0';
 +} /* void init_value_list */
 +
 +static void
 +cpu_submit (unsigned long long cpu_time,
 +            virDomainPtr dom, const char *type)
 +{
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = cpu_time;
 +
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +vcpu_submit (derive_t cpu_time,
 +             virDomainPtr dom, int vcpu_nr, const char *type)
 +{
 +    value_t values[1];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = cpu_time;
 +    vl.values = values;
 +    vl.values_len = 1;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
 +
 +    plugin_dispatch_values (&vl);
 +}
 +
 +static void
 +submit_derive2 (const char *type, derive_t v0, derive_t v1,
 +             virDomainPtr dom, const char *devname)
 +{
 +    value_t values[2];
 +    value_list_t vl = VALUE_LIST_INIT;
 +
 +    init_value_list (&vl, dom);
 +
 +    values[0].derive = v0;
 +    values[1].derive = v1;
 +    vl.values = values;
 +    vl.values_len = 2;
 +
 +    sstrncpy (vl.type, type, sizeof (vl.type));
 +    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
 +
 +    plugin_dispatch_values (&vl);
 +} /* void submit_derive2 */
 +
  static int
  lv_init (void)
  {
@@@ -321,7 -215,7 +321,7 @@@ lv_config (const char *key, const char 
  
          n = strsplit (value_copy, fields, HF_MAX_FIELDS);
          if (n < 1) {
 -            free (value_copy);
 +            sfree (value_copy);
              ERROR ("HostnameFormat: no fields");
              return -1;
          }
              else if (strcasecmp (fields[i], "uuid") == 0)
                  hostname_format[i] = hf_uuid;
              else {
 -                free (value_copy);
 +                sfree (value_copy);
                  ERROR ("unknown HostnameFormat field: %s", fields[i]);
                  return -1;
              }
          }
 -        free (value_copy);
 +        sfree (value_copy);
  
          for (i = n; i < HF_MAX_FIELDS; ++i)
              hostname_format[i] = hf_none;
          return 0;
      }
  
 +    if (strcasecmp (key, "InterfaceFormat") == 0) {
 +        if (strcasecmp (value, "name") == 0)
 +            interface_format = if_name;
 +        else if (strcasecmp (value, "address") == 0)
 +            interface_format = if_address;
 +        else {
 +            ERROR ("unknown InterfaceFormat: %s", value);
 +            return -1;
 +        }
 +        return 0;
 +    }
 +
      /* Unrecognised option. */
      return -1;
  }
@@@ -413,30 -295,40 +413,40 @@@ lv_read (void
      for (i = 0; i < nr_domains; ++i) {
          virDomainInfo info;
          virVcpuInfoPtr vinfo = NULL;
+         int status;
          int j;
  
-         if (virDomainGetInfo (domains[i], &info) != 0)
+         status = virDomainGetInfo (domains[i], &info);
+         if (status != 0)
+         {
+             ERROR ("libvirt plugin: virDomainGetInfo failed with status %i.",
+                     status);
              continue;
+         }
  
 -        cpu_submit (info.cpuTime, t, domains[i], "virt_cpu_total");
 +        cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
  
-         vinfo = malloc (info.nrVirtCpu * sizeof vinfo[0]);
+         vinfo = malloc (info.nrVirtCpu * sizeof (vinfo[0]));
          if (vinfo == NULL) {
              ERROR ("libvirt plugin: malloc failed.");
              continue;
          }
  
-         if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
-                     NULL, 0) != 0) {
-             sfree (vinfo);
+         status = virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
+                 /* cpu map = */ NULL, /* cpu map length = */ 0);
+         if (status < 0)
+         {
+             ERROR ("libvirt plugin: virDomainGetVcpus failed with status %i.",
+                     status);
+             free (vinfo);
              continue;
          }
  
          for (j = 0; j < info.nrVirtCpu; ++j)
              vcpu_submit (vinfo[j].cpuTime,
 -                    t, domains[i], vinfo[j].number, "virt_vcpu");
 +                    domains[i], vinfo[j].number, "virt_vcpu");
  
 -        free (vinfo);
 +        sfree (vinfo);
      }
  
      /* Get block device stats for each domain. */
              continue;
  
          if ((stats.rd_req != -1) && (stats.wr_req != -1))
 -            submit_counter2 ("disk_ops",
 -                    (counter_t) stats.rd_req, (counter_t) stats.wr_req,
 -                    t, block_devices[i].dom, block_devices[i].path);
 +            submit_derive2 ("disk_ops",
 +                    (derive_t) stats.rd_req, (derive_t) stats.wr_req,
 +                    block_devices[i].dom, block_devices[i].path);
  
          if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
 -            submit_counter2 ("disk_octets",
 -                    (counter_t) stats.rd_bytes, (counter_t) stats.wr_bytes,
 -                    t, block_devices[i].dom, block_devices[i].path);
 +            submit_derive2 ("disk_octets",
 +                    (derive_t) stats.rd_bytes, (derive_t) stats.wr_bytes,
 +                    block_devices[i].dom, block_devices[i].path);
      } /* for (nr_block_devices) */
  
      /* Get interface stats for each domain. */
      for (i = 0; i < nr_interface_devices; ++i) {
          struct _virDomainInterfaceStats stats;
 +        char *display_name = interface_devices[i].path;
 +
 +        if (interface_format == if_address)
 +            display_name = interface_devices[i].address;
  
          if (virDomainInterfaceStats (interface_devices[i].dom,
                      interface_devices[i].path,
              continue;
  
        if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
 -          submit_counter2 ("if_octets",
 -                  (counter_t) stats.rx_bytes, (counter_t) stats.tx_bytes,
 -                  t, interface_devices[i].dom, interface_devices[i].path);
 +          submit_derive2 ("if_octets",
 +                  (derive_t) stats.rx_bytes, (derive_t) stats.tx_bytes,
 +                  interface_devices[i].dom, display_name);
  
        if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
 -          submit_counter2 ("if_packets",
 -                  (counter_t) stats.rx_packets, (counter_t) stats.tx_packets,
 -                  t, interface_devices[i].dom, interface_devices[i].path);
 +          submit_derive2 ("if_packets",
 +                  (derive_t) stats.rx_packets, (derive_t) stats.tx_packets,
 +                  interface_devices[i].dom, display_name);
  
        if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
 -          submit_counter2 ("if_errors",
 -                  (counter_t) stats.rx_errs, (counter_t) stats.tx_errs,
 -                  t, interface_devices[i].dom, interface_devices[i].path);
 +          submit_derive2 ("if_errors",
 +                  (derive_t) stats.rx_errs, (derive_t) stats.tx_errs,
 +                  interface_devices[i].dom, display_name);
  
        if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
 -          submit_counter2 ("if_dropped",
 -                  (counter_t) stats.rx_drop, (counter_t) stats.tx_drop,
 -                  t, interface_devices[i].dom, interface_devices[i].path);
 +          submit_derive2 ("if_dropped",
 +                  (derive_t) stats.rx_drop, (derive_t) stats.tx_drop,
 +                  interface_devices[i].dom, display_name);
      } /* for (nr_interface_devices) */
  
      return 0;
@@@ -520,7 -408,7 +530,7 @@@ refresh_lists (void
          n = virConnectListDomains (conn, domids, n);
          if (n < 0) {
              VIRT_ERROR (conn, "reading list of domains");
 -            free (domids);
 +            sfree (domids);
              return -1;
          }
  
  
              /* Network interfaces. */
              xpath_obj = xmlXPathEval
 -                ((xmlChar *) "/domain/devices/interface/target[@dev]",
 +                ((xmlChar *) "/domain/devices/interface[target[@dev]]",
                   xpath_ctx);
              if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
                  xpath_obj->nodesetval == NULL)
                  goto cont;
  
 -            for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
 -                xmlNodePtr node;
 +            xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
 +
 +            for (j = 0; j < xml_interfaces->nodeNr; ++j) {
                  char *path = NULL;
 +                char *address = NULL;
 +                xmlNodePtr xml_interface;
  
 -                node = xpath_obj->nodesetval->nodeTab[j];
 -                if (!node) continue;
 -                path = (char *) xmlGetProp (node, (xmlChar *) "dev");
 -                if (!path) continue;
 +                xml_interface = xml_interfaces->nodeTab[j];
 +                if (!xml_interface) continue;
 +                xmlNodePtr child = NULL;
 +
 +                for (child = xml_interface->children; child; child = child->next) {
 +                    if (child->type != XML_ELEMENT_NODE) continue;
 +
 +                    if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
 +                        path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
 +                        if (!path) continue;
 +                    } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
 +                        address = (char *) xmlGetProp (child, (const xmlChar *) "address");
 +                        if (!address) continue;
 +                    }
 +                }
  
                  if (il_interface_devices &&
 -                    ignore_device_match (il_interface_devices, name, path) != 0)
 +                    (ignore_device_match (il_interface_devices, name, path) != 0 ||
 +                     ignore_device_match (il_interface_devices, name, address) != 0))
                      goto cont3;
  
 -                add_interface_device (dom, path);
 -            cont3:
 -                if (path) xmlFree (path);
 +                add_interface_device (dom, path, address);
 +                cont3:
 +                    if (path) xmlFree (path);
 +                    if (address) xmlFree (address);
              }
  
          cont:
              if (xpath_obj) xmlXPathFreeObject (xpath_obj);
              if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
              if (xml_doc) xmlFreeDoc (xml_doc);
 -            if (xml) free (xml);
 +            sfree (xml);
          }
  
 -        free (domids);
 +        sfree (domids);
      }
  
      return 0;
@@@ -665,7 -537,7 +675,7 @@@ free_domains (
      if (domains) {
          for (i = 0; i < nr_domains; ++i)
              virDomainFree (domains[i]);
 -        free (domains);
 +        sfree (domains);
      }
      domains = NULL;
      nr_domains = 0;
@@@ -697,8 -569,8 +707,8 @@@ free_block_devices (
  
      if (block_devices) {
          for (i = 0; i < nr_block_devices; ++i)
 -            free (block_devices[i].path);
 -        free (block_devices);
 +            sfree (block_devices[i].path);
 +        sfree (block_devices);
      }
      block_devices = NULL;
      nr_block_devices = 0;
@@@ -721,7 -593,7 +731,7 @@@ add_block_device (virDomainPtr dom, con
          new_ptr = malloc (new_size);
  
      if (new_ptr == NULL) {
 -        free (path_copy);
 +        sfree (path_copy);
          return -1;
      }
      block_devices = new_ptr;
@@@ -736,43 -608,36 +746,43 @@@ free_interface_devices (
      int i;
  
      if (interface_devices) {
 -        for (i = 0; i < nr_interface_devices; ++i)
 -            free (interface_devices[i].path);
 -        free (interface_devices);
 +        for (i = 0; i < nr_interface_devices; ++i) {
 +            sfree (interface_devices[i].path);
 +            sfree (interface_devices[i].address);
 +        }
 +        sfree (interface_devices);
      }
      interface_devices = NULL;
      nr_interface_devices = 0;
  }
  
  static int
 -add_interface_device (virDomainPtr dom, const char *path)
 +add_interface_device (virDomainPtr dom, const char *path, const char *address)
  {
      struct interface_device *new_ptr;
      int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
 -    char *path_copy;
 +    char *path_copy, *address_copy;
  
      path_copy = strdup (path);
      if (!path_copy) return -1;
  
 +    address_copy = strdup (address);
 +    if (!address_copy) return -1;
 +
      if (interface_devices)
          new_ptr = realloc (interface_devices, new_size);
      else
          new_ptr = malloc (new_size);
  
      if (new_ptr == NULL) {
 -        free (path_copy);
 +        sfree (path_copy);
 +        sfree (address_copy);
          return -1;
      }
      interface_devices = new_ptr;
      interface_devices[nr_interface_devices].dom = dom;
      interface_devices[nr_interface_devices].path = path_copy;
 +    interface_devices[nr_interface_devices].address = address_copy;
      return nr_interface_devices++;
  }
  
@@@ -790,10 -655,121 +800,10 @@@ ignore_device_match (ignorelist_t *il, 
      }
      ssnprintf (name, n, "%s:%s", domname, devpath);
      r = ignorelist_match (il, name);
 -    free (name);
 +    sfree (name);
      return r;
  }
  
 -static void
 -init_value_list (value_list_t *vl, time_t t, virDomainPtr dom)
 -{
 -    int i, n;
 -    const char *name;
 -    char uuid[VIR_UUID_STRING_BUFLEN];
 -    char  *host_ptr;
 -    size_t host_len;
 -
 -    vl->time = t;
 -    vl->interval = interval_g;
 -
 -    sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
 -
 -    vl->host[0] = '\0';
 -    host_ptr = vl->host;
 -    host_len = sizeof (vl->host);
 -
 -    /* Construct the hostname field according to HostnameFormat. */
 -    for (i = 0; i < HF_MAX_FIELDS; ++i) {
 -        if (hostname_format[i] == hf_none)
 -            continue;
 -
 -        n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
 -
 -        if (i > 0 && n >= 1) {
 -            strncat (vl->host, ":", 1);
 -            n--;
 -        }
 -
 -        switch (hostname_format[i]) {
 -        case hf_none: break;
 -        case hf_hostname:
 -            strncat (vl->host, hostname_g, n);
 -            break;
 -        case hf_name:
 -            name = virDomainGetName (dom);
 -            if (name)
 -                strncat (vl->host, name, n);
 -            break;
 -        case hf_uuid:
 -            if (virDomainGetUUIDString (dom, uuid) == 0)
 -                strncat (vl->host, uuid, n);
 -            break;
 -        }
 -    }
 -
 -    vl->host[sizeof (vl->host) - 1] = '\0';
 -} /* void init_value_list */
 -
 -static void
 -cpu_submit (unsigned long long cpu_time,
 -            time_t t,
 -            virDomainPtr dom, const char *type)
 -{
 -    value_t values[1];
 -    value_list_t vl = VALUE_LIST_INIT;
 -
 -    init_value_list (&vl, t, dom);
 -
 -    values[0].counter = cpu_time;
 -
 -    vl.values = values;
 -    vl.values_len = 1;
 -
 -    sstrncpy (vl.type, type, sizeof (vl.type));
 -
 -    plugin_dispatch_values (&vl);
 -}
 -
 -static void
 -vcpu_submit (counter_t cpu_time,
 -             time_t t,
 -             virDomainPtr dom, int vcpu_nr, const char *type)
 -{
 -    value_t values[1];
 -    value_list_t vl = VALUE_LIST_INIT;
 -
 -    init_value_list (&vl, t, dom);
 -
 -    values[0].counter = cpu_time;
 -    vl.values = values;
 -    vl.values_len = 1;
 -
 -    sstrncpy (vl.type, type, sizeof (vl.type));
 -    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
 -
 -    plugin_dispatch_values (&vl);
 -}
 -
 -static void
 -submit_counter2 (const char *type, counter_t v0, counter_t v1,
 -             time_t t,
 -             virDomainPtr dom, const char *devname)
 -{
 -    value_t values[2];
 -    value_list_t vl = VALUE_LIST_INIT;
 -
 -    init_value_list (&vl, t, dom);
 -
 -    values[0].counter = v0;
 -    values[1].counter = v1;
 -    vl.values = values;
 -    vl.values_len = 2;
 -
 -    sstrncpy (vl.type, type, sizeof (vl.type));
 -    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
 -
 -    plugin_dispatch_values (&vl);
 -} /* void submit_counter2 */
 -
  static int
  lv_shutdown (void)
  {
diff --combined src/plugin.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/plugin.c
 - * Copyright (C) 2005-2009  Florian octo Forster
 + * Copyright (C) 2005-2011  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
@@@ -16,7 -16,7 +16,7 @@@
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Sebastian Harl <sh at tokkee.org>
   **/
  
@@@ -36,6 -36,7 +36,6 @@@
  #include "utils_llist.h"
  #include "utils_heap.h"
  #include "utils_cache.h"
 -#include "utils_threshold.h"
  #include "filter_chain.h"
  
  /*
@@@ -73,7 -74,6 +73,7 @@@ typedef struct read_func_s read_func_t
  static llist_t *list_init;
  static llist_t *list_write;
  static llist_t *list_flush;
 +static llist_t *list_missing;
  static llist_t *list_shutdown;
  static llist_t *list_log;
  static llist_t *list_notification;
@@@ -346,7 -346,7 +346,7 @@@ static void *plugin_read_thread (void _
        while (read_loop != 0)
        {
                read_func_t *rf;
 -              struct timeval now;
 +              cdtime_t now;
                int status;
                int rf_type;
                int rc;
                {
                        struct timespec abstime;
  
 -                      gettimeofday (&now, /* timezone = */ NULL);
 +                      now = cdtime ();
  
 -                      abstime.tv_sec = now.tv_sec + interval_g;
 -                      abstime.tv_nsec = 1000 * now.tv_usec;
 +                      CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime);
  
                        pthread_mutex_lock (&read_lock);
                        pthread_cond_timedwait (&read_cond, &read_lock,
  
                if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0))
                {
 -                      gettimeofday (&now, /* timezone = */ NULL);
 +                      now = cdtime ();
  
 -                      rf->rf_interval.tv_sec = interval_g;
 -                      rf->rf_interval.tv_nsec = 0;
 +                      CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval);
  
                        rf->rf_effective_interval = rf->rf_interval;
  
 -                      rf->rf_next_read.tv_sec = now.tv_sec;
 -                      rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
 +                      CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
  
                /* sleep until this entry is due,
                }
  
                /* update the ``next read due'' field */
 -              gettimeofday (&now, /* timezone = */ NULL);
 +              now = cdtime ();
  
                DEBUG ("plugin_read_thread: Effective interval of the "
                                "%s plugin is %i.%09i.",
                NORMALIZE_TIMESPEC (rf->rf_next_read);
  
                /* Check, if `rf_next_read' is in the past. */
 -              if ((rf->rf_next_read.tv_sec < now.tv_sec)
 -                              || ((rf->rf_next_read.tv_sec == now.tv_sec)
 -                                      && (rf->rf_next_read.tv_nsec < (1000 * now.tv_usec))))
 +              if (TIMESPEC_TO_CDTIME_T (&rf->rf_next_read) < now)
                {
                        /* `rf_next_read' is in the past. Insert `now'
                         * so this value doesn't trail off into the
                         * past too much. */
 -                      rf->rf_next_read.tv_sec = now.tv_sec;
 -                      rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
 +                      CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
                }
  
                DEBUG ("plugin_read_thread: Next read of the %s plugin at %i.%09i.",
@@@ -738,17 -744,6 +738,17 @@@ static int plugin_insert_read (read_fun
                }
        }
  
 +      le = llist_search (read_list, rf->rf_name);
 +      if (le != NULL)
 +      {
 +              pthread_mutex_unlock (&read_lock);
 +              WARNING ("The read function \"%s\" is already registered. "
 +                              "Check for duplicate \"LoadPlugin\" lines "
 +                              "in your configuration!",
 +                              rf->rf_name);
 +              return (EINVAL);
 +      }
 +
        le = llentry_create (rf->rf_name, rf);
        if (le == NULL)
        {
@@@ -777,13 -772,14 +777,13 @@@ int plugin_register_read (const char *n
                int (*callback) (void))
  {
        read_func_t *rf;
 +      int status;
  
 -      rf = (read_func_t *) malloc (sizeof (read_func_t));
 +      rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
 -              char errbuf[1024];
 -              ERROR ("plugin_register_read: malloc failed: %s",
 -                              sstrerror (errno, errbuf, sizeof (errbuf)));
 -              return (-1);
 +              ERROR ("plugin_register_read: malloc failed.");
 +              return (ENOMEM);
        }
  
        memset (rf, 0, sizeof (read_func_t));
        rf->rf_interval.tv_nsec = 0;
        rf->rf_effective_interval = rf->rf_interval;
  
 -      return (plugin_insert_read (rf));
 +      status = plugin_insert_read (rf);
 +      if (status != 0)
 +              sfree (rf);
 +
 +      return (status);
  } /* int plugin_register_read */
  
  int plugin_register_complex_read (const char *group, const char *name,
                user_data_t *user_data)
  {
        read_func_t *rf;
 +      int status;
  
 -      rf = (read_func_t *) malloc (sizeof (read_func_t));
 +      rf = malloc (sizeof (*rf));
        if (rf == NULL)
        {
                ERROR ("plugin_register_complex_read: malloc failed.");
 -              return (-1);
 +              return (ENOMEM);
        }
  
        memset (rf, 0, sizeof (read_func_t));
                rf->rf_udata = *user_data;
        }
  
 -      return (plugin_insert_read (rf));
 +      status = plugin_insert_read (rf);
 +      if (status != 0)
 +              sfree (rf);
 +
 +      return (status);
  } /* int plugin_register_complex_read */
  
  int plugin_register_write (const char *name,
@@@ -865,14 -852,7 +865,14 @@@ int plugin_register_flush (const char *
                                (void *) callback, ud));
  } /* int plugin_register_flush */
  
- int plugin_register_shutdown (char *name,
 +int plugin_register_missing (const char *name,
 +              plugin_missing_cb callback, user_data_t *ud)
 +{
 +      return (create_register_callback (&list_missing, name,
 +                              (void *) callback, ud));
 +} /* int plugin_register_missing */
 +
+ int plugin_register_shutdown (const char *name,
                int (*callback) (void))
  {
        return (create_register_callback (&list_shutdown, name,
@@@ -1058,11 -1038,6 +1058,11 @@@ int plugin_unregister_flush (const cha
        return (plugin_unregister (list_flush, name));
  }
  
 +int plugin_unregister_missing (const char *name)
 +{
 +      return (plugin_unregister (list_missing, name));
 +}
 +
  int plugin_unregister_shutdown (const char *name)
  {
        return (plugin_unregister (list_shutdown, name));
@@@ -1286,7 -1261,7 +1286,7 @@@ int plugin_write (const char *plugin, /
    return (status);
  } /* }}} int plugin_write */
  
 -int plugin_flush (const char *plugin, int timeout, const char *identifier)
 +int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
  {
    llentry_t *le;
  
@@@ -1331,8 -1306,7 +1331,8 @@@ void plugin_shutdown_all (void
  
        destroy_read_heap ();
  
 -      plugin_flush (/* plugin = */ NULL, /* timeout = */ -1,
 +      plugin_flush (/* plugin = */ NULL,
 +                      /* timeout = */ 0,
                        /* identifier = */ NULL);
  
        le = NULL;
         * the real free function when registering the write callback. This way
         * the data isn't freed twice. */
        destroy_all_callbacks (&list_flush);
 +      destroy_all_callbacks (&list_missing);
        destroy_all_callbacks (&list_write);
  
        destroy_all_callbacks (&list_notification);
        destroy_all_callbacks (&list_log);
  } /* void plugin_shutdown_all */
  
 +int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
 +{
 +  llentry_t *le;
 +
 +  if (list_missing == NULL)
 +    return (0);
 +
 +  le = llist_head (list_missing);
 +  while (le != NULL)
 +  {
 +    callback_func_t *cf;
 +    plugin_missing_cb callback;
 +    int status;
 +
 +    cf = le->value;
 +    callback = cf->cf_callback;
 +
 +    status = (*callback) (vl, &cf->cf_udata);
 +    if (status != 0)
 +    {
 +      if (status < 0)
 +      {
 +        ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
 +            "failed with status %i.",
 +            le->key, status);
 +        return (status);
 +      }
 +      else
 +      {
 +        return (0);
 +      }
 +    }
 +
 +    le = le->next;
 +  }
 +  return (0);
 +} /* int }}} plugin_dispatch_missing */
 +
  int plugin_dispatch_values (value_list_t *vl)
  {
        int status;
        }
  
        if (vl->time == 0)
 -              vl->time = time (NULL);
 +              vl->time = cdtime ();
  
        if (vl->interval <= 0)
                vl->interval = interval_g;
  
 -      DEBUG ("plugin_dispatch_values: time = %u; interval = %i; "
 +      DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
                        "host = %s; "
                        "plugin = %s; plugin_instance = %s; "
                        "type = %s; type_instance = %s;",
 -                      (unsigned int) vl->time, vl->interval,
 +                      CDTIME_T_TO_DOUBLE (vl->time),
 +                      CDTIME_T_TO_DOUBLE (vl->interval),
                        vl->host,
                        vl->plugin, vl->plugin_instance,
                        vl->type, vl->type_instance);
        /* Update the value cache */
        uc_update (ds, vl);
  
 -      /* Initiate threshold checking */
 -      ut_check_threshold (ds, vl);
 -
        if (post_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, post_cache_chain);
@@@ -1591,9 -1528,9 +1591,9 @@@ int plugin_dispatch_notification (cons
        /* Possible TODO: Add flap detection here */
  
        DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; "
 -                      "time = %u; host = %s;",
 +                      "time = %.3f; host = %s;",
                        notif->severity, notif->message,
 -                      (unsigned int) notif->time, notif->host);
 +                      CDTIME_T_TO_DOUBLE (notif->time), notif->host);
  
        /* Nobody cares for notifications */
        if (list_notification == NULL)
@@@ -1727,7 -1664,7 +1727,7 @@@ static int plugin_notification_meta_ad
      }
      case NM_TYPE_BOOLEAN:
      {
 -      meta->nm_value.nm_boolean = *((bool *) value);
 +      meta->nm_value.nm_boolean = *((_Bool *) value);
        break;
      }
      default:
@@@ -1781,7 -1718,7 +1781,7 @@@ int plugin_notification_meta_add_doubl
  
  int plugin_notification_meta_add_boolean (notification_t *n,
      const char *name,
 -    bool value)
 +    _Bool value)
  {
    return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
  }
diff --combined src/plugin.h
@@@ -2,7 -2,7 +2,7 @@@
  #define PLUGIN_H
  /**
   * collectd - src/plugin.h
 - * Copyright (C) 2005-2008  Florian octo Forster
 + * Copyright (C) 2005-2010  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
   * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   *
   * Authors:
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Sebastian Harl <sh at tokkee.org>
   **/
  
  #include "collectd.h"
  #include "configfile.h"
  #include "meta_data.h"
 +#include "utils_time.h"
  
  #define PLUGIN_FLAGS_GLOBAL 0x0001
  
@@@ -86,8 -85,8 +86,8 @@@ struct value_list_
  {
        value_t *values;
        int      values_len;
 -      time_t   time;
 -      int      interval;
 +      cdtime_t time;
 +      cdtime_t interval;
        char     host[DATA_MAX_NAME_LEN];
        char     plugin[DATA_MAX_NAME_LEN];
        char     plugin_instance[DATA_MAX_NAME_LEN];
@@@ -136,7 -135,7 +136,7 @@@ typedef struct notification_meta_
                int64_t nm_signed_int;
                uint64_t nm_unsigned_int;
                double nm_double;
 -              bool nm_boolean;
 +              _Bool nm_boolean;
        } nm_value;
        struct notification_meta_s *next;
  } notification_meta_t;
  typedef struct notification_s
  {
        int    severity;
 -      time_t time;
 +      cdtime_t time;
        char   message[NOTIF_MAX_MSG_LEN];
        char   host[DATA_MAX_NAME_LEN];
        char   plugin[DATA_MAX_NAME_LEN];
@@@ -168,12 -167,8 +168,12 @@@ typedef int (*plugin_init_cb) (void)
  typedef int (*plugin_read_cb) (user_data_t *);
  typedef int (*plugin_write_cb) (const data_set_t *, const value_list_t *,
                user_data_t *);
 -typedef int (*plugin_flush_cb) (int timeout, const char *identifier,
 +typedef int (*plugin_flush_cb) (cdtime_t timeout, const char *identifier,
                user_data_t *);
 +/* "missing" callback. Returns less than zero on failure, zero if other
 + * callbacks should be called, greater than zero if no more callbacks should be
 + * called. */
 +typedef int (*plugin_missing_cb) (const value_list_t *, user_data_t *);
  typedef void (*plugin_log_cb) (int severity, const char *message,
                user_data_t *);
  typedef int (*plugin_shutdown_cb) (void);
@@@ -253,7 -248,7 +253,7 @@@ void plugin_shutdown_all (void)
  int plugin_write (const char *plugin,
      const data_set_t *ds, const value_list_t *vl);
  
 -int plugin_flush (const char *plugin, int timeout, const char *identifier);
 +int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
  
  /*
   * The `plugin_register_*' functions are used to make `config', `init',
@@@ -269,8 -264,6 +269,8 @@@ int plugin_register_init (const char *n
                plugin_init_cb callback);
  int plugin_register_read (const char *name,
                int (*callback) (void));
 +/* "user_data" will be freed automatically, unless
 + * "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,
@@@ -279,9 -272,7 +279,9 @@@ int plugin_register_write (const char *
                plugin_write_cb callback, user_data_t *user_data);
  int plugin_register_flush (const char *name,
                plugin_flush_cb callback, user_data_t *user_data);
- int plugin_register_shutdown (char *name,
 +int plugin_register_missing (const char *name,
 +              plugin_missing_cb callback, user_data_t *user_data);
+ int plugin_register_shutdown (const char *name,
                plugin_shutdown_cb callback);
  int plugin_register_data_set (const data_set_t *ds);
  int plugin_register_log (const char *name,
@@@ -296,7 -287,6 +296,7 @@@ int plugin_unregister_read (const char 
  int plugin_unregister_read_group (const char *group);
  int plugin_unregister_write (const char *name);
  int plugin_unregister_flush (const char *name);
 +int plugin_unregister_missing (const char *name);
  int plugin_unregister_shutdown (const char *name);
  int plugin_unregister_data_set (const char *name);
  int plugin_unregister_log (const char *name);
@@@ -318,7 -308,6 +318,7 @@@ int plugin_unregister_notification (con
   *              function.
   */
  int plugin_dispatch_values (value_list_t *vl);
 +int plugin_dispatch_missing (const value_list_t *vl);
  
  int plugin_dispatch_notification (const notification_t *notif);
  
@@@ -351,7 -340,7 +351,7 @@@ int plugin_notification_meta_add_doubl
      double value);
  int plugin_notification_meta_add_boolean (notification_t *n,
      const char *name,
 -    bool value);
 +    _Bool value);
  
  int plugin_notification_meta_copy (notification_t *dst,
      const notification_t *src);