Merge branch 'collectd-5.5' into collectd-5.6
authorFlorian Forster <octo@collectd.org>
Fri, 7 Oct 2016 06:51:29 +0000 (08:51 +0200)
committerFlorian Forster <octo@collectd.org>
Fri, 7 Oct 2016 06:51:29 +0000 (08:51 +0200)
1  2 
contrib/examples/myplugin.c
src/daemon/common.c
src/rrdcached.c
src/vserver.c

@@@ -39,7 -39,6 +39,7 @@@
  #endif /* ! HAVE_CONFIG */
  
  #include <collectd/collectd.h>
 +
  #include <collectd/common.h>
  #include <collectd/plugin.h>
  
@@@ -104,7 -103,7 +104,7 @@@ static int my_read (void
  
        /* it is strongly recommended to use a type defined in the types.db file
         * instead of a custom type */
-       sstrncpy (vl.type, "myplugin", sizeof (vl.plugin));
+       sstrncpy (vl.type, "myplugin", sizeof (vl.type));
        /* optionally set vl.plugin_instance and vl.type_instance to reasonable
         * values (default: "") */
  
  
        /* A return value != 0 indicates an error and the plugin will be skipped
         * for an increasing amount of time. */
-     return 0;
+       return 0;
  } /* static int my_read (void) */
  
  /*
diff --combined src/daemon/common.c
  #endif
  
  #include "collectd.h"
 +
  #include "common.h"
  #include "plugin.h"
  #include "utils_cache.h"
  
 -#if HAVE_PTHREAD_H
 -# include <pthread.h>
 -#endif
 -
  #ifdef HAVE_MATH_H
  # include <math.h>
  #endif
  
  /* for getaddrinfo */
  #include <sys/types.h>
 -#include <sys/socket.h>
  #include <netdb.h>
  
  #include <poll.h>
  # include <netinet/in.h>
  #endif
  
 +#if HAVE_NETINET_TCP_H
 +# include <netinet/tcp.h>
 +#endif
 +
  /* for ntohl and htonl */
  #if HAVE_ARPA_INET_H
  # include <arpa/inet.h>
  #endif
  
 +#ifdef HAVE_SYS_CAPABILITY_H
 +# include <sys/capability.h>
 +#endif
 +
  #ifdef HAVE_LIBKSTAT
  extern kstat_ctl_t *kc;
  #endif
