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