Merge branch 'collectd-4.1' into collectd-4.2
authorFlorian Forster <octo@noris.net>
Tue, 6 Nov 2007 16:40:35 +0000 (16:40 +0000)
committerFlorian Forster <octo@noris.net>
Tue, 6 Nov 2007 16:40:35 +0000 (16:40 +0000)
Conflicts:

contrib/README
src/snmp.c
src/types.db

1  2 
contrib/README
src/snmp.c
src/types.db

diff --combined contrib/README
@@@ -38,11 -38,15 +38,20 @@@ should look something like this
    datadir: "/var/lib/collectd/rrd/"
    libdir: "/usr/lib/collectd/"
  
+ exec-munin.px
+ -------------
+   Script to be used with the exec-plugin (see collectd-exec(5) for details)
+ which executes munin plugins, parses the output and translates it to a format
+ the exec-plugin understands. The features are limited - changing the munin
+ plugins to use the output format understood by the exec-plugin is recommended.
+ See the embedded POD documentation for more details:
+  $ perldoc contrib/exec-munin.px
 +exec-smartctl
 +-------------
 +  Sample script for the exec plugin. Please refer to the documentation in the
 +file - you will have to adapt it to your needs anyway.
 +
  extractDS.px
  ------------
    Creates a new RRD-file with only one data-source (DS) of the source-RRD-
@@@ -63,12 -67,3 +72,12 @@@ been renamed) and others have bee spli
  prints a bash-script to STDOUT which should do most of the work for you. You
  may still need to do some things by hand, read `README.migration' for more
  details.
 +
 +snmp-data.conf
 +--------------
 +  Sample configuration for the SNMP plugin. This config includes a few standard
 +<Data ..> definitions that you can include in your own config using the
 +`Include' statement (available since version 4.2.0). The config includes some
 +data that is defined in the IF-MIB, e. g. octet or packet counters, UPS-MIB and
 +whatever people have send in. If you have some more definitions please send
 +them in, so others can profit from it.
diff --combined src/snmp.c
@@@ -51,11 -51,8 +51,11 @@@ struct data_definition_
    char *type; /* used to find the data_set */
    int is_table;
    instance_t instance;
 +  char *instance_prefix;
    oid_t *values;
    int values_len;
 +  double scale;
 +  double shift;
    struct data_definition_s *next;
  };
  typedef struct data_definition_s data_definition_t;
@@@ -127,7 -124,6 +127,7 @@@ static pthread_cond_t  host_cond = PTHR
   *  !   +-> csnmp_config_add_data_type
   *  !   +-> csnmp_config_add_data_table
   *  !   +-> csnmp_config_add_data_instance
 + *  !   +-> csnmp_config_add_data_instance_prefix
   *  !   +-> csnmp_config_add_data_values
   *  +-> csnmp_config_add_host
   *      +-> csnmp_config_add_host_address
@@@ -153,7 -149,9 +153,7 @@@ static int csnmp_config_add_data_type (
      return (-1);
    }
  
 -  if (dd->type != NULL)
 -    free (dd->type);
 -
 +  sfree (dd->type);
    dd->type = strdup (ci->values[0].value.string);
    if (dd->type == NULL)
      return (-1);
