1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2019 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  * This is a Bacula plugin for backup/restore Docker using native tools.
21  *
22  * Author: Radosław Korzeniewski, MMXIX
23  * radoslaw@korzeniewski.net, radekk@inteos.pl
24  * Inteos Sp. z o.o. http://www.inteos.pl/
25  */
26 
27 #include "docker-fd.h"
28 #include <sys/stat.h>
29 #include <signal.h>
30 #include <time.h>
31 #include <libgen.h>
32 
33 /*
34  * libbac uses its own sscanf implementation which is not compatible with
35  * libc implementation, unfortunately.
36  * use bsscanf for Bacula sscanf flavor
37  */
38 #ifdef sscanf
39 #undef sscanf
40 #endif
41 
42 extern DLL_IMP_EXP int64_t       debug_level;
43 
44 /* Forward referenced functions */
45 static bRC newPlugin(bpContext *ctx);
46 static bRC freePlugin(bpContext *ctx);
47 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
48 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
49 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
50 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
51 static bRC endBackupFile(bpContext *ctx);
52 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
53 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
54 static bRC endRestoreFile(bpContext *ctx);
55 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
56 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
57 // Not used! static bRC checkFile(bpContext *ctx, char *fname);
58 static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl);
59 
60 /* Pointers to Bacula functions */
61 bFuncs *bfuncs = NULL;
62 bInfo *binfo = NULL;
63 
64 static pFuncs pluginFuncs = {
65    sizeof(pluginFuncs),
66    FD_PLUGIN_INTERFACE_VERSION,
67 
68    /* Entry points into plugin */
69    newPlugin,
70    freePlugin,
71    getPluginValue,
72    setPluginValue,
73    handlePluginEvent,
74    startBackupFile,
75    endBackupFile,
76    startRestoreFile,
77    endRestoreFile,
78    pluginIO,
79    createFile,
80    setFileAttributes,
81    NULL,
82    handleXACLdata
83 };
84 
85 #ifdef __cplusplus
86 extern "C" {
87 #endif
88 
89 /* Plugin Information structure */
90 static pInfo pluginInfo = {
91    sizeof(pluginInfo),
92    FD_PLUGIN_INTERFACE_VERSION,
93    FD_PLUGIN_MAGIC,
94    DOCKER_LICENSE,
95    DOCKER_AUTHOR,
96    DOCKER_DATE,
97    DOCKER_VERSION,
98    DOCKER_DESCRIPTION,
99 };
100 
101 /*
102  * Plugin called here when it is first loaded.
103  */
loadPlugin(bInfo * lbinfo,bFuncs * lbfuncs,pInfo ** pinfo,pFuncs ** pfuncs)104 bRC DLL_IMP_EXP loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo ** pinfo, pFuncs ** pfuncs)
105 {
106    bfuncs = lbfuncs;               /* set Bacula function pointers */
107    binfo = lbinfo;
108 
109    Dmsg2(DINFO, PLUGINNAME " Plugin version %s %s (c) 2019 by Inteos\n",
110       DOCKER_VERSION, DOCKER_DATE);
111 
112    *pinfo = &pluginInfo;           /* return pointer to our info */
113    *pfuncs = &pluginFuncs;         /* return pointer to our functions */
114 
115    if (access(DOCKER_CMD, X_OK) < 0){
116       berrno be;
117       bfuncs->DebugMessage(NULL, __FILE__, __LINE__, DERROR,
118          PLUGINPREFIX " Unable to use command tool: %s Err=%s\n", DOCKER_CMD,
119          be.bstrerror());
120       return bRC_Error;
121    }
122 
123    return bRC_OK;
124 }
125 
126 /*
127  * Plugin called here when it is unloaded, normally when Bacula is going to exit.
128  */
unloadPlugin()129 bRC DLL_IMP_EXP unloadPlugin()
130 {
131    return bRC_OK;
132 }
133 
134 #ifdef __cplusplus
135 }
136 #endif
137 
138 /*
139  * Main DOCKER Plugin class constructor.
140  *  Initializes all variables required.
141  */
DOCKER(bpContext * bpctx)142 DOCKER::DOCKER(bpContext *bpctx) :
143       mode(DOCKER_NONE),
144       JobId(0),
145       JobName(NULL),
146       since(0),
147       where(NULL),
148       regexwhere(NULL),
149       replace(0),
150       robjsent(false),
151       estimate(false),
152       accurate_warning(false),
153       local_restore(false),
154       backup_finish(false),
155       unsupportedlevel(false),
156       param_notrunc(false),
157       errortar(false),
158       volumewarning(false),
159       dockerworkclear(0),
160       dkcommctx(NULL),
161       commandlist(NULL),
162       fname(NULL),
163       lname(NULL),
164       dkfd(0),
165       robjbuf(NULL),
166       currdkinfo(NULL),
167       restoredkinfo(NULL),
168       listing_mode(DOCKER_LISTING_NONE),
169       listing_objnr(0),
170       parser(NULL),
171       workingdir(NULL)
172 {
173    /* TODO: we have a ctx variable stored internally, decide if we use it
174     * for every method or rip it off as not required in our code */
175    ctx = bpctx;
176 }
177 
178 /*
179  * Main DOCKER Plugin class destructor, handles variable release on delete.
180  *
181  * in: none
182  * out: freed internal variables and class allocated during job execution
183  */
~DOCKER()184 DOCKER::~DOCKER()
185 {
186    /* free standard variables */
187    free_and_null_pool_memory(fname);
188    free_and_null_pool_memory(lname);
189    free_and_null_pool_memory(robjbuf);
190    free_and_null_pool_memory(workingdir);
191    /* free backend contexts */
192    if (commandlist){
193       /* free all backend contexts */
194       foreach_alist(dkcommctx, commandlist){
195          delete dkcommctx;
196       }
197       delete commandlist;
198    }
199    if (parser){
200       delete parser;
201    }
202    if (restoredkinfo){
203       delete restoredkinfo;
204    }
205 }
206 
207 /*
208  * sets runtime workingdir variable used in working volume creation.
209  *
210  * in:
211  *    workdir - the file daemon working directory parameter
212  * out:
213  *    none
214  */
setworkingdir(char * workdir)215 void DOCKER::setworkingdir(char* workdir)
216 {
217    if (workingdir == NULL){
218       /* not allocated yet */
219       workingdir = get_pool_memory(PM_FNAME);
220    }
221    pm_strcpy(&workingdir, workdir);
222    DMSG1(NULL, DVDEBUG, "workingdir: %s\n", workingdir);
223 };
224 
225 /*
226  * Parse a Restore Object saved during backup and modified by user during restore.
227  *    Every RO received will allocate a dedicated command context which is used
228  *    by bEventRestoreCommand to handle default parameters for restore.
229  *
230  * in:
231  *    bpContext - Bacula Plugin context structure
232  *    rop - a restore object structure to parse
233  * out:
234  *    bRC_OK - on success
235  *    bRC_Error - on error
236  */
parse_plugin_restoreobj(bpContext * ctx,restore_object_pkt * rop)237 bRC DOCKER::parse_plugin_restoreobj(bpContext *ctx, restore_object_pkt *rop)
238 {
239    if (!rop){
240       return bRC_OK;    /* end of rop list */
241    }
242 
243    if (bstrcmp(rop->object_name, INI_RESTORE_OBJECT_NAME)){
244       /* we have a single RO for every command */
245       switch_commandctx(ctx, rop->plugin_name);
246       /* all restore parameters are DKCOMMCTX specific, so forward parsing to it */
247       return dkcommctx->parse_restoreobj(ctx, rop);
248    }
249 
250    return bRC_OK;
251 }
252 
253 /*
254  * Parsing a plugin command.
255  *    Plugin command e.g. plugin = <plugin-name>:[parameters [parameters]...]
256  *
257  * in:
258  *    bpContext - Bacula Plugin context structure
259  *    command - plugin command string to parse
260  * out:
261  *    bRC_OK - on success
262  *    bRC_Error - on error
263  */
parse_plugin_command(bpContext * ctx,const char * command)264 bRC DOCKER::parse_plugin_command(bpContext *ctx, const char *command)
265 {
266    int i, a;
267    bRC status;
268 
269    DMSG(ctx, DINFO, "Parse command: %s\n", command);
270    /* allocate a new parser if required */
271    if (parser == NULL){
272       parser = new cmd_parser();
273    }
274 
275    /* and parse command */
276    if (parser->parse_cmd(command) != bRC_OK) {
277       DMSG0(ctx, DERROR, "Unable to parse Plugin command line.\n");
278       JMSG0(ctx, M_FATAL, "Unable to parse Plugin command line.\n");
279       return bRC_Error;
280    }
281 
282    /* switch dkcommctx to the required context or allocate a new context */
283    switch_commandctx(ctx, command);
284 
285    /* the first (zero) parameter is a plugin name, we should skip it */
286    for (i = 1; i < parser->argc; i++) {
287       /* loop over all parsed parameters */
288       if (estimate && bstrcmp(parser->argk[i], "listing")){
289          /* we have a listing parameter which for estimate means .ls command */
290          listing_objnr = 1;
291          listing_mode = DOCKER_LISTING_TOP;
292          a = 0;
293          while (docker_objects[a].name){
294             if (bstrcmp(parser->argv[i], docker_objects[a].name) ||
295                 (*parser->argv[i] == '/' && bstrcmp(parser->argv[i]+1, docker_objects[a].name))){
296                listing_mode = docker_objects[a].mode;
297                break;
298             }
299             a++;
300          }
301          continue;
302       }
303       if (estimate && bstrcmp(parser->argk[i], "notrunc")){
304          /* we are doing estimate and user requested notrunc in display */
305          param_notrunc = true;
306          continue;
307       }
308       /* handle it with dkcommctx */
309       status = dkcommctx->parse_parameters(ctx, parser->argk[i], parser->argv[i]);
310       switch (status){
311          case bRC_OK:
312             /* the parameter was handled by dkcommctx, proceed to the next */
313             continue;
314          case bRC_Error:
315             /* parsing returned error, raise it up */
316             return bRC_Error;
317          default:
318             break;
319       }
320       DMSG(ctx, DERROR, "Unknown parameter: %s\n", parser->argk[i]);
321       JMSG(ctx, M_ERROR, "Unknown parameter: %s\n", parser->argk[i]);
322    }
323    return bRC_OK;
324 }
325 
326 /*
327  * Allocate and initialize new command context list at commandlist.
328  *
329  * in:
330  *    bpContext - for Bacula debug and jobinfo messages
331  *    command - a Plugin command for a job as a first backend context
332  * out:
333  *    New backend contexts list at commandlist allocated and initialized.
334  *    The only error we can get here is out of memory error, handled internally
335  *    by Bacula itself.
336  */
new_commandctx(bpContext * ctx,const char * command)337 void DOCKER::new_commandctx(bpContext *ctx, const char *command)
338 {
339    /* our new command context */
340    dkcommctx = New(DKCOMMCTX(command));
341    /* add command context to our list */
342    commandlist->append(dkcommctx);
343    DMSG(ctx, DINFO, "Command context allocated for: %s\n", command);
344    /* setup runtime workingdir */
345    dkcommctx->setworkingdir(workingdir);
346 }
347 
348 /*
349  * The function manages the command contexts list.
350  *
351  * in:
352  *    bpContext - for Bacula debug and jobinfo messages
353  *    command - a Plugin command for a job as a first backend context
354  * out:
355  *    this.dkcommctx - the DKCOMMCTX allocated/switched for command
356  */
switch_commandctx(bpContext * ctx,const char * command)357 void DOCKER::switch_commandctx(bpContext *ctx, const char *command)
358 {
359    DKCOMMCTX *dkctx;
360 
361    if (commandlist == NULL){
362       /* new command list required, we assumed 8 command contexts at start, should be sufficient */
363       commandlist = New(alist(8, not_owned_by_alist));
364       /* our first command context */
365       new_commandctx(ctx, command);
366    } else {
367       /* command list available, so search for already allocated context */
368       foreach_alist(dkctx, commandlist){
369          if (bstrcmp(dkctx->command, command)){
370             /* found, set dkcommctx to it and return */
371             dkcommctx = dkctx;
372             DMSG(ctx, DINFO, "Command context switched to: %s\n", command);
373             return;
374          }
375       }
376       /* well, command context not found, so allocate a new one */
377       new_commandctx(ctx, command);
378    }
379 }
380 
381 /*
382  * Prepares a single Plugin command for backup or estimate job.
383  *  Make a preparation by parse a plugin command and check the
384  *  backup/estimate/listing mode and make a proper dkcommctx initialization.
385  *
386  * in:
387  *    bpContext - for Bacula debug and jobinfo messages
388  *    command - a Plugin command to prepare
389  * out:
390  *    bRC_OK - when preparation was successful
391  *    bRC_Error - on any error
392  */
prepare_bejob(bpContext * ctx,char * command)393 bRC DOCKER::prepare_bejob(bpContext* ctx, char *command)
394 {
395    /* check if it is our Plugin command */
396    if (isourplugincommand(PLUGINPREFIX, command)){
397       /* first, parse backup command */
398       if (parse_plugin_command(ctx, command) != bRC_OK){
399          return bRC_Error;
400       }
401 
402       switch (listing_mode){
403          case DOCKER_LISTING_NONE:
404             /* other will prepare backup job in dkcommctx context */
405             return dkcommctx->prepare_bejob(ctx, estimate);
406          case DOCKER_LISTING_CONTAINER:
407             /* listing require all */
408             if (!dkcommctx->get_all_containers(ctx)){
409                return bRC_Error;
410             }
411             dkcommctx->set_all_containers_to_backup(ctx);
412             break;
413          case DOCKER_LISTING_IMAGE:
414             if (!dkcommctx->get_all_images(ctx)){
415                return bRC_Error;
416             }
417             dkcommctx->set_all_images_to_backup(ctx);
418             break;
419          case DOCKER_LISTING_VOLUME:
420             if (!dkcommctx->get_all_volumes(ctx)){
421                return bRC_Error;
422             }
423             dkcommctx->set_all_volumes_to_backup(ctx);
424             break;
425          default:
426             break;
427       }
428    }
429 
430    return bRC_OK;
431 }
432 
433 /*
434  * Prepares a single Plugin command for backup.
435  *
436  * in:
437  *    bpContext - for Bacula debug and jobinfo messages
438  *    command - a Plugin command to prepare
439  * out:
440  *    bRC_OK - when preparation was successful
441  *    bRC_Error - on any error
442  */
prepare_backup(bpContext * ctx,char * command)443 bRC DOCKER::prepare_backup(bpContext* ctx, char *command)
444 {
445    estimate = false;
446    if (prepare_bejob(ctx, command) != bRC_OK){
447       return bRC_Error;
448    }
449    return bRC_OK;
450 }
451 
452 /*
453  * Prepares a single Plugin command for estimate/listing.
454  *
455  * in:
456  *    bpContext - for Bacula debug and jobinfo messages
457  *    command - a Plugin command to prepare
458  * out:
459  *    bRC_OK - when preparation was successful
460  *    bRC_Error - on any error
461  */
prepare_estimate(bpContext * ctx,char * command)462 bRC DOCKER::prepare_estimate(bpContext* ctx, char *command)
463 {
464    estimate = true;
465    if (prepare_bejob(ctx, command) != bRC_OK){
466       return bRC_Error;
467    }
468    dkcommctx->clear_abort_on_error();
469    return bRC_OK;
470 }
471 
472 /*
473  * Prepares a single Plugin command for restore.
474  *  Make a preparation by parse a plugin command and make a proper dkcommctx
475  *  initialization.
476  * in:
477  *    bpContext - for Bacula debug and jobinfo messages
478  *    command - a Plugin command to prepare
479  * out:
480  *    bRC_OK - when preparation was successful
481  *    bRC_Error - on any error
482  */
prepare_restore(bpContext * ctx,char * command)483 bRC DOCKER::prepare_restore(bpContext* ctx, char *command)
484 {
485    /* check if it is our Plugin command */
486    if (isourplugincommand(PLUGINPREFIX, command)){
487       /* first, parse backup command */
488       if (parse_plugin_command(ctx, command) != bRC_OK){
489          return bRC_Error;
490       }
491 
492       /* prepare restore */
493       return dkcommctx->prepare_restore(ctx);
494    }
495    return bRC_OK;
496 }
497 
498 /*
499  * This is the main method for handling events generated by Bacula.
500  *    The behavior of the method depends on event type generated, but there are
501  *    some events which does nothing, just return with bRC_OK. Every event is
502  *    tracked in debug trace file to verify the event flow during development.
503  *
504  * in:
505  *    bpContext - for Bacula debug and jobinfo messages
506  *    event - a Bacula event structure
507  *    value - optional event value
508  * out:
509  *    bRC_OK - in most cases signal success/no error
510  *    bRC_Error - in most cases signal error
511  *    <other> - depend on Bacula Plugin API if applied
512  */
handlePluginEvent(bpContext * ctx,bEvent * event,void * value)513 bRC DOCKER::handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
514 {
515    switch (event->eventType) {
516    case bEventJobStart:
517       DMSG_EVENT_STR(event, value);
518       getBaculaVar(bVarJobId, (void *)&JobId);
519       getBaculaVar(bVarJobName, (void *)&JobName);
520       break;
521 
522    case bEventJobEnd:
523       DMSG_EVENT_STR(event, value);
524       if (dockerworkclear == 1){
525          dkcommctx->clean_working_volume(ctx);
526          dockerworkclear = 0;
527       }
528       break;
529 
530    case bEventLevel:
531       char lvl;
532       lvl = (char)((intptr_t) value & 0xff);
533       DMSG_EVENT_CHAR(event, lvl);
534       /* the plugin support a FULL backup only as Docker does not support other levels */
535       mode = DOCKER_BACKUP_FULL;
536       if (lvl != 'F'){
537          unsupportedlevel = true;
538       }
539       break;
540 
541    case bEventSince:
542       since = (time_t) value;
543       DMSG_EVENT_LONG(event, since);
544       break;
545 
546    case bEventStartBackupJob:
547       DMSG_EVENT_STR(event, value);
548       break;
549 
550    case bEventEndBackupJob:
551       DMSG_EVENT_STR(event, value);
552       break;
553 
554    case bEventStartRestoreJob:
555       DMSG_EVENT_STR(event, value);
556       getBaculaVar(bVarWhere, &where);
557       DMSG(ctx, DINFO, "Where=%s\n", NPRT(where));
558       getBaculaVar(bVarReplace, &replace);
559       DMSG(ctx, DINFO, "Replace=%c\n", replace);
560       mode = DOCKER_RESTORE;
561       break;
562 
563    case bEventEndRestoreJob:
564       DMSG_EVENT_STR(event, value);
565       break;
566 
567    /* Plugin command e.g. plugin = <plugin-name>:parameters */
568    case bEventEstimateCommand:
569       DMSG_EVENT_STR(event, value);
570       estimate = true;
571       free_and_null_pool_memory(fname);
572       return prepare_estimate(ctx, (char*) value);
573 
574    /* Plugin command e.g. plugin = <plugin-name>:parameters */
575    case bEventBackupCommand:
576       DMSG_EVENT_STR(event, value);
577       robjsent = false;
578       free_and_null_pool_memory(fname);
579       return prepare_backup(ctx, (char*)value);
580 
581    /* Plugin command e.g. plugin = <plugin-name>:parameters */
582    case bEventRestoreCommand:
583       DMSG_EVENT_STR(event, value);
584       getBaculaVar(bVarRegexWhere, &regexwhere);
585       DMSG(ctx, DINFO, "RegexWhere=%s\n", NPRT(regexwhere));
586       if (regexwhere){
587          /* the plugin cannot support regexwhere, so raise the error */
588          DMSG0(ctx, DERROR, "Cannot support RegexWhere restore parameter. Aborting Job.\n");
589          JMSG0(ctx, M_FATAL, "Cannot support RegexWhere restore parameter. Aborting Job.\n");
590          return bRC_Error;
591       }
592       return prepare_restore(ctx, (char*)value);
593 
594    /* Plugin command e.g. plugin = <plugin-name>:parameters */
595    case bEventPluginCommand:
596       DMSG_EVENT_STR(event, value);
597       if (isourplugincommand(PLUGINPREFIX, (char*)value)){
598          // Check supported level
599          if (unsupportedlevel){
600             DMSG0(ctx, DERROR, "Unsupported backup level. Doing FULL backup.\n");
601             JMSG0(ctx, M_ERROR, "Unsupported backup level. Doing FULL backup.\n");
602             /* single error message is enough */
603             unsupportedlevel = false;
604          }
605 
606          // check accurate mode backup
607          int accurate;
608          getBaculaVar(bVarAccurate, &accurate);
609          DMSG(ctx, DINFO, "Accurate=%d\n", accurate);
610          if (accurate > 0 && !accurate_warning){
611             DMSG0(ctx, DERROR, "Accurate mode is not supported. Please disable Accurate mode for this job.\n");
612             JMSG0(ctx, M_WARNING, "Accurate mode is not supported. Please disable Accurate mode for this job.\n");
613             /* single error message is enough */
614             accurate_warning = true;
615          }
616       }
617       break;
618 
619    case bEventOptionPlugin:
620    case bEventHandleBackupFile:
621       if (isourplugincommand(PLUGINPREFIX, (char*)value)){
622          DMSG0(ctx, DERROR, "Invalid handle Option Plugin called!\n");
623          JMSG0(ctx, M_FATAL,
624                "The " PLUGINNAME " plugin doesn't support the Option Plugin configuration.\n"
625                "Please review your FileSet and move the Plugin=" PLUGINPREFIX
626                "... command into the Include {} block.\n");
627          return bRC_Error;
628       }
629       break;
630 
631    case bEventEndFileSet:
632       DMSG_EVENT_STR(event, value);
633       break;
634 
635    case bEventRestoreObject:
636       /* Restore Object handle - a plugin configuration for restore and user supplied parameters */
637       if (!value){
638          DMSG0(ctx, DINFO, "End restore objects.\n");
639          break;
640       }
641       DMSG_EVENT_PTR(event, value);
642       return parse_plugin_restoreobj(ctx, (restore_object_pkt *) value);
643 
644    default:
645       // enabled only for Debug
646       DMSG2(ctx, D2, "Unknown event: %s (%d) \n", eventtype2str(event), event->eventType);
647    }
648 
649    return bRC_OK;
650 }
651 
652 /*
653  * Reads a data from command tool on backup.
654  *
655  * in:
656  *    bpContext - for Bacula debug and jobinfo messages
657  *    io - Bacula Plugin API I/O structure for I/O operations
658  * out:
659  *    bRC_OK - when successful
660  *    bRC_Error - on any error
661  */
perform_read_data(bpContext * ctx,struct io_pkt * io)662 bRC DOCKER::perform_read_data(bpContext *ctx, struct io_pkt *io)
663 {
664    int rc;
665 
666    if (dkcommctx->is_eod()){
667       /* TODO: we signal EOD as rc=0, so no need to explicity check for EOD, right? */
668       io->status = 0;
669    } else {
670       rc = dkcommctx->read_data(ctx, io->buf, io->count);
671       io->status = rc;
672       if (rc < 0){
673          io->io_errno = EIO;
674          return bRC_Error;
675       }
676    }
677    return bRC_OK;
678 }
679 
680 /*
681  * Reads a data from command tool on backup.
682  *
683  * in:
684  *    bpContext - for Bacula debug and jobinfo messages
685  *    io - Bacula Plugin API I/O structure for I/O operations
686  * out:
687  *    bRC_OK - when successful
688  *    bRC_Error - on any error
689  */
perform_read_volume_data(bpContext * ctx,struct io_pkt * io)690 bRC DOCKER::perform_read_volume_data(bpContext *ctx, struct io_pkt *io)
691 {
692    io->status = read(dkfd, io->buf, io->count);
693    if (io->status < 0){
694       io->io_errno = errno;
695       return bRC_Error;
696    }
697    return bRC_OK;
698 }
699 
700 /*
701  * Writes data to command tool on restore.
702  *
703  * in:
704  *    bpContext - for Bacula debug and jobinfo messages
705  *    io - Bacula Plugin API I/O structure for I/O operations
706  * out:
707  *    bRC_OK - when successful
708  *    bRC_Error - on any error
709  */
perform_write_data(bpContext * ctx,struct io_pkt * io)710 bRC DOCKER::perform_write_data(bpContext *ctx, struct io_pkt *io)
711 {
712    int rc = 0;
713 
714    if (dkfd){
715       rc = write(dkfd, io->buf, io->count);
716    } else {
717       rc = dkcommctx->write_data(ctx, io->buf, io->count);
718    }
719    io->status = rc;
720    if (rc < 0){
721       io->io_errno = EIO;
722       return bRC_Error;
723    }
724    return bRC_OK;
725 }
726 
727 /*
728  * Execute a backup command.
729  *
730  * in:
731  *    bpContext - for Bacula debug and jobinfo messages
732  *    io - Bacula Plugin API I/O structure for I/O operations
733  * out:
734  *    bRC_OK - when successful
735  *    bRC_Error - on any error
736  *    io->status, io->io_errno - set to error on any error
737  */
perform_backup_open(bpContext * ctx,struct io_pkt * io)738 bRC DOCKER::perform_backup_open(bpContext *ctx, struct io_pkt *io)
739 {
740    POOL_MEM wname(PM_FNAME);
741    struct stat statp;
742    btimer_t *timer;
743 
744    DMSG1(ctx, DDEBUG, "perform_backup_open called: %s\n", io->fname);
745    /* prepare backup for DOCKER_VOLUME */
746    if (currdkinfo->type() == DOCKER_VOLUME){
747       if (dkcommctx->prepare_working_volume(ctx, JobId) != bRC_OK){
748          io->status = -1;
749          io->io_errno = EIO;
750          return bRC_Error;
751       }
752       dkcommctx->render_working_volume_filename(wname, BACULACONTAINERFOUT);
753       if (stat(wname.c_str(), &statp) != 0){
754          berrno be;
755          /* if the path does not exist then create one */
756          if (be.code() != ENOENT || mkfifo(wname.c_str(), 0600) != 0){
757             /* error creating named pipe */
758             berrno be;
759             io->status = -1;
760             io->io_errno = be.code();
761             dkcommctx->set_error();
762             DMSG2(ctx, DERROR, "cannot create file: %s Err=%s\n", wname.c_str(), be.bstrerror());
763             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
764                   "Cannot create file: %s Err=%s\n", wname.c_str(), be.bstrerror());
765             return bRC_Error;
766          }
767       } else {
768          /* check if it is a proper file */
769          if (!S_ISFIFO(statp.st_mode)){
770             /* not fifo, not good */
771             DMSG2(ctx, DERROR, "file is not fifo: %s [%o]\n", wname.c_str(), statp.st_mode);
772             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
773                   "Improper file type: %s [%o]\n", wname.c_str(), statp.st_mode);
774             return bRC_Error;
775          }
776       }
777    }
778 
779    /* execute backup docker */
780    if (dkcommctx->backup_docker(ctx, currdkinfo, JobId) != bRC_OK){
781       io->status = -1;
782       io->io_errno = EIO;
783       if (dkcommctx->is_abort_on_error()){
784          /* abort_on_error set, so terminate other backup for other container */
785          dkcommctx->finish_backup_list(ctx);
786       }
787       return bRC_Error;
788    }
789 
790    /* finish preparation for DOCKER_VOLUME */
791    if (currdkinfo->type() == DOCKER_VOLUME){
792       timer = start_thread_timer(NULL, pthread_self(), dkcommctx->timeout());
793       dkfd = open(wname.c_str(), O_RDONLY);
794       stop_thread_timer(timer);
795       if (dkfd < 0){
796          /* error opening file to read */
797          berrno be;
798          io->status = -1;
799          io->io_errno = be.code();
800          dkcommctx->set_error();
801          DMSG2(ctx, DERROR, "cannot open archive file: %s Err=%s\n", wname.c_str(), be.bstrerror());
802          JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
803                "Cannot open archive file: %s Err=%s\n", wname.c_str(), be.bstrerror());
804          return bRC_Error;
805       }
806       mode = DOCKER_BACKUP_VOLUME_FULL;
807    }
808 
809    dkcommctx->clear_eod();
810 
811    return bRC_OK;
812 }
813 
814 /*
815  * Perform a restore file creation and open when restore to local server or
816  *  restore command execution when restore to Docker.
817  *
818  * in:
819  *    bpContext - for Bacula debug and jobinfo messages
820  *    io - Bacula Plugin API I/O structure for I/O operations
821  * out:
822  *    bRC_OK - when successful
823  *    bRC_Error - on any error
824  *    io->status, io->io_errno - set to error on any error
825  */
perform_restore_open(bpContext * ctx,io_pkt * io)826 bRC DOCKER::perform_restore_open(bpContext* ctx, io_pkt* io)
827 {
828    POOL_MEM wname(PM_FNAME);
829    int status;
830    btimer_t *timer;
831 
832    /* first local restore as a simpler case */
833    if (local_restore){
834       /* restore local */
835       dkfd = open(fname, O_CREAT|O_WRONLY, 0640);
836       if (dkfd < 0){
837          /* error opening file to write */
838          io->status = -1;
839          io->io_errno = errno;
840          return bRC_Error;
841       }
842    } else {
843       /* prepare restore for DOCKER_VOLUME */
844       if (restoredkinfo->type() == DOCKER_VOLUME){
845          if (dkcommctx->prepare_working_volume(ctx, JobId) != bRC_OK){
846             io->status = -1;
847             io->io_errno = EIO;
848             return bRC_Error;
849          }
850          dkcommctx->render_working_volume_filename(wname, BACULACONTAINERFIN);
851          status = mkfifo(wname.c_str(), 0600);
852          if (status < 0){
853             /* error creating named pipe */
854             berrno be;
855             io->status = -1;
856             io->io_errno = be.code();
857             dkcommctx->set_error();
858             DMSG2(ctx, DERROR, "cannot create file: %s Err=%s\n", wname.c_str(), be.bstrerror());
859             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
860                   "Cannot create file: %s Err=%s\n", wname.c_str(), be.bstrerror());
861             return bRC_Error;
862          }
863       }
864 
865       /* execute backup docker */
866       if (dkcommctx->restore_docker(ctx, restoredkinfo, JobId) != bRC_OK){
867          io->status = -1;
868          io->io_errno = EIO;
869          return bRC_Error;
870       }
871 
872       /* finish preparation for DOCKER_VOLUME */
873       if (restoredkinfo->type() == DOCKER_VOLUME){
874          timer = start_thread_timer(NULL, pthread_self(), dkcommctx->timeout());
875          dkfd = open(wname.c_str(), O_WRONLY);
876          stop_thread_timer(timer);
877          if (dkfd < 0){
878             /* error opening file to write */
879             berrno be;
880             io->status = -1;
881             io->io_errno = be.code();
882             dkcommctx->set_error();
883             DMSG2(ctx, DERROR, "cannot open archive file: %s Err=%s\n", wname.c_str(), be.bstrerror());
884             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
885                   "Cannot open archive file: %s Err=%s\n", wname.c_str(), be.bstrerror());
886             return bRC_Error;
887          }
888          mode = DOCKER_RESTORE_VOLUME;
889       }
890 
891       dkcommctx->clear_eod();
892    }
893 
894    return bRC_OK;
895 }
896 
897 /*
898  * Perform command tool termination when backup finish.
899  *
900  * in:
901  *    bpContext - for Bacula debug and jobinfo messages
902  *    io - Bacula Plugin API I/O structure for I/O operations
903  * out:
904  *    bRC_OK - when successful
905  *    bRC_Error - on any error
906  */
perform_backup_close(bpContext * ctx,struct io_pkt * io)907 bRC DOCKER::perform_backup_close(bpContext *ctx, struct io_pkt *io)
908 {
909    bRC status = bRC_OK;
910 
911    dkcommctx->terminate(ctx);
912    if (currdkinfo->type() == DOCKER_VOLUME){
913       if (close(dkfd) < 0){
914          io->status = -1;
915          io->io_errno = errno;
916          status = bRC_Error;
917       }
918       mode = DOCKER_BACKUP_FULL;
919       errortar = check_container_tar_error(ctx, currdkinfo->get_volume_name());
920    }
921    return status;
922 }
923 
924 /*
925  * Perform a restore file close when restore to local server or wait for restore
926  *  command finish execution when restore to Docker.
927  *
928  * in:
929  *    bpContext - for Bacula debug and jobinfo messages
930  *    io - Bacula Plugin API I/O structure for I/O operations
931  * out:
932  *    bRC_OK - when successful
933  *    bRC_Error - on any error
934  */
perform_restore_close(bpContext * ctx,struct io_pkt * io)935 bRC DOCKER::perform_restore_close(bpContext *ctx, struct io_pkt *io)
936 {
937    bRC status = bRC_OK;
938    DKID dkid;
939    POOL_MEM buf(PM_NAME);
940    POOL_MEM names(PM_NAME);
941 
942    /* both local_restore and volume restore uses dkfd */
943    if (dkfd > 0){
944       if (close(dkfd) < 0){
945          io->status = -1;
946          io->io_errno = errno;
947          status = bRC_Error;
948       }
949       dkfd = 0;
950       if (mode == DOCKER_RESTORE_VOLUME && restoredkinfo && restoredkinfo->type() == DOCKER_VOLUME){
951          mode = DOCKER_RESTORE;
952          errortar = check_container_tar_error(ctx, restoredkinfo->get_volume_name());
953       }
954    } else {
955       status = dkcommctx->wait_for_restore(ctx, dkid);
956       if (status != bRC_OK){
957          io->status = -1;
958          io->io_errno = EIO;
959       } else {
960          switch (restoredkinfo->type()){
961             case DOCKER_IMAGE:
962                /* when restore image then rename it only */
963                status = dkcommctx->docker_tag(ctx, dkid, restoredkinfo->get_image_repository_tag());
964                break;
965             case DOCKER_CONTAINER:
966                /* on container image we need to create a container itself, first tag the restored image */
967                Mmsg(buf, "%s/%s/%d:restore", restoredkinfo->name(), restoredkinfo->id()->digest_short(), JobId);
968                status = dkcommctx->docker_tag(ctx, dkid, buf.c_str());
969                if (status != bRC_OK){
970                   DMSG1(ctx, DERROR, "perform_restore_close cannot tag restored image: %s\n", buf.c_str());
971                   JMSG1(ctx, M_ERROR, "perform_restore_close cannot tag restored image: %s\n", buf.c_str());
972                   break;
973                }
974                /* update image information on restoring container */
975                restoredkinfo->set_container_imagesave(dkid);
976                restoredkinfo->set_container_imagesave_tag(buf);
977                /* update a container name */
978                pm_strcpy(names, restoredkinfo->get_container_names());
979                Mmsg(buf, "%s_%d", names.c_str(), JobId);
980                restoredkinfo->set_container_names(buf);
981                status = dkcommctx->docker_create_run_container(ctx, restoredkinfo);
982                if (status != bRC_OK){
983                   DMSG1(ctx, DERROR, "perform_restore_close cannot create container: %s\n",
984                         restoredkinfo->get_container_names());
985                   JMSG1(ctx, M_ERROR, "perform_restore_close cannot create container: %s\n",
986                         restoredkinfo->get_container_names());
987                   break;
988                }
989                break;
990             case DOCKER_VOLUME:
991                /* XXX */
992                break;
993          }
994       }
995    }
996    return status;
997 }
998 
999 /*
1000  * This is to check how Bacula archive container finish its job.
1001  * We are doing this by examining docker.err file contents.
1002  *
1003  * in:
1004  *    bpContext - for Bacula debug and jobinfo messages
1005  * out:
1006  *    false - when no errors found
1007  *    true - errors found and reported to user
1008  */
check_container_tar_error(bpContext * ctx,char * volname)1009 bool DOCKER::check_container_tar_error(bpContext* ctx, char *volname)
1010 {
1011    struct stat statp;
1012    POOL_MEM flog(PM_FNAME);
1013    int rc;
1014 
1015    if (dockerworkclear == 0){
1016       dockerworkclear = 1;
1017    }
1018    dkcommctx->render_working_volume_filename(flog, BACULACONTAINERERRLOG);
1019    if (stat(flog.c_str(), &statp) == 0){
1020       if (statp.st_size > 0){
1021          /* the error file has some content, so archive command was unsuccessful, report it */
1022          POOL_MEM errlog(PM_MESSAGE);
1023          int fd;
1024          char *p;
1025 
1026          fd = open(flog.c_str(), O_RDONLY);
1027          if (fd < 0){
1028             /* error opening errorlog, strange */
1029             berrno be;
1030             DMSG2(ctx, DERROR, "error opening archive errorlog file: %s Err=%s\n",
1031                   flog.c_str(), be.bstrerror());
1032             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
1033                      "Error opening archive errorlog file: %s Err=%s\n", flog.c_str(), be.bstrerror());
1034             return true;
1035          }
1036          rc = read(fd, errlog.c_str(), errlog.size() - 1);
1037          close(fd);
1038          if (rc < 0){
1039             /* we should read some data, right? */
1040             berrno be;
1041             DMSG2(ctx, DERROR, "error reading archive errorlog file: %s Err=%s\n",
1042                   flog.c_str(), be.bstrerror());
1043             JMSG2(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
1044                   "Error reading archive errorlog file: %s Err=%s\n", flog.c_str(), be.bstrerror());
1045             return true;
1046          }
1047          /* clear last newline */
1048          p = errlog.c_str();
1049          if (p[rc-1] == '\n')
1050             p[rc-1] = 0;
1051          /* display error to user */
1052          DMSG1(ctx, DERROR, "errorlog: %s\n", errlog.c_str());
1053          JMSG1(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
1054                "Archive error: %s\n", errlog.c_str());
1055          /* rename log files for future use */
1056          if (debug_level > 200){
1057             POOL_MEM nflog(PM_FNAME);
1058             dockerworkclear = 2;
1059             Mmsg(nflog, "%s.%s", flog.c_str(), volname);
1060             rc = rename(flog.c_str(), nflog.c_str());
1061             if (rc < 0){
1062                /* error renaming, report */
1063                berrno be;
1064                DMSG2(ctx, DERROR, "error renaming archive errorlog to: %s Err=%s\n",
1065                      nflog.c_str(), be.bstrerror());
1066                JMSG2(ctx, M_ERROR,
1067                      "Error renaming archive errorlog file to: %s Err=%s\n", nflog.c_str(), be.bstrerror());
1068             }
1069             dkcommctx->render_working_volume_filename(flog, BACULACONTAINERARCHLOG);
1070             Mmsg(nflog, "%s.%s", flog.c_str(), volname);
1071             rc = rename(flog.c_str(), nflog.c_str());
1072             if (rc < 0){
1073                /* error renaming, report */
1074                berrno be;
1075                DMSG2(ctx, DERROR, "error renaming archive log to: %s Err=%s\n",
1076                      nflog.c_str(), be.bstrerror());
1077                JMSG2(ctx, M_ERROR,
1078                      "Error renaming archive log file to: %s Err=%s\n", nflog.c_str(), be.bstrerror());
1079             }
1080          }
1081          return true;
1082       }
1083    } else {
1084       /* error access to BACULACONTAINERERRLOG, strange, report it */
1085       berrno be;
1086       DMSG2(ctx, DERROR, "error access archive errorlog file: %s Err=%s\n", flog.c_str(), be.bstrerror());
1087       JMSG2(ctx, M_ERROR, "Error access archive errorlog file: %s Err=%s\n", flog.c_str(), be.bstrerror());
1088    }
1089 
1090    return false;
1091 };
1092 
1093 /*
1094  * Handle Bacula Plugin I/O API for backend
1095  *
1096  * in:
1097  *    bpContext - for Bacula debug and jobinfo messages
1098  *    io - Bacula Plugin API I/O structure for I/O operations
1099  * out:
1100  *    bRC_OK - when successful
1101  *    bRC_Error - on any error
1102  *    io->status, io->io_errno - correspond to a plugin io operation status
1103  */
pluginIO(bpContext * ctx,struct io_pkt * io)1104 bRC DOCKER::pluginIO(bpContext *ctx, struct io_pkt *io)
1105 {
1106    static int rw = 0;      // this variable handles single debug message
1107 
1108    /* assume no error from the very beginning */
1109    io->status = 0;
1110    io->io_errno = 0;
1111    switch (io->func) {
1112       case IO_OPEN:
1113          DMSG(ctx, D2, "IO_OPEN: (%s)\n", io->fname);
1114          switch (mode){
1115             case DOCKER_BACKUP_FULL:
1116             case DOCKER_BACKUP_INCR:
1117             case DOCKER_BACKUP_DIFF:
1118             case DOCKER_BACKUP_VOLUME_FULL:
1119                return perform_backup_open(ctx, io);
1120             case DOCKER_RESTORE:
1121             case DOCKER_RESTORE_VOLUME:
1122                return perform_restore_open(ctx, io);
1123             default:
1124                return bRC_Error;
1125          }
1126          break;
1127       case IO_READ:
1128          if (!rw) {
1129             rw = 1;
1130             DMSG2(ctx, D2, "IO_READ buf=%p len=%d\n", io->buf, io->count);
1131          }
1132          switch (mode){
1133             case DOCKER_BACKUP_FULL:
1134             case DOCKER_BACKUP_INCR:
1135             case DOCKER_BACKUP_DIFF:
1136                return perform_read_data(ctx, io);
1137             case DOCKER_BACKUP_VOLUME_FULL:
1138                return perform_read_volume_data(ctx, io);
1139             default:
1140                return bRC_Error;
1141          }
1142          break;
1143       case IO_WRITE:
1144          if (!rw) {
1145             rw = 1;
1146             DMSG2(ctx, D2, "IO_WRITE buf=%p len=%d\n", io->buf, io->count);
1147          }
1148          switch (mode){
1149             case DOCKER_RESTORE:
1150             case DOCKER_RESTORE_VOLUME:
1151                return perform_write_data(ctx, io);
1152             default:
1153                return bRC_Error;
1154          }
1155          break;
1156       case IO_CLOSE:
1157          DMSG0(ctx, D2, "IO_CLOSE\n");
1158          rw = 0;
1159          switch (mode){
1160             case DOCKER_RESTORE:
1161             case DOCKER_RESTORE_VOLUME:
1162                return perform_restore_close(ctx, io);
1163             case DOCKER_BACKUP_FULL:
1164             case DOCKER_BACKUP_VOLUME_FULL:
1165             case DOCKER_BACKUP_INCR:
1166             case DOCKER_BACKUP_DIFF:
1167                return perform_backup_close(ctx, io);
1168             default:
1169                return bRC_Error;
1170          }
1171          break;
1172    }
1173 
1174    return bRC_OK;
1175 }
1176 
1177 /*
1178  * Unimplemented, always return bRC_OK.
1179  */
getPluginValue(bpContext * ctx,pVariable var,void * value)1180 bRC DOCKER::getPluginValue(bpContext *ctx, pVariable var, void *value)
1181 {
1182    return bRC_OK;
1183 }
1184 
1185 /*
1186  * Unimplemented, always return bRC_OK.
1187  */
setPluginValue(bpContext * ctx,pVariable var,void * value)1188 bRC DOCKER::setPluginValue(bpContext *ctx, pVariable var, void *value)
1189 {
1190    return bRC_OK;
1191 }
1192 
1193 /*
1194  * Get all required information from Docker to populate save_pkt for Bacula.
1195  *  It handles a Restore Object (FT_PLUGIN_CONFIG) for every backup and
1196  *  new Plugin Backup Command if setup in FileSet. It handles
1197  *  backup/estimate/listing modes of operation.
1198  *
1199  * in:
1200  *    bpContext - for Bacula debug and jobinfo messages
1201  *    save_pkt - Bacula Plugin API save packet structure
1202  * out:
1203  *    bRC_OK - when save_pkt prepared successfully and we have file to backup
1204  *    bRC_Max - when no more files to backup
1205  *    bRC_Error - in any error
1206  */
startBackupFile(bpContext * ctx,struct save_pkt * sp)1207 bRC DOCKER::startBackupFile(bpContext *ctx, struct save_pkt *sp)
1208 {
1209    /* handle listing mode if requested */
1210    if (estimate && listing_mode == DOCKER_LISTING_TOP){
1211       sp->fname = (char*)docker_objects[listing_objnr++].name;
1212       sp->type = FT_DIREND;
1213       sp->statp.st_size = 0;
1214       sp->statp.st_nlink = 1;
1215       sp->statp.st_uid = 0;
1216       sp->statp.st_gid = 0;
1217       sp->statp.st_mode = 040750;
1218       sp->statp.st_blksize = 4096;
1219       sp->statp.st_blocks = 1;
1220       sp->statp.st_atime = sp->statp.st_mtime = sp->statp.st_ctime = time(NULL);
1221       return bRC_OK;
1222    }
1223 
1224    /* The first file in Full backup, is the RestoreObject */
1225    if (!estimate && mode == DOCKER_BACKUP_FULL && robjsent == false) {
1226       ConfigFile ini;
1227 
1228       /* robj for the first time, allocate the buffer */
1229       if (!robjbuf){
1230          robjbuf = get_pool_memory(PM_FNAME);
1231       }
1232 
1233       ini.register_items(plugin_items_dump, sizeof(struct ini_items));
1234       sp->object_name = (char *)INI_RESTORE_OBJECT_NAME;
1235       sp->object_len = ini.serialize(&robjbuf);
1236       sp->object = robjbuf;
1237       sp->type = FT_PLUGIN_CONFIG;
1238       DMSG0(ctx, DINFO, "Prepared RestoreObject sent.\n");
1239       return bRC_OK;
1240    }
1241 
1242    /* check for forced backup finish */
1243    if (backup_finish){
1244       DMSG0(ctx, DINFO, "forced backup finish!\n");
1245       backup_finish = false;
1246       return bRC_Max;
1247    }
1248 
1249    /* check if this is the first container to backup/estimate/listing */
1250    if (currdkinfo == NULL){
1251       /* set all_to_backup list at first element */
1252       currdkinfo = dkcommctx->get_first_to_backup(ctx);
1253       if (!currdkinfo){
1254          /* no docker objects to backup at all */
1255          DMSG0(ctx, DDEBUG, "No Docker containers or objects to backup found.\n");
1256          JMSG0(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
1257                "No Docker containers or objects to backup found.\n");
1258          return bRC_Max;
1259       }
1260    }
1261 
1262    /* in currdkinfo we have all info about docker object to backup */
1263    if (!estimate && mode != DOCKER_BACKUP_CONTAINER_VOLLIST){
1264       if (currdkinfo->type() != DOCKER_VOLUME){
1265          DMSG3(ctx, DINFO, "Start Backup %s: %s (%s)\n",
1266                currdkinfo->type_str(), currdkinfo->name(), currdkinfo->id()->digest_short());
1267          JMSG3(ctx, M_INFO, "Start Backup %s: %s (%s)\n",
1268                currdkinfo->type_str(), currdkinfo->name(), currdkinfo->id()->digest_short());
1269       } else {
1270          DMSG2(ctx, DINFO, "Start Backup %s: %s\n",
1271                currdkinfo->type_str(), currdkinfo->name());
1272          JMSG2(ctx, M_INFO, "Start Backup %s: %s\n",
1273                currdkinfo->type_str(), currdkinfo->name());
1274       }
1275    }
1276 
1277    /* generate the filename in backup/estimate */
1278    if (!fname){
1279       fname = get_pool_memory(PM_FNAME);
1280    }
1281    if (!lname){
1282       lname = get_pool_memory(PM_FNAME);
1283    }
1284 
1285    /* populate common statp */
1286    sp->statp.st_nlink = 1;
1287    sp->statp.st_uid = 0;
1288    sp->statp.st_gid = 0;
1289    sp->portable = true;
1290    sp->statp.st_blksize = 4096;
1291    // TODO: use created time of image and volume objects
1292    sp->statp.st_atime = sp->statp.st_mtime = sp->statp.st_ctime = time(NULL);
1293    sp->statp.st_mode = S_IFREG | 0640;     // standard file with '-rw-r----' permissions
1294 
1295    if (mode == DOCKER_BACKUP_CONTAINER_VOLLIST && currvols){
1296       sp->statp.st_size = currvols->vol->size();
1297       sp->statp.st_blocks = sp->statp.st_size / 4096 + 1;
1298       sp->type = FT_LNK;
1299       if (!estimate){
1300          Mmsg(fname, "%s%s/%s/volume: %s -> %s", PLUGINNAMESPACE, CONTAINERNAMESPACE,
1301                currdkinfo->name(), currvols->vol->get_volume_name(), currvols->destination);
1302          *lname = 0;
1303       } else {
1304          Mmsg(fname, "%s%s/%s/volume: %s", PLUGINNAMESPACE, CONTAINERNAMESPACE,
1305                currdkinfo->name(), currvols->vol->get_volume_name());
1306          lname = currvols->destination;
1307       }
1308       sp->link = lname;
1309       sp->statp.st_mode = S_IFLNK | 0640;
1310    } else {
1311       sp->statp.st_size = currdkinfo->size();
1312       sp->statp.st_blocks = sp->statp.st_size / 4096 + 1;
1313       sp->type = FT_REG;               // exported archive is a standard file
1314 
1315       switch(listing_mode){
1316          case DOCKER_LISTING_NONE:
1317             /* generate a backup/estimate filename */
1318             switch (currdkinfo->type()){
1319                case DOCKER_CONTAINER:
1320                   Mmsg(fname, "%s%s/%s/%s.tar", PLUGINNAMESPACE, CONTAINERNAMESPACE,
1321                         currdkinfo->name(), (char*)currdkinfo->id());
1322                   break;
1323                case DOCKER_IMAGE:
1324                   Mmsg(fname, "%s%s/%s/%s.tar", PLUGINNAMESPACE, IMAGENAMESPACE,
1325                         currdkinfo->name(), (char*)currdkinfo->id());
1326                   break;
1327                case DOCKER_VOLUME:
1328                   Mmsg(fname, "%s%s/%s.tar", PLUGINNAMESPACE, VOLUMENAMESPACE,
1329                         currdkinfo->name());
1330                   break;
1331                default:
1332                   DMSG1(ctx, DERROR, "unknown object type to backup: %s\n", currdkinfo->type_str());
1333                   JMSG1(ctx, M_ERROR, "Unknown object type to backup: %s\n", currdkinfo->type_str());
1334                   return bRC_Error;
1335             }
1336             break;
1337          case DOCKER_LISTING_VOLUME:
1338             sp->statp.st_mode = S_IFBLK | 0640;     // standard block device with 'brw-r----' permissions
1339             Mmsg(fname, "%s", currdkinfo->name());
1340             break;
1341          case DOCKER_LISTING_IMAGE:
1342             sp->statp.st_mode = S_IFBLK | 0640;     // standard block device with 'brw-r----' permissions
1343          case DOCKER_LISTING_CONTAINER:
1344             Mmsg(lname, "%s", param_notrunc?(char*)currdkinfo->id():currdkinfo->id()->digest_short());
1345             Mmsg(fname, "%s", currdkinfo->name());
1346             sp->link = lname;
1347             sp->type = FT_LNK;
1348             break;
1349          default:
1350             /* error */
1351             break;
1352       }
1353    }
1354 
1355    /* populate rest of statp */
1356    sp->fname = fname;
1357 
1358    return bRC_OK;
1359 }
1360 
1361 /*
1362  * Finish the Docker backup and clean temporary objects.
1363  *  For estimate/listing modes it handles next object to display.
1364  *
1365  * in:
1366  *    bpContext - for Bacula debug and jobinfo messages
1367  *    save_pkt - Bacula Plugin API save packet structure
1368  * out:
1369  *    bRC_OK - when no more files to backup
1370  *    bRC_More - when Bacula should expect a next file
1371  *    bRC_Error - in any error
1372  */
endBackupFile(bpContext * ctx)1373 bRC DOCKER::endBackupFile(bpContext *ctx)
1374 {
1375    if (!estimate && mode != DOCKER_BACKUP_CONTAINER_VOLLIST){
1376       /* If the current file was the restore object, so just ask for the next file */
1377       if (mode == DOCKER_BACKUP_FULL && robjsent == false) {
1378          robjsent = true;
1379          return bRC_More;
1380       }
1381       switch (currdkinfo->type()){
1382          case DOCKER_CONTAINER:
1383             /* delete backup commit image */
1384             if (dkcommctx->delete_container_commit(ctx, currdkinfo, JobId) != bRC_OK){
1385                /* TODO: report problem to the user but not abort backup */
1386                return bRC_Error;
1387             }
1388          case DOCKER_IMAGE:
1389             DMSG4(ctx, DINFO, "Backup of %s: %s (%s) %s.\n", currdkinfo->type_str(), currdkinfo->name(),
1390                   currdkinfo->id()->digest_short(), dkcommctx->is_error() ? "Failed" : "OK");
1391             JMSG4(ctx, M_INFO, "Backup of %s: %s (%s) %s.\n", currdkinfo->type_str(), currdkinfo->name(),
1392                   currdkinfo->id()->digest_short(), dkcommctx->is_error() ? "Failed" : "OK");
1393             break;
1394          case DOCKER_VOLUME:
1395             /* check */
1396             DMSG3(ctx, DINFO, "Backup of %s: %s %s.\n", currdkinfo->type_str(), currdkinfo->name(),
1397                   dkcommctx->is_error() || errortar ? "Failed" : "OK");
1398             JMSG3(ctx, M_INFO, "Backup of %s: %s %s.\n", currdkinfo->type_str(), currdkinfo->name(),
1399                   dkcommctx->is_error() || errortar ? "Failed" : "OK");
1400             break;
1401       };
1402    }
1403 
1404    /* handle listing and next file to backup */
1405    if (listing_mode == DOCKER_LISTING_TOP){
1406       /* handle top-level listing mode */
1407       if (docker_objects[listing_objnr].name){
1408          /* next object available */
1409          return bRC_More;
1410       }
1411    } else {
1412       /* check if container we just backup has any vols mounted */
1413       if (currdkinfo->type() == DOCKER_CONTAINER && !currvols && currdkinfo->container_has_vols() &&
1414             mode != DOCKER_BACKUP_CONTAINER_VOLLIST){
1415          /* yes, so prepare the flow for symbolic link backup */
1416          currvols = currdkinfo->container_first_vols();
1417          mode = DOCKER_BACKUP_CONTAINER_VOLLIST;
1418          DMSG0(ctx, DDEBUG, "docker vols to backup found\n");
1419          return bRC_More;
1420       }
1421       /* check if we already in symbolic link backup mode */
1422       if (mode == DOCKER_BACKUP_CONTAINER_VOLLIST && currvols){
1423          /* yes, so check for next symbolic link to backup */
1424          currvols = currdkinfo->container_next_vols();
1425          if (currvols){
1426             DMSG0(ctx, DDEBUG, "docker next vols to backup found\n");
1427             return bRC_More;
1428          } else {
1429             /* it was the last symbolic link, so finish this mode */
1430             mode = DOCKER_BACKUP_FULL;
1431             currvols = NULL;
1432          }
1433       }
1434       /* check if next object to backup/estimate/listing */
1435       currdkinfo = dkcommctx->get_next_to_backup(ctx);
1436       if (currdkinfo){
1437          DMSG0(ctx, DDEBUG, "next docker object to backup found\n");
1438          return bRC_More;
1439       }
1440    }
1441 
1442    return bRC_OK;
1443 }
1444 
1445 /*
1446  * Start Restore File.
1447  */
startRestoreFile(bpContext * ctx,const char * cmd)1448 bRC DOCKER::startRestoreFile(bpContext *ctx, const char *cmd)
1449 {
1450    return bRC_OK;
1451 }
1452 
1453 /*
1454  * End Restore File.
1455  *    Handles the next vm state.
1456  */
endRestoreFile(bpContext * ctx)1457 bRC DOCKER::endRestoreFile(bpContext *ctx)
1458 {
1459    /* release restore dkinfo */
1460    if (restoredkinfo){
1461       delete restoredkinfo;
1462       restoredkinfo = NULL;
1463    }
1464    return bRC_OK;
1465 }
1466 
1467 /*
1468  * Search in Docker all available images if image we are restoring already exist.
1469  *
1470  * in:
1471  *    bpContext - bacula plugin context
1472  *    this->restoredkinfo - current image to restore
1473  * out:
1474  *    *DKINFO from Docker all_images if image to restore found
1475  *    NULL when not found
1476  */
search_docker_image(bpContext * ctx)1477 DKINFO *DOCKER::search_docker_image(bpContext *ctx)
1478 {
1479    alist *allimages;
1480    DKINFO *image = NULL;
1481 
1482    allimages = dkcommctx->get_all_images(ctx);
1483    if (allimages){
1484       DMSG1(ctx, DDEBUG, "search allimages for: %s\n", (char*)restoredkinfo->get_image_id());
1485       /* check if image which we are restoring exist on Docker already */
1486       foreach_alist(image, allimages){
1487          DMSG1(ctx, DDEBUG, "compare: %s\n", (char*)image->get_image_id());
1488          if (image && *image->get_image_id() == *restoredkinfo->get_image_id()){
1489             DMSG0(ctx, DINFO, "image to restore found available\n");
1490             break;
1491          }
1492       };
1493    }
1494    return image;
1495 };
1496 
1497 /*
1498  * Search in Docker all available volumes if volume we are restoring already exist.
1499  *
1500  * in:
1501  *    bpContext - bacula plugin context
1502  *    this->restoredkinfo - current volume to restore
1503  * out:
1504  *    *DKINFO from Docker all_volumes if volume to restore found
1505  *    NULL when not found
1506  */
search_docker_volume(bpContext * ctx)1507 DKINFO *DOCKER::search_docker_volume(bpContext *ctx)
1508 {
1509    alist *allvolumes;
1510    DKINFO *volume = NULL;
1511 
1512    allvolumes = dkcommctx->get_all_volumes(ctx);
1513    if (allvolumes){
1514       DMSG1(ctx, DDEBUG, "search allvolumes for: %s\n", restoredkinfo->get_volume_name());
1515       /* check if image which we are restoring exist on Docker already */
1516       foreach_alist(volume, allvolumes){
1517          DMSG1(ctx, DDEBUG, "compare: %s\n", volume->get_volume_name());
1518          if (volume && bstrcmp(volume->get_volume_name(), restoredkinfo->get_volume_name())){
1519             DMSG0(ctx, DINFO, "volume to restore found available\n");
1520             break;
1521          }
1522       };
1523    }
1524    return volume;
1525 };
1526 
1527 /*
1528  * When restore to local server then handle restored file creation else
1529  *  inform user about starting a restore.
1530  *
1531  * in:
1532  *    bpContext - bacula plugin context
1533  *    restore_pkt - Bacula Plugin API restore packet structure
1534  * out:
1535  *    bRC_OK - when success reported from backend
1536  *    rp->create_status = CF_EXTRACT - the backend will restore the file
1537  *                                     with pleasure
1538  *    rp->create_status = CF_SKIP - the backend wants to skip restoration, i.e.
1539  *                                  the file already exist and Replace=n was set
1540  *    bRC_Error, rp->create_status = CF_ERROR - in any error
1541  */
createFile(bpContext * ctx,struct restore_pkt * rp)1542 bRC DOCKER::createFile(bpContext *ctx, struct restore_pkt *rp)
1543 {
1544    POOL_MEM fmt(PM_FNAME);
1545    POOL_MEM fmt2(PM_FNAME);
1546    POOL_MEM imageid(PM_FNAME);
1547    POOL_MEM label(PM_FNAME);
1548    struct stat statp;
1549    char *dir, *p;
1550    int len;
1551    int status;
1552    DKINFO *image;
1553 
1554    /* skip a support volume file link */
1555    if (rp->type == FT_LNK && S_ISLNK(rp->statp.st_mode)){
1556       DMSG1(ctx, DDEBUG, "skipping support file: %s\n", rp->ofname);
1557       rp->create_status = CF_SKIP;
1558    } else {
1559       /* it seems something to restore */
1560       if (!fname){
1561          fname = get_pool_memory(PM_FNAME);
1562       }
1563       /* where=/ then we'll restore to Docker else we'll restore local */
1564       if (where && strlen(where) > 1 && *where == PathSeparator){
1565          local_restore = true;
1566          len = strlen(where);
1567          DMSG(ctx, DINFO, "local restore to: %s\n", where);
1568          pm_strcpy(fmt, rp->ofname);
1569          dir = strrchr(fmt.c_str(), '.');
1570          if (dir && bstrcmp(dir, ".tar")){
1571             *dir = 0;
1572             JMSG(ctx, M_INFO, "Docker local restore: %s\n", fmt.c_str() + len + strlen(PLUGINNAMESPACE) + 1);
1573          }
1574          /* compose a destination fname */
1575          pm_strcpy(fname, where);
1576          pm_strcat(fname, rp->ofname + len + strlen(PLUGINNAMESPACE));
1577          DMSG(ctx, DDEBUG, "composed fname: %s\n", fname);
1578          /* prepare a destination directory */
1579          pm_strcpy(fmt, fname);
1580          dir = dirname(fmt.c_str());
1581          if (!dir){
1582             berrno be;
1583             DMSG2(ctx, DERROR, "dirname error for %s Err=%s\n", fmt.c_str(), be.bstrerror());
1584             JMSG2(ctx, dkcommctx->is_fatal() ? M_FATAL : M_ERROR, "dirname error for %s Err=%s\n", fmt.c_str(), be.bstrerror());
1585             rp->create_status = CF_ERROR;
1586             return bRC_Error;
1587          }
1588          DMSG(ctx, DDEBUG, "dirname: %s\n", fmt.c_str());
1589          if (pluglib_mkpath(ctx, dir, dkcommctx->is_fatal()) != bRC_OK){
1590             rp->create_status = CF_ERROR;
1591             return bRC_Error;
1592          }
1593          switch (replace){
1594             case REPLACE_ALWAYS:
1595                rp->create_status = CF_EXTRACT;
1596                break;
1597             case REPLACE_NEVER:
1598                /* check if file exist locally */
1599                if (stat(fname, &statp) == 0){
1600                   /* exist, so skip restore */
1601                   rp->create_status = CF_SKIP;
1602                   break;
1603                }
1604                rp->create_status = CF_EXTRACT;
1605                break;
1606             case REPLACE_IFNEWER:
1607                if (stat(fname, &statp) == 0){
1608                   /* exist, so check if newer */
1609                   if (statp.st_mtime < rp->statp.st_mtime){
1610                      rp->create_status = CF_SKIP;
1611                      break;
1612                   }
1613                }
1614                rp->create_status = CF_EXTRACT;
1615                break;
1616             case REPLACE_IFOLDER:
1617                if (stat(fname, &statp) == 0){
1618                   /* exist, so check if newer */
1619                   if (statp.st_mtime > rp->statp.st_mtime){
1620                      rp->create_status = CF_SKIP;
1621                      break;
1622                   }
1623                }
1624                rp->create_status = CF_EXTRACT;
1625                break;
1626          }
1627       } else {
1628          /* TODO: report docker restore start */
1629          local_restore = false;
1630          pm_strcpy(fname, rp->ofname + strlen(PLUGINNAMESPACE));
1631          DMSG(ctx, DINFO, "scanning fname to restore: %s\n", fname);
1632 
1633          /*
1634           * first scan for Container backup file
1635           * the dirtmp variable has a sscanf format to scan which is dynamically generated
1636           * based on the size of label and imageid variables. this limits the size of the scan
1637           * and prevents any memory overflow. the destination scan format is something like this:
1638           * "/container/%256[^/]/%256[^.]", so it will scan two string variables up to
1639           * 256 characters long
1640           */
1641          Mmsg(fmt, "%s/%%%d[^/]/%%%d[^.]", CONTAINERNAMESPACE,
1642                label.size(), imageid.size());
1643          // DMSG(ctx, DVDEBUG, "container scan str: %s\n", dirtmp.c_str());
1644          status = sscanf(fname, fmt.c_str(), label.c_str(), imageid.c_str());
1645          if (status == 2){
1646             /* insanity check for memleak */
1647             if (restoredkinfo != NULL){
1648                delete restoredkinfo;
1649             }
1650             restoredkinfo = New(DKINFO(DOCKER_CONTAINER));
1651             restoredkinfo->set_container_id(imageid);
1652             restoredkinfo->set_container_names(label);
1653             pm_strcpy(fmt, label.c_str());   // Well there is no a pm_strcpy(POOL_MEM&, POOL_MEM&), strange
1654             Mmsg(label, "%s/%s", fmt.c_str(), restoredkinfo->get_container_id()->digest_short());
1655             DMSG2(ctx, DINFO, "scanned: %s %s\n", restoredkinfo->get_container_names(),
1656                   (char*)restoredkinfo->get_container_id());
1657             /* we replace container always? */
1658             rp->create_status = CF_EXTRACT;
1659          } else {
1660             /*
1661              * scan for Volume backup file
1662              * the dirtmp variable has a sscanf format to scan which is dynamically generated
1663              * based on the size of label variable. this limits the size of the scan
1664              * and prevents any memory overflow. the destination scan format is something like this:
1665              * "/volume/%256s", so it will scan a single string variable up to
1666              * 256 characters long
1667              */
1668             Mmsg(fmt, "%s/%%%ds", VOLUMENAMESPACE, label.size());
1669             // DMSG(ctx, DVDEBUG, "volume scan str: %s\n", dirtmp.c_str());
1670             status = sscanf(fname, fmt.c_str(), label.c_str());
1671             if (status == 1){
1672                /* terminate volume name, so fname without '.tar. */
1673                p = strstr(label.c_str(), ".tar");
1674                *p = 0;
1675                /* insanity check for memleak */
1676                if (restoredkinfo != NULL){
1677                   delete restoredkinfo;
1678                }
1679                restoredkinfo = New(DKINFO(DOCKER_VOLUME));
1680                restoredkinfo->set_volume_name(label);
1681                DMSG1(ctx, DINFO, "scanned: %s\n", restoredkinfo->get_volume_name());
1682 
1683                /* check for remote docker operations as this is not supported currently */
1684                if (dkcommctx->is_remote_docker()){
1685                   DMSG1(ctx, DINFO, "volume %s restore with docker_host skipped.\n", restoredkinfo->get_volume_name());
1686                   if (!volumewarning){
1687                      JMSG0(ctx, M_WARNING, "Docker Volume restore with docker_host is unsupported! All volumes restore skipped.\n");
1688                      volumewarning = true;
1689                   }
1690                   rp->create_status = CF_SKIP;
1691                   return bRC_OK;
1692                }
1693 
1694                switch (replace){
1695                   case REPLACE_ALWAYS:
1696                      rp->create_status = CF_EXTRACT;
1697                      break;
1698                   case REPLACE_NEVER:
1699                   case REPLACE_IFNEWER:
1700                   case REPLACE_IFOLDER:
1701                   default:
1702                      /*
1703                       * check if volume exist on docker,
1704                       * as we cannot check if the volume was modified
1705                       * then we will treat it the same as REPLACE_NEVER flag
1706                       */
1707                      if ((image = search_docker_volume(ctx)) != NULL){
1708                         /* exist, so skip restore */
1709                         DMSG1(ctx, DINFO, "volume exist, skipping restore of: %s\n",
1710                               restoredkinfo->get_volume_name());
1711                         JMSG1(ctx, M_INFO, "Volume exist, skipping restore of: %s\n",
1712                               restoredkinfo->get_volume_name());
1713                         rp->create_status = CF_SKIP;
1714                         break;
1715                      }
1716                      rp->create_status = CF_EXTRACT;
1717                      break;
1718                   }
1719             } else {
1720                /* now scan for Image backup */
1721                p = strrchr(fname, '/');
1722                if (p){
1723                   /* found the last (first in reverse) path_separator,
1724                    * so before $p we have a path and after $p we have digest to scan */
1725                   *p++ = 0;
1726                }
1727                /*
1728                 * scan path to separate image repository:tag data from filename
1729                 * the dirtmp and tmp2 variables have a sscanf format to scan which is dynamically
1730                 * generated based on the size of label and imageid variables. this limits the size
1731                 * of the scan and prevents any memory overflow. the destination scan format is
1732                 * something like this:
1733                 * "/image/%256s", for image repository:tag encoded in filename and
1734                 * "%256[^.]", for imageid part of the encoded filename, so it will scan
1735                 * two string variables in two sscanf up to 256 characters long each
1736                 */
1737                Mmsg(fmt, "%s/%%%ds", IMAGENAMESPACE, label.size());
1738                Mmsg(fmt2, "%%%d[^.]", imageid.size());
1739                // DMSG(ctx, DVDEBUG, "image scan str: %s\n", dirtmp.c_str());
1740                if (sscanf(fname, fmt.c_str(), label.c_str()) == 1 &&
1741                      sscanf(p, fmt2.c_str(), imageid.c_str()) == 1){
1742                   /* insanity check for memleak */
1743                   if (restoredkinfo != NULL){
1744                      delete restoredkinfo;
1745                   }
1746                   /* we will restore the Docker Image */
1747                   restoredkinfo = New(DKINFO(DOCKER_IMAGE));
1748                   restoredkinfo->set_image_id(imageid);
1749                   restoredkinfo->scan_image_repository_tag(label);
1750                   DMSG2(ctx, DINFO, "scanned: %s %s\n", restoredkinfo->get_image_repository_tag(),
1751                         (char*)restoredkinfo->get_image_id());
1752                   switch (replace){
1753                      case REPLACE_ALWAYS:
1754                         rp->create_status = CF_EXTRACT;
1755                         break;
1756                      case REPLACE_NEVER:
1757                         /* check if image exist on docker */
1758                         if ((image = search_docker_image(ctx)) != NULL){
1759                            /* exist, so skip restore */
1760                            DMSG1(ctx, DINFO, "image exist, skipping restore of: %s\n",
1761                                  restoredkinfo->get_image_repository_tag());
1762                            JMSG1(ctx, M_INFO, "Image exist, skipping restore of: %s\n",
1763                                  restoredkinfo->get_image_repository_tag());
1764                            rp->create_status = CF_SKIP;
1765                            break;
1766                         }
1767                         rp->create_status = CF_EXTRACT;
1768                         break;
1769                      case REPLACE_IFNEWER:
1770                         if ((image = search_docker_image(ctx)) != NULL){
1771                            /* exist, so check if newer */
1772                            if (image->get_image_created() < rp->statp.st_mtime){
1773                               DMSG1(ctx, DINFO, "image exist and is newer, skipping restore of: %s\n",
1774                                     restoredkinfo->get_image_repository_tag());
1775                               JMSG1(ctx, M_INFO, "Image exist and is newer, skipping restore of: %s\n",
1776                                     restoredkinfo->get_image_repository_tag());
1777                               rp->create_status = CF_SKIP;
1778                               break;
1779                            }
1780                         }
1781                         rp->create_status = CF_EXTRACT;
1782                         break;
1783                      case REPLACE_IFOLDER:
1784                         if ((image = search_docker_image(ctx)) != NULL){
1785                            /* exist, so check if newer */
1786                            if (image->get_image_created() > rp->statp.st_mtime){
1787                               rp->create_status = CF_SKIP;
1788                               DMSG1(ctx, DINFO, "image exist and is older, skipping restore of: %s\n",
1789                                     restoredkinfo->get_image_repository_tag());
1790                               JMSG1(ctx, M_INFO, "Image exist and is older, skipping restore of: %s\n",
1791                                     restoredkinfo->get_image_repository_tag());
1792                               break;
1793                            }
1794                         }
1795                         rp->create_status = CF_EXTRACT;
1796                         break;
1797                   }
1798                } else {
1799                   // fname scanning error
1800                   DMSG1(ctx, DERROR, "Filename scan error on: %s\n", fmt.c_str());
1801                   JMSG1(ctx, dkcommctx->is_abort_on_error() ? M_FATAL : M_ERROR,
1802                         "Filename scan error on: %s\n", fmt.c_str());
1803                   rp->create_status = CF_ERROR;
1804                   return bRC_Error;
1805                }
1806             }
1807          }
1808          if (rp->create_status == CF_EXTRACT){
1809             /* display info about a restore to the user */
1810             DMSG2(ctx, DINFO, "%s restore: %s\n", restoredkinfo-> type_str(), label.c_str());
1811             JMSG2(ctx, M_INFO, "%s restore: %s\n", restoredkinfo->type_str(), label.c_str());
1812          }
1813       }
1814    }
1815    return bRC_OK;
1816 }
1817 
1818 /*
1819  * Unimplemented, always return bRC_OK.
1820  */
setFileAttributes(bpContext * ctx,struct restore_pkt * rp)1821 bRC DOCKER::setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
1822 {
1823    return bRC_OK;
1824 }
1825 
1826 #if 0
1827 /*
1828  * Unimplemented, always return bRC_Seen.
1829  */
1830 bRC DOCKER::checkFile(bpContext *ctx, char *fname)
1831 {
1832    if (!accurate_warning){
1833       accurate_warning = true;
1834       JMSG0(ctx, M_WARNING, "Accurate mode is not supported. Please disable Accurate mode for this job.\n");
1835    }
1836    return bRC_Seen;
1837 }
1838 #endif
1839 
1840 /*
1841  * We will not generate any acl/xattr data, always return bRC_OK.
1842  */
handleXACLdata(bpContext * ctx,struct xacl_pkt * xacl)1843 bRC DOCKER::handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl)
1844 {
1845    return bRC_OK;
1846 }
1847 
1848 /*
1849  * Called here to make a new instance of the plugin -- i.e. when
1850  * a new Job is started.  There can be multiple instances of
1851  * each plugin that are running at the same time.  Your
1852  * plugin instance must be thread safe and keep its own
1853  * local data.
1854  */
newPlugin(bpContext * ctx)1855 static bRC newPlugin(bpContext *ctx)
1856 {
1857    int JobId;
1858    DOCKER *self = New(DOCKER(ctx));
1859    char *workdir;
1860 
1861    if (!self){
1862       return bRC_Error;
1863    }
1864    ctx->pContext = (void*) self;
1865 
1866    getBaculaVar(bVarJobId, (void *)&JobId);
1867    DMSG(ctx, DINFO, "newPlugin JobId=%d\n", JobId);
1868 
1869    /* we are very paranoid here to double check it */
1870    if (access(DOCKER_CMD, X_OK) < 0){
1871       berrno be;
1872       DMSG2(ctx, DERROR, "Unable to use command tool: %s Err=%s\n", DOCKER_CMD, be.bstrerror());
1873       JMSG2(ctx, M_FATAL, "Unable to use command tool: %s Err=%s\n", DOCKER_CMD, be.bstrerror());
1874       return bRC_Error;
1875    }
1876 
1877    /* get dynamic working directory from file daemon */
1878    getBaculaVar(bVarWorkingDir, (void *)&workdir);
1879    self->setworkingdir(workdir);
1880 
1881    return bRC_OK;
1882 }
1883 
1884 /*
1885  * Release everything concerning a particular instance of
1886  *  a plugin. Normally called when the Job terminates.
1887  */
freePlugin(bpContext * ctx)1888 static bRC freePlugin(bpContext *ctx)
1889 {
1890    if (!ctx){
1891       return bRC_Error;
1892    }
1893    DOCKER *self = pluginclass(ctx);
1894    DMSG(ctx, D1, "freePlugin this=%p\n", self);
1895    if (!self){
1896       return bRC_Error;
1897    }
1898    delete self;
1899    return bRC_OK;
1900 }
1901 
1902 /*
1903  * Called by core code to get a variable from the plugin.
1904  *   Not currently used.
1905  */
getPluginValue(bpContext * ctx,pVariable var,void * value)1906 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
1907 {
1908    ASSERT_CTX;
1909 
1910    DMSG0(ctx, D3, "getPluginValue called.\n");
1911    DOCKER *self = pluginclass(ctx);
1912    return self->getPluginValue(ctx,var, value);
1913 }
1914 
1915 /*
1916  * Called by core code to set a plugin variable.
1917  *  Not currently used.
1918  */
setPluginValue(bpContext * ctx,pVariable var,void * value)1919 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
1920 {
1921    ASSERT_CTX;
1922 
1923    DMSG0(ctx, D3, "setPluginValue called.\n");
1924    DOCKER *self = pluginclass(ctx);
1925    return self->setPluginValue(ctx, var, value);
1926 }
1927 
1928 /*
1929  * Called by Bacula when there are certain events that the
1930  *   plugin might want to know.  The value depends on the
1931  *   event.
1932  */
handlePluginEvent(bpContext * ctx,bEvent * event,void * value)1933 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
1934 {
1935    ASSERT_CTX;
1936 
1937    DMSG(ctx, D1, "handlePluginEvent (%i)\n", event->eventType);
1938    DOCKER *self = pluginclass(ctx);
1939    return self->handlePluginEvent(ctx, event, value);
1940 }
1941 
1942 /*
1943  * Called when starting to backup a file. Here the plugin must
1944  *  return the "stat" packet for the directory/file and provide
1945  *  certain information so that Bacula knows what the file is.
1946  *  The plugin can create "Virtual" files by giving them
1947  *  a name that is not normally found on the file system.
1948  */
startBackupFile(bpContext * ctx,struct save_pkt * sp)1949 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
1950 {
1951    ASSERT_CTX;
1952    if (!sp){
1953       return bRC_Error;
1954    }
1955    DMSG0(ctx, D1, "startBackupFile.\n");
1956    DOCKER *self = pluginclass(ctx);
1957    return self->startBackupFile(ctx, sp);
1958 }
1959 
1960 /*
1961  * Done backing up a file.
1962  */
endBackupFile(bpContext * ctx)1963 static bRC endBackupFile(bpContext *ctx)
1964 {
1965    ASSERT_CTX;
1966 
1967    DMSG0(ctx, D1, "endBackupFile.\n");
1968    DOCKER *self = pluginclass(ctx);
1969    return self->endBackupFile(ctx);
1970 }
1971 
1972 /*
1973  * Called when starting restore the file, right after a createFile().
1974  */
startRestoreFile(bpContext * ctx,const char * cmd)1975 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
1976 {
1977    ASSERT_CTX;
1978 
1979    DMSG0(ctx, D1, "startRestoreFile.\n");
1980    DOCKER *self = pluginclass(ctx);
1981    return self->startRestoreFile(ctx, cmd);
1982 }
1983 
1984 /*
1985  * Done restore the file.
1986  */
endRestoreFile(bpContext * ctx)1987 static bRC endRestoreFile(bpContext *ctx)
1988 {
1989    ASSERT_CTX;
1990 
1991    DMSG0(ctx, D1, "endRestoreFile.\n");
1992    DOCKER *self = pluginclass(ctx);
1993    return self->endRestoreFile(ctx);
1994 }
1995 
1996 /*
1997  * Do actual I/O. Bacula calls this after startBackupFile
1998  *   or after startRestoreFile to do the actual file
1999  *   input or output.
2000  */
pluginIO(bpContext * ctx,struct io_pkt * io)2001 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
2002 {
2003    ASSERT_CTX;
2004 
2005    DMSG0(ctx, DVDEBUG, "pluginIO.\n");
2006    DOCKER *self = pluginclass(ctx);
2007    return self->pluginIO(ctx, io);
2008 }
2009 
2010 /*
2011  * Called here to give the plugin the information needed to
2012  *  re-create the file on a restore.  It basically gets the
2013  *  stat packet that was created during the backup phase.
2014  *  This data is what is needed to create the file, but does
2015  *  not contain actual file data.
2016  */
createFile(bpContext * ctx,struct restore_pkt * rp)2017 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
2018 {
2019    ASSERT_CTX;
2020 
2021    DMSG0(ctx, D1, "createFile.\n");
2022    DOCKER *self = pluginclass(ctx);
2023    return self->createFile(ctx, rp);
2024 }
2025 
2026 #if 0
2027 /*
2028  * checkFile used for accurate mode backup
2029  */
2030 static bRC checkFile(bpContext *ctx, char *fname)
2031 {
2032    ASSERT_CTX;
2033 
2034    DMSG(ctx, D1, "checkFile: %s\n", fname);
2035    DOCKER *self = pluginclass(ctx);
2036    return self->checkFile(ctx, fname);
2037 }
2038 #endif
2039 
2040 /*
2041  * Called after the file has been restored. This can be used to
2042  *  set directory permissions, ...
2043  */
setFileAttributes(bpContext * ctx,struct restore_pkt * rp)2044 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
2045 {
2046    ASSERT_CTX;
2047 
2048    DMSG0(ctx, D1, "setFileAttributes.\n");
2049    DOCKER *self = pluginclass(ctx);
2050    return self->setFileAttributes(ctx, rp);
2051 }
2052 
2053 /*
2054  * handleXACLdata used for ACL/XATTR backup and restore
2055  */
handleXACLdata(bpContext * ctx,struct xacl_pkt * xacl)2056 static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl)
2057 {
2058    ASSERT_CTX;
2059 
2060    DMSG(ctx, D1, "handleXACLdata: %i\n", xacl->func);
2061    DOCKER *self = pluginclass(ctx);
2062    return self->handleXACLdata(ctx, xacl);
2063 }
2064