From 2fb08f10b81b2639a1147ad915ca2c2c420f7b17 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 8 Sep 2008 18:15:02 +0000 Subject: [PATCH] First cut SD plugin + minor plugin changes git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7564 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/dird/dir_plugins.h | 12 +- bacula/src/filed/fd_plugins.h | 12 +- bacula/src/plugins/README | 22 +- bacula/src/plugins/dir/example-plugin-dir.c | 2 +- bacula/src/plugins/sd/Makefile | 24 +- bacula/src/stored/Makefile.in | 2 +- bacula/src/stored/sd_plugins.c | 257 ++++++++++++++++++++ bacula/src/stored/sd_plugins.h | 183 ++++++++++++++ bacula/src/version.h | 4 +- bacula/technotes-2.5 | 2 + 10 files changed, 486 insertions(+), 34 deletions(-) create mode 100644 bacula/src/stored/sd_plugins.c create mode 100644 bacula/src/stored/sd_plugins.h diff --git a/bacula/src/dird/dir_plugins.h b/bacula/src/dird/dir_plugins.h index 68362429ad..d631e98a8e 100644 --- a/bacula/src/dird/dir_plugins.h +++ b/bacula/src/dird/dir_plugins.h @@ -155,12 +155,12 @@ typedef enum { 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 { diff --git a/bacula/src/filed/fd_plugins.h b/bacula/src/filed/fd_plugins.h index 2ca6cf017c..24a77401a8 100644 --- a/bacula/src/filed/fd_plugins.h +++ b/bacula/src/filed/fd_plugins.h @@ -205,12 +205,12 @@ typedef enum { 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; /* diff --git a/bacula/src/plugins/README b/bacula/src/plugins/README index 559a1f163e..6e9112e94d 100644 --- a/bacula/src/plugins/README +++ b/bacula/src/plugins/README @@ -15,23 +15,27 @@ What is implemented: 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). diff --git a/bacula/src/plugins/dir/example-plugin-dir.c b/bacula/src/plugins/dir/example-plugin-dir.c index 14129e6beb..ff1474a770 100644 --- a/bacula/src/plugins/dir/example-plugin-dir.c +++ b/bacula/src/plugins/dir/example-plugin-dir.c @@ -42,7 +42,7 @@ extern "C" { #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); diff --git a/bacula/src/plugins/sd/Makefile b/bacula/src/plugins/sd/Makefile index fc79538f3a..cc2775f043 100644 --- a/bacula/src/plugins/sd/Makefile +++ b/bacula/src/plugins/sd/Makefile @@ -1,25 +1,31 @@ # -# 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 diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index abb3f1741f..7193b73e06 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -27,7 +27,7 @@ SDOBJS = stored.o ansi_label.o vtape.o \ 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 diff --git a/bacula/src/stored/sd_plugins.c b/bacula/src/stored/sd_plugins.c new file mode 100644 index 0000000000..d289c986d8 --- /dev/null +++ b/bacula/src/stored/sd_plugins.c @@ -0,0 +1,257 @@ +/* + 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 */ diff --git a/bacula/src/stored/sd_plugins.h b/bacula/src/stored/sd_plugins.h new file mode 100644 index 0000000000..5974fc9ff3 --- /dev/null +++ b/bacula/src/stored/sd_plugins.h @@ -0,0 +1,183 @@ +/* + 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 +#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 */ diff --git a/bacula/src/version.h b/bacula/src/version.h index 0153028c76..10c63b9963 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #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 */ diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index 9be8a02c8d..68488fae35 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -61,6 +61,8 @@ plugin 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. -- 2.39.5