Merge branch 'collectd-5.7' into collectd-5.8
authorFlorian Forster <octo@collectd.org>
Sat, 18 Nov 2017 08:55:58 +0000 (09:55 +0100)
committerFlorian Forster <octo@collectd.org>
Sat, 18 Nov 2017 08:55:58 +0000 (09:55 +0100)
1  2 
src/gps.c
src/snmp.c
src/write_riemann.c

diff --combined src/gps.c
+++ b/src/gps.c
@@@ -226,7 -226,7 +226,7 @@@ static int cgps_read(void) 
    cgps_submit("satellites", data_copy.sats_used, "used");
    cgps_submit("satellites", data_copy.sats_visible, "visible");
  
 -  return (0);
 +  return 0;
  }
  
  /**
@@@ -262,7 -262,7 +262,7 @@@ static int cgps_config(oconfig_item_t *
      cgps_config_data.timeout = CGPS_DEFAULT_TIMEOUT;
    }
  
 -  return (0);
 +  return 0;
  }
  
  /**
@@@ -286,10 -286,10 +286,10 @@@ static int cgps_init(void) 
        plugin_thread_create(&cgps_thread_id, NULL, cgps_thread, NULL, "gps");
    if (status != 0) {
      ERROR("gps plugin: pthread_create() failed.");
 -    return (-1);
 +    return -1;
    }
  
 -  return (0);
 +  return 0;
  }
  
  /**
@@@ -307,7 -307,6 +307,6 @@@ static int cgps_shutdown(void) 
    free(res);
  
    // Clean mutex:
-   pthread_mutex_unlock(&cgps_thread_lock);
    pthread_mutex_destroy(&cgps_thread_lock);
    pthread_mutex_unlock(&cgps_data_lock);
    pthread_mutex_destroy(&cgps_data_lock);
    sfree(cgps_config_data.port);
    sfree(cgps_config_data.host);
  
 -  return (0);
 +  return 0;
  }
  
  /**
diff --combined src/snmp.c
@@@ -63,7 -63,7 +63,7 @@@ struct data_definition_s 
    struct data_definition_s *next;
    char **ignores;
    size_t ignores_len;
 -  int invert_match;
 +  _Bool invert_match;
  };
  typedef struct data_definition_s data_definition_t;
  
@@@ -71,8 -71,6 +71,8 @@@ struct host_definition_s 
    char *name;
    char *address;
    int version;
 +  cdtime_t timeout;
 +  int retries;
  
    /* snmpv1/2 options */
    char *community;
@@@ -132,22 -130,23 +132,22 @@@ static void csnmp_oid_init(oid_t *dst, 
  }
  
  static int csnmp_oid_compare(oid_t const *left, oid_t const *right) {
 -  return (
 -      snmp_oid_compare(left->oid, left->oid_len, right->oid, right->oid_len));
 +  return snmp_oid_compare(left->oid, left->oid_len, right->oid, right->oid_len);
  }
  
  static int csnmp_oid_suffix(oid_t *dst, oid_t const *src, oid_t const *root) {
    /* Make sure "src" is in "root"s subtree. */
    if (src->oid_len <= root->oid_len)
 -    return (EINVAL);
 +    return EINVAL;
    if (snmp_oid_ncompare(root->oid, root->oid_len, src->oid, src->oid_len,
                          /* n = */ root->oid_len) != 0)
 -    return (EINVAL);
 +    return EINVAL;
  
    memset(dst, 0, sizeof(*dst));
    dst->oid_len = src->oid_len - root->oid_len;
    memcpy(dst->oid, &src->oid[root->oid_len],
           dst->oid_len * sizeof(dst->oid[0]));
 -  return (0);
 +  return 0;
  }
  
  static int csnmp_oid_to_string(char *buffer, size_t buffer_size,
    char *oid_str_ptr[MAX_OID_LEN];
  
    for (size_t i = 0; i < o->oid_len; i++) {
 -    ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
 +    snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
      oid_str_ptr[i] = oid_str[i];
    }
  
 -  return (strjoin(buffer, buffer_size, oid_str_ptr, o->oid_len,
 -                  /* separator = */ "."));
 +  return strjoin(buffer, buffer_size, oid_str_ptr, o->oid_len, ".");
  }
  
  static void csnmp_host_close_session(host_definition_t *host) /* {{{ */
