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(FF_PKT *ff_pkt, void *vjcr, bool top_level);
43 /* Function pointers to be set here */
44 extern int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode);
45 extern int (*plugin_bclose)(JCR *jcr);
46 extern ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count);
47 extern ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count);
48 extern 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;
101 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
102 event.eventType = eventType;
104 Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
105 if (eventType != bEventPluginCommand) {
106 /* Pass event to every plugin */
107 foreach_alist(plugin, plugin_list) {
108 plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
113 /* Handle plugin command here (backup/restore of file) */
114 Dmsg1(000, "plugin cmd=%s\n", cmd);
115 if (!(p = strchr(cmd, ':'))) {
116 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
124 foreach_alist(plugin, plugin_list) {
125 Dmsg3(000, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
126 if (strncmp(plugin->file, cmd, len) == 0) {
129 Dmsg1(000, "Command plugin = %s\n", cmd);
130 if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, value) != bRC_OK) {
133 memset(&sp, 0, sizeof(sp));
137 Dmsg0(000, "Plugin startBackup\n");
138 if (plug_func(plugin)->startPluginBackup(&plugin_ctx_list[i], &sp) != bRC_OK) {
141 jcr->plugin_ctx = &plugin_ctx_list[i];
142 jcr->plugin = plugin;
143 jcr->plugin_sp = &sp;
145 ff_pkt->fname = sp.fname;
146 ff_pkt->type = sp.type;
147 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
148 Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname);
149 save_file(ff_pkt, (void *)jcr, true);
160 * Send plugin name record to SD
162 bool send_plugin_name(JCR *jcr, BSOCK *sd)
165 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
166 Plugin *plugin = (Plugin *)jcr->plugin;
167 if (!sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_PLUGIN_NAME)) {
168 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
172 stat = sd->fsend("%ld %d %s%c%s%c", jcr->JobFiles, sp->portable, 0, plugin->file,
175 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
179 sd->signal(BNET_EOD); /* indicate end of plugin name data */
184 void load_fd_plugins(const char *plugin_dir)
190 plugin_list = New(alist(10, not_owned_by_alist));
191 load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
192 plugin_bopen = my_plugin_bopen;
193 plugin_bclose = my_plugin_bclose;
194 plugin_bread = my_plugin_bread;
195 plugin_bwrite = my_plugin_bwrite;
196 plugin_blseek = my_plugin_blseek;
201 * Create a new instance of each plugin for this Job
203 void new_plugins(JCR *jcr)
212 int num = plugin_list->size();
218 jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
220 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
221 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
222 foreach_alist(plugin, plugin_list) {
223 /* Start a new instance of each plugin */
224 plugin_ctx_list[i].bContext = (void *)jcr;
225 plugin_ctx_list[i].pContext = NULL;
226 plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
231 * Free the plugin instances for this Job
233 void free_plugins(JCR *jcr)
242 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
243 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
244 foreach_alist(plugin, plugin_list) {
245 /* Free the plugin instance */
246 plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
248 free(plugin_ctx_list);
249 jcr->plugin_ctx_list = NULL;
252 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode)
254 Plugin *plugin = (Plugin *)jcr->plugin;
255 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
257 Dmsg0(000, "plugin_bopen\n");
261 plug_func(plugin)->pluginIO(plugin_ctx, &io);
265 static int my_plugin_bclose(JCR *jcr)
267 Plugin *plugin = (Plugin *)jcr->plugin;
268 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
270 Dmsg0(000, "plugin_bclose\n");
274 plug_func(plugin)->pluginIO(plugin_ctx, &io);
278 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count)
280 Plugin *plugin = (Plugin *)jcr->plugin;
281 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
283 Dmsg0(000, "plugin_bread\n");
286 io.buf = (char *)buf;
287 plug_func(plugin)->pluginIO(plugin_ctx, &io);
288 return (ssize_t)io.status;
291 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count)
293 Plugin *plugin = (Plugin *)jcr->plugin;
294 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
296 Dmsg0(000, "plugin_bwrite\n");
299 io.buf = (char *)buf;
300 plug_func(plugin)->pluginIO(plugin_ctx, &io);
301 return (ssize_t)io.status;
304 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence)
306 Plugin *plugin = (Plugin *)jcr->plugin;
307 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
309 Dmsg0(000, "plugin_bseek\n");
313 plug_func(plugin)->pluginIO(plugin_ctx, &io);
314 return (boffset_t)io.offset;
317 /* ==============================================================
319 * Callbacks from the plugin
321 * ==============================================================
323 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
325 JCR *jcr = (JCR *)(ctx->bContext);
326 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
330 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
333 *((int *)value) = jcr->JobId;
334 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
337 *((char **)value) = my_name;
338 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
351 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
353 Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
357 static bRC baculaRegisterEvents(bpContext *ctx, ...)
363 while ((event = va_arg(args, uint32_t))) {
364 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
370 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
371 int type, time_t mtime, const char *msg)
373 Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
374 file, line, type, mtime, msg);
378 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
379 int level, const char *msg)
381 Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
382 file, line, level, msg);
388 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
389 int (*plugin_bclose)(JCR *jcr) = NULL;
390 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
391 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
392 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
394 int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
399 int main(int argc, char *argv[])
401 char plugin_dir[1000];
406 strcpy(my_name, "test-fd");
408 getcwd(plugin_dir, sizeof(plugin_dir)-1);
409 load_fd_plugins(plugin_dir);
417 generate_plugin_event(jcr1, bEventJobStart);
418 generate_plugin_event(jcr1, bEventJobEnd);
419 generate_plugin_event(jcr2, bEventJobStart);
421 generate_plugin_event(jcr2, bEventJobEnd);
426 Dmsg0(dbglvl, "bacula: OK ...\n");
432 #endif /* TEST_PROGRAM */