Merge branch 'collectd-4.5' into collectd-4.6
[collectd.git] / src / plugin.c
index 4aabebe..74565c3 100644 (file)
@@ -171,7 +171,7 @@ static int plugin_load_file (char *file)
        return (0);
 }
 
-static void *plugin_read_thread (void *args)
+static void *plugin_read_thread (void __attribute__((unused)) *args)
 {
        llentry_t   *le;
        read_func_t *rf;
@@ -328,6 +328,7 @@ int plugin_load (const char *type)
        int   ret;
        struct stat    statbuf;
        struct dirent *de;
+       int status;
 
        DEBUG ("type = %s", type);
 
@@ -336,8 +337,8 @@ int plugin_load (const char *type)
 
        /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
         * type when matching the filename */
-       if (ssnprintf (typename, sizeof (typename),
-                       "%s.so", type) >= sizeof (typename))
+       status = ssnprintf (typename, sizeof (typename), "%s.so", type);
+       if ((status < 0) || ((size_t) status >= sizeof (typename)))
        {
                WARNING ("snprintf: truncated: `%s.so'", type);
                return (-1);
@@ -357,8 +358,9 @@ int plugin_load (const char *type)
                if (strncasecmp (de->d_name, typename, typename_len))
                        continue;
 
-               if (ssnprintf (filename, sizeof (filename),
-                               "%s/%s", dir, de->d_name) >= sizeof (filename))
+               status = ssnprintf (filename, sizeof (filename),
+                               "%s/%s", dir, de->d_name);
+               if ((status < 0) || ((size_t) status >= sizeof (filename)))
                {
                        WARNING ("snprintf: truncated: `%s/%s'", dir, de->d_name);
                        continue;
@@ -374,6 +376,7 @@ int plugin_load (const char *type)
                else if (!S_ISREG (statbuf.st_mode))
                {
                        /* don't follow symlinks */
+                       WARNING ("stat %s: not a regular file", filename);
                        continue;
                }
 
@@ -835,9 +838,14 @@ int plugin_dispatch_values (value_list_t *vl)
        int status;
        static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
 
+       value_t *saved_values;
+       int      saved_values_len;
+
        data_set_t *ds;
 
-       if ((vl == NULL) || (*vl->type == '\0')) {
+       if ((vl == NULL) || (vl->type[0] == 0)
+                       || (vl->values == NULL) || (vl->values_len < 1))
+       {
                ERROR ("plugin_dispatch_values: Invalid value list.");
                return (-1);
        }
@@ -901,6 +909,31 @@ int plugin_dispatch_values (value_list_t *vl)
        escape_slashes (vl->type, sizeof (vl->type));
        escape_slashes (vl->type_instance, sizeof (vl->type_instance));
 
+       /* Copy the values. This way, we can assure `targets' that they get
+        * dynamically allocated values, which they can free and replace if
+        * they like. */
+       if ((pre_cache_chain != NULL) || (post_cache_chain != NULL))
+       {
+               saved_values     = vl->values;
+               saved_values_len = vl->values_len;
+
+               vl->values = (value_t *) calloc (vl->values_len,
+                               sizeof (*vl->values));
+               if (vl->values == NULL)
+               {
+                       ERROR ("plugin_dispatch_values: calloc failed.");
+                       vl->values = saved_values;
+                       return (-1);
+               }
+               memcpy (vl->values, saved_values,
+                               vl->values_len * sizeof (*vl->values));
+       }
+       else /* if ((pre == NULL) && (post == NULL)) */
+       {
+               saved_values     = NULL;
+               saved_values_len = 0;
+       }
+
        if (pre_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, pre_cache_chain);
@@ -912,7 +945,17 @@ int plugin_dispatch_values (value_list_t *vl)
                                        status, status);
                }
                else if (status == FC_TARGET_STOP)
+               {
+                       /* Restore the state of the value_list so that plugins
+                        * don't get confused.. */
+                       if (saved_values != NULL)
+                       {
+                               free (vl->values);
+                               vl->values     = saved_values;
+                               vl->values_len = saved_values_len;
+                       }
                        return (0);
+               }
        }
 
        /* Update the value cache */
@@ -932,6 +975,15 @@ int plugin_dispatch_values (value_list_t *vl)
        else
                fc_default_action (ds, vl);
 
+       /* Restore the state of the value_list so that plugins don't get
+        * confused.. */
+       if (saved_values != NULL)
+       {
+               free (vl->values);
+               vl->values     = saved_values;
+               vl->values_len = saved_values_len;
+       }
+
        return (0);
 } /* int plugin_dispatch_values */
 
@@ -1152,7 +1204,7 @@ int plugin_notification_meta_copy (notification_t *dst,
   return (0);
 } /* int plugin_notification_meta_copy */
 
-int plugin_notification_meta_free (notification_t *n)
+int plugin_notification_meta_free (notification_meta_t *n)
 {
   notification_meta_t *this;
   notification_meta_t *next;
@@ -1163,8 +1215,7 @@ int plugin_notification_meta_free (notification_t *n)
     return (-1);
   }
 
-  this = n->meta;
-  n->meta = NULL;
+  this = n;
   while (this != NULL)
   {
     next = this->next;