]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/sd_plugins.c
Remove old Bacula Systems notices
[bacula/bacula] / bacula / src / stored / sd_plugins.c
index 7bbc7f549ae1c3f02ef4d745d427b0682f62e9a9..8c70440b82eecab4cf8197d9be6d3541cf98b5ac 100644 (file)
@@ -1,29 +1,20 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   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 three of the GNU Affero General Public
-   License as published by the Free Software Foundation, which is 
-   listed in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   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 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.
-
-   Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2017 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  * Main program to test loading and running Bacula plugins.
 #include "stored.h"
 #include "sd_plugins.h"
 
-const int dbglvl = 0;
+const int dbglvl = 250;
 const char *plugin_type = "-sd.so";
 
 
 /* Forward referenced functions */
-static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value);
-static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value);
+static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value);
+static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value);
 static bRC baculaRegisterEvents(bpContext *ctx, ...);
 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
-  int type, utime_t mtime, const char *msg);
+  int type, utime_t mtime, const char *fmt, ...);
 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
-  int level, const char *msg);
+  int level, const char *fmt, ...);
+static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
+  const char *imsg, const char *cmd);
+static bool is_plugin_compatible(Plugin *plugin);
 
 
 /* Bacula info */
-static bInfo binfo = {
-   sizeof(bFuncs),
-   SD_PLUGIN_INTERFACE_VERSION,
+static bsdInfo binfo = {
+   sizeof(bsdFuncs),
+   SD_PLUGIN_INTERFACE_VERSION
 };
 
 /* Bacula entry points */
-static bFuncs bfuncs = {
-   sizeof(bFuncs),
+static bsdFuncs bfuncs = {
+   sizeof(bsdFuncs),
    SD_PLUGIN_INTERFACE_VERSION,
    baculaRegisterEvents,
    baculaGetValue,
    baculaSetValue,
    baculaJobMsg,
-   baculaDebugMsg
+   baculaDebugMsg,
+   baculaEditDeviceCodes,
 };
 
 /*
- * Create a plugin event 
+ * Bacula private context
  */
-void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
+struct bacula_ctx {
+   JCR *jcr;                             /* jcr for plugin */
+   bRC  rc;                              /* last return code */
+   bool disabled;                        /* set if plugin disabled */
+};
+
+static bool is_plugin_disabled(bpContext *plugin_ctx)
 {
-   bEvent event;
+   bacula_ctx *b_ctx;
+   if (!plugin_ctx) {
+      return true;
+   }
+   b_ctx = (bacula_ctx *)plugin_ctx->bContext;
+   return b_ctx->disabled;
+}
+
+#ifdef needed
+static bool is_plugin_disabled(JCR *jcr)
+{
+   return is_plugin_disabled(jcr->plugin_ctx);
+}
+#endif
+
+/*
+ * Create a plugin event
+ */
+int generate_plugin_event(JCR *jcr, bsdEventType eventType, void *value)
+{
+   bpContext *plugin_ctx;
+   bsdEvent event;
    Plugin *plugin;
    int i = 0;
+   bRC rc = bRC_OK;
 
-   if (!plugin_list) {
-      return;
+   if (!b_plugin_list) {
+      Dmsg0(dbglvl, "No b_plugin_list: generate_plugin_event ignored.\n");
+      return bRC_OK;
+   }
+   if (!jcr) {
+      Dmsg0(dbglvl, "No jcr: generate_plugin_event ignored.\n");
+      return bRC_OK;
+   }
+   if (!jcr->plugin_ctx_list) {
+       Dmsg0(dbglvl, "No plugin_ctx_list: generate_plugin_event ignored.\n");
+       return bRC_OK;                  /* Return if no plugins loaded */
+   }
+
+   /* Always handle JobEnd and DeviceClose requests */
+   switch (eventType) {
+   case bsdEventJobEnd:
+   case bsdEventDeviceClose:
+      break;               /* pass these through even if canceled */
+   default:
+      if (jcr->is_job_canceled()) {
+         Dmsg0(dbglvl, "Cancel return from generate_plugin_event\n");
+         return bRC_Cancel;
+      }
    }
 
    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
    event.eventType = eventType;
 
-   Dmsg2(dbglvl, "plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
+   Dmsg2(dbglvl, "sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
 
-   foreach_alist(plugin, plugin_list) {
-      bRC rc;
-      rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
+   foreach_alist_index(i, plugin, b_plugin_list) {
+      plugin_ctx = &plugin_ctx_list[i];
+      if (is_plugin_disabled(plugin_ctx)) {
+         continue;
+      }
+      rc = sdplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
       if (rc != bRC_OK) {
          break;
       }
    }
+   return rc;
+}
+
+
+/*
+ * Create a global plugin event -- i.e. no context
+ */
+int generate_global_plugin_event(bsdGlobalEventType eventType, void *value)
+{
+   bsdEvent event;
+   Plugin *plugin;
+   int i;
+   bRC rc = bRC_OK;
+
+   if (!b_plugin_list) {
+      Dmsg0(dbglvl, "No b_plugin_list: generate_global_plugin_event ignored.\n");
+      return bRC_OK;
+   }
+   event.eventType = eventType;
 
-   return;
+   foreach_alist_index(i, plugin, b_plugin_list) {
+      if (sdplug_func(plugin)->handleGlobalPluginEvent != NULL) {
+         rc = sdplug_func(plugin)->handleGlobalPluginEvent(&event, value);
+         if (rc != bRC_OK) {
+            break;
+         }
+      }
+   }
+   return rc;
 }
 
-static void dump_sd_plugin(Plugin *plugin, FILE *fp)
+
+/*
+ * Print to file the plugin info.
+ */
+void dump_sd_plugin(Plugin *plugin, FILE *fp)
 {
    if (!plugin) {
       return ;
    }
-   pInfo *info = (pInfo *) plugin->pinfo;
+   psdInfo *info = (psdInfo *) plugin->pinfo;
    fprintf(fp, "\tversion=%d\n", info->version);
    fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
    fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
@@ -110,31 +188,116 @@ static void dump_sd_plugin(Plugin *plugin, FILE *fp)
    fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
 }
 
+/**
+ * This entry point is called internally by Bacula to ensure
+ *  that the plugin IO calls come into this code.
+ */
 void load_sd_plugins(const char *plugin_dir)
 {
+   Plugin *plugin;
+   int i;
+
+   Dmsg0(dbglvl, "Load sd plugins\n");
    if (!plugin_dir) {
+      Dmsg0(dbglvl, "No sd plugin dir!\n");
       return;
    }
+   b_plugin_list = New(alist(10, not_owned_by_alist));
+   if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
+                is_plugin_compatible)) {
+      /* Either none found, or some error */
+      if (b_plugin_list->size() == 0) {
+         delete b_plugin_list;
+         b_plugin_list = NULL;
+         Dmsg0(dbglvl, "No plugins loaded\n");
+         return;
+      }
+   }
+   /*
+    * Verify that the plugin is acceptable, and print information
+    *  about it.
+    */
+   foreach_alist_index(i, plugin, b_plugin_list) {
+      Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
+      Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
+   }
 
-   plugin_list = New(alist(10, not_owned_by_alist));
-   load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, NULL);
+   Dmsg1(dbglvl, "num plugins=%d\n", b_plugin_list->size());
    dbg_plugin_add_hook(dump_sd_plugin);
 }
 
+/**
+ * Check if a plugin is compatible.  Called by the load_plugin function
+ *  to allow us to verify the plugin.
+ */
+static bool is_plugin_compatible(Plugin *plugin)
+{
+   psdInfo *info = (psdInfo *)plugin->pinfo;
+   Dmsg0(50, "is_plugin_compatible called\n");
+   if (chk_dbglvl(50)) {
+      dump_sd_plugin(plugin, stdin);
+   }
+   if (strcmp(info->plugin_magic, SD_PLUGIN_MAGIC) != 0) {
+      Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
+           plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
+      Dmsg3(000, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
+           plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
+
+      return false;
+   }
+   if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
+      Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
+           plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
+      Dmsg3(000, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
+           plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
+      return false;
+   }
+   if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
+       strcmp(info->plugin_license, "AGPLv3") != 0 &&
+       strcmp(info->plugin_license, "Bacula") != 0) {
+      Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
+           plugin->file, info->plugin_license);
+      Dmsg2(000, "Plugin license incompatible. Plugin=%s license=%s\n",
+           plugin->file, info->plugin_license);
+      return false;
+   }
+   if (info->size != sizeof(psdInfo)) {
+      Jmsg(NULL, M_ERROR, 0,
+           _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
+           plugin->file, sizeof(psdInfo), info->size);
+      return false;
+   }
+
+   return true;
+}
+
+
 /*
  * Create a new instance of each plugin for this Job
  */
 void new_plugins(JCR *jcr)
 {
    Plugin *plugin;
-   int i = 0;
+   int i = 0;;
 
-   if (!plugin_list) {
+   Dmsg0(dbglvl, "=== enter new_plugins ===\n");
+   if (!b_plugin_list) {
+      Dmsg0(dbglvl, "No sd plugin list!\n");
+      return;
+   }
+   if (jcr->is_job_canceled()) {
+      return;
+   }
+   /*
+    * If plugins already loaded, just return
+    */
+   if (jcr->plugin_ctx_list) {
       return;
    }
 
-   int num = plugin_list->size();
+   int num = b_plugin_list->size();
 
+   Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
    if (num == 0) {
       return;
    }
@@ -142,12 +305,17 @@ void new_plugins(JCR *jcr)
    jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
 
    bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
-   Dmsg2(dbglvl, "Instantiate plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
-   foreach_alist(plugin, plugin_list) {
+   Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
+   foreach_alist_index(i, plugin, b_plugin_list) {
       /* Start a new instance of each plugin */
-      plugin_ctx_list[i].bContext = (void *)jcr;
+      bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
+      memset(b_ctx, 0, sizeof(bacula_ctx));
+      b_ctx->jcr = jcr;
+      plugin_ctx_list[i].bContext = (void *)b_ctx;
       plugin_ctx_list[i].pContext = NULL;
-      plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
+      if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
+         b_ctx->disabled = true;
+      }
    }
 }
 
@@ -159,15 +327,16 @@ void free_plugins(JCR *jcr)
    Plugin *plugin;
    int i = 0;
 
-   if (!plugin_list) {
+   if (!b_plugin_list || !jcr->plugin_ctx_list) {
       return;
    }
 
    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
-   Dmsg2(dbglvl, "Free instance plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
-   foreach_alist(plugin, plugin_list) {
+   Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
+   foreach_alist_index(i, plugin, b_plugin_list) {
       /* Free the plugin instance */
-      plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
+      sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
+      free(plugin_ctx_list[i].bContext);     /* free Bacula private context */
    }
    free(plugin_ctx_list);
    jcr->plugin_ctx_list = NULL;
@@ -180,28 +349,53 @@ void free_plugins(JCR *jcr)
  *
  * ==============================================================
  */
-static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value)
+
+static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
 {
-   JCR *jcr = (JCR *)(ctx->bContext);
-// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
+   JCR *jcr;
+   if (!ctx) {
+      return bRC_Error;
+   }
+   jcr = ((bacula_ctx *)ctx->bContext)->jcr;
+   if (!jcr) {
+      return bRC_Error;
+   }
    if (!value) {
       return bRC_Error;
    }
-// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
    switch (var) {
-   case bVarJobId:
+   case bsdVarJobId:
       *((int *)value) = jcr->JobId;
-      Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
+      Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
+      break;
+   case bsdVarJobName:
+      *((char **)value) = jcr->Job;
+      Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
       break;
+#if 0
+   case bsdVarDevTypes:
+      *((s_kw **)value) = dev_types;
+#endif
    default:
       break;
    }
    return bRC_OK;
 }
 
-static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value)
+static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
 {
-   Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
+   JCR *jcr;
+   if (!value || !ctx) {
+      return bRC_Error;
+   }
+// Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
+   jcr = ((bacula_ctx *)ctx->bContext)->jcr;
+   if (!jcr) {
+      return bRC_Error;
+   }
+// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
+   /* Nothing implemented yet */
+   Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
    return bRC_OK;
 }
 
@@ -212,30 +406,52 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...)
 
    va_start(args, ctx);
    while ((event = va_arg(args, uint32_t))) {
-      Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
+      Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
    }
    va_end(args);
    return bRC_OK;
 }
 
 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
-  int type, utime_t mtime, const char *msg)
+  int type, utime_t mtime, const char *fmt, ...)
 {
-   Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%lld msg=%s\n",
-      file, line, type, mtime, msg);
+   va_list arg_ptr;
+   char buf[2000];
+   JCR *jcr;
+
+   if (ctx) {
+      jcr = ((bacula_ctx *)ctx->bContext)->jcr;
+   } else {
+      jcr = NULL;
+   }
+
+   va_start(arg_ptr, fmt);
+   bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
+   va_end(arg_ptr);
+   Jmsg(jcr, type, mtime, "%s", buf);
    return bRC_OK;
 }
 
 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
