From 391ea648739f337bda62dea10b4eaadbdf7f28a5 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 7 Apr 2010 14:55:53 +0200 Subject: [PATCH] Create test-plugin-fd --- bacula/src/plugins/fd/Makefile.in | 9 +- bacula/src/plugins/fd/test-plugin-fd.c | 373 +++++++++++++++++++++++++ 2 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 bacula/src/plugins/fd/test-plugin-fd.c diff --git a/bacula/src/plugins/fd/Makefile.in b/bacula/src/plugins/fd/Makefile.in index edb4337660..2c5b47a593 100644 --- a/bacula/src/plugins/fd/Makefile.in +++ b/bacula/src/plugins/fd/Makefile.in @@ -1,7 +1,6 @@ # # Simple Makefile for building test FD plugins for Bacula # -# Version $Id$ # @MCOMMON@ @@ -17,7 +16,7 @@ LIBDIR=../../lib .c.lo: $(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) $(CPPFLAGS) -I${SRCDIR} -I${FDDIR} -DTEST_PROGRAM -c $< -all: bpipe-fd.la +all: bpipe-fd.la test-plugin-fd.la bpipe-fd.lo: bpipe-fd.c ${FDDIR}/fd_plugins.h $(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) $(CPPFLAGS) $(CFLAGS) -I../.. -I${FDDIR} -c bpipe-fd.c @@ -25,6 +24,12 @@ bpipe-fd.lo: bpipe-fd.c ${FDDIR}/fd_plugins.h bpipe-fd.la: Makefile bpipe-fd$(DEFAULT_OBJECT_TYPE) $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -shared bpipe-fd.lo -o $@ -rpath $(plugindir) -module -export-dynamic -avoid-version +test-plugin-fd.lo: test-plugin-fd.c ${FDDIR}/fd_plugins.h + $(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) $(CPPFLAGS) $(CFLAGS) -I../.. -I${FDDIR} -c test-plugin-fd.c + +test-plugin-fd.la: Makefile test-plugin-fd$(DEFAULT_OBJECT_TYPE) + $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -shared test-plugin-fd.lo -o $@ -rpath $(plugindir) -module -export-dynamic -avoid-version + install: all $(MKDIR) $(DESTDIR)$(plugindir) $(LIBTOOL_INSTALL) $(INSTALL_PROGRAM) bpipe-fd.la $(DESTDIR)$(plugindir) diff --git a/bacula/src/plugins/fd/test-plugin-fd.c b/bacula/src/plugins/fd/test-plugin-fd.c new file mode 100644 index 0000000000..df36da3b80 --- /dev/null +++ b/bacula/src/plugins/fd/test-plugin-fd.c @@ -0,0 +1,373 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2007-2010 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. +*/ +/* + * A simple test plugin for the Bacula File Daemon derived from + * the bpipe plugin, but used for testing new features. + * + * Kern Sibbald, October 2007 + * + */ +#include "bacula.h" +#include "fd_plugins.h" + +#undef malloc +#undef free +#undef strdup + +#define fi __FILE__ +#define li __LINE__ + +#ifdef __cplusplus +extern "C" { +#endif + +static const int dbglvl = 150; + +#define PLUGIN_LICENSE "Bacula GPLv2" +#define PLUGIN_AUTHOR "Kern Sibbald" +#define PLUGIN_DATE "April 2010" +#define PLUGIN_VERSION "1" +#define PLUGIN_DESCRIPTION "Bacula Test File Daemon Plugin" + +/* Forward referenced functions */ +static bRC newPlugin(bpContext *ctx); +static bRC freePlugin(bpContext *ctx); +static bRC getPluginValue(bpContext *ctx, pVariable var, void *value); +static bRC setPluginValue(bpContext *ctx, pVariable var, void *value); +static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value); +static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp); +static bRC endBackupFile(bpContext *ctx); +static bRC pluginIO(bpContext *ctx, struct io_pkt *io); +static bRC startRestoreFile(bpContext *ctx, const char *cmd); +static bRC endRestoreFile(bpContext *ctx); +static bRC createFile(bpContext *ctx, struct restore_pkt *rp); +static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp); + +/* Pointers to Bacula functions */ +static bFuncs *bfuncs = NULL; +static bInfo *binfo = NULL; + +/* Plugin Information block */ +static pInfo pluginInfo = { + sizeof(pluginInfo), + FD_PLUGIN_INTERFACE_VERSION, + FD_PLUGIN_MAGIC, + PLUGIN_LICENSE, + PLUGIN_AUTHOR, + PLUGIN_DATE, + PLUGIN_VERSION, + PLUGIN_DESCRIPTION, +}; + +/* Plugin entry points for Bacula */ +static pFuncs pluginFuncs = { + sizeof(pluginFuncs), + FD_PLUGIN_INTERFACE_VERSION, + + /* Entry points into plugin */ + newPlugin, /* new plugin instance */ + freePlugin, /* free plugin instance */ + getPluginValue, + setPluginValue, + handlePluginEvent, + startBackupFile, + endBackupFile, + startRestoreFile, + endRestoreFile, + pluginIO, + createFile, + setFileAttributes +}; + +/* + * Plugin private context + */ +struct plugin_ctx { + boffset_t offset; + FILE *fd; /* pipe file descriptor */ + bool backup; /* set for backup (not needed) */ + char *cmd; /* plugin command line */ + char *fname; /* filename to "backup/restore" */ + char *reader; /* reader program for backup */ + char *writer; /* writer program for backup */ + + char where[512]; + int replace; +}; + +/* + * loadPlugin() and unloadPlugin() are entry points that are + * exported, so Bacula can directly call these two entry points + * they are common to all Bacula plugins. + */ +/* + * External entry point called by Bacula to "load the plugin + */ +bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs) +{ + bfuncs = lbfuncs; /* set Bacula funct pointers */ + binfo = lbinfo; + *pinfo = &pluginInfo; /* return pointer to our info */ + *pfuncs = &pluginFuncs; /* return pointer to our functions */ + + return bRC_OK; +} + +/* + * External entry point to unload the plugin + */ +bRC unloadPlugin() +{ +// printf("test-plugin-fd: Unloaded\n"); + return bRC_OK; +} + +/* + * The following entry points are accessed through the function + * pointers we supplied to Bacula. Each plugin type (dir, fd, sd) + * has its own set of entry points that the plugin must define. + */ +/* + * Create a new instance of the plugin i.e. allocate our private storage + */ +static bRC newPlugin(bpContext *ctx) +{ + struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx)); + if (!p_ctx) { + return bRC_Error; + } + memset(p_ctx, 0, sizeof(struct plugin_ctx)); + ctx->pContext = (void *)p_ctx; /* set our context pointer */ + return bRC_OK; +} + +/* + * Free a plugin instance, i.e. release our private storage + */ +static bRC freePlugin(bpContext *ctx) +{ + struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext; + if (!p_ctx) { + return bRC_Error; + } + if (p_ctx->cmd) { + free(p_ctx->cmd); /* free any allocated command string */ + } + free(p_ctx); /* free our private context */ + p_ctx = NULL; + return bRC_OK; +} + +/* + * Return some plugin value (none defined) + */ +static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) +{ + return bRC_OK; +} + +/* + * Set a plugin value (none defined) + */ +static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) +{ + return bRC_OK; +} + +/* + * Handle an event that was generated in Bacula + */ +static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) +{ + struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext; + if (!p_ctx) { + return bRC_Error; + } + +// char *name; + + /* + * Most events don't interest us so we ignore them. + * the printfs are so that plugin writers can enable them to see + * what is really going on. + */ + switch (event->eventType) { + case bEventJobStart: + bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: JobStart=%s\n", (char *)value); + break; + case bEventJobEnd: + case bEventStartBackupJob: + case bEventEndBackupJob: + case bEventLevel: + case bEventSince: + case bEventStartRestoreJob: + case bEventEndRestoreJob: + break; + + /* Plugin command e.g. plugin = ::read command:write command */ + case bEventRestoreCommand: + /* Fall-through wanted */ + case bEventBackupCommand: + char *p; + bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: pluginEvent cmd=%s\n", (char *)value); + p_ctx->cmd = strdup((char *)value); + p = strchr(p_ctx->cmd, ':'); + if (!p) { + bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value); + return bRC_Error; + } + *p++ = 0; /* terminate plugin */ + p_ctx->fname = p; + p = strchr(p, ':'); + if (!p) { + bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value); + return bRC_Error; + } + *p++ = 0; /* terminate file */ + p_ctx->reader = p; + p = strchr(p, ':'); + if (!p) { + bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value); + return bRC_Error; + } + *p++ = 0; /* terminate reader string */ + p_ctx->writer = p; + printf("test-plugin-fd: plugin=%s fname=%s reader=%s writer=%s\n", + p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer); + break; + + default: + printf("test-plugin-fd: unknown event=%d\n", event->eventType); + break; + } + return bRC_OK; +} + +/* + * Start the backup of a specific file + */ +static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp) +{ + struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext; + if (!p_ctx) { + return bRC_Error; + } + time_t now = time(NULL); + sp->fname = p_ctx->fname; + sp->type = FT_RESTORE_FIRST; + sp->statp.st_mode = 0700 | S_IFREG; + sp->statp.st_ctime = now; + sp->statp.st_mtime = now; + sp->statp.st_atime = now; + sp->statp.st_size = -1; + sp->statp.st_blksize = 4096; + sp->statp.st_blocks = 1; + sp->object = (char *)"This is test data for the restore object\n"; + sp->index = 2; + p_ctx->backup = true; + printf("test-plugin-fd: startBackupFile\n"); + return bRC_OK; +} + +/* + * Done with backup of this file + */ +static bRC endBackupFile(bpContext *ctx) +{ + /* + * We would return bRC_More if we wanted startBackupFile to be + * called again to backup another file + */ + return bRC_OK; +} + + +/* + * Bacula is calling us to do the actual I/O + */ +static bRC pluginIO(bpContext *ctx, struct io_pkt *io) +{ + return bRC_OK; +} + +/* + * Bacula is notifying us that a plugin name string was found, and + * passing us the plugin command, so we can prepare for a restore. + */ +static bRC startRestoreFile(bpContext *ctx, const char *cmd) +{ + printf("test-plugin-fd: startRestoreFile cmd=%s\n", cmd); + return bRC_OK; +} + +/* + * Bacula is notifying us that the plugin data has terminated, so + * the restore for this particular file is done. + */ +static bRC endRestoreFile(bpContext *ctx) +{ + printf("test-plugin-fd: endRestoreFile\n"); + return bRC_OK; +} + +/* + * This is called during restore to create the file (if necessary) + * We must return in rp->create_status: + * + * 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) + * + */ +static bRC createFile(bpContext *ctx, struct restore_pkt *rp) +{ + printf("test-plugin-fd: createFile\n"); + if (strlen(rp->where) > 512) { + printf("Restore target dir too long. Restricting to first 512 bytes.\n"); + } + strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513); + ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace; + rp->create_status = CF_EXTRACT; + return bRC_OK; +} + +/* + * We will get here if the File is a directory after everything + * is written in the directory. + */ +static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp) +{ + printf("test-plugin-fd: setFileAttributes\n"); + return bRC_OK; +} + + +#ifdef __cplusplus +} +#endif -- 2.39.5