2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2011 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
36 #include "dir_plugins.h"
38 const int dbglvl = 50;
39 const char *plugin_type = "-dir.so";
42 /* Forward referenced functions */
43 static bRC baculaGetValue(bpContext *ctx, brDirVariable var, void *value);
44 static bRC baculaSetValue(bpContext *ctx, bwDirVariable var, void *value);
45 static bRC baculaRegisterEvents(bpContext *ctx, ...);
46 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
47 int type, utime_t mtime, const char *fmt, ...);
48 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
49 int level, const char *fmt, ...);
50 static bool is_plugin_compatible(Plugin *plugin);
54 static bDirInfo binfo = {
56 DIR_PLUGIN_INTERFACE_VERSION
59 /* Bacula entry points */
60 static bDirFuncs bfuncs = {
62 DIR_PLUGIN_INTERFACE_VERSION,
71 * Bacula private context
74 JCR *jcr; /* jcr for plugin */
75 bRC rc; /* last return code */
76 bool disabled; /* set if plugin disabled */
79 static bool is_plugin_disabled(bpContext *plugin_ctx)
85 b_ctx = (bacula_ctx *)plugin_ctx->bContext;
86 return b_ctx->disabled;
90 static bool is_plugin_disabled(JCR *jcr)
92 return is_plugin_disabled(jcr->plugin_ctx);
97 * Create a plugin event
99 int generate_plugin_event(JCR *jcr, bDirEventType eventType, void *value)
101 bpContext *plugin_ctx;
107 if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) {
108 return bRC_OK; /* Return if no plugins loaded */
110 if (jcr->is_job_canceled()) {
114 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
115 event.eventType = eventType;
117 Dmsg2(dbglvl, "dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
119 foreach_alist(plugin, bplugin_list) {
120 plugin_ctx = &plugin_ctx_list[i++];
121 if (is_plugin_disabled(plugin_ctx)) {
124 rc = dirplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
134 * Print to file the plugin info.
136 void dump_dir_plugin(Plugin *plugin, FILE *fp)
141 pDirInfo *info = (pDirInfo *) plugin->pinfo;
142 fprintf(fp, "\tversion=%d\n", info->version);
143 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
144 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
145 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
146 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
147 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
148 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
152 * This entry point is called internally by Bacula to ensure
153 * that the plugin IO calls come into this code.
155 void load_dir_plugins(const char *plugin_dir)
159 Dmsg0(dbglvl, "Load dir plugins\n");
161 Dmsg0(dbglvl, "No dir plugin dir!\n");
164 bplugin_list = New(alist(10, not_owned_by_alist));
165 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
166 is_plugin_compatible)) {
167 /* Either none found, or some error */
168 if (bplugin_list->size() == 0) {
171 Dmsg0(dbglvl, "No plugins loaded\n");
176 * Verify that the plugin is acceptable, and print information
179 foreach_alist(plugin, bplugin_list) {
180 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
181 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
184 Dmsg1(dbglvl, "num plugins=%d\n", bplugin_list->size());
185 dbg_plugin_add_hook(dump_dir_plugin);
189 * Check if a plugin is compatible. Called by the load_plugin function
190 * to allow us to verify the plugin.
192 static bool is_plugin_compatible(Plugin *plugin)
194 pDirInfo *info = (pDirInfo *)plugin->pinfo;
195 Dmsg0(50, "is_plugin_compatible called\n");
196 if (debug_level >= 50) {
197 dump_dir_plugin(plugin, stdin);
199 if (strcmp(info->plugin_magic, DIR_PLUGIN_MAGIC) != 0) {
200 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
201 plugin->file, DIR_PLUGIN_MAGIC, info->plugin_magic);
202 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
203 plugin->file, DIR_PLUGIN_MAGIC, info->plugin_magic);
207 if (info->version != DIR_PLUGIN_INTERFACE_VERSION) {
208 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
209 plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
210 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
211 plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
214 if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
215 strcmp(info->plugin_license, "AGPLv3") != 0 &&
216 strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
217 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
218 plugin->file, info->plugin_license);
219 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
220 plugin->file, info->plugin_license);
223 if (info->size != sizeof(pDirInfo)) {
224 Jmsg(NULL, M_ERROR, 0,
225 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
226 plugin->file, sizeof(pDirInfo), info->size);
235 * Create a new instance of each plugin for this Job
237 void new_plugins(JCR *jcr)
242 Dmsg0(dbglvl, "=== enter new_plugins ===\n");
244 Dmsg0(dbglvl, "No dir plugin list!\n");
247 if (jcr->is_job_canceled()) {
251 int num = bplugin_list->size();
253 Dmsg1(dbglvl, "dir-plugin-list size=%d\n", num);
258 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
260 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
261 Dmsg2(dbglvl, "Instantiate dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
262 foreach_alist(plugin, bplugin_list) {
263 /* Start a new instance of each plugin */
264 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
265 memset(b_ctx, 0, sizeof(bacula_ctx));
267 plugin_ctx_list[i].bContext = (void *)b_ctx;
268 plugin_ctx_list[i].pContext = NULL;
269 if (dirplug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
270 b_ctx->disabled = true;
276 * Free the plugin instances for this Job
278 void free_plugins(JCR *jcr)
283 if (!bplugin_list || !jcr->plugin_ctx_list) {
287 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
288 Dmsg2(dbglvl, "Free instance dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
289 foreach_alist(plugin, bplugin_list) {
290 /* Free the plugin instance */
291 dirplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
292 free(plugin_ctx_list[i++].bContext); /* free Bacula private context */
294 free(plugin_ctx_list);
295 jcr->plugin_ctx_list = NULL;
299 /* ==============================================================
301 * Callbacks from the plugin
303 * ==============================================================
305 static bRC baculaGetValue(bpContext *ctx, brDirVariable var, void *value)
313 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
322 *((int *)value) = jcr->JobId;
323 Dmsg1(dbglvl, "dir-plugin: return bDirVarJobId=%d\n", jcr->JobId);
326 *((char **)value) = jcr->Job;
327 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
330 *((char **)value) = jcr->job->hdr.name;
331 Dmsg1(dbglvl, "Bacula: return bDirVarJob=%s\n", jcr->job->hdr.name);
334 *((int *)value) = jcr->getJobLevel();
335 Dmsg1(dbglvl, "Bacula: return bDirVarLevel=%c\n", jcr->getJobLevel());
338 *((int *)value) = jcr->getJobType();
339 Dmsg1(dbglvl, "Bacula: return bDirVarType=%c\n", jcr->getJobType());
342 *((char **)value) = jcr->client->hdr.name;
343 Dmsg1(dbglvl, "Bacula: return bDirVarClient=%s\n", jcr->client->hdr.name);
347 memset(&pr, 0, sizeof(pr));
348 bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
349 if (!db_get_pool_record(jcr, jcr->db, &pr)) {
352 *((int *)value) = pr.NumVols;
353 Dmsg1(dbglvl, "Bacula: return bDirVarNumVols=%d\n", pr.NumVols);
356 *((char **)value) = jcr->pool->hdr.name;
357 Dmsg1(dbglvl, "Bacula: return bDirVarPool=%s\n", jcr->pool->hdr.name);
361 *((char **)value) = jcr->wstore->hdr.name;
362 } else if (jcr->rstore) {
363 *((char **)value) = jcr->rstore->hdr.name;
365 *((char **)value) = NULL;
368 Dmsg1(dbglvl, "Bacula: return bDirVarStorage=%s\n", NPRT(*((char **)value)));
370 case bDirVarWriteStorage:
372 *((char **)value) = jcr->wstore->hdr.name;
374 *((char **)value) = NULL;
377 Dmsg1(dbglvl, "Bacula: return bDirVarWriteStorage=%s\n", NPRT(*((char **)value)));
379 case bDirVarReadStorage:
381 *((char **)value) = jcr->rstore->hdr.name;
383 *((char **)value) = NULL;
386 Dmsg1(dbglvl, "Bacula: return bDirVarReadStorage=%s\n", NPRT(*((char **)value)));
389 *((char **)value) = jcr->catalog->hdr.name;
390 Dmsg1(dbglvl, "Bacula: return bDirVarCatalog=%s\n", jcr->catalog->hdr.name);
392 case bDirVarMediaType:
394 *((char **)value) = jcr->wstore->media_type;
395 } else if (jcr->rstore) {
396 *((char **)value) = jcr->rstore->media_type;
398 *((char **)value) = NULL;
401 Dmsg1(dbglvl, "Bacula: return bDirVarMediaType=%s\n", NPRT(*((char **)value)));
403 case bDirVarJobStatus:
404 *((int *)value) = jcr->JobStatus;
405 Dmsg1(dbglvl, "Bacula: return bDirVarJobStatus=%c\n", jcr->JobStatus);
407 case bDirVarPriority:
408 *((int *)value) = jcr->JobPriority;
409 Dmsg1(dbglvl, "Bacula: return bDirVarPriority=%d\n", jcr->JobPriority);
411 case bDirVarVolumeName:
412 *((char **)value) = jcr->VolumeName;
413 Dmsg1(dbglvl, "Bacula: return bDirVarVolumeName=%s\n", jcr->VolumeName);
415 case bDirVarCatalogRes:
418 case bDirVarJobErrors:
419 *((int *)value) = jcr->JobErrors;
420 Dmsg1(dbglvl, "Bacula: return bDirVarErrors=%d\n", jcr->JobErrors);
422 case bDirVarJobFiles:
423 *((int *)value) = jcr->JobFiles;
424 Dmsg1(dbglvl, "Bacula: return bDirVarFiles=%d\n", jcr->JobFiles);
426 case bDirVarSDJobFiles:
427 *((int *)value) = jcr->SDJobFiles;
428 Dmsg1(dbglvl, "Bacula: return bDirVarSDFiles=%d\n", jcr->SDJobFiles);
430 case bDirVarSDErrors:
431 *((int *)value) = jcr->SDErrors;
432 Dmsg1(dbglvl, "Bacula: return bDirVarSDErrors=%d\n", jcr->SDErrors);
434 case bDirVarFDJobStatus:
435 *((int *)value) = jcr->FDJobStatus;
436 Dmsg1(dbglvl, "Bacula: return bDirVarFDJobStatus=%c\n", jcr->FDJobStatus);
438 case bDirVarSDJobStatus:
439 *((int *)value) = jcr->SDJobStatus;
440 Dmsg1(dbglvl, "Bacula: return bDirVarSDJobStatus=%c\n", jcr->SDJobStatus);
448 static bRC baculaSetValue(bpContext *ctx, bwDirVariable var, void *value)
451 if (!value || !ctx) {
454 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
455 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
459 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
460 /* Nothing implemented yet */
461 Dmsg1(dbglvl, "dir-plugin: baculaSetValue var=%d\n", var);
465 static bRC baculaRegisterEvents(bpContext *ctx, ...)
471 while ((event = va_arg(args, uint32_t))) {
472 Dmsg1(dbglvl, "dir-Plugin wants event=%u\n", event);
478 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
479 int type, utime_t mtime, const char *fmt, ...)
486 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
491 va_start(arg_ptr, fmt);
492 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
494 Jmsg(jcr, type, mtime, "%s", buf);
498 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
499 int level, const char *fmt, ...)
504 va_start(arg_ptr, fmt);
505 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
507 d_msg(file, line, level, "%s", buf);
513 int main(int argc, char *argv[])
515 char plugin_dir[1000];
520 strcpy(my_name, "test-dir");
522 getcwd(plugin_dir, sizeof(plugin_dir)-1);
523 load_dir_plugins(plugin_dir);
531 generate_plugin_event(jcr1, bDirEventJobStart, (void *)"Start Job 1");
532 generate_plugin_event(jcr1, bDirEventJobEnd);
533 generate_plugin_event(jcr2, bDirEventJobStart, (void *)"Start Job 1");
535 generate_plugin_event(jcr2, bDirEventJobEnd);
540 Dmsg0(dbglvl, "dir-plugin: OK ...\n");
546 #endif /* TEST_PROGRAM */