@@@ -241,14 -241,14 +241,14 @@@ static int csnmp_config_add_data_instan
  
      if (!read_objid(buffer, dd->instance.oid.oid, &dd->instance.oid.oid_len)) {
        ERROR("snmp plugin: read_objid (%s) failed.", buffer);
 -      return (-1);
 +      return -1;
      }
    } else {
      /* Instance is a simple string */
      sstrncpy(dd->instance.string, buffer, sizeof(dd->instance.string));
    }
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_data_instance */
  
  static int csnmp_config_add_data_instance_prefix(data_definition_t *dd,
      WARNING("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
              "is set to `false'.",
              dd->name);
 -    return (-1);
 +    return -1;
    }
  
    status = cf_util_get_string(ci, &dd->instance_prefix);
@@@ -270,20 -270,20 +270,20 @@@ static int csnmp_config_add_data_values
                                          oconfig_item_t *ci) {
    if (ci->values_num < 1) {
      WARNING("snmp plugin: `Values' needs at least one argument.");
 -    return (-1);
 +    return -1;
    }
  
    for (int i = 0; i < ci->values_num; i++)
      if (ci->values[i].type != OCONFIG_TYPE_STRING) {
        WARNING("snmp plugin: `Values' needs only string argument.");
 -      return (-1);
 +      return -1;
      }
  
    sfree(dd->values);
    dd->values_len = 0;
    dd->values = malloc(sizeof(*dd->values) * ci->values_num);
    if (dd->values == NULL)
 -    return (-1);
 +    return -1;
    dd->values_len = (size_t)ci->values_num;
  
    for (int i = 0; i < ci->values_num; i++) {
        free(dd->values);
        dd->values = NULL;
        dd->values_len = 0;
 -      return (-1);
 +      return -1;
      }
    }
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_data_instance */
  
  static int csnmp_config_add_data_blacklist(data_definition_t *dd,
                                             oconfig_item_t *ci) {
    if (ci->values_num < 1)
 -    return (0);
 +    return 0;
  
    for (int i = 0; i < ci->values_num; i++) {
      if (ci->values[i].type != OCONFIG_TYPE_STRING) {
        WARNING("snmp plugin: `Ignore' needs only string argument.");
 -      return (-1);
 +      return -1;
      }
    }
  
                       ci->values[i].value.string) != 0) {
        ERROR("snmp plugin: Can't allocate memory");
        strarray_free(dd->ignores, dd->ignores_len);
 -      return (ENOMEM);
 +      return ENOMEM;
      }
    }
    return 0;
  } /* int csnmp_config_add_data_blacklist */
  
 -static int csnmp_config_add_data_blacklist_match_inverted(data_definition_t *dd,
 -                                                          oconfig_item_t *ci) {
 -  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
 -    WARNING("snmp plugin: `InvertMatch' needs exactly one boolean argument.");
 -    return (-1);
 -  }
 -
 -  dd->invert_match = ci->values[0].value.boolean ? 1 : 0;
 -
 -  return (0);
 -} /* int csnmp_config_add_data_blacklist_match_inverted */
 -
  static int csnmp_config_add_data(oconfig_item_t *ci) {
 -  data_definition_t *dd;
 -  int status = 0;
 -
 -  dd = calloc(1, sizeof(*dd));
 +  data_definition_t *dd = calloc(1, sizeof(*dd));
    if (dd == NULL)
 -    return (-1);
 +    return -1;
  
 -  status = cf_util_get_string(ci, &dd->name);
 +  int status = cf_util_get_string(ci, &dd->name);
    if (status != 0) {
 -    free(dd);
 -    return (-1);
 +    sfree(dd);
 +    return -1;
    }
  
    dd->scale = 1.0;
      else if (strcasecmp("Ignore", option->key) == 0)
        status = csnmp_config_add_data_blacklist(dd, option);
      else if (strcasecmp("InvertMatch", option->key) == 0)
 -      status = csnmp_config_add_data_blacklist_match_inverted(dd, option);
 +      status = cf_util_get_boolean(option, &dd->invert_match);
      else {
        WARNING("snmp plugin: Option `%s' not allowed here.", option->key);
        status = -1;
      sfree(dd->values);
      sfree(dd->ignores);
      sfree(dd);
 -    return (-1);
 +    return -1;
    }
  
    DEBUG("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = "
      last->next = dd;
    }
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_data */
  
  static int csnmp_config_add_host_version(host_definition_t *hd,
    if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
      WARNING("snmp plugin: The `Version' config option needs exactly one number "
              "argument.");
 -    return (-1);
 +    return -1;
    }
  
    version = (int)ci->values[0].value.number;
    if ((version < 1) || (version > 3)) {
      WARNING("snmp plugin: `Version' must either be `1', `2', or `3'.");
 -    return (-1);
 +    return -1;
    }
  
    hd->version = version;
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host_address */
  
  static int csnmp_config_add_host_collect(host_definition_t *host,
  
    if (ci->values_num < 1) {
      WARNING("snmp plugin: `Collect' needs at least one argument.");
 -    return (-1);
 +    return -1;
    }
  
    for (int i = 0; i < ci->values_num; i++)
      if (ci->values[i].type != OCONFIG_TYPE_STRING) {
        WARNING("snmp plugin: All arguments to `Collect' must be strings.");
 -      return (-1);
 +      return -1;
      }
  
    data_list_len = host->data_list_len + ci->values_num;
    data_list =
        realloc(host->data_list, sizeof(data_definition_t *) * data_list_len);
    if (data_list == NULL)
 -    return (-1);
 +    return -1;
    host->data_list = data_list;
  
    for (int i = 0; i < ci->values_num; i++) {
      host->data_list_len++;
    } /* for (values_num) */
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host_collect */
  
  static int csnmp_config_add_host_auth_protocol(host_definition_t *hd,
    } else {
      WARNING("snmp plugin: The `AuthProtocol' config option must be `MD5' or "
              "`SHA'.");
 -    return (-1);
 +    return -1;
    }
  
    DEBUG("snmp plugin: host = %s; host->auth_protocol = %s;", hd->name,
          hd->auth_protocol == usmHMACMD5AuthProtocol ? "MD5" : "SHA");
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host_auth_protocol */
  
  static int csnmp_config_add_host_priv_protocol(host_definition_t *hd,
    } else {
      WARNING("snmp plugin: The `PrivProtocol' config option must be `AES' or "
              "`DES'.");
 -    return (-1);
 +    return -1;
    }
  
    DEBUG("snmp plugin: host = %s; host->priv_protocol = %s;", hd->name,
          hd->priv_protocol == usmAESPrivProtocol ? "AES" : "DES");
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host_priv_protocol */
  
  static int csnmp_config_add_host_security_level(host_definition_t *hd,
    else {
      WARNING("snmp plugin: The `SecurityLevel' config option must be "
              "`noAuthNoPriv', `authNoPriv', or `authPriv'.");
 -    return (-1);
 +    return -1;
    }
  
    DEBUG("snmp plugin: host = %s; host->security_level = %d;", hd->name,
          hd->security_level);
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host_security_level */
  
  static int csnmp_config_add_host(oconfig_item_t *ci) {
  
    hd = calloc(1, sizeof(*hd));
    if (hd == NULL)
 -    return (-1);
 +    return -1;
    hd->version = 2;
    C_COMPLAIN_INIT(&hd->complaint);
  
    hd->sess_handle = NULL;
    hd->interval = 0;
  
 +  /* These mean that we have not set a timeout or retry value */
 +  hd->timeout = 0;
 +  hd->retries = -1;
 +
    for (int i = 0; i < ci->children_num; i++) {
      oconfig_item_t *option = ci->children + i;
      status = 0;
        status = cf_util_get_string(option, &hd->community);
      else if (strcasecmp("Version", option->key) == 0)
        status = csnmp_config_add_host_version(hd, option);
 +    else if (strcasecmp("Timeout", option->key) == 0)
 +      cf_util_get_cdtime(option, &hd->timeout);
 +    else if (strcasecmp("Retries", option->key) == 0)
 +      cf_util_get_int(option, &hd->retries);
      else if (strcasecmp("Collect", option->key) == 0)
        csnmp_config_add_host_collect(hd, option);
      else if (strcasecmp("Interval", option->key) == 0)
  
    if (status != 0) {
      csnmp_host_definition_destroy(hd);
 -    return (-1);
 +    return -1;
    }
  
    DEBUG("snmp plugin: hd = { name = %s, address = %s, community = %s, version "
          "= %i }",
          hd->name, hd->address, hd->community, hd->version);
  
 -  ssnprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name);
 +  snprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name);
  
    status = plugin_register_complex_read(
        /* group = */ NULL, cb_name, csnmp_read_host, hd->interval,
        });
    if (status != 0) {
      ERROR("snmp plugin: Registering complex read function failed.");
 -    csnmp_host_definition_destroy(hd);
 -    return (-1);
 +    return -1;
    }
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config_add_host */
  
  static int csnmp_config(oconfig_item_t *ci) {
      }
    } /* for (ci->children) */
  
 -  return (0);
 +  return 0;
  } /* int csnmp_config */
  
  /* }}} End of the config stuff. Now the interesting part begins */
