From: Kern Sibbald Date: Sat, 8 Mar 2008 15:18:47 +0000 (+0000) Subject: Rename fd/dir plugin to use Bacula standard underscore. X-Git-Tag: Release-3.0.0~1731 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c28b3a61c2bab7eb13f407a73467d7a0752ec9b8;p=bacula%2Fbacula Rename fd/dir plugin to use Bacula standard underscore. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6559 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index e3e68e76fc..d202384b28 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -29,7 +29,7 @@ dummy: # SVRSRCS = dird.c admin.c authenticate.c \ autoprune.c backup.c bsr.c \ - catreq.c dir-plugins.c dird_conf.c expand.c \ + catreq.c dir_plugins.c dird_conf.c expand.c \ fd_cmds.c getmsg.c inc_conf.c job.c \ jobq.c migrate.c \ mountreq.c msgchan.c next_vol.c newvol.c \ @@ -44,7 +44,7 @@ SVRSRCS = dird.c admin.c authenticate.c \ ua_status.c ua_tree.c ua_update.c verify.c SVROBJS = dird.o admin.o authenticate.o \ autoprune.o backup.o bsr.o \ - catreq.o dir-plugins.o dird_conf.o expand.o \ + catreq.o dir_plugins.o dird_conf.o expand.o \ fd_cmds.o getmsg.o inc_conf.o job.o \ jobq.o migrate.o \ mountreq.o msgchan.o next_vol.o newvol.o \ diff --git a/bacula/src/dird/dir-plugins.c b/bacula/src/dird/dir-plugins.c deleted file mode 100644 index 1821c593ff..0000000000 --- a/bacula/src/dird/dir-plugins.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - 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 John Walker. - 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 "dird.h" - -const int dbglvl = 0; -const char *plugin_type = "-dir.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), - DIR_PLUGIN_INTERFACE_VERSION, -}; - -/* Bacula entry points */ -static bFuncs bfuncs = { - sizeof(bFuncs), - DIR_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/dird/dir-plugins.h b/bacula/src/dird/dir-plugins.h deleted file mode 100644 index 0e77dbf902..0000000000 --- a/bacula/src/dird/dir-plugins.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - 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 John Walker. - 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 __FD_PLUGINS_H -#define __FD_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 DIR_PLUGIN_MAGIC "*DirPluginData*" -#define DIR_PLUGIN_INTERFACE_VERSION 1 - -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; -} 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 /* __FD_PLUGINS_H */ diff --git a/bacula/src/dird/dir_plugins.c b/bacula/src/dird/dir_plugins.c new file mode 100644 index 0000000000..1821c593ff --- /dev/null +++ b/bacula/src/dird/dir_plugins.c @@ -0,0 +1,256 @@ +/* + 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 John Walker. + 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 "dird.h" + +const int dbglvl = 0; +const char *plugin_type = "-dir.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), + DIR_PLUGIN_INTERFACE_VERSION, +}; + +/* Bacula entry points */ +static bFuncs bfuncs = { + sizeof(bFuncs), + DIR_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/dird/dir_plugins.h b/bacula/src/dird/dir_plugins.h new file mode 100644 index 0000000000..0e77dbf902 --- /dev/null +++ b/bacula/src/dird/dir_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 John Walker. + 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 __FD_PLUGINS_H +#define __FD_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 DIR_PLUGIN_MAGIC "*DirPluginData*" +#define DIR_PLUGIN_INTERFACE_VERSION 1 + +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; +} 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 /* __FD_PLUGINS_H */ diff --git a/bacula/src/dird/dird.h b/bacula/src/dird/dird.h index f4c603fb74..594e6bd5de 100644 --- a/bacula/src/dird/dird.h +++ b/bacula/src/dird/dird.h @@ -36,7 +36,7 @@ #include "lib/runscript.h" #include "lib/breg.h" #include "dird_conf.h" -#include "dir-plugins.h" +#include "dir_plugins.h" #define DIRECTOR_DAEMON 1 diff --git a/bacula/src/filed/Makefile.in b/bacula/src/filed/Makefile.in index 8009ff619d..5ee629842b 100644 --- a/bacula/src/filed/Makefile.in +++ b/bacula/src/filed/Makefile.in @@ -29,11 +29,11 @@ dummy: # SVRSRCS = filed.c authenticate.c acl.c backup.c estimate.c \ - fd-plugins.c \ + fd_plugins.c \ filed_conf.c heartbeat.c job.c pythonfd.c \ restore.c status.c verify.c verify_vol.c SVROBJS = filed.o authenticate.o acl.o backup.o estimate.o \ - fd-plugins.o \ + fd_plugins.o \ filed_conf.o heartbeat.o job.o pythonfd.o \ restore.o status.o verify.o verify_vol.o diff --git a/bacula/src/filed/fd-plugins.c b/bacula/src/filed/fd-plugins.c deleted file mode 100644 index e99ce1fedc..0000000000 --- a/bacula/src/filed/fd-plugins.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - 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 John Walker. - 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 "filed.h" - -const int dbglvl = 50; -const char *plugin_type = "-fd.so"; - -extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level); - -/* Function pointers to be set here */ -extern DLL_IMP_EXP int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode); -extern DLL_IMP_EXP int (*plugin_bclose)(JCR *jcr); -extern DLL_IMP_EXP ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count); -extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count); -extern DLL_IMP_EXP boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence); - - -/* Forward referenced functions */ -static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value); -static bRC baculaSetValue(bpContext *ctx, bVariable 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 *fmt, ...); -static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line, - int level, const char *fmt, ...); - -static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode); -static int my_plugin_bclose(JCR *jcr); -static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count); -static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count); -static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence); - - -/* Bacula info */ -static bInfo binfo = { - sizeof(bFuncs), - FD_PLUGIN_INTERFACE_VERSION -}; - -/* Bacula entry points */ -static bFuncs bfuncs = { - sizeof(bFuncs), - FD_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; /* Return if no plugins loaded */ - } - - bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; - event.eventType = eventType; - - Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId); - - /* Pass event to every plugin */ - foreach_alist(plugin, plugin_list) { - bRC rc; - rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value); - if (rc != bRC_OK) { - break; - } - } - - return; -} - -/* - * Sequence of calls for a backup: - * 1. plugin_save() here is called with ff_pkt - * 2. we find the plugin requested on the command string - * 3. we generate a bEventBackupCommand event to the specified plugin - * and pass it the command string. - * 4. we make a startPluginBackup call to the plugin, which gives - * us the data we need in save_pkt - * 5. we call Bacula's save_file() subroutine to save the specified - * file. The plugin will be called at pluginIO() to supply the - * file data. - * - * Sequence of calls for restore: - * See subroutine plugin_name_stream() below. - */ -int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) -{ - Plugin *plugin; - int i = 0; - int len; - char *p; - char *cmd = ff_pkt->top_fname; - struct save_pkt sp; - bEvent event; - - if (!plugin_list) { - return 1; /* Return if no plugins loaded */ - } - - bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; - event.eventType = bEventBackupCommand; - - /* Handle plugin command here backup */ - Dmsg1(100, "plugin cmd=%s\n", cmd); - if (!(p = strchr(cmd, ':'))) { - Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd); - goto bail_out; - } - len = p - cmd; - if (len <= 0) { - goto bail_out; - } - - foreach_alist(plugin, plugin_list) { - Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); - if (strncmp(plugin->file, cmd, len) != 0) { - i++; - continue; - } - Dmsg1(100, "Command plugin = %s\n", cmd); - /* Send the backup command */ - if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, cmd) != bRC_OK) { - goto bail_out; - } - /* Loop getting filenames to backup then saving them */ - while (!job_canceled(jcr)) { - memset(&sp, 0, sizeof(sp)); - sp.type = FT_REG; - sp.portable = true; - sp.cmd = cmd; - Dmsg3(000, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks, - &sp); - /* Get the file save parameters */ - if (plug_func(plugin)->startBackupFile(&plugin_ctx_list[i], &sp) != bRC_OK) { - goto bail_out; - } - jcr->plugin_ctx = &plugin_ctx_list[i]; - jcr->plugin = plugin; - jcr->plugin_sp = &sp; - ff_pkt = jcr->ff; - ff_pkt->fname = sp.fname; - ff_pkt->type = sp.type; - memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp)); - Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname); - save_file(jcr, ff_pkt, true); - if (plug_func(plugin)->endBackupFile(&plugin_ctx_list[i]) != bRC_More) { - goto bail_out; - } - } - } - Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd); - -bail_out: - return 1; -} - -/* - * Send plugin name start/end record to SD - */ -bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) -{ - int stat; - struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp; - - Dmsg1(000, "send_plugin_name=%s\n", sp->cmd); - if (!sd->fsend("%ld %d 0", jcr->JobFiles+1, STREAM_PLUGIN_NAME)) { - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - sd->bstrerror()); - return false; - } - Dmsg1(000, "send: %s\n", sd->msg); - - if (start) { - stat = sd->fsend("%ld 1 %d %s%c", jcr->JobFiles+1, sp->portable, sp->cmd, 0); - } else { - stat = sd->fsend("%ld 0"); - } - if (!stat) { - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - sd->bstrerror()); - return false; - } - Dmsg1(000, "send: %s\n", sd->msg); - sd->signal(BNET_EOD); /* indicate end of plugin name data */ - return true; -} - -/* - * Plugin name stream found during restore. The record passed in - * argument name was generated in send_plugin_name() above. - */ -void plugin_name_stream(JCR *jcr, char *name) -{ - char *p = name; - char *cmd; - bool start, portable; - Plugin *plugin; - int len; - int i = 0; - bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; - - Dmsg1(100, "Read plugin stream string=%s\n", name); - skip_nonspaces(&p); /* skip over jcr->JobFiles */ - skip_spaces(&p); - start = *p == '1'; - skip_nonspaces(&p); /* skip start/end flag */ - skip_spaces(&p); - portable = *p == '1'; - skip_nonspaces(&p); /* skip portable flag */ - skip_spaces(&p); - cmd = p; - - /* Check for restore end */ - if (!start) { - /* - * If end of restore, notify plugin, then clear flags - */ - plugin = (Plugin *)jcr->plugin; - plug_func(plugin)->endRestoreFile(&plugin_ctx_list[i]); - jcr->plugin_ctx = NULL; - jcr->plugin = NULL; - goto bail_out; - } - - /* - * After this point, we are dealing with a restore start - */ - - Dmsg1(100, "plugin restore cmd=%s\n", cmd); - if (!(p = strchr(cmd, ':'))) { - Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd); - goto bail_out; - } - len = p - cmd; - if (len <= 0) { - goto bail_out; - } - - /* - * Search for correct plugin as specified on the command - */ - foreach_alist(plugin, plugin_list) { - bEvent event; - Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); - if (strncmp(plugin->file, cmd, len) != 0) { - i++; - continue; - } - Dmsg1(100, "Restore Command plugin = %s\n", cmd); - event.eventType = bEventRestoreCommand; - if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], - &event, cmd) != bRC_OK) { - goto bail_out; - } - jcr->plugin_ctx = &plugin_ctx_list[i]; - jcr->plugin = plugin; - goto bail_out; - } -bail_out: - return; -} - -/* - * Tell the plugin to create the file. Return values are - * - * CF_ERROR -- error - * CF_SKIP -- skip processing this file - * CF_EXTRACT -- extract the file (i.e.call i/o routines) - * CF_CREATED -- created, but no content to extract (typically directories) - * - */ -int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) -{ - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - Plugin *plugin = (Plugin *)jcr->plugin; - struct restore_pkt rp; - struct io_pkt io; - - if (!set_cmd_plugin(bfd, jcr)) { - return CF_ERROR; - } - rp.stream = attr->stream; - rp.data_stream = attr->data_stream; - rp.type = attr->type; - rp.file_index = attr->file_index; - rp.LinkFI = attr->LinkFI; - rp.uid = attr->uid; - rp.statp = attr->statp; /* structure assignment */ - rp.attrEx = attr->attrEx; - rp.ofname = attr->ofname; - rp.olname = attr->olname; - rp.where = jcr->where; - rp.RegexWhere = jcr->RegexWhere; - rp.replace = jcr->replace; - if (plug_func(plugin)->createFile(plugin_ctx, &rp) != bRC_OK) { - return CF_ERROR; - } - io.func = IO_OPEN; - io.count = 0; - io.buf = NULL; - io.mode = 0777 & attr->statp.st_mode; - io.flags = O_WRONLY; - if (plug_func(plugin)->pluginIO(plugin_ctx, &io) != bRC_OK) { - return CF_ERROR; - } - return CF_EXTRACT; -} - -/* - * Reset the file attributes after all file I/O is done -- this allows - * the previous access time/dates to be set properly, and it also allows - * us to properly set directory permissions. - */ -bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) -{ - return true; -} - -void load_fd_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); - - /* Plug entry points called from findlib */ - plugin_bopen = my_plugin_bopen; - plugin_bclose = my_plugin_bclose; - plugin_bread = my_plugin_bread; - plugin_bwrite = my_plugin_bwrite; - plugin_blseek = my_plugin_blseek; - -} - -/* - * 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=%p JobId=%d\n", 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=%p JobId=%d\n", 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; -} - -static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode) -{ - Plugin *plugin = (Plugin *)jcr->plugin; - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - struct io_pkt io; - Dmsg0(000, "plugin_bopen\n"); - io.func = IO_OPEN; - io.count = 0; - io.buf = NULL; - io.mode = mode; - io.flags = flags; - plug_func(plugin)->pluginIO(plugin_ctx, &io); - return io.status; -} - -static int my_plugin_bclose(JCR *jcr) -{ - Plugin *plugin = (Plugin *)jcr->plugin; - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - struct io_pkt io; - Dmsg0(000, "plugin_bclose\n"); - io.func = IO_CLOSE; - io.count = 0; - io.buf = NULL; - plug_func(plugin)->pluginIO(plugin_ctx, &io); - return io.status; -} - -static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count) -{ - Plugin *plugin = (Plugin *)jcr->plugin; - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - struct io_pkt io; - Dmsg0(000, "plugin_bread\n"); - io.func = IO_READ; - io.count = count; - io.buf = (char *)buf; - plug_func(plugin)->pluginIO(plugin_ctx, &io); - return (ssize_t)io.status; -} - -static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count) -{ - Plugin *plugin = (Plugin *)jcr->plugin; - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - struct io_pkt io; - Dmsg0(000, "plugin_bwrite\n"); - io.func = IO_WRITE; - io.count = count; - io.buf = (char *)buf; - plug_func(plugin)->pluginIO(plugin_ctx, &io); - return (ssize_t)io.status; -} - -static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence) -{ - Plugin *plugin = (Plugin *)jcr->plugin; - bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; - struct io_pkt io; - Dmsg0(000, "plugin_bseek\n"); - io.func = IO_SEEK; - io.offset = offset; - io.whence = whence; - plug_func(plugin)->pluginIO(plugin_ctx, &io); - return (boffset_t)io.offset; -} - -/* ============================================================== - * - * Callbacks from the plugin - * - * ============================================================== - */ -static bRC baculaGetValue(bpContext *ctx, bVariable 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; - case bVarFDName: - *((char **)value) = my_name; - Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name); - break; - case bVarLevel: - case bVarType: - case bVarClient: - case bVarJobName: - case bVarJobStatus: - case bVarSinceTime: - break; - } - return bRC_OK; -} - -static bRC baculaSetValue(bpContext *ctx, bVariable 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 *fmt, ...) -{ - va_list arg_ptr; - char buf[2000]; - JCR *jcr = (JCR *)(ctx->bContext); - - 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 *fmt, ...) -{ - 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 - -int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL; -int (*plugin_bclose)(JCR *jcr) = NULL; -ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL; -ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL; -boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL; - -int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) -{ - return 0; -} - -bool set_cmd_plugin(BFILE *bfd, JCR *jcr) -{ - return true; -} - -int main(int argc, char *argv[]) -{ - char plugin_dir[1000]; - JCR mjcr1, mjcr2; - JCR *jcr1 = &mjcr1; - JCR *jcr2 = &mjcr2; - - strcpy(my_name, "test-fd"); - - getcwd(plugin_dir, sizeof(plugin_dir)-1); - load_fd_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 2"); - 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/filed/fd-plugins.h b/bacula/src/filed/fd-plugins.h deleted file mode 100644 index 099862d038..0000000000 --- a/bacula/src/filed/fd-plugins.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - 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 John Walker. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. -*/ -/* - * Application Programming Interface (API) definition for Bacula Plugins - * - * Kern Sibbald, October 2007 - * - */ - -#ifndef __FD_PLUGINS_H -#define __FD_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" -#include - -/* - * This packet is used for file save info transfer. -*/ -struct save_pkt { - char *fname; /* Full path and filename */ - char *link; /* Link name if any */ - struct stat statp; /* System stat() packet for file */ - int32_t type; /* FT_xx for this file */ - uint32_t flags; /* Bacula internal flags */ - bool portable; /* set if data format is portable */ - char *cmd; /* command */ -}; - -/* - * This packet is used for file restore info transfer. -*/ -struct restore_pkt { - int32_t stream; /* attribute stream id */ - int32_t data_stream; /* id of data stream to follow */ - int32_t type; /* file type FT */ - int32_t file_index; /* file index */ - int32_t LinkFI; /* file index to data if hard link */ - uid_t uid; /* userid */ - struct stat statp; /* decoded stat packet */ - const char *attrEx; /* extended attributes if any */ - const char *ofname; /* output filename */ - const char *olname; /* output link name */ - const char *where; /* where */ - const char *RegexWhere; /* regex where */ - int replace; /* replace flag */ -}; - -enum { - IO_OPEN = 1, - IO_READ = 2, - IO_WRITE = 3, - IO_CLOSE = 4, - IO_SEEK = 5 -}; - -struct io_pkt { - int32_t func; /* Function code */ - int32_t count; /* read/write count */ - mode_t mode; /* permissions for created files */ - int32_t flags; /* open flags (e.g. O_WRONLY ...) */ - char *buf; /* read/write buffer */ - int32_t status; /* return status */ - int32_t io_errno; /* errno code */ - int32_t whence; - boffset_t offset; -}; - -/**************************************************************************** - * * - * Bacula definitions * - * * - ****************************************************************************/ - -/* Bacula Variable Ids */ -typedef enum { - bVarJobId = 1, - bVarFDName = 2, - bVarLevel = 3, - bVarType = 4, - bVarClient = 5, - bVarJobName = 6, - bVarJobStatus = 7, - bVarSinceTime = 8 -} bVariable; - -typedef enum { - bEventJobStart = 1, - bEventJobEnd = 2, - bEventStartBackupJob = 3, - bEventEndBackupJob = 4, - bEventStartRestoreJob = 5, - bEventEndRestoreJob = 6, - bEventStartVerifyJob = 7, - bEventEndVerifyJob = 8, - bEventBackupCommand = 9, - bEventRestoreCommand = 10, - bEventLevel = 11, - bEventSince = 12, -} bEventType; - -typedef struct s_bEvent { - uint32_t eventType; -} bEvent; - -typedef struct s_baculaInfo { - uint32_t size; - uint32_t version; -} bInfo; - -/* Bacula Core Routines -- not used by plugins */ -struct BFILE; /* forward referenced */ -struct FF_PKT; -void load_fd_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); -bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start); -void plugin_name_stream(JCR *jcr, char *name); -int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace); -bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd); -int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level); - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Bacula interface version and function pointers -- - * i.e. callbacks from the plugin to Bacula - */ -typedef struct s_baculaFuncs { - uint32_t size; - uint32_t version; - bRC (*registerBaculaEvents)(bpContext *ctx, ...); - bRC (*getBaculaValue)(bpContext *ctx, bVariable var, void *value); - bRC (*setBaculaValue)(bpContext *ctx, bVariable var, void *value); - bRC (*JobMessage)(bpContext *ctx, const char *file, int line, - int type, time_t mtime, const char *fmt, ...); - bRC (*DebugMessage)(bpContext *ctx, const char *file, int line, - int level, const char *fmt, ...); -} bFuncs; - - - - -/**************************************************************************** - * * - * Plugin definitions * - * * - ****************************************************************************/ - -typedef enum { - pVarName = 1, - pVarDescription = 2 -} pVariable; - - -#define FD_PLUGIN_MAGIC "*FDPluginData*" -#define FD_PLUGIN_INTERFACE_VERSION 1 - -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; -} pInfo; - -/* - * This is a set of function pointers that Bacula can call - * within the plugin. - */ -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); - bRC (*startBackupFile)(bpContext *ctx, struct save_pkt *sp); - bRC (*endBackupFile)(bpContext *ctx); - bRC (*startRestoreFile)(bpContext *ctx, const char *cmd); - bRC (*endRestoreFile)(bpContext *ctx); - bRC (*pluginIO)(bpContext *ctx, struct io_pkt *io); - bRC (*createFile)(bpContext *ctx, struct restore_pkt *rp); - bRC (*setFileAttributes)(bpContext *ctx, struct restore_pkt *rp); -} pFuncs; - -#define plug_func(plugin) ((pFuncs *)(plugin->pfuncs)) -#define plug_info(plugin) ((pInfo *)(plugin->pinfo)) - -#ifdef __cplusplus -} -#endif - -#endif /* __FD_PLUGINS_H */ diff --git a/bacula/src/filed/fd_plugins.c b/bacula/src/filed/fd_plugins.c new file mode 100644 index 0000000000..e99ce1fedc --- /dev/null +++ b/bacula/src/filed/fd_plugins.c @@ -0,0 +1,630 @@ +/* + 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 John Walker. + 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 "filed.h" + +const int dbglvl = 50; +const char *plugin_type = "-fd.so"; + +extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level); + +/* Function pointers to be set here */ +extern DLL_IMP_EXP int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode); +extern DLL_IMP_EXP int (*plugin_bclose)(JCR *jcr); +extern DLL_IMP_EXP ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count); +extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count); +extern DLL_IMP_EXP boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence); + + +/* Forward referenced functions */ +static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value); +static bRC baculaSetValue(bpContext *ctx, bVariable 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 *fmt, ...); +static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line, + int level, const char *fmt, ...); + +static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode); +static int my_plugin_bclose(JCR *jcr); +static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count); +static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count); +static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence); + + +/* Bacula info */ +static bInfo binfo = { + sizeof(bFuncs), + FD_PLUGIN_INTERFACE_VERSION +}; + +/* Bacula entry points */ +static bFuncs bfuncs = { + sizeof(bFuncs), + FD_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; /* Return if no plugins loaded */ + } + + bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; + event.eventType = eventType; + + Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId); + + /* Pass event to every plugin */ + foreach_alist(plugin, plugin_list) { + bRC rc; + rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value); + if (rc != bRC_OK) { + break; + } + } + + return; +} + +/* + * Sequence of calls for a backup: + * 1. plugin_save() here is called with ff_pkt + * 2. we find the plugin requested on the command string + * 3. we generate a bEventBackupCommand event to the specified plugin + * and pass it the command string. + * 4. we make a startPluginBackup call to the plugin, which gives + * us the data we need in save_pkt + * 5. we call Bacula's save_file() subroutine to save the specified + * file. The plugin will be called at pluginIO() to supply the + * file data. + * + * Sequence of calls for restore: + * See subroutine plugin_name_stream() below. + */ +int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) +{ + Plugin *plugin; + int i = 0; + int len; + char *p; + char *cmd = ff_pkt->top_fname; + struct save_pkt sp; + bEvent event; + + if (!plugin_list) { + return 1; /* Return if no plugins loaded */ + } + + bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; + event.eventType = bEventBackupCommand; + + /* Handle plugin command here backup */ + Dmsg1(100, "plugin cmd=%s\n", cmd); + if (!(p = strchr(cmd, ':'))) { + Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd); + goto bail_out; + } + len = p - cmd; + if (len <= 0) { + goto bail_out; + } + + foreach_alist(plugin, plugin_list) { + Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); + if (strncmp(plugin->file, cmd, len) != 0) { + i++; + continue; + } + Dmsg1(100, "Command plugin = %s\n", cmd); + /* Send the backup command */ + if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, cmd) != bRC_OK) { + goto bail_out; + } + /* Loop getting filenames to backup then saving them */ + while (!job_canceled(jcr)) { + memset(&sp, 0, sizeof(sp)); + sp.type = FT_REG; + sp.portable = true; + sp.cmd = cmd; + Dmsg3(000, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks, + &sp); + /* Get the file save parameters */ + if (plug_func(plugin)->startBackupFile(&plugin_ctx_list[i], &sp) != bRC_OK) { + goto bail_out; + } + jcr->plugin_ctx = &plugin_ctx_list[i]; + jcr->plugin = plugin; + jcr->plugin_sp = &sp; + ff_pkt = jcr->ff; + ff_pkt->fname = sp.fname; + ff_pkt->type = sp.type; + memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp)); + Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname); + save_file(jcr, ff_pkt, true); + if (plug_func(plugin)->endBackupFile(&plugin_ctx_list[i]) != bRC_More) { + goto bail_out; + } + } + } + Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd); + +bail_out: + return 1; +} + +/* + * Send plugin name start/end record to SD + */ +bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) +{ + int stat; + struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp; + + Dmsg1(000, "send_plugin_name=%s\n", sp->cmd); + if (!sd->fsend("%ld %d 0", jcr->JobFiles+1, STREAM_PLUGIN_NAME)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + return false; + } + Dmsg1(000, "send: %s\n", sd->msg); + + if (start) { + stat = sd->fsend("%ld 1 %d %s%c", jcr->JobFiles+1, sp->portable, sp->cmd, 0); + } else { + stat = sd->fsend("%ld 0"); + } + if (!stat) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + return false; + } + Dmsg1(000, "send: %s\n", sd->msg); + sd->signal(BNET_EOD); /* indicate end of plugin name data */ + return true; +} + +/* + * Plugin name stream found during restore. The record passed in + * argument name was generated in send_plugin_name() above. + */ +void plugin_name_stream(JCR *jcr, char *name) +{ + char *p = name; + char *cmd; + bool start, portable; + Plugin *plugin; + int len; + int i = 0; + bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; + + Dmsg1(100, "Read plugin stream string=%s\n", name); + skip_nonspaces(&p); /* skip over jcr->JobFiles */ + skip_spaces(&p); + start = *p == '1'; + skip_nonspaces(&p); /* skip start/end flag */ + skip_spaces(&p); + portable = *p == '1'; + skip_nonspaces(&p); /* skip portable flag */ + skip_spaces(&p); + cmd = p; + + /* Check for restore end */ + if (!start) { + /* + * If end of restore, notify plugin, then clear flags + */ + plugin = (Plugin *)jcr->plugin; + plug_func(plugin)->endRestoreFile(&plugin_ctx_list[i]); + jcr->plugin_ctx = NULL; + jcr->plugin = NULL; + goto bail_out; + } + + /* + * After this point, we are dealing with a restore start + */ + + Dmsg1(100, "plugin restore cmd=%s\n", cmd); + if (!(p = strchr(cmd, ':'))) { + Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd); + goto bail_out; + } + len = p - cmd; + if (len <= 0) { + goto bail_out; + } + + /* + * Search for correct plugin as specified on the command + */ + foreach_alist(plugin, plugin_list) { + bEvent event; + Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); + if (strncmp(plugin->file, cmd, len) != 0) { + i++; + continue; + } + Dmsg1(100, "Restore Command plugin = %s\n", cmd); + event.eventType = bEventRestoreCommand; + if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], + &event, cmd) != bRC_OK) { + goto bail_out; + } + jcr->plugin_ctx = &plugin_ctx_list[i]; + jcr->plugin = plugin; + goto bail_out; + } +bail_out: + return; +} + +/* + * Tell the plugin to create the file. Return values are + * + * CF_ERROR -- error + * CF_SKIP -- skip processing this file + * CF_EXTRACT -- extract the file (i.e.call i/o routines) + * CF_CREATED -- created, but no content to extract (typically directories) + * + */ +int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) +{ + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + Plugin *plugin = (Plugin *)jcr->plugin; + struct restore_pkt rp; + struct io_pkt io; + + if (!set_cmd_plugin(bfd, jcr)) { + return CF_ERROR; + } + rp.stream = attr->stream; + rp.data_stream = attr->data_stream; + rp.type = attr->type; + rp.file_index = attr->file_index; + rp.LinkFI = attr->LinkFI; + rp.uid = attr->uid; + rp.statp = attr->statp; /* structure assignment */ + rp.attrEx = attr->attrEx; + rp.ofname = attr->ofname; + rp.olname = attr->olname; + rp.where = jcr->where; + rp.RegexWhere = jcr->RegexWhere; + rp.replace = jcr->replace; + if (plug_func(plugin)->createFile(plugin_ctx, &rp) != bRC_OK) { + return CF_ERROR; + } + io.func = IO_OPEN; + io.count = 0; + io.buf = NULL; + io.mode = 0777 & attr->statp.st_mode; + io.flags = O_WRONLY; + if (plug_func(plugin)->pluginIO(plugin_ctx, &io) != bRC_OK) { + return CF_ERROR; + } + return CF_EXTRACT; +} + +/* + * Reset the file attributes after all file I/O is done -- this allows + * the previous access time/dates to be set properly, and it also allows + * us to properly set directory permissions. + */ +bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) +{ + return true; +} + +void load_fd_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); + + /* Plug entry points called from findlib */ + plugin_bopen = my_plugin_bopen; + plugin_bclose = my_plugin_bclose; + plugin_bread = my_plugin_bread; + plugin_bwrite = my_plugin_bwrite; + plugin_blseek = my_plugin_blseek; + +} + +/* + * 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=%p JobId=%d\n", 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=%p JobId=%d\n", 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; +} + +static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode) +{ + Plugin *plugin = (Plugin *)jcr->plugin; + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + struct io_pkt io; + Dmsg0(000, "plugin_bopen\n"); + io.func = IO_OPEN; + io.count = 0; + io.buf = NULL; + io.mode = mode; + io.flags = flags; + plug_func(plugin)->pluginIO(plugin_ctx, &io); + return io.status; +} + +static int my_plugin_bclose(JCR *jcr) +{ + Plugin *plugin = (Plugin *)jcr->plugin; + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + struct io_pkt io; + Dmsg0(000, "plugin_bclose\n"); + io.func = IO_CLOSE; + io.count = 0; + io.buf = NULL; + plug_func(plugin)->pluginIO(plugin_ctx, &io); + return io.status; +} + +static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count) +{ + Plugin *plugin = (Plugin *)jcr->plugin; + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + struct io_pkt io; + Dmsg0(000, "plugin_bread\n"); + io.func = IO_READ; + io.count = count; + io.buf = (char *)buf; + plug_func(plugin)->pluginIO(plugin_ctx, &io); + return (ssize_t)io.status; +} + +static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count) +{ + Plugin *plugin = (Plugin *)jcr->plugin; + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + struct io_pkt io; + Dmsg0(000, "plugin_bwrite\n"); + io.func = IO_WRITE; + io.count = count; + io.buf = (char *)buf; + plug_func(plugin)->pluginIO(plugin_ctx, &io); + return (ssize_t)io.status; +} + +static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence) +{ + Plugin *plugin = (Plugin *)jcr->plugin; + bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx; + struct io_pkt io; + Dmsg0(000, "plugin_bseek\n"); + io.func = IO_SEEK; + io.offset = offset; + io.whence = whence; + plug_func(plugin)->pluginIO(plugin_ctx, &io); + return (boffset_t)io.offset; +} + +/* ============================================================== + * + * Callbacks from the plugin + * + * ============================================================== + */ +static bRC baculaGetValue(bpContext *ctx, bVariable 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; + case bVarFDName: + *((char **)value) = my_name; + Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name); + break; + case bVarLevel: + case bVarType: + case bVarClient: + case bVarJobName: + case bVarJobStatus: + case bVarSinceTime: + break; + } + return bRC_OK; +} + +static bRC baculaSetValue(bpContext *ctx, bVariable 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 *fmt, ...) +{ + va_list arg_ptr; + char buf[2000]; + JCR *jcr = (JCR *)(ctx->bContext); + + 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 *fmt, ...) +{ + 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 + +int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL; +int (*plugin_bclose)(JCR *jcr) = NULL; +ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL; +ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL; +boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL; + +int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) +{ + return 0; +} + +bool set_cmd_plugin(BFILE *bfd, JCR *jcr) +{ + return true; +} + +int main(int argc, char *argv[]) +{ + char plugin_dir[1000]; + JCR mjcr1, mjcr2; + JCR *jcr1 = &mjcr1; + JCR *jcr2 = &mjcr2; + + strcpy(my_name, "test-fd"); + + getcwd(plugin_dir, sizeof(plugin_dir)-1); + load_fd_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 2"); + 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/filed/fd_plugins.h b/bacula/src/filed/fd_plugins.h new file mode 100644 index 0000000000..099862d038 --- /dev/null +++ b/bacula/src/filed/fd_plugins.h @@ -0,0 +1,244 @@ +/* + 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 John Walker. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Application Programming Interface (API) definition for Bacula Plugins + * + * Kern Sibbald, October 2007 + * + */ + +#ifndef __FD_PLUGINS_H +#define __FD_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" +#include + +/* + * This packet is used for file save info transfer. +*/ +struct save_pkt { + char *fname; /* Full path and filename */ + char *link; /* Link name if any */ + struct stat statp; /* System stat() packet for file */ + int32_t type; /* FT_xx for this file */ + uint32_t flags; /* Bacula internal flags */ + bool portable; /* set if data format is portable */ + char *cmd; /* command */ +}; + +/* + * This packet is used for file restore info transfer. +*/ +struct restore_pkt { + int32_t stream; /* attribute stream id */ + int32_t data_stream; /* id of data stream to follow */ + int32_t type; /* file type FT */ + int32_t file_index; /* file index */ + int32_t LinkFI; /* file index to data if hard link */ + uid_t uid; /* userid */ + struct stat statp; /* decoded stat packet */ + const char *attrEx; /* extended attributes if any */ + const char *ofname; /* output filename */ + const char *olname; /* output link name */ + const char *where; /* where */ + const char *RegexWhere; /* regex where */ + int replace; /* replace flag */ +}; + +enum { + IO_OPEN = 1, + IO_READ = 2, + IO_WRITE = 3, + IO_CLOSE = 4, + IO_SEEK = 5 +}; + +struct io_pkt { + int32_t func; /* Function code */ + int32_t count; /* read/write count */ + mode_t mode; /* permissions for created files */ + int32_t flags; /* open flags (e.g. O_WRONLY ...) */ + char *buf; /* read/write buffer */ + int32_t status; /* return status */ + int32_t io_errno; /* errno code */ + int32_t whence; + boffset_t offset; +}; + +/**************************************************************************** + * * + * Bacula definitions * + * * + ****************************************************************************/ + +/* Bacula Variable Ids */ +typedef enum { + bVarJobId = 1, + bVarFDName = 2, + bVarLevel = 3, + bVarType = 4, + bVarClient = 5, + bVarJobName = 6, + bVarJobStatus = 7, + bVarSinceTime = 8 +} bVariable; + +typedef enum { + bEventJobStart = 1, + bEventJobEnd = 2, + bEventStartBackupJob = 3, + bEventEndBackupJob = 4, + bEventStartRestoreJob = 5, + bEventEndRestoreJob = 6, + bEventStartVerifyJob = 7, + bEventEndVerifyJob = 8, + bEventBackupCommand = 9, + bEventRestoreCommand = 10, + bEventLevel = 11, + bEventSince = 12, +} bEventType; + +typedef struct s_bEvent { + uint32_t eventType; +} bEvent; + +typedef struct s_baculaInfo { + uint32_t size; + uint32_t version; +} bInfo; + +/* Bacula Core Routines -- not used by plugins */ +struct BFILE; /* forward referenced */ +struct FF_PKT; +void load_fd_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); +bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start); +void plugin_name_stream(JCR *jcr, char *name); +int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace); +bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd); +int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level); + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Bacula interface version and function pointers -- + * i.e. callbacks from the plugin to Bacula + */ +typedef struct s_baculaFuncs { + uint32_t size; + uint32_t version; + bRC (*registerBaculaEvents)(bpContext *ctx, ...); + bRC (*getBaculaValue)(bpContext *ctx, bVariable var, void *value); + bRC (*setBaculaValue)(bpContext *ctx, bVariable var, void *value); + bRC (*JobMessage)(bpContext *ctx, const char *file, int line, + int type, time_t mtime, const char *fmt, ...); + bRC (*DebugMessage)(bpContext *ctx, const char *file, int line, + int level, const char *fmt, ...); +} bFuncs; + + + + +/**************************************************************************** + * * + * Plugin definitions * + * * + ****************************************************************************/ + +typedef enum { + pVarName = 1, + pVarDescription = 2 +} pVariable; + + +#define FD_PLUGIN_MAGIC "*FDPluginData*" +#define FD_PLUGIN_INTERFACE_VERSION 1 + +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; +} pInfo; + +/* + * This is a set of function pointers that Bacula can call + * within the plugin. + */ +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); + bRC (*startBackupFile)(bpContext *ctx, struct save_pkt *sp); + bRC (*endBackupFile)(bpContext *ctx); + bRC (*startRestoreFile)(bpContext *ctx, const char *cmd); + bRC (*endRestoreFile)(bpContext *ctx); + bRC (*pluginIO)(bpContext *ctx, struct io_pkt *io); + bRC (*createFile)(bpContext *ctx, struct restore_pkt *rp); + bRC (*setFileAttributes)(bpContext *ctx, struct restore_pkt *rp); +} pFuncs; + +#define plug_func(plugin) ((pFuncs *)(plugin->pfuncs)) +#define plug_info(plugin) ((pInfo *)(plugin->pinfo)) + +#ifdef __cplusplus +} +#endif + +#endif /* __FD_PLUGINS_H */ diff --git a/bacula/src/filed/filed.h b/bacula/src/filed/filed.h index 5212530265..ec1aa07bb6 100644 --- a/bacula/src/filed/filed.h +++ b/bacula/src/filed/filed.h @@ -36,7 +36,7 @@ #define FILE_DAEMON 1 #include "filed_conf.h" -#include "fd-plugins.h" +#include "fd_plugins.h" #include "findlib/find.h" #include "jcr.h" #include "acl.h" diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index cbbbe6c63c..040458d5d2 100644 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -36,7 +36,7 @@ #include "jcr.h" #include "bfile.h" -#include "../filed/fd-plugins.h" +#include "../filed/fd_plugins.h" #ifdef HAVE_DIRENT_H #include diff --git a/bacula/src/plugins/dir/Makefile b/bacula/src/plugins/dir/Makefile index 8645dace37..1b18a57e8b 100644 --- a/bacula/src/plugins/dir/Makefile +++ b/bacula/src/plugins/dir/Makefile @@ -15,13 +15,13 @@ LIBDIR=../../lib test: main example-plugin-dir.so -dir-plugins.o: ${DIRDIR}/dir-plugins.h ${DIRDIR}/dir-plugins.c - $(CC) -I${SRCDIR} -I${DIRDIR} -DTEST_PROGRAM -c ${DIRDIR}/dir-plugins.c +dir_plugins.o: ${DIRDIR}/dir_plugins.h ${DIRDIR}/dir_plugins.c + $(CC) -I${SRCDIR} -I${DIRDIR} -DTEST_PROGRAM -c ${DIRDIR}/dir_plugins.c -main: dir-plugins.o - $(CC) -L${LIBDIR} dir-plugins.o -o main -lbac -lpthread -lssl -l crypto -ldl +main: dir_plugins.o + $(CC) -L${LIBDIR} dir_plugins.o -o main -lbac -lpthread -lssl -l crypto -ldl -example-plugin-dir.o: example-plugin-dir.c ${DIRDIR}/dir-plugins.h +example-plugin-dir.o: example-plugin-dir.c ${DIRDIR}/dir_plugins.h $(CC) -fPIC -I../.. -I${DIRDIR} -c example-plugin-dir.c example-plugin-dir.so: example-plugin-dir.o diff --git a/bacula/src/plugins/dir/example-plugin-dir.c b/bacula/src/plugins/dir/example-plugin-dir.c index d98f120363..704243e371 100644 --- a/bacula/src/plugins/dir/example-plugin-dir.c +++ b/bacula/src/plugins/dir/example-plugin-dir.c @@ -32,7 +32,7 @@ * */ #include -#include "dir-plugins.h" +#include "dir_plugins.h" #ifdef __cplusplus extern "C" { diff --git a/bacula/src/plugins/fd/Makefile b/bacula/src/plugins/fd/Makefile index 8a27f1ec1d..ebc7fb0fed 100644 --- a/bacula/src/plugins/fd/Makefile +++ b/bacula/src/plugins/fd/Makefile @@ -17,19 +17,19 @@ all: bpipe-fd.so test: main example-plugin-fd.so -fd-plugins.o: ${FDDIR}/fd-plugins.h ${FDDIR}/fd-plugins.c - $(CC) -I${SRCDIR} -I${FDDIR} -DTEST_PROGRAM -c ${FDDIR}/fd-plugins.c +fd_plugins.o: ${FDDIR}/fd_plugins.h ${FDDIR}/fd_plugins.c + $(CC) -I${SRCDIR} -I${FDDIR} -DTEST_PROGRAM -c ${FDDIR}/fd_plugins.c -main: fd-plugins.o - $(CC) -L${LIBDIR} fd-plugins.o -o main -lbac -lpthread -lssl -l crypto -ldl +main: fd_plugins.o + $(CC) -L${LIBDIR} fd_plugins.o -o main -lbac -lpthread -lssl -l crypto -ldl -example-plugin-fd.o: example-plugin-fd.c ${FDDIR}/fd-plugins.h +example-plugin-fd.o: example-plugin-fd.c ${FDDIR}/fd_plugins.h $(CC) -fPIC -I../.. -I${FDDIR} -c example-plugin-fd.c example-plugin-fd.so: example-plugin-fd.o $(CC) -shared example-plugin-fd.o -o example-plugin-fd.so -bpipe-fd.o: bpipe-fd.c ${FDDIR}/fd-plugins.h +bpipe-fd.o: bpipe-fd.c ${FDDIR}/fd_plugins.h $(CC) -fPIC -I../.. -I${FDDIR} -c bpipe-fd.c bpipe-fd.so: bpipe-fd.o diff --git a/bacula/src/plugins/fd/bpipe-fd.c b/bacula/src/plugins/fd/bpipe-fd.c index 71f384c2dd..970060dcc6 100644 --- a/bacula/src/plugins/fd/bpipe-fd.c +++ b/bacula/src/plugins/fd/bpipe-fd.c @@ -31,7 +31,7 @@ * Kern Sibbald, October 2007 * */ -#include "fd-plugins.h" +#include "fd_plugins.h" #undef malloc #undef free diff --git a/bacula/src/plugins/fd/example-plugin-fd.c b/bacula/src/plugins/fd/example-plugin-fd.c index 1b4422cffc..c0533186a2 100644 --- a/bacula/src/plugins/fd/example-plugin-fd.c +++ b/bacula/src/plugins/fd/example-plugin-fd.c @@ -32,7 +32,7 @@ * */ #include -#include "fd-plugins.h" +#include "fd_plugins.h" #ifdef __cplusplus extern "C" { diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index 4106cdaddd..4f81c92e71 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -2,6 +2,7 @@ General: 08Mar08 +kes Rename fd/dir plugin to use Bacula standard underscore. kes Plugin work -- bring dir up to fd level. kes Start implementation of VTL code kes Fix Win32 build after adding new cats subroutine.