Merge branch 'collectd-5.4' into collectd-5.5
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 1 Mar 2016 10:26:25 +0000 (11:26 +0100)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 1 Mar 2016 10:26:25 +0000 (11:26 +0100)
16 files changed:
1  2 
src/daemon/plugin.h
src/daemon/types_list.c
src/daemon/utils_random.c
src/daemon/utils_subst.c
src/liboconfig/oconfig.c
src/processes.c
src/sensors.c
src/threshold.c
src/utils_cmd_flush.c
src/utils_cmd_getval.c
src/utils_cmd_putnotif.c
src/utils_cmd_putval.c
src/utils_db_query.c
src/utils_latency.c
src/utils_latency.h
src/xmms.c

diff --combined src/daemon/plugin.h
index 70a2232,0000000..3db88e3
mode 100644,000000..100644
--- /dev/null
@@@ -1,460 -1,0 +1,466 @@@
 +/**
 + * collectd - src/plugin.h
 + * Copyright (C) 2005-2014  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>
 + *   Sebastian Harl <sh at tokkee.org>
 + **/
 +
 +#ifndef PLUGIN_H
 +#define PLUGIN_H
 +
 +#include "collectd.h"
 +#include "configfile.h"
 +#include "meta_data.h"
 +#include "utils_time.h"
 +
 +#if HAVE_PTHREAD_H
 +# include <pthread.h>
 +#endif
 +
 +#define PLUGIN_FLAGS_GLOBAL 0x0001
 +
 +#define DATA_MAX_NAME_LEN 64
 +
 +#define DS_TYPE_COUNTER  0
 +#define DS_TYPE_GAUGE    1
 +#define DS_TYPE_DERIVE   2
 +#define DS_TYPE_ABSOLUTE 3
 +
 +#define DS_TYPE_TO_STRING(t) (t == DS_TYPE_COUNTER)     ? "counter"  : \
 +                              (t == DS_TYPE_GAUGE)    ? "gauge"    : \
 +                              (t == DS_TYPE_DERIVE)   ? "derive"   : \
 +                              (t == DS_TYPE_ABSOLUTE) ? "absolute" : \
 +                              "unknown"
 +
 +
 +#ifndef LOG_ERR
 +# define LOG_ERR 3
 +#endif
 +#ifndef LOG_WARNING
 +# define LOG_WARNING 4
 +#endif
 +#ifndef LOG_NOTICE
 +# define LOG_NOTICE 5
 +#endif
 +#ifndef LOG_INFO
 +# define LOG_INFO 6
 +#endif
 +#ifndef LOG_DEBUG
 +# define LOG_DEBUG 7
 +#endif
 +
 +#define NOTIF_MAX_MSG_LEN 256
 +
 +#define NOTIF_FAILURE 1
 +#define NOTIF_WARNING 2
 +#define NOTIF_OKAY    4
 +
 +#define plugin_interval (plugin_get_ctx().interval)
 +
 +/*
 + * Public data types
 + */
 +typedef unsigned long long counter_t;
 +typedef double gauge_t;
 +typedef int64_t derive_t;
 +typedef uint64_t absolute_t;
 +
 +union value_u
 +{
 +      counter_t  counter;
 +      gauge_t    gauge;
 +      derive_t   derive;
 +      absolute_t absolute;
 +};
 +typedef union value_u value_t;
 +
 +struct value_list_s
 +{
 +      value_t *values;
 +      int      values_len;
 +      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];
 +      char     type[DATA_MAX_NAME_LEN];
 +      char     type_instance[DATA_MAX_NAME_LEN];
 +      meta_data_t *meta;
 +};
 +typedef struct value_list_s value_list_t;
 +
 +#define VALUE_LIST_INIT { NULL, 0, 0, plugin_get_interval (), \
 +      "localhost", "", "", "", "", NULL }
 +#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "", NULL }
 +
 +struct data_source_s
 +{
 +      char   name[DATA_MAX_NAME_LEN];
 +      int    type;
 +      double min;
 +      double max;
 +};
 +typedef struct data_source_s data_source_t;
 +
 +struct data_set_s
 +{
 +      char           type[DATA_MAX_NAME_LEN];
 +      int            ds_num;
 +      data_source_t *ds;
 +};
 +typedef struct data_set_s data_set_t;
 +
 +enum notification_meta_type_e
 +{
 +      NM_TYPE_STRING,
 +      NM_TYPE_SIGNED_INT,
 +      NM_TYPE_UNSIGNED_INT,
 +      NM_TYPE_DOUBLE,
 +      NM_TYPE_BOOLEAN
 +};
 +
 +typedef struct notification_meta_s
 +{
 +      char name[DATA_MAX_NAME_LEN];
 +      enum notification_meta_type_e type;
 +      union
 +      {
 +              const char *nm_string;
 +              int64_t nm_signed_int;
 +              uint64_t nm_unsigned_int;
 +              double nm_double;
 +              _Bool nm_boolean;
 +      } nm_value;
 +      struct notification_meta_s *next;
 +} notification_meta_t;
 +
 +typedef struct notification_s
 +{
 +      int    severity;
 +      cdtime_t time;
 +      char   message[NOTIF_MAX_MSG_LEN];
 +      char   host[DATA_MAX_NAME_LEN];
 +      char   plugin[DATA_MAX_NAME_LEN];
 +      char   plugin_instance[DATA_MAX_NAME_LEN];
 +      char   type[DATA_MAX_NAME_LEN];
 +      char   type_instance[DATA_MAX_NAME_LEN];
 +      notification_meta_t *meta;
 +} notification_t;
 +
 +struct user_data_s
 +{
 +      void *data;
 +      void (*free_func) (void *);
 +};
 +typedef struct user_data_s user_data_t;
 +
 +struct plugin_ctx_s
 +{
 +      cdtime_t interval;
 +};
 +typedef struct plugin_ctx_s plugin_ctx_t;
 +
 +/*
 + * Callback types
 + */
 +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) (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);
 +typedef int (*plugin_notification_cb) (const notification_t *,
 +              user_data_t *);
 +
 +/*
 + * NAME
 + *  plugin_set_dir
 + *
 + * DESCRIPTION
 + *  Sets the current `plugindir'
 + *
 + * ARGUMENTS
 + *  `dir'       Path to the plugin directory
 + *
 + * NOTES
 + *  If `dir' is NULL the compiled in default `PLUGINDIR' is used.
 + */
 +void plugin_set_dir (const char *dir);
 +
 +/*
 + * NAME
 + *  plugin_load
 + *
 + * DESCRIPTION
 + *  Searches the current `plugindir' (see `plugin_set_dir') for the plugin
 + *  named $type and loads it. Afterwards the plugin's `module_register'
 + *  function is called, which then calls `plugin_register' to register callback
 + *  functions.
 + *
 + * ARGUMENTS
 + *  `name'      Name of the plugin to load.
 + *  `flags'     Hints on how to handle this plugin.
 + *
 + * RETURN VALUE
 + *  Returns zero upon success, a value greater than zero if no plugin was found
 + *  and a value below zero if an error occurs.
 + *
 + * NOTES
 + *  Re-loading an already loaded module is detected and zero is returned in
 + *  this case.
 + */
 +int plugin_load (const char *name, uint32_t flags);
 +
 +void plugin_init_all (void);
 +void plugin_read_all (void);
 +int plugin_read_all_once (void);
 +void plugin_shutdown_all (void);
 +
 +/*
 + * NAME
 + *  plugin_write
 + *
 + * DESCRIPTION
 + *  Calls the write function of the given plugin with the provided data set and
 + *  value list. It differs from `plugin_dispatch_value' in that it does not
 + *  update the cache, does not do threshold checking, call the chain subsystem
 + *  and so on. It looks up the requested plugin and invokes the function, end
 + *  of story.
 + *
 + * ARGUMENTS
 + *  plugin     Name of the plugin. If NULL, the value is sent to all registered
 + *             write functions.
 + *  ds         Pointer to the data_set_t structure. If NULL, the data set is
 + *             looked up according to the `type' member in the `vl' argument.
 + *  vl         The actual value to be processed. Must not be NULL.
 + *
 + * RETURN VALUE
 + *  Returns zero upon success or non-zero if an error occurred. If `plugin' is
 + *  NULL and more than one plugin is called, an error is only returned if *all*
 + *  plugins fail.
 + *
 + * NOTES
 + *  This is the function used by the `write' built-in target. May be used by
 + *  other target plugins.
 + */
 +int plugin_write (const char *plugin,
 +    const data_set_t *ds, const value_list_t *vl);
 +
 +int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
 +
 +/*
 + * The `plugin_register_*' functions are used to make `config', `init',
 + * `read', `write' and `shutdown' functions known to the plugin
 + * infrastructure. Also, the data-formats are made public like this.
 + */
 +int plugin_register_config (const char *name,
 +              int (*callback) (const char *key, const char *val),
 +              const char **keys, int keys_num);
 +int plugin_register_complex_config (const char *type,
 +              int (*callback) (oconfig_item_t *));
 +int plugin_register_init (const char *name,
 +              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,
 +              user_data_t *user_data);
 +int plugin_register_write (const char *name,
 +              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_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,
 +              plugin_log_cb callback, user_data_t *user_data);
 +int plugin_register_notification (const char *name,
 +              plugin_notification_cb callback, user_data_t *user_data);
 +
 +int plugin_unregister_config (const char *name);
 +int plugin_unregister_complex_config (const char *name);
 +int plugin_unregister_init (const char *name);
 +int plugin_unregister_read (const char *name);
 +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);
 +int plugin_unregister_notification (const char *name);
 +
 +/*
 + * NAME
 + *  plugin_log_available_writers
 + *
 + * DESCRIPTION
 + *  This function can be called to output a list of _all_ registered
 + *  writers to the logfacility.
 + *  Since some writers dynamically build their name it can be hard for
 + *  the configuring person to know it. This function will fill this gap.
 + */
 +void plugin_log_available_writers ();
 +
 +/*
 + * NAME
 + *  plugin_dispatch_values
 + *
 + * DESCRIPTION
 + *  This function is called by reading processes with the values they've
 + *  aquired. The function fetches the data-set definition (that has been
 + *  registered using `plugin_register_data_set') and calls _all_ registered
 + *  write-functions.
 + *
 + * ARGUMENTS
 + *  `vl'        Value list of the values that have been read by a `read'
 + *              function.
 + */
 +int plugin_dispatch_values (value_list_t const *vl);
 +
 +/*
 + * NAME
 + *  plugin_dispatch_multivalue
 + *
 + * SYNOPSIS
 + *  plugin_dispatch_multivalue (vl, 1, DS_TYPE_GAUGE,
 + *                              "free", 42.0,
 + *                              "used", 58.0,
 + *                              NULL);
 + *
 + * DESCRIPTION
 + *  Takes a list of type instances and values and dispatches that in a batch,
 + *  making sure that all values have the same time stamp. If "store_percentage"
 + *  is set to true, the "type" is set to "percent" and a percentage is
 + *  calculated and dispatched, rather than the absolute values. Values that are
 + *  NaN are dispatched as NaN and will not influence the total.
 + *
 + *  The variadic arguments is a list of type_instance / type pairs, that are
 + *  interpreted as type "char const *" and type, encoded by their corresponding
 + *  "store_type":
 + *
 + *     - "gauge_t"    when "DS_TYPE_GAUGE"
 + *     - "absolute_t" when "DS_TYPE_ABSOLUTE"
 + *     - "derive_t"   when "DS_TYPE_DERIVE"
 + *     - "counter_t"  when "DS_TYPE_COUNTER"
 + *
 + *  The last argument must be
 + *  a NULL pointer to signal end-of-list.
 + *
 + * RETURNS
 + *  The number of values it failed to dispatch (zero on success).
 + */
 +__attribute__((sentinel))
 +int plugin_dispatch_multivalue (value_list_t const *vl,
 +              _Bool store_percentage, int store_type, ...);
 +
 +int plugin_dispatch_missing (const value_list_t *vl);
 +
 +int plugin_dispatch_notification (const notification_t *notif);
 +
 +void plugin_log (int level, const char *format, ...)
 +      __attribute__ ((format(printf,2,3)));
 +
 +/* These functions return the parsed severity or less than zero on failure. */
 +int parse_log_severity (const char *severity);
 +int parse_notif_severity (const char *severity);
 +
 +#define ERROR(...)   plugin_log (LOG_ERR,     __VA_ARGS__)
 +#define WARNING(...) plugin_log (LOG_WARNING, __VA_ARGS__)
 +#define NOTICE(...)  plugin_log (LOG_NOTICE,  __VA_ARGS__)
 +#define INFO(...)    plugin_log (LOG_INFO,    __VA_ARGS__)
 +#if COLLECT_DEBUG
 +# define DEBUG(...)  plugin_log (LOG_DEBUG,   __VA_ARGS__)
 +#else /* COLLECT_DEBUG */
 +# define DEBUG(...)  /* noop */
 +#endif /* ! COLLECT_DEBUG */
 +
 +const data_set_t *plugin_get_ds (const char *name);
 +
 +int plugin_notification_meta_add_string (notification_t *n,
 +    const char *name,
 +    const char *value);
 +int plugin_notification_meta_add_signed_int (notification_t *n,
 +    const char *name,
 +    int64_t value);
 +int plugin_notification_meta_add_unsigned_int (notification_t *n,
 +    const char *name,
 +    uint64_t value);
 +int plugin_notification_meta_add_double (notification_t *n,
 +    const char *name,
 +    double value);
 +int plugin_notification_meta_add_boolean (notification_t *n,
 +    const char *name,
 +    _Bool value);
 +
 +int plugin_notification_meta_copy (notification_t *dst,
 +    const notification_t *src);
 +
 +int plugin_notification_meta_free (notification_meta_t *n);
 +
 +/*
 + * Plugin context management.
 + */
 +
 +void plugin_init_ctx (void);
 +
 +plugin_ctx_t plugin_get_ctx (void);
 +plugin_ctx_t plugin_set_ctx (plugin_ctx_t ctx);
 +
 +/*
 + * NAME
 + *  plugin_get_interval
 + *
 + * DESCRIPTION
 + *  This function returns the current value of the plugin's interval. The
 + *  return value will be strictly greater than zero in all cases. If
 + *  everything else fails, it will fall back to 10 seconds.
 + */
 +cdtime_t plugin_get_interval (void);
 +
 +/*
 + * Context-aware thread management.
 + */
 +
 +int plugin_thread_create (pthread_t *thread, const pthread_attr_t *attr,
 +              void *(*start_routine) (void *), void *arg);
 +
