]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/plugins/fd/bpipe-fd.c
Applied modified patch from bug#2117 to fix bpipe end of stream
[bacula/bacula] / bacula / src / plugins / fd / bpipe-fd.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * A simple pipe plugin for the Bacula File Daemon
21  *
22  *  Kern Sibbald, October 2007
23  *
24  */
25 #include "bacula.h"
26 #include "fd_plugins.h"
27
28 #undef malloc
29 #undef free
30 #undef strdup
31
32 #define fi __FILE__
33 #define li __LINE__
34
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38
39 static const int dbglvl = 150;
40
41 #define PLUGIN_LICENSE      "AGPLv3"
42 #define PLUGIN_AUTHOR       "Kern Sibbald"
43 #define PLUGIN_DATE         "January 2008"
44 #define PLUGIN_VERSION      "1"
45 #define PLUGIN_DESCRIPTION  "Bacula Pipe File Daemon Plugin"
46
47 /* Forward referenced functions */
48 static bRC newPlugin(bpContext *ctx);
49 static bRC freePlugin(bpContext *ctx);
50 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
51 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
52 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
53 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
54 static bRC endBackupFile(bpContext *ctx);
55 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
56 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
57 static bRC endRestoreFile(bpContext *ctx);
58 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
59 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
60 static bRC checkFile(bpContext *ctx, char *fname);
61
62 static char *apply_rp_codes(struct plugin_ctx * p_ctx);
63
64 /* Pointers to Bacula functions */
65 static bFuncs *bfuncs = NULL;
66 static bInfo  *binfo = NULL;
67
68 /* Plugin Information block */
69 static pInfo pluginInfo = {
70    sizeof(pluginInfo),
71    FD_PLUGIN_INTERFACE_VERSION,
72    FD_PLUGIN_MAGIC,
73    PLUGIN_LICENSE,
74    PLUGIN_AUTHOR,
75    PLUGIN_DATE,
76    PLUGIN_VERSION,
77    PLUGIN_DESCRIPTION
78 };
79
80 /* Plugin entry points for Bacula */
81 static pFuncs pluginFuncs = {
82    sizeof(pluginFuncs),
83    FD_PLUGIN_INTERFACE_VERSION,
84
85    /* Entry points into plugin */
86    newPlugin,                         /* new plugin instance */
87    freePlugin,                        /* free plugin instance */
88    getPluginValue,
89    setPluginValue,
90    handlePluginEvent,
91    startBackupFile,
92    endBackupFile,
93    startRestoreFile,
94    endRestoreFile,
95    pluginIO,
96    createFile,
97    setFileAttributes,
98    checkFile
99 };
100
101 /*
102  * Plugin private context
103  */
104 struct plugin_ctx {
105    boffset_t offset;
106    BPIPE *pfd;                        /* bpipe file descriptor */
107    bool backup;                       /* set for backup (not needed) */
108    char *cmd;                         /* plugin command line */
109    char *fname;                       /* filename to "backup/restore" */
110    char *reader;                      /* reader program for backup */
111    char *writer;                      /* writer program for backup */
112
113    char where[512];
114    int replace;
115 };
116
117 /*
118  * loadPlugin() and unloadPlugin() are entry points that are
119  *  exported, so Bacula can directly call these two entry points
120  *  they are common to all Bacula plugins.
121  */
122 /*
123  * External entry point called by Bacula to "load the plugin
124  */
125 bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
126 {
127    bfuncs = lbfuncs;                  /* set Bacula funct pointers */
128    binfo  = lbinfo;
129    *pinfo  = &pluginInfo;             /* return pointer to our info */
130    *pfuncs = &pluginFuncs;            /* return pointer to our functions */
131
132    return bRC_OK;
133 }
134
135 /*
136  * External entry point to unload the plugin 
137  */
138 bRC unloadPlugin() 
139 {
140 // printf("bpipe-fd: Unloaded\n");
141    return bRC_OK;
142 }
143
144 /*
145  * The following entry points are accessed through the function 
146  *   pointers we supplied to Bacula. Each plugin type (dir, fd, sd)
147  *   has its own set of entry points that the plugin must define.
148  */
149 /*
150  * Create a new instance of the plugin i.e. allocate our private storage
151  */
152 static bRC newPlugin(bpContext *ctx)
153 {
154    struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
155    if (!p_ctx) {
156       return bRC_Error;
157    }
158    memset(p_ctx, 0, sizeof(struct plugin_ctx));
159    ctx->pContext = (void *)p_ctx;        /* set our context pointer */
160    return bRC_OK;
161 }
162
163 /*
164  * Free a plugin instance, i.e. release our private storage
165  */
166 static bRC freePlugin(bpContext *ctx)
167 {
168    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
169    if (!p_ctx) {
170       return bRC_Error;
171    }
172    if (p_ctx->cmd) {
173       free(p_ctx->cmd);                  /* free any allocated command string */
174    }
175    free(p_ctx);                          /* free our private context */
176    p_ctx = NULL;
177    return bRC_OK;
178 }
179
180 /*
181  * Return some plugin value (none defined)
182  */
183 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value) 
184 {
185    return bRC_OK;
186 }
187
188 /*
189  * Set a plugin value (none defined)
190  */
191 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value) 
192 {
193    return bRC_OK;
194 }
195
196 /*
197  * Handle an event that was generated in Bacula
198  */
199 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
200 {
201    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
202    if (!p_ctx) {
203       return bRC_Error;
204    }
205
206 // char *name;
207
208    /*
209     * Most events don't interest us so we ignore them.
210     *   the printfs are so that plugin writers can enable them to see
211     *   what is really going on.
212     */
213    switch (event->eventType) {
214    case bEventPluginCommand:
215       bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
216                            "bpipe-fd: PluginCommand=%s\n", (char *)value);
217       break;
218    case bEventJobStart:
219       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: JobStart=%s\n", (char *)value);
220       break;
221    case bEventJobEnd:
222 //    printf("bpipe-fd: JobEnd\n");
223       break;
224    case bEventStartBackupJob:
225 //    printf("bpipe-fd: StartBackupJob\n");
226       break;
227    case bEventEndBackupJob:
228 //    printf("bpipe-fd: EndBackupJob\n");
229       break;
230    case bEventLevel:
231 //    printf("bpipe-fd: JobLevel=%c %d\n", (int)value, (int)value);
232       break;
233    case bEventSince:
234 //    printf("bpipe-fd: since=%d\n", (int)value);
235       break;
236
237    case bEventStartRestoreJob:
238 //    printf("bpipe-fd: StartRestoreJob\n");
239       break;
240
241    case bEventEndRestoreJob:
242 //    printf("bpipe-fd: EndRestoreJob\n");
243       break;
244
245    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
246    case bEventRestoreCommand:
247 //    printf("bpipe-fd: EventRestoreCommand cmd=%s\n", (char *)value);
248       /* Fall-through wanted */
249    case bEventEstimateCommand:
250       /* Fall-through wanted */
251    case bEventBackupCommand:
252       char *p;
253       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
254       p_ctx->cmd = strdup((char *)value);
255       p = strchr(p_ctx->cmd, ':');
256       if (!p) {
257          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
258          return bRC_Error;
259       }
260       *p++ = 0;           /* terminate plugin */
261       p_ctx->fname = p;
262       p = strchr(p, ':');
263       if (!p) {
264          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
265          return bRC_Error;
266       }
267       *p++ = 0;           /* terminate file */
268       p_ctx->reader = p;
269       p = strchr(p, ':');
270       if (!p) {
271          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
272          return bRC_Error;
273       }
274       *p++ = 0;           /* terminate reader string */
275       p_ctx->writer = p;
276 //    printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
277 //         p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
278       break;
279
280    default:
281 //    printf("bpipe-fd: unknown event=%d\n", event->eventType);
282       break;
283    }
284    return bRC_OK;
285 }
286
287 /* 
288  * Start the backup of a specific file
289  */
290 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
291 {
292    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
293    if (!p_ctx) {
294       return bRC_Error;
295    }
296    time_t now = time(NULL);
297    sp->fname = p_ctx->fname;
298    sp->type = FT_REG;
299    sp->statp.st_mode = 0700 | S_IFREG;
300    sp->statp.st_ctime = now;
301    sp->statp.st_mtime = now;
302    sp->statp.st_atime = now;
303    sp->statp.st_size = -1;
304    sp->statp.st_blksize = 4096;
305    sp->statp.st_blocks = 1;
306    p_ctx->backup = true;
307 // printf("bpipe-fd: startBackupFile\n");
308    return bRC_OK;
309 }
310
311 /*
312  * Done with backup of this file
313  */
314 static bRC endBackupFile(bpContext *ctx)
315 {
316    /*
317     * We would return bRC_More if we wanted startBackupFile to be
318     * called again to backup another file
319     */
320    return bRC_OK;
321 }
322
323
324 /*
325  * Bacula is calling us to do the actual I/O
326  */
327 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
328 {
329    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
330    if (!p_ctx) {
331       return bRC_Error;
332    }
333     
334    io->status = -1;
335    io->io_errno = 0;
336    switch(io->func) {
337    case IO_OPEN:
338       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
339       if (io->flags & (O_CREAT | O_WRONLY)) {
340          char *writer_codes = apply_rp_codes(p_ctx);
341
342          p_ctx->pfd = open_bpipe(writer_codes, 0, "ws");
343          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p writer=%s\n", 
344              p_ctx->pfd, writer_codes);
345          if (!p_ctx->pfd) {
346             io->io_errno = errno;
347             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
348                "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
349             if (writer_codes) {
350                free(writer_codes);
351             }
352             return bRC_Error;
353          }
354          if (writer_codes) {
355             free(writer_codes);
356          }
357          io->status = fileno(p_ctx->pfd->wfd);
358       } else {
359          p_ctx->pfd = open_bpipe(p_ctx->reader, 0, "rs");
360          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n", 
361             p_ctx->pfd, p_ctx->reader);
362          if (!p_ctx->pfd) {
363             io->io_errno = errno;
364             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
365                "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
366             return bRC_Error;
367          }
368          io->status = fileno(p_ctx->pfd->rfd);
369       }
370       sleep(1);                 /* let pipe connect */
371       break;
372
373    case IO_READ:
374       if (!p_ctx->pfd) {
375          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
376          return bRC_Error;
377       }
378       io->status = fread(io->buf, 1, io->count, p_ctx->pfd->rfd);
379 //    bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
380       if (!feof(p_ctx->pfd->rfd) && io->status == 0 && ferror(p_ctx->pfd->rfd)) {
381          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
382             "Pipe read error: ERR=%s\n", strerror(errno));
383          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
384             "Pipe read error: ERR=%s\n", strerror(errno));
385          return bRC_Error;
386       }
387       break;
388
389    case IO_WRITE:
390       if (!p_ctx->pfd) {
391          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
392          return bRC_Error;
393       }
394 //    printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
395       io->status = fwrite(io->buf, 1, io->count, p_ctx->pfd->wfd);
396 //    printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
397       if (!feof(p_ctx->pfd->wfd) && io->status == 0 && ferror(p_ctx->pfd->wfd)) {
398          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
399             "Pipe write error\n");
400          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
401             "Pipe write error: ERR=%s\n", strerror(errno));
402          return bRC_Error;
403       }
404       break;
405
406    case IO_CLOSE:
407       if (!p_ctx->pfd) {
408          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
409          return bRC_Error;
410       }
411       io->status = close_bpipe(p_ctx->pfd);
412       if (io->status != 0) {
413          bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "bpipe-fd: Error closing for file %s: %d\n", 
414                             p_ctx->fname, io->status);
415       }
416       break;
417
418    case IO_SEEK:
419       io->offset = p_ctx->offset;
420       io->status = 0;
421       break;
422    }
423    return bRC_OK;
424 }
425
426 /*
427  * Bacula is notifying us that a plugin name string was found, and
428  *   passing us the plugin command, so we can prepare for a restore.
429  */
430 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
431 {
432 // printf("bpipe-fd: startRestoreFile cmd=%s\n", cmd);
433    return bRC_OK;
434 }
435
436 /*
437  * Bacula is notifying us that the plugin data has terminated, so
438  *  the restore for this particular file is done.
439  */
440 static bRC endRestoreFile(bpContext *ctx)
441 {
442 // printf("bpipe-fd: endRestoreFile\n");
443    return bRC_OK;
444 }
445
446 /*
447  * This is called during restore to create the file (if necessary)
448  * We must return in rp->create_status:
449  *   
450  *  CF_ERROR    -- error
451  *  CF_SKIP     -- skip processing this file
452  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
453  *  CF_CREATED  -- created, but no content to extract (typically directories)
454  *
455  */
456 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
457 {
458 // printf("bpipe-fd: createFile\n");
459    if (strlen(rp->where) > 512) {
460       printf("Restore target dir too long. Restricting to first 512 bytes.\n");
461    }
462    strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513);
463    ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
464    rp->create_status = CF_EXTRACT;
465    return bRC_OK;
466 }
467
468 /*
469  * We will get here if the File is a directory after everything
470  * is written in the directory.
471  */
472 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
473 {
474 // printf("bpipe-fd: setFileAttributes\n");
475    return bRC_OK;
476 }
477
478 /* When using Incremental dump, all previous dumps are necessary */
479 static bRC checkFile(bpContext *ctx, char *fname)
480 {
481    return bRC_OK;
482 }
483
484 /*************************************************************************
485  * Apply codes in writer command:
486  * %w -> "where"
487  * %r -> "replace"
488  *
489  * Replace:
490  * 'always' => 'a', chr(97)
491  * 'ifnewer' => 'w', chr(119)
492  * 'ifolder' => 'o', chr(111)
493  * 'never' => 'n', chr(110)
494  *
495  * This function will allocate the required amount of memory with malloc.
496  * Need to be free()d manually.
497  * Inspired by edit_job_codes in lib/util.c
498  */
499
500 static char *apply_rp_codes(struct plugin_ctx * p_ctx)
501 {
502    char *p, *q;
503    const char *str;
504    char add[10];
505    int w_count = 0, r_count = 0;
506    char *omsg;
507
508    char *imsg = p_ctx->writer;
509
510    if (!imsg) {
511       return NULL;
512    }
513
514    if ((p = imsg)) {
515       while ((q = strstr(p, "%w"))) {
516          w_count++;
517          p=q+1;
518       }
519
520       p = imsg;
521       while ((q = strstr(p, "%r"))) {
522          r_count++;
523          p=q+1;
524       }
525    }
526
527    /* Required mem: 
528     * len(imsg) 
529     * + number of "where" codes * (len(where)-2) 
530     * - number of "replace" codes
531     */
532    omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
533    if (!omsg) {
534       fprintf(stderr, "Out of memory.");
535       return NULL;
536    }
537
538    *omsg = 0;
539    //printf("apply_rp_codes: %s\n", imsg);
540    for (p=imsg; *p; p++) {
541       if (*p == '%') {
542          switch (*++p) {
543          case '%':
544             str = "%";
545             break;
546          case 'w':
547              str = p_ctx->where;
548              break;
549          case 'r':
550             snprintf(add, 2, "%c", p_ctx->replace);
551             str = add;
552             break;
553          default:
554             add[0] = '%';
555             add[1] = *p;
556             add[2] = 0;
557             str = add;
558             break;
559          }
560       } else {
561          add[0] = *p;
562          add[1] = 0;
563          str = add;
564       }
565       //printf("add_str %s\n", str);
566       strcat(omsg, str);
567       //printf("omsg=%s\n", omsg);
568    }
569    return omsg;
570 }
571
572 #ifdef __cplusplus
573 }
574 #endif