@@@ -204,30 -202,6 +204,30 @@@ static int csnmp_config_add_data_instan
    return (0);
  } /* int csnmp_config_add_data_instance */
  
 +static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
 +    oconfig_item_t *ci)
 +{
 +  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 +  {
 +    WARNING ("snmp plugin: `InstancePrefix' needs exactly one string argument.");
 +    return (-1);
 +  }
 +
 +  if (!dd->is_table)
 +  {
 +    WARNING ("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
 +      "is set to `false'.", dd->name);
 +    return (-1);
 +  }
 +
 +  sfree (dd->instance_prefix);
 +  dd->instance_prefix = strdup (ci->values[0].value.string);
 +  if (dd->instance_prefix == NULL)
 +    return (-1);
 +
 +  return (0);
 +} /* int csnmp_config_add_data_instance_prefix */
 +
  static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
  {
    int i;
        return (-1);
      }
  
 -  if (dd->values != NULL)
 -    free (dd->values);
 +  sfree (dd->values);
 +  dd->values_len = 0;
    dd->values = (oid_t *) malloc (sizeof (oid_t) * ci->values_num);
    if (dd->values == NULL)
      return (-1);
    return (0);
  } /* int csnmp_config_add_data_instance */
  
 +static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *ci)
 +{
 +  if ((ci->values_num != 1)
 +      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  {
 +    WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
 +    return (-1);
 +  }
 +
 +  dd->shift = ci->values[0].value.number;
 +
 +  return (0);
 +} /* int csnmp_config_add_data_shift */
 +
 +static int csnmp_config_add_data_scale (data_definition_t *dd, oconfig_item_t *ci)
 +{
 +  if ((ci->values_num != 1)
 +      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  {
 +    WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
 +    return (-1);
 +  }
 +
 +  dd->scale = ci->values[0].value.number;
 +
 +  return (0);
 +} /* int csnmp_config_add_data_scale */
 +
  static int csnmp_config_add_data (oconfig_item_t *ci)
  {
    data_definition_t *dd;
      free (dd);
      return (-1);
    }
 +  dd->scale = 1.0;
 +  dd->shift = 0.0;
  
    for (i = 0; i < ci->children_num; i++)
    {
        status = csnmp_config_add_data_table (dd, option);
      else if (strcasecmp ("Instance", option->key) == 0)
        status = csnmp_config_add_data_instance (dd, option);
 +    else if (strcasecmp ("InstancePrefix", option->key) == 0)
 +      status = csnmp_config_add_data_instance_prefix (dd, option);
      else if (strcasecmp ("Values", option->key) == 0)
        status = csnmp_config_add_data_values (dd, option);
 +    else if (strcasecmp ("Shift", option->key) == 0)
 +      status = csnmp_config_add_data_shift (dd, option);
 +    else if (strcasecmp ("Scale", option->key) == 0)
 +      status = csnmp_config_add_data_scale (dd, option);
      else
      {
        WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
    if (status != 0)
    {
      sfree (dd->name);
 +    sfree (dd->instance_prefix);
      sfree (dd->values);
      sfree (dd);
      return (-1);
@@@ -656,24 -593,10 +656,10 @@@ static int csnmp_config (oconfig_item_
  
  static void csnmp_host_close_session (host_definition_t *host)
  {
-   int status;
    if (host->sess_handle == NULL)
      return;
  
-   status = snmp_sess_close (host->sess_handle);
-   if (status != 0)
-   {
-     char *errstr = NULL;
-     snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
-     ERROR ("snmp plugin: host %s: snmp_sess_close failed: %s",
-       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
-     sfree (errstr);
-   }
+   snmp_sess_close (host->sess_handle);
    host->sess_handle = NULL;
  } /* void csnmp_host_close_session */
  
@@@ -705,8 -628,7 +691,8 @@@ static void csnmp_host_open_session (ho
    }
  } /* void csnmp_host_open_session */
  
 -static value_t csnmp_value_list_to_value (struct variable_list *vl, int type)
 +static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
 +    double scale, double shift)
  {
    value_t ret;
    uint64_t temp = 0;
    {
      ret.gauge = NAN;
      if (defined != 0)
 -      ret.gauge = temp;
 +      ret.gauge = (scale * temp) + shift;
    }
  
    return (ret);
  } /* value_t csnmp_value_list_to_value */
  
 +/* Returns true if all OIDs have left their subtree */
 +static int csnmp_check_res_left_subtree (const host_definition_t *host,
 +    const data_definition_t *data,
 +    struct snmp_pdu *res)
 +{
 +  struct variable_list *vb;
 +  int num_checked;
 +  int num_left_subtree;
 +  int i;
 +
 +  vb = res->variables;
 +  if (vb == NULL)
 +    return (-1);
 +
 +  num_checked = 0;
 +  num_left_subtree = 0;
 +
 +  /* check all the variables and count how many have left their subtree */
 +  for (vb = res->variables, i = 0;
 +      (vb != NULL) && (i < data->values_len);
 +      vb = vb->next_variable, i++)
 +  {
 +    num_checked++;
 +    if (snmp_oid_ncompare (data->values[i].oid,
 +        data->values[i].oid_len,
 +        vb->name, vb->name_length,
 +        data->values[i].oid_len) != 0)
 +      num_left_subtree++;
 +  }
 +
 +  /* check if enough variables have been returned */
 +  if (i < data->values_len)
 +  {
 +    ERROR ("snmp plugin: host %s: Expected %i variables, but got only %i",
 +      host->name, data->values_len, i);
 +    return (-1);
 +  }
 +
 +  if (data->instance.oid.oid_len > 0)
 +  {
 +    if (vb == NULL)
 +    {
 +      ERROR ("snmp plugin: host %s: Expected one more variable for "
 +        "the instance..");
 +      return (-1);
 +    }
 +
 +    num_checked++;
 +    if (snmp_oid_ncompare (data->instance.oid.oid,
 +        data->instance.oid.oid_len,
 +        vb->name, vb->name_length,
 +        data->instance.oid.oid_len) != 0)
 +      num_left_subtree++;
 +  }
 +
 +  DEBUG ("snmp plugin: csnmp_check_res_left_subtree: %i of %i variables have "
 +      "left their subtree",
 +      num_left_subtree, num_checked);
 +  if (num_left_subtree >= num_checked)
 +    return (1);
 +  return (0);
 +} /* int csnmp_check_res_left_subtree */
 +
 +static int csnmp_instance_list_add (csnmp_list_instances_t **head,
 +    csnmp_list_instances_t **tail,
 +    const struct snmp_pdu *res)
 +{
 +  csnmp_list_instances_t *il;
 +  struct variable_list *vb;
 +
 +  /* 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);
 +
 +  il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
 +  if (il == NULL)
 +  {
 +    ERROR ("snmp plugin: malloc failed.");
 +    return (-1);
 +  }
 +  il->subid = vb->name[vb->name_length - 1];
 +  il->next = NULL;
 +
 +  /* Get instance name */
 +  if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
 +  {
 +    char *ptr;
 +    size_t instance_len;
 +
 +    instance_len = sizeof (il->instance) - 1;
 +    if (instance_len > vb->val_len)
 +      instance_len = vb->val_len;
 +
 +    strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
 +        ? vb->val.string
 +        : vb->val.bitstring),
 +      instance_len);
 +    il->instance[instance_len] = '\0';
 +
 +    for (ptr = il->instance; *ptr != '\0'; ptr++)
 +    {
 +      if ((*ptr > 0) && (*ptr < 32))
 +      *ptr = ' ';
 +      else if (*ptr == '/')
 +      *ptr = '_';
 +    }
 +    DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
 +  }
 +  else
 +  {
 +    value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, 1.0, 0.0);
 +    snprintf (il->instance, sizeof (il->instance),
 +      "%llu", val.counter);
 +  }
 +  il->instance[sizeof (il->instance) - 1] = '\0';
 +
 +  /* TODO: Debugging output */
 +
 +  if (*head == NULL)
 +    *head = il;
 +  else
 +    (*tail)->next = il;
 +  *tail = il;
 +
 +  return (0);
 +} /* int csnmp_instance_list_add */
 +
  static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *data,
      csnmp_list_instances_t *instance_list,
      csnmp_table_values_t **value_table)
    csnmp_table_values_t **value_table_ptr;
  
    int i;
 +  oid subid;
 +  int have_more;
  
    ds = plugin_get_ds (data->type);
    if (!ds)
    }
    assert (ds->ds_num == data->values_len);
  
 +  instance_list_ptr = instance_list;
 +
    value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
        * data->values_len);
    if (value_table_ptr == NULL)
    vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
    if (vl.values == NULL)
    {
 +    ERROR ("snmp plugin: malloc failed.");
      sfree (value_table_ptr);
      return (-1);
    }
    vl.interval = host->interval;
    vl.time = time (NULL);
  
 -  for (instance_list_ptr = instance_list;
 -      instance_list_ptr != NULL;
 -      instance_list_ptr = instance_list_ptr->next)
 +  subid = 0;
 +  have_more = 1;
 +
 +  while (have_more != 0)
    {
 -    strncpy (vl.type_instance, instance_list_ptr->instance, sizeof (vl.type_instance));
 -    vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
 +    if (instance_list != NULL)
 +    {
 +      while ((instance_list_ptr != NULL)
 +        && (instance_list_ptr->subid < subid))
 +      instance_list_ptr = instance_list_ptr->next;
 +
 +      if (instance_list_ptr == NULL)
 +      {
 +      have_more = 0;
 +      continue;
 +      }
 +      else if (instance_list_ptr->subid > subid)
 +      {
 +      subid = instance_list_ptr->subid;
 +      continue;
 +      }
 +    } /* if (instance_list != NULL) */
  
      for (i = 0; i < data->values_len; i++)
      {
        while ((value_table_ptr[i] != NULL)
 -        && (value_table_ptr[i]->subid < instance_list_ptr->subid))
 +        && (value_table_ptr[i]->subid < subid))
        value_table_ptr[i] = value_table_ptr[i]->next;
 -      if ((value_table_ptr[i] == NULL)
 -        || (value_table_ptr[i]->subid != instance_list_ptr->subid))
 -      break;
 -      vl.values[i] = value_table_ptr[i]->value;
 -    } /* for (data->values_len) */
  
 -    /* If the for-loop was aborted early, not all subid's match. */
 +      if (value_table_ptr[i] == NULL)
 +      {
 +      have_more = 0;
 +      break;
 +      }
 +      else if (value_table_ptr[i]->subid > subid)
 +      {
 +      subid = value_table_ptr[i]->subid;
 +      break;
 +      }
 +    } /* for (i = 0; i < columns; i++) */
 +    /* The subid has been increased - start scanning from the beginning
 +     * again.. */
      if (i < data->values_len)
 -    {
 -      DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
 -        "Skipping SUBID %i",
 -        host->name, data->name, i, instance_list_ptr->subid);
        continue;
 +
 +    /* if we reach this line, all value_table_ptr[i] are non-NULL and are set
 +     * to the same subid. instance_list_ptr is either NULL or points to the
 +     * same subid, too. */
 +#if COLLECT_DEBUG
 +    for (i = 1; i < data->values_len; i++)
 +    {
 +      assert (value_table_ptr[i] != NULL);
 +      assert (value_table_ptr[i-1]->subid == value_table_ptr[i]->subid);
 +    }
 +    assert ((instance_list_ptr == NULL)
 +      || (instance_list_ptr->subid == value_table_ptr[0]->subid));
 +#endif
 +
 +    {
 +      char temp[DATA_MAX_NAME_LEN];
 +
 +      if (instance_list_ptr == NULL)
 +      snprintf (temp, sizeof (temp), "%u",
 +          (uint32_t) subid);
 +      else
 +      strncpy (temp, instance_list_ptr->instance,
 +          sizeof (temp));
 +      temp[sizeof (temp) - 1] = '\0';
 +
 +      if (data->instance_prefix == NULL)
 +      strncpy (vl.type_instance, temp, sizeof (vl.type_instance));
 +      else
 +      snprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
 +          data->instance_prefix, temp);
 +      vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
      }
  
 +    for (i = 0; i < data->values_len; i++)
 +      vl.values[i] = value_table_ptr[i]->value;
 +
      /* If we get here `vl.type_instance' and all `vl.values' have been set */
      plugin_dispatch_values (data->type, &vl);
 -  } /* for (instance_list) */
 +
 +    subid++;
 +  } /* while (have_more != 0) */
  
    sfree (vl.values);
    sfree (value_table_ptr);