++/*
++ * Plugins need to implement this
++ */
++
++void module_register (void);
++
 +#endif /* PLUGIN_H */
diff --combined src/daemon/types_list.c
index c0e61c5,0000000..4023a8f
mode 100644,000000..100644
--- /dev/null
@@@ -1,207 -1,0 +1,208 @@@
 +/**
 + * collectd - src/types_list.c
 + * Copyright (C) 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 "collectd.h"
 +#include "common.h"
 +
 +#include "plugin.h"
 +#include "configfile.h"
++#include "types_list.h"
 +
 +static int parse_ds (data_source_t *dsrc, char *buf, size_t buf_len)
 +{
 +  char *dummy;
 +  char *saveptr;
 +  char *fields[8];
 +  int   fields_num;
 +
 +  if (buf_len < 11)
 +  {
 +    ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
 +    return (-1);
 +  }
 +
 +  if (buf[buf_len - 1] == ',')
 +  {
 +    buf_len--;
 +    buf[buf_len] = '\0';
 +  }
 +
 +  dummy = buf;
 +  saveptr = NULL;
 +
 +  fields_num = 0;
 +  while (fields_num < 8)
 +  {
 +    if ((fields[fields_num] = strtok_r (dummy, ":", &saveptr)) == NULL)
 +      break;
 +    dummy = NULL;
 +    fields_num++;
 +  }
 +
 +  if (fields_num != 4)
 +  {
 +    ERROR ("parse_ds: (fields_num = %i) != 4", fields_num);
 +    return (-1);
 +  }
 +
 +  sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
 +
 +  if (strcasecmp (fields[1], "GAUGE") == 0)
 +    dsrc->type = DS_TYPE_GAUGE;
 +  else if (strcasecmp (fields[1], "COUNTER") == 0)
 +    dsrc->type = DS_TYPE_COUNTER;
 +  else if (strcasecmp (fields[1], "DERIVE") == 0)
 +    dsrc->type = DS_TYPE_DERIVE;
 +  else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
 +    dsrc->type = DS_TYPE_ABSOLUTE;
 +  else
 +  {
 +    ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
 +    return (-1);
 +  }
 +
 +  if (strcasecmp (fields[2], "U") == 0)
 +    dsrc->min = NAN;
 +  else
 +    dsrc->min = atof (fields[2]);
 +
 +  if (strcasecmp (fields[3], "U") == 0)
 +    dsrc->max = NAN;
 +  else
 +    dsrc->max = atof (fields[3]);
 +
 +  return (0);
 +} /* int parse_ds */
 +
 +static void parse_line (char *buf)
 +{
 +  char  *fields[64];
 +  size_t fields_num;
 +  data_set_t *ds;
 +  int i;
 +
 +  fields_num = strsplit (buf, fields, 64);
 +  if (fields_num < 2)
 +    return;
 +
 +  /* Ignore lines which begin with a hash sign. */
 +  if (fields[0][0] == '#')
 +    return;
 +
 +  ds = (data_set_t *) malloc (sizeof (data_set_t));
 +  if (ds == NULL)
 +    return;
 +
 +  memset (ds, '\0', sizeof (data_set_t));
 +
 +  sstrncpy (ds->type, fields[0], sizeof (ds->type));
 +
 +  ds->ds_num = fields_num - 1;
 +  ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
 +  if (ds->ds == NULL)
 +    return;
 +
 +  for (i = 0; i < ds->ds_num; i++)
 +    if (parse_ds (ds->ds + i, fields[i + 1], strlen (fields[i + 1])) != 0)
 +    {
 +      sfree (ds->ds);
 +      ERROR ("types_list: parse_line: Cannot parse data source #%i "
 +        "of data set %s", i, ds->type);
 +      return;
 +    }
 +
 +  plugin_register_data_set (ds);
 +
 +  sfree (ds->ds);
 +  sfree (ds);
 +} /* void parse_line */
 +
 +static void parse_file (FILE *fh)
 +{
 +  char buf[4096];
 +  size_t buf_len;
 +
 +  while (fgets (buf, sizeof (buf), fh) != NULL)
 +  {
 +    buf_len = strlen (buf);
 +
 +    if (buf_len >= 4095)
 +    {
 +      NOTICE ("Skipping line with more than 4095 characters.");
 +      do
 +      {
 +      if (fgets (buf, sizeof (buf), fh) == NULL)
 +        break;
 +      buf_len = strlen (buf);
 +      } while (buf_len >= 4095);
 +      continue;
 +    } /* if (buf_len >= 4095) */
 +
 +    if ((buf_len == 0) || (buf[0] == '#'))
 +      continue;
 +
 +    while ((buf_len > 0) && ((buf[buf_len - 1] == '\n')
 +        || (buf[buf_len - 1] == '\r')))
 +      buf[--buf_len] = '\0';
 +
 +    if (buf_len == 0)
 +      continue;
 +
 +    parse_line (buf);
 +  } /* while (fgets) */
 +} /* void parse_file */
 +
 +int read_types_list (const char *file)
 +{
 +  FILE *fh;
 +
 +  if (file == NULL)
 +    return (-1);
 +
 +  fh = fopen (file, "r");
 +  if (fh == NULL)
 +  {
 +    char errbuf[1024];
 +    fprintf (stderr, "Failed to open types database `%s': %s.\n",
 +      file, sstrerror (errno, errbuf, sizeof (errbuf)));
 +    ERROR ("Failed to open types database `%s': %s",
 +      file, sstrerror (errno, errbuf, sizeof (errbuf)));
 +    return (-1);
 +  }
 +
 +  parse_file (fh);
 +
 +  fclose (fh);
 +  fh = NULL;
 +
 +  DEBUG ("Done parsing `%s'", file);
 +
 +  return (0);
 +} /* int read_types_list */
 +
 +/*
 + * vim: shiftwidth=2:softtabstop=2:tabstop=8
 + */