-  int level, const char *msg)
+  int level, const char *fmt, ...)
 {
-   Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
-      file, line, level, msg);
+   va_list arg_ptr;
+   char buf[2000];
+
+   va_start(arg_ptr, fmt);
+   bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
+   va_end(arg_ptr);
+   d_msg(file, line, level, "%s", buf);
    return bRC_OK;
 }
 
-#ifdef TEST_PROGRAM
+static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
+  const char *imsg, const char *cmd)
+{
+   return edit_device_codes(dcr, omsg, imsg, cmd);
+}
 
+#ifdef TEST_PROGRAM
 
 int main(int argc, char *argv[])
 {
@@ -245,7 +461,7 @@ int main(int argc, char *argv[])
    JCR *jcr2 = &mjcr2;
 
    strcpy(my_name, "test-dir");
-    
+
    getcwd(plugin_dir, sizeof(plugin_dir)-1);
    load_sd_plugins(plugin_dir);
 
@@ -255,16 +471,16 @@ int main(int argc, char *argv[])
    jcr2->JobId = 222;
    new_plugins(jcr2);
 
-   generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
-   generate_plugin_event(jcr1, bEventJobEnd);
-   generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 1");
+   generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
+   generate_plugin_event(jcr1, bsdEventJobEnd);
+   generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
    free_plugins(jcr1);
-   generate_plugin_event(jcr2, bEventJobEnd);
+   generate_plugin_event(jcr2, bsdEventJobEnd);
    free_plugins(jcr2);
 
    unload_plugins();
 
-   Dmsg0(dbglvl, "bacula: OK ...\n");
+   Dmsg0(dbglvl, "sd-plugin: Test OK ...\n");
    close_memory_pool();
    sm_dump(false);
    return 0;