2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 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, "jcr==NULL: 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 Systems(R) SA") != 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 */
293 if (jcr->plugin_ctx_list) return;
295 int num = b_plugin_list->size();
297 Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
302 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
304 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
305 Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
306 foreach_alist_index(i, plugin, b_plugin_list) {
307 /* Start a new instance of each plugin */
308 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
309 memset(b_ctx, 0, sizeof(bacula_ctx));
311 plugin_ctx_list[i].bContext = (void *)b_ctx;
312 plugin_ctx_list[i].pContext = NULL;
313 if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
314 b_ctx->disabled = true;
320 * Free the plugin instances for this Job
322 void free_plugins(JCR *jcr)
327 if (!b_plugin_list || !jcr->plugin_ctx_list) {
331 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
332 Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
333 foreach_alist_index(i, plugin, b_plugin_list) {
334 /* Free the plugin instance */
335 sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
336 free(plugin_ctx_list[i].bContext); /* free Bacula private context */
338 free(plugin_ctx_list);
339 jcr->plugin_ctx_list = NULL;
343 /* ==============================================================
345 * Callbacks from the plugin
347 * ==============================================================
351 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
357 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
366 *((int *)value) = jcr->JobId;
367 Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
370 *((char **)value) = jcr->Job;
371 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
379 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
382 if (!value || !ctx) {
385 // Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
386 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
390 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
391 /* Nothing implemented yet */
392 Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
396 static bRC baculaRegisterEvents(bpContext *ctx, ...)
402 while ((event = va_arg(args, uint32_t))) {
403 Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
409 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
410 int type, utime_t mtime, const char *fmt, ...)
417 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
422 va_start(arg_ptr, fmt);
423 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
425 Jmsg(jcr, type, mtime, "%s", buf);
429 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
430 int level, const char *fmt, ...)
435 va_start(arg_ptr, fmt);
436 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
438 d_msg(file, line, level, "%s", buf);
442 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
443 const char *imsg, const char *cmd)
445 return edit_device_codes(dcr, omsg, imsg, cmd);
450 int main(int argc, char *argv[])
452 char plugin_dir[1000];
457 strcpy(my_name, "test-dir");
459 getcwd(plugin_dir, sizeof(plugin_dir)-1);
460 load_sd_plugins(plugin_dir);
468 generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
469 generate_plugin_event(jcr1, bsdEventJobEnd);
470 generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
472 generate_plugin_event(jcr2, bsdEventJobEnd);
477 Dmsg0(dbglvl, "sd-plugin: Test OK ...\n");
483 #endif /* TEST_PROGRAM */