@@@ -1068,22 -799,16 +1054,22 @@@ static int csnmp_read_table (host_defin
    oid_list_len = data->values_len + 1;
    oid_list = (oid_t *) malloc (sizeof (oid_t) * (oid_list_len));
    if (oid_list == NULL)
 +  {
 +    ERROR ("snmp plugin: csnmp_read_table: malloc failed.");
      return (-1);
 -  memcpy (oid_list, &data->instance.oid, sizeof (oid_t));
 -  for (i = 0; i < data->values_len; i++)
 -    memcpy (oid_list + (i + 1), data->values + i, sizeof (oid_t));
 +  }
 +  memcpy (oid_list, data->values, data->values_len * sizeof (oid_t));
 +  if (data->instance.oid.oid_len > 0)
 +    memcpy (oid_list + data->values_len, &data->instance.oid, sizeof (oid_t));
 +  else
 +    oid_list_len--;
  
    /* Allocate the `value_table' */
    value_table = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
        * 2 * data->values_len);
    if (value_table == NULL)
    {
 +    ERROR ("snmp plugin: csnmp_read_table: malloc failed.");
      sfree (oid_list);
      return (-1);
    }
    status = 0;
    while (status == 0)
    {
 -    csnmp_list_instances_t *il;
 -
      req = snmp_pdu_create (SNMP_MSG_GETNEXT);
      if (req == NULL)
      {
      for (i = 0; i < oid_list_len; i++)
        snmp_add_null_var (req, oid_list[i].oid, oid_list[i].oid_len);
  
+     res = NULL;
      status = snmp_sess_synch_response (host->sess_handle, req, &res);
  
-     if (status != STAT_SUCCESS)
+     if ((status != STAT_SUCCESS) || (res == NULL))
      {
        char *errstr = NULL;
  
        snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
        ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
          host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+       if (res != NULL)
+       snmp_free_pdu (res);
+       res = NULL;
+       sfree (errstr);
        csnmp_host_close_session (host);
  
        status = -1;
      vb = res->variables;
      if (vb == NULL)
      {
+       if (res != NULL)
+       snmp_free_pdu (res);
+       res = NULL;
        status = -1;
        break;
      }
  
 -    /* Check if we left the subtree */
 -    if (snmp_oid_ncompare (data->instance.oid.oid, data->instance.oid.oid_len,
 -        vb->name, vb->name_length,
 -        data->instance.oid.oid_len) != 0)
 -    {
 -      if (res != NULL)
 -      snmp_free_pdu (res);
 -      res = NULL;
 -
 -      break;
 -    }
 -
 -    /* Allocate a new `csnmp_list_instances_t', insert the instance name and
 -     * add it to the list */
 -    il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
 -    if (il == NULL)
 +    /* Check if all values (and possibly the instance) have left their
 +     * subtree */
 +    if (csnmp_check_res_left_subtree (host, data, res) != 0)
+     {
+       if (res != NULL)
+       snmp_free_pdu (res);
+       res = NULL;
 -      status = -1;
        break;
 -    il->subid = vb->name[vb->name_length - 1];
 -    il->next = NULL;
+     }
  
 -    /* Get instance name */
 -    if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
 +    /* if an instance-OID is configured.. */
 +    if (data->instance.oid.oid_len > 0)
      {
 -      char *ptr;
 -      size_t instance_len;
 -
 -      instance_len = sizeof (il->instance) - 1;
 -      if (instance_len > vb->val_len)
 -      instance_len = vb->val_len;
 -
 -      strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
 -          ? vb->val.string
 -          : vb->val.bitstring),
 -        instance_len);
 -      il->instance[instance_len] = '\0';
 -
 -      for (ptr = il->instance; *ptr != '\0'; ptr++)
 +      /* Allocate a new `csnmp_list_instances_t', insert the instance name and
 +       * add it to the list */
 +      if (csnmp_instance_list_add (&instance_list, &instance_list_ptr,
 +          res) != 0)
        {
 -      if ((*ptr > 0) && (*ptr < 32))
 -        *ptr = ' ';
 -      else if (*ptr == '/')
 -        *ptr = '_';
 +      ERROR ("snmp plugin: csnmp_instance_list_add failed.");
 +      status = -1;
 +      break;
        }
 -      DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
 -    }
 -    else
 -    {
 -      value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER);
 -      snprintf (il->instance, sizeof (il->instance),
 -        "%llu", val.counter);
 -    }
 -    il->instance[sizeof (il->instance) - 1] = '\0';
 -    DEBUG ("snmp plugin: data = `%s'; il->instance = `%s';",
 -      data->name, il->instance);
 -
 -    if (instance_list_ptr == NULL)
 -      instance_list = il;
 -    else
 -      instance_list_ptr->next = il;
 -    instance_list_ptr = il;
 -
 -    /* Copy OID to oid_list[0] */
 -    memcpy (oid_list[0].oid, vb->name, sizeof (oid) * vb->name_length);
 -    oid_list[0].oid_len = vb->name_length;
 -
 -    for (i = 0; i < data->values_len; i++)
 -    {
 -      csnmp_table_values_t *vt;
  
 -      vb = vb->next_variable;
 +      /* 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)
        {
        status = -1;
        break;
        }
  
 +      /* Copy OID to oid_list[data->values_len] */
 +      memcpy (oid_list[data->values_len].oid, vb->name,
 +        sizeof (oid) * vb->name_length);
 +      oid_list[data->values_len].oid_len = vb->name_length;
 +    }
 +
 +    for (vb = res->variables, i = 0;
 +      (vb != NULL) && (i < data->values_len);
 +      vb = vb->next_variable, i++)
 +    {
 +      csnmp_table_values_t *vt;
 +
        /* Check if we left the subtree */
        if (snmp_oid_ncompare (data->values[i].oid,
            data->values[i].oid_len,
        if ((value_table_ptr[i] != NULL)
          && (vb->name[vb->name_length - 1] <= value_table_ptr[i]->subid))
        {
 -      DEBUG ("snmp plugin: host = %s; data = %s; i = %i; SUBID is not increasing.",
 +      DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
 +          "SUBID is not increasing.",
            host->name, data->name, i);
        continue;
        }
  
        vt = (csnmp_table_values_t *) malloc (sizeof (csnmp_table_values_t));
 -      if (vt != NULL)
 +      if (vt == NULL)
        {
 -      vt->subid = vb->name[vb->name_length - 1];
 -      vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type);
 -      vt->next = NULL;
 -
 -      if (value_table_ptr[i] == NULL)
 -        value_table[i] = vt;
 -      else
 -        value_table_ptr[i]->next = vt;
 -      value_table_ptr[i] = vt;
 +      ERROR ("snmp plugin: malloc failed.");
 +      status = -1;
 +      break;
        }
  
 +      vt->subid = vb->name[vb->name_length - 1];
 +      vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
 +        data->scale, data->shift);
 +      vt->next = NULL;
 +
 +      if (value_table_ptr[i] == NULL)
 +      value_table[i] = vt;
 +      else
 +      value_table_ptr[i]->next = vt;
 +      value_table_ptr[i] = vt;
 +
        /* Copy OID to oid_list[i + 1] */
 -      memcpy (oid_list[i + 1].oid, vb->name, sizeof (oid) * vb->name_length);
 -      oid_list[i + 1].oid_len = vb->name_length;
 +      memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length);
 +      oid_list[i].oid_len = vb->name_length;
      } /* for (i = data->values_len) */
  
      if (res != NULL)
