1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2007-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2018 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation, which is
11 listed in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, October 2007
25 */
26 /**
27 * @file
28 * Bareos pluginloader
29 */
30 #include "include/bareos.h"
31 #include "filed/filed.h"
32 #include "filed/filed_globals.h"
33 #include "filed/accurate.h"
34 #include "filed/heartbeat.h"
35 #include "filed/fileset.h"
36 #include "filed/heartbeat.h"
37 #include "findlib/attribs.h"
38 #include "findlib/find.h"
39 #include "findlib/find_one.h"
40 #include "findlib/hardlink.h"
41
42 /**
43 * Function pointers to be set here (findlib)
44 */
45 extern int (*plugin_bopen)(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode);
46 extern int (*plugin_bclose)(BareosWinFilePacket *bfd);
47 extern ssize_t (*plugin_bread)(BareosWinFilePacket *bfd, void *buf, size_t count);
48 extern ssize_t (*plugin_bwrite)(BareosWinFilePacket *bfd, void *buf, size_t count);
49 extern boffset_t (*plugin_blseek)(BareosWinFilePacket *bfd, boffset_t offset, int whence);
50
51 extern char *exepath;
52 extern char *version;
53 extern char *dist_name;
54
55 namespace filedaemon {
56
57 const int debuglevel = 150;
58 #ifdef HAVE_WIN32
59 const char *plugin_type = "-fd.dll";
60 #else
61 const char *plugin_type = "-fd.so";
62 #endif
63 static alist *fd_plugin_list = NULL;
64 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
65
66 extern int SaveFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level);
67
68 /**
69 * Forward referenced functions
70 */
71 static bRC bareosGetValue(bpContext *ctx, bVariable var, void *value);
72 static bRC bareosSetValue(bpContext *ctx, bVariable var, void *value);
73 static bRC bareosRegisterEvents(bpContext *ctx, int nr_events, ...);
74 static bRC bareosUnRegisterEvents(bpContext *ctx, int nr_events, ...);
75 static bRC bareosJobMsg(bpContext *ctx, const char *fname, int line,
76 int type, utime_t mtime, const char *fmt, ...);
77 static bRC bareosDebugMsg(bpContext *ctx, const char *fname, int line,
78 int level, const char *fmt, ...);
79 static void *bareosMalloc(bpContext *ctx, const char *fname, int line,
80 size_t size);
81 static void bareosFree(bpContext *ctx, const char *file, int line, void *mem);
82 static bRC bareosAddExclude(bpContext *ctx, const char *file);
83 static bRC bareosAddInclude(bpContext *ctx, const char *file);
84 static bRC bareosAddOptions(bpContext *ctx, const char *opts);
85 static bRC bareosAddRegex(bpContext *ctx, const char *item, int type);
86 static bRC bareosAddWild(bpContext *ctx, const char *item, int type);
87 static bRC bareosNewOptions(bpContext *ctx);
88 static bRC bareosNewInclude(bpContext *ctx);
89 static bRC bareosNewPreInclude(bpContext *ctx);
90 static bool IsPluginCompatible(Plugin *plugin);
91 static bool GetPluginName(JobControlRecord *jcr, char *cmd, int *ret);
92 static bRC bareosCheckChanges(bpContext *ctx, struct save_pkt *sp);
93 static bRC bareosAcceptFile(bpContext *ctx, struct save_pkt *sp);
94 static bRC bareosSetSeenBitmap(bpContext *ctx, bool all, char *fname);
95 static bRC bareosClearSeenBitmap(bpContext *ctx, bool all, char *fname);
96 static bRC bareosGetInstanceCount(bpContext *ctx, int *ret);
97
98 /**
99 * These will be plugged into the global pointer structure for the findlib.
100 */
101 static int MyPluginBopen(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode);
102 static int MyPluginBclose(BareosWinFilePacket *bfd);
103 static ssize_t MyPluginBread(BareosWinFilePacket *bfd, void *buf, size_t count);
104 static ssize_t MyPluginBwrite(BareosWinFilePacket *bfd, void *buf, size_t count);
105 static boffset_t MyPluginBlseek(BareosWinFilePacket *bfd, boffset_t offset, int whence);
106
107 /* Bareos info */
108 static bInfo binfo = {
109 sizeof(bInfo),
110 FD_PLUGIN_INTERFACE_VERSION
111 };
112
113 /* Bareos entry points */
114 static bFuncs bfuncs = {
115 sizeof(bFuncs),
116 FD_PLUGIN_INTERFACE_VERSION,
117 bareosRegisterEvents,
118 bareosUnRegisterEvents,
119 bareosGetInstanceCount,
120 bareosGetValue,
121 bareosSetValue,
122 bareosJobMsg,
123 bareosDebugMsg,
124 bareosMalloc,
125 bareosFree,
126 bareosAddExclude,
127 bareosAddInclude,
128 bareosAddOptions,
129 bareosAddRegex,
130 bareosAddWild,
131 bareosNewOptions,
132 bareosNewInclude,
133 bareosNewPreInclude,
134 bareosCheckChanges,
135 bareosAcceptFile,
136 bareosSetSeenBitmap,
137 bareosClearSeenBitmap
138 };
139
140 /**
141 * Bareos private context
142 */
143 struct b_plugin_ctx {
144 JobControlRecord *jcr; /* jcr for plugin */
145 bRC ret; /* last return code */
146 bool disabled; /* set if plugin disabled */
147 bool restoreFileStarted;
148 bool createFileCalled;
149 char events[NbytesForBits(FD_NR_EVENTS + 1)]; /* enabled events bitmask */
150 findIncludeExcludeItem *exclude; /* pointer to exclude files */
151 findIncludeExcludeItem *include; /* pointer to include/exclude files */
152 Plugin *plugin; /* pointer to plugin of which this is an instance off */
153 };
154
IsEventEnabled(bpContext * ctx,bEventType eventType)155 static inline bool IsEventEnabled(bpContext *ctx, bEventType eventType)
156 {
157 b_plugin_ctx *b_ctx;
158
159 if (!ctx) {
160 return false;
161 }
162
163 b_ctx = (b_plugin_ctx *)ctx->bContext;
164 if (!b_ctx) {
165 return false;
166 }
167
168 return BitIsSet(eventType, b_ctx->events);
169 }
170
IsPluginDisabled(bpContext * ctx)171 static inline bool IsPluginDisabled(bpContext *ctx)
172 {
173 b_plugin_ctx *b_ctx;
174
175 if (!ctx) {
176 return true;
177 }
178
179 b_ctx = (b_plugin_ctx *)ctx->bContext;
180 if (!b_ctx) {
181 return true;
182 }
183
184 return b_ctx->disabled;
185 }
186
IsCtxGood(bpContext * ctx,JobControlRecord * & jcr,b_plugin_ctx * & bctx)187 static bool IsCtxGood(bpContext *ctx, JobControlRecord *&jcr, b_plugin_ctx *&bctx)
188 {
189 if (!ctx) {
190 return false;
191 }
192
193 bctx = (b_plugin_ctx *)ctx->bContext;
194 if (!bctx) {
195 return false;
196 }
197
198 jcr = bctx->jcr;
199 if (!jcr) {
200 return false;
201 }
202
203 return true;
204 }
205
206 /**
207 * Test if event is for this plugin
208 */
for_thIsPlugin(Plugin * plugin,char * name,int len)209 static bool for_thIsPlugin(Plugin *plugin, char *name, int len)
210 {
211 Dmsg4(debuglevel, "name=%s len=%d plugin=%s plen=%d\n", name, len, plugin->file, plugin->file_len);
212 if (!name) { /* if no plugin name, all plugins get it */
213 return true;
214 }
215
216 /*
217 * Return global VSS job metadata to all plugins
218 */
219 if (bstrcmp("job", name)) { /* old V4.0 name for VSS job metadata */
220 return true;
221 }
222
223 if (bstrcmp("*all*", name)) { /* new v6.0 name for VSS job metadata */
224 return true;
225 }
226
227 /*
228 * Check if this is the correct plugin
229 */
230 if (len == plugin->file_len && bstrncmp(plugin->file, name, len)) {
231 return true;
232 }
233
234 return false;
235 }
236
237 /**
238 * Raise a certain plugin event.
239 */
trigger_plugin_event(JobControlRecord * jcr,bEventType eventType,bEvent * event,bpContext * ctx,void * value,alist * plugin_ctx_list,int * index,bRC * rc)240 static inline bool trigger_plugin_event(JobControlRecord *jcr, bEventType eventType,
241 bEvent *event, bpContext *ctx,
242 void *value, alist *plugin_ctx_list,
243 int *index, bRC *rc)
244
245 {
246 bool stop = false;
247
248 if (!IsEventEnabled(ctx, eventType)) {
249 Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
250 if (rc) {
251 *rc = bRC_OK;
252 }
253 goto bail_out;
254 }
255
256 if (IsPluginDisabled(ctx)) {
257 if (rc) {
258 *rc = bRC_OK;
259 }
260 goto bail_out;
261 }
262
263 if (eventType == bEventEndRestoreJob) {
264 b_plugin_ctx *b_ctx = (b_plugin_ctx *)ctx->bContext;
265
266 Dmsg0(50, "eventType == bEventEndRestoreJob\n");
267 if (b_ctx && b_ctx->restoreFileStarted) {
268 PlugFunc(ctx->plugin)->endRestoreFile(ctx);
269 }
270
271 if (b_ctx) {
272 b_ctx->restoreFileStarted = false;
273 b_ctx->createFileCalled = false;
274 }
275 }
276
277 /*
278 * See if we should care about the return code.
279 */
280 if (rc) {
281 *rc = PlugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
282 switch (*rc) {
283 case bRC_OK:
284 break;
285 case bRC_Stop:
286 case bRC_Error:
287 stop = true;
288 break;
289 case bRC_More:
290 break;
291 case bRC_Term:
292 /*
293 * Request to unload this plugin.
294 * As we remove the plugin from the list of plugins we decrement
295 * the running index value so the next plugin gets triggered as
296 * that moved back a position in the alist.
297 */
298 if (index) {
299 UnloadPlugin(plugin_ctx_list, ctx->plugin, *index);
300 *index = ((*index) - 1);
301 }
302 break;
303 case bRC_Seen:
304 break;
305 case bRC_Core:
306 break;
307 case bRC_Skip:
308 stop = true;
309 break;
310 case bRC_Cancel:
311 break;
312 default:
313 break;
314 }
315 } else {
316 PlugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
317 }
318
319 bail_out:
320 return stop;
321 }
322
323 /**
324 * Create a plugin event When receiving bEventCancelCommand, this function is called by another thread.
325 */
GeneratePluginEvent(JobControlRecord * jcr,bEventType eventType,void * value,bool reverse)326 bRC GeneratePluginEvent(JobControlRecord *jcr, bEventType eventType, void *value, bool reverse)
327 {
328 bEvent event;
329 char *name = NULL;
330 int i;
331 int len = 0;
332 bool call_if_canceled = false;
333 restore_object_pkt *rop;
334 bpContext *ctx = nullptr;
335 alist *plugin_ctx_list;
336 bRC rc = bRC_OK;
337
338 if (!fd_plugin_list) {
339 Dmsg0(debuglevel, "No bplugin_list: GeneratePluginEvent ignored.\n");
340 goto bail_out;
341 }
342
343 if (!jcr) {
344 Dmsg0(debuglevel, "No jcr: GeneratePluginEvent ignored.\n");
345 goto bail_out;
346 }
347
348 if (!jcr->plugin_ctx_list) {
349 Dmsg0(debuglevel, "No plugin_ctx_list: GeneratePluginEvent ignored.\n");
350 goto bail_out;
351 }
352
353 plugin_ctx_list = jcr->plugin_ctx_list;
354
355 /*
356 * Some events are sent to only a particular plugin or must be called even if the job is canceled.
357 */
358 switch(eventType) {
359 case bEventPluginCommand:
360 case bEventOptionPlugin:
361 name = (char *)value;
362 if (!GetPluginName(jcr, name, &len)) {
363 goto bail_out;
364 }
365 break;
366 case bEventRestoreObject:
367 /*
368 * After all RestoreObject, we have it one more time with value = NULL
369 */
370 if (value) {
371 /*
372 * Some RestoreObjects may not have a plugin name
373 */
374 rop = (restore_object_pkt *)value;
375 if (*rop->plugin_name) {
376 name = rop->plugin_name;
377 if (!GetPluginName(jcr, name, &len)) {
378 goto bail_out;
379 }
380 }
381 }
382 break;
383 case bEventEndBackupJob:
384 case bEventEndVerifyJob:
385 call_if_canceled = true; /* plugin *must* see this call */
386 break;
387 case bEventStartRestoreJob:
388 foreach_alist(ctx, plugin_ctx_list) {
389 ((b_plugin_ctx *)ctx->bContext)->restoreFileStarted = false;
390 ((b_plugin_ctx *)ctx->bContext)->createFileCalled = false;
391 }
392 break;
393 case bEventEndRestoreJob:
394 call_if_canceled = true; /* plugin *must* see this call */
395 break;
396 default:
397 break;
398 }
399
400 /*
401 * If call_if_canceled is set, we call the plugin anyway
402 */
403 if (!call_if_canceled && jcr->IsJobCanceled()) {
404 goto bail_out;
405 }
406
407 event.eventType = eventType;
408
409 Dmsg2(debuglevel, "plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
410
411 /*
412 * Pass event to every plugin that has requested this event type (except if name is set).
413 * If name is set, we pass it only to the plugin with that name.
414 *
415 * See if we need to trigger the loaded plugins in reverse order.
416 */
417 if (reverse) {
418 foreach_alist_rindex(i, ctx, plugin_ctx_list) {
419 if (!for_thIsPlugin(ctx->plugin, name, len)) {
420 Dmsg2(debuglevel, "Not for this plugin name=%s NULL=%d\n", name, (name == NULL) ? 1 : 0);
421 continue;
422 }
423
424 if (trigger_plugin_event(jcr, eventType, &event, ctx, value, plugin_ctx_list, &i, &rc)) {
425 break;
426 }
427 }
428 } else {
429 foreach_alist_index(i, ctx, plugin_ctx_list) {
430 if (!for_thIsPlugin(ctx->plugin, name, len)) {
431 Dmsg2(debuglevel, "Not for this plugin name=%s NULL=%d\n", name, (name == NULL) ? 1 : 0);
432 continue;
433 }
434
435 if (trigger_plugin_event(jcr, eventType, &event, ctx, value, plugin_ctx_list, &i, &rc)) {
436 break;
437 }
438 }
439 }
440
441 if (jcr->IsJobCanceled()) {
442 Dmsg0(debuglevel, "Cancel return from GeneratePluginEvent\n");
443 rc = bRC_Cancel;
444 }
445
446 bail_out:
447 return rc;
448 }
449
450 /**
451 * Check if file was seen for accurate
452 */
PluginCheckFile(JobControlRecord * jcr,char * fname)453 bool PluginCheckFile(JobControlRecord *jcr, char *fname)
454 {
455 bpContext *ctx = nullptr;
456 alist *plugin_ctx_list;
457 int retval = bRC_OK;
458
459 if (!fd_plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->IsJobCanceled()) {
460 return false; /* Return if no plugins loaded */
461 }
462
463 plugin_ctx_list = jcr->plugin_ctx_list;
464 Dmsg2(debuglevel, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
465
466 /*
467 * Pass event to every plugin
468 */
469 foreach_alist(ctx, plugin_ctx_list) {
470 if (IsPluginDisabled(ctx)) {
471 continue;
472 }
473
474 jcr->plugin_ctx = ctx;
475 if (PlugFunc(ctx->plugin)->checkFile == NULL) {
476 continue;
477 }
478
479 retval = PlugFunc(ctx->plugin)->checkFile(ctx, fname);
480 if (retval == bRC_Seen) {
481 break;
482 }
483 }
484
485 return retval == bRC_Seen;
486 }
487
488 /**
489 * Get the first part of the the plugin command
490 * systemstate:/@SYSTEMSTATE/
491 * => ret = 11
492 * => can use for_thIsPlugin(plug, cmd, ret);
493 *
494 * The plugin command can contain only the plugin name
495 * Plugin = alldrives
496 * => ret = 9
497 */
GetPluginName(JobControlRecord * jcr,char * cmd,int * ret)498 static bool GetPluginName(JobControlRecord *jcr, char *cmd, int *ret)
499 {
500 char *p;
501 int len;
502
503 if (!cmd || (*cmd == '\0')) {
504 return false;
505 }
506
507 /*
508 * Handle plugin command here backup
509 */
510 Dmsg1(debuglevel, "plugin cmd=%s\n", cmd);
511 if ((p = strchr(cmd, ':')) == NULL) {
512 if (strchr(cmd, ' ') == NULL) { /* we have just the plugin name */
513 len = strlen(cmd);
514 } else {
515 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
516 return false;
517 }
518 } else { /* plugin:argument */
519 len = p - cmd;
520 if (len <= 0) {
521 return false;
522 }
523 }
524 *ret = len;
525
526 return true;
527 }
528
PluginUpdateFfPkt(FindFilesPacket * ff_pkt,struct save_pkt * sp)529 void PluginUpdateFfPkt(FindFilesPacket *ff_pkt, struct save_pkt *sp)
530 {
531 ff_pkt->no_read = sp->no_read;
532 ff_pkt->delta_seq = sp->delta_seq;
533
534 if (BitIsSet(FO_DELTA, sp->flags)) {
535 SetBit(FO_DELTA, ff_pkt->flags);
536 ff_pkt->delta_seq++; /* make new delta sequence number */
537 } else {
538 ClearBit(FO_DELTA, ff_pkt->flags);
539 ff_pkt->delta_seq = 0; /* clean delta sequence number */
540 }
541
542 if (BitIsSet(FO_OFFSETS, sp->flags)) {
543 SetBit(FO_OFFSETS, ff_pkt->flags);
544 } else {
545 ClearBit(FO_OFFSETS, ff_pkt->flags);
546 }
547
548 /*
549 * Sparse code doesn't work with plugins
550 * that use FIFO or STDOUT/IN to communicate
551 */
552 if (BitIsSet(FO_SPARSE, sp->flags)) {
553 SetBit(FO_SPARSE, ff_pkt->flags);
554 } else {
555 ClearBit(FO_SPARSE, ff_pkt->flags);
556 }
557
558 if (BitIsSet(FO_PORTABLE_DATA, sp->flags)) {
559 SetBit(FO_PORTABLE_DATA, ff_pkt->flags);
560 } else {
561 ClearBit(FO_PORTABLE_DATA, ff_pkt->flags);
562 }
563
564 SetBit(FO_PLUGIN, ff_pkt->flags); /* data from plugin */
565 }
566
567 /**
568 * Ask to a Option Plugin what to do with the current file
569 */
PluginOptionHandleFile(JobControlRecord * jcr,FindFilesPacket * ff_pkt,struct save_pkt * sp)570 bRC PluginOptionHandleFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, struct save_pkt *sp)
571 {
572 int len;
573 char *cmd;
574 bRC retval = bRC_Core;
575 bEvent event;
576 bEventType eventType;
577 bpContext *ctx = nullptr;
578 alist *plugin_ctx_list;
579
580 cmd = ff_pkt->plugin;
581 eventType = bEventHandleBackupFile;
582 event.eventType = eventType;
583
584 memset(sp, 0, sizeof(struct save_pkt));
585 sp->pkt_size = sp->pkt_end = sizeof(struct save_pkt);
586 sp->portable = true;
587 CopyBits(FO_MAX, ff_pkt->flags, sp->flags);
588 sp->cmd = cmd;
589 sp->link = ff_pkt->link;
590 sp->statp = ff_pkt->statp;
591 sp->type = ff_pkt->type;
592 sp->fname = ff_pkt->fname;
593 sp->delta_seq = ff_pkt->delta_seq;
594 sp->accurate_found = ff_pkt->accurate_found;
595
596 plugin_ctx_list = jcr->plugin_ctx_list;
597 if (!fd_plugin_list || !plugin_ctx_list || jcr->IsJobCanceled()) {
598 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
599 goto bail_out; /* Return if no plugins loaded */
600 }
601
602 if (!GetPluginName(jcr, cmd, &len)) {
603 goto bail_out;
604 }
605
606 /*
607 * Note, we stop the loop on the first plugin that matches the name
608 */
609 foreach_alist(ctx, plugin_ctx_list) {
610 Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
611 if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
612 continue;
613 }
614
615 if (!IsEventEnabled(ctx, eventType)) {
616 Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
617 continue;
618 }
619
620 if (IsPluginDisabled(ctx)) {
621 goto bail_out;
622 }
623
624 jcr->plugin_ctx = ctx;
625 retval = PlugFunc(ctx->plugin)->handlePluginEvent(ctx, &event, sp);
626
627 goto bail_out;
628 } /* end foreach loop */
629
630 bail_out:
631 return retval;
632 }
633
634 /**
635 * Sequence of calls for a backup:
636 * 1. PluginSave() here is called with ff_pkt
637 * 2. we find the plugin requested on the command string
638 * 3. we generate a bEventBackupCommand event to the specified plugin
639 * and pass it the command string.
640 * 4. we make a startPluginBackup call to the plugin, which gives
641 * us the data we need in save_pkt
642 * 5. we call Bareos's SaveFile() subroutine to save the specified
643 * file. The plugin will be called at pluginIO() to supply the
644 * file data.
645 *
646 * Sequence of calls for restore:
647 * See subroutine PluginNameStream() below.
648 */
PluginSave(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)649 int PluginSave(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
650 {
651 int len;
652 bRC retval;
653 char *cmd;
654 bEvent event;
655 bpContext *ctx = nullptr;
656 struct save_pkt sp;
657 bEventType eventType;
658 PoolMem fname(PM_FNAME);
659 PoolMem link(PM_FNAME);
660 alist *plugin_ctx_list;
661 char flags[FOPTS_BYTES];
662
663 cmd = ff_pkt->top_fname;
664 plugin_ctx_list = jcr->plugin_ctx_list;
665 if (!fd_plugin_list || !plugin_ctx_list || jcr->IsJobCanceled()) {
666 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
667 return 1; /* Return if no plugins loaded */
668 }
669
670 jcr->cmd_plugin = true;
671 eventType = bEventBackupCommand;
672 event.eventType = eventType;
673
674 if (!GetPluginName(jcr, cmd, &len)) {
675 goto bail_out;
676 }
677
678 /*
679 * Note, we stop the loop on the first plugin that matches the name
680 */
681 foreach_alist(ctx, plugin_ctx_list) {
682 Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
683 if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
684 continue;
685 }
686
687 /*
688 * We put the current plugin pointer, and the plugin context into the jcr, because during SaveFile(),
689 * the plugin will be called many times and these values are needed.
690 */
691 if (!IsEventEnabled(ctx, eventType)) {
692 Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
693 continue;
694 }
695
696 if (IsPluginDisabled(ctx)) {
697 goto bail_out;
698 }
699
700 jcr->plugin_ctx = ctx;
701
702 /*
703 * Send the backup command to the right plugin
704 */
705 Dmsg1(debuglevel, "Command plugin = %s\n", cmd);
706 if (PlugFunc(ctx->plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
707 goto bail_out;
708 }
709
710 /*
711 * Loop getting filenames to backup then saving them
712 */
713 while (!jcr->IsJobCanceled()) {
714 memset(&sp, 0, sizeof(sp));
715 sp.pkt_size = sizeof(sp);
716 sp.pkt_end = sizeof(sp);
717 sp.portable = true;
718 sp.no_read = false;
719 CopyBits(FO_MAX, ff_pkt->flags, sp.flags);
720 sp.cmd = cmd;
721 Dmsg3(debuglevel, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks, &sp);
722
723 /*
724 * Get the file save parameters. I.e. the stat pkt ...
725 */
726 if (PlugFunc(ctx->plugin)->startBackupFile(ctx, &sp) != bRC_OK) {
727 goto bail_out;
728 }
729
730 if (sp.type == 0) {
731 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"), cmd);
732 goto bail_out;
733 }
734
735 jcr->plugin_sp = &sp;
736 ff_pkt = jcr->ff;
737
738 /*
739 * Save original flags.
740 */
741 CopyBits(FO_MAX, ff_pkt->flags, flags);
742
743 /*
744 * Copy fname and link because SaveFile() zaps them. This avoids zaping the plugin's strings.
745 */
746 ff_pkt->type = sp.type;
747 if (IS_FT_OBJECT(sp.type)) {
748 if (!sp.object_name) {
749 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no object_name in startBackupFile packet.\n"), cmd);
750 goto bail_out;
751 }
752 ff_pkt->fname = cmd; /* full plugin string */
753 ff_pkt->object_name = sp.object_name;
754 ff_pkt->object_index = sp.index; /* restore object index */
755 ff_pkt->object_compression = 0; /* no compression for now */
756 ff_pkt->object = sp.object;
757 ff_pkt->object_len = sp.object_len;
758 } else {
759 if (!sp.fname) {
760 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"), cmd);
761 goto bail_out;
762 }
763
764 PmStrcpy(fname, sp.fname);
765 PmStrcpy(link, sp.link);
766
767 ff_pkt->fname = fname.c_str();
768 ff_pkt->link = link.c_str();
769
770 PluginUpdateFfPkt(ff_pkt, &sp);
771 }
772
773 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
774 Dmsg2(debuglevel, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
775 if (sp.object) {
776 Dmsg2(debuglevel, "index=%d object=%s\n", sp.index, sp.object);
777 }
778
779 /*
780 * Handle hard linked files
781 *
782 * Maintain a list of hard linked files already backed up. This allows us to ensure
783 * that the data of each file gets backed up only once.
784 */
785 ff_pkt->LinkFI = 0;
786 if (!BitIsSet(FO_NO_HARDLINK, ff_pkt->flags) && ff_pkt->statp.st_nlink > 1) {
787 CurLink *hl;
788
789 switch (ff_pkt->statp.st_mode & S_IFMT) {
790 case S_IFREG:
791 case S_IFCHR:
792 case S_IFBLK:
793 case S_IFIFO:
794 #ifdef S_IFSOCK
795 case S_IFSOCK:
796 #endif
797 hl = lookup_hardlink(jcr, ff_pkt, ff_pkt->statp.st_ino, ff_pkt->statp.st_dev);
798 if (hl) {
799 /*
800 * If we have already backed up the hard linked file don't do it again
801 */
802 if (bstrcmp(hl->name, sp.fname)) {
803 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", hl->FileIndex, fname.c_str());
804 ff_pkt->no_read = true;
805 } else {
806 ff_pkt->link = hl->name;
807 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
808 ff_pkt->LinkFI = hl->FileIndex;
809 ff_pkt->linked = NULL;
810 ff_pkt->digest = hl->digest;
811 ff_pkt->digest_stream = hl->digest_stream;
812 ff_pkt->digest_len = hl->digest_len;
813
814 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", ff_pkt->FileIndex, hl->FileIndex, hl->name);
815
816 ff_pkt->no_read = true;
817 }
818 } else {
819 /*
820 * File not previously dumped. Chain it into our list.
821 */
822 hl = new_hardlink(jcr, ff_pkt, sp.fname, ff_pkt->statp.st_ino, ff_pkt->statp.st_dev);
823 ff_pkt->linked = hl; /* Mark saved link */
824 Dmsg2(400, "Added to hash FI=%d file=%s\n", ff_pkt->FileIndex, hl->name);
825 }
826 break;
827 default:
828 ff_pkt->linked = NULL;
829 break;
830 }
831 } else {
832 ff_pkt->linked = NULL;
833 }
834
835 /*
836 * Call Bareos core code to backup the plugin's file
837 */
838 SaveFile(jcr, ff_pkt, true);
839
840 /*
841 * Restore original flags.
842 */
843 CopyBits(FO_MAX, flags, ff_pkt->flags);
844
845 retval = PlugFunc(ctx->plugin)->endBackupFile(ctx);
846 if (retval == bRC_More || retval == bRC_OK) {
847 AccurateMarkFileAsSeen(jcr, fname.c_str());
848 }
849
850 if (retval == bRC_More) {
851 continue;
852 }
853
854 goto bail_out;
855 } /* end while loop */
856
857 goto bail_out;
858 } /* end loop over all plugins */
859 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
860
861 bail_out:
862 jcr->cmd_plugin = false;
863
864 return 1;
865 }
866
867 /**
868 * Sequence of calls for a estimate:
869 * 1. PluginEstimate() here is called with ff_pkt
870 * 2. we find the plugin requested on the command string
871 * 3. we generate a bEventEstimateCommand event to the specified plugin
872 * and pass it the command string.
873 * 4. we make a startPluginBackup call to the plugin, which gives
874 * us the data we need in save_pkt
875 *
876 */
PluginEstimate(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)877 int PluginEstimate(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
878 {
879 int len;
880 char *cmd = ff_pkt->top_fname;
881 struct save_pkt sp;
882 bEvent event;
883 bEventType eventType;
884 PoolMem fname(PM_FNAME);
885 PoolMem link(PM_FNAME);
886 bpContext *ctx = nullptr;
887 alist *plugin_ctx_list;
888 Attributes attr;
889
890 plugin_ctx_list = jcr->plugin_ctx_list;
891 if (!fd_plugin_list || !plugin_ctx_list) {
892 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
893 return 1; /* Return if no plugins loaded */
894 }
895
896 jcr->cmd_plugin = true;
897 eventType = bEventEstimateCommand;
898 event.eventType = eventType;
899
900 if (!GetPluginName(jcr, cmd, &len)) {
901 goto bail_out;
902 }
903
904 /*
905 * Note, we stop the loop on the first plugin that matches the name
906 */
907 foreach_alist(ctx, plugin_ctx_list) {
908 Dmsg4(debuglevel, "plugin=%s plen=%d cmd=%s len=%d\n", ctx->plugin->file, ctx->plugin->file_len, cmd, len);
909 if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
910 continue;
911 }
912
913 /*
914 * We put the current plugin pointer, and the plugin context into the jcr, because during SaveFile(),
915 * the plugin will be called many times and these values are needed.
916 */
917 if (!IsEventEnabled(ctx, eventType)) {
918 Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
919 continue;
920 }
921
922 if (IsPluginDisabled(ctx)) {
923 goto bail_out;
924 }
925
926 jcr->plugin_ctx = ctx;
927
928 /*
929 * Send the backup command to the right plugin
930 */
931 Dmsg1(debuglevel, "Command plugin = %s\n", cmd);
932 if (PlugFunc(ctx->plugin)->handlePluginEvent(ctx, &event, cmd) != bRC_OK) {
933 goto bail_out;
934 }
935
936 /*
937 * Loop getting filenames to backup then saving them
938 */
939 while (!jcr->IsJobCanceled()) {
940 memset(&sp, 0, sizeof(sp));
941 sp.pkt_size = sizeof(sp);
942 sp.pkt_end = sizeof(sp);
943 sp.portable = true;
944 CopyBits(FO_MAX, ff_pkt->flags, sp.flags);
945 sp.cmd = cmd;
946 Dmsg3(debuglevel, "startBackup st_size=%p st_blocks=%p sp=%p\n",
947 &sp.statp.st_size, &sp.statp.st_blocks, &sp);
948
949 /*
950 * Get the file save parameters. I.e. the stat pkt ...
951 */
952 if (PlugFunc(ctx->plugin)->startBackupFile(ctx, &sp) != bRC_OK) {
953 goto bail_out;
954 }
955
956 if (sp.type == 0) {
957 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"), cmd);
958 goto bail_out;
959 }
960
961 if (!IS_FT_OBJECT(sp.type)) {
962 if (!sp.fname) {
963 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"),
964 cmd);
965 goto bail_out;
966 }
967
968 /*
969 * Count only files backed up
970 */
971 switch (sp.type) {
972 case FT_REGE:
973 case FT_REG:
974 case FT_LNK:
975 case FT_DIREND:
976 case FT_SPEC:
977 case FT_RAW:
978 case FT_FIFO:
979 case FT_LNKSAVED:
980 jcr->JobFiles++; /* increment number of files backed up */
981 break;
982 default:
983 break;
984 }
985 jcr->num_files_examined++;
986
987 if (sp.type != FT_LNKSAVED && S_ISREG(sp.statp.st_mode)) {
988 if (sp.statp.st_size > 0) {
989 jcr->JobBytes += sp.statp.st_size;
990 }
991 }
992
993 if (jcr->listing) {
994 memcpy(&attr.statp, &sp.statp, sizeof(struct stat));
995 attr.type = sp.type;
996 attr.ofname = (POOLMEM *)sp.fname;
997 attr.olname = (POOLMEM *)sp.link;
998 PrintLsOutput(jcr, &attr);
999 }
1000 }
1001
1002 Dmsg2(debuglevel, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
1003 if (sp.object) {
1004 Dmsg2(debuglevel, "index=%d object=%s\n", sp.index, sp.object);
1005 }
1006
1007 bRC retval = PlugFunc(ctx->plugin)->endBackupFile(ctx);
1008 if (retval == bRC_More || retval == bRC_OK) {
1009 AccurateMarkFileAsSeen(jcr, sp.fname);
1010 }
1011
1012 if (retval == bRC_More) {
1013 continue;
1014 }
1015
1016 goto bail_out;
1017 } /* end while loop */
1018
1019 goto bail_out;
1020 } /* end loop over all plugins */
1021 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
1022
1023 bail_out:
1024 jcr->cmd_plugin = false;
1025
1026 return 1;
1027 }
1028
1029 /**
1030 * Send plugin name start/end record to SD
1031 */
SendPluginName(JobControlRecord * jcr,BareosSocket * sd,bool start)1032 bool SendPluginName(JobControlRecord *jcr, BareosSocket *sd, bool start)
1033 {
1034 int status;
1035 int index = jcr->JobFiles;
1036 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
1037
1038 if (!sp) {
1039 Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
1040 return false;
1041 }
1042 if (jcr->IsJobCanceled()) {
1043 return false;
1044 }
1045
1046 if (start) {
1047 index++; /* JobFiles not incremented yet */
1048 }
1049 Dmsg1(debuglevel, "SendPluginName=%s\n", sp->cmd);
1050
1051 /*
1052 * Send stream header
1053 */
1054 if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
1055 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
1056 return false;
1057 }
1058 Dmsg1(debuglevel, "send plugin name hdr: %s\n", sd->msg);
1059
1060 if (start) {
1061 /*
1062 * Send data -- not much
1063 */
1064 status = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
1065 } else {
1066 /*
1067 * Send end of data
1068 */
1069 status = sd->fsend("%ld 0", jcr->JobFiles);
1070 }
1071 if (!status) {
1072 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
1073 return false;
1074 }
1075 Dmsg1(debuglevel, "send plugin start/end: %s\n", sd->msg);
1076 sd->signal(BNET_EOD); /* indicate end of plugin name data */
1077
1078 return true;
1079 }
1080
1081 /**
1082 * Plugin name stream found during restore. The record passed in argument name was
1083 * generated in SendPluginName() above.
1084 *
1085 * Returns: true if start of stream
1086 * false if end of steam
1087 */
PluginNameStream(JobControlRecord * jcr,char * name)1088 bool PluginNameStream(JobControlRecord *jcr, char *name)
1089 {
1090 int len;
1091 char *cmd;
1092 char *p = name;
1093 bool start;
1094 bpContext *ctx = nullptr;
1095 alist *plugin_ctx_list;
1096
1097 Dmsg1(debuglevel, "Read plugin stream string=%s\n", name);
1098 SkipNonspaces(&p); /* skip over jcr->JobFiles */
1099 SkipSpaces(&p);
1100 start = *p == '1';
1101 if (start) {
1102 /*
1103 * Start of plugin data
1104 */
1105 SkipNonspaces(&p); /* skip start/end flag */
1106 SkipSpaces(&p);
1107 SkipNonspaces(&p); /* skip portable flag */
1108 SkipSpaces(&p);
1109 cmd = p;
1110 } else {
1111 /*
1112 * End of plugin data, notify plugin, then clear flags
1113 */
1114 if (jcr->plugin_ctx) {
1115 Plugin *plugin = jcr->plugin_ctx->plugin;
1116 b_plugin_ctx *b_ctx = (b_plugin_ctx *)jcr->plugin_ctx->bContext;
1117
1118 Dmsg2(debuglevel, "End plugin data plugin=%p ctx=%p\n", plugin, jcr->plugin_ctx);
1119 if (b_ctx->restoreFileStarted) {
1120 PlugFunc(plugin)->endRestoreFile(jcr->plugin_ctx);
1121 }
1122 b_ctx->restoreFileStarted = false;
1123 b_ctx->createFileCalled = false;
1124 }
1125
1126 goto bail_out;
1127 }
1128
1129 plugin_ctx_list = jcr->plugin_ctx_list;
1130 if (!plugin_ctx_list) {
1131 goto bail_out;
1132 }
1133
1134 /*
1135 * After this point, we are dealing with a restore start
1136 */
1137 if (!GetPluginName(jcr, cmd, &len)) {
1138 goto bail_out;
1139 }
1140
1141 /*
1142 * Search for correct plugin as specified on the command
1143 */
1144 foreach_alist(ctx, plugin_ctx_list) {
1145 bEvent event;
1146 bEventType eventType;
1147 b_plugin_ctx *b_ctx;
1148
1149 Dmsg3(debuglevel, "plugin=%s cmd=%s len=%d\n", ctx->plugin->file, cmd, len);
1150 if (!for_thIsPlugin(ctx->plugin, cmd, len)) {
1151 continue;
1152 }
1153
1154 if (IsPluginDisabled(ctx)) {
1155 Dmsg1(debuglevel, "Plugin %s disabled\n", cmd);
1156 goto bail_out;
1157 }
1158
1159 Dmsg1(debuglevel, "Restore Command plugin = %s\n", cmd);
1160 eventType = bEventRestoreCommand;
1161 event.eventType = eventType;
1162
1163 if (!IsEventEnabled(ctx, eventType)) {
1164 Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
1165 continue;
1166 }
1167
1168 jcr->plugin_ctx = ctx;
1169 jcr->cmd_plugin = true;
1170 b_ctx = (b_plugin_ctx *)ctx->bContext;
1171
1172 if (PlugFunc(ctx->plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
1173 Dmsg1(debuglevel, "Handle event failed. Plugin=%s\n", cmd);
1174 goto bail_out;
1175 }
1176
1177 if (b_ctx->restoreFileStarted) {
1178 Jmsg2(jcr, M_FATAL, 0, "Second call to startRestoreFile. plugin=%s cmd=%s\n", ctx->plugin->file, cmd);
1179 b_ctx->restoreFileStarted = false;
1180 goto bail_out;
1181 }
1182
1183 if (PlugFunc(ctx->plugin)->startRestoreFile(jcr->plugin_ctx, cmd) == bRC_OK) {
1184 b_ctx->restoreFileStarted = true;
1185 goto bail_out;
1186 } else {
1187 Dmsg1(debuglevel, "startRestoreFile failed. plugin=%s\n", cmd);
1188 goto bail_out;
1189 }
1190 }
1191 Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
1192
1193 bail_out:
1194 return start;
1195 }
1196
1197 /**
1198 * Tell the plugin to create the file. this is called only during Restore.
1199 * Return values are:
1200 *
1201 * CF_ERROR -> error
1202 * CF_SKIP -> skip processing this file
1203 * CF_EXTRACT -> extract the file (i.e.call i/o routines)
1204 * CF_CREATED -> created, but no content to extract (typically directories)
1205 */
PluginCreateFile(JobControlRecord * jcr,Attributes * attr,BareosWinFilePacket * bfd,int replace)1206 int PluginCreateFile(JobControlRecord *jcr, Attributes *attr, BareosWinFilePacket *bfd, int replace)
1207 {
1208 int flags;
1209 int retval;
1210 int status;
1211 Plugin *plugin;
1212 struct restore_pkt rp;
1213 bpContext *ctx = jcr->plugin_ctx;
1214 b_plugin_ctx *b_ctx = (b_plugin_ctx *)jcr->plugin_ctx->bContext;
1215
1216 if (!ctx || !SetCmdPlugin(bfd, jcr) || jcr->IsJobCanceled()) {
1217 return CF_ERROR;
1218 }
1219 plugin = ctx->plugin;
1220
1221 rp.pkt_size = sizeof(rp);
1222 rp.pkt_end = sizeof(rp);
1223 rp.delta_seq = attr->delta_seq;
1224 rp.stream = attr->stream;
1225 rp.data_stream = attr->data_stream;
1226 rp.type = attr->type;
1227 rp.file_index = attr->file_index;
1228 rp.LinkFI = attr->LinkFI;
1229 rp.uid = attr->uid;
1230 memcpy(&rp.statp, &attr->statp, sizeof(rp.statp));
1231 rp.attrEx = attr->attrEx;
1232 rp.ofname = attr->ofname;
1233 rp.olname = attr->olname;
1234 rp.where = jcr->where;
1235 rp.RegexWhere = jcr->RegexWhere;
1236 rp.replace = jcr->replace;
1237 rp.create_status = CF_ERROR;
1238
1239 Dmsg4(debuglevel, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n",
1240 rp.stream, rp.type, rp.LinkFI, rp.ofname);
1241 if (rp.attrEx) {
1242 Dmsg1(debuglevel, "attrEx=\"%s\"\n", rp.attrEx);
1243 }
1244
1245 if (!b_ctx->restoreFileStarted || b_ctx->createFileCalled) {
1246 Jmsg2(jcr, M_FATAL, 0, "Unbalanced call to createFile=%d %d\n",
1247 b_ctx->createFileCalled, b_ctx->restoreFileStarted);
1248 b_ctx->createFileCalled = false;
1249 return CF_ERROR;
1250 }
1251
1252 retval = PlugFunc(plugin)->createFile(ctx, &rp);
1253 if (retval != bRC_OK) {
1254 Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"), retval, attr->ofname);
1255 return CF_ERROR;
1256 }
1257
1258 switch (rp.create_status) {
1259 case CF_ERROR:
1260 Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"), attr->ofname);
1261 /*
1262 * FALLTHROUGH
1263 */
1264 case CF_SKIP:
1265 /*
1266 * FALLTHROUGH
1267 */
1268 case CF_CORE:
1269 /*
1270 * FALLTHROUGH
1271 */
1272 case CF_CREATED:
1273 return rp.create_status;
1274 }
1275
1276 flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
1277 Dmsg0(debuglevel, "call bopen\n");
1278
1279 status = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR, attr->statp.st_rdev);
1280 Dmsg1(debuglevel, "bopen status=%d\n", status);
1281
1282 if (status < 0) {
1283 BErrNo be;
1284
1285 be.SetErrno(bfd->BErrNo);
1286 Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
1287 attr->ofname, be.bstrerror());
1288 Dmsg2(debuglevel,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
1289 return CF_ERROR;
1290 }
1291
1292 if (!IsBopen(bfd)) {
1293 Dmsg0(000, "===== BFD is not open!!!!\n");
1294 }
1295
1296 return CF_EXTRACT;
1297 }
1298
1299 /**
1300 * Reset the file attributes after all file I/O is done -- this allows the previous access time/dates
1301 * to be set properly, and it also allows us to properly set directory permissions.
1302 */
PluginSetAttributes(JobControlRecord * jcr,Attributes * attr,BareosWinFilePacket * ofd)1303 bool PluginSetAttributes(JobControlRecord *jcr, Attributes *attr, BareosWinFilePacket *ofd)
1304 {
1305 Plugin *plugin;
1306 struct restore_pkt rp;
1307
1308 Dmsg0(debuglevel, "PluginSetAttributes\n");
1309
1310 if (!jcr->plugin_ctx) {
1311 return false;
1312 }
1313 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1314
1315 memset(&rp, 0, sizeof(rp));
1316 rp.pkt_size = sizeof(rp);
1317 rp.pkt_end = sizeof(rp);
1318 rp.stream = attr->stream;
1319 rp.data_stream = attr->data_stream;
1320 rp.type = attr->type;
1321 rp.file_index = attr->file_index;
1322 rp.LinkFI = attr->LinkFI;
1323 rp.uid = attr->uid;
1324 memcpy(&rp.statp, &attr->statp, sizeof(rp.statp));
1325 rp.attrEx = attr->attrEx;
1326 rp.ofname = attr->ofname;
1327 rp.olname = attr->olname;
1328 rp.where = jcr->where;
1329 rp.RegexWhere = jcr->RegexWhere;
1330 rp.replace = jcr->replace;
1331 rp.create_status = CF_ERROR;
1332
1333 PlugFunc(plugin)->setFileAttributes(jcr->plugin_ctx, &rp);
1334
1335 if (rp.create_status == CF_CORE) {
1336 SetAttributes(jcr, attr, ofd);
1337 } else {
1338 if (IsBopen(ofd)) {
1339 bclose(ofd);
1340 }
1341 PmStrcpy(attr->ofname, "*None*");
1342 }
1343
1344 return true;
1345 }
1346
1347 /**
1348 * Plugin specific callback for getting ACL information.
1349 */
PluginBuildAclStreams(JobControlRecord * jcr,acl_data_t * acl_data,FindFilesPacket * ff_pkt)1350 bacl_exit_code PluginBuildAclStreams(JobControlRecord *jcr,
1351 acl_data_t *acl_data,
1352 FindFilesPacket *ff_pkt)
1353 {
1354 Plugin *plugin;
1355
1356 Dmsg0(debuglevel, "PluginBuildAclStreams\n");
1357
1358 if (!jcr->plugin_ctx) {
1359 return bacl_exit_ok;
1360 }
1361 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1362
1363 if (PlugFunc(plugin)->getAcl == NULL) {
1364 return bacl_exit_ok;
1365 } else {
1366 bacl_exit_code retval = bacl_exit_error;
1367 #if defined(HAVE_ACL)
1368 struct acl_pkt ap;
1369
1370 memset(&ap, 0, sizeof(ap));
1371 ap.pkt_size = ap.pkt_end = sizeof(struct acl_pkt);
1372 ap.fname = acl_data->last_fname;
1373
1374 switch (PlugFunc(plugin)->getAcl(jcr->plugin_ctx, &ap)) {
1375 case bRC_OK:
1376 if (ap.content_length && ap.content) {
1377 acl_data->u.build->content = CheckPoolMemorySize(acl_data->u.build->content, ap.content_length);
1378 memcpy(acl_data->u.build->content, ap.content, ap.content_length);
1379 acl_data->u.build->content_length = ap.content_length;
1380 free(ap.content);
1381 retval = SendAclStream(jcr, acl_data, STREAM_ACL_PLUGIN);
1382 } else {
1383 retval = bacl_exit_ok;
1384 }
1385 break;
1386 default:
1387 break;
1388 }
1389 #endif
1390
1391 return retval;
1392 }
1393 }
1394
1395 /**
1396 * Plugin specific callback for setting ACL information.
1397 */
plugin_parse_acl_streams(JobControlRecord * jcr,acl_data_t * acl_data,int stream,char * content,uint32_t content_length)1398 bacl_exit_code plugin_parse_acl_streams(JobControlRecord *jcr,
1399 acl_data_t *acl_data,
1400 int stream,
1401 char *content,
1402 uint32_t content_length)
1403 {
1404 Plugin *plugin;
1405
1406 Dmsg0(debuglevel, "plugin_parse_acl_streams\n");
1407
1408 if (!jcr->plugin_ctx) {
1409 return bacl_exit_ok;
1410 }
1411 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1412
1413 if (PlugFunc(plugin)->setAcl == NULL) {
1414 return bacl_exit_error;
1415 } else {
1416 bacl_exit_code retval = bacl_exit_error;
1417 #if defined(HAVE_ACL)
1418 struct acl_pkt ap;
1419
1420 memset(&ap, 0, sizeof(ap));
1421 ap.pkt_size = ap.pkt_end = sizeof(struct acl_pkt);
1422 ap.fname = acl_data->last_fname;
1423 ap.content = content;
1424 ap.content_length = content_length;
1425
1426 switch (PlugFunc(plugin)->setAcl(jcr->plugin_ctx, &ap)) {
1427 case bRC_OK:
1428 retval = bacl_exit_ok;
1429 break;
1430 default:
1431 break;
1432 }
1433 #endif
1434
1435 return retval;
1436 }
1437 }
1438
1439 /**
1440 * Plugin specific callback for getting XATTR information.
1441 */
PluginBuildXattrStreams(JobControlRecord * jcr,struct xattr_data_t * xattr_data,FindFilesPacket * ff_pkt)1442 BxattrExitCode PluginBuildXattrStreams(JobControlRecord *jcr,
1443 struct xattr_data_t *xattr_data,
1444 FindFilesPacket *ff_pkt)
1445 {
1446 Plugin *plugin;
1447 #if defined(HAVE_XATTR)
1448 alist *xattr_value_list = NULL;
1449 #endif
1450 BxattrExitCode retval = BxattrExitCode::kError;
1451
1452 Dmsg0(debuglevel, "PluginBuildXattrStreams\n");
1453
1454 if (!jcr->plugin_ctx) {
1455 return BxattrExitCode::kSuccess;
1456 }
1457 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1458
1459 if (PlugFunc(plugin)->getXattr == NULL) {
1460 return BxattrExitCode::kSuccess;
1461 } else {
1462 #if defined(HAVE_XATTR)
1463 bool more;
1464 int xattr_count = 0;
1465 xattr_t *current_xattr;
1466 struct xattr_pkt xp;
1467 uint32_t expected_serialize_len = 0;
1468
1469 while (1) {
1470 memset(&xp, 0, sizeof(xp));
1471 xp.pkt_size = xp.pkt_end = sizeof(struct xattr_pkt);
1472 xp.fname = xattr_data->last_fname;
1473
1474 switch (PlugFunc(plugin)->getXattr(jcr->plugin_ctx, &xp)) {
1475 case bRC_OK:
1476 more = false;
1477 break;
1478 case bRC_More:
1479 more = true;
1480 break;
1481 default:
1482 goto bail_out;
1483 }
1484
1485 /*
1486 * Make sure the plugin filled a XATTR name.
1487 * The name and value returned by the plugin need to be in allocated memory
1488 * and are freed by XattrDropInternalTable() function when we are done
1489 * processing the data.
1490 */
1491 if (xp.name_length && xp.name) {
1492 /*
1493 * Each xattr valuepair starts with a magic so we can parse it easier.
1494 */
1495 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1496 current_xattr->magic = XATTR_MAGIC;
1497 expected_serialize_len += sizeof(current_xattr->magic);
1498
1499 current_xattr->name_length = xp.name_length;
1500 current_xattr->name = xp.name;
1501 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1502
1503 current_xattr->value_length = xp.value_length;
1504 current_xattr->value = xp.value;
1505 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1506
1507 if (xattr_value_list == NULL) {
1508 xattr_value_list = New(alist(10, not_owned_by_alist));
1509 }
1510
1511 xattr_value_list->append(current_xattr);
1512 xattr_count++;
1513
1514 /*
1515 * Protect ourself against things getting out of hand.
1516 */
1517 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1518 Mmsg2(jcr->errmsg,
1519 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1520 xattr_data->last_fname, MAX_XATTR_STREAM);
1521 goto bail_out;
1522 }
1523 }
1524
1525 /*
1526 * Does the plugin have more xattrs ?
1527 */
1528 if (!more) {
1529 break;
1530 }
1531 }
1532
1533 /*
1534 * If we found any xattr send them to the SD.
1535 */
1536 if (xattr_count > 0) {
1537 /*
1538 * Serialize the datastream.
1539 */
1540 if (SerializeXattrStream(jcr,
1541 xattr_data,
1542 expected_serialize_len,
1543 xattr_value_list) < expected_serialize_len) {
1544 Mmsg1(jcr->errmsg,
1545 _("Failed to Serialize extended attributes on file \"%s\"\n"),
1546 xattr_data->last_fname);
1547 Dmsg1(100, "Failed to Serialize extended attributes on file \"%s\"\n",
1548 xattr_data->last_fname);
1549 goto bail_out;
1550 }
1551
1552 /*
1553 * Send the datastream to the SD.
1554 */
1555 retval = SendXattrStream(jcr, xattr_data, STREAM_XATTR_PLUGIN);
1556 } else {
1557 retval = BxattrExitCode::kSuccess;
1558 }
1559 #endif
1560 }
1561
1562 #if defined(HAVE_XATTR)
1563 bail_out:
1564 if (xattr_value_list) {
1565 XattrDropInternalTable(xattr_value_list);
1566 }
1567 #endif
1568
1569 return retval;
1570 }
1571
1572 /**
1573 * Plugin specific callback for setting XATTR information.
1574 */
PluginParseXattrStreams(JobControlRecord * jcr,struct xattr_data_t * xattr_data,int stream,char * content,uint32_t content_length)1575 BxattrExitCode PluginParseXattrStreams(JobControlRecord *jcr,
1576 struct xattr_data_t *xattr_data,
1577 int stream,
1578 char *content,
1579 uint32_t content_length)
1580 {
1581 #if defined(HAVE_XATTR)
1582 Plugin *plugin;
1583 alist *xattr_value_list = NULL;
1584 #endif
1585 BxattrExitCode retval = BxattrExitCode::kError;
1586
1587 Dmsg0(debuglevel, "PluginParseXattrStreams\n");
1588
1589 if (!jcr->plugin_ctx) {
1590 return BxattrExitCode::kSuccess;
1591 }
1592
1593 #if defined(HAVE_XATTR)
1594 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1595 if (PlugFunc(plugin)->setXattr != NULL) {
1596 xattr_t *current_xattr = nullptr;
1597 struct xattr_pkt xp;
1598
1599 xattr_value_list = New(alist(10, not_owned_by_alist));
1600
1601 if (UnSerializeXattrStream(jcr,
1602 xattr_data,
1603 content,
1604 content_length,
1605 xattr_value_list) != BxattrExitCode::kSuccess) {
1606 goto bail_out;
1607 }
1608
1609 memset(&xp, 0, sizeof(xp));
1610 xp.pkt_size = xp.pkt_end = sizeof(struct xattr_pkt);
1611 xp.fname = xattr_data->last_fname;
1612
1613 foreach_alist(current_xattr, xattr_value_list) {
1614 xp.name = current_xattr->name;
1615 xp.name_length = current_xattr->name_length;
1616 xp.value = current_xattr->value;
1617 xp.value_length = current_xattr->value_length;
1618
1619 switch (PlugFunc(plugin)->setXattr(jcr->plugin_ctx, &xp)) {
1620 case bRC_OK:
1621 break;
1622 default:
1623 goto bail_out;
1624 }
1625 }
1626
1627 retval = BxattrExitCode::kSuccess;
1628 }
1629
1630 bail_out:
1631 if (xattr_value_list) {
1632 XattrDropInternalTable(xattr_value_list);
1633 }
1634 #endif
1635
1636 return retval;
1637 }
1638
1639 /**
1640 * Print to file the plugin info.
1641 */
DumpFdPlugin(Plugin * plugin,FILE * fp)1642 static void DumpFdPlugin(Plugin *plugin, FILE *fp)
1643 {
1644 genpInfo *info;
1645
1646 if (!plugin) {
1647 return ;
1648 }
1649
1650 info = (genpInfo *)plugin->pinfo;
1651 fprintf(fp, "\tversion=%d\n", info->version);
1652 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
1653 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
1654 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
1655 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
1656 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
1657 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
1658 }
1659
DumpFdPlugins(FILE * fp)1660 static void DumpFdPlugins(FILE *fp)
1661 {
1662 DumpPlugins(fd_plugin_list, fp);
1663 }
1664
1665 /**
1666 * This entry point is called internally by Bareos to ensure that the plugin IO calls come into this code.
1667 */
LoadFdPlugins(const char * plugin_dir,alist * plugin_names)1668 void LoadFdPlugins(const char *plugin_dir, alist *plugin_names)
1669 {
1670 Plugin *plugin;
1671 int i;
1672
1673 if (!plugin_dir) {
1674 Dmsg0(debuglevel, "plugin dir is NULL\n");
1675 return;
1676 }
1677
1678 fd_plugin_list = New(alist(10, not_owned_by_alist));
1679 if (!LoadPlugins((void *)&binfo, (void *)&bfuncs, fd_plugin_list,
1680 plugin_dir, plugin_names, plugin_type, IsPluginCompatible)) {
1681 /*
1682 * Either none found, or some error
1683 */
1684 if (fd_plugin_list->size() == 0) {
1685 delete fd_plugin_list;
1686 fd_plugin_list = NULL;
1687 Dmsg0(debuglevel, "No plugins loaded\n");
1688 return;
1689 }
1690 }
1691
1692 /*
1693 * Plug entry points called from findlib
1694 */
1695 plugin_bopen = MyPluginBopen;
1696 plugin_bclose = MyPluginBclose;
1697 plugin_bread = MyPluginBread;
1698 plugin_bwrite = MyPluginBwrite;
1699 plugin_blseek = MyPluginBlseek;
1700
1701 /*
1702 * Verify that the plugin is acceptable, and print information about it.
1703 */
1704 foreach_alist_index(i, plugin, fd_plugin_list) {
1705 Dmsg1(debuglevel, "Loaded plugin: %s\n", plugin->file);
1706 }
1707
1708 DbgPluginAddHook(DumpFdPlugin);
1709 DbgPrintPluginAddHook(DumpFdPlugins);
1710 }
1711
UnloadFdPlugins(void)1712 void UnloadFdPlugins(void)
1713 {
1714 UnloadPlugins(fd_plugin_list);
1715 delete fd_plugin_list;
1716 fd_plugin_list = NULL;
1717 }
1718
ListFdPlugins(PoolMem & msg)1719 int ListFdPlugins(PoolMem &msg)
1720 {
1721 return ListPlugins(fd_plugin_list, msg);
1722 }
1723
1724 /**
1725 * Check if a plugin is compatible. Called by the load_plugin function to allow us to verify the plugin.
1726 */
IsPluginCompatible(Plugin * plugin)1727 static bool IsPluginCompatible(Plugin *plugin)
1728 {
1729 genpInfo *info = (genpInfo *)plugin->pinfo;
1730 Dmsg0(debuglevel, "IsPluginCompatible called\n");
1731 if (debug_level >= 50) {
1732 DumpFdPlugin(plugin, stdin);
1733 }
1734 if (!bstrcmp(info->plugin_magic, FD_PLUGIN_MAGIC)) {
1735 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
1736 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1737 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
1738 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1739
1740 return false;
1741 }
1742 if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
1743 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
1744 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1745 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
1746 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1747 return false;
1748 }
1749 if (!Bstrcasecmp(info->plugin_license, "Bareos AGPLv3") &&
1750 !Bstrcasecmp(info->plugin_license, "AGPLv3")) {
1751 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
1752 plugin->file, info->plugin_license);
1753 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
1754 plugin->file, info->plugin_license);
1755 return false;
1756 }
1757 if (info->size != sizeof(genpInfo)) {
1758 Jmsg(NULL, M_ERROR, 0,
1759 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
1760 plugin->file, sizeof(genpInfo), info->size);
1761 return false;
1762 }
1763
1764 return true;
1765 }
1766
1767 /**
1768 * Instantiate a new plugin instance.
1769 */
instantiate_plugin(JobControlRecord * jcr,Plugin * plugin,char instance)1770 static inline bpContext *instantiate_plugin(JobControlRecord *jcr, Plugin *plugin, char instance)
1771 {
1772 bpContext *ctx;
1773 b_plugin_ctx *b_ctx;
1774
1775 b_ctx = (b_plugin_ctx *)malloc(sizeof(b_plugin_ctx));
1776 b_ctx = (b_plugin_ctx *)memset(b_ctx, 0, sizeof(b_plugin_ctx));
1777 b_ctx->jcr = jcr;
1778 b_ctx->plugin = plugin;
1779
1780 ctx = (bpContext *)malloc(sizeof(bpContext));
1781 ctx->instance = instance;
1782 ctx->plugin = plugin;
1783 ctx->bContext = (void *)b_ctx;
1784 ctx->pContext = NULL;
1785
1786 jcr->plugin_ctx_list->append(ctx);
1787
1788 if (PlugFunc(plugin)->newPlugin(ctx) != bRC_OK) {
1789 b_ctx->disabled = true;
1790 }
1791
1792 return ctx;
1793 }
1794
1795 /**
1796 * Create a new instance of each plugin for this Job
1797 *
1798 * Note, fd_plugin_list can exist but jcr->plugin_ctx_list can be NULL if no plugins were loaded.
1799 */
NewPlugins(JobControlRecord * jcr)1800 void NewPlugins(JobControlRecord *jcr)
1801 {
1802 int i, num;
1803 Plugin *plugin;
1804
1805 if (!fd_plugin_list) {
1806 Dmsg0(debuglevel, "plugin list is NULL\n");
1807 return;
1808 }
1809
1810 if (jcr->IsJobCanceled()) {
1811 return;
1812 }
1813
1814 num = fd_plugin_list->size();
1815 if (num == 0) {
1816 Dmsg0(debuglevel, "No plugins loaded\n");
1817 return;
1818 }
1819
1820 jcr->plugin_ctx_list = New(alist(10, owned_by_alist));
1821 Dmsg2(debuglevel, "Instantiate plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
1822 foreach_alist_index(i, plugin, fd_plugin_list) {
1823 /*
1824 * Start a new instance of each plugin
1825 */
1826 instantiate_plugin(jcr, plugin, 0);
1827 }
1828 }
1829
1830 /**
1831 * Free the plugin instances for this Job
1832 */
FreePlugins(JobControlRecord * jcr)1833 void FreePlugins(JobControlRecord *jcr)
1834 {
1835 bpContext *ctx = nullptr;
1836
1837 if (!fd_plugin_list || !jcr->plugin_ctx_list) {
1838 return;
1839 }
1840
1841 Dmsg2(debuglevel, "Free instance fd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
1842 foreach_alist(ctx, jcr->plugin_ctx_list) {
1843 /*
1844 * Free the plugin instance
1845 */
1846 PlugFunc(ctx->plugin)->freePlugin(ctx);
1847 free(ctx->bContext); /* Free BAREOS private context */
1848 }
1849
1850 delete jcr->plugin_ctx_list;
1851 jcr->plugin_ctx_list = NULL;
1852 }
1853
1854 /**
1855 * Entry point for opening the file this is a wrapper around the pluginIO entry point in the plugin.
1856 */
MyPluginBopen(BareosWinFilePacket * bfd,const char * fname,int flags,mode_t mode)1857 static int MyPluginBopen(BareosWinFilePacket *bfd, const char *fname, int flags, mode_t mode)
1858 {
1859 Plugin *plugin;
1860 struct io_pkt io;
1861 JobControlRecord *jcr = bfd->jcr;
1862
1863 Dmsg1(debuglevel, "plugin_bopen flags=%08o\n", flags);
1864 if (!jcr->plugin_ctx) {
1865 return 0;
1866 }
1867 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1868
1869 memset(&io, 0, sizeof(io));
1870 io.pkt_size = sizeof(io);
1871 io.pkt_end = sizeof(io);
1872
1873 io.func = IO_OPEN;
1874 io.fname = fname;
1875 io.flags = flags;
1876 io.mode = mode;
1877
1878 PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1879 bfd->BErrNo = io.io_errno;
1880
1881 if (io.win32) {
1882 errno = b_errno_win32;
1883 } else {
1884 errno = io.io_errno;
1885 bfd->lerror = io.lerror;
1886 }
1887
1888 Dmsg1(debuglevel, "Return from plugin open status=%d\n", io.status);
1889
1890 return io.status;
1891 }
1892
1893 /**
1894 * Entry point for closing the file this is a wrapper around the pluginIO entry point in the plugin.
1895 */
MyPluginBclose(BareosWinFilePacket * bfd)1896 static int MyPluginBclose(BareosWinFilePacket *bfd)
1897 {
1898 Plugin *plugin;
1899 struct io_pkt io;
1900 JobControlRecord *jcr = bfd->jcr;
1901
1902 Dmsg0(debuglevel, "===== plugin_bclose\n");
1903 if (!jcr->plugin_ctx) {
1904 return 0;
1905 }
1906 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1907
1908 memset(&io, 0, sizeof(io));
1909 io.pkt_size = sizeof(io);
1910 io.pkt_end = sizeof(io);
1911
1912 io.func = IO_CLOSE;
1913
1914 PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1915 bfd->BErrNo = io.io_errno;
1916
1917 if (io.win32) {
1918 errno = b_errno_win32;
1919 } else {
1920 errno = io.io_errno;
1921 bfd->lerror = io.lerror;
1922 }
1923
1924 Dmsg1(debuglevel, "plugin_bclose stat=%d\n", io.status);
1925
1926 return io.status;
1927 }
1928
1929 /**
1930 * Entry point for reading from the file this is a wrapper around the pluginIO entry point in the plugin.
1931 */
MyPluginBread(BareosWinFilePacket * bfd,void * buf,size_t count)1932 static ssize_t MyPluginBread(BareosWinFilePacket *bfd, void *buf, size_t count)
1933 {
1934 Plugin *plugin;
1935 struct io_pkt io;
1936 JobControlRecord *jcr = bfd->jcr;
1937
1938 Dmsg0(debuglevel, "plugin_bread\n");
1939 if (!jcr->plugin_ctx) {
1940 return 0;
1941 }
1942 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1943
1944 memset(&io, 0, sizeof(io));
1945 io.pkt_size = sizeof(io);
1946 io.pkt_end = sizeof(io);
1947
1948 io.func = IO_READ;
1949 io.count = count;
1950 io.buf = (char *)buf;
1951
1952 PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1953 bfd->offset = io.offset;
1954 bfd->BErrNo = io.io_errno;
1955
1956 if (io.win32) {
1957 errno = b_errno_win32;
1958 } else {
1959 errno = io.io_errno;
1960 bfd->lerror = io.lerror;
1961 }
1962
1963 return (ssize_t)io.status;
1964 }
1965
1966 /**
1967 * Entry point for writing to the file this is a wrapper around the pluginIO entry point in the plugin.
1968 */
MyPluginBwrite(BareosWinFilePacket * bfd,void * buf,size_t count)1969 static ssize_t MyPluginBwrite(BareosWinFilePacket *bfd, void *buf, size_t count)
1970 {
1971 Plugin *plugin;
1972 struct io_pkt io;
1973 JobControlRecord *jcr = bfd->jcr;
1974
1975 Dmsg0(debuglevel, "plugin_bwrite\n");
1976 if (!jcr->plugin_ctx) {
1977 Dmsg0(0, "No plugin context\n");
1978 return 0;
1979 }
1980 plugin = (Plugin *)jcr->plugin_ctx->plugin;
1981
1982 memset(&io, 0, sizeof(io));
1983 io.pkt_size = sizeof(io);
1984 io.pkt_end = sizeof(io);
1985
1986 io.func = IO_WRITE;
1987 io.count = count;
1988 io.buf = (char *)buf;
1989
1990 PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
1991 bfd->BErrNo = io.io_errno;
1992
1993 if (io.win32) {
1994 errno = b_errno_win32;
1995 } else {
1996 errno = io.io_errno;
1997 bfd->lerror = io.lerror;
1998 }
1999
2000 return (ssize_t)io.status;
2001 }
2002
2003 /**
2004 * Entry point for seeking in the file this is a wrapper around the pluginIO entry point in the plugin.
2005 */
MyPluginBlseek(BareosWinFilePacket * bfd,boffset_t offset,int whence)2006 static boffset_t MyPluginBlseek(BareosWinFilePacket *bfd, boffset_t offset, int whence)
2007 {
2008 Plugin *plugin;
2009 struct io_pkt io;
2010 JobControlRecord *jcr = bfd->jcr;
2011
2012 Dmsg0(debuglevel, "plugin_bseek\n");
2013 if (!jcr->plugin_ctx) {
2014 return 0;
2015 }
2016 plugin = (Plugin *)jcr->plugin_ctx->plugin;
2017
2018 io.pkt_size = sizeof(io);
2019 io.pkt_end = sizeof(io);
2020 io.func = IO_SEEK;
2021 io.offset = offset;
2022 io.whence = whence;
2023 io.win32 = false;
2024 io.lerror = 0;
2025 PlugFunc(plugin)->pluginIO(jcr->plugin_ctx, &io);
2026 bfd->BErrNo = io.io_errno;
2027 if (io.win32) {
2028 errno = b_errno_win32;
2029 } else {
2030 errno = io.io_errno;
2031 bfd->lerror = io.lerror;
2032 }
2033
2034 return (boffset_t)io.offset;
2035 }
2036
2037 /* ==============================================================
2038 *
2039 * Callbacks from the plugin
2040 *
2041 * ==============================================================
2042 */
bareosGetValue(bpContext * ctx,bVariable var,void * value)2043 static bRC bareosGetValue(bpContext *ctx, bVariable var, void *value)
2044 {
2045 JobControlRecord *jcr = NULL;
2046 if (!value) {
2047 return bRC_Error;
2048 }
2049
2050 switch (var) { /* General variables, no need of ctx */
2051 case bVarFDName:
2052 *((char **)value) = my_name;
2053 break;
2054 case bVarWorkingDir:
2055 *(void **)value = me->working_directory;
2056 break;
2057 case bVarExePath:
2058 *(char **)value = exepath;
2059 break;
2060 case bVarVersion:
2061 *(char **)value = version;
2062 break;
2063 case bVarDistName:
2064 *(char **)value = dist_name;
2065 break;
2066 default:
2067 if (!ctx) { /* Other variables need context */
2068 return bRC_Error;
2069 }
2070
2071 jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2072 if (!jcr) {
2073 return bRC_Error;
2074 }
2075 break;
2076 }
2077
2078 if (jcr) {
2079 switch (var) {
2080 case bVarJobId:
2081 *((int *)value) = jcr->JobId;
2082 Dmsg1(debuglevel, "fd-plugin: return bVarJobId=%d\n", jcr->JobId);
2083 break;
2084 case bVarLevel:
2085 *((int *)value) = jcr->getJobLevel();
2086 Dmsg1(debuglevel, "fd-plugin: return bVarJobLevel=%d\n", jcr->getJobLevel());
2087 break;
2088 case bVarType:
2089 *((int *)value) = jcr->getJobType();
2090 Dmsg1(debuglevel, "fd-plugin: return bVarJobType=%d\n", jcr->getJobType());
2091 break;
2092 case bVarClient:
2093 *((char **)value) = jcr->client_name;
2094 Dmsg1(debuglevel, "fd-plugin: return bVarClient=%s\n", NPRT(*((char **)value)));
2095 break;
2096 case bVarJobName:
2097 *((char **)value) = jcr->Job;
2098 Dmsg1(debuglevel, "fd-plugin: return bVarJobName=%s\n", NPRT(*((char **)value)));
2099 break;
2100 case bVarPrevJobName:
2101 *((char **)value) = jcr->PrevJob;
2102 Dmsg1(debuglevel, "fd-plugin: return bVarPrevJobName=%s\n", NPRT(*((char **)value)));
2103 break;
2104 case bVarJobStatus:
2105 *((int *)value) = jcr->JobStatus;
2106 Dmsg1(debuglevel, "fd-plugin: return bVarJobStatus=%d\n", jcr->JobStatus);
2107 break;
2108 case bVarSinceTime:
2109 *((int *)value) = (int)jcr->mtime;
2110 Dmsg1(debuglevel, "fd-plugin: return bVarSinceTime=%d\n", (int)jcr->mtime);
2111 break;
2112 case bVarAccurate:
2113 *((int *)value) = (int)jcr->accurate;
2114 Dmsg1(debuglevel, "fd-plugin: return bVarAccurate=%d\n", (int)jcr->accurate);
2115 break;
2116 case bVarFileSeen:
2117 break; /* a write only variable, ignore read request */
2118 case bVarVssClient:
2119 #ifdef HAVE_WIN32
2120 if (jcr->pVSSClient) {
2121 *(void **)value = jcr->pVSSClient;
2122 Dmsg1(debuglevel, "fd-plugin: return bVarVssClient=%p\n", *(void **)value);
2123 break;
2124 }
2125 #endif
2126 return bRC_Error;
2127 case bVarWhere:
2128 *(char **)value = jcr->where;
2129 Dmsg1(debuglevel, "fd-plugin: return bVarWhere=%s\n", NPRT(*((char **)value)));
2130 break;
2131 case bVarRegexWhere:
2132 *(char **)value = jcr->RegexWhere;
2133 Dmsg1(debuglevel, "fd-plugin: return bVarRegexWhere=%s\n", NPRT(*((char **)value)));
2134 break;
2135 case bVarPrefixLinks:
2136 *(int *)value = (int)jcr->prefix_links;
2137 Dmsg1(debuglevel, "fd-plugin: return bVarPrefixLinks=%d\n", (int)jcr->prefix_links);
2138 break;
2139 default:
2140 break;
2141 }
2142 }
2143
2144 return bRC_OK;
2145 }
2146
bareosSetValue(bpContext * ctx,bVariable var,void * value)2147 static bRC bareosSetValue(bpContext *ctx, bVariable var, void *value)
2148 {
2149 JobControlRecord *jcr;
2150
2151 if (!value || !ctx) {
2152 return bRC_Error;
2153 }
2154
2155 jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2156 if (!jcr) {
2157 return bRC_Error;
2158 }
2159
2160 switch (var) {
2161 case bVarLevel:
2162 jcr->setJobLevel(*(int *)value);
2163 break;
2164 case bVarFileSeen:
2165 if (!AccurateMarkFileAsSeen(jcr, (char *)value)) {
2166 return bRC_Error;
2167 }
2168 break;
2169 default:
2170 break;
2171 }
2172
2173 return bRC_OK;
2174 }
2175
bareosRegisterEvents(bpContext * ctx,int nr_events,...)2176 static bRC bareosRegisterEvents(bpContext *ctx, int nr_events, ...)
2177 {
2178 int i;
2179 va_list args;
2180 uint32_t event;
2181 b_plugin_ctx *b_ctx;
2182
2183 if (!ctx) {
2184 return bRC_Error;
2185 }
2186 b_ctx = (b_plugin_ctx *)ctx->bContext;
2187
2188 va_start(args, nr_events);
2189 for (i = 0; i < nr_events; i++) {
2190 event = va_arg(args, uint32_t);
2191 Dmsg1(debuglevel, "fd-plugin: Plugin registered event=%u\n", event);
2192 SetBit(event, b_ctx->events);
2193 }
2194 va_end(args);
2195
2196 return bRC_OK;
2197 }
2198
2199 /**
2200 * Get the number of instaces instantiated of a certain plugin.
2201 */
bareosGetInstanceCount(bpContext * ctx,int * ret)2202 static bRC bareosGetInstanceCount(bpContext *ctx, int *ret)
2203 {
2204 int cnt;
2205 JobControlRecord *jcr, *njcr;
2206 bpContext *nctx;
2207 b_plugin_ctx *bctx;
2208 bRC retval = bRC_Error;
2209
2210 if (!IsCtxGood(ctx, jcr, bctx)) {
2211 goto bail_out;
2212 }
2213
2214 P(mutex);
2215
2216 cnt = 0;
2217 foreach_jcr(njcr) {
2218 if (jcr->plugin_ctx_list) {
2219 foreach_alist(nctx, jcr->plugin_ctx_list) {
2220 if (nctx->plugin == bctx->plugin) {
2221 cnt++;
2222 }
2223 }
2224 }
2225 }
2226 endeach_jcr(njcr);
2227
2228 V(mutex);
2229
2230 *ret = cnt;
2231 retval = bRC_OK;
2232
2233 bail_out:
2234 return retval;
2235 }
2236
bareosUnRegisterEvents(bpContext * ctx,int nr_events,...)2237 static bRC bareosUnRegisterEvents(bpContext *ctx, int nr_events, ...)
2238 {
2239 int i;
2240 va_list args;
2241 uint32_t event;
2242 b_plugin_ctx *b_ctx;
2243
2244 if (!ctx) {
2245 return bRC_Error;
2246 }
2247 b_ctx = (b_plugin_ctx *)ctx->bContext;
2248
2249 va_start(args, nr_events);
2250 for (i = 0; i < nr_events; i++) {
2251 event = va_arg(args, uint32_t);
2252 Dmsg1(debuglevel, "fd-plugin: Plugin unregistered event=%u\n", event);
2253 ClearBit(event, b_ctx->events);
2254 }
2255 va_end(args);
2256
2257 return bRC_OK;
2258 }
2259
bareosJobMsg(bpContext * ctx,const char * fname,int line,int type,utime_t mtime,const char * fmt,...)2260 static bRC bareosJobMsg(bpContext *ctx, const char *fname, int line,
2261 int type, utime_t mtime, const char *fmt, ...)
2262 {
2263 JobControlRecord *jcr;
2264 va_list arg_ptr;
2265 PoolMem buffer(PM_MESSAGE);
2266
2267 if (ctx) {
2268 jcr = ((b_plugin_ctx *)ctx->bContext)->jcr;
2269 } else {
2270 jcr = NULL;
2271 }
2272
2273 va_start(arg_ptr, fmt);
2274 buffer.Bvsprintf(fmt, arg_ptr);
2275 va_end(arg_ptr);
2276 Jmsg(jcr, type, mtime, "%s", buffer.c_str());
2277
2278 return bRC_OK;
2279 }
2280
bareosDebugMsg(bpContext * ctx,const char * fname,int line,int level,const char * fmt,...)2281 static bRC bareosDebugMsg(bpContext *ctx, const char *fname, int line,
2282 int level, const char *fmt, ...)
2283 {
2284 va_list arg_ptr;
2285 PoolMem buffer(PM_MESSAGE);
2286
2287 va_start(arg_ptr, fmt);
2288 buffer.Bvsprintf(fmt, arg_ptr);
2289 va_end(arg_ptr);
2290 d_msg(fname, line, level, "%s", buffer.c_str());
2291
2292 return bRC_OK;
2293 }
2294
bareosMalloc(bpContext * ctx,const char * fname,int line,size_t size)2295 static void *bareosMalloc(bpContext *ctx, const char *fname, int line, size_t size)
2296 {
2297 #ifdef SMARTALLOC
2298 return sm_malloc(fname, line, size);
2299 #else
2300 return malloc(size);
2301 #endif
2302 }
2303
bareosFree(bpContext * ctx,const char * fname,int line,void * mem)2304 static void bareosFree(bpContext *ctx, const char *fname, int line, void *mem)
2305 {
2306 #ifdef SMARTALLOC
2307 sm_free(fname, line, mem);
2308 #else
2309 free(mem);
2310 #endif
2311 }
2312
2313 /**
2314 * Let the plugin define files/directories to be excluded from the main backup.
2315 */
bareosAddExclude(bpContext * ctx,const char * fname)2316 static bRC bareosAddExclude(bpContext *ctx, const char *fname)
2317 {
2318 JobControlRecord *jcr;
2319 findIncludeExcludeItem *old;
2320 b_plugin_ctx *bctx;
2321
2322 if (!IsCtxGood(ctx, jcr, bctx)) {
2323 return bRC_Error;
2324 }
2325 if (!fname) {
2326 return bRC_Error;
2327 }
2328
2329 /*
2330 * Save the include context
2331 */
2332 old = get_incexe(jcr);
2333
2334 /*
2335 * Not right time to add exlude
2336 */
2337 if (!old) {
2338 return bRC_Error;
2339 }
2340
2341 if (!bctx->exclude) {
2342 bctx->exclude = new_exclude(jcr->ff->fileset);
2343 }
2344
2345 /*
2346 * Set the Exclude context
2347 */
2348 SetIncexe(jcr, bctx->exclude);
2349
2350 AddFileToFileset(jcr, fname, true);
2351
2352 /*
2353 * Restore the current context
2354 */
2355 SetIncexe(jcr, old);
2356
2357 Dmsg1(100, "Add exclude file=%s\n", fname);
2358
2359 return bRC_OK;
2360 }
2361
2362 /**
2363 * Let the plugin define files/directories to be excluded from the main backup.
2364 */
bareosAddInclude(bpContext * ctx,const char * fname)2365 static bRC bareosAddInclude(bpContext *ctx, const char *fname)
2366 {
2367 JobControlRecord *jcr;
2368 findIncludeExcludeItem *old;
2369 b_plugin_ctx *bctx;
2370
2371 if (!IsCtxGood(ctx, jcr, bctx)) {
2372 return bRC_Error;
2373 }
2374
2375 if (!fname) {
2376 return bRC_Error;
2377 }
2378
2379 /*
2380 * Save the include context
2381 */
2382 old = get_incexe(jcr);
2383
2384 /*
2385 * Not right time to add include
2386 */
2387 if (!old) {
2388 return bRC_Error;
2389 }
2390
2391 if (!bctx->include) {
2392 bctx->include = old;
2393 }
2394
2395 SetIncexe(jcr, bctx->include);
2396 AddFileToFileset(jcr, fname, true);
2397
2398 /*
2399 * Restore the current context
2400 */
2401 SetIncexe(jcr, old);
2402
2403 Dmsg1(100, "Add include file=%s\n", fname);
2404
2405 return bRC_OK;
2406 }
2407
bareosAddOptions(bpContext * ctx,const char * opts)2408 static bRC bareosAddOptions(bpContext *ctx, const char *opts)
2409 {
2410 JobControlRecord *jcr;
2411 b_plugin_ctx *bctx;
2412
2413 if (!IsCtxGood(ctx, jcr, bctx)) {
2414 return bRC_Error;
2415 }
2416
2417 if (!opts) {
2418 return bRC_Error;
2419 }
2420 AddOptionsToFileset(jcr, opts);
2421 Dmsg1(1000, "Add options=%s\n", opts);
2422
2423 return bRC_OK;
2424 }
2425
bareosAddRegex(bpContext * ctx,const char * item,int type)2426 static bRC bareosAddRegex(bpContext *ctx, const char *item, int type)
2427 {
2428 JobControlRecord *jcr;
2429 b_plugin_ctx *bctx;
2430
2431 if (!IsCtxGood(ctx, jcr, bctx)) {
2432 return bRC_Error;
2433 }
2434
2435 if (!item) {
2436 return bRC_Error;
2437 }
2438 AddRegexToFileset(jcr, item, type);
2439 Dmsg1(100, "Add regex=%s\n", item);
2440
2441 return bRC_OK;
2442 }
2443
bareosAddWild(bpContext * ctx,const char * item,int type)2444 static bRC bareosAddWild(bpContext *ctx, const char *item, int type)
2445 {
2446 JobControlRecord *jcr;
2447 b_plugin_ctx *bctx;
2448
2449 if (!IsCtxGood(ctx, jcr, bctx)) {
2450 return bRC_Error;
2451 }
2452
2453 if (!item) {
2454 return bRC_Error;
2455 }
2456 AddWildToFileset(jcr, item, type);
2457 Dmsg1(100, "Add wild=%s\n", item);
2458
2459 return bRC_OK;
2460 }
2461
bareosNewOptions(bpContext * ctx)2462 static bRC bareosNewOptions(bpContext *ctx)
2463 {
2464 JobControlRecord *jcr;
2465 b_plugin_ctx *bctx;
2466
2467 if (!IsCtxGood(ctx, jcr, bctx)) {
2468 return bRC_Error;
2469 }
2470 (void)NewOptions(jcr->ff, jcr->ff->fileset->incexe);
2471
2472 return bRC_OK;
2473 }
2474
bareosNewInclude(bpContext * ctx)2475 static bRC bareosNewInclude(bpContext *ctx)
2476 {
2477 JobControlRecord *jcr;
2478 b_plugin_ctx *bctx;
2479
2480 if (!IsCtxGood(ctx, jcr, bctx)) {
2481 return bRC_Error;
2482 }
2483 (void)new_include(jcr->ff->fileset);
2484
2485 return bRC_OK;
2486 }
2487
bareosNewPreInclude(bpContext * ctx)2488 static bRC bareosNewPreInclude(bpContext *ctx)
2489 {
2490 JobControlRecord *jcr;
2491 b_plugin_ctx *bctx;
2492
2493 if (!IsCtxGood(ctx, jcr, bctx)) {
2494 return bRC_Error;
2495 }
2496
2497 bctx->include = new_preinclude(jcr->ff->fileset);
2498 NewOptions(jcr->ff, bctx->include);
2499 SetIncexe(jcr, bctx->include);
2500
2501 return bRC_OK;
2502 }
2503
2504 /**
2505 * Check if a file have to be backuped using Accurate code
2506 */
bareosCheckChanges(bpContext * ctx,struct save_pkt * sp)2507 static bRC bareosCheckChanges(bpContext *ctx, struct save_pkt *sp)
2508 {
2509 JobControlRecord *jcr;
2510 b_plugin_ctx *bctx;
2511 FindFilesPacket *ff_pkt;
2512 bRC retval = bRC_Error;
2513
2514 if (!IsCtxGood(ctx, jcr, bctx)) {
2515 goto bail_out;
2516 }
2517
2518 if (!sp) {
2519 goto bail_out;
2520 }
2521
2522 ff_pkt = jcr->ff;
2523 /*
2524 * Copy fname and link because SaveFile() zaps them.
2525 * This avoids zaping the plugin's strings.
2526 */
2527 ff_pkt->type = sp->type;
2528 if (!sp->fname) {
2529 Jmsg0(jcr, M_FATAL, 0, _("Command plugin: no fname in bareosCheckChanges packet.\n"));
2530 goto bail_out;
2531 }
2532
2533 ff_pkt->fname = sp->fname;
2534 ff_pkt->link = sp->link;
2535 if (sp->save_time) {
2536 ff_pkt->save_time = sp->save_time;
2537 ff_pkt->incremental = true;
2538 }
2539 memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
2540
2541 if (CheckChanges(jcr, ff_pkt)) {
2542 retval = bRC_OK;
2543 } else {
2544 retval = bRC_Seen;
2545 }
2546
2547 /*
2548 * CheckChanges() can update delta sequence number, return it to the plugin
2549 */
2550 sp->delta_seq = ff_pkt->delta_seq;
2551 sp->accurate_found = ff_pkt->accurate_found;
2552
2553 bail_out:
2554 Dmsg1(100, "checkChanges=%i\n", retval);
2555 return retval;
2556 }
2557
2558 /**
2559 * Check if a file would be saved using current Include/Exclude code
2560 */
bareosAcceptFile(bpContext * ctx,struct save_pkt * sp)2561 static bRC bareosAcceptFile(bpContext *ctx, struct save_pkt *sp)
2562 {
2563 JobControlRecord *jcr;
2564 FindFilesPacket *ff_pkt;
2565 b_plugin_ctx *bctx;
2566 bRC retval = bRC_Error;
2567
2568 if (!IsCtxGood(ctx, jcr, bctx)) {
2569 goto bail_out;
2570 }
2571 if (!sp) {
2572 goto bail_out;
2573 }
2574
2575 ff_pkt = jcr->ff;
2576
2577 ff_pkt->fname = sp->fname;
2578 memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
2579
2580 if (AcceptFile(ff_pkt)) {
2581 retval = bRC_OK;
2582 } else {
2583 retval = bRC_Skip;
2584 }
2585
2586 bail_out:
2587 return retval;
2588 }
2589
2590 /**
2591 * Manipulate the accurate seen bitmap for setting bits
2592 */
bareosSetSeenBitmap(bpContext * ctx,bool all,char * fname)2593 static bRC bareosSetSeenBitmap(bpContext *ctx, bool all, char *fname)
2594 {
2595 JobControlRecord *jcr;
2596 b_plugin_ctx *bctx;
2597 bRC retval = bRC_Error;
2598
2599 if (!IsCtxGood(ctx, jcr, bctx)) {
2600 goto bail_out;
2601 }
2602
2603 if (all && fname) {
2604 Dmsg0(debuglevel, "fd-plugin: API error in call to SetSeenBitmap, both all and fname set!!!\n");
2605 goto bail_out;
2606 }
2607
2608 if (all) {
2609 if (AccurateMarkAllFilesAsSeen(jcr)) {
2610 retval = bRC_OK;
2611 }
2612 } else if (fname) {
2613 if (AccurateMarkFileAsSeen(jcr, fname)) {
2614 retval = bRC_OK;
2615 }
2616 }
2617
2618 bail_out:
2619 return retval;
2620 }
2621
2622 /**
2623 * Manipulate the accurate seen bitmap for clearing bits
2624 */
bareosClearSeenBitmap(bpContext * ctx,bool all,char * fname)2625 static bRC bareosClearSeenBitmap(bpContext *ctx, bool all, char *fname)
2626 {
2627 JobControlRecord *jcr;
2628 b_plugin_ctx *bctx;
2629 bRC retval = bRC_Error;
2630
2631 if (!IsCtxGood(ctx, jcr, bctx)) {
2632 goto bail_out;
2633 }
2634
2635 if (all && fname) {
2636 Dmsg0(debuglevel, "fd-plugin: API error in call to ClearSeenBitmap, both all and fname set!!!\n");
2637 goto bail_out;
2638 }
2639
2640 if (all) {
2641 if (accurate_unMarkAllFilesAsSeen(jcr)) {
2642 retval = bRC_OK;
2643 }
2644 } else if (fname) {
2645 if (accurate_unMarkFileAsSeen(jcr, fname)) {
2646 retval = bRC_OK;
2647 }
2648 }
2649
2650 bail_out:
2651 return retval;
2652 }
2653
2654 #ifdef TEST_PROGRAM
2655 /* Exported variables */
2656 ClientResource *me; /* my resource */
2657
SaveFile(JobControlRecord * jcr,FindFilesPacket * ff_pkt,bool top_level)2658 int SaveFile(JobControlRecord *jcr, FindFilesPacket *ff_pkt, bool top_level)
2659 {
2660 return 0;
2661 }
2662
AccurateMarkFileAsSeen(JobControlRecord * jcr,char * fname)2663 bool AccurateMarkFileAsSeen(JobControlRecord *jcr, char *fname)
2664 {
2665 return true;
2666 }
2667
SetCmdPlugin(BareosWinFilePacket * bfd,JobControlRecord * jcr)2668 bool SetCmdPlugin(BareosWinFilePacket *bfd, JobControlRecord *jcr)
2669 {
2670 return true;
2671 }
2672
main(int argc,char * argv[])2673 int main(int argc, char *argv[])
2674 {
2675 char plugin_dir[PATH_MAX];
2676 JobControlRecord mjcr1, mjcr2;
2677 JobControlRecord *jcr1 = &mjcr1;
2678 JobControlRecord *jcr2 = &mjcr2;
2679
2680 MyNameIs(argc, argv, "plugtest");
2681 InitMsg(NULL, NULL);
2682
2683 OSDependentInit();
2684
2685 if (argc != 1) {
2686 bstrncpy(plugin_dir, argv[1], sizeof(plugin_dir));
2687 } else {
2688 getcwd(plugin_dir, sizeof(plugin_dir)-1);
2689 }
2690 LoadFdPlugins(plugin_dir, NULL);
2691
2692 jcr1->JobId = 111;
2693 NewPlugins(jcr1);
2694
2695 jcr2->JobId = 222;
2696 NewPlugins(jcr2);
2697
2698 GeneratePluginEvent(jcr1, bEventJobStart, (void *)"Start Job 1");
2699 GeneratePluginEvent(jcr1, bEventJobEnd);
2700 GeneratePluginEvent(jcr2, bEventJobStart, (void *)"Start Job 2");
2701 FreePlugins(jcr1);
2702 GeneratePluginEvent(jcr2, bEventJobEnd);
2703 FreePlugins(jcr2);
2704
2705 UnloadFdPlugins();
2706
2707 Dmsg0(debuglevel, "bareos: OK ...\n");
2708
2709 TermMsg();
2710 CloseMemoryPool();
2711 LmgrCleanupMain();
2712 sm_dump(false);
2713 exit(0);
2714 }
2715
2716 #endif /* TEST_PROGRAM */
2717 } /* namespace filedaemon */
2718