2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2007-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Main program to test loading and running Bacula plugins.
22 * Destined to become Bacula pluginloader, ...
24 * Kern Sibbald, October 2007
28 #include "sd_plugins.h"
30 const int dbglvl = 250;
31 const char *plugin_type = "-sd.so";
34 /* Forward referenced functions */
35 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value);
36 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value);
37 static bRC baculaRegisterEvents(bpContext *ctx, ...);
38 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
39 int type, utime_t mtime, const char *fmt, ...);
40 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
41 int level, const char *fmt, ...);
42 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
43 const char *imsg, const char *cmd);
44 static bool is_plugin_compatible(Plugin *plugin);
48 static bsdInfo binfo = {
50 SD_PLUGIN_INTERFACE_VERSION
53 /* Bacula entry points */
54 static bsdFuncs bfuncs = {
56 SD_PLUGIN_INTERFACE_VERSION,
62 baculaEditDeviceCodes,
66 * Bacula private context
69 JCR *jcr; /* jcr for plugin */
70 bRC rc; /* last return code */
71 bool disabled; /* set if plugin disabled */
74 static bool is_plugin_disabled(bpContext *plugin_ctx)
80 b_ctx = (bacula_ctx *)plugin_ctx->bContext;
81 return b_ctx->disabled;
85 static bool is_plugin_disabled(JCR *jcr)
87 return is_plugin_disabled(jcr->plugin_ctx);
92 * Create a plugin event
94 int generate_plugin_event(JCR *jcr, bsdEventType eventType, void *value)
96 bpContext *plugin_ctx;
102 if (!b_plugin_list) {
103 Dmsg0(dbglvl, "No b_plugin_list: generate_plugin_event ignored.\n");
107 Dmsg0(dbglvl, "No jcr: generate_plugin_event ignored.\n");
110 if (!jcr->plugin_ctx_list) {
111 Dmsg0(dbglvl, "No plugin_ctx_list: generate_plugin_event ignored.\n");
112 return bRC_OK; /* Return if no plugins loaded */
115 /* Always handle JobEnd and DeviceClose requests */
118 case bsdEventDeviceClose:
119 break; /* pass these through even if canceled */
121 if (jcr->is_job_canceled()) {
122 Dmsg0(dbglvl, "Cancel return from generate_plugin_event\n");
127 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
128 event.eventType = eventType;
130 Dmsg2(dbglvl, "sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
132 foreach_alist_index(i, plugin, b_plugin_list) {
133 plugin_ctx = &plugin_ctx_list[i];
134 if (is_plugin_disabled(plugin_ctx)) {
137 rc = sdplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
147 * Create a global plugin event -- i.e. no context
149 int generate_global_plugin_event(bsdGlobalEventType eventType, void *value)
156 if (!b_plugin_list) {
157 Dmsg0(dbglvl, "No b_plugin_list: generate_global_plugin_event ignored.\n");
160 event.eventType = eventType;
162 foreach_alist_index(i, plugin, b_plugin_list) {
163 if (sdplug_func(plugin)->handleGlobalPluginEvent != NULL) {
164 rc = sdplug_func(plugin)->handleGlobalPluginEvent(&event, value);
175 * Print to file the plugin info.
177 void dump_sd_plugin(Plugin *plugin, FILE *fp)
182 psdInfo *info = (psdInfo *) plugin->pinfo;
183 fprintf(fp, "\tversion=%d\n", info->version);
184 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
185 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
186 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
187 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
188 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
189 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
193 * This entry point is called internally by Bacula to ensure
194 * that the plugin IO calls come into this code.
196 void load_sd_plugins(const char *plugin_dir)
201 Dmsg0(dbglvl, "Load sd plugins\n");
203 Dmsg0(dbglvl, "No sd plugin dir!\n");
206 b_plugin_list = New(alist(10, not_owned_by_alist));
207 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
208 is_plugin_compatible)) {
209 /* Either none found, or some error */
210 if (b_plugin_list->size() == 0) {
211 delete b_plugin_list;
212 b_plugin_list = NULL;
213 Dmsg0(dbglvl, "No plugins loaded\n");
218 * Verify that the plugin is acceptable, and print information
221 foreach_alist_index(i, plugin, b_plugin_list) {
222 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
223 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
226 Dmsg1(dbglvl, "num plugins=%d\n", b_plugin_list->size());
227 dbg_plugin_add_hook(dump_sd_plugin);
231 * Check if a plugin is compatible. Called by the load_plugin function
232 * to allow us to verify the plugin.
234 static bool is_plugin_compatible(Plugin *plugin)
236 psdInfo *info = (psdInfo *)plugin->pinfo;
237 Dmsg0(50, "is_plugin_compatible called\n");
238 if (chk_dbglvl(50)) {
239 dump_sd_plugin(plugin, stdin);
241 if (strcmp(info->plugin_magic, SD_PLUGIN_MAGIC) != 0) {
242 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
243 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
244 Dmsg3(000, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
245 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
249 if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
250 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
251 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
252 Dmsg3(000, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
253 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
256 if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
257 strcmp(info->plugin_license, "AGPLv3") != 0 &&
258 strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
259 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
260 plugin->file, info->plugin_license);
261 Dmsg2(000, "Plugin license incompatible. Plugin=%s license=%s\n",
262 plugin->file, info->plugin_license);
265 if (info->size != sizeof(psdInfo)) {
266 Jmsg(NULL, M_ERROR, 0,
267 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
268 plugin->file, sizeof(psdInfo), info->size);
277 * Create a new instance of each plugin for this Job
279 void new_plugins(JCR *jcr)
284 Dmsg0(dbglvl, "=== enter new_plugins ===\n");
285 if (!b_plugin_list) {
286 Dmsg0(dbglvl, "No sd plugin list!\n");
289 if (jcr->is_job_canceled()) {
293 * If plugins already loaded, just return
295 if (jcr->plugin_ctx_list) {
299 int num = b_plugin_list->size();
301 Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
306 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
308 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
309 Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
310 foreach_alist_index(i, plugin, b_plugin_list) {
311 /* Start a new instance of each plugin */
312 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
313 memset(b_ctx, 0, sizeof(bacula_ctx));
315 plugin_ctx_list[i].bContext = (void *)b_ctx;
316 plugin_ctx_list[i].pContext = NULL;
317 if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
318 b_ctx->disabled = true;
324 * Free the plugin instances for this Job
326 void free_plugins(JCR *jcr)
331 if (!b_plugin_list || !jcr->plugin_ctx_list) {
335 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
336 Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
337 foreach_alist_index(i, plugin, b_plugin_list) {
338 /* Free the plugin instance */
339 sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
340 free(plugin_ctx_list[i].bContext); /* free Bacula private context */
342 free(plugin_ctx_list);
343 jcr->plugin_ctx_list = NULL;
347 /* ==============================================================
349 * Callbacks from the plugin
351 * ==============================================================
355 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
361 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
370 *((int *)value) = jcr->JobId;
371 Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
374 *((char **)value) = jcr->Job;
375 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
383 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
386 if (!value || !ctx) {
389 // Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
390 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
394 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
395 /* Nothing implemented yet */
396 Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
400 static bRC baculaRegisterEvents(bpContext *ctx, ...)
406 while ((event = va_arg(args, uint32_t))) {
407 Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
413 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
414 int type, utime_t mtime, const char *fmt, ...)
421 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
426 va_start(arg_ptr, fmt);
427 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
429 Jmsg(jcr, type, mtime, "%s", buf);
433 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
434 int level, const char *fmt, ...)
439 va_start(arg_ptr, fmt);
440 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
442 d_msg(file, line, level, "%s", buf);
446 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
447 const char *imsg, const char *cmd)
449 return edit_device_codes(dcr, omsg, imsg, cmd);
454 int main(int argc, char *argv[])
456 char plugin_dir[1000];
461 strcpy(my_name, "test-dir");
463 getcwd(plugin_dir, sizeof(plugin_dir)-1);
464 load_sd_plugins(plugin_dir);
472 generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
473 generate_plugin_event(jcr1, bsdEventJobEnd);
474 generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
476 generate_plugin_event(jcr2, bsdEventJobEnd);
481 Dmsg0(dbglvl, "sd-plugin: Test OK ...\n");
487 #endif /* TEST_PROGRAM */