@@@ -798,15 -806,6 +798,15 @@@ static void csnmp_host_open_session(hos
      sess.community_len = strlen(host->community);
    }
  
 +  /* Set timeout & retries, if they have been changed from the default */
 +  if (host->timeout != 0) {
 +    /* net-snmp expects microseconds */
 +    sess.timeout = CDTIME_T_TO_US(host->timeout);
 +  }
 +  if (host->retries >= 0) {
 +    sess.retries = host->retries;
 +  }
 +
    /* snmp_sess_open will copy the `struct snmp_session *'. */
    host->sess_handle = snmp_sess_open(&sess);
  
@@@ -945,7 -944,7 +945,7 @@@ static value_t csnmp_value_list_to_valu
      ret.gauge = NAN;
    }
  
 -  return (ret);
 +  return ret;
  } /* value_t csnmp_value_list_to_value */
  
  /* csnmp_strvbcopy_hexstring converts the bit string contained in "vb" to a hex
@@@ -999,13 -998,13 +999,13 @@@ static int csnmp_strvbcopy(char *dst, /
    else if (vb->type == ASN_BIT_STR)
      src = (char *)vb->val.bitstring;
    else if (vb->type == ASN_IPADDRESS) {
 -    return ssnprintf(dst, dst_size,
 -                     "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "",
 -                     (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1],
 -                     (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]);
 +    return snprintf(dst, dst_size,
 +                    "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "",
 +                    (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1],
 +                    (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]);
    } else {
      dst[0] = 0;
 -    return (EINVAL);
 +    return EINVAL;
    }
  
    num_chars = dst_size - 1;
    for (size_t i = 0; i < num_chars; i++) {
      /* Check for control characters. */
      if ((unsigned char)src[i] < 32)
 -      return (csnmp_strvbcopy_hexstring(dst, vb, dst_size));
 +      return csnmp_strvbcopy_hexstring(dst, vb, dst_size);
      dst[i] = src[i];
    }
    dst[num_chars] = 0;
