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