Merge branch 'collectd-5.5'
authorFlorian Forster <octo@collectd.org>
Sat, 6 Aug 2016 18:36:21 +0000 (20:36 +0200)
committerFlorian Forster <octo@collectd.org>
Sat, 6 Aug 2016 18:36:21 +0000 (20:36 +0200)
1  2 
src/libcollectdclient/client.c
src/libcollectdclient/collectd/client.h
src/ping.c
src/utils_db_query.c

@@@ -36,6 -36,7 +36,7 @@@
  
  #include <stdlib.h>
  #include <stdio.h>
+ #include <stdarg.h>
  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/socket.h>
    (c)->errbuf[sizeof ((c)->errbuf) - 1] = 0; \
  } while (0)
  
- #if COLLECT_DEBUG
- # define LCC_DEBUG(...) printf (__VA_ARGS__)
- #else
- # define LCC_DEBUG(...) /**/
- #endif
  /*
   * Types
   */
@@@ -118,6 -113,22 +113,22 @@@ typedef struct lcc_response_s lcc_respo
  /*
   * Private functions
   */
+ static int lcc_tracef(char const *format, ...)
+ {
+   va_list ap;
+   int status;
+   char const *trace = getenv (LCC_TRACE_ENV);
+   if (!trace || (strcmp ("", trace) == 0) || (strcmp ("0", trace) == 0))
+     return 0;
+   va_start (ap, format);
+   status = vprintf (format, ap);
+   va_end (ap);
+   return status;
+ }
  /* Even though Posix requires "strerror_r" to return an "int",
   * some systems (e.g. the GNU libc) return a "char *" _and_
   * ignore the second argument ... -tokkee */
