typedef struct s_pluginInfo {
uint32_t size;
uint32_t version;
- char *plugin_magic;
- char *plugin_license;
- char *plugin_author;
- char *plugin_date;
- char *plugin_version;
- char *plugin_description;
+ const char *plugin_magic;
+ const char *plugin_license;
+ const char *plugin_author;
+ const char *plugin_date;
+ const char *plugin_version;
+ const char *plugin_description;
} pInfo;
typedef struct s_pluginFuncs {
typedef struct s_pluginInfo {
uint32_t size;
uint32_t version;
- char *plugin_magic;
- char *plugin_license;
- char *plugin_author;
- char *plugin_date;
- char *plugin_version;
- char *plugin_description;
+ const char *plugin_magic;
+ const char *plugin_license;
+ const char *plugin_author;
+ const char *plugin_date;
+ const char *plugin_version;
+ const char *plugin_description;
} pInfo;
/*
totally independent of Bacula.
- The main test program is intended to be integrated into
Bacula (at least a number of the functions therein).
-
-What is not yet implemented:
- Search for all plugins in the plugin directory
- Implement Bacula context for plugin instances
- Implement plugin context for plugin instances
-- Some better method to pass variables
+- Integrate the code into Bacula
+- Figure out a way to deal with 3 types of plugins (Director,
+ File daemon, Storage daemon).
- Pass Version information in plugin Initialize
+
+What is not yet implemented:
+- Document the interface
+- Test Win32 plugins
+- Print all plugins loaded when Bacula starts
+- Print all plugins loaded during traceback
+- Implement plugin license/version checking
+- Some better method to pass variables
- Define more functionality (Bacula entry points, ...)
-- Integrate the code into Bacula
- Make libbac.a into a shared object and allow plugin
to call functions in directly so that plugins can use
the same "safe" system utilities that Bacula uses.
-- Document the interface
- Document libbac.so (when implemented)
-- Write a couple of plugins that really do something.
-- Figure out a way to deal with 3 types of plugins (Director,
- File daemon, Storage daemon).
+- Write more plugins that really do something.
- Error handling must be much improved and brought into Bacula
programming style. It currently just printf()s a message then
- exits.
+ exits (partially done).
#define PLUGIN_AUTHOR "Kern Sibbald"
#define PLUGIN_DATE "January 2008"
#define PLUGIN_VERSION "1"
-#define PLUGIN_DESCRIPTION "Test File Daemon Plugin"
+#define PLUGIN_DESCRIPTION "Test Director Daemon Plugin"
/* Forward referenced functions */
static bRC newPlugin(bpContext *ctx);
#
-# Simple Makefile for building test plugin-sds for Bacula
+# Simple Makefile for building test SD plugins for Bacula
#
# No optimization for now for easy debugging
CC = g++ -g -O0 -Wall
+SDDIR=../../stored
+SRCDIR=../..
+LIBDIR=../../lib
+
.SUFFIXES: .c .o
.c.o:
- $(CC) -I../.. -DTEST_PROGRAM -c $<
+ $(CC) -I${SRCDIR} -I${SDDIR} -DTEST_PROGRAM -c $<
-all: main plugin-sd.so
+test: main example-plugin-sd.so
-main: main.o plugin-sd.h
- $(CC) -L../../lib main.o -o main -lbac -lpthread -lssl -l crypto -ldl
+sd_plugins.o: ${SDDIR}/sd_plugins.h ${SDDIR}/sd_plugins.c
+ $(CC) -I${SRCDIR} -I${SDDIR} -DTEST_PROGRAM -c ${SDDIR}/sd_plugins.c
-plugin-sd.o: plugin-sd.c plugin-sd.h
- $(CC) -fPIC -I../.. -c plugin-sd.c
+main: sd_plugins.o
+ $(CC) -L${LIBDIR} sd_plugins.o -o main -lbac -lpthread -lssl -l crypto -ldl
-plugin-sd.so: plugin-sd.o
- $(CC) -shared plugin-sd.o -o plugin-sd.so
+example-plugin-sd.o: example-plugin-sd.c ${SDDIR}/sd_plugins.h
+ $(CC) -fPIC -I../.. -I${SDDIR} -c example-plugin-sd.c
+example-plugin-sd.so: example-plugin-sd.o
+ $(CC) -shared example-plugin-sd.o -o example-plugin-sd.so
clean:
rm -f main *.so *.o 1 2 3
device.o dircmd.o dvd.o ebcdic.o fd_cmds.o job.o \
label.o lock.o mac.o match_bsr.o mount.o parse_bsr.o \
pythonsd.o read.o read_record.o record.o \
- reserve.o scan.o \
+ reserve.o scan.o sd_plugins.o \
spool.o status.o stored_conf.o wait.o
# btape
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2007-2008 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
+ 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 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.
+*/
+/*
+ * Main program to test loading and running Bacula plugins.
+ * Destined to become Bacula pluginloader, ...
+ *
+ * Kern Sibbald, October 2007
+ */
+#include "bacula.h"
+#include "stored.h"
+#include "sd_plugins.h"
+
+const int dbglvl = 0;
+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 baculaRegisterEvents(bpContext *ctx, ...);
+static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
+ int type, time_t mtime, const char *msg);
+static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
+ int level, const char *msg);
+
+
+/* Bacula info */
+static bInfo binfo = {
+ sizeof(bFuncs),
+ SD_PLUGIN_INTERFACE_VERSION,
+};
+
+/* Bacula entry points */
+static bFuncs bfuncs = {
+ sizeof(bFuncs),
+ SD_PLUGIN_INTERFACE_VERSION,
+ baculaRegisterEvents,
+ baculaGetValue,
+ baculaSetValue,
+ baculaJobMsg,
+ baculaDebugMsg
+};
+
+/*
+ * Create a plugin event
+ */
+void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
+{
+ bEvent event;
+ Plugin *plugin;
+ int i = 0;
+
+ if (!plugin_list) {
+ return;
+ }
+
+ 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);
+
+ foreach_alist(plugin, plugin_list) {
+ bRC rc;
+ rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
+ if (rc != bRC_OK) {
+ break;
+ }
+ }
+
+ return;
+}
+
+void load_dir_plugins(const char *plugin_dir)
+{
+ if (!plugin_dir) {
+ return;
+ }
+
+ plugin_list = New(alist(10, not_owned_by_alist));
+ load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
+}
+
+/*
+ * Create a new instance of each plugin for this Job
+ */
+void new_plugins(JCR *jcr)
+{
+ Plugin *plugin;
+ int i = 0;
+
+ if (!plugin_list) {
+ return;
+ }
+
+ int num = plugin_list->size();
+
+ if (num == 0) {
+ return;
+ }
+
+ jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
+
+ bpContext *plugin_ctx_list = (bpContext *)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) {
+ /* Start a new instance of each plugin */
+ plugin_ctx_list[i].bContext = (void *)jcr;
+ plugin_ctx_list[i].pContext = NULL;
+ plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
+ }
+}
+
+/*
+ * Free the plugin instances for this Job
+ */
+void free_plugins(JCR *jcr)
+{
+ Plugin *plugin;
+ int i = 0;
+
+ if (!plugin_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) {
+ /* Free the plugin instance */
+ plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
+ }
+ free(plugin_ctx_list);
+ jcr->plugin_ctx_list = NULL;
+}
+
+
+/* ==============================================================
+ *
+ * Callbacks from the plugin
+ *
+ * ==============================================================
+ */
+static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value)
+{
+ JCR *jcr = (JCR *)(ctx->bContext);
+// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
+ if (!value) {
+ return bRC_Error;
+ }
+// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
+ switch (var) {
+ case bVarJobId:
+ *((int *)value) = jcr->JobId;
+ Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
+ break;
+ default:
+ break;
+ }
+ return bRC_OK;
+}
+
+static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value)
+{
+ Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
+ return bRC_OK;
+}
+
+static bRC baculaRegisterEvents(bpContext *ctx, ...)
+{
+ va_list args;
+ uint32_t event;
+
+ va_start(args, ctx);
+ while ((event = va_arg(args, uint32_t))) {
+ Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
+ }
+ va_end(args);
+ return bRC_OK;
+}
+
+static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
+ int type, time_t mtime, const char *msg)
+{
+ Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
+ file, line, type, mtime, msg);
+ return bRC_OK;
+}
+
+static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
+ int level, const char *msg)
+{
+ Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
+ file, line, level, msg);
+ return bRC_OK;
+}
+
+#ifdef TEST_PROGRAM
+
+
+int main(int argc, char *argv[])
+{
+ char plugin_dir[1000];
+ JCR mjcr1, mjcr2;
+ JCR *jcr1 = &mjcr1;
+ JCR *jcr2 = &mjcr2;
+
+ strcpy(my_name, "test-dir");
+
+ getcwd(plugin_dir, sizeof(plugin_dir)-1);
+ load_dir_plugins(plugin_dir);
+
+ jcr1->JobId = 111;
+ new_plugins(jcr1);
+
+ 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");
+ free_plugins(jcr1);
+ generate_plugin_event(jcr2, bEventJobEnd);
+ free_plugins(jcr2);
+
+ unload_plugins();
+
+ Dmsg0(dbglvl, "bacula: OK ...\n");
+ close_memory_pool();
+ sm_dump(false);
+ return 0;
+}
+
+#endif /* TEST_PROGRAM */
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2007-2008 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
+ 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 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.
+*/
+/*
+ * Interface definition for Bacula Plugins
+ *
+ * Kern Sibbald, October 2007
+ *
+ */
+
+#ifndef __SD_PLUGINS_H
+#define __SD_PLUGINS_H
+
+#ifndef _BACULA_H
+#ifdef __cplusplus
+/* Workaround for SGI IRIX 6.5 */
+#define _LANGUAGE_C_PLUS_PLUS 1
+#endif
+#define _REENTRANT 1
+#define _THREAD_SAFE 1
+#define _POSIX_PTHREAD_SEMANTICS 1
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE 1
+#define _LARGE_FILES 1
+#endif
+
+#include <sys/types.h>
+#ifndef __CONFIG_H
+#define __CONFIG_H
+#include "config.h"
+#endif
+#include "bc_types.h"
+#include "lib/plugins.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+/****************************************************************************
+ * *
+ * Bacula definitions *
+ * *
+ ****************************************************************************/
+
+/* Bacula Variable Ids */
+typedef enum {
+ bVarJob = 1,
+ bVarLevel = 2,
+ bVarType = 3,
+ bVarJobId = 4,
+ bVarClient = 5,
+ bVarNumVols = 6,
+ bVarPool = 7,
+ bVarStorage = 8,
+ bVarCatalog = 9,
+ bVarMediaType = 10,
+ bVarJobName = 11,
+ bVarJobStatus = 12,
+ bVarPriority = 13,
+ bVarVolumeName = 14,
+ bVarCatalogRes = 15,
+ bVarJobErrors = 16,
+ bVarJobFiles = 17,
+ bVarSDJobFiles = 18,
+ bVarSDErrors = 19,
+ bVarFDJobStatus = 20,
+ bVarSDJobStatus = 21
+} brVariable;
+
+typedef enum {
+ bwVarJobReport = 1,
+ bwVarVolumeName = 2,
+ bwVarPriority = 3,
+ bwVarJobLevel = 4,
+} bwVariable;
+
+
+typedef enum {
+ bEventJobStart = 1,
+ bEventJobEnd = 2,
+} bEventType;
+
+typedef struct s_bEvent {
+ uint32_t eventType;
+} bEvent;
+
+typedef struct s_baculaInfo {
+ uint32_t size;
+ uint32_t version;
+} bInfo;
+
+/* Bacula interface version and function pointers */
+typedef struct s_baculaFuncs {
+ uint32_t size;
+ uint32_t version;
+ bRC (*registerBaculaEvents)(bpContext *ctx, ...);
+ bRC (*getBaculaValue)(bpContext *ctx, brVariable var, void *value);
+ bRC (*setBaculaValue)(bpContext *ctx, bwVariable var, void *value);
+ bRC (*JobMessage)(bpContext *ctx, const char *file, int line,
+ int type, time_t mtime, const char *msg);
+ bRC (*DebugMessage)(bpContext *ctx, const char *file, int line,
+ int level, const char *msg);
+} bFuncs;
+
+/* Bacula Subroutines */
+void load_dir_plugins(const char *plugin_dir);
+void new_plugins(JCR *jcr);
+void free_plugins(JCR *jcr);
+void generate_plugin_event(JCR *jcr, bEventType event, void *value=NULL);
+
+
+
+/****************************************************************************
+ * *
+ * Plugin definitions *
+ * *
+ ****************************************************************************/
+
+typedef enum {
+ pVarName = 1,
+ pVarDescription = 2
+} pVariable;
+
+
+#define SD_PLUGIN_MAGIC "*DirPluginData*"
+#define SD_PLUGIN_INTERFACE_VERSION 1
+
+typedef struct s_pluginInfo {
+ uint32_t size;
+ uint32_t version;
+ const char *plugin_magic;
+ const char *plugin_license;
+ const char *plugin_author;
+ const char *plugin_date;
+ const char *plugin_version;
+ const char *plugin_description;
+} pInfo;
+
+typedef struct s_pluginFuncs {
+ uint32_t size;
+ uint32_t version;
+ bRC (*newPlugin)(bpContext *ctx);
+ bRC (*freePlugin)(bpContext *ctx);
+ bRC (*getPluginValue)(bpContext *ctx, pVariable var, void *value);
+ bRC (*setPluginValue)(bpContext *ctx, pVariable var, void *value);
+ bRC (*handlePluginEvent)(bpContext *ctx, bEvent *event, void *value);
+} pFuncs;
+
+#define plug_func(plugin) ((pFuncs *)(plugin->pfuncs))
+#define plug_info(plugin) ((pInfo *)(plugin->pinfo))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SD_PLUGINS_H */
#undef VERSION
#define VERSION "2.5.3"
-#define BDATE "03 September 2008"
-#define LSMDATE "3Sep08"
+#define BDATE "08 September 2008"
+#define LSMDATE "8Sep08"
#define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n"
#define BYEAR "2008" /* year for copyright messages in progs */
remove reader/writer in FOPTS????
General:
+08Sep08
+kes First cut adding SD plugins.
03Sep08
kes Add Slot if it is non-zero to writing bsr file after a
backup.