]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/plugins/fd/test-plugin-fd.c
Tweak version date
[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 "lib/ini.h"
38 #include <wchar.h>
39
40 #undef malloc
41 #undef free
42 #undef strdup
43
44 #define fi __FILE__
45 #define li __LINE__
46
47 #ifdef __cplusplus
48 extern "C" {
49 #endif
50
51 static const int dbglvl = 000;
52
53 #define PLUGIN_LICENSE      "Bacula AGPLv3"
54 #define PLUGIN_AUTHOR       "Kern Sibbald"
55 #define PLUGIN_DATE         "May 2011"
56 #define PLUGIN_VERSION      "3"
57 #define PLUGIN_DESCRIPTION  "Bacula Test File Daemon Plugin"
58
59 /* Forward referenced functions */
60 static bRC newPlugin(bpContext *ctx);
61 static bRC freePlugin(bpContext *ctx);
62 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
63 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
64 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
65 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
66 static bRC endBackupFile(bpContext *ctx);
67 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
68 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
69 static bRC endRestoreFile(bpContext *ctx);
70 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
71 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
72
73 /* Pointers to Bacula functions */
74 static bFuncs *bfuncs = NULL;
75 static bInfo  *binfo = NULL;
76
77 /* Plugin Information block */
78 static pInfo pluginInfo = {
79    sizeof(pluginInfo),
80    FD_PLUGIN_INTERFACE_VERSION,
81    FD_PLUGIN_MAGIC,
82    PLUGIN_LICENSE,
83    PLUGIN_AUTHOR,
84    PLUGIN_DATE,
85    PLUGIN_VERSION,
86    PLUGIN_DESCRIPTION,
87 };
88
89 /* Plugin entry points for Bacula */
90 static pFuncs pluginFuncs = {
91    sizeof(pluginFuncs),
92    FD_PLUGIN_INTERFACE_VERSION,
93
94    /* Entry points into plugin */
95    newPlugin,                         /* new plugin instance */
96    freePlugin,                        /* free plugin instance */
97    getPluginValue,
98    setPluginValue,
99    handlePluginEvent,
100    startBackupFile,
101    endBackupFile,
102    startRestoreFile,
103    endRestoreFile,
104    pluginIO,
105    createFile,
106    setFileAttributes
107 };
108
109 static struct ini_items test_items[] = {
110    // name       handler         comment            required
111    { "string1",  ini_store_str,  "Special String",    1},
112    { "string2",  ini_store_str,  "2nd String",        0},
113    { "ok",       ini_store_bool, "boolean",           0},
114
115 // We can also use the ITEMS_DEFAULT  
116 // { "ok",       ini_store_bool, "boolean",           0, ITEMS_DEFAULT},
117    { NULL,       NULL,           NULL,                0}
118 };
119
120 /*
121  * Plugin private context
122  */
123 struct plugin_ctx {
124    boffset_t offset;
125    FILE *fd;                          /* pipe file descriptor */
126    char *cmd;                         /* plugin command line */
127    char *fname;                       /* filename to "backup/restore" */
128    char *reader;                      /* reader program for backup */
129    char *writer;                      /* writer program for backup */
130
131    char where[512];
132    int replace;
133
134    int nb_obj;                        /* Number of objects created */
135    POOLMEM *buf;                      /* store ConfigFile */
136 };
137
138 /*
139  * loadPlugin() and unloadPlugin() are entry points that are
140  *  exported, so Bacula can directly call these two entry points
141  *  they are common to all Bacula plugins.
142  */
143 /*
144  * External entry point called by Bacula to "load the plugin
145  */
146 bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
147 {
148    bfuncs = lbfuncs;                  /* set Bacula funct pointers */
149    binfo  = lbinfo;
150    *pinfo  = &pluginInfo;             /* return pointer to our info */
151    *pfuncs = &pluginFuncs;            /* return pointer to our functions */
152
153    return bRC_OK;
154 }
155
156 /*
157  * External entry point to unload the plugin 
158  */
159 bRC unloadPlugin() 
160 {
161 // printf("test-plugin-fd: Unloaded\n");
162    return bRC_OK;
163 }
164
165 /*
166  * The following entry points are accessed through the function 
167  *   pointers we supplied to Bacula. Each plugin type (dir, fd, sd)
168  *   has its own set of entry points that the plugin must define.
169  */
170 /*
171  * Create a new instance of the plugin i.e. allocate our private storage
172  */
173 static bRC newPlugin(bpContext *ctx)
174 {
175    struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
176    if (!p_ctx) {
177       return bRC_Error;
178    }
179    memset(p_ctx, 0, sizeof(struct plugin_ctx));
180    ctx->pContext = (void *)p_ctx;        /* set our context pointer */
181    return bRC_OK;
182 }
183
184 /*
185  * Free a plugin instance, i.e. release our private storage
186  */
187 static bRC freePlugin(bpContext *ctx)
188 {
189    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
190    if (!p_ctx) {
191       return bRC_Error;
192    }
193    if (p_ctx->buf) {
194       free_pool_memory(p_ctx->buf);
195    }
196    if (p_ctx->cmd) {
197       free(p_ctx->cmd);                  /* free any allocated command string */
198    }
199    free(p_ctx);                          /* free our private context */
200    ctx->pContext = NULL;
201    return bRC_OK;
202 }
203
204 /*
205  * Return some plugin value (none defined)
206  */
207 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) 
208 {
209    return bRC_OK;
210 }
211
212 /*
213  * Set a plugin value (none defined)
214  */
215 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) 
216 {
217    return bRC_OK;
218 }
219
220 /*
221  * Handle an event that was generated in Bacula
222  */
223 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
224 {
225    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
226    restore_object_pkt *rop;
227    if (!p_ctx) {
228       return bRC_Error;
229    }
230
231 // char *name;
232
233    /*
234     * Most events don't interest us so we ignore them.
235     *   the printfs are so that plugin writers can enable them to see
236     *   what is really going on.
237     */
238    switch (event->eventType) {
239    case bEventJobStart:
240       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: JobStart=%s\n", (char *)value);
241       break;
242    case bEventJobEnd:
243    case bEventEndBackupJob:
244    case bEventLevel:
245    case bEventSince:
246    case bEventStartRestoreJob:
247    case bEventEndRestoreJob:
248       break;
249    /* End of Dir FileSet commands, now we can add excludes */
250    case bEventEndFileSet:
251       bfuncs->NewOptions(ctx);
252       bfuncs->AddWild(ctx, "*.c", ' ');
253       bfuncs->AddWild(ctx, "*.cpp", ' ');
254       bfuncs->AddOptions(ctx, "ei");         /* exclude, ignore case */
255       bfuncs->AddExclude(ctx, "/home/kern/bacula/regress/README");
256       break;
257    case bEventStartBackupJob:
258       break;
259    case bEventRestoreObject:
260       printf("Plugin RestoreObject\n");
261       if (!value) {
262          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: End restore objects\n");
263          break;
264       }
265       rop = (restore_object_pkt *)value;
266       bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
267                            "Get RestoreObject len=%d JobId=%d oname=%s type=%d data=%s\n",
268                            rop->object_len, rop->JobId, rop->object_name, rop->object_type,
269                            rop->object);
270
271       if (!strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME)) {
272          ConfigFile ini;
273          if (ini.dump_string(rop->object, rop->object_len)) {
274             break;
275          }
276          ini.register_items(test_items, sizeof(struct ini_items));
277          if (ini.parse(ini.out_fname)) {
278             bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "string1 = %s\n", 
279                                ini.items[0].val.strval);
280          } else {
281             bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "Can't parse config\n");
282          }
283       }
284
285       break;
286    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
287    case bEventRestoreCommand:
288       /* Fall-through wanted */
289    case bEventEstimateCommand:
290       /* Fall-through wanted */
291    case bEventBackupCommand:
292       char *p;
293       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "test-plugin-fd: pluginEvent cmd=%s\n", (char *)value);
294       p_ctx->cmd = strdup((char *)value);
295       p = strchr(p_ctx->cmd, ':');
296       if (!p) {
297          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
298          return bRC_Error;
299       }
300       *p++ = 0;           /* terminate plugin */
301       p_ctx->fname = p;
302       p = strchr(p, ':');
303       if (!p) {
304          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
305          return bRC_Error;
306       }
307       *p++ = 0;           /* terminate file */
308       p_ctx->reader = p;
309       p = strchr(p, ':');
310       if (!p) {
311          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
312          return bRC_Error;
313       }
314       *p++ = 0;           /* terminate reader string */
315       p_ctx->writer = p;
316       printf("test-plugin-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
317           p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
318       break;
319    case bEventPluginCommand:
320       break;
321    case bEventVssBeforeCloseRestore:
322       break;
323    default:
324       printf("test-plugin-fd: unknown event=%d\n", event->eventType);
325       break;
326    }
327    return bRC_OK;
328 }
329
330 /* 
331  * Start the backup of a specific file
332  */
333 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
334 {
335    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
336    if (!p_ctx) {
337       return bRC_Error;
338    }
339
340    if (p_ctx->nb_obj == 0) {
341       sp->object_name = (char *)"james.xml";
342       sp->object = (char *)"This is test data for the restore object. "
343   "garbage=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
344   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
345   "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
346   "\0secret";
347       sp->object_len = strlen(sp->object)+1+6+1; /* str + 0 + secret + 0 */
348       sp->type = FT_RESTORE_FIRST;
349    
350    } else if (p_ctx->nb_obj == 1) {
351       ConfigFile ini;
352       p_ctx->buf = get_pool_memory(PM_BSOCK);
353       ini.register_items(test_items, sizeof(struct ini_items));
354
355       sp->object_name = (char*)INI_RESTORE_OBJECT_NAME;
356       sp->object_len = ini.serialize(&p_ctx->buf);
357       sp->object = p_ctx->buf;
358       sp->type = FT_PLUGIN_CONFIG;
359
360       Dmsg1(0, "RestoreOptions=<%s>\n", p_ctx->buf);
361    } 
362
363    time_t now = time(NULL);
364    sp->index = ++p_ctx->nb_obj;
365    sp->statp.st_mode = 0700 | S_IFREG;
366    sp->statp.st_ctime = now;
367    sp->statp.st_mtime = now;
368    sp->statp.st_atime = now;
369    sp->statp.st_size = sp->object_len;
370    sp->statp.st_blksize = 4096;
371    sp->statp.st_blocks = 1;
372    bfuncs->DebugMessage(ctx, fi, li, dbglvl,
373                         "Creating RestoreObject len=%d oname=%s data=%s\n", 
374                         sp->object_len, sp->object_name, sp->object);
375
376    printf("test-plugin-fd: startBackupFile\n");
377    return bRC_OK;
378 }
379
380 /*
381  * Done with backup of this file
382  */
383 static bRC endBackupFile(bpContext *ctx)
384 {
385    /*
386     * We would return bRC_More if we wanted startBackupFile to be
387     * called again to backup another file
388     */
389    return bRC_OK;
390 }
391
392
393 /*
394  * Bacula is calling us to do the actual I/O
395  */
396 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
397 {
398    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
399    if (!p_ctx) {
400       return bRC_Error;
401    }
402     
403    io->status = 0;
404    io->io_errno = 0;
405    return bRC_OK;
406 }
407
408 /*
409  * Bacula is notifying us that a plugin name string was found, and
410  *   passing us the plugin command, so we can prepare for a restore.
411  */
412 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
413 {
414    printf("test-plugin-fd: startRestoreFile cmd=%s\n", cmd);
415    return bRC_OK;
416 }
417
418 /*
419  * Bacula is notifying us that the plugin data has terminated, so
420  *  the restore for this particular file is done.
421  */
422 static bRC endRestoreFile(bpContext *ctx)
423 {
424    printf("test-plugin-fd: endRestoreFile\n");
425    return bRC_OK;
426 }
427
428 /*
429  * This is called during restore to create the file (if necessary)
430  * We must return in rp->create_status:
431  *   
432  *  CF_ERROR    -- error
433  *  CF_SKIP     -- skip processing this file
434  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
435  *  CF_CREATED  -- created, but no content to extract (typically directories)
436  *
437  */
438 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
439 {
440    printf("test-plugin-fd: createFile\n");
441    if (strlen(rp->where) > 512) {
442       printf("Restore target dir too long. Restricting to first 512 bytes.\n");
443    }
444    strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513);
445    ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
446    rp->create_status = CF_EXTRACT;
447    return bRC_OK;
448 }
449
450 /*
451  * We will get here if the File is a directory after everything
452  * is written in the directory.
453  */
454 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
455 {
456    printf("test-plugin-fd: setFileAttributes\n");
457    return bRC_OK;
458 }
459
460
461 #ifdef __cplusplus
462 }
463 #endif