@@@ -235,10 -246,12 +246,10 @@@ static void lcc_chomp (char *str) /* {{
  
  static void lcc_response_free (lcc_response_t *res) /* {{{ */
  {
 -  size_t i;
 -
    if (res == NULL)
      return;
  
 -  for (i = 0; i < res->lines_num; i++)
 +  for (size_t i = 0; i < res->lines_num; i++)
      free (res->lines[i]);
    free (res->lines);
    res->lines = NULL;
@@@ -248,7 -261,7 +259,7 @@@ static int lcc_send (lcc_connection_t *
  {
    int status;
  
-   LCC_DEBUG ("send:    --> %s\n", command);
+   lcc_tracef ("send:    --> %s\n", command);
  
    status = fprintf (c->fh, "%s\r\n", command);
    if (status < 0)
  static int lcc_receive (lcc_connection_t *c, /* {{{ */
      lcc_response_t *ret_res)
  {
 -  lcc_response_t res;
 +  lcc_response_t res = { 0 };
    char *ptr;
    char buffer[4096];
    size_t i;
  
 -  memset (&res, 0, sizeof (res));
 -
    /* Read the first line, containing the status and a message */
    ptr = fgets (buffer, sizeof (buffer), c->fh);
    if (ptr == NULL)
      return (-1);
    }
    lcc_chomp (buffer);
-   LCC_DEBUG ("receive: <-- %s\n", buffer);
+   lcc_tracef ("receive: <-- %s\n", buffer);
  
    /* Convert the leading status to an integer and make `ptr' to point to the
     * beginning of the message. */
    ptr = NULL;
    errno = 0;
 -  res.status = strtol (buffer, &ptr, 0);
 +  res.status = (int) strtol (buffer, &ptr, 0);
    if ((errno != 0) || (ptr == &buffer[0]))
    {
      lcc_set_errno (c, errno);
    /* Allocate space for the char-pointers */
    res.lines_num = (size_t) res.status;
    res.status = 0;
 -  res.lines = (char **) malloc (res.lines_num * sizeof (char *));
 +  res.lines = malloc (res.lines_num * sizeof (*res.lines));
    if (res.lines == NULL)
    {
      lcc_set_errno (c, ENOMEM);
        break;
      }
      lcc_chomp (buffer);
-     LCC_DEBUG ("receive: <-- %s\n", buffer);
+     lcc_tracef ("receive: <-- %s\n", buffer);
  
      res.lines[i] = strdup (buffer);
      if (res.lines[i] == NULL)
  static int lcc_sendreceive (lcc_connection_t *c, /* {{{ */
      const char *command, lcc_response_t *ret_res)
  {
 -  lcc_response_t res;
 +  lcc_response_t res = { 0 };
    int status;
  
    if (c->fh == NULL)
    if (status != 0)
      return (status);
  
 -  memset (&res, 0, sizeof (res));
    status = lcc_receive (c, &res);
    if (status == 0)
      memcpy (ret_res, &res, sizeof (*ret_res));
  
  static int lcc_open_unixsocket (lcc_connection_t *c, const char *path) /* {{{ */
  {
 -  struct sockaddr_un sa;
 +  struct sockaddr_un sa = { 0 };
    int fd;
    int status;
  
      return (-1);
    }
  
 -  memset (&sa, 0, sizeof (sa));
    sa.sun_family = AF_UNIX;
    strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1);
  
  static int lcc_open_netsocket (lcc_connection_t *c, /* {{{ */
      const char *addr_orig)
  {
 -  struct addrinfo ai_hints;
    struct addrinfo *ai_res;
 -  struct addrinfo *ai_ptr;
    char addr_copy[NI_MAXHOST];
    char *addr;
    char *port;
    addr_copy[sizeof(addr_copy) - 1] = '\0';
    addr = addr_copy;
  
 -  memset (&ai_hints, 0, sizeof (ai_hints));
 -  ai_hints.ai_flags = 0;
 -#ifdef AI_ADDRCONFIG
 -  ai_hints.ai_flags |= AI_ADDRCONFIG;
 -#endif
 -  ai_hints.ai_family = AF_UNSPEC;
 -  ai_hints.ai_socktype = SOCK_STREAM;
 -
    port = NULL;
    if (*addr == '[') /* IPv6+port format */
    {
      }
    }
  
 -  ai_res = NULL;
 +  struct addrinfo ai_hints = {
 +    .ai_family = AF_UNSPEC,
 +    .ai_flags = AI_ADDRCONFIG,
 +    .ai_socktype = SOCK_STREAM
 +  };
 +
    status = getaddrinfo (addr,
                          port == NULL ? LCC_DEFAULT_PORT : port,
                          &ai_hints, &ai_res);
      return (-1);
    }
  
 -  for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
 +  for (struct addrinfo *ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
    {
      fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
      if (fd < 0)
@@@ -573,9 -595,10 +584,9 @@@ int lcc_connect (const char *address, l
    if (ret_con == NULL)
      return (-1);
  
 -  c = (lcc_connection_t *) malloc (sizeof (*c));
 +  c = calloc (1, sizeof (*c));
    if (c == NULL)
      return (-1);
 -  memset (c, 0, sizeof (*c));
  
    status = lcc_open_socket (c, address);
    if (status != 0)
@@@ -675,14 -698,14 +686,14 @@@ int lcc_getval (lcc_connection_t *c, lc
    /* Allocate space for the values */
    if (ret_values != NULL)
    {
 -    values = (gauge_t *) malloc (values_num * sizeof (*values));
 +    values = malloc (values_num * sizeof (*values));
      if (values == NULL)
        BAIL_OUT (ENOMEM);
    }
  
    if (ret_values_names != NULL)
    {
 -    values_names = (char **) calloc (values_num, sizeof (*values_names));
 +    values_names = calloc (values_num, sizeof (*values_names));
      if (values_names == NULL)
        BAIL_OUT (ENOMEM);
    }
@@@ -738,6 -761,7 +749,6 @@@ int lcc_putval (lcc_connection_t *c, co
    char command[1024] = "";
    lcc_response_t res;
    int status;
 -  size_t i;
  
    if ((c == NULL) || (vl == NULL) || (vl->values_len < 1)
        || (vl->values == NULL) || (vl->values_types == NULL))
    else
      SSTRCAT (command, " N");
  
 -  for (i = 0; i < vl->values_len; i++)
 +  for (size_t i = 0; i < vl->values_len; i++)
    {
      if (vl->values_types[i] == LCC_TYPE_COUNTER)
        SSTRCATF (command, ":%"PRIu64, vl->values[i].counter);
@@@ -854,6 -878,7 +865,6 @@@ int lcc_listval (lcc_connection_t *c, /
      lcc_identifier_t **ret_ident, size_t *ret_ident_num)
  {
    lcc_response_t res;
 -  size_t i;
    int status;
  
    lcc_identifier_t *ident;
    }
  
    ident_num = res.lines_num;
 -  ident = (lcc_identifier_t *) malloc (ident_num * sizeof (*ident));
 +  ident = malloc (ident_num * sizeof (*ident));
    if (ident == NULL)
    {
      lcc_response_free (&res);
      return (-1);
    }
  
 -  for (i = 0; i < res.lines_num; i++)
 +  for (size_t i = 0; i < res.lines_num; i++)
    {
      char *time_str;
      char *ident_str;
@@@ -1049,11 -1074,9 +1060,11 @@@ int lcc_string_to_identifier (lcc_conne
    return (0);
  } /* }}} int lcc_string_to_identifier */
  
 -int lcc_identifier_compare (const lcc_identifier_t *i0, /* {{{ */
 -    const lcc_identifier_t *i1)
 +int lcc_identifier_compare (const void *a, /* {{{ */
 +    const void *b)
  {
 +  const lcc_identifier_t *i0 = a;
 +  const lcc_identifier_t *i1 = b;
    int status;
  
    if ((i0 == NULL) && (i1 == NULL))
@@@ -1090,7 -1113,7 +1101,7 @@@ int lcc_sort_identifiers (lcc_connectio
    }
  
    qsort (idents, idents_num, sizeof (*idents),
 -      (void *) lcc_identifier_compare);
 +      lcc_identifier_compare);
    return (0);
  } /* }}} int lcc_sort_identifiers */
  
  
  #include "lcc_features.h"
  
+ /* COLLECTD_TRACE is the environment variable used to control trace output. When
+  * set to something non-zero, all lines sent to / received from the daemon are
+  * printed to STDOUT. */
+ #ifndef LCC_TRACE_ENV
+ # define LCC_TRACE_ENV "COLLECTD_TRACE"
+ #endif
  /*
   * Includes (for data types)
   */
@@@ -124,8 -131,8 +131,8 @@@ int lcc_string_to_identifier (lcc_conne
  /* Compares the identifiers "i0" and "i1" and returns less than zero or greater
   * than zero if "i0" is smaller than or greater than "i1", respectively. If
   * "i0" and "i1" are identical, zero is returned. */
 -int lcc_identifier_compare (const lcc_identifier_t *i0,
 -    const lcc_identifier_t *i1);
 +int lcc_identifier_compare (const void *i0,
 +    const void *i1);
  int lcc_sort_identifiers (lcc_connection_t *c,
      lcc_identifier_t *idents, size_t idents_num);
  
diff --combined src/ping.c
   **/
  
  #include "collectd.h"
 +
  #include "common.h"
  #include "plugin.h"
  #include "configfile.h"
  #include "utils_complain.h"
  
 -#include <pthread.h>
  #include <netinet/in.h>
  #if HAVE_NETDB_H
  # include <netdb.h> /* NI_MAXHOST */
@@@ -73,7 -73,6 +73,7 @@@ static char  *ping_source = NULL
  #ifdef HAVE_OPING_1_3
  static char  *ping_device = NULL;
  #endif
 +static char  *ping_data = NULL;
  static int    ping_ttl = PING_DEF_TTL;
  static double ping_interval = 1.0;
  static double ping_timeout = 0.9;
@@@ -92,7 -91,6 +92,7 @@@ static const char *config_keys[] 
  #ifdef HAVE_OPING_1_3
    "Device",
  #endif
 +  "Size",
    "TTL",
    "Interval",
    "Timeout",
@@@ -152,10 -150,11 +152,10 @@@ static void time_calc (struct timespec 
  
  static int ping_dispatch_all (pingobj_t *pingobj) /* {{{ */
  {
 -  pingobj_iter_t *iter;
    hostlist_t *hl;
    int status;
  
 -  for (iter = ping_iterator_get (pingobj);
 +  for (pingobj_iter_t *iter = ping_iterator_get (pingobj);
        iter != NULL;
        iter = ping_iterator_next (iter))
    { /* {{{ */
        hl->pkg_missed++;
  
      /* if the host did not answer our last N packages, trigger a resolv. */
 -    if (ping_max_missed >= 0 && hl->pkg_missed >= ping_max_missed)
 +    if ((ping_max_missed >= 0)
 +        && (hl->pkg_missed >= ((uint32_t) ping_max_missed)))
      { /* {{{ */
        /* we reset the missed package counter here, since we only want to
         * trigger a resolv every N packages and not every package _AFTER_ N
@@@ -250,6 -248,7 +250,6 @@@ static void *ping_thread (void *arg) /
    struct timespec ts_wait;
    struct timespec ts_int;
  
 -  hostlist_t *hl;
    int count;
  
    c_complain_t complaint = C_COMPLAIN_INIT_STATIC;
    ping_setopt (pingobj, PING_OPT_TIMEOUT, (void *) &ping_timeout);
    ping_setopt (pingobj, PING_OPT_TTL, (void *) &ping_ttl);
  
 +  if (ping_data != NULL)
 +    ping_setopt (pingobj, PING_OPT_DATA, (void *) ping_data);
 +
    /* Add all the hosts to the ping object. */
    count = 0;
 -  for (hl = hostlist_head; hl != NULL; hl = hl->next)
 +  for (hostlist_t *hl = hostlist_head; hl != NULL; hl = hl->next)
    {
      int tmp_status;
      tmp_status = ping_host_add (pingobj, hl->host);
@@@ -383,7 -379,7 +383,7 @@@ static int start_thread (void) /* {{{ *
    if (ping_thread_loop != 0)
    {
      pthread_mutex_unlock (&ping_lock);
-     return (-1);
+     return (0);
    }
  
    ping_thread_loop = 1;
@@@ -448,10 -444,7 +448,7 @@@ static int ping_init (void) /* {{{ *
          "Will use a timeout of %gs.", ping_timeout);
    }
  
-   if (start_thread () != 0)
-     return (-1);
-   return (0);
+   return (start_thread ());
  } /* }}} int ping_init */
  
  static int config_set_string (const char *name, /* {{{ */
@@@ -481,7 -474,7 +478,7 @@@ static int ping_config (const char *key
      hostlist_t *hl;
      char *host;
  
 -    hl = (hostlist_t *) malloc (sizeof (hostlist_t));
 +    hl = malloc (sizeof (*hl));
      if (hl == NULL)
      {
        char errbuf[1024];
        WARNING ("ping plugin: Ignoring invalid interval %g (%s)",
            tmp, value);
    }
 +  else if (strcasecmp (key, "Size") == 0) {
 +    size_t size = (size_t) atoi (value);
 +
 +    /* Max IP packet size - (IPv6 + ICMP) = 65535 - (40 + 8) = 65487 */
 +    if (size <= 65487)
 +    {
 +      sfree (ping_data);
 +      ping_data = malloc (size + 1);
 +      if (ping_data == NULL)
 +      {
 +        ERROR ("ping plugin: malloc failed.");
 +        return (1);
 +      }
 +
 +      /* Note: By default oping is using constant string
 +       * "liboping -- ICMP ping library <http://octo.it/liboping/>"
 +       * which is exactly 56 bytes.
 +       *
 +       * Optimally we would follow the ping(1) behaviour, but we
 +       * cannot use byte 00 or start data payload at exactly same
 +       * location, due to oping library limitations. */
 +      for (size_t i = 0; i < size; i++) /* {{{ */
 +      {
 +        /* This restricts data pattern to be only composed of easily
 +         * printable characters, and not NUL character. */
 +        ping_data[i] = ('0' + i % 64);
 +      }  /* }}} for (i = 0; i < size; i++) */
 +      ping_data[size] = 0;
 +    } else
 +      WARNING ("ping plugin: Ignoring invalid Size %zu.", size);
 +  }
    else if (strcasecmp (key, "Timeout") == 0)
    {
      double tmp;
@@@ -619,13 -581,15 +616,13 @@@ static void submit (const char *host, c
  
  static int ping_read (void) /* {{{ */
  {
 -  hostlist_t *hl;
 -
    if (ping_thread_error != 0)
    {
      ERROR ("ping plugin: The ping thread had a problem. Restarting it.");
  
      stop_thread ();
  
 -    for (hl = hostlist_head; hl != NULL; hl = hl->next)
 +    for (hostlist_t *hl = hostlist_head; hl != NULL; hl = hl->next)
      {
        hl->pkg_sent = 0;
        hl->pkg_recv = 0;
      return (-1);
    } /* if (ping_thread_error != 0) */
  
 -  for (hl = hostlist_head; hl != NULL; hl = hl->next) /* {{{ */
 +  for (hostlist_t *hl = hostlist_head; hl != NULL; hl = hl->next) /* {{{ */
    {
      uint32_t pkg_sent;
      uint32_t pkg_recv;
@@@ -722,11 -686,6 +719,11 @@@ static int ping_shutdown (void) /* {{{ 
      hl = hl_next;
    }
  
 +  if (ping_data != NULL) {
 +    free (ping_data);
 +    ping_data = NULL;
 +  }
 +
    return (0);
  } /* }}} int ping_shutdown */
  
diff --combined src/utils_db_query.c
@@@ -25,7 -25,6 +25,7 @@@
   **/
  
  #include "collectd.h"
 +
  #include "common.h"
  #include "plugin.h"
  #include "configfile.h"
@@@ -55,7 -54,6 +55,7 @@@ struct udb_query_s /* {{{ *
    char *name;
    char *statement;
    void *user_data;
 +  char *plugin_instance_from;
  
    unsigned int min_version;
    unsigned int max_version;
@@@ -72,7 -70,6 +72,7 @@@ struct udb_result_preparation_area_s /
    char  **instances_buffer;
    char  **values_buffer;
    char  **metadata_buffer;
 +  char   *plugin_instance;
  
    struct udb_result_preparation_area_s *next;
  }; /* }}} */
@@@ -81,7 -78,6 +81,7 @@@ typedef struct udb_result_preparation_a
  struct udb_query_preparation_area_s /* {{{ */
  {
    size_t column_num;
 +  size_t plugin_instance_pos;
    char *host;
    char *plugin;
    char *db_name;
@@@ -126,6 -122,7 +126,6 @@@ static int udb_config_add_string (char 
  {
    char **array;
    size_t array_len;
 -  int i;
  
    if (ci->values_num < 1)
    {
      return (-1);
    }
  
 -  for (i = 0; i < ci->values_num; i++)
 +  for (int i = 0; i < ci->values_num; i++)
    {
      if (ci->values[i].type != OCONFIG_TYPE_STRING)
      {
    }
  
    array_len = *ret_array_len;
 -  array = (char **) realloc (*ret_array,
 +  array = realloc (*ret_array,
        sizeof (char *) * (array_len + ci->values_num));
    if (array == NULL)
    {
    }
    *ret_array = array;
  
 -  for (i = 0; i < ci->values_num; i++)
 +  for (int i = 0; i < ci->values_num; i++)
    {
      array[array_len] = strdup (ci->values[i].value.string);
      if (array[array_len] == NULL)
@@@ -199,6 -196,7 +199,6 @@@ static int udb_result_submit (udb_resul
      udb_query_t const *q, udb_query_preparation_area_t *q_area)
  {
    value_list_t vl = VALUE_LIST_INIT;
 -  size_t i;
    int status;
  
    assert (r != NULL);
    assert (((size_t) r_area->ds->ds_num) == r->values_num);
    assert (r->values_num > 0);
  
 -  vl.values = (value_t *) calloc (r->values_num, sizeof (value_t));
 +  vl.values = calloc (r->values_num, sizeof (*vl.values));
    if (vl.values == NULL)
    {
 -    ERROR ("db query utils: malloc failed.");
 +    ERROR ("db query utils: calloc failed.");
      return (-1);
    }
    vl.values_len = r_area->ds->ds_num;
  
 -  for (i = 0; i < r->values_num; i++)
 +  for (size_t i = 0; i < r->values_num; i++)
    {
      char *value_str = r_area->values_buffer[i];
  
        ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
            value_str, DS_TYPE_TO_STRING (r_area->ds->ds[i].type));
        errno = EINVAL;
 +      free (vl.values);
        return (-1);
      }
    }
  
    sstrncpy (vl.host, q_area->host, sizeof (vl.host));
    sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
 -  sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
    sstrncpy (vl.type, r->type, sizeof (vl.type));
  
 +  /* Set vl.plugin_instance */
 +  if (q->plugin_instance_from != NULL) {
 +    sstrncpy (vl.plugin_instance, r_area->plugin_instance, sizeof (vl.plugin_instance));
 +  }
 +  else {
 +    sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
 +  }
 +
    /* Set vl.type_instance {{{ */
 -  if (r->instances_num <= 0)
 +  if (r->instances_num == 0)
    {
      if (r->instance_prefix == NULL)
        vl.type_instance[0] = 0;
    {
      if (r->instance_prefix == NULL)
      {
-       strjoin (vl.type_instance, sizeof (vl.type_instance),
+       int status = strjoin (vl.type_instance, sizeof (vl.type_instance),
            r_area->instances_buffer, r->instances_num, "-");
+       if (status != 0)
+       {
+         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
+             status);
+         return (status);
+       }
      }
      else
      {
        char tmp[DATA_MAX_NAME_LEN];
  
-       strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
+       int status = strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
            r->instances_num, "-");
+       if (status != 0)
+       {
+         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
+             status);
+         return (status);
+       }
        tmp[sizeof (tmp) - 1] = 0;
  
        snprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
        return (-ENOMEM);
      }
  
 -    for (i = 0; i < r->metadata_num; i++)
 +    for (size_t i = 0; i < r->metadata_num; i++)
      {
        status = meta_data_add_string (vl.meta, r->metadata[i],
            r_area->metadata_buffer[i]);
@@@ -330,20 -332,19 +342,20 @@@ static int udb_result_handle_result (ud
      udb_result_preparation_area_t *r_area,
      udb_query_t const *q, char **column_values)
  {
 -  size_t i;
 -
    assert (r && q_area && r_area);
  
 -  for (i = 0; i < r->instances_num; i++)
 +  for (size_t i = 0; i < r->instances_num; i++)
      r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
  
 -  for (i = 0; i < r->values_num; i++)
 +  for (size_t 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++)
 +  for (size_t i = 0; i < r->metadata_num; i++)
      r_area->metadata_buffer[i] = column_values[r_area->metadata_pos[i]];
  
 +  if (q->plugin_instance_from)
 +    r_area->plugin_instance = column_values[q_area->plugin_instance_pos];
 +
    return udb_result_submit (r, r_area, q, q_area);
  } /* }}} int udb_result_handle_result */
  
@@@ -351,6 -352,8 +363,6 @@@ static int udb_result_prepare_result (u
      udb_result_preparation_area_t *prep_area,
      char **column_names, size_t column_num)
  {
 -  size_t i;
 -
    if ((r == NULL) || (prep_area == NULL))
      return (-EINVAL);
  
      BAIL_OUT (-1);
    }
  
 -  if (((size_t) prep_area->ds->ds_num) != r->values_num)
 +  if (prep_area->ds->ds_num != r->values_num)
    {
      ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
 -        "requires exactly %i value%s, but the configuration specifies %zu.",
 +        "requires exactly %zu value%s, but the configuration specifies %zu.",
          r->type,
          prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
          r->values_num);
        = (size_t *) calloc (r->instances_num, sizeof (size_t));
      if (prep_area->instances_pos == NULL)
      {
 -      ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +      ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
        BAIL_OUT (-ENOMEM);
      }
  
        = (char **) calloc (r->instances_num, sizeof (char *));
      if (prep_area->instances_buffer == NULL)
      {
 -      ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +      ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
        BAIL_OUT (-ENOMEM);
      }
    } /* if (r->instances_num > 0) */
      = (size_t *) calloc (r->values_num, sizeof (size_t));
    if (prep_area->values_pos == NULL)
    {
 -    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
      BAIL_OUT (-ENOMEM);
    }
  
      = (char **) calloc (r->values_num, sizeof (char *));
    if (prep_area->values_buffer == NULL)
    {
 -    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
      BAIL_OUT (-ENOMEM);
    }
  
      = (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.");
 +    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
      BAIL_OUT (-ENOMEM);
    }
  
      = (char **) calloc (r->metadata_num, sizeof (char *));
    if (prep_area->metadata_buffer == NULL)
    {
 -    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
 +    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
      BAIL_OUT (-ENOMEM);
    }
  
    /* }}} */
  
 -  /* Determine the position of the instance columns {{{ */
 -  for (i = 0; i < r->instances_num; i++)
 +  /* Determine the position of the plugin instance column {{{ */
 +  for (size_t i = 0; i < r->instances_num; i++)
    {
      size_t j;
  
      }
    } /* }}} for (i = 0; i < r->instances_num; i++) */
  
 +
    /* Determine the position of the value columns {{{ */
 -  for (i = 0; i < r->values_num; i++)
 +  for (size_t i = 0; i < r->values_num; i++)
    {
      size_t j;
  
    } /* }}} for (i = 0; i < r->values_num; i++) */
  
    /* Determine the position of the metadata columns {{{ */
 -  for (i = 0; i < r->metadata_num; i++)
 +  for (size_t i = 0; i < r->metadata_num; i++)
    {
      size_t j;
  
  
  static void udb_result_free (udb_result_t *r) /* {{{ */
  {
 -  size_t i;
 -
    if (r == NULL)
      return;
  
    sfree (r->type);
 +  sfree (r->instance_prefix);
  
 -  for (i = 0; i < r->instances_num; i++)
 +  for (size_t i = 0; i < r->instances_num; i++)
      sfree (r->instances[i]);
    sfree (r->instances);
  
 -  for (i = 0; i < r->values_num; i++)
 +  for (size_t i = 0; i < r->values_num; i++)
      sfree (r->values[i]);
    sfree (r->values);
  
 -  for (i = 0; i < r->metadata_num; i++)
 +  for (size_t i = 0; i < r->metadata_num; i++)
      sfree (r->metadata[i]);
    sfree (r->metadata);
  
@@@ -550,6 -553,7 +562,6 @@@ static int udb_result_create (const cha
  {
    udb_result_t *r;
    int status;
 -  int i;
  
    if (ci->values_num != 0)
    {
          ci->values_num, (ci->values_num == 1) ? "" : "s");
    }
  
 -  r = (udb_result_t *) malloc (sizeof (*r));
 +  r = calloc (1, sizeof (*r));
    if (r == NULL)
    {
 -    ERROR ("db query utils: malloc failed.");
 +    ERROR ("db query utils: calloc failed.");
      return (-1);
    }
 -  memset (r, 0, sizeof (*r));
    r->type = NULL;
    r->instance_prefix = NULL;
    r->instances = NULL;
  
    /* Fill the `udb_result_t' structure.. */
    status = 0;
 -  for (i = 0; i < ci->children_num; i++)
 +  for (int i = 0; i < ci->children_num; i++)
    {
      oconfig_item_t *child = ci->children + i;
  
@@@ -652,7 -657,6 +664,7 @@@ static void udb_query_free_one (udb_que
  
    sfree (q->name);
    sfree (q->statement);
 +  sfree (q->plugin_instance_from);
  
    udb_result_free (q->results);
  
@@@ -671,6 -675,7 +683,6 @@@ int udb_query_create (udb_query_t ***re
  
    udb_query_t *q;
    int status;
 -  int i;
  
    if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
      return (-EINVAL);
      return (-1);
    }
  
 -  q = (udb_query_t *) malloc (sizeof (*q));
 +  q = calloc (1, sizeof (*q));
    if (q == NULL)
    {
 -    ERROR ("db query utils: malloc failed.");
 +    ERROR ("db query utils: calloc failed.");
      return (-1);
    }
 -  memset (q, 0, sizeof (*q));
    q->min_version = 0;
    q->max_version = UINT_MAX;
 +  q->statement = NULL;
 +  q->results = NULL;
 +  q->plugin_instance_from = NULL;
  
    status = udb_config_set_string (&q->name, ci);
    if (status != 0)
    }
  
    /* Fill the `udb_query_t' structure.. */
 -  for (i = 0; i < ci->children_num; i++)
 +  for (int i = 0; i < ci->children_num; i++)
    {
      oconfig_item_t *child = ci->children + i;
  
        status = udb_config_set_uint (&q->min_version, child);
      else if (strcasecmp ("MaxVersion", child->key) == 0)
        status = udb_config_set_uint (&q->max_version, child);
 +    else if (strcasecmp ("PluginInstanceFrom", child->key) == 0)
 +      status = udb_config_set_string (&q->plugin_instance_from, child);
  
      /* Call custom callbacks */
      else if (cb != NULL)
    {
      udb_query_t **temp;
  
 -    temp = (udb_query_t **) realloc (query_list,
 +    temp = realloc (query_list,
          sizeof (*query_list) * (query_list_len + 1));
      if (temp == NULL)
      {
  
  void udb_query_free (udb_query_t **query_list, size_t query_list_len) /* {{{ */
  {
 -  size_t i;
 -
    if (query_list == NULL)
      return;
  
 -  for (i = 0; i < query_list_len; i++)
 +  for (size_t i = 0; i < query_list_len; i++)
      udb_query_free_one (query_list[i]);
  
    sfree (query_list);
@@@ -805,6 -808,7 +817,6 @@@ int udb_query_pick_from_list_by_name (c
      udb_query_t **src_list, size_t src_list_len,
      udb_query_t ***dst_list, size_t *dst_list_len)
  {
 -  size_t i;
    int num_added;
  
    if ((name == NULL) || (src_list == NULL) || (dst_list == NULL)
    }
  
    num_added = 0;
 -  for (i = 0; i < src_list_len; i++)
 +  for (size_t i = 0; i < src_list_len; i++)
    {
      udb_query_t **tmp_list;
      size_t tmp_list_len;
        continue;
  
      tmp_list_len = *dst_list_len;
 -    tmp_list = (udb_query_t **) realloc (*dst_list, (tmp_list_len + 1)
 +    tmp_list = realloc (*dst_list, (tmp_list_len + 1)
          * sizeof (udb_query_t *));
      if (tmp_list == NULL)
      {
@@@ -977,7 -981,9 +989,7 @@@ int udb_query_handle_result (udb_query_
  #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
    do
    {
 -    size_t i;
 -
 -    for (i = 0; i < prep_area->column_num; i++)
 +    for (size_t i = 0; i < prep_area->column_num; i++)
      {
        DEBUG ("db query utils: udb_query_handle_result (%s, %s): "
            "column[%zu] = %s;",
@@@ -1038,7 -1044,9 +1050,7 @@@ int udb_query_prepare_result (udb_query
  #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
    do
    {
 -    size_t i;
 -
 -    for (i = 0; i < column_num; i++)
 +    for (size_t i = 0; i < column_num; i++)
      {
        DEBUG ("db query utils: udb_query_prepare_result: "
            "query = %s; column[%zu] = %s;",
    } while (0);
  #endif
  
 +  /* Determine the position of the PluginInstance column {{{ */
 +  if (q->plugin_instance_from != NULL)
 +  {
 +    size_t i;
 +
 +    for (i = 0; i < column_num; i++)
 +    {
 +      if (strcasecmp (q->plugin_instance_from, column_names[i]) == 0)
 +      {
 +        prep_area->plugin_instance_pos = i;
 +        break;
 +      }
 +    }
 +
 +    if (i >= column_num)
 +    {
 +      ERROR ("db query utils: udb_query_prepare_result: "
 +          "Column `%s' from `PluginInstanceFrom' could not be found.",
 +          q->plugin_instance_from);
 +      udb_query_finish_result (q, prep_area);
 +      return (-ENOENT);
 +    }
 +  }
 +  /* }}} */
 +
    for (r = q->results, r_area = prep_area->result_prep_areas;
        r != NULL; r = r->next, r_area = r_area->next)
    {
@@@ -1101,16 -1084,17 +1113,16 @@@ udb_query_allocate_preparation_area (ud
    udb_result_preparation_area_t **next_r_area;
    udb_result_t *r;
  
 -  q_area = malloc (sizeof (*q_area));
 +  q_area = calloc (1, sizeof (*q_area));
    if (q_area == NULL)
      return NULL;
 -  memset (q_area, 0, sizeof (*q_area));
  
    next_r_area = &q_area->result_prep_areas;
    for (r = q->results; r != NULL; r = r->next)
    {
      udb_result_preparation_area_t *r_area;
  
 -    r_area = malloc (sizeof (*r_area));
 +    r_area = calloc (1, sizeof (*r_area));
      if (r_area == NULL)
      {
        udb_result_preparation_area_t *a = q_area->result_prep_areas;
        return NULL;
      }
  
 -    memset (r_area, 0, sizeof (*r_area));
 -
      *next_r_area = r_area;
      next_r_area  = &r_area->next;
    }