index b873845,0000000..548d1d8
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,77 @@@
- #include <pthread.h>
 +/**
 + * collectd - src/utils_random.c
 + * Copyright (C) 2013       Florian 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 Forster <octo at collectd.org>
 + **/
 +
++#include <pthread.h>
++
 +#include "collectd.h"
 +#include "utils_time.h"
++#include "utils_random.h"
 +
 +
 +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 +static _Bool have_seed = 0;
 +static unsigned short seed[3];
 +
 +static void cdrand_seed (void)
 +{
 +  cdtime_t t;
 +
 +  if (have_seed)
 +    return;
 +
 +  t = cdtime();
 +
 +  seed[0] = (unsigned short) t;
 +  seed[1] = (unsigned short) (t >> 16);
 +  seed[2] = (unsigned short) (t >> 32);
 +
 +  have_seed = 1;
 +}
 +
 +double cdrand_d (void)
 +{
 +  double r;
 +
 +  pthread_mutex_lock (&lock);
 +  cdrand_seed ();
 +  r = erand48 (seed);
 +  pthread_mutex_unlock (&lock);
 +
 +  return (r);
 +}
 +
 +long cdrand_range (long min, long max)
 +{
 +  long range;
 +  long r;
 +
 +  range = 1 + max - min;
 +
 +  r = (long) (0.5 + (cdrand_d () * range));
 +  r += min;
 +
 +  return (r);
 +}
