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;
217 POOL_MEM fname(PM_FNAME);
218 POOL_MEM link(PM_FNAME);
220 if (!plugin_list || !jcr->plugin_ctx_list) {
221 return 1; /* Return if no plugins loaded */
224 jcr->cmd_plugin = true;
225 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
226 event.eventType = bEventBackupCommand;
228 /* Handle plugin command here backup */
229 Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
230 if (!(p = strchr(cmd, ':'))) {
231 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
239 /* Note, we stop the loop on the first plugin that matches the name */
240 foreach_alist(plugin, plugin_list) {
241 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
242 if (strncmp(plugin->file, cmd, len) != 0) {
247 * We put the current plugin pointer, and the plugin context
248 * into the jcr, because during save_file(), the plugin
249 * will be called many times and these values are needed.
251 jcr->plugin_ctx = &plugin_ctx_list[i];
252 jcr->plugin = plugin;
253 if (is_plugin_disabled(jcr)) {
257 Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
258 /* Send the backup command to the right plugin*/
259 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
262 /* Loop getting filenames to backup then saving them */
263 while (!job_canceled(jcr)) {
264 memset(&sp, 0, sizeof(sp));
265 sp.pkt_size = sizeof(sp);
266 sp.pkt_end = sizeof(sp);
269 Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
271 /* Get the file save parameters */
272 if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) {
275 if (sp.type == 0 || sp.fname == NULL) {
276 Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\" returned bad startBackupFile packet.\n"),
280 jcr->plugin_sp = &sp;
283 * Copy fname and link because save_file() zaps them. This
284 * avoids zaping the plugin's strings.
286 pm_strcpy(fname, sp.fname);
287 pm_strcpy(link, sp.link);
288 ff_pkt->fname = fname.c_str();
289 ff_pkt->link = link.c_str();
290 ff_pkt->type = sp.type;
291 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
292 Dmsg1(dbglvl, "Save_file: file=%s\n", fname.c_str());
293 save_file(jcr, ff_pkt, true);
294 bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx);
295 if (rc == bRC_More || rc == bRC_OK) {
296 accurate_mark_file_as_seen(jcr, fname.c_str());
298 if (rc == bRC_More) {
305 Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
308 jcr->cmd_plugin = false;
310 jcr->plugin_ctx = NULL;
315 * Send plugin name start/end record to SD
317 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
320 int index = jcr->JobFiles;
321 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
324 Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
329 index++; /* JobFiles not incremented yet */
331 Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
332 /* Send stream header */
333 if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
334 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
338 Dmsg1(50, "send: %s\n", sd->msg);
341 /* Send data -- not much */
342 stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
344 /* Send end of data */
345 stat = sd->fsend("0 0");
348 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
352 Dmsg1(dbglvl, "send: %s\n", sd->msg);
353 sd->signal(BNET_EOD); /* indicate end of plugin name data */
358 * Plugin name stream found during restore. The record passed in
359 * argument name was generated in send_plugin_name() above.
361 * Returns: true if start of stream
362 * false if end of steam
364 bool plugin_name_stream(JCR *jcr, char *name)
368 bool start, portable;
372 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
374 Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
375 skip_nonspaces(&p); /* skip over jcr->JobFiles */
379 /* Start of plugin data */
380 skip_nonspaces(&p); /* skip start/end flag */
382 portable = *p == '1';
383 skip_nonspaces(&p); /* skip portable flag */
388 * End of plugin data, notify plugin, then clear flags
390 Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
392 plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
394 jcr->plugin_ctx = NULL;
398 if (!plugin_ctx_list) {
403 * After this point, we are dealing with a restore start
406 // Dmsg1(dbglvl, "plugin restore cmd=%s\n", cmd);
407 if (!(p = strchr(cmd, ':'))) {
408 Jmsg1(jcr, M_ERROR, 0,
409 _("Malformed plugin command. Name not terminated by colon: %s\n"), cmd);
418 * Search for correct plugin as specified on the command
420 foreach_alist(plugin, plugin_list) {
422 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
423 if (strncmp(plugin->file, cmd, len) != 0) {
427 jcr->plugin_ctx = &plugin_ctx_list[i];
428 jcr->plugin = plugin;
429 if (is_plugin_disabled(jcr)) {
432 Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
433 event.eventType = bEventRestoreCommand;
434 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
435 &event, cmd) != bRC_OK) {
438 /* ***FIXME**** check error code */
439 plug_func(plugin)->startRestoreFile((bpContext *)jcr->plugin_ctx, cmd);
442 Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
449 * Tell the plugin to create the file. Return values are
450 * This is called only during Restore
453 * CF_SKIP -- skip processing this file
454 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
455 * CF_CREATED -- created, but no content to extract (typically directories)
458 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
460 bpContext *plugin_ctx = jcr->plugin_ctx;
461 Plugin *plugin = jcr->plugin;
462 struct restore_pkt rp;
466 if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr)) {
469 rp.pkt_size = sizeof(rp);
470 rp.pkt_end = sizeof(rp);
471 rp.stream = attr->stream;
472 rp.data_stream = attr->data_stream;
473 rp.type = attr->type;
474 rp.file_index = attr->file_index;
475 rp.LinkFI = attr->LinkFI;
477 rp.statp = attr->statp; /* structure assignment */
478 rp.attrEx = attr->attrEx;
479 rp.ofname = attr->ofname;
480 rp.olname = attr->olname;
481 rp.where = jcr->where;
482 rp.RegexWhere = jcr->RegexWhere;
483 rp.replace = jcr->replace;
484 rp.create_status = CF_ERROR;
485 Dmsg1(dbglvl, "call plugin createFile=%s\n", rp.ofname);
486 rc = plug_func(plugin)->createFile(plugin_ctx, &rp);
488 Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"),
492 if (rp.create_status == CF_ERROR) {
493 Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
497 /* Created link or directory? */
498 if (rp.create_status == CF_CREATED) {
499 return rp.create_status; /* yes, no need to bopen */
502 flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
503 Dmsg0(dbglvl, "call bopen\n");
504 int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR);
505 Dmsg1(50, "bopen status=%d\n", stat);
508 be.set_errno(bfd->berrno);
509 Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
510 attr->ofname, be.bstrerror());
511 Dmsg2(dbglvl,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
515 if (!is_bopen(bfd)) {
516 Dmsg0(000, "===== BFD is not open!!!!\n");
522 * Reset the file attributes after all file I/O is done -- this allows
523 * the previous access time/dates to be set properly, and it also allows
524 * us to properly set directory permissions.
525 * Not currently Implemented.
527 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
529 Dmsg0(dbglvl, "plugin_set_attributes\n");
533 pm_strcpy(attr->ofname, "*none*");
538 * Print to file the plugin info.
540 void dump_fd_plugin(Plugin *plugin, FILE *fp)
545 pInfo *info = (pInfo *)plugin->pinfo;
546 fprintf(fp, "\tversion=%d\n", info->version);
547 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
548 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
549 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
550 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
551 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
552 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
556 * This entry point is called internally by Bacula to ensure
557 * that the plugin IO calls come into this code.
559 void load_fd_plugins(const char *plugin_dir)
564 Dmsg0(dbglvl, "plugin dir is NULL\n");
568 plugin_list = New(alist(10, not_owned_by_alist));
569 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
570 is_plugin_compatible)) {
571 /* Either none found, or some error */
572 if (plugin_list->size() == 0) {
575 Dmsg0(dbglvl, "No plugins loaded\n");
580 /* Plug entry points called from findlib */
581 plugin_bopen = my_plugin_bopen;
582 plugin_bclose = my_plugin_bclose;
583 plugin_bread = my_plugin_bread;
584 plugin_bwrite = my_plugin_bwrite;
585 plugin_blseek = my_plugin_blseek;
588 * Verify that the plugin is acceptable, and print information
591 foreach_alist(plugin, plugin_list) {
592 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
593 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
596 dbg_plugin_add_hook(dump_fd_plugin);
600 * Check if a plugin is compatible. Called by the load_plugin function
601 * to allow us to verify the plugin.
603 static bool is_plugin_compatible(Plugin *plugin)
605 pInfo *info = (pInfo *)plugin->pinfo;
606 Dmsg0(50, "is_plugin_compatible called\n");
607 if (debug_level >= 50) {
608 dump_fd_plugin(plugin, stdin);
610 if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) {
611 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
612 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
613 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
614 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
618 if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
619 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
620 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
621 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
622 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
625 if (strcmp(info->plugin_license, "Bacula GPLv2") != 0 &&
626 strcmp(info->plugin_license, "GPLv2") != 0) {
627 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
628 plugin->file, info->plugin_license);
629 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
630 plugin->file, info->plugin_license);
639 * Create a new instance of each plugin for this Job
640 * Note, plugin_list can exist but jcr->plugin_ctx_list can
641 * be NULL if no plugins were loaded.
643 void new_plugins(JCR *jcr)
649 Dmsg0(dbglvl, "plugin list is NULL\n");
653 int num = plugin_list->size();
656 Dmsg0(dbglvl, "No plugins loaded\n");
660 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
662 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
663 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
664 foreach_alist(plugin, plugin_list) {
665 /* Start a new instance of each plugin */
666 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
667 memset(b_ctx, 0, sizeof(bacula_ctx));
669 plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */
670 plugin_ctx_list[i].pContext = NULL;
671 if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
672 b_ctx->disabled = true;
678 * Free the plugin instances for this Job
680 void free_plugins(JCR *jcr)
685 if (!plugin_list || !jcr->plugin_ctx_list) {
686 return; /* no plugins, nothing to do */
689 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
690 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
691 foreach_alist(plugin, plugin_list) {
692 /* Free the plugin instance */
693 plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
694 free(plugin_ctx_list[i++].bContext); /* free Bacula private context */
696 free(plugin_ctx_list);
697 jcr->plugin_ctx_list = NULL;
700 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
703 Plugin *plugin = (Plugin *)jcr->plugin;
706 Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags);
707 io.pkt_size = sizeof(io);
708 io.pkt_end = sizeof(io);
717 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
718 bfd->berrno = io.io_errno;
720 errno = b_errno_win32;
723 bfd->lerror = io.lerror;
725 Dmsg1(50, "Return from plugin open status=%d\n", io.status);
729 static int my_plugin_bclose(BFILE *bfd)
732 Plugin *plugin = (Plugin *)jcr->plugin;
734 Dmsg0(dbglvl, "===== plugin_bclose\n");
735 io.pkt_size = sizeof(io);
736 io.pkt_end = sizeof(io);
742 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
743 bfd->berrno = io.io_errno;
745 errno = b_errno_win32;
748 bfd->lerror = io.lerror;
750 Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status);
754 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
757 Plugin *plugin = (Plugin *)jcr->plugin;
759 Dmsg0(dbglvl, "plugin_bread\n");
760 io.pkt_size = sizeof(io);
761 io.pkt_end = sizeof(io);
764 io.buf = (char *)buf;
767 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
768 bfd->berrno = io.io_errno;
770 errno = b_errno_win32;
773 bfd->lerror = io.lerror;
775 return (ssize_t)io.status;
778 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
781 Plugin *plugin = (Plugin *)jcr->plugin;
783 Dmsg0(dbglvl, "plugin_bwrite\n");
784 io.pkt_size = sizeof(io);
785 io.pkt_end = sizeof(io);
788 io.buf = (char *)buf;
791 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
792 bfd->berrno = io.io_errno;
794 errno = b_errno_win32;
797 bfd->lerror = io.lerror;
799 return (ssize_t)io.status;
802 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
805 Plugin *plugin = (Plugin *)jcr->plugin;
807 Dmsg0(dbglvl, "plugin_bseek\n");
808 io.pkt_size = sizeof(io);
809 io.pkt_end = sizeof(io);
815 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
816 bfd->berrno = io.io_errno;
818 errno = b_errno_win32;
821 bfd->lerror = io.lerror;
823 return (boffset_t)io.offset;
826 /* ==============================================================
828 * Callbacks from the plugin
830 * ==============================================================
832 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
835 if (!value || !ctx) {
838 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
839 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
840 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
844 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
847 *((int *)value) = jcr->JobId;
848 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
851 *((char **)value) = my_name;
852 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
855 *((int *)value) = jcr->get_JobLevel();
856 Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->get_JobLevel());
859 *((int *)value) = jcr->get_JobType();
860 Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->get_JobType());
863 *((char **)value) = jcr->client_name;
864 Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name);
867 *((char **)value) = jcr->Job;
868 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
871 *((int *)value) = jcr->JobStatus;
872 Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus);
875 *((int *)value) = (int)jcr->mtime;
876 Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime);
879 *((int *)value) = (int)jcr->accurate;
880 Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate);
883 break; /* a write only variable, ignore read request */
888 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
891 if (!value || !ctx) {
894 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
895 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
896 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
900 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
903 if (!accurate_mark_file_as_seen(jcr, (char *)value)) {
913 static bRC baculaRegisterEvents(bpContext *ctx, ...)
923 while ((event = va_arg(args, uint32_t))) {
924 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
930 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
931 int type, utime_t mtime, const char *fmt, ...)
938 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
943 va_start(arg_ptr, fmt);
944 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
946 Jmsg(jcr, type, mtime, "%s", buf);
950 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
951 int level, const char *fmt, ...)
956 va_start(arg_ptr, fmt);
957 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
959 d_msg(file, line, level, "%s", buf);
963 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
967 return sm_malloc(file, line, size);
973 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem)
976 sm_free(file, line, mem);
986 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
987 int (*plugin_bclose)(JCR *jcr) = NULL;
988 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
989 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
990 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
992 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
997 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
1002 int main(int argc, char *argv[])
1004 char plugin_dir[1000];
1009 strcpy(my_name, "test-fd");
1011 getcwd(plugin_dir, sizeof(plugin_dir)-1);
1012 load_fd_plugins(plugin_dir);
1020 generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
1021 generate_plugin_event(jcr1, bEventJobEnd);
1022 generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
1024 generate_plugin_event(jcr2, bEventJobEnd);
1029 Dmsg0(dbglvl, "bacula: OK ...\n");
1030 close_memory_pool();
1035 #endif /* TEST_PROGRAM */