@@@ -1036,27 -1035,28 +1036,27 @@@ static int csnmp_instance_list_add(csnm
    struct variable_list *vb;
    oid_t vb_name;
    int status;
 -  uint32_t is_matched;
  
    /* Set vb on the last variable */
    for (vb = res->variables; (vb != NULL) && (vb->next_variable != NULL);
         vb = vb->next_variable)
      /* do nothing */;
    if (vb == NULL)
 -    return (-1);
 +    return -1;
  
    csnmp_oid_init(&vb_name, vb->name, vb->name_length);
  
    il = calloc(1, sizeof(*il));
    if (il == NULL) {
      ERROR("snmp plugin: calloc failed.");
 -    return (-1);
 +    return -1;
    }
    il->next = NULL;
  
    status = csnmp_oid_suffix(&il->suffix, &vb_name, &dd->instance.oid);
    if (status != 0) {
      sfree(il);
 -    return (status);
 +    return status;
    }
  
    /* Get instance name */
      char *ptr;
  
      csnmp_strvbcopy(il->instance, vb, sizeof(il->instance));
 -    is_matched = 0;
 +    _Bool is_matched = 0;
      for (uint32_t i = 0; i < dd->ignores_len; i++) {
        status = fnmatch(dd->ignores[i], il->instance, 0);
        if (status == 0) {
 -        if (dd->invert_match == 0) {
 +        if (!dd->invert_match) {
            sfree(il);
            return 0;
          } else {
          }
        }
      }
 -    if (dd->invert_match != 0 && is_matched == 0) {
 +    if (dd->invert_match && !is_matched) {
        sfree(il);
        return 0;
      }
      value_t val = csnmp_value_list_to_value(
          vb, DS_TYPE_COUNTER,
          /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
 -    ssnprintf(il->instance, sizeof(il->instance), "%llu", val.counter);
 +    snprintf(il->instance, sizeof(il->instance), "%llu", val.counter);
    }
  
    /* TODO: Debugging output */
      (*tail)->next = il;
    *tail = il;
  
 -  return (0);
 +  return 0;
  } /* int csnmp_instance_list_add */
  
  static int csnmp_dispatch_table(host_definition_t *host,
    value_list_t vl = VALUE_LIST_INIT;
  
    csnmp_list_instances_t *instance_list_ptr;
 -  csnmp_table_values_t **value_table_ptr;
 +  csnmp_table_values_t *value_table_ptr[data->values_len];
  
    size_t i;
    _Bool have_more;
    ds = plugin_get_ds(data->type);
    if (!ds) {
      ERROR("snmp plugin: DataSet `%s' not defined.", data->type);
 -    return (-1);
 +    return -1;
    }
    assert(ds->ds_num == data->values_len);
    assert(data->values_len > 0);
  
    instance_list_ptr = instance_list;
  
 -  value_table_ptr = calloc(data->values_len, sizeof(*value_table_ptr));
 -  if (value_table_ptr == NULL)
 -    return (-1);
    for (i = 0; i < data->values_len; i++)
      value_table_ptr[i] = value_table[i];
  
 -  vl.values_len = data->values_len;
 -  vl.values = malloc(sizeof(*vl.values) * vl.values_len);
 -  if (vl.values == NULL) {
 -    ERROR("snmp plugin: malloc failed.");
 -    sfree(value_table_ptr);
 -    return (-1);
 -  }
 -
    sstrncpy(vl.host, host->name, sizeof(vl.host));
    sstrncpy(vl.plugin, "snmp", sizeof(vl.plugin));
  
  
        memcpy(&current_suffix, &instance_list_ptr->suffix,
               sizeof(current_suffix));
 -    } else /* no instance configured */
 -    {
 +    } else {
 +      /* no instance configured */
        csnmp_table_values_t *ptr = value_table_ptr[0];
        if (ptr == NULL) {
          have_more = 0;
        if (data->instance_prefix == NULL)
          sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
        else
 -        ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
 -                  data->instance_prefix, temp);
 +        snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
 +                 data->instance_prefix, temp);
      }
  
 +    vl.values_len = data->values_len;
 +    value_t values[vl.values_len];
 +    vl.values = values;
 +
      for (i = 0; i < data->values_len; i++)
        vl.values[i] = value_table_ptr[i]->value;
  
      if (vl.type_instance[0] != '\0')
        plugin_dispatch_values(&vl);
  
 +    /* prevent leakage of pointer to local variable. */
 +    vl.values_len = 0;
 +    vl.values = NULL;
 +
      if (instance_list != NULL)
        instance_list_ptr = instance_list_ptr->next;
      else
        value_table_ptr[0] = value_table_ptr[0]->next;
    } /* while (have_more) */
  
 -  sfree(vl.values);
 -  sfree(value_table_ptr);
 -
    return (0);
  } /* int csnmp_dispatch_table */
  
