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) {
294 Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
297 jcr->cmd_plugin = false;
299 jcr->plugin_ctx = NULL;
304 * Send plugin name start/end record to SD
306 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
309 int index = jcr->JobFiles;
310 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
313 Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
318 index++; /* JobFiles not incremented yet */
320 Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
321 /* Send stream header */
322 if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
323 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
327 Dmsg1(50, "send: %s\n", sd->msg);
330 /* Send data -- not much */
331 stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
333 /* Send end of data */
334 stat = sd->fsend("0 0");
337 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
341 Dmsg1(dbglvl, "send: %s\n", sd->msg);
342 sd->signal(BNET_EOD); /* indicate end of plugin name data */
347 * Plugin name stream found during restore. The record passed in
348 * argument name was generated in send_plugin_name() above.
350 * Returns: true if start of stream
351 * false if end of steam
353 bool plugin_name_stream(JCR *jcr, char *name)
357 bool start, portable;
361 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
363 Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
364 skip_nonspaces(&p); /* skip over jcr->JobFiles */
368 /* Start of plugin data */
369 skip_nonspaces(&p); /* skip start/end flag */
371 portable = *p == '1';
372 skip_nonspaces(&p); /* skip portable flag */
377 * End of plugin data, notify plugin, then clear flags
379 Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
381 plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
383 jcr->plugin_ctx = NULL;
387 if (!plugin_ctx_list) {
392 * After this point, we are dealing with a restore start
395 // Dmsg1(dbglvl, "plugin restore cmd=%s\n", cmd);
396 if (!(p = strchr(cmd, ':'))) {
397 Jmsg1(jcr, M_ERROR, 0,
398 _("Malformed plugin command. Name not terminated by colon: %s\n"), cmd);
407 * Search for correct plugin as specified on the command
409 foreach_alist(plugin, plugin_list) {
411 Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
412 if (strncmp(plugin->file, cmd, len) != 0) {
416 jcr->plugin_ctx = &plugin_ctx_list[i];
417 jcr->plugin = plugin;
418 if (is_plugin_disabled(jcr)) {
421 Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
422 event.eventType = bEventRestoreCommand;
423 if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
424 &event, cmd) != bRC_OK) {
427 /* ***FIXME**** check error code */
428 plug_func(plugin)->startRestoreFile((bpContext *)jcr->plugin_ctx, cmd);
431 Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
438 * Tell the plugin to create the file. Return values are
439 * This is called only during Restore
442 * CF_SKIP -- skip processing this file
443 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
444 * CF_CREATED -- created, but no content to extract (typically directories)
447 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
449 bpContext *plugin_ctx = jcr->plugin_ctx;
450 Plugin *plugin = jcr->plugin;
451 struct restore_pkt rp;
455 if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr)) {
458 rp.pkt_size = sizeof(rp);
459 rp.pkt_end = sizeof(rp);
460 rp.stream = attr->stream;
461 rp.data_stream = attr->data_stream;
462 rp.type = attr->type;
463 rp.file_index = attr->file_index;
464 rp.LinkFI = attr->LinkFI;
466 rp.statp = attr->statp; /* structure assignment */
467 rp.attrEx = attr->attrEx;
468 rp.ofname = attr->ofname;
469 rp.olname = attr->olname;
470 rp.where = jcr->where;
471 rp.RegexWhere = jcr->RegexWhere;
472 rp.replace = jcr->replace;
473 rp.create_status = CF_ERROR;
474 Dmsg1(dbglvl, "call plugin createFile=%s\n", rp.ofname);
475 rc = plug_func(plugin)->createFile(plugin_ctx, &rp);
477 Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"),
481 if (rp.create_status == CF_ERROR) {
482 Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
486 /* Created link or directory? */
487 if (rp.create_status == CF_CREATED) {
488 return rp.create_status; /* yes, no need to bopen */
491 flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
492 Dmsg0(dbglvl, "call bopen\n");
493 int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR);
494 Dmsg1(50, "bopen status=%d\n", stat);
497 be.set_errno(bfd->berrno);
498 Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
499 attr->ofname, be.bstrerror());
500 Dmsg2(dbglvl,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
504 if (!is_bopen(bfd)) {
505 Dmsg0(000, "===== BFD is not open!!!!\n");
511 * Reset the file attributes after all file I/O is done -- this allows
512 * the previous access time/dates to be set properly, and it also allows
513 * us to properly set directory permissions.
514 * Not currently Implemented.
516 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
518 Dmsg0(dbglvl, "plugin_set_attributes\n");
522 pm_strcpy(attr->ofname, "*none*");
527 * Print to file the plugin info.
529 void dump_fd_plugin(Plugin *plugin, FILE *fp)
534 pInfo *info = (pInfo *)plugin->pinfo;
535 fprintf(fp, "\tversion=%d\n", info->version);
536 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
537 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
538 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
539 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
540 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
541 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
545 * This entry point is called internally by Bacula to ensure
546 * that the plugin IO calls come into this code.
548 void load_fd_plugins(const char *plugin_dir)
553 Dmsg0(dbglvl, "plugin dir is NULL\n");
557 plugin_list = New(alist(10, not_owned_by_alist));
558 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
559 is_plugin_compatible)) {
560 /* Either none found, or some error */
561 if (plugin_list->size() == 0) {
564 Dmsg0(dbglvl, "No plugins loaded\n");
569 /* Plug entry points called from findlib */
570 plugin_bopen = my_plugin_bopen;
571 plugin_bclose = my_plugin_bclose;
572 plugin_bread = my_plugin_bread;
573 plugin_bwrite = my_plugin_bwrite;
574 plugin_blseek = my_plugin_blseek;
577 * Verify that the plugin is acceptable, and print information
580 foreach_alist(plugin, plugin_list) {
581 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
582 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
585 dbg_plugin_add_hook(dump_fd_plugin);
589 * Check if a plugin is compatible. Called by the load_plugin function
590 * to allow us to verify the plugin.
592 static bool is_plugin_compatible(Plugin *plugin)
594 pInfo *info = (pInfo *)plugin->pinfo;
595 Dmsg0(50, "is_plugin_compatible called\n");
596 if (debug_level >= 50) {
597 dump_fd_plugin(plugin, stdin);
599 if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) {
600 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
601 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
602 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
603 plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
607 if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
608 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
609 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
610 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
611 plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
614 if (strcmp(info->plugin_license, "Bacula GPLv2") != 0 &&
615 strcmp(info->plugin_license, "GPLv2") != 0) {
616 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
617 plugin->file, info->plugin_license);
618 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
619 plugin->file, info->plugin_license);
628 * Create a new instance of each plugin for this Job
629 * Note, plugin_list can exist but jcr->plugin_ctx_list can
630 * be NULL if no plugins were loaded.
632 void new_plugins(JCR *jcr)
638 Dmsg0(dbglvl, "plugin list is NULL\n");
642 int num = plugin_list->size();
645 Dmsg0(dbglvl, "No plugins loaded\n");
649 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
651 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
652 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
653 foreach_alist(plugin, plugin_list) {
654 /* Start a new instance of each plugin */
655 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
656 memset(b_ctx, 0, sizeof(bacula_ctx));
658 plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */
659 plugin_ctx_list[i].pContext = NULL;
660 if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
661 b_ctx->disabled = true;
667 * Free the plugin instances for this Job
669 void free_plugins(JCR *jcr)
674 if (!plugin_list || !jcr->plugin_ctx_list) {
675 return; /* no plugins, nothing to do */
678 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
679 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
680 foreach_alist(plugin, plugin_list) {
681 /* Free the plugin instance */
682 plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
683 free(plugin_ctx_list[i++].bContext); /* free Bacula private context */
685 free(plugin_ctx_list);
686 jcr->plugin_ctx_list = NULL;
689 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
692 Plugin *plugin = (Plugin *)jcr->plugin;
695 Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags);
696 io.pkt_size = sizeof(io);
697 io.pkt_end = sizeof(io);
706 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
707 bfd->berrno = io.io_errno;
709 errno = b_errno_win32;
712 bfd->lerror = io.lerror;
714 Dmsg1(50, "Return from plugin open status=%d\n", io.status);
718 static int my_plugin_bclose(BFILE *bfd)
721 Plugin *plugin = (Plugin *)jcr->plugin;
723 Dmsg0(dbglvl, "===== plugin_bclose\n");
724 io.pkt_size = sizeof(io);
725 io.pkt_end = sizeof(io);
731 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
732 bfd->berrno = io.io_errno;
734 errno = b_errno_win32;
737 bfd->lerror = io.lerror;
739 Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status);
743 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
746 Plugin *plugin = (Plugin *)jcr->plugin;
748 Dmsg0(dbglvl, "plugin_bread\n");
749 io.pkt_size = sizeof(io);
750 io.pkt_end = sizeof(io);
753 io.buf = (char *)buf;
756 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
757 bfd->berrno = io.io_errno;
759 errno = b_errno_win32;
762 bfd->lerror = io.lerror;
764 return (ssize_t)io.status;
767 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
770 Plugin *plugin = (Plugin *)jcr->plugin;
772 Dmsg0(dbglvl, "plugin_bwrite\n");
773 io.pkt_size = sizeof(io);
774 io.pkt_end = sizeof(io);
777 io.buf = (char *)buf;
780 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
781 bfd->berrno = io.io_errno;
783 errno = b_errno_win32;
786 bfd->lerror = io.lerror;
788 return (ssize_t)io.status;
791 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
794 Plugin *plugin = (Plugin *)jcr->plugin;
796 Dmsg0(dbglvl, "plugin_bseek\n");
797 io.pkt_size = sizeof(io);
798 io.pkt_end = sizeof(io);
804 plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
805 bfd->berrno = io.io_errno;
807 errno = b_errno_win32;
810 bfd->lerror = io.lerror;
812 return (boffset_t)io.offset;
815 /* ==============================================================
817 * Callbacks from the plugin
819 * ==============================================================
821 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
824 if (!value || !ctx) {
827 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
828 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
829 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
833 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
836 *((int *)value) = jcr->JobId;
837 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
840 *((char **)value) = my_name;
841 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
844 *((int *)value) = jcr->get_JobLevel();
845 Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->get_JobLevel());
848 *((int *)value) = jcr->get_JobType();
849 Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->get_JobType());
852 *((char **)value) = jcr->client_name;
853 Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name);
856 *((char **)value) = jcr->Job;
857 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
860 *((int *)value) = jcr->JobStatus;
861 Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus);
864 *((int *)value) = (int)jcr->mtime;
865 Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime);
868 *((int *)value) = (int)jcr->accurate;
869 Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate);
872 break; /* a write only variable, ignore read request */
877 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
880 if (!value || !ctx) {
883 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
884 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
885 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
889 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
892 if (!accurate_mark_file_as_seen(jcr, (char *)value)) {
902 static bRC baculaRegisterEvents(bpContext *ctx, ...)
912 while ((event = va_arg(args, uint32_t))) {
913 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
919 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
920 int type, utime_t mtime, const char *fmt, ...)
927 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
932 va_start(arg_ptr, fmt);
933 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
935 Jmsg(jcr, type, mtime, "%s", buf);
939 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
940 int level, const char *fmt, ...)
945 va_start(arg_ptr, fmt);
946 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
948 d_msg(file, line, level, "%s", buf);
952 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
956 return sm_malloc(file, line, size);
962 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem)
965 sm_free(file, line, mem);
975 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
976 int (*plugin_bclose)(JCR *jcr) = NULL;
977 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
978 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
979 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
981 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
986 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
991 int main(int argc, char *argv[])
993 char plugin_dir[1000];
998 strcpy(my_name, "test-fd");
1000 getcwd(plugin_dir, sizeof(plugin_dir)-1);
1001 load_fd_plugins(plugin_dir);
1009 generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
1010 generate_plugin_event(jcr1, bEventJobEnd);
1011 generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
1013 generate_plugin_event(jcr2, bEventJobEnd);
1018 Dmsg0(dbglvl, "bacula: OK ...\n");
1019 close_memory_pool();
1024 #endif /* TEST_PROGRAM */