]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/plugins/fd/bpipe-fd.c
Use new FO_xxx bits in backup/restore and plugins
[bacula/bacula] / bacula / src / plugins / fd / bpipe-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 pipe plugin for the Bacula File Daemon
30  *
31  *  Kern Sibbald, October 2007
32  *
33  */
34 #include "bacula.h"
35 #include "fd_plugins.h"
36
37 #undef malloc
38 #undef free
39 #undef strdup
40
41 #define fi __FILE__
42 #define li __LINE__
43
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47
48 static const int dbglvl = 150;
49
50 #define PLUGIN_LICENSE      "Bacula AGPLv3"
51 #define PLUGIN_AUTHOR       "Kern Sibbald"
52 #define PLUGIN_DATE         "January 2008"
53 #define PLUGIN_VERSION      "1"
54 #define PLUGIN_DESCRIPTION  "Bacula Pipe File Daemon Plugin"
55
56 /* Forward referenced functions */
57 static bRC newPlugin(bpContext *ctx);
58 static bRC freePlugin(bpContext *ctx);
59 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
60 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
61 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
62 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
63 static bRC endBackupFile(bpContext *ctx);
64 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
65 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
66 static bRC endRestoreFile(bpContext *ctx);
67 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
68 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
69
70 static char *apply_rp_codes(struct plugin_ctx * p_ctx);
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("bpipe-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    if (!p_ctx) {
210       return bRC_Error;
211    }
212
213 // char *name;
214
215    /*
216     * Most events don't interest us so we ignore them.
217     *   the printfs are so that plugin writers can enable them to see
218     *   what is really going on.
219     */
220    switch (event->eventType) {
221    case bEventPluginCommand:
222       bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
223                            "bpipe-fd: PluginCommand=%s\n", (char *)value);
224       break;
225    case bEventJobStart:
226       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: JobStart=%s\n", (char *)value);
227       break;
228    case bEventJobEnd:
229 //    printf("bpipe-fd: JobEnd\n");
230       break;
231    case bEventStartBackupJob:
232 //    printf("bpipe-fd: StartBackupJob\n");
233       break;
234    case bEventEndBackupJob:
235 //    printf("bpipe-fd: EndBackupJob\n");
236       break;
237    case bEventLevel:
238 //    printf("bpipe-fd: JobLevel=%c %d\n", (int)value, (int)value);
239       break;
240    case bEventSince:
241 //    printf("bpipe-fd: since=%d\n", (int)value);
242       break;
243
244    case bEventStartRestoreJob:
245 //    printf("bpipe-fd: StartRestoreJob\n");
246       break;
247
248    case bEventEndRestoreJob:
249 //    printf("bpipe-fd: EndRestoreJob\n");
250       break;
251
252    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
253    case bEventRestoreCommand:
254 //    printf("bpipe-fd: EventRestoreCommand cmd=%s\n", (char *)value);
255       /* Fall-through wanted */
256    case bEventBackupCommand:
257       char *p;
258       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
259       p_ctx->cmd = strdup((char *)value);
260       p = strchr(p_ctx->cmd, ':');
261       if (!p) {
262          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
263          return bRC_Error;
264       }
265       *p++ = 0;           /* terminate plugin */
266       p_ctx->fname = p;
267       p = strchr(p, ':');
268       if (!p) {
269          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
270          return bRC_Error;
271       }
272       *p++ = 0;           /* terminate file */
273       p_ctx->reader = p;
274       p = strchr(p, ':');
275       if (!p) {
276          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
277          return bRC_Error;
278       }
279       *p++ = 0;           /* terminate reader string */
280       p_ctx->writer = p;
281 //    printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
282 //         p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
283       break;
284
285    default:
286 //    printf("bpipe-fd: unknown event=%d\n", event->eventType);
287       break;
288    }
289    return bRC_OK;
290 }
291
292 /* 
293  * Start the backup of a specific file
294  */
295 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
296 {
297    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
298    if (!p_ctx) {
299       return bRC_Error;
300    }
301    time_t now = time(NULL);
302    sp->fname = p_ctx->fname;
303    sp->type = FT_REG;
304    sp->statp.st_mode = 0700 | S_IFREG;
305    sp->statp.st_ctime = now;
306    sp->statp.st_mtime = now;
307    sp->statp.st_atime = now;
308    sp->statp.st_size = -1;
309    sp->statp.st_blksize = 4096;
310    sp->statp.st_blocks = 1;
311    p_ctx->backup = true;
312 // printf("bpipe-fd: startBackupFile\n");
313    return bRC_OK;
314 }
315
316 /*
317  * Done with backup of this file
318  */
319 static bRC endBackupFile(bpContext *ctx)
320 {
321    /*
322     * We would return bRC_More if we wanted startBackupFile to be
323     * called again to backup another file
324     */
325    return bRC_OK;
326 }
327
328
329 /*
330  * Bacula is calling us to do the actual I/O
331  */
332 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
333 {
334    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
335    if (!p_ctx) {
336       return bRC_Error;
337    }
338     
339    io->status = 0;
340    io->io_errno = 0;
341    switch(io->func) {
342    case IO_OPEN:
343       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
344       if (io->flags & (O_CREAT | O_WRONLY)) {
345          char *writer_codes = apply_rp_codes(p_ctx);
346
347          p_ctx->fd = popen(writer_codes, "w");
348          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%d writer=%s\n", 
349              p_ctx->fd, writer_codes);
350          if (!p_ctx->fd) {
351             io->io_errno = errno;
352             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
353                "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
354             if (writer_codes) {
355                free(writer_codes);
356             }
357             return bRC_Error;
358          }
359          if (writer_codes) {
360             free(writer_codes);
361          }
362       } else {
363          p_ctx->fd = popen(p_ctx->reader, "r");
364          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n", 
365             p_ctx->fd, p_ctx->reader);
366          if (!p_ctx->fd) {
367             io->io_errno = errno;
368             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
369                "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
370             return bRC_Error;
371          }
372       }
373       sleep(1);                 /* let pipe connect */
374       break;
375
376    case IO_READ:
377       if (!p_ctx->fd) {
378          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
379          return bRC_Error;
380       }
381       io->status = fread(io->buf, 1, io->count, p_ctx->fd);
382 //    bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
383       if (io->status == 0 && ferror(p_ctx->fd)) {
384          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
385             "Pipe read error: ERR=%s\n", strerror(errno));
386          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
387             "Pipe read error: ERR=%s\n", strerror(errno));
388          return bRC_Error;
389       }
390       break;
391
392    case IO_WRITE:
393       if (!p_ctx->fd) {
394          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
395          return bRC_Error;
396       }
397 //    printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
398       io->status = fwrite(io->buf, 1, io->count, p_ctx->fd);
399 //    printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
400       if (io->status == 0 && ferror(p_ctx->fd)) {
401          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
402             "Pipe write error\n");
403          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
404             "Pipe read error: ERR=%s\n", strerror(errno));
405          return bRC_Error;
406       }
407       break;
408
409    case IO_CLOSE:
410       if (!p_ctx->fd) {
411          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
412          return bRC_Error;
413       }
414       io->status = pclose(p_ctx->fd);
415       break;
416
417    case IO_SEEK:
418       io->offset = p_ctx->offset;
419       break;
420    }
421    return bRC_OK;
422 }
423
424 /*
425  * Bacula is notifying us that a plugin name string was found, and
426  *   passing us the plugin command, so we can prepare for a restore.
427  */
428 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
429 {
430 // printf("bpipe-fd: startRestoreFile cmd=%s\n", cmd);
431    return bRC_OK;
432 }
433
434 /*
435  * Bacula is notifying us that the plugin data has terminated, so
436  *  the restore for this particular file is done.
437  */
438 static bRC endRestoreFile(bpContext *ctx)
439 {
440 // printf("bpipe-fd: endRestoreFile\n");
441    return bRC_OK;
442 }
443
444 /*
445  * This is called during restore to create the file (if necessary)
446  * We must return in rp->create_status:
447  *   
448  *  CF_ERROR    -- error
449  *  CF_SKIP     -- skip processing this file
450  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
451  *  CF_CREATED  -- created, but no content to extract (typically directories)
452  *
453  */
454 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
455 {
456 // printf("bpipe-fd: createFile\n");
457    if (strlen(rp->where) > 512) {
458       printf("Restore target dir too long. Restricting to first 512 bytes.\n");
459    }
460    strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513);
461    ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
462    rp->create_status = CF_EXTRACT;
463    return bRC_OK;
464 }
465
466 /*
467  * We will get here if the File is a directory after everything
468  * is written in the directory.
469  */
470 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
471 {
472 // printf("bpipe-fd: setFileAttributes\n");
473    return bRC_OK;
474 }
475
476 /*************************************************************************
477  * Apply codes in writer command:
478  * %w -> "where"
479  * %r -> "replace"
480  *
481  * Replace:
482  * 'always' => 'a', chr(97)
483  * 'ifnewer' => 'w', chr(119)
484  * 'ifolder' => 'o', chr(111)
485  * 'never' => 'n', chr(110)
486  *
487  * This function will allocate the required amount of memory with malloc.
488  * Need to be free()d manually.
489  * Inspired by edit_job_codes in lib/util.c
490  */
491
492 static char *apply_rp_codes(struct plugin_ctx * p_ctx)
493 {
494    char *p, *q;
495    const char *str;
496    char add[10];
497    int w_count = 0, r_count = 0;
498    char *omsg;
499
500    char *imsg = p_ctx->writer;
501
502    if (!imsg) {
503       return NULL;
504    }
505
506    if ((p = imsg)) {
507       while ((q = strstr(p, "%w"))) {
508          w_count++;
509          p=q+1;
510       }
511
512       p = imsg;
513       while ((q = strstr(p, "%r"))) {
514          r_count++;
515          p=q+1;
516       }
517    }
518
519    /* Required mem: 
520     * len(imsg) 
521     * + number of "where" codes * (len(where)-2) 
522     * - number of "replace" codes
523     */
524    omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
525    if (!omsg) {
526       fprintf(stderr, "Out of memory.");
527       return NULL;
528    }
529
530    *omsg = 0;
531    //printf("apply_rp_codes: %s\n", imsg);
532    for (p=imsg; *p; p++) {
533       if (*p == '%') {
534          switch (*++p) {
535          case '%':
536             str = "%";
537             break;
538          case 'w':
539              str = p_ctx->where;
540              break;
541          case 'r':
542             snprintf(add, 2, "%c", p_ctx->replace);
543             str = add;
544             break;
545          default:
546             add[0] = '%';
547             add[1] = *p;
548             add[2] = 0;
549             str = add;
550             break;
551          }
552       } else {
553          add[0] = *p;
554          add[1] = 0;
555          str = add;
556       }
557       //printf("add_str %s\n", str);
558       strcat(omsg, str);
559       //printf("omsg=%s\n", omsg);
560    }
561    return omsg;
562 }
563
564
565 #ifdef __cplusplus
566 }
567 #endif