2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2009 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 bool is_plugin_compatible(Plugin *plugin);
68 * These will be plugged into the global pointer structure for
71 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode);
72 static int my_plugin_bclose(BFILE *bfd);
73 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count);
74 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count);
75 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence);
79 static bInfo binfo = {
81 FD_PLUGIN_INTERFACE_VERSION
84 /* Bacula entry points */
85 static bFuncs bfuncs = {
87 FD_PLUGIN_INTERFACE_VERSION,
98 * Bacula private context
101 JCR *jcr; /* jcr for plugin */
102 bRC rc; /* last return code */
103 bool disabled; /* set if plugin disabled */
106 static bool is_plugin_disabled(JCR *jcr)
109 if (!jcr->plugin_ctx) {
112 b_ctx = (bacula_ctx *)jcr->plugin_ctx->bContext;
113 return b_ctx->disabled;
118 * Create a plugin event
120 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
126 if (!plugin_list || !jcr || !jcr->plugin_ctx_list) {
127 return; /* Return if no plugins loaded */
130 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
131 event.eventType = eventType;
133 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
135 /* Pass event to every plugin */
136 foreach_alist(plugin, plugin_list) {
138 jcr->plugin_ctx = &plugin_ctx_list[i++];
139 jcr->plugin = plugin;
140 if (is_plugin_disabled(jcr)) {
143 rc = plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, value);
150 jcr->plugin_ctx = NULL;
155 * Check if file was seen for accurate
157 bool plugin_check_file(JCR *jcr, char *fname)
163 if (!plugin_list || !jcr || !jcr->plugin_ctx_list) {
164 return false; /* Return if no plugins loaded */
167 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
169 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
171 /* Pass event to every plugin */
172 foreach_alist(plugin, plugin_list) {
173 jcr->plugin_ctx = &plugin_ctx_list[i++];
174 jcr->plugin = plugin;
175 if (is_plugin_disabled(jcr)) {
178 if (plug_func(plugin)->checkFile == NULL) {
181 rc = plug_func(plugin)->checkFile(jcr->plugin_ctx, fname);
182 if (rc == bRC_Seen) {
188 jcr->plugin_ctx = NULL;
189 return rc == bRC_Seen;
194 * Sequence of calls for a backup:
195 * 1. plugin_save() here is called with ff_pkt
196 * 2. we find the plugin requested on the command string
197 * 3. we generate a bEventBackupCommand event to the specified plugin
198 * and pass it the command string.
199 * 4. we make a startPluginBackup call to the plugin, which gives
200 * us the data we need in save_pkt
201 * 5. we call Bacula's save_file() subroutine to save the specified
202 * file. The plugin will be called at pluginIO() to supply the
205 * Sequence of calls for restore:
206 * See subroutine plugin_name_stream() below.
208 int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
214 char *cmd = ff_pkt->top_fname;
218 if (!plugin_list || !jcr->plugin_ctx_list) {
219 return 1; /* Return if no plugins loaded */
222 jcr->cmd_plugin = true;
223 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
224 event.eventType = bEventBackupCommand;
226 /* Handle plugin command here backup */
227 Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
228 if (!(p = strchr(cmd, ':'))) {
229 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
237 /* Note, we stop the loop on the first plugin that matches the name */
238 foreach_alist(plugin, plugin_list) {
239 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
240 if (strncmp(plugin->file, cmd, len) != 0) {
245 * We put the current plugin pointer, and the plugin context
246 * into the jcr, because during save_file(), the plugin
247 * will be called many times and these values are needed.
249 jcr->plugin_ctx = &plugin_ctx_list[i];
250 jcr->plugin = plugin;
251 if (is_plugin_disabled(jcr)) {
255 Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
256 /* Send the backup command to the right plugin*/
257 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
260 /* Loop getting filenames to backup then saving them */
261 while (!job_canceled(jcr)) {
262 memset(&sp, 0, sizeof(sp));
263 sp.pkt_size = sizeof(sp);
264 sp.pkt_end = sizeof(sp);
267 Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
269 /* Get the file save parameters */
270 if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) {
273 if (sp.type == 0 || sp.fname == NULL) {
274 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\" returned bad startBackupFile packet.\n"),
278 jcr->plugin_sp = &sp;
280 ff_pkt->fname = sp.fname;
281 ff_pkt->link = sp.link;
282 ff_pkt->type = sp.type;
283 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
284 Dmsg1(dbglvl, "Save_file: file=%s\n", ff_pkt->fname);
285 save_file(jcr, ff_pkt, true);
286 bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx);
287 if (rc == bRC_More || rc == bRC_OK) {
288 accurate_mark_file_as_seen(jcr, ff_pkt->fname);
290 if (rc == bRC_More) {
297 Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
300 jcr->cmd_plugin = false;
302 jcr->plugin_ctx = NULL;
307 * Send plugin name start/end record to SD
309 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
312 int index = jcr->JobFiles;
313 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
316 Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
321 index++; /* JobFiles not incremented yet */
323 Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
324 /* Send stream header */
325 if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
326 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
330 Dmsg1(50, "send: %s\n", sd->msg);
333 /* Send data -- not much */
334 stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
336 /* Send end of data */
337 stat = sd->fsend("0 0");
340 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
344 Dmsg1(dbglvl, "send: %s\n", sd->msg);
345 sd->signal(BNET_EOD); /* indicate end of plugin name data */
350 * Plugin name stream found during restore. The record passed in
351 * argument name was generated in send_plugin_name() above.
353 * Returns: true if start of stream
354 * false if end of steam
356 bool plugin_name_stream(JCR *jcr, char *name)
360 bool start, portable;
364 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
366 Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
367 skip_nonspaces(&p); /* skip over jcr->JobFiles */
371 /* Start of plugin data */
372 skip_nonspaces(&p); /* skip start/end flag */
374 portable = *p == '1';
375 skip_nonspaces(&p); /* skip portable flag */
380 * End of plugin data, notify plugin, then clear flags
382 Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
384 plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
386 jcr->plugin_ctx = NULL;
390 if (!plugin_ctx_list) {
395 * After this point, we are dealing with a restore start
398 // Dmsg1(dbglvl, "plugin restore cmd=%s\n", cmd);
399 if (!(p = strchr(cmd, ':'))) {
400 Jmsg1(jcr, M_ERROR, 0,
401 _("Malformed plugin command. Name not terminated by colon: %s\n"), cmd);
410 * Search for correct plugin as specified on the command
412 foreach_alist(plugin, plugin_list) {
414 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
415 if (strncmp(plugin->file, cmd, len) != 0) {
419 jcr->plugin_ctx = &plugin_ctx_list[i];
420 jcr->plugin = plugin;
421 if (is_plugin_disabled(jcr)) {
424 Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
425 event.eventType = bEventRestoreCommand;
426 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
427 &event, cmd) != bRC_OK) {
430 /* ***FIXME**** check error code */
431 plug_func(plugin)->startRestoreFile((bpContext *)jcr->plugin_ctx, cmd);
434 Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
441 * Tell the plugin to create the file. Return values are
442 * This is called only during Restore
445 * CF_SKIP -- skip processing this file
446 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
447 * CF_CREATED -- created, but no content to extract (typically directories)
450 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
452 bpContext *plugin_ctx = jcr->plugin_ctx;
453 Plugin *plugin = jcr->plugin;
454 struct restore_pkt rp;
458 if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr)) {
461 rp.pkt_size = sizeof(rp);
462 rp.pkt_end = sizeof(rp);
463 rp.stream = attr->stream;
464 rp.data_stream = attr->data_stream;
465 rp.type = attr->type;
466 rp.file_index = attr->file_index;
467 rp.LinkFI = attr->LinkFI;
469 rp.statp = attr->statp; /* structure assignment */
470 rp.attrEx = attr->attrEx;
471 rp.ofname = attr->ofname;
472 rp.olname = attr->olname;
473 rp.where = jcr->where;
474 rp.RegexWhere = jcr->RegexWhere;
475 rp.replace = jcr->replace;
476 rp.create_status = CF_ERROR;
477 Dmsg1(dbglvl, "call plugin createFile=%s\n", rp.ofname);
478 rc = plug_func(plugin)->createFile(plugin_ctx, &rp);
480 Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"),
484 if (rp.create_status == CF_ERROR) {
485 Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
489 /* Created link or directory? */
490 if (rp.create_status == CF_CREATED) {
491 return rp.create_status; /* yes, no need to bopen */
494 flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
495 Dmsg0(dbglvl, "call bopen\n");
496 int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR);
497 Dmsg1(50, "bopen status=%d\n", stat);
500 be.set_errno(bfd->berrno);
501 Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
502 attr->ofname, be.bstrerror());
503 Dmsg2(dbglvl,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
507 if (!is_bopen(bfd)) {
508 Dmsg0(000, "===== BFD is not open!!!!\n");
514 * Reset the file attributes after all file I/O is done -- this allows
515 * the previous access time/dates to be set properly, and it also allows
516 * us to properly set directory permissions.
517 * Not currently Implemented.
519 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
521 Dmsg0(dbglvl, "plugin_set_attributes\n");
525 pm_strcpy(attr->ofname, "*none*");
530 * Print to file the plugin info.
532 void dump_fd_plugin(Plugin *plugin, FILE *fp)
537 pInfo *info = (pInfo *)plugin->pinfo;
538 fprintf(fp, "\tversion=%d\n", info->version);
539 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
540 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
541 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
542 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
543 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
544 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
548 * This entry point is called internally by Bacula to ensure
549 * that the plugin IO calls come into this code.
551 void load_fd_plugins(const char *plugin_dir)
556 Dmsg0(dbglvl, "plugin dir is NULL\n");
560 plugin_list = New(alist(10, not_owned_by_alist));
561 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
562 is_plugin_compatible)) {
563 /* Either none found, or some error */
564 if (plugin_list->size() == 0) {
567 Dmsg0(dbglvl, "No plugins loaded\n");
572 /* Plug entry points called from findlib */
573 plugin_bopen = my_plugin_bopen;
574 plugin_bclose = my_plugin_bclose;
575 plugin_bread = my_plugin_bread;
576 plugin_bwrite = my_plugin_bwrite;
577 plugin_blseek = my_plugin_blseek;
580 * Verify that the plugin is acceptable, and print information
583 foreach_alist(plugin, plugin_list) {
584 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
585 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
588 dbg_plugin_add_hook(dump_fd_plugin);
592 * Check if a plugin is compatible. Called by the load_plugin function
593 * to allow us to verify the plugin.
595 static bool is_plugin_compatible(Plugin *plugin)
597 pInfo *info = (pInfo *)plugin->pinfo;
598 Dmsg0(50, "is_plugin_compatible called\n");
599 if (debug_level >= 50) {
600 dump_fd_plugin(plugin, stdin);
602 if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) {
603 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
604 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
605 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
606 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
610 if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
611 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
612 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
613 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
614 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
617 if (strcmp(info->plugin_license, "Bacula GPLv2") != 0 &&
618 strcmp(info->plugin_license, "GPLv2") != 0) {
619 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
620 plugin->file, info->plugin_license);
621 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
622 plugin->file, info->plugin_license);
631 * Create a new instance of each plugin for this Job
632 * Note, plugin_list can exist but jcr->plugin_ctx_list can
633 * be NULL if no plugins were loaded.
635 void new_plugins(JCR *jcr)
641 Dmsg0(dbglvl, "plugin list is NULL\n");
645 int num = plugin_list->size();
648 Dmsg0(dbglvl, "No plugins loaded\n");
652 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
654 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
655 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
656 foreach_alist(plugin, plugin_list) {
657 /* Start a new instance of each plugin */
658 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
659 memset(b_ctx, 0, sizeof(bacula_ctx));
661 plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */
662 plugin_ctx_list[i].pContext = NULL;
663 if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
664 b_ctx->disabled = true;
670 * Free the plugin instances for this Job
672 void free_plugins(JCR *jcr)
677 if (!plugin_list || !jcr->plugin_ctx_list) {
678 return; /* no plugins, nothing to do */
681 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
682 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
683 foreach_alist(plugin, plugin_list) {
684 /* Free the plugin instance */
685 plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
686 free(plugin_ctx_list[i++].bContext); /* free Bacula private context */
688 free(plugin_ctx_list);
689 jcr->plugin_ctx_list = NULL;
692 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
695 Plugin *plugin = (Plugin *)jcr->plugin;
698 Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags);
699 io.pkt_size = sizeof(io);
700 io.pkt_end = sizeof(io);
709 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
710 bfd->berrno = io.io_errno;
712 errno = b_errno_win32;
715 bfd->lerror = io.lerror;
717 Dmsg1(50, "Return from plugin open status=%d\n", io.status);
721 static int my_plugin_bclose(BFILE *bfd)
724 Plugin *plugin = (Plugin *)jcr->plugin;
726 Dmsg0(dbglvl, "===== plugin_bclose\n");
727 io.pkt_size = sizeof(io);
728 io.pkt_end = sizeof(io);
734 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
735 bfd->berrno = io.io_errno;
737 errno = b_errno_win32;
740 bfd->lerror = io.lerror;
742 Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status);
746 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
749 Plugin *plugin = (Plugin *)jcr->plugin;
751 Dmsg0(dbglvl, "plugin_bread\n");
752 io.pkt_size = sizeof(io);
753 io.pkt_end = sizeof(io);
756 io.buf = (char *)buf;
759 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
760 bfd->berrno = io.io_errno;
762 errno = b_errno_win32;
765 bfd->lerror = io.lerror;
767 return (ssize_t)io.status;
770 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
773 Plugin *plugin = (Plugin *)jcr->plugin;
775 Dmsg0(dbglvl, "plugin_bwrite\n");
776 io.pkt_size = sizeof(io);
777 io.pkt_end = sizeof(io);
780 io.buf = (char *)buf;
783 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
784 bfd->berrno = io.io_errno;
786 errno = b_errno_win32;
789 bfd->lerror = io.lerror;
791 return (ssize_t)io.status;
794 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
797 Plugin *plugin = (Plugin *)jcr->plugin;
799 Dmsg0(dbglvl, "plugin_bseek\n");
800 io.pkt_size = sizeof(io);
801 io.pkt_end = sizeof(io);
807 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
808 bfd->berrno = io.io_errno;
810 errno = b_errno_win32;
813 bfd->lerror = io.lerror;
815 return (boffset_t)io.offset;
818 /* ==============================================================
820 * Callbacks from the plugin
822 * ==============================================================
824 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
827 if (!value || !ctx) {
830 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
831 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
832 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
836 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
839 *((int *)value) = jcr->JobId;
840 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
843 *((char **)value) = my_name;
844 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
847 *((int *)value) = jcr->get_JobLevel();
848 Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->get_JobLevel());
851 *((int *)value) = jcr->get_JobType();
852 Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->get_JobType());
855 *((char **)value) = jcr->client_name;
856 Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name);
859 *((char **)value) = jcr->Job;
860 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
863 *((int *)value) = jcr->JobStatus;
864 Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus);
867 *((int *)value) = (int)jcr->mtime;
868 Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime);
871 *((int *)value) = (int)jcr->accurate;
872 Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate);
875 break; /* a write only variable, ignore read request */
880 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
883 if (!value || !ctx) {
886 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
887 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
888 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
892 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
895 if (!accurate_mark_file_as_seen(jcr, (char *)value)) {
905 static bRC baculaRegisterEvents(bpContext *ctx, ...)
915 while ((event = va_arg(args, uint32_t))) {
916 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
922 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
923 int type, utime_t mtime, const char *fmt, ...)
930 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
935 va_start(arg_ptr, fmt);
936 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
938 Jmsg(jcr, type, mtime, "%s", buf);
942 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
943 int level, const char *fmt, ...)
948 va_start(arg_ptr, fmt);
949 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
951 d_msg(file, line, level, "%s", buf);
955 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
959 return sm_malloc(file, line, size);
965 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem)
968 sm_free(file, line, mem);
978 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
979 int (*plugin_bclose)(JCR *jcr) = NULL;
980 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
981 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
982 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
984 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
989 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
994 int main(int argc, char *argv[])
996 char plugin_dir[1000];
1001 strcpy(my_name, "test-fd");
1003 getcwd(plugin_dir, sizeof(plugin_dir)-1);
1004 load_fd_plugins(plugin_dir);
1012 generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
1013 generate_plugin_event(jcr1, bEventJobEnd);
1014 generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
1016 generate_plugin_event(jcr2, bEventJobEnd);
1021 Dmsg0(dbglvl, "bacula: OK ...\n");
1022 close_memory_pool();
1027 #endif /* TEST_PROGRAM */