@@@ -1286,20 -1292,20 +1286,20 @@@ static int csnmp_read_table(host_defini
  
    if (host->sess_handle == NULL) {
      DEBUG("snmp plugin: csnmp_read_table: host->sess_handle == NULL");
 -    return (-1);
 +    return -1;
    }
  
    ds = plugin_get_ds(data->type);
    if (!ds) {
      ERROR("snmp plugin: DataSet `%s' not defined.", data->type);
 -    return (-1);
 +    return -1;
    }
  
    if (ds->ds_num != data->values_len) {
      ERROR("snmp plugin: DataSet `%s' requires %zu values, but config talks "
            "about %zu",
            data->type, ds->ds_num, data->values_len);
 -    return (-1);
 +    return -1;
    }
    assert(data->values_len > 0);
  
      ERROR("snmp plugin: csnmp_read_table: calloc failed.");
      sfree(value_list_head);
      sfree(value_list_tail);
 -    return (-1);
 +    return -1;
    }
  
    instance_list_head = NULL;
  
    status = 0;
    while (status == 0) {
 -    int oid_list_todo_num;
 -
      req = snmp_pdu_create(SNMP_MSG_GETNEXT);
      if (req == NULL) {
        ERROR("snmp plugin: snmp_pdu_create failed.");
        break;
      }
  
 -    oid_list_todo_num = 0;
 +    size_t oid_list_todo_num = 0;
 +    size_t var_idx[oid_list_len];
 +    memset(var_idx, 0, sizeof(var_idx));
 +
      for (i = 0; i < oid_list_len; i++) {
        /* Do not rerequest already finished OIDs */
        if (!oid_list_todo[i])
          continue;
 -      oid_list_todo_num++;
        snmp_add_null_var(req, oid_list[i].oid, oid_list[i].oid_len);
 +      var_idx[oid_list_todo_num] = i;
 +      oid_list_todo_num++;
      }
  
      if (oid_list_todo_num == 0) {
        break;
      }
  
 +    if (res->errstat != SNMP_ERR_NOERROR) {
 +      if (res->errindex != 0) {
 +        /* Find the OID which caused error */
 +        for (i = 1, vb = res->variables; vb != NULL && i != res->errindex;
 +             vb = vb->next_variable, i++)
 +          /* do nothing */;
 +      }
 +
 +      if ((res->errindex == 0) || (vb == NULL)) {
 +        ERROR("snmp plugin: host %s; data %s: response error: %s (%li) ",
 +              host->name, data->name, snmp_errstring(res->errstat),
 +              res->errstat);
 +        status = -1;
 +        break;
 +      }
 +
 +      char oid_buffer[1024] = {0};
 +      snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, vb->name,
 +                    vb->name_length);
 +      NOTICE("snmp plugin: host %s; data %s: OID `%s` failed: %s", host->name,
 +             data->name, oid_buffer, snmp_errstring(res->errstat));
 +
 +      /* Get value index from todo list and skip OID found */
 +      assert(res->errindex <= oid_list_todo_num);
 +      i = var_idx[res->errindex - 1];
 +      assert(i < oid_list_len);
 +      oid_list_todo[i] = 0;
 +
 +      snmp_free_pdu(res);
 +      res = NULL;
 +      continue;
 +    }
 +
      for (vb = res->variables, i = 0; (vb != NULL);
           vb = vb->next_variable, i++) {
        /* Calculate value index from todo list */
-       while ((i < oid_list_len) && !oid_list_todo[i])
+       while ((i < oid_list_len) && !oid_list_todo[i]) {
          i++;
+       }
+       if (i >= oid_list_len) {
+         break;
+       }
  
        /* An instance is configured and the res variable we process is the
         * instance value (last index) */
    sfree(value_list_head);
    sfree(value_list_tail);
  
 -  return (0);
 +  return 0;
  } /* int csnmp_read_table */
  
  static int csnmp_read_value(host_definition_t *host, data_definition_t *data) {
  
    if (host->sess_handle == NULL) {
      DEBUG("snmp plugin: csnmp_read_value: host->sess_handle == NULL");
 -    return (-1);
 +    return -1;
    }
  
    ds = plugin_get_ds(data->type);
    if (!ds) {
      ERROR("snmp plugin: DataSet `%s' not defined.", data->type);
 -    return (-1);
 +    return -1;
    }
  
    if (ds->ds_num != data->values_len) {
      ERROR("snmp plugin: DataSet `%s' requires %zu values, but config talks "
            "about %zu",
            data->type, ds->ds_num, data->values_len);
 -    return (-1);
 +    return -1;
    }
  
    vl.values_len = ds->ds_num;
    vl.values = malloc(sizeof(*vl.values) * vl.values_len);
    if (vl.values == NULL)
 -    return (-1);
 +    return -1;
    for (i = 0; i < vl.values_len; i++) {
      if (ds->ds[i].type == DS_TYPE_COUNTER)
        vl.values[i].counter = 0;
    if (req == NULL) {
      ERROR("snmp plugin: snmp_pdu_create failed.");
      sfree(vl.values);
 -    return (-1);
 +    return -1;
    }
  
    for (i = 0; i < data->values_len; i++)
      sfree(vl.values);
      csnmp_host_close_session(host);
  
 -    return (-1);
 +    return -1;
    }
  
    for (vb = res->variables; vb != NULL; vb = vb->next_variable) {
    plugin_dispatch_values(&vl);
    sfree(vl.values);
  
 -  return (0);
 +  return 0;
  } /* int csnmp_read_value */
  
  static int csnmp_read_host(user_data_t *ud) {
      csnmp_host_open_session(host);
  
    if (host->sess_handle == NULL)
 -    return (-1);
 +    return -1;
  
    success = 0;
    for (i = 0; i < host->data_list_len; i++) {
    }
  
    if (success == 0)
 -    return (-1);
 +    return -1;
  
 -  return (0);
 +  return 0;
  } /* int csnmp_read_host */
  
  static int csnmp_init(void) {
    call_snmp_init_once();
  
 -  return (0);
 +  return 0;
  } /* int csnmp_init */
  
  static int csnmp_shutdown(void) {
      data_this = data_next;
    }
  
 -  return (0);
 +  return 0;
  } /* int csnmp_shutdown */
  
  void module_register(void) {
    plugin_register_init("snmp", csnmp_init);
    plugin_register_shutdown("snmp", csnmp_shutdown);
  } /* void module_register */
 -
 -/*
 - * vim: shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker
 - */