@@@ -1314,17 -1088,24 +1317,24 @@@ static int csnmp_read_value (host_defin
  
    for (i = 0; i < data->values_len; i++)
      snmp_add_null_var (req, data->values[i].oid, data->values[i].oid_len);
+   res = NULL;
    status = snmp_sess_synch_response (host->sess_handle, req, &res);
  
-   if (status != STAT_SUCCESS)
+   if ((status != STAT_SUCCESS) || (res == NULL))
    {
      char *errstr = NULL;
  
      snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
      ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
        host->name, (errstr == NULL) ? "Unknown problem" : errstr);
-     csnmp_host_close_session (host);
+     if (res != NULL)
+       snmp_free_pdu (res);
+     res = NULL;
      sfree (errstr);
+     csnmp_host_close_session (host);
  
      return (-1);
    }
      for (i = 0; i < data->values_len; i++)
        if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
            vb->name, vb->name_length) == 0)
 -      vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type);
 +      vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type,
 +          data->scale, data->shift);
    } /* for (res->variables) */
  
-   snmp_free_pdu (res);
+   if (res != NULL)
+     snmp_free_pdu (res);
+   res = NULL;
  
    DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type);
    plugin_dispatch_values (data->type, &vl);
diff --combined src/types.db
@@@ -4,10 -4,9 +4,10 @@@ apache_requests                count:COUNTER:0:134217
  apache_scoreboard     count:GAUGE:0:65535
  bitrate                       value:GAUGE:0:4294967295
  charge                        value:GAUGE:0:U
 +connections           value:COUNTER:0:U
  counter                       value:COUNTER:U:U
