]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/plugins/fd/test-plugin-fd.c
regress: Add debug for RestoreObject test
[bacula/bacula] / bacula / src / plugins / fd / test-plugin-fd.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation, which is 
11    listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * A simple test plugin for the Bacula File Daemon derived from
30  *   the bpipe plugin, but used for testing new features.
31  *
32  *  Kern Sibbald, October 2007
33  *
34  */
35 #include "bacula.h"
36 #include "fd_plugins.h"
37 #include <wchar.h>
38
39 #undef malloc
40 #undef free
41 #undef strdup
42
43 #define fi __FILE__
44 #define li __LINE__
45
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49
50 static const int dbglvl = 000;
51
52 #define PLUGIN_LICENSE      "Bacula AGPLv3"
53 #define PLUGIN_AUTHOR       "Kern Sibbald"
54 #define PLUGIN_DATE         "March 2011"
55 #define PLUGIN_VERSION      "2"
56 #define PLUGIN_DESCRIPTION  "Bacula Test File Daemon Plugin"
57
58 /* Forward referenced functions */
59 static bRC newPlugin(bpContext *ctx);
60 static bRC freePlugin(bpContext *ctx);
61 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
62 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
63 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
64 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
65 static bRC endBackupFile(bpContext *ctx);
66 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
67 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
68 static bRC endRestoreFile(bpContext *ctx);
69 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
70 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
71
72 /* Pointers to Bacula functions */
73 static bFuncs *bfuncs = NULL;
74 static bInfo  *binfo = NULL;
75
76 /* Plugin Information block */
77 static pInfo pluginInfo = {
78    sizeof(pluginInfo),
79    FD_PLUGIN_INTERFACE_VERSION,
80    FD_PLUGIN_MAGIC,
81    PLUGIN_LICENSE,
82    PLUGIN_AUTHOR,
83    PLUGIN_DATE,
84    PLUGIN_VERSION,
85    PLUGIN_DESCRIPTION,
86 };
87
88 /* Plugin entry points for Bacula */
89 static pFuncs pluginFuncs = {
90    sizeof(pluginFuncs),
91    FD_PLUGIN_INTERFACE_VERSION,
92
93    /* Entry points into plugin */
94    newPlugin,                         /* new plugin instance */
95    freePlugin,                        /* free plugin instance */
96    getPluginValue,
97    setPluginValue,
98    handlePluginEvent,
99    startBackupFile,
100    endBackupFile,
101    startRestoreFile,
102    endRestoreFile,
103    pluginIO,
104    createFile,
105    setFileAttributes
106 };
107
108 /*
109  * Plugin private context
110  */
111 struct plugin_ctx {
112    boffset_t offset;
113    FILE *fd;                          /* pipe file descriptor */
114    bool backup;                       /* set for backup (not needed) */
115    char *cmd;                         /* plugin command line */
116    char *fname;                       /* filename to "backup/restore" */
117    char *reader;                      /* reader program for backup */
118    char *writer;                      /* writer program for backup */
119
120    char where[512];
121    int replace;
122 };
123
124 /*
125  * loadPlugin() and unloadPlugin() are entry points that are
126  *  exported, so Bacula can directly call these two entry points
127  *  they are common to all Bacula plugins.
128  */
129 /*
130  * External entry point called by Bacula to "load the plugin
131  */
132 bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
133 {
134    bfuncs = lbfuncs;                  /* set Bacula funct pointers */
135    binfo  = lbinfo;
136    *pinfo  = &pluginInfo;             /* return pointer to our info */
137    *pfuncs = &pluginFuncs;            /* return pointer to our functions */
138
139    return bRC_OK;
140 }
141
142 /*
143  * External entry point to unload the plugin 
144  */
145 bRC unloadPlugin() 
146 {
147 // printf("test-plugin-fd: Unloaded\n");
148    return bRC_OK;
149 }
150
151 /*
152  * The following entry points are accessed through the function 
153  *   pointers we supplied to Bacula. Each plugin type (dir, fd, sd)
154  *   has its own set of entry points that the plugin must define.
155  */
156 /*
157  * Create a new instance of the plugin i.e. allocate our private storage
158  */
159 static bRC newPlugin(bpContext *ctx)
160 {
161    struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
162    if (!p_ctx) {
163       return bRC_Error;
164    }
165    memset(p_ctx, 0, sizeof(struct plugin_ctx));
166    ctx->pContext = (void *)p_ctx;        /* set our context pointer */
167    return bRC_OK;
168 }
169
170 /*
171  * Free a plugin instance, i.e. release our private storage
172  */
173 static bRC freePlugin(bpContext *ctx)
174 {
175    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
176    if (!p_ctx) {
177       return bRC_Error;
178    }
179    if (p_ctx->cmd) {
180       free(p_ctx->cmd);                  /* free any allocated command string */
181    }
182    free(p_ctx);                          /* free our private context */
183    p_ctx = NULL;
184    return bRC_OK;
185 }
186
187 /*
188  * Return some plugin value (none defined)
189  */
190 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) 
191 {
192    return bRC_OK;
193 }
194
195 /*
196  * Set a plugin value (none defined)
197  */
198 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) 
199 {
200    return bRC_OK;
201 }
202
203 /*
204  * Handle an event that was generated in Bacula
205  */
206 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
207 {
208    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
209    restore_object_pkt *rop;
210    if (!p_ctx) {
211       return bRC_Error;
212    }
213
214 // char *name;
215
216    /*
217     * Most events don't interest us so we ignore them.
218     *   the printfs are so that plugin writers can enable them to see
219     *   what is really going on.
220     */
221    switch (event->eventType) {
222    case bEventJobStart:
223       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: JobStart=%s\n", (char *)value);
224       break;
225    case bEventJobEnd:
226    case bEventEndBackupJob:
227    case bEventLevel:
228    case bEventSince:
229    case bEventStartRestoreJob:
230    case bEventEndRestoreJob:
231       break;
232    /* End of Dir FileSet commands, now we can add excludes */
233    case bEventEndFileSet:
234       bfuncs->NewOptions(ctx);
235       bfuncs->AddWild(ctx, "*.c", ' ');
236       bfuncs->AddWild(ctx, "*.cpp", ' ');
237       bfuncs->AddOptions(ctx, "ei");         /* exclude, ignore case */
238       bfuncs->AddExclude(ctx, "/home/kern/bacula/regress/README");
239       break;
240    case bEventStartBackupJob:
241       break;
242    case bEventRestoreObject:
243       printf("Plugin RestoreObject\n");
244       if (!value) {
245          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: End restore objects\n");
246          break;
247       }
248       rop = (restore_object_pkt *)value;
249       bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
250                         "Get RestoreObject len=%d JobId=%d oname=%s data=%s\n",
251                         rop->object_len, rop->JobId, rop->object_name, 
252                         rop->object);
253       break;
254    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
255    case bEventRestoreCommand:
256       /* Fall-through wanted */
257    case bEventBackupCommand:
258       char *p;
259       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: pluginEvent cmd=%s\n", (char *)value);
260       p_ctx->cmd = strdup((char *)value);
261       p = strchr(p_ctx->cmd, ':');
262       if (!p) {
263          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
264          return bRC_Error;
265       }
266       *p++ = 0;           /* terminate plugin */
267       p_ctx->fname = p;
268       p = strchr(p, ':');
269       if (!p) {
270          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
271          return bRC_Error;
272       }
273       *p++ = 0;           /* terminate file */
274       p_ctx->reader = p;
275       p = strchr(p, ':');
276       if (!p) {
277          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
278          return bRC_Error;
279       }
280       *p++ = 0;           /* terminate reader string */
281       p_ctx->writer = p;
282       printf("test-plugin-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
283           p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
284       break;
285
286    default:
287       printf("test-plugin-fd: unknown event=%d\n", event->eventType);
288       break;
289    }
290    return bRC_OK;
291 }
292
293 /* 
294  * Start the backup of a specific file
295  */
296 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
297 {
298    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
299    if (!p_ctx) {
300       return bRC_Error;
301    }
302    time_t now = time(NULL);
303    sp->object_name = (char *)"james.xml";
304    sp->object = (char *)"This is test data for the restore object. "
305    "garbage=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
306    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
307    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
308    "\0secret";
309    sp->object_len = strlen(sp->object)+1+6+1; /* str + 0 + secret + 0 */
310    sp->index = 2;
311    sp->type = FT_RESTORE_FIRST;
312    sp->statp.st_mode = 0700 | S_IFREG;
313    sp->statp.st_ctime = now;
314    sp->statp.st_mtime = now;
315    sp->statp.st_atime = now;
316    sp->statp.st_size = sp->object_len;
317    sp->statp.st_blksize = 4096;
318    sp->statp.st_blocks = 1;
319    bfuncs->DebugMessage(ctx, fi, li, dbglvl,
320                         "Creating RestoreObject len=%d oname=%s data=%s\n", 
321                         sp->object_len, sp->object_name, sp->object);
322    p_ctx->backup = true;
323    printf("test-plugin-fd: startBackupFile\n");
324    return bRC_OK;
325 }
326
327 /*
328  * Done with backup of this file
329  */
330 static bRC endBackupFile(bpContext *ctx)
331 {
332    /*
333     * We would return bRC_More if we wanted startBackupFile to be
334     * called again to backup another file
335     */
336    return bRC_OK;
337 }
338
339
340 /*
341  * Bacula is calling us to do the actual I/O
342  */
343 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
344 {
345    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
346    if (!p_ctx) {
347       return bRC_Error;
348    }
349     
350    io->status = 0;
351    io->io_errno = 0;
352    return bRC_OK;
353 }
354
355 /*
356  * Bacula is notifying us that a plugin name string was found, and
357  *   passing us the plugin command, so we can prepare for a restore.
358  */
359 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
360 {
361    printf("test-plugin-fd: startRestoreFile cmd=%s\n", cmd);
362    return bRC_OK;
363 }
364
365 /*
366  * Bacula is notifying us that the plugin data has terminated, so
367  *  the restore for this particular file is done.
368  */
369 static bRC endRestoreFile(bpContext *ctx)
370 {
371    printf("test-plugin-fd: endRestoreFile\n");
372    return bRC_OK;
373 }
374
375 /*
376  * This is called during restore to create the file (if necessary)
377  * We must return in rp->create_status:
378  *   
379  *  CF_ERROR    -- error
380  *  CF_SKIP     -- skip processing this file
381  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
382  *  CF_CREATED  -- created, but no content to extract (typically directories)
383  *
384  */
385 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
386 {
387    printf("test-plugin-fd: createFile\n");
388    if (strlen(rp->where) > 512) {
389       printf("Restore target dir too long. Restricting to first 512 bytes.\n");
390    }
391    strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513);
392    ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
393    rp->create_status = CF_EXTRACT;
394    return bRC_OK;
395 }
396
397 /*
398  * We will get here if the File is a directory after everything
399  * is written in the directory.
400  */
401 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
402 {
403    printf("test-plugin-fd: setFileAttributes\n");
404    return bRC_OK;
405 }
406
407
408 #ifdef __cplusplus
409 }
410 #endif