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, ®exwhere);
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