X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fplugin.c;h=f4461b5d174851df287e88fd659e7a53aab8845e;hb=c6da31fb30c2fb1d131f92efcde0b3ec9a010b2c;hp=2579856455cee341a100192cf079efb66a393062;hpb=47f2b4a92d3390e27ce2fa6f6bd1340c9cb0491b;p=collectd.git diff --git a/src/plugin.c b/src/plugin.c index 25798564..f4461b5d 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -59,6 +59,7 @@ struct read_func_s #define rf_callback rf_super.cf_callback #define rf_udata rf_super.cf_udata callback_func_t rf_super; + char rf_group[DATA_MAX_NAME_LEN]; char rf_name[DATA_MAX_NAME_LEN]; int rf_type; struct timespec rf_interval; @@ -151,7 +152,7 @@ static void destroy_read_heap (void) /* {{{ */ { callback_func_t *cf; - cf = c_head_get_root (read_heap); + cf = c_heap_get_root (read_heap); if (cf == NULL) break; @@ -173,7 +174,7 @@ static int register_callback (llist_t **list, /* {{{ */ *list = llist_create (); if (*list == NULL) { - ERROR ("plugin: create_register_callback: " + ERROR ("plugin: register_callback: " "llist_create failed."); destroy_callback (cf); return (-1); @@ -183,7 +184,7 @@ static int register_callback (llist_t **list, /* {{{ */ key = strdup (name); if (key == NULL) { - ERROR ("plugin: create_register_callback: strdup failed."); + ERROR ("plugin: register_callback: strdup failed."); destroy_callback (cf); return (-1); } @@ -194,7 +195,7 @@ static int register_callback (llist_t **list, /* {{{ */ le = llentry_create (key, cf); if (le == NULL) { - ERROR ("plugin: create_register_callback: " + ERROR ("plugin: register_callback: " "llentry_create failed."); free (key); destroy_callback (cf); @@ -210,6 +211,10 @@ static int register_callback (llist_t **list, /* {{{ */ old_cf = le->value; le->value = cf; + WARNING ("plugin: register_callback: " + "a callback named `%s' already exists - " + "overwriting the old entry!", name); + destroy_callback (old_cf); sfree (key); } @@ -275,8 +280,6 @@ static int plugin_load_file (char *file, uint32_t flags) lt_dlhandle dlh; void (*reg_handle) (void); - DEBUG ("file = %s", file); - lt_dlinit (); lt_dlerror (); /* clear errors */ @@ -292,23 +295,35 @@ static int plugin_load_file (char *file, uint32_t flags) } #else /* if LIBTOOL_VERSION == 1 */ if (flags & PLUGIN_FLAGS_GLOBAL) - ERROR ("plugin_load_file: The global flag is not supported, " + WARNING ("plugin_load_file: The global flag is not supported, " "libtool 2 is required for this."); dlh = lt_dlopen (file); #endif if (dlh == NULL) { - const char *error = lt_dlerror (); + char errbuf[1024] = ""; + + ssnprintf (errbuf, sizeof (errbuf), + "lt_dlopen (\"%s\") failed: %s. " + "The most common cause for this problem is " + "missing dependencies. Use ldd(1) to check " + "the dependencies of the plugin " + "/ shared object.", + file, lt_dlerror ()); + + ERROR ("%s", errbuf); + /* Make sure this is printed to STDERR in any case, but also + * make sure it's printed only once. */ + if (list_log != NULL) + fprintf (stderr, "ERROR: %s\n", errbuf); - ERROR ("lt_dlopen (%s) failed: %s", file, error); - fprintf (stderr, "lt_dlopen (%s) failed: %s\n", file, error); return (1); } if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL) { - WARNING ("Couldn't find symbol `module_register' in `%s': %s\n", + WARNING ("Couldn't find symbol \"module_register\" in \"%s\": %s\n", file, lt_dlerror ()); lt_dlclose (dlh); return (-1); @@ -319,6 +334,13 @@ static int plugin_load_file (char *file, uint32_t flags) return (0); } +static _Bool timeout_reached(struct timespec timeout) +{ + struct timeval now; + gettimeofday(&now, NULL); + return (now.tv_sec >= timeout.tv_sec && now.tv_usec >= (timeout.tv_nsec / 1000)); +} + static void *plugin_read_thread (void __attribute__((unused)) *args) { while (read_loop != 0) @@ -327,9 +349,10 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) struct timeval now; int status; int rf_type; + int rc; /* Get the read function that needs to be read next. */ - rf = c_head_get_root (read_heap); + rf = c_heap_get_root (read_heap); if (rf == NULL) { struct timespec abstime; @@ -362,9 +385,20 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) /* sleep until this entry is due, * using pthread_cond_timedwait */ pthread_mutex_lock (&read_lock); - pthread_cond_timedwait (&read_cond, &read_lock, + /* In pthread_cond_timedwait, spurious wakeups are possible + * (and really happen, at least on NetBSD with > 1 CPU), thus + * we need to re-evaluate the condition every time + * pthread_cond_timedwait returns. */ + rc = 0; + while ((read_loop != 0) + && !timeout_reached(rf->rf_next_read) + && rc == 0) + { + rc = pthread_cond_timedwait (&read_cond, &read_lock, &rf->rf_next_read); - /* Must hold `real_lock' when accessing `rf->rf_type'. */ + } + + /* Must hold `read_lock' when accessing `rf->rf_type'. */ rf_type = rf->rf_type; pthread_mutex_unlock (&read_lock); @@ -752,6 +786,7 @@ int plugin_register_read (const char *name, rf->rf_callback = (void *) callback; rf->rf_udata.data = NULL; rf->rf_udata.free_func = NULL; + rf->rf_group[0] = '\0'; sstrncpy (rf->rf_name, name, sizeof (rf->rf_name)); rf->rf_type = RF_SIMPLE; rf->rf_interval.tv_sec = 0; @@ -761,7 +796,7 @@ int plugin_register_read (const char *name, return (plugin_insert_read (rf)); } /* int plugin_register_read */ -int plugin_register_complex_read (const char *name, +int plugin_register_complex_read (const char *group, const char *name, plugin_read_cb callback, const struct timespec *interval, user_data_t *user_data) @@ -777,6 +812,10 @@ int plugin_register_complex_read (const char *name, memset (rf, 0, sizeof (read_func_t)); rf->rf_callback = (void *) callback; + if (group != NULL) + sstrncpy (rf->rf_group, group, sizeof (rf->rf_group)); + else + rf->rf_group[0] = '\0'; sstrncpy (rf->rf_name, name, sizeof (rf->rf_name)); rf->rf_type = RF_COMPLEX; if (interval != NULL) @@ -813,7 +852,7 @@ int plugin_register_flush (const char *name, (void *) callback, ud)); } /* int plugin_register_flush */ -int plugin_register_shutdown (char *name, +int plugin_register_shutdown (const char *name, int (*callback) (void)) { return (create_register_callback (&list_shutdown, name, @@ -928,6 +967,67 @@ int plugin_unregister_read (const char *name) /* {{{ */ return (0); } /* }}} int plugin_unregister_read */ +static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */ +{ + read_func_t *rf = e->value; + char *group = ud; + + return strcmp (rf->rf_group, (const char *)group); +} /* }}} int compare_read_func_group */ + +int plugin_unregister_read_group (const char *group) /* {{{ */ +{ + llentry_t *le; + read_func_t *rf; + + int found = 0; + + if (group == NULL) + return (-ENOENT); + + pthread_mutex_lock (&read_lock); + + if (read_list == NULL) + { + pthread_mutex_unlock (&read_lock); + return (-ENOENT); + } + + while (42) + { + le = llist_search_custom (read_list, + compare_read_func_group, (void *)group); + + if (le == NULL) + break; + + ++found; + + llist_remove (read_list, le); + + rf = le->value; + assert (rf != NULL); + rf->rf_type = RF_REMOVE; + + llentry_destroy (le); + + DEBUG ("plugin_unregister_read_group: " + "Marked `%s' (group `%s') for removal.", + rf->rf_name, group); + } + + pthread_mutex_unlock (&read_lock); + + if (found == 0) + { + WARNING ("plugin_unregister_read_group: No such " + "group of read function: %s", group); + return (-ENOENT); + } + + return (0); +} /* }}} int plugin_unregister_read_group */ + int plugin_unregister_write (const char *name) { return (plugin_unregister (list_write, name)); @@ -1053,7 +1153,7 @@ int plugin_read_all_once (void) { read_func_t *rf; - rf = c_head_get_root (read_heap); + rf = c_heap_get_root (read_heap); if (rf == NULL) break; @@ -1258,7 +1358,8 @@ int plugin_dispatch_values (value_list_t *vl) if ((vl == NULL) || (vl->type[0] == 0) || (vl->values == NULL) || (vl->values_len < 1)) { - ERROR ("plugin_dispatch_values: Invalid value list."); + ERROR ("plugin_dispatch_values: Invalid value list " + "from plugin %s.", vl->plugin); return (-1); } @@ -1284,7 +1385,12 @@ int plugin_dispatch_values (value_list_t *vl) if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0) { - INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type); + char ident[6 * DATA_MAX_NAME_LEN]; + + FORMAT_VL (ident, sizeof (ident), vl); + INFO ("plugin_dispatch_values: Dataset not found: %s " + "(from \"%s\"), check your types.db!", + vl->type, ident); return (-1); } @@ -1417,6 +1523,52 @@ int plugin_dispatch_values (value_list_t *vl) return (0); } /* int plugin_dispatch_values */ +int plugin_dispatch_values_secure (const value_list_t *vl) +{ + value_list_t vl_copy; + int status; + + if (vl == NULL) + return EINVAL; + + memcpy (&vl_copy, vl, sizeof (vl_copy)); + + /* Write callbacks must not change the values and meta pointers, so we can + * savely skip copying those and make this more efficient. */ + if ((pre_cache_chain == NULL) && (post_cache_chain == NULL)) + return (plugin_dispatch_values (&vl_copy)); + + /* Set pointers to NULL, just to be on the save side. */ + vl_copy.values = NULL; + vl_copy.meta = NULL; + + vl_copy.values = malloc (sizeof (*vl_copy.values) * vl->values_len); + if (vl_copy.values == NULL) + { + ERROR ("plugin_dispatch_values_secure: malloc failed."); + return (ENOMEM); + } + memcpy (vl_copy.values, vl->values, sizeof (*vl_copy.values) * vl->values_len); + + if (vl->meta != NULL) + { + vl_copy.meta = meta_data_clone (vl->meta); + if (vl_copy.meta == NULL) + { + ERROR ("plugin_dispatch_values_secure: meta_data_clone failed."); + free (vl_copy.values); + return (ENOMEM); + } + } /* if (vl->meta) */ + + status = plugin_dispatch_values (&vl_copy); + + meta_data_destroy (vl_copy.meta); + free (vl_copy.values); + + return (status); +} /* int plugin_dispatch_values_secure */ + int plugin_dispatch_notification (const notification_t *notif) { llentry_t *le; @@ -1460,9 +1612,6 @@ void plugin_log (int level, const char *format, ...) va_list ap; llentry_t *le; - if (list_log == NULL) - return; - #if !COLLECT_DEBUG if (level >= LOG_DEBUG) return; @@ -1473,6 +1622,12 @@ void plugin_log (int level, const char *format, ...) msg[sizeof (msg) - 1] = '\0'; va_end (ap); + if (list_log == NULL) + { + fprintf (stderr, "%s\n", msg); + return; + } + le = llist_head (list_log); while (le != NULL) {