X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fplugin.c;h=2daeea9fd67e42e8ef36c5b6eee4e185542ed8e1;hb=2cea8075c666a6c6c7d6e1b4f95e1bee6f3803ac;hp=a6792de055251a18c62d9688eba94904fb211ec9;hpb=7fa270a1fb517c7fbed55d9f5f70bb28516b6229;p=collectd.git diff --git a/src/plugin.c b/src/plugin.c index a6792de0..2daeea9f 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -1,11 +1,10 @@ /** * collectd - src/plugin.c - * Copyright (C) 2005 Florian octo Forster + * Copyright (C) 2005,2006 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * Free Software Foundation; only version 2 of the License is applicable. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,105 +24,178 @@ #include #include "plugin.h" -#include "multicast.h" +#include "configfile.h" +#include "utils_llist.h" +#include "utils_debug.h" -typedef struct plugin +/* + * Private structures + */ +struct read_func_s { - char *type; - void (*init) (void); - void (*read) (void); - void (*write) (char *host, char *inst, char *val); - struct plugin *next; -} plugin_t; + int wait_time; + int wait_left; + int (*callback) (void); +}; +typedef struct read_func_s read_func_t; + +/* + * Private variables + */ +static llist_t *list_init; +static llist_t *list_read; +static llist_t *list_write; +static llist_t *list_shutdown; +static llist_t *list_data_set; -static plugin_t *first_plugin = NULL; +static char *plugindir = NULL; -#ifdef HAVE_LIBRRD -extern int operating_mode; -#endif +char hostname[DATA_MAX_NAME_LEN] = "localhost"; /* - * Returns the number of plugins registered + * Static functions */ -int plugin_count (void) +static const char *plugin_get_dir (void) { - int i; - plugin_t *p; + if (plugindir == NULL) + return (PLUGINDIR); + else + return (plugindir); +} - for (i = 0, p = first_plugin; p != NULL; p = p->next) - i++; +static int register_callback (llist_t **list, const char *name, void *callback) +{ + llentry_t *le; - return (i); -} + if ((*list == NULL) + && ((*list = llist_create ()) == NULL)) + return (-1); -/* - * Returns the plugins with the type `type' or NULL if it's not found. - */ -plugin_t *plugin_search (char *type) + le = llist_search (*list, name); + if (le == NULL) + { + le = llentry_create (name, callback); + if (le == NULL) + return (-1); + + llist_append (*list, le); + } + else + { + le->value = callback; + } + + return (0); +} /* int register_callback */ + +static int plugin_unregister (llist_t *list, const char *name) { - plugin_t *ret; + llentry_t *e; - if (type == NULL) - return (NULL); + e = llist_search (list, name); - for (ret = first_plugin; ret != NULL; ret = ret->next) - if (strcmp (ret->type, type) == 0) - break; + if (e == NULL) + return (-1); - return (ret); -} + llist_remove (list, e); + llentry_destroy (e); + + return (0); +} /* int plugin_unregister */ /* - * (Try to) load the shared object `name'. Won't complain if it isn't a shared + * (Try to) load the shared object `file'. Won't complain if it isn't a shared * object, but it will bitch about a shared object not having a * ``module_register'' symbol.. */ -void plugin_load (char *name) +static int plugin_load_file (char *file) { lt_dlhandle dlh; void (*reg_handle) (void); + DBG ("file = %s", file); + lt_dlinit (); lt_dlerror (); /* clear errors */ - if ((dlh = lt_dlopen (name)) == NULL) - return; + if ((dlh = lt_dlopen (file)) == NULL) + { + const char *error = lt_dlerror (); + + syslog (LOG_ERR, "lt_dlopen failed: %s", error); + DBG ("lt_dlopen failed: %s", error); + return (1); + } - if ((reg_handle = lt_dlsym (dlh, "module_register")) == NULL) + if ((reg_handle = (void (*) (void)) lt_dlsym (dlh, "module_register")) == NULL) { syslog (LOG_WARNING, "Couldn't find symbol ``module_register'' in ``%s'': %s\n", - name, lt_dlerror ()); + file, lt_dlerror ()); lt_dlclose (dlh); - return; + return (-1); } (*reg_handle) (); + + return (0); } /* - * (Try to) load all plugins in `dir'. Returns the number of loaded plugins.. + * Public functions */ +void plugin_set_dir (const char *dir) +{ + if (plugindir != NULL) + free (plugindir); + + if (dir == NULL) + plugindir = NULL; + else if ((plugindir = strdup (dir)) == NULL) + syslog (LOG_ERR, "strdup failed: %s", strerror (errno)); +} + #define BUFSIZE 512 -int plugin_load_all (char *dir) +int plugin_load (const char *type) { - DIR *dh; + DIR *dh; + const char *dir; + char filename[BUFSIZE]; + char typename[BUFSIZE]; + int typename_len; + int ret; + struct stat statbuf; struct dirent *de; - char filename[BUFSIZE]; - struct stat statbuf; - if (dir == NULL) - dir = PLUGINDIR; + DBG ("type = %s", type); + + dir = plugin_get_dir (); + ret = 1; + + /* `cpu' should not match `cpufreq'. To solve this we add `.so' to the + * type when matching the filename */ + if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE) + { + syslog (LOG_WARNING, "snprintf: truncated: `%s.so'", type); + return (-1); + } + typename_len = strlen (typename); if ((dh = opendir (dir)) == NULL) { - fprintf (stderr, "Error: Cannot read plugin directory `%s'\n", dir); - return (0); + syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno)); + return (-1); } while ((de = readdir (dh)) != NULL) { + if (strncasecmp (de->d_name, typename, typename_len)) + continue; + if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE) + { + syslog (LOG_WARNING, "snprintf: truncated: `%s/%s'", dir, de->d_name); continue; + } if (lstat (filename, &statbuf) == -1) { @@ -132,106 +204,284 @@ int plugin_load_all (char *dir) } else if (!S_ISREG (statbuf.st_mode)) { + /* don't follow symlinks */ continue; } - plugin_load (filename); + if (plugin_load_file (filename) == 0) + { + /* success */ + ret = 0; + break; + } } closedir (dh); - return (plugin_count ()); + return (ret); } -#undef BUFSIZE /* - * Call `init' on all plugins (if given) + * The `register_*' functions follow */ -void plugin_init_all (void) +int plugin_register_config (const char *name, + int (*callback) (const char *key, const char *val), + const char **keys, int keys_num) +{ + cf_register (name, callback, keys, keys_num); + return (0); +} /* int plugin_register_config */ + +int plugin_register_init (const char *name, + int (*callback) (void)) { - plugin_t *p; + return (register_callback (&list_init, name, (void *) callback)); +} /* plugin_register_init */ - for (p = first_plugin; p != NULL; p = p->next) - if (p->init != NULL) - (*p->init) (); +int plugin_register_read (const char *name, + int (*callback) (void)) +{ + read_func_t *rf; + + rf = (read_func_t *) malloc (sizeof (read_func_t)); + if (rf == NULL) + { + syslog (LOG_ERR, "plugin_register_read: malloc failed: %s", + strerror (errno)); + return (-1); + } + + memset (rf, '\0', sizeof (read_func_t)); + rf->wait_time = atoi (COLLECTD_STEP); + rf->wait_left = 0; + rf->callback = callback; + + return (register_callback (&list_read, name, (void *) rf)); +} /* int plugin_register_read */ + +int plugin_register_write (const char *name, + int (*callback) (const data_set_t *ds, const value_list_t *vl)) +{ + return (register_callback (&list_write, name, (void *) callback)); +} /* int plugin_register_write */ + +int plugin_register_shutdown (char *name, + int (*callback) (void)) +{ + return (register_callback (&list_shutdown, name, (void *) callback)); +} /* int plugin_register_shutdown */ + +int plugin_register_data_set (const data_set_t *ds) +{ + return (register_callback (&list_data_set, ds->type, (void *) ds)); +} /* int plugin_register_data_set */ + +int plugin_unregister_init (const char *name) +{ + return (plugin_unregister (list_init, name)); } -/* - * Call `read' on all plugins (if given) - */ -void plugin_read_all (void) +int plugin_unregister_read (const char *name) +{ + return (plugin_unregister (list_read, name)); + llentry_t *e; + + e = llist_search (list_read, name); + + if (e == NULL) + return (-1); + + llist_remove (list_read, e); + free (e->value); + llentry_destroy (e); + + return (0); +} + +int plugin_unregister_write (const char *name) { - plugin_t *p; + return (plugin_unregister (list_write, name)); +} - for (p = first_plugin; p != NULL; p = p->next) - if (p->read != NULL) - (*p->read) (); +int plugin_unregister_shutdown (const char *name) +{ + return (plugin_unregister (list_shutdown, name)); } -/* - * Add plugin to the linked list of registered plugins. - */ -void plugin_register (char *type, - void (*init) (void), - void (*read) (void), - void (*write) (char *, char *, char *)) +int plugin_unregister_data_set (const char *name) +{ + return (plugin_unregister (list_data_set, name)); +} + +void plugin_init_all (void) { - plugin_t *p; + int (*callback) (void); + llentry_t *le; + + gethostname (hostname, sizeof (hostname)); - if (plugin_search (type) != NULL) + if (list_init == NULL) return; - if ((p = (plugin_t *) malloc (sizeof (plugin_t))) == NULL) + le = llist_head (list_init); + while (le != NULL) + { + callback = le->value; + (*callback) (); + + le = le->next; + } +} /* void plugin_init_all */ + +void plugin_read_all (const int *loop) +{ + llentry_t *le; + read_func_t *rf; + int status; + int step; + + if (list_read == NULL) return; - if ((p->type = strdup (type)) == NULL) + step = atoi (COLLECTD_STEP); + + le = llist_head (list_read); + while ((*loop == 0) && (le != NULL)) { - free (p); + rf = (read_func_t *) le->value; + + if (rf->wait_left > 0) + rf->wait_left -= step; + if (rf->wait_left > 0) + { + le = le->next; + continue; + } + + status = rf->callback (); + if (status != 0) + { + rf->wait_left = rf->wait_time; + rf->wait_time = rf->wait_time * 2; + if (rf->wait_time > 86400) + rf->wait_time = 86400; + + syslog (LOG_NOTICE, "read-function of plugin `%s' " + "failed. Will syspend it for %i " + "seconds.", le->key, rf->wait_left); + } + else + { + rf->wait_left = 0; + rf->wait_time = step; + } + + le = le->next; + } /* while ((*loop == 0) && (le != NULL)) */ +} /* void plugin_read_all */ + +void plugin_shutdown_all (void) +{ + int (*callback) (void); + llentry_t *le; + + if (list_shutdown == NULL) return; + + le = llist_head (list_shutdown); + while (le != NULL) + { + callback = le->value; + (*callback) (); + + le = le->next; } +} /* void plugin_shutdown_all */ - p->init = init; - p->read = read; - p->write = write; +int plugin_dispatch_values (const char *name, const value_list_t *vl) +{ + int (*callback) (const data_set_t *, const value_list_t *); + data_set_t *ds; + llentry_t *le; + + if (list_write == NULL) + return (-1); - p->next = first_plugin; - first_plugin = p; + le = llist_search (list_data_set, name); + if (le == NULL) + { + DBG ("No such dataset registered: %s", name); + return (-1); + } + + ds = (data_set_t *) le->value; + + DBG ("time = %u; host = %s; " + "plugin = %s; plugin_instance = %s; " + "type = %s; type_instance = %s;", + (unsigned int) vl->time, vl->host, + vl->plugin, vl->plugin_instance, + ds->type, vl->type_instance); + + le = llist_head (list_write); + while (le != NULL) + { + callback = le->value; + (*callback) (ds, vl); + + le = le->next; + } + + return (0); } -/* - * Send received data back to the plugin/module which will append DS - * definitions and pass it on to ``rrd_update_file''. - */ -#ifdef HAVE_LIBRRD -void plugin_write (char *host, char *type, char *inst, char *val) +void plugin_complain (int level, complain_t *c, const char *format, ...) { - plugin_t *p; + char message[512]; + va_list ap; + int step; - if ((p = plugin_search (type)) == NULL) + if (c->delay > 0) + { + c->delay--; return; + } - if (p->write == NULL) - return; + step = atoi (COLLECTD_STEP); + assert (step > 0); + + if (c->interval < step) + c->interval = step; + else + c->interval *= 2; + + if (c->interval > 86400) + c->interval = 86400; + + c->delay = c->interval / step; + + va_start (ap, format); + vsnprintf (message, 512, format, ap); + message[511] = '\0'; + va_end (ap); - (*p->write) (host, inst, val); + syslog (level, message); } -#endif /* HAVE_LIBRRD */ -/* - * Receive data from the plugin/module and get it somehow to ``plugin_write'': - * Either using ``multicast_send'' (when in network/client mode) or call it - * directly (in local mode). - */ -void plugin_submit (char *type, char *inst, char *val) -{ -#ifdef HAVE_LIBRRD - if (operating_mode == MODE_LOCAL) - plugin_write (NULL, type, inst, val); - else if (operating_mode == MODE_CLIENT) - multicast_send (type, inst, val); - else /* operating_mode == MODE_SERVER */ - syslog (LOG_ERR, "WTF is the server doing in ``plugin_submit''?!?\n"); -#else - multicast_send (type, inst, val); -#endif +void plugin_relief (int level, complain_t *c, const char *format, ...) +{ + char message[512]; + va_list ap; + + if (c->interval == 0) + return; + + c->interval = 0; + + va_start (ap, format); + vsnprintf (message, 512, format, ap); + message[511] = '\0'; + va_end (ap); + + syslog (level, message); }