2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Main program to test loading and running Bacula plugins.
21 * Destined to become Bacula pluginloader, ...
23 * Kern Sibbald, October 2007
27 #include "sd_plugins.h"
29 const int dbglvl = 250;
30 const char *plugin_type = "-sd.so";
33 /* Forward referenced functions */
34 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value);
35 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value);
36 static bRC baculaRegisterEvents(bpContext *ctx, ...);
37 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
38 int type, utime_t mtime, const char *fmt, ...);
39 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
40 int level, const char *fmt, ...);
41 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
42 const char *imsg, const char *cmd);
43 static bool is_plugin_compatible(Plugin *plugin);
47 static bsdInfo binfo = {
49 SD_PLUGIN_INTERFACE_VERSION
52 /* Bacula entry points */
53 static bsdFuncs bfuncs = {
55 SD_PLUGIN_INTERFACE_VERSION,
61 baculaEditDeviceCodes,
65 * Bacula private context
68 JCR *jcr; /* jcr for plugin */
69 bRC rc; /* last return code */
70 bool disabled; /* set if plugin disabled */
73 static bool is_plugin_disabled(bpContext *plugin_ctx)
79 b_ctx = (bacula_ctx *)plugin_ctx->bContext;
80 return b_ctx->disabled;
84 static bool is_plugin_disabled(JCR *jcr)
86 return is_plugin_disabled(jcr->plugin_ctx);
91 * Create a plugin event
93 int generate_plugin_event(JCR *jcr, bsdEventType eventType, void *value)
95 bpContext *plugin_ctx;
101 if (!b_plugin_list) {
102 Dmsg0(dbglvl, "No b_plugin_list: generate_plugin_event ignored.\n");
106 Dmsg0(dbglvl, "No jcr: generate_plugin_event ignored.\n");
109 if (!jcr->plugin_ctx_list) {
110 Dmsg0(dbglvl, "No plugin_ctx_list: generate_plugin_event ignored.\n");
111 return bRC_OK; /* Return if no plugins loaded */
114 /* Always handle JobEnd and DeviceClose requests */
117 case bsdEventDeviceClose:
118 break; /* pass these through even if canceled */
120 if (jcr->is_job_canceled()) {
121 Dmsg0(dbglvl, "Cancel return from generate_plugin_event\n");
126 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
127 event.eventType = eventType;
129 Dmsg2(dbglvl, "sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
131 foreach_alist_index(i, plugin, b_plugin_list) {
132 plugin_ctx = &plugin_ctx_list[i];
133 if (is_plugin_disabled(plugin_ctx)) {
136 rc = sdplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
146 * Create a global plugin event -- i.e. no context
148 int generate_global_plugin_event(bsdGlobalEventType eventType, void *value)
155 if (!b_plugin_list) {
156 Dmsg0(dbglvl, "No b_plugin_list: generate_global_plugin_event ignored.\n");
159 event.eventType = eventType;
161 foreach_alist_index(i, plugin, b_plugin_list) {
162 if (sdplug_func(plugin)->handleGlobalPluginEvent != NULL) {
163 rc = sdplug_func(plugin)->handleGlobalPluginEvent(&event, value);
174 * Print to file the plugin info.
176 void dump_sd_plugin(Plugin *plugin, FILE *fp)
181 psdInfo *info = (psdInfo *) plugin->pinfo;
182 fprintf(fp, "\tversion=%d\n", info->version);
183 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
184 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
185 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
186 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
187 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
188 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
192 * This entry point is called internally by Bacula to ensure
193 * that the plugin IO calls come into this code.
195 void load_sd_plugins(const char *plugin_dir)
200 Dmsg0(dbglvl, "Load sd plugins\n");
202 Dmsg0(dbglvl, "No sd plugin dir!\n");
205 b_plugin_list = New(alist(10, not_owned_by_alist));
206 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
207 is_plugin_compatible)) {
208 /* Either none found, or some error */
209 if (b_plugin_list->size() == 0) {
210 delete b_plugin_list;
211 b_plugin_list = NULL;
212 Dmsg0(dbglvl, "No plugins loaded\n");
217 * Verify that the plugin is acceptable, and print information
220 foreach_alist_index(i, plugin, b_plugin_list) {
221 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
222 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
225 Dmsg1(dbglvl, "num plugins=%d\n", b_plugin_list->size());
226 dbg_plugin_add_hook(dump_sd_plugin);
230 * Check if a plugin is compatible. Called by the load_plugin function
231 * to allow us to verify the plugin.
233 static bool is_plugin_compatible(Plugin *plugin)
235 psdInfo *info = (psdInfo *)plugin->pinfo;
236 Dmsg0(50, "is_plugin_compatible called\n");
237 if (chk_dbglvl(50)) {
238 dump_sd_plugin(plugin, stdin);
240 if (strcmp(info->plugin_magic, SD_PLUGIN_MAGIC) != 0) {
241 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
242 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
243 Dmsg3(000, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
244 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
248 if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
249 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
250 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
251 Dmsg3(000, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
252 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
255 if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
256 strcmp(info->plugin_license, "AGPLv3") != 0 &&
257 strcmp(info->plugin_license, "Bacula") != 0) {
258 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
259 plugin->file, info->plugin_license);
260 Dmsg2(000, "Plugin license incompatible. Plugin=%s license=%s\n",
261 plugin->file, info->plugin_license);
264 if (info->size != sizeof(psdInfo)) {
265 Jmsg(NULL, M_ERROR, 0,
266 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
267 plugin->file, sizeof(psdInfo), info->size);
276 * Create a new instance of each plugin for this Job
278 void new_plugins(JCR *jcr)
283 Dmsg0(dbglvl, "=== enter new_plugins ===\n");
284 if (!b_plugin_list) {
285 Dmsg0(dbglvl, "No sd plugin list!\n");
288 if (jcr->is_job_canceled()) {
292 * If plugins already loaded, just return
294 if (jcr->plugin_ctx_list) {
298 int num = b_plugin_list->size();
300 Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
305 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
307 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
308 Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
309 foreach_alist_index(i, plugin, b_plugin_list) {
310 /* Start a new instance of each plugin */
311 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
312 memset(b_ctx, 0, sizeof(bacula_ctx));
314 plugin_ctx_list[i].bContext = (void *)b_ctx;
315 plugin_ctx_list[i].pContext = NULL;
316 if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
317 b_ctx->disabled = true;
323 * Free the plugin instances for this Job
325 void free_plugins(JCR *jcr)
330 if (!b_plugin_list || !jcr->plugin_ctx_list) {
334 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
335 Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
336 foreach_alist_index(i, plugin, b_plugin_list) {
337 /* Free the plugin instance */
338 sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
339 free(plugin_ctx_list[i].bContext); /* free Bacula private context */
341 free(plugin_ctx_list);
342 jcr->plugin_ctx_list = NULL;
346 /* ==============================================================
348 * Callbacks from the plugin
350 * ==============================================================
353 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
359 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
368 *((int *)value) = jcr->JobId;
369 Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
372 *((char **)value) = jcr->Job;
373 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
377 *((s_kw **)value) = dev_types;
385 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
388 if (!value || !ctx) {
391 // Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
392 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
396 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
397 /* Nothing implemented yet */
398 Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
402 static bRC baculaRegisterEvents(bpContext *ctx, ...)
408 while ((event = va_arg(args, uint32_t))) {
409 Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
415 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
416 int type, utime_t mtime, const char *fmt, ...)
423 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
428 va_start(arg_ptr, fmt);
429 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
431 Jmsg(jcr, type, mtime, "%s", buf);
435 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
436 int level, const char *fmt, ...)
441 va_start(arg_ptr, fmt);
442 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
444 d_msg(file, line, level, "%s", buf);
448 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
449 const char *imsg, const char *cmd)
451 return edit_device_codes(dcr, omsg, imsg, cmd);
456 int main(int argc, char *argv[])
458 char plugin_dir[1000];
463 strcpy(my_name, "test-dir");
465 getcwd(plugin_dir, sizeof(plugin_dir)-1);
466 load_sd_plugins(plugin_dir);
474 generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
475 generate_plugin_event(jcr1, bsdEventJobEnd);
476 generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
478 generate_plugin_event(jcr2, bsdEventJobEnd);
483 Dmsg0(dbglvl, "sd-plugin: Test OK ...\n");
489 #endif /* TEST_PROGRAM */