]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/plugins.c
Detect mount/junction points and ignore junctions in Windows
[bacula/bacula] / bacula / src / lib / plugins.c
index 1c60be7cf4cacb3fc5cd1766a5f0e3dfdb3a7774..35a0abf3679ebe4d0edf491576cb3e0145d2fedd 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation, which is 
    listed in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
  *
  * Kern Sibbald, October 2007
  */
+
 #include "bacula.h"
+#include <dlfcn.h>
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMELEN(dirent) (strlen((dirent)->d_name))
+#endif
+#ifndef HAVE_READDIR_R
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+#endif
+
+#ifndef RTLD_NOW
+#define RTLD_NOW 2
+#endif
+
 #include "plugins.h"
 
+static const int dbglvl = 50;
+
 /* All loaded plugins */
 alist *plugin_list = NULL;
 
@@ -47,20 +63,35 @@ Plugin *new_plugin()
 
    plugin = (Plugin *)malloc(sizeof(Plugin));
    memset(plugin, 0, sizeof(Plugin));
-   plugin_list->append(plugin);
    return plugin;
 }
 
+static void close_plugin(Plugin *plugin)
+{
+   if (plugin->file) {
+      Dmsg1(50, "Got plugin=%s but not accepted.\n", plugin->file);
+   }
+   if (plugin->unloadPlugin) {
+      plugin->unloadPlugin();
+   }
+   if (plugin->pHandle) {
+      dlclose(plugin->pHandle);
+   }
+   if (plugin->file) {
+      free(plugin->file);
+   }
+   free(plugin);
+}
 
 /*
  * Load all the plugins in the specified directory.
  */
-bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char *type)
+bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, 
+        const char *type, bool is_plugin_compatible(Plugin *plugin))
 {
    bool found = false;
-//#ifndef HAVE_WIN32
    t_loadPlugin loadPlugin;
-   Plugin *plugin;
+   Plugin *plugin = NULL;
    DIR* dp = NULL;
    struct dirent *entry = NULL, *result;
    int name_max;
@@ -77,7 +108,9 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char
 
    if (!(dp = opendir(plugin_dir))) {
       berrno be;
-      Jmsg(NULL, M_ERROR, 0, _("Failed to open Plugin directory %s: ERR=%s\n"), 
+      Jmsg(NULL, M_ERROR_TERM, 0, _("Failed to open Plugin directory %s: ERR=%s\n"), 
+            plugin_dir, be.bstrerror());
+      Dmsg2(dbglvl, "Failed to open Plugin directory %s: ERR=%s\n", 
             plugin_dir, be.bstrerror());
       goto get_out;
    }
@@ -88,10 +121,13 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char
    }
    entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
    for ( ;; ) {
+      plugin = NULL;            /* Start from a fresh plugin */
+
       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
          if (!found) {
-            Jmsg(NULL, M_INFO, 0, _("Failed to find any plugins in %s\n"), 
+            Jmsg(NULL, M_WARNING, 0, _("Failed to find any plugins in %s\n"), 
                   plugin_dir);
+            Dmsg1(dbglvl, "Failed to find any plugins in %s\n", plugin_dir);
          }
          break;
       }
@@ -103,10 +139,10 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char
       len = strlen(result->d_name);
       type_len = strlen(type);
       if (len < type_len+1 || strcmp(&result->d_name[len-type_len], type) != 0) {
-         Dmsg3(100, "Rejected plugin: want=%s name=%s len=%d\n", type, result->d_name, len);
+         Dmsg3(dbglvl, "Rejected plugin: want=%s name=%s len=%d\n", type, result->d_name, len);
          continue;
       }
-      Dmsg2(100, "Loaded plugin: name=%s len=%d\n", result->d_name, len);
+      Dmsg2(dbglvl, "Loaded plugin: name=%s len=%d\n", result->d_name, len);
        
       pm_strcpy(fname, plugin_dir);
       if (need_slash) {
@@ -119,11 +155,15 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char
 
       plugin = new_plugin();
       plugin->file = bstrdup(result->d_name);
+      plugin->file_len = strstr(plugin->file, type) - plugin->file;
       plugin->pHandle = dlopen(fname.c_str(), RTLD_NOW);
       if (!plugin->pHandle) {
          Jmsg(NULL, M_ERROR, 0, _("Plugin load %s failed: ERR=%s\n"), 
               fname.c_str(), NPRT(dlerror()));
-         goto get_out;
+         Dmsg2(dbglvl, "Plugin load %s failed: ERR=%s\n", fname.c_str(), 
+               NPRT(dlerror()));
+         close_plugin(plugin);
+         continue;
       }
 
       /* Get two global entry points */
@@ -131,29 +171,47 @@ bool load_plugins(void *binfo, void *bfuncs, const char *plugin_dir, const char
       if (!loadPlugin) {
          Jmsg(NULL, M_ERROR, 0, _("Lookup of loadPlugin in plugin %s failed: ERR=%s\n"),
             fname.c_str(), NPRT(dlerror()));
-         goto get_out;
+         Dmsg2(dbglvl, "Lookup of loadPlugin in plugin %s failed: ERR=%s\n", 
+            fname.c_str(), NPRT(dlerror()));
+         close_plugin(plugin);
+         continue;
       }
       plugin->unloadPlugin = (t_unloadPlugin)dlsym(plugin->pHandle, "unloadPlugin");
       if (!plugin->unloadPlugin) {
          Jmsg(NULL, M_ERROR, 0, _("Lookup of unloadPlugin in plugin %s failed: ERR=%s\n"),
             fname.c_str(), NPRT(dlerror()));
-         goto get_out;
+         Dmsg2(dbglvl, "Lookup of unloadPlugin in plugin %s failed: ERR=%s\n",
+            fname.c_str(), NPRT(dlerror()));
+         close_plugin(plugin);
+         continue;
       }
 
       /* Initialize the plugin */
-      loadPlugin(binfo, bfuncs, &plugin->pinfo, &plugin->pfuncs);
+      if (loadPlugin(binfo, bfuncs, &plugin->pinfo, &plugin->pfuncs) != bRC_OK) {
+         close_plugin(plugin);
+         continue;
+      }
+      if (!is_plugin_compatible) {
+         Dmsg0(50, "Plugin compatibility pointer not set.\n");   
+      } else if (!is_plugin_compatible(plugin)) {
+         close_plugin(plugin);
+         continue;
+      }
 
       found = true;                /* found a plugin */
+      plugin_list->append(plugin);
    }
 
 get_out:
+   if (!found && plugin) {
+      close_plugin(plugin);
+   }
    if (entry) {
       free(entry);
    }
    if (dp) {
       closedir(dp);
    }
-//#endif
    return found;
 }
 
@@ -162,7 +220,6 @@ get_out:
  */
 void unload_plugins()
 {
-//#ifndef HAVE_WIN32
    Plugin *plugin;
 
    if (!plugin_list) {
@@ -179,5 +236,37 @@ void unload_plugins()
    }
    delete plugin_list;
    plugin_list = NULL;
-//#endif
+}
+
+/*
+ * Dump plugin information
+ * Each daemon can register a hook that will be called
+ * after a fatal signal.
+ */
+#define DBG_MAX_HOOK 10
+static dbg_plugin_hook_t *dbg_plugin_hooks[DBG_MAX_HOOK];
+static int dbg_plugin_hook_count=0;
+
+void dbg_plugin_add_hook(dbg_plugin_hook_t *fct)
+{
+   ASSERT(dbg_plugin_hook_count < DBG_MAX_HOOK);
+   dbg_plugin_hooks[dbg_plugin_hook_count++] = fct;
+}
+
+void dbg_print_plugin(FILE *fp)
+{
+   Plugin *plugin;
+   fprintf(fp, "Attempt to dump plugins. Hook count=%d\n", dbg_plugin_hook_count);
+
+   if (!plugin_list) {
+      return;
+   }
+   foreach_alist(plugin, plugin_list) {
+      for(int i=0; i < dbg_plugin_hook_count; i++) {
+//       dbg_plugin_hook_t *fct = dbg_plugin_hooks[i];
+         fprintf(fp, "Plugin %p name=\"%s\" disabled=%d\n",
+                 plugin, plugin->file, plugin->disabled);
+//       fct(plugin, fp);
+      }
+   }
 }