diff --combined src/write_riemann.c
@@@ -125,12 -125,12 +125,12 @@@ static int wrr_connect(struct riemann_h
  static int wrr_disconnect(struct riemann_host *host) /* {{{ */
  {
    if (!host->client)
 -    return (0);
 +    return 0;
  
    riemann_client_free(host->client);
    host->client = NULL;
  
 -  return (0);
 +  return 0;
  } /* }}} int wrr_disconnect */
  
  /**
@@@ -214,11 -214,6 +214,11 @@@ wrr_notification_to_message(struct riem
        RIEMANN_EVENT_FIELD_SERVICE, &service_buffer[1],
        RIEMANN_EVENT_FIELD_NONE);
  
 +#if RCC_VERSION_NUMBER >= 0x010A00
 +  riemann_event_set(event, RIEMANN_EVENT_FIELD_TIME_MICROS,
 +                    (int64_t)CDTIME_T_TO_US(n->time));
 +#endif
 +
    if (n->host[0] != 0)
      riemann_event_string_attribute_add(event, "host", n->host);
    if (n->plugin[0] != 0)
    if (msg == NULL) {
      ERROR("write_riemann plugin: riemann_message_create_with_events() failed.");
      riemann_event_free(event);
 -    return (NULL);
 +    return NULL;
    }
  
    DEBUG("write_riemann plugin: Successfully created message for notification: "
          "host = \"%s\", service = \"%s\", state = \"%s\"",
          event->host, event->service, event->state);
 -  return (msg);
 +  return msg;
  } /* }}} riemann_message_t *wrr_notification_to_message */
  
  static riemann_event_t *
@@@ -285,7 -280,7 +285,7 @@@ wrr_value_to_event(struct riemann_host 
    event = riemann_event_new();
    if (event == NULL) {
      ERROR("write_riemann plugin: riemann_event_new() failed.");
 -    return (NULL);
 +    return NULL;
    }
  
    format_name(name_buffer, sizeof(name_buffer),
                vl->type_instance);
    if (host->always_append_ds || (ds->ds_num > 1)) {
      if (host->event_service_prefix == NULL)
 -      ssnprintf(service_buffer, sizeof(service_buffer), "%s/%s",
 -                &name_buffer[1], ds->ds[index].name);
 +      snprintf(service_buffer, sizeof(service_buffer), "%s/%s", &name_buffer[1],
 +               ds->ds[index].name);
      else
 -      ssnprintf(service_buffer, sizeof(service_buffer), "%s%s/%s",
 -                host->event_service_prefix, &name_buffer[1],
 -                ds->ds[index].name);
 +      snprintf(service_buffer, sizeof(service_buffer), "%s%s/%s",
 +               host->event_service_prefix, &name_buffer[1], ds->ds[index].name);
    } else {
      if (host->event_service_prefix == NULL)
        sstrncpy(service_buffer, &name_buffer[1], sizeof(service_buffer));
      else
 -      ssnprintf(service_buffer, sizeof(service_buffer), "%s%s",
 -                host->event_service_prefix, &name_buffer[1]);
 +      snprintf(service_buffer, sizeof(service_buffer), "%s%s",
 +               host->event_service_prefix, &name_buffer[1]);
    }
  
    riemann_event_set(
        vl->type, "ds_name", ds->ds[index].name, NULL,
        RIEMANN_EVENT_FIELD_SERVICE, service_buffer, RIEMANN_EVENT_FIELD_NONE);
  
 +#if RCC_VERSION_NUMBER >= 0x010A00
 +  riemann_event_set(event, RIEMANN_EVENT_FIELD_TIME_MICROS,
 +                    (int64_t)CDTIME_T_TO_US(vl->time));
 +#endif
 +
    if (host->check_thresholds) {
      const char *state = NULL;
  
    if ((ds->ds[index].type != DS_TYPE_GAUGE) && (rates != NULL)) {
      char ds_type[DATA_MAX_NAME_LEN];
  
 -    ssnprintf(ds_type, sizeof(ds_type), "%s:rate",
 -              DS_TYPE_TO_STRING(ds->ds[index].type));
 +    snprintf(ds_type, sizeof(ds_type), "%s:rate",
 +             DS_TYPE_TO_STRING(ds->ds[index].type));
      riemann_event_string_attribute_add(event, "ds_type", ds_type);
    } else {
      riemann_event_string_attribute_add(event, "ds_type",
    {
      char ds_index[DATA_MAX_NAME_LEN];
  
 -    ssnprintf(ds_index, sizeof(ds_index), "%zu", index);
 +    snprintf(ds_index, sizeof(ds_index), "%zu", index);
      riemann_event_string_attribute_add(event, "ds_index", ds_index);
    }
  
    DEBUG("write_riemann plugin: Successfully created message for metric: "
          "host = \"%s\", service = \"%s\"",
          event->host, event->service);
 -  return (event);
 +  return event;
  } /* }}} riemann_event_t *wrr_value_to_event */
  
  static riemann_message_t *
@@@ -412,7 -403,7 +412,7 @@@ wrr_value_list_to_message(struct rieman
    msg = riemann_message_new();
    if (msg == NULL) {
      ERROR("write_riemann plugin: riemann_message_new failed.");
 -    return (NULL);
 +    return NULL;
    }
  
    if (host->store_rates) {
      if (rates == NULL) {
        ERROR("write_riemann plugin: uc_get_rate failed.");
        riemann_message_free(msg);
 -      return (NULL);
 +      return NULL;
      }
    }
  
      if (event == NULL) {
        riemann_message_free(msg);
        sfree(rates);
 -      return (NULL);
 +      return NULL;
      }
      riemann_message_append_events(msg, event, NULL);
    }
  
    sfree(rates);
 -  return (msg);
 +  return msg;
  } /* }}} riemann_message_t *wrr_value_list_to_message */
  
  /*
@@@ -468,7 -459,7 +468,7 @@@ static int wrr_batch_flush(cdtime_t tim
    int status;
  
    if (user_data == NULL)
 -    return (-EINVAL);
 +    return -EINVAL;
  
    host = user_data->data;
    pthread_mutex_lock(&host->lock);
@@@ -548,7 -539,7 +548,7 @@@ static int wrr_notification(const notif
     */
    msg = wrr_notification_to_message(host, n);
    if (msg == NULL)
 -    return (-1);
 +    return -1;
  
    status = wrr_send(host, msg);
    if (status != 0)
                "write_riemann plugin: riemann_client_send succeeded");
  
    riemann_message_free(msg);
 -  return (status);
 +  return status;
  } /* }}} int wrr_notification */
  
  static int wrr_write(const data_set_t *ds, /* {{{ */
    } else {
      msg = wrr_value_list_to_message(host, ds, vl, statuses);
      if (msg == NULL)
 -      return (-1);
 +      return -1;
  
      status = wrr_send(host, msg);
  
@@@ -610,6 -601,7 +610,7 @@@ static void wrr_free(void *p) /* {{{ *
  
    wrr_disconnect(host);
  
+   pthread_mutex_lock(&host->lock);
    pthread_mutex_destroy(&host->lock);
    sfree(host);
  } /* }}} void wrr_free */
@@@ -801,8 -793,8 +802,8 @@@ static int wrr_config_node(oconfig_item
      return status;
    }
  
 -  ssnprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
 -            host->name);
 +  snprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
 +           host->name);
  
    user_data_t ud = {.data = host, .free_func = wrr_free};
  
       * holding a reference. */
      pthread_mutex_unlock(&host->lock);
      wrr_free(host);
 -    return (-1);
 +    return -1;
    }
  
    host->reference_count--;