- cpu                   value:COUNTER:0:4294967295
  cpufreq                       value:GAUGE:0:U
+ cpu                   value:COUNTER:0:4294967295
  current                       value:GAUGE:U:U
  delay                 seconds:GAUGE:-1000000:1000000
  df                    used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
@@@ -48,13 -47,6 +48,13 @@@ mysql_octets                rx:COUNTER:0:4294967295, 
  mysql_qcache          hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
  mysql_threads         running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
  nfs_procedure         value:COUNTER:0:4294967295
 +memcached_command     value:COUNTER:0:U
 +memcached_connections value:GAUGE:0:U
 +memcached_items               value:GAUGE:0:U
 +memcached_octets      rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
 +memcached_ops         value:COUNTER:0:134217728
 +nginx_connections     value:GAUGE:0:U
 +nginx_requests                value:COUNTER:0:134217728
  percent                       percent:GAUGE:0:100.1
  ping                  ping:GAUGE:0:65535
  power                 value:GAUGE:0:U
@@@ -63,19 -55,19 +63,20 @@@ ps_cputime         user:COUNTER:0:16000000, sy
  ps_pagefaults         minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
  ps_rss                        value:GAUGE:0:9223372036854775807
  ps_state              value:GAUGE:0:65535
+ serial_octets         rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
+ signal_noise          value:GAUGE:U:0
+ signal_power          value:GAUGE:U:0
+ signal_quality                value:GAUGE:0:U
  spam_score            value:GAUGE:U:U
+ swap                  value:GAUGE:0:1099511627776
 +tcp_connections               value:GAUGE:0:4294967295
  temperature           value:GAUGE:-273.15:U
  time_dispersion               seconds:GAUGE:-1000000:1000000
- time_offset           seconds:GAUGE:-1000000:1000000
  timeleft              timeleft:GAUGE:0:3600
- voltage                       value:GAUGE:U:U
- serial_octets         rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
- swap                  value:GAUGE:0:1099511627776
+ time_offset           seconds:GAUGE:-1000000:1000000
  users                 users:GAUGE:0:65535
- vs_threads            value:GAUGE:0:65535
- vs_processes          value:GAUGE:0:65535
+ voltage_threshold     value:GAUGE:U:U, threshold:GAUGE:U:U
+ voltage                       value:GAUGE:U:U
  vs_memory             value:GAUGE:0:9223372036854775807
- signal_quality                value:GAUGE:0:U
- signal_power          value:GAUGE:U:0
- signal_noise          value:GAUGE:U:0
+ vs_processes          value:GAUGE:0:65535
+ vs_threads            value:GAUGE:0:65535