2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2008 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 John Walker.
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 = 50;
38 const char *plugin_type = "-fd.so";
40 extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
43 /* Function pointers to be set here */
44 extern DLL_IMP_EXP int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode);
45 extern DLL_IMP_EXP int (*plugin_bclose)(JCR *jcr);
46 extern DLL_IMP_EXP ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count);
47 extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count);
48 extern DLL_IMP_EXP boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence);
51 /* Forward referenced functions */
52 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
53 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
54 static bRC baculaRegisterEvents(bpContext *ctx, ...);
55 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
56 int type, time_t mtime, const char *msg);
57 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
58 int level, const char *msg);
60 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode);
61 static int my_plugin_bclose(JCR *jcr);
62 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count);
63 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count);
64 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence);
68 static bInfo binfo = {
70 PLUGIN_INTERFACE_VERSION
73 /* Bacula entry points */
74 static bFuncs bfuncs = {
76 PLUGIN_INTERFACE_VERSION,
86 * Create a plugin event
88 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
95 char *cmd = (char *)value;
103 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
104 event.eventType = eventType;
106 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
108 case bEventPluginCommand:
109 /* Handle plugin command here backup */
110 Dmsg1(100, "plugin cmd=%s\n", cmd);
111 if (!(p = strchr(cmd, ':'))) {
112 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
120 foreach_alist(plugin, plugin_list) {
121 Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
122 if (strncmp(plugin->file, cmd, len) == 0) {
123 Dmsg1(100, "Command plugin = %s\n", cmd);
124 if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, value) != bRC_OK) {
127 memset(&sp, 0, sizeof(sp));
131 Dmsg3(000, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
133 if (plug_func(plugin)->startPluginBackup(&plugin_ctx_list[i], &sp) != bRC_OK) {
136 jcr->plugin_ctx = &plugin_ctx_list[i];
137 jcr->plugin = plugin;
138 jcr->plugin_sp = &sp;
140 ff_pkt->fname = sp.fname;
141 ff_pkt->type = sp.type;
142 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
143 Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname);
144 save_file(jcr, ff_pkt, true);
149 Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
153 /* Pass event to every plugin */
154 foreach_alist(plugin, plugin_list) {
155 plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
166 * Send plugin name start/end record to SD
168 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
171 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
173 if (!sd->fsend("%ld %d %d", jcr->JobFiles, STREAM_PLUGIN_NAME, start)) {
174 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
178 stat = sd->fsend("%ld %d %d %s%c", jcr->JobFiles, start, sp->portable, sp->cmd, 0);
180 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
184 sd->signal(BNET_EOD); /* indicate end of plugin name data */
189 * Plugin name stream found during restore. This is the record
190 * that was generated in send_plugin_name() above.
192 void plugin_name_stream(JCR *jcr, char *name)
196 bool start, portable;
201 bpContext *plugin_ctx_list;
203 Dmsg1(000, "plugin stream string=%s\n", name);
204 skip_nonspaces(&p); /* skip over jcr->JobFiles */
207 skip_nonspaces(&p); /* skip start/end flag */
209 portable = *p == '1';
210 skip_nonspaces(&p); /* skip portable flag */
213 event.eventType = start ? bEventRestoreStart : bEventRestoreEnd;
215 /* Check for restore end */
218 * If end of restore, notify plugin, then clear flags
220 plugin = (Plugin *)jcr->plugin;
221 plug_func(plugin)->handlePluginEvent((bpContext *)jcr->plugin_ctx, &event, cmd);
222 jcr->plugin_ctx = NULL;
228 * After this point, we are dealing with a restore start
231 Dmsg1(000, "plugin cmd=%s\n", cmd);
232 if (!(p = strchr(cmd, ':'))) {
233 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
242 plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
243 foreach_alist(plugin, plugin_list) {
244 Dmsg3(100, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
245 if (strncmp(plugin->file, cmd, len) == 0) {
246 Dmsg1(100, "Command plugin = %s\n", cmd);
247 if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i],
248 &event, (void *)name) != bRC_OK) {
251 jcr->plugin_ctx = &plugin_ctx_list[i];
252 jcr->plugin = plugin;
262 void load_fd_plugins(const char *plugin_dir)
268 plugin_list = New(alist(10, not_owned_by_alist));
269 load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
270 plugin_bopen = my_plugin_bopen;
271 plugin_bclose = my_plugin_bclose;
272 plugin_bread = my_plugin_bread;
273 plugin_bwrite = my_plugin_bwrite;
274 plugin_blseek = my_plugin_blseek;
279 * Create a new instance of each plugin for this Job
281 void new_plugins(JCR *jcr)
290 int num = plugin_list->size();
296 jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
298 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
299 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
300 foreach_alist(plugin, plugin_list) {
301 /* Start a new instance of each plugin */
302 plugin_ctx_list[i].bContext = (void *)jcr;
303 plugin_ctx_list[i].pContext = NULL;
304 plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
309 * Free the plugin instances for this Job
311 void free_plugins(JCR *jcr)
320 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
321 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
322 foreach_alist(plugin, plugin_list) {
323 /* Free the plugin instance */
324 plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
326 free(plugin_ctx_list);
327 jcr->plugin_ctx_list = NULL;
330 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode)
332 Plugin *plugin = (Plugin *)jcr->plugin;
333 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
335 Dmsg0(000, "plugin_bopen\n");
339 plug_func(plugin)->pluginIO(plugin_ctx, &io);
343 static int my_plugin_bclose(JCR *jcr)
345 Plugin *plugin = (Plugin *)jcr->plugin;
346 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
348 Dmsg0(000, "plugin_bclose\n");
352 plug_func(plugin)->pluginIO(plugin_ctx, &io);
356 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count)
358 Plugin *plugin = (Plugin *)jcr->plugin;
359 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
361 Dmsg0(000, "plugin_bread\n");
364 io.buf = (char *)buf;
365 plug_func(plugin)->pluginIO(plugin_ctx, &io);
366 return (ssize_t)io.status;
369 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count)
371 Plugin *plugin = (Plugin *)jcr->plugin;
372 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
374 Dmsg0(000, "plugin_bwrite\n");
377 io.buf = (char *)buf;
378 plug_func(plugin)->pluginIO(plugin_ctx, &io);
379 return (ssize_t)io.status;
382 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence)
384 Plugin *plugin = (Plugin *)jcr->plugin;
385 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
387 Dmsg0(000, "plugin_bseek\n");
391 plug_func(plugin)->pluginIO(plugin_ctx, &io);
392 return (boffset_t)io.offset;
395 /* ==============================================================
397 * Callbacks from the plugin
399 * ==============================================================
401 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
403 JCR *jcr = (JCR *)(ctx->bContext);
404 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
408 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
411 *((int *)value) = jcr->JobId;
412 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
415 *((char **)value) = my_name;
416 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
429 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
431 Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
435 static bRC baculaRegisterEvents(bpContext *ctx, ...)
441 while ((event = va_arg(args, uint32_t))) {
442 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
448 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
449 int type, time_t mtime, const char *msg)
451 Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
452 file, line, type, mtime, msg);
456 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
457 int level, const char *msg)
459 Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
460 file, line, level, msg);
466 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
467 int (*plugin_bclose)(JCR *jcr) = NULL;
468 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
469 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
470 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
472 int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
477 int main(int argc, char *argv[])
479 char plugin_dir[1000];
484 strcpy(my_name, "test-fd");
486 getcwd(plugin_dir, sizeof(plugin_dir)-1);
487 load_fd_plugins(plugin_dir);
495 generate_plugin_event(jcr1, bEventJobStart);
496 generate_plugin_event(jcr1, bEventJobEnd);
497 generate_plugin_event(jcr2, bEventJobStart);
499 generate_plugin_event(jcr2, bEventJobEnd);
504 Dmsg0(dbglvl, "bacula: OK ...\n");
510 #endif /* TEST_PROGRAM */