2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation, which is
11 listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU 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
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main program to test loading and running Bacula plugins.
30 * Destined to become Bacula pluginloader, ...
32 * Kern Sibbald, October 2007
37 const int dbglvl = 150;
39 const char *plugin_type = "-fd.dll";
41 const char *plugin_type = "-fd.so";
44 extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
46 /* Function pointers to be set here */
47 extern DLL_IMP_EXP int (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode);
48 extern DLL_IMP_EXP int (*plugin_bclose)(BFILE *bfd);
49 extern DLL_IMP_EXP ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count);
50 extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count);
51 extern DLL_IMP_EXP boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence);
54 /* Forward referenced functions */
55 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
56 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
57 static bRC baculaRegisterEvents(bpContext *ctx, ...);
58 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
59 int type, utime_t mtime, const char *fmt, ...);
60 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
61 int level, const char *fmt, ...);
62 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
64 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem);
65 static bRC baculaAddExclude(bpContext *ctx, const char *file);
66 static bool is_plugin_compatible(Plugin *plugin);
69 * These will be plugged into the global pointer structure for
72 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode);
73 static int my_plugin_bclose(BFILE *bfd);
74 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count);
75 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count);
76 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence);
80 static bInfo binfo = {
82 FD_PLUGIN_INTERFACE_VERSION
85 /* Bacula entry points */
86 static bFuncs bfuncs = {
88 FD_PLUGIN_INTERFACE_VERSION,
100 * Bacula private context
103 JCR *jcr; /* jcr for plugin */
104 bRC rc; /* last return code */
105 bool disabled; /* set if plugin disabled */
106 findFILESET *fileset; /* pointer to exclude files */
109 static bool is_plugin_disabled(JCR *jcr)
112 if (!jcr->plugin_ctx) {
115 b_ctx = (bacula_ctx *)jcr->plugin_ctx->bContext;
116 return b_ctx->disabled;
121 * Create a plugin event
123 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
129 if (!plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
130 return; /* Return if no plugins loaded */
133 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
134 event.eventType = eventType;
136 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
138 /* Pass event to every plugin */
139 foreach_alist(plugin, plugin_list) {
141 jcr->plugin_ctx = &plugin_ctx_list[i++];
142 jcr->plugin = plugin;
143 if (is_plugin_disabled(jcr)) {
146 rc = plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, value);
153 jcr->plugin_ctx = NULL;
158 * Check if file was seen for accurate
160 bool plugin_check_file(JCR *jcr, char *fname)
166 if (!plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
167 return false; /* Return if no plugins loaded */
170 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
172 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
174 /* Pass event to every plugin */
175 foreach_alist(plugin, plugin_list) {
176 jcr->plugin_ctx = &plugin_ctx_list[i++];
177 jcr->plugin = plugin;
178 if (is_plugin_disabled(jcr)) {
181 if (plug_func(plugin)->checkFile == NULL) {
184 rc = plug_func(plugin)->checkFile(jcr->plugin_ctx, fname);
185 if (rc == bRC_Seen) {
191 jcr->plugin_ctx = NULL;
192 return rc == bRC_Seen;
197 * Sequence of calls for a backup:
198 * 1. plugin_save() here is called with ff_pkt
199 * 2. we find the plugin requested on the command string
200 * 3. we generate a bEventBackupCommand event to the specified plugin
201 * and pass it the command string.
202 * 4. we make a startPluginBackup call to the plugin, which gives
203 * us the data we need in save_pkt
204 * 5. we call Bacula's save_file() subroutine to save the specified
205 * file. The plugin will be called at pluginIO() to supply the
208 * Sequence of calls for restore:
209 * See subroutine plugin_name_stream() below.
211 int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
217 char *cmd = ff_pkt->top_fname;
220 POOL_MEM fname(PM_FNAME);
221 POOL_MEM link(PM_FNAME);
223 if (!plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
224 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not loaded.\n", cmd);
225 return 1; /* Return if no plugins loaded */
228 jcr->cmd_plugin = true;
229 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
230 event.eventType = bEventBackupCommand;
232 /* Handle plugin command here backup */
233 Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
234 if (!(p = strchr(cmd, ':'))) {
235 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
243 /* Note, we stop the loop on the first plugin that matches the name */
244 foreach_alist(plugin, plugin_list) {
245 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
246 if (strncmp(plugin->file, cmd, len) != 0) {
251 * We put the current plugin pointer, and the plugin context
252 * into the jcr, because during save_file(), the plugin
253 * will be called many times and these values are needed.
255 jcr->plugin_ctx = &plugin_ctx_list[i];
256 jcr->plugin = plugin;
257 if (is_plugin_disabled(jcr)) {
261 Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
262 /* Send the backup command to the right plugin*/
263 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
266 /* Loop getting filenames to backup then saving them */
267 while (!jcr->is_job_canceled()) {
268 memset(&sp, 0, sizeof(sp));
269 sp.pkt_size = sizeof(sp);
270 sp.pkt_end = sizeof(sp);
273 Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
275 /* Get the file save parameters. I.e. the stat pkt ... */
276 if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) {
279 if (sp.type == 0 || sp.fname == NULL) {
280 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\" returned bad startBackupFile packet.\n"),
284 jcr->plugin_sp = &sp;
287 * Copy fname and link because save_file() zaps them. This
288 * avoids zaping the plugin's strings.
290 pm_strcpy(fname, sp.fname);
291 pm_strcpy(link, sp.link);
292 ff_pkt->fname = fname.c_str();
293 ff_pkt->link = link.c_str();
294 ff_pkt->type = sp.type;
295 if (sp.type == FT_RESTORE_FIRST) {
296 ff_pkt->LinkFI = sp.index; /* restore object index */
297 ff_pkt->object = sp.object;
298 ff_pkt->object_len = sp.object_len;
300 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
301 Dmsg2(dbglvl, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
303 Dmsg2(dbglvl, "index=%d object=%s\n", sp.index, sp.object);
305 /* Call Bacula core code to backup the plugin's file */
306 save_file(jcr, ff_pkt, true);
307 bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx);
308 if (rc == bRC_More || rc == bRC_OK) {
309 accurate_mark_file_as_seen(jcr, fname.c_str());
311 if (rc == bRC_More) {
318 Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
321 jcr->cmd_plugin = false;
323 jcr->plugin_ctx = NULL;
328 * Send plugin name start/end record to SD
330 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
333 int index = jcr->JobFiles;
334 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
337 Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
340 if (jcr->is_job_canceled()) {
345 index++; /* JobFiles not incremented yet */
347 Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
348 /* Send stream header */
349 if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
350 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
354 Dmsg1(50, "send plugin name hdr: %s\n", sd->msg);
357 /* Send data -- not much */
358 stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
360 /* Send end of data */
361 stat = sd->fsend("0 0");
364 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
368 Dmsg1(dbglvl, "send plugin start/end: %s\n", sd->msg);
369 sd->signal(BNET_EOD); /* indicate end of plugin name data */
374 * Plugin name stream found during restore. The record passed in
375 * argument name was generated in send_plugin_name() above.
377 * Returns: true if start of stream
378 * false if end of steam
380 bool plugin_name_stream(JCR *jcr, char *name)
384 bool start, portable;
388 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
390 Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
391 skip_nonspaces(&p); /* skip over jcr->JobFiles */
395 /* Start of plugin data */
396 skip_nonspaces(&p); /* skip start/end flag */
398 portable = *p == '1';
399 skip_nonspaces(&p); /* skip portable flag */
404 * End of plugin data, notify plugin, then clear flags
406 Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
408 plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
410 jcr->plugin_ctx = NULL;
414 if (!plugin_ctx_list) {
419 * After this point, we are dealing with a restore start
422 // Dmsg1(dbglvl, "plugin restore cmd=%s\n", cmd);
423 if (!(p = strchr(cmd, ':'))) {
424 Jmsg1(jcr, M_ERROR, 0,
425 _("Malformed plugin command. Name not terminated by colon: %s\n"), cmd);
434 * Search for correct plugin as specified on the command
436 foreach_alist(plugin, plugin_list) {
438 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
439 if (strncmp(plugin->file, cmd, len) != 0) {
443 jcr->plugin_ctx = &plugin_ctx_list[i];
444 jcr->plugin = plugin;
445 if (is_plugin_disabled(jcr)) {
448 Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
449 event.eventType = bEventRestoreCommand;
450 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
451 &event, cmd) != bRC_OK) {
454 /* ***FIXME**** check error code */
455 plug_func(plugin)->startRestoreFile((bpContext *)jcr->plugin_ctx, cmd);
458 Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
465 * Tell the plugin to create the file. Return values are
466 * This is called only during Restore
469 * CF_SKIP -- skip processing this file
470 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
471 * CF_CREATED -- created, but no content to extract (typically directories)
474 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
476 bpContext *plugin_ctx = jcr->plugin_ctx;
477 Plugin *plugin = jcr->plugin;
478 struct restore_pkt rp;
482 if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr) || jcr->is_job_canceled()) {
486 rp.pkt_size = sizeof(rp);
487 rp.pkt_end = sizeof(rp);
488 rp.stream = attr->stream;
489 rp.data_stream = attr->data_stream;
490 rp.type = attr->type;
491 rp.file_index = attr->file_index;
492 rp.LinkFI = attr->LinkFI;
494 rp.statp = attr->statp; /* structure assignment */
495 rp.attrEx = attr->attrEx;
496 rp.ofname = attr->ofname;
497 rp.olname = attr->olname;
498 rp.where = jcr->where;
499 rp.RegexWhere = jcr->RegexWhere;
500 rp.replace = jcr->replace;
501 rp.create_status = CF_ERROR;
502 Dmsg4(dbglvl, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n",
503 rp.stream, rp.type, rp.LinkFI, rp.ofname);
505 Dmsg1(dbglvl, "attrEx=\"%s\"\n", rp.attrEx);
507 rc = plug_func(plugin)->createFile(plugin_ctx, &rp);
509 Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"),
513 if (rp.create_status == CF_ERROR) {
514 Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
518 /* Created link or directory? */
519 if (rp.create_status == CF_CREATED) {
520 return rp.create_status; /* yes, no need to bopen */
523 flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
524 Dmsg0(dbglvl, "call bopen\n");
525 int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR);
526 Dmsg1(50, "bopen status=%d\n", stat);
529 be.set_errno(bfd->berrno);
530 Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
531 attr->ofname, be.bstrerror());
532 Dmsg2(dbglvl,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
536 if (!is_bopen(bfd)) {
537 Dmsg0(000, "===== BFD is not open!!!!\n");
543 * Reset the file attributes after all file I/O is done -- this allows
544 * the previous access time/dates to be set properly, and it also allows
545 * us to properly set directory permissions.
546 * Not currently Implemented.
548 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
550 Dmsg0(dbglvl, "plugin_set_attributes\n");
554 pm_strcpy(attr->ofname, "*none*");
559 * Print to file the plugin info.
561 void dump_fd_plugin(Plugin *plugin, FILE *fp)
566 pInfo *info = (pInfo *)plugin->pinfo;
567 fprintf(fp, "\tversion=%d\n", info->version);
568 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
569 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
570 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
571 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
572 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
573 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
577 * This entry point is called internally by Bacula to ensure
578 * that the plugin IO calls come into this code.
580 void load_fd_plugins(const char *plugin_dir)
585 Dmsg0(dbglvl, "plugin dir is NULL\n");
589 plugin_list = New(alist(10, not_owned_by_alist));
590 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
591 is_plugin_compatible)) {
592 /* Either none found, or some error */
593 if (plugin_list->size() == 0) {
596 Dmsg0(dbglvl, "No plugins loaded\n");
601 /* Plug entry points called from findlib */
602 plugin_bopen = my_plugin_bopen;
603 plugin_bclose = my_plugin_bclose;
604 plugin_bread = my_plugin_bread;
605 plugin_bwrite = my_plugin_bwrite;
606 plugin_blseek = my_plugin_blseek;
609 * Verify that the plugin is acceptable, and print information
612 foreach_alist(plugin, plugin_list) {
613 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
614 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
617 dbg_plugin_add_hook(dump_fd_plugin);
621 * Check if a plugin is compatible. Called by the load_plugin function
622 * to allow us to verify the plugin.
624 static bool is_plugin_compatible(Plugin *plugin)
626 pInfo *info = (pInfo *)plugin->pinfo;
627 Dmsg0(50, "is_plugin_compatible called\n");
628 if (debug_level >= 50) {
629 dump_fd_plugin(plugin, stdin);
631 if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) {
632 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
633 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
634 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
635 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
639 if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
640 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
641 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
642 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
643 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
646 if (strcmp(info->plugin_license, "Bacula GPLv2") != 0 &&
647 strcmp(info->plugin_license, "GPLv2") != 0) {
648 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
649 plugin->file, info->plugin_license);
650 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
651 plugin->file, info->plugin_license);
660 * Create a new instance of each plugin for this Job
661 * Note, plugin_list can exist but jcr->plugin_ctx_list can
662 * be NULL if no plugins were loaded.
664 void new_plugins(JCR *jcr)
670 Dmsg0(dbglvl, "plugin list is NULL\n");
673 if (jcr->is_job_canceled() || jcr->JobId == 0) {
677 int num = plugin_list->size();
680 Dmsg0(dbglvl, "No plugins loaded\n");
684 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
686 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
687 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
688 foreach_alist(plugin, plugin_list) {
689 /* Start a new instance of each plugin */
690 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
691 memset(b_ctx, 0, sizeof(bacula_ctx));
693 plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */
694 plugin_ctx_list[i].pContext = NULL;
695 if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
696 b_ctx->disabled = true;
702 * Free the plugin instances for this Job
704 void free_plugins(JCR *jcr)
709 if (!plugin_list || !jcr->plugin_ctx_list) {
710 return; /* no plugins, nothing to do */
713 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
714 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
715 foreach_alist(plugin, plugin_list) {
716 /* Free the plugin instance */
717 plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
718 free(plugin_ctx_list[i++].bContext); /* free Bacula private context */
720 free(plugin_ctx_list);
721 jcr->plugin_ctx_list = NULL;
724 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
727 Plugin *plugin = (Plugin *)jcr->plugin;
730 Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags);
731 if (!plugin || !jcr->plugin_ctx) {
734 io.pkt_size = sizeof(io);
735 io.pkt_end = sizeof(io);
744 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
745 bfd->berrno = io.io_errno;
747 errno = b_errno_win32;
750 bfd->lerror = io.lerror;
752 Dmsg1(50, "Return from plugin open status=%d\n", io.status);
756 static int my_plugin_bclose(BFILE *bfd)
759 Plugin *plugin = (Plugin *)jcr->plugin;
762 Dmsg0(dbglvl, "===== plugin_bclose\n");
763 if (!plugin || !jcr->plugin_ctx) {
766 io.pkt_size = sizeof(io);
767 io.pkt_end = sizeof(io);
773 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
774 bfd->berrno = io.io_errno;
776 errno = b_errno_win32;
779 bfd->lerror = io.lerror;
781 Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status);
785 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
788 Plugin *plugin = (Plugin *)jcr->plugin;
791 Dmsg0(dbglvl, "plugin_bread\n");
792 if (!plugin || !jcr->plugin_ctx) {
795 io.pkt_size = sizeof(io);
796 io.pkt_end = sizeof(io);
799 io.buf = (char *)buf;
802 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
803 bfd->berrno = io.io_errno;
805 errno = b_errno_win32;
808 bfd->lerror = io.lerror;
810 return (ssize_t)io.status;
813 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
816 Plugin *plugin = (Plugin *)jcr->plugin;
819 Dmsg0(dbglvl, "plugin_bwrite\n");
820 if (!plugin || !jcr->plugin_ctx) {
823 io.pkt_size = sizeof(io);
824 io.pkt_end = sizeof(io);
827 io.buf = (char *)buf;
830 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
831 bfd->berrno = io.io_errno;
833 errno = b_errno_win32;
836 bfd->lerror = io.lerror;
838 return (ssize_t)io.status;
841 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
844 Plugin *plugin = (Plugin *)jcr->plugin;
847 Dmsg0(dbglvl, "plugin_bseek\n");
848 if (!plugin || !jcr->plugin_ctx) {
851 io.pkt_size = sizeof(io);
852 io.pkt_end = sizeof(io);
858 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
859 bfd->berrno = io.io_errno;
861 errno = b_errno_win32;
864 bfd->lerror = io.lerror;
866 return (boffset_t)io.offset;
869 /* ==============================================================
871 * Callbacks from the plugin
873 * ==============================================================
875 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
878 if (!value || !ctx) {
881 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
882 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
886 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
889 *((int *)value) = jcr->JobId;
890 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
893 *((char **)value) = my_name;
894 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
897 *((int *)value) = jcr->getJobLevel();
898 Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->getJobLevel());
901 *((int *)value) = jcr->getJobType();
902 Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->getJobType());
905 *((char **)value) = jcr->client_name;
906 Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name);
909 *((char **)value) = jcr->Job;
910 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
913 *((int *)value) = jcr->JobStatus;
914 Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus);
917 *((int *)value) = (int)jcr->mtime;
918 Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime);
921 *((int *)value) = (int)jcr->accurate;
922 Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate);
925 break; /* a write only variable, ignore read request */
929 *(void **)value = g_pVSSClient->GetVssObject();
934 case bVarVssDllHandle:
937 *(void **)value = g_pVSSClient->GetVssDllHandle();
946 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
949 if (!value || !ctx) {
952 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
953 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
957 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
960 if (!accurate_mark_file_as_seen(jcr, (char *)value)) {
970 static bRC baculaRegisterEvents(bpContext *ctx, ...)
980 while ((event = va_arg(args, uint32_t))) {
981 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
987 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
988 int type, utime_t mtime, const char *fmt, ...)
995 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
1000 va_start(arg_ptr, fmt);
1001 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
1003 Jmsg(jcr, type, mtime, "%s", buf);
1007 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
1008 int level, const char *fmt, ...)
1013 va_start(arg_ptr, fmt);
1014 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
1016 d_msg(file, line, level, "%s", buf);
1020 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
1024 return sm_malloc(file, line, size);
1026 return malloc(size);
1030 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem)
1033 sm_free(file, line, mem);
1040 * Let the plugin define files/directories to be excluded
1041 * from the main backup.
1043 static bRC baculaAddExclude(bpContext *ctx, const char *file)
1053 bctx = (bacula_ctx *)ctx->bContext;
1061 if (!bctx->fileset) {
1062 bctx->fileset = new_exclude(jcr);
1064 add_file_to_fileset(jcr, file, bctx->fileset, true);
1071 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
1072 int (*plugin_bclose)(JCR *jcr) = NULL;
1073 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
1074 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
1075 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
1077 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
1082 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
1087 int main(int argc, char *argv[])
1089 char plugin_dir[1000];
1094 strcpy(my_name, "test-fd");
1096 getcwd(plugin_dir, sizeof(plugin_dir)-1);
1097 load_fd_plugins(plugin_dir);
1105 generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
1106 generate_plugin_event(jcr1, bEventJobEnd);
1107 generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
1109 generate_plugin_event(jcr2, bEventJobEnd);
1114 Dmsg0(dbglvl, "bacula: OK ...\n");
1115 close_memory_pool();
1120 #endif /* TEST_PROGRAM */