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