@@@ -120,9 -116,10 +120,9 @@@ char *ssnprintf_alloc (char const *form
                return (strdup (static_buffer));
  
        /* Allocate a buffer large enough to hold the string. */
 -      alloc_buffer = malloc (alloc_buffer_size);
 +      alloc_buffer = calloc (1, alloc_buffer_size);
        if (alloc_buffer == NULL)
                return (NULL);
 -      memset (alloc_buffer, 0, alloc_buffer_size);
  
        /* Print again into this new buffer. */
        va_start (ap, format);
@@@ -148,7 -145,7 +148,7 @@@ char *sstrdup (const char *s
        /* Do not use `strdup' here, because it's not specified in POSIX. It's
         * ``only'' an XSI extension. */
        sz = strlen (s) + 1;
 -      r = (char *) malloc (sizeof (char) * sz);
 +      r = malloc (sz);
        if (r == NULL)
        {
                ERROR ("sstrdup: Out of memory.");
@@@ -262,8 -259,8 +262,8 @@@ ssize_t sread (int fd, void *buf, size_
  
                assert ((0 > status) || (nleft >= (size_t)status));
  
 -              nleft = nleft - status;
 -              ptr   = ptr   + status;
 +              nleft = nleft - ((size_t) status);
 +              ptr   = ptr   + ((size_t) status);
        }
  
        return (0);
@@@ -280,9 -277,6 +280,9 @@@ ssize_t swrite (int fd, const void *buf
        ptr   = (const char *) buf;
        nleft = count;
        
 +      if (fd < 0)
 +              return (-1);
 +
        /* checking for closed peer connection */
        pfd.fd = fd;
        pfd.events = POLLIN | POLLHUP;
                if (status < 0)
                        return (status);
  
 -              nleft = nleft - status;
 -              ptr   = ptr   + status;
 +              nleft = nleft - ((size_t) status);
 +              ptr   = ptr   + ((size_t) status);
        }
  
        return (0);
@@@ -341,8 -335,9 +341,8 @@@ int strjoin (char *buffer, size_t buffe
        size_t avail;
        char *ptr;
        size_t sep_len;
 -      size_t i;
  
 -      if ((buffer_size < 1) || (fields_num <= 0))
 +      if ((buffer_size < 1) || (fields_num == 0))
                return (-1);
  
        memset (buffer, 0, buffer_size);
        if (sep != NULL)
                sep_len = strlen (sep);
  
 -      for (i = 0; i < fields_num; i++)
 +      for (size_t i = 0; i < fields_num; i++)
        {
                size_t field_len;
  
        }
  
        assert (buffer[buffer_size - 1] == 0);
 -      return (strlen (buffer));
 +      return ((int) strlen (buffer));
  }
  
 -int strsubstitute (char *str, char c_from, char c_to)
 -{
 -      int ret;
 -
 -      if (str == NULL)
 -              return (-1);
 -
 -      ret = 0;
 -      while (*str != '\0')
 -      {
 -              if (*str == c_from)
 -              {
 -                      *str = c_to;
 -                      ret++;
 -              }
 -              str++;
 -      }
 -
 -      return (ret);
 -} /* int strsubstitute */
 -
  int escape_string (char *buffer, size_t buffer_size)
  {
    char *temp;
 -  size_t i;
    size_t j;
  
    /* Check if we need to escape at all first */
    if (buffer_size < 3)
      return (EINVAL);
  
 -  temp = (char *) malloc (buffer_size);
 +  temp = calloc (1, buffer_size);
    if (temp == NULL)
      return (ENOMEM);
 -  memset (temp, 0, buffer_size);
  
    temp[0] = '"';
    j = 1;
  
 -  for (i = 0; i < buffer_size; i++)
 +  for (size_t i = 0; i < buffer_size; i++)
    {
      if (buffer[i] == 0)
      {
  
  int strunescape (char *buf, size_t buf_len)
  {
 -      size_t i;
 -
 -      for (i = 0; (i < buf_len) && (buf[i] != '\0'); ++i)
 +      for (size_t i = 0; (i < buf_len) && (buf[i] != '\0'); ++i)
        {
                if (buf[i] != '\\')
                        continue;
@@@ -487,6 -507,7 +487,6 @@@ size_t strstripnewline (char *buffer
  
  int escape_slashes (char *buffer, size_t buffer_size)
  {
 -      int i;
        size_t buffer_len;
  
        buffer_len = strlen (buffer);
                buffer_len--;
        }
  
 -      for (i = 0; i < buffer_len; i++)
 +      for (size_t i = 0; i < buffer_len; i++)
        {
                if (buffer[i] == '/')
                        buffer[i] = '_';
  
  void replace_special (char *buffer, size_t buffer_size)
  {
 -      size_t i;
 -
 -      for (i = 0; i < buffer_size; i++)
 +      for (size_t i = 0; i < buffer_size; i++)
        {
                if (buffer[i] == 0)
                        return;
@@@ -594,6 -617,7 +594,6 @@@ int check_create_dir (const char *file_
        int   last_is_file = 1;
        int   path_is_absolute = 0;
        size_t len;
 -      int   i;
  
        /*
         * Sanity checks first
        /*
         * For each component, do..
         */
 -      for (i = 0; i < (fields_num - last_is_file); i++)
 +      for (int i = 0; i < (fields_num - last_is_file); i++)
        {
                /*
                 * Do not create directories that start with a dot. This
                 * Join the components together again
                 */
                dir[0] = '/';
 -              if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
 -                                      fields, i + 1, "/") < 0)
 +              if (strjoin (dir + path_is_absolute, (size_t) (dir_len - path_is_absolute),
 +                                      fields, (size_t) (i + 1), "/") < 0)
                {
                        ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
                        return (-1);
@@@ -938,6 -962,7 +938,6 @@@ int format_values (char *ret, size_t re
  {
          size_t offset = 0;
          int status;
 -        int i;
          gauge_t *rates = NULL;
  
          assert (0 == strcmp (ds->type, vl->type));
  
          BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
  
 -        for (i = 0; i < ds->ds_num; i++)
 +        for (size_t i = 0; i < ds->ds_num; i++)
          {
                  if (ds->ds[i].type == DS_TYPE_GAUGE)
                          BUFFER_ADD (":"GAUGE_FORMAT, vl->values[i].gauge);
@@@ -1124,7 -1149,7 +1124,7 @@@ int parse_value (const char *value_orig
    }
  
    if (value == endptr) {
-     ERROR ("parse_value: Failed to parse string as %s: %s.",
+     ERROR ("parse_value: Failed to parse string as %s: \"%s\".",
          DS_TYPE_TO_STRING (ds_type), value);
      sfree (value);
      return -1;
  
  int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
  {
 -      int i;
 +      size_t i;
        char *dummy;
        char *ptr;
        char *saveptr;
        if ((buffer == NULL) || (vl == NULL) || (ds == NULL))
                return EINVAL;
  
 -      i = -1;
 +      i = 0;
        dummy = buffer;
        saveptr = NULL;
 +      vl->time = 0;
        while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
        {
                dummy = NULL;
                if (i >= vl->values_len)
                {
                        /* Make sure i is invalid. */
 -                      i = vl->values_len + 1;
 +                      i = 0;
                        break;
                }
  
 -              if (i == -1)
 +              if (vl->time == 0)
                {
                        if (strcmp ("N", ptr) == 0)
                                vl->time = cdtime ();
  
                                vl->time = DOUBLE_TO_CDTIME_T (tmp);
                        }
 +
 +                      continue;
                }
 -              else
 -              {
 -                      if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
 -                              vl->values[i].gauge = NAN;
 -                      else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
 -                              return -1;
 -              }
 +
 +              if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
 +                      vl->values[i].gauge = NAN;
 +              else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
 +                      return -1;
  
                i++;
        } /* while (strtok_r) */
  
 -      if ((ptr != NULL) || (i != vl->values_len))
 +      if ((ptr != NULL) || (i == 0))
                return (-1);
        return (0);
  } /* int parse_values */
@@@ -1356,9 -1380,10 +1356,9 @@@ counter_t counter_diff (counter_t old_v
        if (old_value > new_value)
        {
                if (old_value <= 4294967295U)
 -                      diff = (4294967295U - old_value) + new_value;
 +                      diff = (4294967295U - old_value) + new_value + 1;
                else
 -                      diff = (18446744073709551615ULL - old_value)
 -                              + new_value;
 +                      diff = (18446744073709551615ULL - old_value) + new_value + 1;
        }
        else
        {
@@@ -1463,10 -1488,11 +1463,10 @@@ int rate_to_value (value_t *ret_value, 
        return (0);
  } /* }}} value_t rate_to_value */
  
 -int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
 -              value_to_rate_state_t *state,
 -              int ds_type, cdtime_t t)
 +int value_to_rate (gauge_t *ret_rate, /* {{{ */
 +              value_t value, int ds_type, cdtime_t t, value_to_rate_state_t *state)
  {
 -      double interval;
 +      gauge_t interval;
  
        /* Another invalid state: The time is not increasing. */
        if (t <= state->last_time)
        interval = CDTIME_T_TO_DOUBLE(t - state->last_time);
  
        /* Previous value is invalid. */
 -      if (state->last_time == 0) /* {{{ */
 +      if (state->last_time == 0)
        {
 -              if (ds_type == DS_TYPE_DERIVE)
 -              {
 -                      state->last_value.derive = value;
 -              }
 -              else if (ds_type == DS_TYPE_COUNTER)
 -              {
 -                      state->last_value.counter = (counter_t) value;
 -              }
 -              else if (ds_type == DS_TYPE_ABSOLUTE)
 -              {
 -                      state->last_value.absolute = (absolute_t) value;
 -              }
 -              else
 -              {
 -                      assert (23 == 42);
 -              }
 -
 +              state->last_value = value;
                state->last_time = t;
                return (EAGAIN);
 -      } /* }}} */
 +      }
  
 -      if (ds_type == DS_TYPE_DERIVE)
 -      {
 -              ret_rate->gauge = (value - state->last_value.derive) / interval;
 -              state->last_value.derive = value;
 +      switch (ds_type) {
 +      case DS_TYPE_DERIVE: {
 +              derive_t diff = value.derive - state->last_value.derive;
 +              *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
 +              break;
        }
 -      else if (ds_type == DS_TYPE_COUNTER)
 -      {
 -              ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
 -              state->last_value.counter = (counter_t) value;
 +      case DS_TYPE_GAUGE: {
 +              *ret_rate = value.gauge;
 +              break;
        }
 -      else if (ds_type == DS_TYPE_ABSOLUTE)
 -      {
 -              ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval;
 -              state->last_value.absolute = (absolute_t) value;
 +      case DS_TYPE_COUNTER: {
 +              counter_t diff = counter_diff (state->last_value.counter, value.counter);
 +              *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
 +              break;
        }
 -      else
 -      {
 -              assert (23 == 42);
 +      case DS_TYPE_ABSOLUTE: {
 +              absolute_t diff = value.absolute;
 +              *ret_rate = ((gauge_t) diff) / ((gauge_t) interval);
 +              break;
 +      }
 +      default:
 +              return EINVAL;
        }
  
 -        state->last_time = t;
 +      state->last_value = value;
 +      state->last_time = t;
        return (0);
  } /* }}} value_t rate_to_value */
  
  int service_name_to_port_number (const char *service_name)
  {
        struct addrinfo *ai_list;
 -      struct addrinfo *ai_ptr;
 -      struct addrinfo ai_hints;
        int status;
        int service_number;
  
        if (service_name == NULL)
                return (-1);
  
 -      ai_list = NULL;
 -      memset (&ai_hints, 0, sizeof (ai_hints));
 -      ai_hints.ai_family = AF_UNSPEC;
 +      struct addrinfo ai_hints = {
 +              .ai_family = AF_UNSPEC
 +      };
  
        status = getaddrinfo (/* node = */ NULL, service_name,
                        &ai_hints, &ai_list);
        }
  
        service_number = -1;
 -      for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
 +      for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
        {
                if (ai_ptr->ai_family == AF_INET)
                {
        return (-1);
  } /* int service_name_to_port_number */
  
 +void set_sock_opts (int sockfd) /* {{{ */
 +{
 +      int status;
 +      int socktype;
 +
 +      socklen_t socklen = sizeof (socklen_t);
 +      int so_keepalive = 1;
 +
 +      status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen);
 +      if (status != 0)
 +      {
 +              WARNING ("set_sock_opts: failed to determine socket type");
 +              return;
 +      }
 +
 +      if (socktype == SOCK_STREAM)
 +      {
 +              status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
 +                              &so_keepalive, sizeof (so_keepalive));
 +              if (status != 0)
 +                      WARNING ("set_sock_opts: failed to set socket keepalive flag");
 +
 +#ifdef TCP_KEEPIDLE
 +              int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
 +              status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
 +                              &tcp_keepidle, sizeof (tcp_keepidle));
 +              if (status != 0)
 +                      WARNING ("set_sock_opts: failed to set socket tcp keepalive time");
 +#endif
 +
 +#ifdef TCP_KEEPINTVL
 +              int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1);
 +              status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
 +                              &tcp_keepintvl, sizeof (tcp_keepintvl));
 +              if (status != 0)
 +                      WARNING ("set_sock_opts: failed to set socket tcp keepalive interval");
 +#endif
 +      }
 +} /* }}} void set_sock_opts */
 +
  int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
  {
        derive_t tmp;
@@@ -1668,56 -1667,9 +1668,56 @@@ int strarray_add (char ***ret_array, si
  
  void strarray_free (char **array, size_t array_len) /* {{{ */
  {
 -      size_t i;
 -
 -      for (i = 0; i < array_len; i++)
 +      for (size_t i = 0; i < array_len; i++)
                sfree (array[i]);
        sfree (array);
  } /* }}} void strarray_free */
 +
 +#ifdef HAVE_SYS_CAPABILITY_H
 +int check_capability (int capability) /* {{{ */
 +{
 +#ifdef _LINUX_CAPABILITY_VERSION_3
 +      cap_user_header_t cap_header = calloc(1, sizeof (*cap_header));
 +      if (cap_header == NULL)
 +      {
 +              ERROR("check_capability: calloc failed");
 +              return (-1);
 +      }
 +
 +      cap_user_data_t cap_data = calloc(1, sizeof (*cap_data));
 +      if (cap_data == NULL)
 +      {
 +              ERROR("check_capability: calloc failed");
 +              sfree(cap_header);
 +              return (-1);
 +      }
 +
 +      cap_header->pid = getpid();
 +      cap_header->version = _LINUX_CAPABILITY_VERSION;
 +      if (capget(cap_header, cap_data) < 0)
 +      {
 +              ERROR("check_capability: capget failed");
 +              sfree(cap_header);
 +              sfree(cap_data);
 +              return (-1);
 +      }
 +
 +      if ((cap_data->effective & (1 << capability)) == 0)
 +      {
 +              sfree(cap_header);
 +              sfree(cap_data);
 +              return (-1);
 +      }
 +      else
 +      {
 +              sfree(cap_header);
 +              sfree(cap_data);
 +              return (0);
 +      }
 +#else
 +      WARNING ("check_capability: unsupported capability implementation. "
 +          "Some plugin(s) may require elevated privileges to work properly.");
 +      return (0);
 +#endif /* _LINUX_CAPABILITY_VERSION_3 */
 +} /* }}} int check_capability */
 +#endif /* HAVE_SYS_CAPABILITY_H */
diff --combined src/rrdcached.c
@@@ -25,7 -25,6 +25,7 @@@
   **/
  
  #include "collectd.h"
 +
  #include "plugin.h"
  #include "common.h"
  #include "utils_rrdcreate.h"
@@@ -70,6 -69,7 +70,6 @@@ static int value_list_to_string (char *
  {
    int offset;
    int status;
 -  int i;
    time_t t;
  
    assert (0 == strcmp (ds->type, vl->type));
@@@ -82,7 -82,7 +82,7 @@@
      return (-1);
    offset = status;
  
 -  for (i = 0; i < ds->ds_num; i++)
 +  for (size_t i = 0; i < ds->ds_num; i++)
    {
      if ((ds->ds[i].type != DS_TYPE_COUNTER)
          && (ds->ds[i].type != DS_TYPE_GAUGE)
@@@ -95,7 -95,7 +95,7 @@@
        status = ssnprintf (buffer + offset, buffer_len - offset,
            ":%llu", vl->values[i].counter);
      }
 -    else if (ds->ds[i].type == DS_TYPE_GAUGE) 
 +    else if (ds->ds[i].type == DS_TYPE_GAUGE)
      {
        status = ssnprintf (buffer + offset, buffer_len - offset,
            ":%f", vl->values[i].gauge);
      else /* if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ {
        status = ssnprintf (buffer + offset, buffer_len - offset,
          ":%"PRIu64, vl->values[i].absolute);
 - 
 +
      }
  
      if ((status < 1) || (status >= (buffer_len - offset)))
@@@ -217,7 -217,9 +217,7 @@@ static int rc_config_add_timespan (int 
  
  static int rc_config (oconfig_item_t *ci)
  {
 -  int i;
 -
 -  for (i = 0; i < ci->children_num; i++)
 +  for (int i = 0; i < ci->children_num; i++)
    {
      oconfig_item_t const *child = ci->children + i;
      const char *key = child->key;
    return (0);
  } /* int rc_config */
  
+ static int try_reconnect (void)
+ {
+   int status;
+   rrdc_disconnect ();
+   rrd_clear_error ();
+   status = rrdc_connect (daemon_address);
+   if (status != 0)
+   {
+     ERROR ("rrdcached plugin: Failed to reconnect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
+     return (-1);
+   }
+   INFO ("rrdcached plugin: Successfully reconnected to RRDCacheD "
+       "at %s", daemon_address);
+   return (0);
+ } /* int try_reconnect */
  static int rc_read (void)
  {
    int status;
    rrdc_stats_t *head;
 -  rrdc_stats_t *ptr;
+   _Bool retried = 0;
  
    value_t values[1];
    value_list_t vl = VALUE_LIST_INIT;
      sstrncpy (vl.host, daemon_address, sizeof (vl.host));
    sstrncpy (vl.plugin, "rrdcached", sizeof (vl.plugin));
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   head = NULL;
-   status = rrdc_stats_get (&head);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_stats_get failed with status %i.", status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     head = NULL;
+     rrd_clear_error ();
+     status = rrdc_stats_get (&head);
+     if (status == 0)
+       break;
 -    if (! retried)
++    if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_stats_get failed: %s (status=%i).",
+         rrd_get_error (), status);
      return (-1);
    }
  
 -  for (ptr = head; ptr != NULL; ptr = ptr->next)
 +  for (rrdc_stats_t *ptr = head; ptr != NULL; ptr = ptr->next)
    {
      if (ptr->type == RRDC_STATS_TYPE_GAUGE)
        values[0].gauge = (gauge_t) ptr->value.gauge;
@@@ -411,6 -451,7 +448,7 @@@ static int rc_write (const data_set_t *
    char values[512];
    char *values_array[2];
    int status;
+   _Bool retried = 0;
  
    if (daemon_address == NULL)
    {
      }
    }
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed with "
-         "status %i.",
-         filename, values_array[0], status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     rrd_clear_error ();
+     status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
+     if (status == 0)
+       break;
 -    if (! retried)
++    if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed: %s (status=%i)",
+         filename, values_array[0], rrd_get_error (), status);
      return (-1);
    }
  
@@@ -493,6 -548,7 +545,7 @@@ static int rc_flush (__attribute__((unu
  {
    char filename[PATH_MAX + 1];
    int status;
+   _Bool retried = 0;
  
    if (identifier == NULL)
      return (EINVAL);
    else
      ssnprintf (filename, sizeof (filename), "%s.rrd", identifier);
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   status = rrdc_flush (filename);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_flush (%s) failed with status %i.",
-         filename, status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     rrd_clear_error ();
+     status = rrdc_flush (filename);
+     if (status == 0)
+       break;
 -    if (! retried)
++    if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_flush (%s) failed: %s (status=%i).",
+         filename, rrd_get_error (), status);
      return (-1);
    }
    DEBUG ("rrdcached plugin: rrdc_flush (%s): Success.", filename);
diff --combined src/vserver.c
@@@ -27,7 -27,6 +27,7 @@@
   **/
  
  #include "collectd.h"
 +
  #include "common.h"
  #include "plugin.h"
  
@@@ -132,28 -131,21 +132,21 @@@ static derive_t vserver_get_sock_bytes(
  
  static int vserver_read (void)
  {
- #if NAME_MAX < 1024
- # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + 1024 + 1)
- #else
- # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + NAME_MAX + 1)
- #endif
-       DIR                     *proc;
-       struct dirent   *dent; /* 42 */
-       char dirent_buffer[DIRENT_BUFFER_SIZE];
+       DIR *proc;
  
        errno = 0;
        proc = opendir (PROCDIR);
        if (proc == NULL)
        {
                char errbuf[1024];
 -              ERROR ("vserver plugin: fopen (%s): %s", PROCDIR, 
 +              ERROR ("vserver plugin: fopen (%s): %s", PROCDIR,
                                sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
  
        while (42)
        {
+               struct dirent *dent;
                int len;
                char file[BUFSIZE];
  
  
                int status;
  
-               status = readdir_r (proc, (struct dirent *) dirent_buffer, &dent);
-               if (status != 0)
+               errno = 0;
+               dent = readdir (proc);
+               if (dent == NULL)
                {
                        char errbuf[4096];
-                       ERROR ("vserver plugin: readdir_r failed: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       if (errno == 0) /* end of directory */
+                               break;
+                       ERROR ("vserver plugin: failed to read directory %s: %s",
+                                       PROCDIR, sstrerror (errno, errbuf, sizeof (errbuf)));
                        closedir (proc);
                        return (-1);
                }
-               else if (dent == NULL)
-               {
-                       /* end of directory */
-                       break;
-               }
  
                if (dent->d_name[0] == '.')
                        continue;
                len = ssnprintf (file, sizeof (file), PROCDIR "/%s", dent->d_name);
                if ((len < 0) || (len >= BUFSIZE))
                        continue;
 -              
 +
                status = stat (file, &statbuf);
                if (status != 0)
                {
                                        file, sstrerror (errno, errbuf, sizeof (errbuf)));
                        continue;
                }
 -              
 +
                if (!S_ISDIR (statbuf.st_mode))
                        continue;
  
                {
                        derive_t rx;
                        derive_t tx;
 -                      char *type_instance;
 +                      const char *type_instance;
  
                        if (strsplit (buffer, cols, 4) < 4)
                                continue;
  
                        if (2 == n)
                        {
 -                              char   *type_instance;
 +                              const char *type_instance;
                                gauge_t value;
  
                                if (0 == strcmp (cols[0], "nr_threads:"))
  
                while ((fh != NULL) && (NULL != fgets (buffer, BUFSIZE, fh)))
                {
 -                      char *type = "vs_memory";
 -                      char *type_instance;
 +                      const char *type = "vs_memory";
 +                      const char *type_instance;
                        gauge_t value;
  
                        if (strsplit (buffer, cols, 2) < 2)