diff --combined src/daemon/utils_subst.c
index 2f28eb9,0000000..3e55497
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,150 @@@
 +/**
 + * collectd - src/utils_subst.c
 + * Copyright (C) 2008       Sebastian Harl
 + *
 + * 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:
 + *   Sebastian "tokkee" Harl <sh at tokkee.org>
 + **/
 +
 +/*
 + * This module provides functions for string substitution.
 + */
 +
 +#include "collectd.h"
 +#include "common.h"
++#include "utils_subst.h"
 +
 +char *subst (char *buf, size_t buflen, const char *string, int off1, int off2,
 +              const char *replacement)
 +{
 +      char  *buf_ptr = buf;
 +      size_t len     = buflen;
 +
 +      if ((NULL == buf) || (0 >= buflen) || (NULL == string)
 +                      || (0 > off1) || (0 > off2) || (off1 > off2)
 +                      || (NULL == replacement))
 +              return NULL;
 +
 +      sstrncpy (buf_ptr, string,
 +                      ((size_t)off1 + 1 > buflen) ? buflen : (size_t)off1 + 1);
 +      buf_ptr += off1;
 +      len     -= off1;
 +
 +      if (0 >= len)
 +              return buf;
 +
 +      sstrncpy (buf_ptr, replacement, len);
 +      buf_ptr += strlen (replacement);
 +      len     -= strlen (replacement);
 +
 +      if (0 >= len)
 +              return buf;
 +
 +      sstrncpy (buf_ptr, string + off2, len);
 +      return buf;
 +} /* subst */
 +
 +char *asubst (const char *string, int off1, int off2, const char *replacement)
 +{
 +      char *buf;
 +      int   len;
 +
 +      char *ret;
 +
 +      if ((NULL == string) || (0 > off1) || (0 > off2) || (off1 > off2)
 +                      || (NULL ==replacement))
 +              return NULL;
 +
 +      len = off1 + strlen (replacement) + strlen (string) - off2 + 1;
 +
 +      buf = (char *)malloc (len);
 +      if (NULL == buf)
 +              return NULL;
 +
 +      ret = subst (buf, len, string, off1, off2, replacement);
 +      if (NULL == ret)
 +              free (buf);
 +      return ret;
 +} /* asubst */
 +
 +char *subst_string (char *buf, size_t buflen, const char *string,
 +              const char *needle, const char *replacement)
 +{
 +      char *temp;
 +      size_t needle_len;
 +      size_t i;
 +
 +      if ((buf == NULL) || (string == NULL)
 +                      || (needle == NULL) || (replacement == NULL))
 +              return (NULL);
 +
 +      temp = (char *) malloc (buflen);
 +      if (temp == NULL)
 +      {
 +              ERROR ("subst_string: malloc failed.");
 +              return (NULL);
 +      }
 +
 +      needle_len = strlen (needle);
 +      strncpy (buf, string, buflen);
 +
 +      /* Limit the loop to prevent endless loops. */
 +      for (i = 0; i < buflen; i++)
 +      {
 +              char *begin_ptr;
 +              size_t begin;
 +
 +              /* Find `needle' in `buf'. */
 +              begin_ptr = strstr (buf, needle);
 +              if (begin_ptr == NULL)
 +                      break;
 +
 +              /* Calculate the start offset. */
 +              begin = begin_ptr - buf;
 +
 +              /* Substitute the region using `subst'. The result is stored in
 +               * `temp'. */
 +              begin_ptr = subst (temp, buflen, buf,
 +                              begin, begin + needle_len,
 +                              replacement);
 +              if (begin_ptr == NULL)
 +              {
 +                      WARNING ("subst_string: subst failed.");
 +                      break;
 +              }
 +
 +              /* Copy the new string in `temp' to `buf' for the next round. */
 +              strncpy (buf, temp, buflen);
 +      }
 +
 +      if (i >= buflen)
 +      {
 +              WARNING ("subst_string: Loop exited after %zu iterations: "
 +                              "string = %s; needle = %s; replacement = %s;",
 +                              i, string, needle, replacement);
 +      }
 +
 +      sfree (temp);
 +      return (buf);
 +} /* char *subst_string */
 +
 +/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
 +
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>
@@@ -196,7 -188,7 +196,7 @@@ oconfig_item_t *oconfig_clone (const oc
    return (ci_copy);
  } /* oconfig_item_t *oconfig_clone */
  
