2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 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 "dir_plugins.h"
29 const int dbglvl = 50;
30 const char *plugin_type = "-dir.so";
33 /* Forward referenced functions */
34 static bRC baculaGetValue(bpContext *ctx, brDirVariable var, void *value);
35 static bRC baculaSetValue(bpContext *ctx, bwDirVariable 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 bool is_plugin_compatible(Plugin *plugin);
45 static bDirInfo binfo = {
47 DIR_PLUGIN_INTERFACE_VERSION
50 /* Bacula entry points */
51 static bDirFuncs bfuncs = {
53 DIR_PLUGIN_INTERFACE_VERSION,
62 * Bacula private context
65 JCR *jcr; /* jcr for plugin */
66 bRC rc; /* last return code */
67 bool disabled; /* set if plugin disabled */
70 static bool is_plugin_disabled(bpContext *plugin_ctx)
76 b_ctx = (bacula_ctx *)plugin_ctx->bContext;
77 return b_ctx->disabled;
81 static bool is_plugin_disabled(JCR *jcr)
83 return is_plugin_disabled(jcr->plugin_ctx);
88 * Create a plugin event
90 int generate_plugin_event(JCR *jcr, bDirEventType eventType, void *value)
92 bpContext *plugin_ctx;
98 if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list) {
99 return bRC_OK; /* Return if no plugins loaded */
101 if (jcr->is_job_canceled()) {
105 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
106 event.eventType = eventType;
108 Dmsg2(dbglvl, "dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
110 foreach_alist_index(i, plugin, b_plugin_list) {
111 plugin_ctx = &plugin_ctx_list[i];
112 if (is_plugin_disabled(plugin_ctx)) {
115 rc = dirplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
125 * Print to file the plugin info.
127 void dump_dir_plugin(Plugin *plugin, FILE *fp)
132 pDirInfo *info = (pDirInfo *) plugin->pinfo;
133 fprintf(fp, "\tversion=%d\n", info->version);
134 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
135 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
136 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
137 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
138 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
139 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
143 * This entry point is called internally by Bacula to ensure
144 * that the plugin IO calls come into this code.
146 void load_dir_plugins(const char *plugin_dir)
151 Dmsg0(dbglvl, "Load Director plugins\n");
153 Dmsg0(dbglvl, "No Director plugin directory!\n");
156 b_plugin_list = New(alist(10, not_owned_by_alist));
157 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
158 is_plugin_compatible)) {
159 /* Either none found, or some error */
160 if (b_plugin_list->size() == 0) {
161 delete b_plugin_list;
162 b_plugin_list = NULL;
163 Dmsg0(dbglvl, "No plugins loaded\n");
168 * Verify that the plugin is acceptable, and print information
171 foreach_alist_index(i, plugin, b_plugin_list) {
172 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
173 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
176 Dmsg1(dbglvl, "num plugins=%d\n", b_plugin_list->size());
177 dbg_plugin_add_hook(dump_dir_plugin);
181 * Check if a plugin is compatible. Called by the load_plugin function
182 * to allow us to verify the plugin.
184 static bool is_plugin_compatible(Plugin *plugin)
186 pDirInfo *info = (pDirInfo *)plugin->pinfo;
187 Dmsg0(50, "is_plugin_compatible called\n");
188 if (chk_dbglvl(50)) {
189 dump_dir_plugin(plugin, stdin);
191 if (strcmp(info->plugin_magic, DIR_PLUGIN_MAGIC) != 0) {
192 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
193 plugin->file, DIR_PLUGIN_MAGIC, info->plugin_magic);
194 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
195 plugin->file, DIR_PLUGIN_MAGIC, info->plugin_magic);
199 if (info->version != DIR_PLUGIN_INTERFACE_VERSION) {
200 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
201 plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
202 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
203 plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
206 if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
207 strcmp(info->plugin_license, "AGPLv3") != 0 &&
208 strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
209 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
210 plugin->file, info->plugin_license);
211 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
212 plugin->file, info->plugin_license);
215 if (info->size != sizeof(pDirInfo)) {
216 Jmsg(NULL, M_ERROR, 0,
217 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
218 plugin->file, sizeof(pDirInfo), info->size);
227 * Create a new instance of each plugin for this Job
229 void new_plugins(JCR *jcr)
234 Dmsg0(dbglvl, "=== enter new_plugins ===\n");
235 if (!b_plugin_list) {
236 Dmsg0(dbglvl, "No Director plugin list!\n");
239 if (jcr->is_job_canceled()) {
243 int num = b_plugin_list->size();
245 Dmsg1(dbglvl, "dir-plugin-list size=%d\n", num);
250 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
252 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
253 Dmsg2(dbglvl, "Instantiate dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
254 foreach_alist_index(i, plugin, b_plugin_list) {
255 /* Start a new instance of each plugin */
256 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
257 memset(b_ctx, 0, sizeof(bacula_ctx));
259 plugin_ctx_list[i].bContext = (void *)b_ctx;
260 plugin_ctx_list[i].pContext = NULL;
261 if (dirplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
262 b_ctx->disabled = true;
268 * Free the plugin instances for this Job
270 void free_plugins(JCR *jcr)
275 if (!b_plugin_list || !jcr->plugin_ctx_list) {
279 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
280 Dmsg2(dbglvl, "Free instance dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
281 foreach_alist_index(i, plugin, b_plugin_list) {
282 /* Free the plugin instance */
283 dirplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
284 free(plugin_ctx_list[i].bContext); /* free Bacula private context */
286 free(plugin_ctx_list);
287 jcr->plugin_ctx_list = NULL;
291 /* ==============================================================
293 * Callbacks from the plugin
295 * ==============================================================
297 static bRC baculaGetValue(bpContext *ctx, brDirVariable var, void *value)
305 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
314 *((int *)value) = jcr->JobId;
315 Dmsg1(dbglvl, "dir-plugin: return bDirVarJobId=%d\n", jcr->JobId);
318 *((char **)value) = jcr->Job;
319 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
322 *((char **)value) = jcr->job->hdr.name;
323 Dmsg1(dbglvl, "Bacula: return bDirVarJob=%s\n", jcr->job->hdr.name);
326 *((int *)value) = jcr->getJobLevel();
327 Dmsg1(dbglvl, "Bacula: return bDirVarLevel=%c\n", jcr->getJobLevel());
330 *((int *)value) = jcr->getJobType();
331 Dmsg1(dbglvl, "Bacula: return bDirVarType=%c\n", jcr->getJobType());
334 *((char **)value) = jcr->client->hdr.name;
335 Dmsg1(dbglvl, "Bacula: return bDirVarClient=%s\n", jcr->client->hdr.name);
339 memset(&pr, 0, sizeof(pr));
340 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
341 if (!db_get_pool_numvols(jcr, jcr->db, &pr)) {
344 *((int *)value) = pr.NumVols;
345 Dmsg1(dbglvl, "Bacula: return bDirVarNumVols=%d\n", pr.NumVols);
348 *((char **)value) = jcr->pool->hdr.name;
349 Dmsg1(dbglvl, "Bacula: return bDirVarPool=%s\n", jcr->pool->hdr.name);
353 *((char **)value) = jcr->wstore->hdr.name;
354 } else if (jcr->rstore) {
355 *((char **)value) = jcr->rstore->hdr.name;
357 *((char **)value) = NULL;
360 Dmsg1(dbglvl, "Bacula: return bDirVarStorage=%s\n", NPRT(*((char **)value)));
362 case bDirVarWriteStorage:
364 *((char **)value) = jcr->wstore->hdr.name;
366 *((char **)value) = NULL;
369 Dmsg1(dbglvl, "Bacula: return bDirVarWriteStorage=%s\n", NPRT(*((char **)value)));
371 case bDirVarReadStorage:
373 *((char **)value) = jcr->rstore->hdr.name;
375 *((char **)value) = NULL;
378 Dmsg1(dbglvl, "Bacula: return bDirVarReadStorage=%s\n", NPRT(*((char **)value)));
381 *((char **)value) = jcr->catalog->hdr.name;
382 Dmsg1(dbglvl, "Bacula: return bDirVarCatalog=%s\n", jcr->catalog->hdr.name);
384 case bDirVarMediaType:
386 *((char **)value) = jcr->wstore->media_type;
387 } else if (jcr->rstore) {
388 *((char **)value) = jcr->rstore->media_type;
390 *((char **)value) = NULL;
393 Dmsg1(dbglvl, "Bacula: return bDirVarMediaType=%s\n", NPRT(*((char **)value)));
395 case bDirVarJobStatus:
396 *((int *)value) = jcr->JobStatus;
397 Dmsg1(dbglvl, "Bacula: return bDirVarJobStatus=%c\n", jcr->JobStatus);
399 case bDirVarPriority:
400 *((int *)value) = jcr->JobPriority;
401 Dmsg1(dbglvl, "Bacula: return bDirVarPriority=%d\n", jcr->JobPriority);
403 case bDirVarVolumeName:
404 *((char **)value) = jcr->VolumeName;
405 Dmsg1(dbglvl, "Bacula: return bDirVarVolumeName=%s\n", jcr->VolumeName);
407 case bDirVarCatalogRes:
410 case bDirVarJobErrors:
411 *((int *)value) = jcr->JobErrors;
412 Dmsg1(dbglvl, "Bacula: return bDirVarErrors=%d\n", jcr->JobErrors);
414 case bDirVarJobFiles:
415 *((int *)value) = jcr->JobFiles;
416 Dmsg1(dbglvl, "Bacula: return bDirVarFiles=%d\n", jcr->JobFiles);
418 case bDirVarSDJobFiles:
419 *((int *)value) = jcr->SDJobFiles;
420 Dmsg1(dbglvl, "Bacula: return bDirVarSDFiles=%d\n", jcr->SDJobFiles);
422 case bDirVarSDErrors:
423 *((int *)value) = jcr->SDErrors;
424 Dmsg1(dbglvl, "Bacula: return bDirVarSDErrors=%d\n", jcr->SDErrors);
426 case bDirVarFDJobStatus:
427 *((int *)value) = jcr->FDJobStatus;
428 Dmsg1(dbglvl, "Bacula: return bDirVarFDJobStatus=%c\n", jcr->FDJobStatus);
430 case bDirVarSDJobStatus:
431 *((int *)value) = jcr->SDJobStatus;
432 Dmsg1(dbglvl, "Bacula: return bDirVarSDJobStatus=%c\n", jcr->SDJobStatus);
440 static bRC baculaSetValue(bpContext *ctx, bwDirVariable var, void *value)
443 if (!value || !ctx) {
446 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
447 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
451 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
452 /* Nothing implemented yet */
453 Dmsg1(dbglvl, "dir-plugin: baculaSetValue var=%d\n", var);
457 static bRC baculaRegisterEvents(bpContext *ctx, ...)
463 while ((event = va_arg(args, uint32_t))) {
464 Dmsg1(dbglvl, "dir-Plugin wants event=%u\n", event);
470 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
471 int type, utime_t mtime, const char *fmt, ...)
478 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
483 va_start(arg_ptr, fmt);
484 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
486 Jmsg(jcr, type, mtime, "%s", buf);
490 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
491 int level, const char *fmt, ...)
496 va_start(arg_ptr, fmt);
497 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
499 d_msg(file, line, level, "%s", buf);
505 int main(int argc, char *argv[])
507 char plugin_dir[1000];
512 strcpy(my_name, "test-dir");
514 getcwd(plugin_dir, sizeof(plugin_dir)-1);
515 load_dir_plugins(plugin_dir);
523 generate_plugin_event(jcr1, bDirEventJobStart, (void *)"Start Job 1");
524 generate_plugin_event(jcr1, bDirEventJobEnd);
525 generate_plugin_event(jcr2, bDirEventJobStart, (void *)"Start Job 1");
527 generate_plugin_event(jcr2, bDirEventJobEnd);
532 Dmsg0(dbglvl, "dir-plugin: OK ...\n");
538 #endif /* TEST_PROGRAM */