]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/plugins/fd/bpipe-fd.c
Tweak version date
[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 bEventEstimateCommand:
257       /* Fall-through wanted */
258    case bEventBackupCommand:
259       char *p;
260       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
261       p_ctx->cmd = strdup((char *)value);
262       p = strchr(p_ctx->cmd, ':');
263       if (!p) {
264          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
265          return bRC_Error;
266       }
267       *p++ = 0;           /* terminate plugin */
268       p_ctx->fname = p;
269       p = strchr(p, ':');
270       if (!p) {
271          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
272          return bRC_Error;
273       }
274       *p++ = 0;           /* terminate file */
275       p_ctx->reader = p;
276       p = strchr(p, ':');
277       if (!p) {
278          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
279          return bRC_Error;
280       }
281       *p++ = 0;           /* terminate reader string */
282       p_ctx->writer = p;
283 //    printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
284 //         p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
285       break;
286
287    default:
288 //    printf("bpipe-fd: unknown event=%d\n", event->eventType);
289       break;
290    }
291    return bRC_OK;
292 }
293
294 /* 
295  * Start the backup of a specific file
296  */
297 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
298 {
299    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
300    if (!p_ctx) {
301       return bRC_Error;
302    }
303    time_t now = time(NULL);
304    sp->fname = p_ctx->fname;
305    sp->type = FT_REG;
306    sp->statp.st_mode = 0700 | S_IFREG;
307    sp->statp.st_ctime = now;
308    sp->statp.st_mtime = now;
309    sp->statp.st_atime = now;
310    sp->statp.st_size = -1;
311    sp->statp.st_blksize = 4096;
312    sp->statp.st_blocks = 1;
313    p_ctx->backup = true;
314 // printf("bpipe-fd: startBackupFile\n");
315    return bRC_OK;
316 }
317
318 /*
319  * Done with backup of this file
320  */
321 static bRC endBackupFile(bpContext *ctx)
322 {
323    /*
324     * We would return bRC_More if we wanted startBackupFile to be
325     * called again to backup another file
326     */
327    return bRC_OK;
328 }
329
330
331 /*
332  * Bacula is calling us to do the actual I/O
333  */
334 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
335 {
336    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
337    if (!p_ctx) {
338       return bRC_Error;
339    }
340     
341    io->status = 0;
342    io->io_errno = 0;
343    switch(io->func) {
344    case IO_OPEN:
345       bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
346       if (io->flags & (O_CREAT | O_WRONLY)) {
347          char *writer_codes = apply_rp_codes(p_ctx);
348
349          p_ctx->fd = popen(writer_codes, "w");
350          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%d writer=%s\n", 
351              p_ctx->fd, writer_codes);
352          if (!p_ctx->fd) {
353             io->io_errno = errno;
354             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
355                "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
356             if (writer_codes) {
357                free(writer_codes);
358             }
359             return bRC_Error;
360          }
361          if (writer_codes) {
362             free(writer_codes);
363          }
364       } else {
365          p_ctx->fd = popen(p_ctx->reader, "r");
366          bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n", 
367             p_ctx->fd, p_ctx->reader);
368          if (!p_ctx->fd) {
369             io->io_errno = errno;
370             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
371                "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
372             return bRC_Error;
373          }
374       }
375       sleep(1);                 /* let pipe connect */
376       break;
377
378    case IO_READ:
379       if (!p_ctx->fd) {
380          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
381          return bRC_Error;
382       }
383       io->status = fread(io->buf, 1, io->count, p_ctx->fd);
384 //    bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
385       if (io->status == 0 && ferror(p_ctx->fd)) {
386          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
387             "Pipe read error: ERR=%s\n", strerror(errno));
388          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
389             "Pipe read error: ERR=%s\n", strerror(errno));
390          return bRC_Error;
391       }
392       break;
393
394    case IO_WRITE:
395       if (!p_ctx->fd) {
396          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
397          return bRC_Error;
398       }
399 //    printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
400       io->status = fwrite(io->buf, 1, io->count, p_ctx->fd);
401 //    printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
402       if (io->status == 0 && ferror(p_ctx->fd)) {
403          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
404             "Pipe write error\n");
405          bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
406             "Pipe read error: ERR=%s\n", strerror(errno));
407          return bRC_Error;
408       }
409       break;
410
411    case IO_CLOSE:
412       if (!p_ctx->fd) {
413          bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
414          return bRC_Error;
415       }
416       io->status = pclose(p_ctx->fd);
417       break;
418
419    case IO_SEEK:
420       io->offset = p_ctx->offset;
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 /*************************************************************************
479  * Apply codes in writer command:
480  * %w -> "where"
481  * %r -> "replace"
482  *
483  * Replace:
484  * 'always' => 'a', chr(97)
485  * 'ifnewer' => 'w', chr(119)
486  * 'ifolder' => 'o', chr(111)
487  * 'never' => 'n', chr(110)
488  *
489  * This function will allocate the required amount of memory with malloc.
490  * Need to be free()d manually.
491  * Inspired by edit_job_codes in lib/util.c
492  */
493
494 static char *apply_rp_codes(struct plugin_ctx * p_ctx)
495 {
496    char *p, *q;
497    const char *str;
498    char add[10];
499    int w_count = 0, r_count = 0;
500    char *omsg;
501
502    char *imsg = p_ctx->writer;
503
504    if (!imsg) {
505       return NULL;
506    }
507
508    if ((p = imsg)) {
509       while ((q = strstr(p, "%w"))) {
510          w_count++;
511          p=q+1;
512       }
513
514       p = imsg;
515       while ((q = strstr(p, "%r"))) {
516          r_count++;
517          p=q+1;
518       }
519    }
520
521    /* Required mem: 
522     * len(imsg) 
523     * + number of "where" codes * (len(where)-2) 
524     * - number of "replace" codes
525     */
526    omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
527    if (!omsg) {
528       fprintf(stderr, "Out of memory.");
529       return NULL;
530    }
531
532    *omsg = 0;
533    //printf("apply_rp_codes: %s\n", imsg);
534    for (p=imsg; *p; p++) {
535       if (*p == '%') {
536          switch (*++p) {
537          case '%':
538             str = "%";
539             break;
540          case 'w':
541              str = p_ctx->where;
542              break;
543          case 'r':
544             snprintf(add, 2, "%c", p_ctx->replace);
545             str = add;
546             break;
547          default:
548             add[0] = '%';
549             add[1] = *p;
550             add[2] = 0;
551             str = add;
552             break;
553          }
554       } else {
555          add[0] = *p;
556          add[1] = 0;
557          str = add;
558       }
559       //printf("add_str %s\n", str);
560       strcat(omsg, str);
561       //printf("omsg=%s\n", omsg);
562    }
563    return omsg;
564 }
565
566
567 #ifdef __cplusplus
568 }
569 #endif