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;
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);
107 if (eventType != bEventPluginCommand) {
108 /* Pass event to every plugin */
109 foreach_alist(plugin, plugin_list) {
110 plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
115 /* Handle plugin command here (backup/restore of file) */
116 Dmsg1(000, "plugin cmd=%s\n", cmd);
117 if (!(p = strchr(cmd, ':'))) {
118 Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
126 foreach_alist(plugin, plugin_list) {
127 Dmsg3(000, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
128 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 printf("st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
140 if (plug_func(plugin)->startPluginBackup(&plugin_ctx_list[i], &sp) != bRC_OK) {
143 jcr->plugin_ctx = &plugin_ctx_list[i];
144 jcr->plugin = plugin;
145 jcr->plugin_sp = &sp;
147 ff_pkt->fname = sp.fname;
148 ff_pkt->type = sp.type;
149 memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
150 Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname);
151 save_file(ff_pkt, (void *)jcr, true);
162 * Send plugin name start/end record to SD
164 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
167 struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
168 Plugin *plugin = (Plugin *)jcr->plugin;
170 if (!sd->fsend("%ld %d %d", jcr->JobFiles, STREAM_PLUGIN_NAME, start)) {
171 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
176 stat = sd->fsend("%ld 1 %d %s%c%s%c", jcr->JobFiles, sp->portable, plugin->file, 0,
179 stat = sd->fsend("%ld 0 %d %s%c%s%c", jcr->JobFiles, sp->portable, plugin->file, 0,
183 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
187 sd->signal(BNET_EOD); /* indicate end of plugin name data */
192 void load_fd_plugins(const char *plugin_dir)
198 plugin_list = New(alist(10, not_owned_by_alist));
199 load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
200 plugin_bopen = my_plugin_bopen;
201 plugin_bclose = my_plugin_bclose;
202 plugin_bread = my_plugin_bread;
203 plugin_bwrite = my_plugin_bwrite;
204 plugin_blseek = my_plugin_blseek;
209 * Create a new instance of each plugin for this Job
211 void new_plugins(JCR *jcr)
220 int num = plugin_list->size();
226 jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
228 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
229 Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
230 foreach_alist(plugin, plugin_list) {
231 /* Start a new instance of each plugin */
232 plugin_ctx_list[i].bContext = (void *)jcr;
233 plugin_ctx_list[i].pContext = NULL;
234 plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
239 * Free the plugin instances for this Job
241 void free_plugins(JCR *jcr)
250 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
251 Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
252 foreach_alist(plugin, plugin_list) {
253 /* Free the plugin instance */
254 plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
256 free(plugin_ctx_list);
257 jcr->plugin_ctx_list = NULL;
260 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode)
262 Plugin *plugin = (Plugin *)jcr->plugin;
263 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
265 Dmsg0(000, "plugin_bopen\n");
269 plug_func(plugin)->pluginIO(plugin_ctx, &io);
273 static int my_plugin_bclose(JCR *jcr)
275 Plugin *plugin = (Plugin *)jcr->plugin;
276 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
278 Dmsg0(000, "plugin_bclose\n");
282 plug_func(plugin)->pluginIO(plugin_ctx, &io);
286 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count)
288 Plugin *plugin = (Plugin *)jcr->plugin;
289 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
291 Dmsg0(000, "plugin_bread\n");
294 io.buf = (char *)buf;
295 plug_func(plugin)->pluginIO(plugin_ctx, &io);
296 return (ssize_t)io.status;
299 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count)
301 Plugin *plugin = (Plugin *)jcr->plugin;
302 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
304 Dmsg0(000, "plugin_bwrite\n");
307 io.buf = (char *)buf;
308 plug_func(plugin)->pluginIO(plugin_ctx, &io);
309 return (ssize_t)io.status;
312 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence)
314 Plugin *plugin = (Plugin *)jcr->plugin;
315 bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
317 Dmsg0(000, "plugin_bseek\n");
321 plug_func(plugin)->pluginIO(plugin_ctx, &io);
322 return (boffset_t)io.offset;
325 /* ==============================================================
327 * Callbacks from the plugin
329 * ==============================================================
331 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
333 JCR *jcr = (JCR *)(ctx->bContext);
334 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
338 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
341 *((int *)value) = jcr->JobId;
342 Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
345 *((char **)value) = my_name;
346 Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
359 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
361 Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
365 static bRC baculaRegisterEvents(bpContext *ctx, ...)
371 while ((event = va_arg(args, uint32_t))) {
372 Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
378 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
379 int type, time_t mtime, const char *msg)
381 Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
382 file, line, type, mtime, msg);
386 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
387 int level, const char *msg)
389 Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
390 file, line, level, msg);
396 int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
397 int (*plugin_bclose)(JCR *jcr) = NULL;
398 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
399 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
400 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
402 int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
407 int main(int argc, char *argv[])
409 char plugin_dir[1000];
414 strcpy(my_name, "test-fd");
416 getcwd(plugin_dir, sizeof(plugin_dir)-1);
417 load_fd_plugins(plugin_dir);
425 generate_plugin_event(jcr1, bEventJobStart);
426 generate_plugin_event(jcr1, bEventJobEnd);
427 generate_plugin_event(jcr2, bEventJobStart);
429 generate_plugin_event(jcr2, bEventJobEnd);
434 Dmsg0(dbglvl, "bacula: OK ...\n");
440 #endif /* TEST_PROGRAM */