solaris-fixes branch: Applied the swap-patch by Christophe Kalt.
[collectd.git] / src / plugin.c
index a249cf7..2f52157 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * 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
@@ -25,7 +25,8 @@
 #include <ltdl.h>
 
 #include "plugin.h"
-#include "multicast.h"
+#include "network.h"
+#include "utils_debug.h"
 
 typedef struct plugin
 {
@@ -38,9 +39,28 @@ typedef struct plugin
 
 static plugin_t *first_plugin = NULL;
 
-#ifdef HAVE_LIBRRD
 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 +79,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;
 
@@ -77,45 +97,125 @@ plugin_t *plugin_search (char *type)
  * Returns true if the plugin is loaded (i.e. `exists') and false otherwise.
  * This is used in `configfile.c' to skip sections that are not needed..
  */
-bool plugin_exists (char *type)
+int plugin_exists (char *type)
 {
        if (plugin_search (type) == NULL)
-               return (false);
+               return (0);
        else
-               return (true);
+               return (1);
 }
 
 /*
- * (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);
 
+       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);
+}
+
+#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;
+
+       DBG ("type = %s", type);
+
+       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 +224,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 +252,7 @@ int plugin_load_all (char *dir)
                        continue;
                }
 
-               plugin_load (filename);
+               plugin_load_file (filename);
        }
 
        closedir (dh);
@@ -193,6 +298,12 @@ void plugin_register (char *type,
        if (plugin_search (type) != NULL)
                return;
 
+#ifdef HAVE_LIBRRD
+       if (operating_mode != MODE_SERVER)
+#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;
 
@@ -214,7 +325,6 @@ void plugin_register (char *type,
  * 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)
 {
        plugin_t *p;
@@ -227,23 +337,16 @@ void plugin_write (char *host, char *type, char *inst, char *val)
 
        (*p->write) (host, inst, val);
 }
-#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
+ * 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)
 {
-#ifdef HAVE_LIBRRD
-       if (operating_mode == MODE_LOCAL)
+        if (operating_mode == MODE_CLIENT)
+               network_send (type, inst, val);
+       else
                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
 }