@@@ -862,21 -854,21 +863,21 @@@ static int wrr_config(oconfig_item_t *c
  
        if (child->values_num != 2) {
          WARNING("riemann attributes need both a key and a value.");
 -        return (-1);
 +        return -1;
        }
        if (child->values[0].type != OCONFIG_TYPE_STRING ||
            child->values[1].type != OCONFIG_TYPE_STRING) {
          WARNING("riemann attribute needs string arguments.");
 -        return (-1);
 +        return -1;
        }
        if ((key = strdup(child->values[0].value.string)) == NULL) {
          WARNING("cannot allocate memory for attribute key.");
 -        return (-1);
 +        return -1;
        }
        if ((val = strdup(child->values[1].value.string)) == NULL) {
          WARNING("cannot allocate memory for attribute value.");
          sfree(key);
 -        return (-1);
 +        return -1;
        }
        strarray_add(&riemann_attrs, &riemann_attrs_num, key);
        strarray_add(&riemann_attrs, &riemann_attrs_num, val);
                child->key);
      }
    }
 -  return (0);
 +  return 0;
  } /* }}} int wrr_config */
  
  void module_register(void) {
    plugin_register_complex_config("write_riemann", wrr_config);
  }
 -
 -/* vim: set sw=8 sts=8 ts=8 noet : */