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