Replaced all hardcoded heartbeat values (== 25 seconds) with `COLLECTD_HEARTBEAT'.
[collectd.git] / src / plugin.c
index 9bc02ab..fc79668 100644 (file)
@@ -25,7 +25,7 @@
 #include <ltdl.h>
 
 #include "plugin.h"
-#include "multicast.h"
+#include "network.h"
 
 typedef struct plugin
 {
@@ -42,6 +42,27 @@ static plugin_t *first_plugin = NULL;
 extern int operating_mode;
 #endif
 
+static char *plugindir = NULL;
+
+char *plugin_get_dir (void)
+{
+       if (plugindir == NULL)
+               return (PLUGINDIR);
+       else
+               return (plugindir);
+}
+
+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: %s", strerror (errno));
+}
+
 /*
  * Returns the number of plugins registered
  */
@@ -59,7 +80,7 @@ int plugin_count (void)
 /*
  * Returns the plugins with the type `type' or NULL if it's not found.
  */
-plugin_t *plugin_search (char *type)
+plugin_t *plugin_search (const char *type)
 {
        plugin_t *ret;
 
@@ -86,11 +107,11 @@ int plugin_exists (char *type)
 }
 
 /*
- * (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)
+int plugin_load_file (char *file)
 {
        lt_dlhandle dlh;
        void (*reg_handle) (void);
@@ -98,24 +119,94 @@ void plugin_load (char *name)
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
 
-       if ((dlh = lt_dlopen (name)) == NULL)
-               return;
+       if ((dlh = lt_dlopen (file)) == NULL)
+               return (1);
 
        if ((reg_handle = 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);
+}
+
+#define BUFSIZE 512
+int plugin_load (const char *type)
+{
+       DIR  *dh;
+       char *dir;
+       char  filename[BUFSIZE];
+       char  typename[BUFSIZE];
+       int   typename_len;
+       int   ret;
+       struct stat    statbuf;
+       struct dirent *de;
+
+       dir = plugin_get_dir ();
+       ret = 1;
+
+       /* don't load twice */
+       if (plugin_search (type) != NULL)
+               return (0);
+
+       /* `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)
+       {
+               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)
+               {
+                       syslog (LOG_WARNING, "stat %s: %s", filename, strerror (errno));
+                       continue;
+               }
+               else if (!S_ISREG (statbuf.st_mode))
+               {
+                       /* don't follow symlinks */
+                       continue;
+               }
+
+               if (plugin_load_file (filename) == 0)
+               {
+                       /* success */
+                       ret = 0;
+                       break;
+               }
+       }
+
+       closedir (dh);
+
+       return (ret);
 }
 
 /*
  * (Try to) load all plugins in `dir'. Returns the number of loaded plugins..
  */
-#define BUFSIZE 512
 int plugin_load_all (char *dir)
 {
        DIR *dh;
@@ -124,18 +215,23 @@ int plugin_load_all (char *dir)
        struct stat statbuf;
 
        if (dir == NULL)
-               dir = PLUGINDIR;
+               dir = plugin_get_dir ();
+       else
+               plugin_set_dir (dir);
 
        if ((dh = opendir (dir)) == NULL)
        {
-               fprintf (stderr, "Error: Cannot read plugin directory `%s'\n", dir);
+               syslog (LOG_ERR, "opendir (%s): %s", dir, strerror (errno));
                return (0);
        }
 
        while ((de = readdir (dh)) != NULL)
        {
                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)
                {
@@ -147,7 +243,7 @@ int plugin_load_all (char *dir)
                        continue;
                }
 
-               plugin_load (filename);
+               plugin_load_file (filename);
        }
 
        closedir (dh);
@@ -193,6 +289,12 @@ void plugin_register (char *type,
        if (plugin_search (type) != NULL)
                return;
 
+#ifdef HAVE_LIBRRD
+       if ((operating_mode == MODE_LOCAL) || (operating_mode == MODE_CLIENT))
+#endif
+               if ((init != NULL) && (read == NULL))
+                       syslog (LOG_NOTICE, "Plugin `%s' doesn't provide a read function.", type);
+
        if ((p = (plugin_t *) malloc (sizeof (plugin_t))) == NULL)
                return;
 
@@ -231,7 +333,7 @@ void plugin_write (char *host, char *type, char *inst, char *val)
 
 /*
  * 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
+ * Either using ``network_send'' (when in network/client mode) or call it
  * directly (in local mode).
  */
 void plugin_submit (char *type, char *inst, char *val)
@@ -240,10 +342,10 @@ void plugin_submit (char *type, char *inst, char *val)
        if (operating_mode == MODE_LOCAL)
                plugin_write (NULL, type, inst, val);
        else if (operating_mode == MODE_CLIENT)
-               multicast_send (type, inst, val);
+               network_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);
+       network_send (type, inst, val);
 #endif
 }