- void oconfig_free_all (oconfig_item_t *ci)
static void oconfig_free_all (oconfig_item_t *ci)
  {
    int i;
  
diff --combined src/processes.c
@@@ -25,7 -25,7 +25,7 @@@
   *
   * Authors:
   *   Lyonel Vincent <lyonel at ezix.org>
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Oleg King <king2 at kaluga.ru>
   *   Sebastian Harl <sh at tokkee.org>
   *   Andrés J. Díaz <ajdiaz at connectical.com>
  #  endif
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
  #  include <kvm.h>
  #  include <sys/param.h>
  #  include <sys/sysctl.h>
  #  include <sys/user.h>
  #  include <sys/proc.h>
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
  #  include <procinfo.h>
  # include <kstat.h>
  #endif
  
 -#ifndef ARG_MAX
 -#  define ARG_MAX 4096
 +#ifndef CMDLINE_BUFFER_SIZE
 +# if defined(ARG_MAX) && (ARG_MAX < 4096)
 +#  define CMDLINE_BUFFER_SIZE ARG_MAX
 +# else
 +#  define CMDLINE_BUFFER_SIZE 4096
 +# endif
  #endif
  
  typedef struct procstat_entry_s
@@@ -229,9 -225,9 +229,9 @@@ static mach_msg_type_number_t     pset_
  static long pagesize_g;
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
  static int pagesize;
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
  static  struct procentry64 procentry[MAXPROCENTRY];
@@@ -641,9 -637,9 +641,9 @@@ static int ps_init (void
                        pagesize_g, CONFIG_HZ);
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
        pagesize = getpagesize();
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
        pagesize = getpagesize();
@@@ -926,7 -922,7 +926,7 @@@ static procstat_t *ps_read_io (long pid
        return (ps);
  } /* procstat_t *ps_read_io */
  
- int ps_read_process (long pid, procstat_t *ps, char *state)
static int ps_read_process (long pid, procstat_t *ps, char *state)
  {
        char  filename[64];
        char  buffer[1024];
@@@ -1707,7 -1703,7 +1707,7 @@@ static int ps_read (void
        DIR           *proc;
        long           pid;
  
 -      char cmdline[ARG_MAX];
 +      char cmdline[CMDLINE_BUFFER_SIZE];
  
        int        status;
        procstat_t ps;
                        continue;
                }
  
 +              memset (&pse, 0, sizeof (pse));
                pse.id       = pid;
                pse.age      = 0;
  
                 * filter out threads (duplicate PID entries). */
                if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid))
                {
 -                      char cmdline[ARG_MAX] = "";
 +                      char cmdline[CMDLINE_BUFFER_SIZE] = "";
                        _Bool have_cmdline = 0;
  
                        proc_ptr = &(procs[i]);
                ps_submit_proc_list (ps_ptr);
  /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
  
 +#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD
 +      int running  = 0;
 +      int sleeping = 0;
 +      int zombies  = 0;
 +      int stopped  = 0;
 +      int onproc   = 0;
 +      int idle     = 0;
 +      int dead     = 0;
 +
 +      kvm_t *kd;
 +      char errbuf[1024];
 +      struct kinfo_proc *procs;          /* array of processes */
 +      struct kinfo_proc *proc_ptr = NULL;
 +      int count;                         /* returns number of processes */
 +      int i;
 +
 +      procstat_t *ps_ptr;
 +      procstat_entry_t pse;
 +
 +      ps_list_reset ();
 +
 +      /* Open the kvm interface, get a descriptor */
 +      kd = kvm_open (NULL, NULL, NULL, 0, errbuf);
 +      if (kd == NULL)
 +      {
 +              ERROR ("processes plugin: Cannot open kvm interface: %s",
 +                              errbuf);
 +              return (0);
 +      }
 +
 +      /* Get the list of processes. */
 +      procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
 +      if (procs == NULL)
 +      {
 +              ERROR ("processes plugin: Cannot get kvm processes list: %s",
 +                              kvm_geterr(kd));
 +              kvm_close (kd);
 +              return (0);
 +      }
 +
 +      /* Iterate through the processes in kinfo_proc */
 +      for (i = 0; i < count; i++)
 +      {
 +              /* Create only one process list entry per _process_, i.e.
 +               * filter out threads (duplicate PID entries). */
 +              if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid))
 +              {
 +                      char cmdline[CMDLINE_BUFFER_SIZE] = "";
 +                      _Bool have_cmdline = 0;
 +
 +                      proc_ptr = &(procs[i]);
 +                      /* Don't probe zombie processes  */
 +                      if (!P_ZOMBIE(proc_ptr))
 +                      {
 +                              char **argv;
 +                              int argc;
 +                              int status;
 +
 +                              /* retrieve the arguments */
 +                              argv = kvm_getargv (kd, proc_ptr, /* nchr = */ 0);
 +                              argc = 0;
 +                              if ((argv != NULL) && (argv[0] != NULL))
 +                              {
 +                                      while (argv[argc] != NULL)
 +                                              argc++;
 +
 +                                      status = strjoin (cmdline, sizeof (cmdline), argv, argc, " ");
 +                                      if (status < 0)
 +                                              WARNING ("processes plugin: Command line did not fit into buffer.");
 +                                      else
 +                                              have_cmdline = 1;
 +                              }
 +                      } /* if (process has argument list) */
 +
 +                      memset (&pse, 0, sizeof (pse));
 +                      pse.id       = procs[i].p_pid;
 +                      pse.age      = 0;
 +
 +                      pse.num_proc = 1;
 +                      pse.num_lwp  = 1; /* XXX: accumulate p_tid values for a single p_pid ? */
 +
 +                      pse.vmem_rss = procs[i].p_vm_rssize * pagesize;
 +                      pse.vmem_data = procs[i].p_vm_dsize * pagesize;
 +                      pse.vmem_code = procs[i].p_vm_tsize * pagesize;
 +                      pse.stack_size = procs[i].p_vm_ssize * pagesize;
 +                      pse.vmem_size = pse.stack_size + pse.vmem_code + pse.vmem_data;
 +                      pse.vmem_minflt = 0;
 +                      pse.vmem_minflt_counter = procs[i].p_uru_minflt;
 +                      pse.vmem_majflt = 0;
 +                      pse.vmem_majflt_counter = procs[i].p_uru_majflt;
 +
 +                      pse.cpu_user = 0;
 +                      pse.cpu_system = 0;
 +                      pse.cpu_user_counter = procs[i].p_uutime_usec +
 +                                              (1000000lu * procs[i].p_uutime_sec);
 +                      pse.cpu_system_counter = procs[i].p_ustime_usec +
 +                                              (1000000lu * procs[i].p_ustime_sec);
 +
 +                      /* no I/O data */
 +                      pse.io_rchar = -1;
 +                      pse.io_wchar = -1;
 +                      pse.io_syscr = -1;
 +                      pse.io_syscw = -1;
 +
 +                      pse.cswitch_vol = -1;
 +                      pse.cswitch_invol = -1;
 +
 +                      ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
 +
 +                      switch (procs[i].p_stat)
 +                      {
 +                              case SSTOP:     stopped++;      break;
 +                              case SSLEEP:    sleeping++;     break;
 +                              case SRUN:      running++;      break;
 +                              case SIDL:      idle++;         break;
 +                              case SONPROC:   onproc++;       break;
 +                              case SDEAD:     dead++;         break;
 +                              case SZOMB:     zombies++;      break;
 +                      }
 +              } /* if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid)) */
 +      }
 +
 +      kvm_close(kd);
 +
 +      ps_submit_state ("running",  running);
 +      ps_submit_state ("sleeping", sleeping);
 +      ps_submit_state ("zombies",  zombies);
 +      ps_submit_state ("stopped",  stopped);
 +      ps_submit_state ("onproc",   onproc);
 +      ps_submit_state ("idle",     idle);
 +      ps_submit_state ("dead",     dead);
 +
 +      for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
 +              ps_submit_proc_list (ps_ptr);
 +/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD */
 +
  #elif HAVE_PROCINFO_H
        /* AIX */
        int running  = 0;
                        continue;
                }
  
 +              memset (&pse, 0, sizeof (pse));
                pse.id = pid;
                pse.age = 0;
  
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
  
 +              pse.cswitch_vol = -1;
 +              pse.cswitch_invol = -1;
 +
                switch (state)
                {
                        case 'R': running++;  break;
diff --combined src/sensors.c
@@@ -17,7 -17,7 +17,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>
   *   
   *   Lubos Stanek <lubek at users.sourceforge.net> Wed Oct 27, 2006
   *   - config ExtendedSensorNaming option
@@@ -62,9 -62,7 +62,9 @@@ static char *sensor_type_name_map[] 
        "fanspeed",
  # define SENSOR_TYPE_TEMPERATURE 2
        "temperature",
 -# define SENSOR_TYPE_UNKNOWN     3
 +# define SENSOR_TYPE_POWER       3
 +      "power",
 +# define SENSOR_TYPE_UNKNOWN     4
        NULL
  };
  
@@@ -129,8 -127,7 +129,8 @@@ static sensors_labeltypes_t known_featu
        { "3.3V", SENSOR_TYPE_VOLTAGE },
        { "2.5V", SENSOR_TYPE_VOLTAGE },
        { "2.0V", SENSOR_TYPE_VOLTAGE },
 -      { "12V", SENSOR_TYPE_VOLTAGE }
 +      { "12V", SENSOR_TYPE_VOLTAGE },
 +      { "power1", SENSOR_TYPE_POWER }
  };
  static int known_features_num = STATIC_ARRAY_SIZE (known_features);
  /* end new naming */
@@@ -265,7 -262,7 +265,7 @@@ static int sensors_config (const char *
        return (0);
  }
  
- void sensors_free_features (void)
static void sensors_free_features (void)
  {
        featurelist_t *thisft;
        featurelist_t *nextft;
@@@ -414,8 -411,7 +414,8 @@@ static int sensors_load_conf (void
                        /* Only handle voltage, fanspeeds and temperatures */
                        if ((feature->type != SENSORS_FEATURE_IN)
                                        && (feature->type != SENSORS_FEATURE_FAN)
 -                                      && (feature->type != SENSORS_FEATURE_TEMP))
 +                                      && (feature->type != SENSORS_FEATURE_TEMP)
 +                                      && (feature->type != SENSORS_FEATURE_POWER))
                        {
                                DEBUG ("sensors plugin: sensors_load_conf: "
                                                "Ignoring feature `%s', "
  
                                if ((subfeature->type != SENSORS_SUBFEATURE_IN_INPUT)
                                                && (subfeature->type != SENSORS_SUBFEATURE_FAN_INPUT)
 -                                              && (subfeature->type != SENSORS_SUBFEATURE_TEMP_INPUT))
 +                                              && (subfeature->type != SENSORS_SUBFEATURE_TEMP_INPUT)
 +                                              && (subfeature->type != SENSORS_SUBFEATURE_POWER_INPUT))
                                        continue;
  
                                fl = (featurelist_t *) malloc (sizeof (featurelist_t));
@@@ -578,9 -573,6 +578,9 @@@ static int sensors_read (void
                else if (fl->feature->type
                                == SENSORS_FEATURE_TEMP)
                        type = "temperature";
 +              else if (fl->feature->type
 +                              == SENSORS_FEATURE_POWER)
 +                      type = "power";
                else
                        continue;
  
diff --combined src/threshold.c
  #include "plugin.h"
  #include "utils_avltree.h"
  #include "utils_cache.h"
 +#include "utils_threshold.h"
  
  #include <assert.h>
  #include <pthread.h>
  
  /*
 - * Private data structures
 - * {{{ */
 -#define UT_FLAG_INVERT  0x01
 -#define UT_FLAG_PERSIST 0x02
 -#define UT_FLAG_PERCENTAGE 0x04
 -#define UT_FLAG_INTERESTING 0x08
 -#define UT_FLAG_PERSIST_OK 0x10
 -typedef struct threshold_s
 -{
 -  char host[DATA_MAX_NAME_LEN];
 -  char plugin[DATA_MAX_NAME_LEN];
 -  char plugin_instance[DATA_MAX_NAME_LEN];
 -  char type[DATA_MAX_NAME_LEN];
 -  char type_instance[DATA_MAX_NAME_LEN];
 -  char data_source[DATA_MAX_NAME_LEN];
 -  gauge_t warning_min;
 -  gauge_t warning_max;
 -  gauge_t failure_min;
 -  gauge_t failure_max;
 -  gauge_t hysteresis;
 -  unsigned int flags;
 -  int hits;
 -  struct threshold_s *next;
 -} threshold_t;
 -/* }}} */
 -
 -/*
 - * Private (static) variables
 - * {{{ */
 -static c_avl_tree_t   *threshold_tree = NULL;
 -static pthread_mutex_t threshold_lock = PTHREAD_MUTEX_INITIALIZER;
 -/* }}} */
 -
 -/*
   * Threshold management
   * ====================
   * The following functions add, delete, search, etc. configured thresholds to
   * the underlying AVL trees.
   */
 -/*
 - * threshold_t *threshold_get
 - *
 - * Retrieve one specific threshold configuration. For looking up a threshold
 - * matching a value_list_t, see "threshold_search" below. Returns NULL if the
 - * specified threshold doesn't exist.
 - */
 -static threshold_t *threshold_get (const char *hostname,
 -    const char *plugin, const char *plugin_instance,
 -    const char *type, const char *type_instance)
 -{ /* {{{ */
 -  char name[6 * DATA_MAX_NAME_LEN];
 -  threshold_t *th = NULL;
 -
 -  format_name (name, sizeof (name),
 -      (hostname == NULL) ? "" : hostname,
 -      (plugin == NULL) ? "" : plugin, plugin_instance,
 -      (type == NULL) ? "" : type, type_instance);
 -  name[sizeof (name) - 1] = '\0';
 -
 -  if (c_avl_get (threshold_tree, name, (void *) &th) == 0)
 -    return (th);
 -  else
 -    return (NULL);
 -} /* }}} threshold_t *threshold_get */
  
  /*
   * int ut_threshold_add
@@@ -113,6 -171,58 +113,6 @@@ static int ut_threshold_add (const thre
    return (status);
  } /* }}} int ut_threshold_add */
  
 -/* 
 - * threshold_t *threshold_search
 - *
 - * Searches for a threshold configuration using all the possible variations of
 - * "Host", "Plugin" and "Type" blocks. Returns NULL if no threshold could be
 - * found.
 - * XXX: This is likely the least efficient function in collectd.
 - */
 -static threshold_t *threshold_search (const value_list_t *vl)
 -{ /* {{{ */
 -  threshold_t *th;
 -
 -  if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get (vl->host, vl->plugin, NULL,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get (vl->host, "", NULL,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get (vl->host, "", NULL,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", vl->plugin, NULL,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", vl->plugin, NULL,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", "", NULL,
 -        vl->type, vl->type_instance)) != NULL)
 -    return (th);
 -  else if ((th = threshold_get ("", "", NULL,
 -        vl->type, NULL)) != NULL)
 -    return (th);
 -
 -  return (NULL);
 -} /* }}} threshold_t *threshold_search */
 -
  /*
   * Configuration
   * =============
@@@ -514,10 -624,7 +514,10 @@@ static int ut_report_state (const data_
      if (state_old == STATE_MISSING)
        ssnprintf (buf, bufsize, ": Value is no longer missing.");
      else
 -      ssnprintf (buf, bufsize, ": All data sources are within range again.");
 +      ssnprintf (buf, bufsize,
 +          ": All data sources are within range again. "
 +          "Current value of \"%s\" is %f.",
 +          ds->ds[ds_index].name, values[ds_index]);
    }
    else
    {
@@@ -631,40 -738,23 +631,40 @@@ static int ut_check_one_data_source (co
  
    /* XXX: This is an experimental code, not optimized, not fast, not reliable,
     * and probably, do not work as you expect. Enjoy! :D */
 -  if ( (th->hysteresis > 0) && ((prev_state = uc_get_state(ds,vl)) != STATE_OKAY) )
 -  {
 -    switch(prev_state)
 +  if (th->hysteresis > 0)
 +  {
 +    prev_state = uc_get_state(ds,vl);
 +    /* The purpose of hysteresis is elliminating flapping state when the value
 +     * oscilates around the thresholds. In other words, what is important is
 +     * the previous state; if the new value would trigger a transition, make
 +     * sure that we artificially widen the range which is considered to apply
 +     * for the previous state, and only trigger the notification if the value
 +     * is outside of this expanded range.
 +     *
 +     * There is no hysteresis for the OKAY state.
 +     * */
 +    gauge_t hysteresis_for_warning = 0, hysteresis_for_failure = 0;
 +    switch (prev_state)
      {
        case STATE_ERROR:
 -      if ( (!isnan (th->failure_min) && ((th->failure_min + th->hysteresis) < values[ds_index])) ||
 -           (!isnan (th->failure_max) && ((th->failure_max - th->hysteresis) > values[ds_index])) )
 -        return (STATE_OKAY);
 -      else
 -        is_failure++;
 +        hysteresis_for_failure = th->hysteresis;
 +        break;
        case STATE_WARNING:
 -      if ( (!isnan (th->warning_min) && ((th->warning_min + th->hysteresis) < values[ds_index])) ||
 -           (!isnan (th->warning_max) && ((th->warning_max - th->hysteresis) > values[ds_index])) )
 -        return (STATE_OKAY);
 -      else
 -        is_warning++;
 -     }
 +        hysteresis_for_warning = th->hysteresis;
 +        break;
 +      case STATE_OKAY:
 +        /* do nothing -- the hysteresis only applies to the non-normal states */
 +        break;
 +    }
 +
 +    if ((!isnan (th->failure_min) && (th->failure_min + hysteresis_for_failure > values[ds_index]))
 +      || (!isnan (th->failure_max) && (th->failure_max - hysteresis_for_failure < values[ds_index])))
 +      is_failure++;
 +
 +    if ((!isnan (th->warning_min) && (th->warning_min + hysteresis_for_warning > values[ds_index]))
 +      || (!isnan (th->warning_max) && (th->warning_max - hysteresis_for_warning < values[ds_index])))
 +      is_warning++;
 +
    }
    else { /* no hysteresis */
      if ((!isnan (th->failure_min) && (th->failure_min > values[ds_index]))
      if ((!isnan (th->warning_min) && (th->warning_min > values[ds_index]))
        || (!isnan (th->warning_max) && (th->warning_max < values[ds_index])))
        is_warning++;
 - }
 +  }
  
    if (is_failure != 0)
      return (STATE_ERROR);
@@@ -763,7 -853,7 +763,7 @@@ static int ut_check_one_threshold (cons
   *
   * Gets a list of matching thresholds and searches for the worst status by one
   * of the thresholds. Then reports that status using the ut_report_state
 - * function above. 
 + * function above.
   * Returns zero on success and if no threshold has been configured. Returns
   * less than zero on failure.
   */
@@@ -868,7 -958,7 +868,7 @@@ static int ut_missing (const value_list
    return (0);
  } /* }}} int ut_missing */
  
- int ut_config (oconfig_item_t *ci)
static int ut_config (oconfig_item_t *ci)
  { /* {{{ */
    int i;
    int status = 0;
    th.hits = 0;
    th.hysteresis = 0;
    th.flags = UT_FLAG_INTERESTING; /* interesting by default */
 -    
 +
    for (i = 0; i < ci->children_num; i++)
    {
      oconfig_item_t *option = ci->children + i;
diff --combined src/utils_cmd_flush.c
@@@ -1,35 -1,31 +1,36 @@@
  /**
   * collectd - src/utils_cmd_flush.c
 - * Copyright (C) 2008  Sebastian Harl
 - * Copyright (C) 2008  Florian Forster
 + * Copyright (C) 2008       Sebastian Harl
 + * 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:
   *   Sebastian "tokkee" Harl <sh at tokkee.org>
 - *   Florian "octo" Forster <octo at verplant.org>
 + *   Florian "octo" Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
  #include "common.h"
  #include "plugin.h"
  #include "utils_parse_option.h"
+ #include "utils_cmd_flush.h"
  
  int handle_flush (FILE *fh, char *buffer)
  {
diff --combined src/utils_cmd_getval.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_getval.c
 - * Copyright (C) 2008  Florian octo Forster
 + * collectd - src/utils_cmd_getval.c
 + * Copyright (C) 2008       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.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -30,6 -25,7 +30,7 @@@
  
  #include "utils_cache.h"
  #include "utils_parse_option.h"
+ #include "utils_cmd_getval.h"
  
  #define print_to_socket(fh, ...) \
    do { \
diff --combined src/utils_cmd_putnotif.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_putnotif.c
 - * Copyright (C) 2008  Florian octo Forster
 + * collectd - src/utils_cmd_putnotif.c
 + * Copyright (C) 2008       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.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -29,6 -24,7 +29,7 @@@
  #include "plugin.h"
  
  #include "utils_parse_option.h"
+ #include "utils_cmd_putnotif.h"
  
  #define print_to_socket(fh, ...) \
    do { \
@@@ -81,18 -77,6 +82,18 @@@ static int set_option (notification_t *
    DEBUG ("utils_cmd_putnotif: set_option (option = %s, value = %s);",
        option, value);
  
 +  /* Add a meta option in the form: <type>:<key> */
 +  if (option[0] != '\0' && option[1] == ':') {
 +    /* Refuse empty key */
 +    if (option[2] == '\0')
 +      return (1);
 +
 +    if (option[0] == 's')
 +      return plugin_notification_meta_add_string (n, option + 2, value);
 +    else
 +      return (1);
 +  }
 +
    if (strcasecmp ("severity", option) == 0)
      return (set_option_severity (n, value));
    else if (strcasecmp ("time", option) == 0)
diff --combined src/utils_cmd_putval.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
 - * collectd - src/utils_cms_putval.c
 + * collectd - src/utils_cmd_putval.c
   * Copyright (C) 2007-2009  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.
   *
 - * Author:
 - *   Florian octo Forster <octo at verplant.org>
 + * Authors:
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -29,6 -24,7 +29,7 @@@
  #include "plugin.h"
  
  #include "utils_parse_option.h"
+ #include "utils_cmd_putval.h"
  
  #define print_to_socket(fh, ...) \
      do { \
diff --combined src/utils_db_query.c
@@@ -2,26 -2,21 +2,26 @@@
   * collectd - src/utils_db_query.c
   * Copyright (C) 2008,2009  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 verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -43,8 -38,6 +43,8 @@@ struct udb_result_
    size_t   instances_num;
    char   **values;
    size_t   values_num;
 +  char   **metadata;
 +  size_t   metadata_num;
  
    udb_result_t *next;
  }; /* }}} */
@@@ -66,10 -59,8 +66,10 @@@ struct udb_result_preparation_area_s /
    const   data_set_t *ds;
    size_t *instances_pos;
    size_t *values_pos;
 +  size_t *metadata_pos;
    char  **instances_buffer;
    char  **values_buffer;
 +  char  **metadata_buffer;
  
    struct udb_result_preparation_area_s *next;
  }; /* }}} */
@@@ -197,7 -188,6 +197,7 @@@ static int udb_result_submit (udb_resul
  {
    value_list_t vl = VALUE_LIST_INIT;
    size_t i;
 +  int status;
  
    assert (r != NULL);
    assert (r_area->ds != NULL);
    vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
    /* }}} */
  
 +  /* Annotate meta data. {{{ */
 +  if (r->metadata_num > 0)
 +  {
 +    vl.meta = meta_data_create ();
 +    if (vl.meta == NULL)
 +    {
 +      ERROR ("db query utils:: meta_data_create failed.");
 +      return (-ENOMEM);
 +    }
 +
 +    for (i = 0; i < r->metadata_num; i++)
 +    {
 +      status = meta_data_add_string (vl.meta, r->metadata[i],
 +          r_area->metadata_buffer[i]);
 +      if (status != 0)
 +      {
 +        ERROR ("db query utils:: meta_data_add_string failed.");
 +        meta_data_destroy (vl.meta);
 +        vl.meta = NULL;
 +        return (status);
 +      }
 +    }
 +  }
 +  /* }}} */
 +
    plugin_dispatch_values (&vl);
  
 +  if (r->metadata_num > 0)
 +  {
 +    meta_data_destroy (vl.meta);
 +    vl.meta = NULL;
 +  }
    sfree (vl.values);
    return (0);
  } /* }}} void udb_result_submit */
@@@ -309,10 -269,8 +309,10 @@@ static void udb_result_finish_result (u
    prep_area->ds = NULL;
    sfree (prep_area->instances_pos);
    sfree (prep_area->values_pos);
 +  sfree (prep_area->metadata_pos);
    sfree (prep_area->instances_buffer);
    sfree (prep_area->values_buffer);
 +  sfree (prep_area->metadata_buffer);
  } /* }}} void udb_result_finish_result */
  
  static int udb_result_handle_result (udb_result_t *r, /* {{{ */
    for (i = 0; i < r->values_num; i++)
      r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
  
 +  for (i = 0; i < r->metadata_num; i++)
 +    r_area->metadata_buffer[i] = column_values[r_area->metadata_pos[i]];
 +
    return udb_result_submit (r, r_area, q, q_area);
  } /* }}} int udb_result_handle_result */
  
@@@ -349,17 -304,14 +349,17 @@@ static int udb_result_prepare_result (u
    prep_area->ds = NULL; \
    sfree (prep_area->instances_pos); \
    sfree (prep_area->values_pos); \
 +  sfree (prep_area->metadata_pos); \
    sfree (prep_area->instances_buffer); \
    sfree (prep_area->values_buffer); \
 +  sfree (prep_area->metadata_buffer); \
    return (status)
  
    /* Make sure previous preparations are cleaned up. */
    udb_result_finish_result (r, prep_area);
    prep_area->instances_pos = NULL;
    prep_area->values_pos = NULL;
 +  prep_area->metadata_pos = NULL;
  
    /* Read `ds' and check number of values {{{ */
    prep_area->ds = plugin_get_ds (r->type);
    }
    /* }}} */
  
 -  /* Allocate r->instances_pos, r->values_pos, r->instances_buffer, and
 -   * r->values_buffer {{{ */
 +  /* Allocate r->instances_pos, r->values_pos, r->metadata_post,
 +   * r->instances_buffer, r->values_buffer, and r->metadata_buffer {{{ */
    if (r->instances_num > 0)
    {
      prep_area->instances_pos
      ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
      BAIL_OUT (-ENOMEM);
    }
 +
 +  prep_area->metadata_pos
 +    = (size_t *) calloc (r->metadata_num, sizeof (size_t));
 +  if (prep_area->metadata_pos == NULL)
 +  {
 +    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +    BAIL_OUT (-ENOMEM);
 +  }
 +
 +  prep_area->metadata_buffer
 +    = (char **) calloc (r->metadata_num, sizeof (char *));
 +  if (prep_area->metadata_buffer == NULL)
 +  {
 +    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +    BAIL_OUT (-ENOMEM);
 +  }
 +
    /* }}} */
  
    /* Determine the position of the instance columns {{{ */
      }
    } /* }}} for (i = 0; i < r->values_num; i++) */
  
 +  /* Determine the position of the metadata columns {{{ */
 +  for (i = 0; i < r->metadata_num; i++)
 +  {
 +    size_t j;
 +
 +    for (j = 0; j < column_num; j++)
 +    {
 +      if (strcasecmp (r->metadata[i], column_names[j]) == 0)
 +      {
 +        prep_area->metadata_pos[i] = j;
 +        break;
 +      }
 +    }
 +
 +    if (j >= column_num)
 +    {
 +      ERROR ("db query utils: udb_result_prepare_result: "
 +          "Metadata column `%s' could not be found.",
 +          r->values[i]);
 +      BAIL_OUT (-ENOENT);
 +    }
 +  } /* }}} for (i = 0; i < r->metadata_num; i++) */
 +
  #undef BAIL_OUT
    return (0);
  } /* }}} int udb_result_prepare_result */
@@@ -527,10 -439,6 +527,10 @@@ static void udb_result_free (udb_result
      sfree (r->values[i]);
    sfree (r->values);
  
 +  for (i = 0; i < r->metadata_num; i++)
 +    sfree (r->metadata[i]);
 +  sfree (r->metadata);
 +
    udb_result_free (r->next);
  
    sfree (r);
@@@ -561,7 -469,6 +561,7 @@@ static int udb_result_create (const cha
    r->instance_prefix = NULL;
    r->instances = NULL;
    r->values = NULL;
 +  r->metadata = NULL;
    r->next = NULL;
  
    /* Fill the `udb_result_t' structure.. */
        status = udb_config_add_string (&r->instances, &r->instances_num, child);
      else if (strcasecmp ("ValuesFrom", child->key) == 0)
        status = udb_config_add_string (&r->values, &r->values_num, child);
 +    else if (strcasecmp ("MetadataFrom", child->key) == 0)
 +      status = udb_config_add_string (&r->metadata, &r->metadata_num, child);
      else
      {
        WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
  /*
   * Query private functions
   */
- void udb_query_free_one (udb_query_t *q) /* {{{ */
static void udb_query_free_one (udb_query_t *q) /* {{{ */
  {
    if (q == NULL)
      return;
diff --combined src/utils_latency.c
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/utils_latency.c
 - * Copyright (C) 2013  Florian Forster
 + * Copyright (C) 2013       Florian Forster
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   *   Florian Forster <ff at octo.it>
   **/
  
+ #include <math.h>
+ #include <limits.h>
  #include "collectd.h"
  #include "plugin.h"
  #include "utils_latency.h"
  #include "common.h"
  
- #include <math.h>
- #include <limits.h>
  #ifndef LLONG_MAX
  # define LLONG_MAX 9223372036854775807LL
  #endif
@@@ -76,7 -76,7 +76,7 @@@ struct latency_counter_
  * So, if the required bin width is 300, then new bin width will be 512 as it is
  * the next nearest power of 2.
  */
- void change_bin_width (latency_counter_t *lc, cdtime_t latency) /* {{{ */
static void change_bin_width (latency_counter_t *lc, cdtime_t latency) /* {{{ */
  {
    /* This function is called because the new value is above histogram's range.
     * First find the required bin width:
        CDTIME_T_TO_DOUBLE (new_bin_width));
  } /* }}} void change_bin_width */
  
- latency_counter_t *latency_counter_create () /* {{{ */
+ latency_counter_t *latency_counter_create (void) /* {{{ */
  {
    latency_counter_t *lc;
  
diff --combined src/utils_latency.h
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/utils_latency.h
 - * Copyright (C) 2013  Florian Forster
 + * Copyright (C) 2013       Florian Forster
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
@@@ -30,7 -30,7 +30,7 @@@
  struct latency_counter_s;
  typedef struct latency_counter_s latency_counter_t;
  
- latency_counter_t *latency_counter_create ();
+ latency_counter_t *latency_counter_create (void);
  void latency_counter_destroy (latency_counter_t *lc);
  
  void latency_counter_add (latency_counter_t *lc, cdtime_t latency);
diff --combined src/xmms.c
@@@ -1,27 -1,22 +1,27 @@@
  /**
   * collectd - src/xmms.c
 - * Copyright (C) 2007  Florian octo Forster
 + * Copyright (C) 2007       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 verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   **/
  
  #include "collectd.h"
@@@ -48,7 -43,7 +48,7 @@@ static void cxmms_submit (const char *t
        plugin_dispatch_values (&vl);
  } /* void cxmms_submit */
  
- int cxmms_read (void)
static int cxmms_read (void)
  {
    gint rate;
    gint freq;