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 "sd_plugins.h"
38 const int dbglvl = 50;
39 const char *plugin_type = "-sd.so";
42 /* Forward referenced functions */
43 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value);
44 static bRC baculaSetValue(bpContext *ctx, bsdwVariable 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 char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
51 const char *imsg, const char *cmd);
52 static bool is_plugin_compatible(Plugin *plugin);
56 static bsdInfo binfo = {
58 SD_PLUGIN_INTERFACE_VERSION
61 /* Bacula entry points */
62 static bsdFuncs bfuncs = {
64 SD_PLUGIN_INTERFACE_VERSION,
74 * Bacula private context
77 JCR *jcr; /* jcr for plugin */
78 bRC rc; /* last return code */
79 bool disabled; /* set if plugin disabled */
82 static bool is_plugin_disabled(bpContext *plugin_ctx)
88 b_ctx = (bacula_ctx *)plugin_ctx->bContext;
89 return b_ctx->disabled;
93 static bool is_plugin_disabled(JCR *jcr)
95 return is_plugin_disabled(jcr->plugin_ctx);
100 * Create a plugin event
102 int generate_plugin_event(JCR *jcr, bsdEventType eventType, void *value)
104 bpContext *plugin_ctx;
110 if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) {
111 return bRC_OK; /* Return if no plugins loaded */
113 if (jcr->is_job_canceled()) {
117 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
118 event.eventType = eventType;
120 Dmsg2(dbglvl, "sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
122 foreach_alist_index(i, plugin, bplugin_list) {
123 plugin_ctx = &plugin_ctx_list[i];
124 if (is_plugin_disabled(plugin_ctx)) {
127 rc = sdplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
137 * Print to file the plugin info.
139 void dump_sd_plugin(Plugin *plugin, FILE *fp)
144 psdInfo *info = (psdInfo *) plugin->pinfo;
145 fprintf(fp, "\tversion=%d\n", info->version);
146 fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
147 fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
148 fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
149 fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
150 fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
151 fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
155 * This entry point is called internally by Bacula to ensure
156 * that the plugin IO calls come into this code.
158 void load_sd_plugins(const char *plugin_dir)
163 Dmsg0(dbglvl, "Load sd plugins\n");
165 Dmsg0(dbglvl, "No sd plugin dir!\n");
168 bplugin_list = New(alist(10, not_owned_by_alist));
169 if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
170 is_plugin_compatible)) {
171 /* Either none found, or some error */
172 if (bplugin_list->size() == 0) {
175 Dmsg0(dbglvl, "No plugins loaded\n");
180 * Verify that the plugin is acceptable, and print information
183 foreach_alist_index(i, plugin, bplugin_list) {
184 Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
185 Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
188 Dmsg1(dbglvl, "num plugins=%d\n", bplugin_list->size());
189 dbg_plugin_add_hook(dump_sd_plugin);
193 * Check if a plugin is compatible. Called by the load_plugin function
194 * to allow us to verify the plugin.
196 static bool is_plugin_compatible(Plugin *plugin)
198 psdInfo *info = (psdInfo *)plugin->pinfo;
199 Dmsg0(50, "is_plugin_compatible called\n");
200 if (debug_level >= 50) {
201 dump_sd_plugin(plugin, stdin);
203 if (strcmp(info->plugin_magic, SD_PLUGIN_MAGIC) != 0) {
204 Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
205 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
206 Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
207 plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
211 if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
212 Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
213 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
214 Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
215 plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
218 if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
219 strcmp(info->plugin_license, "AGPLv3") != 0 &&
220 strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
221 Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
222 plugin->file, info->plugin_license);
223 Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
224 plugin->file, info->plugin_license);
227 if (info->size != sizeof(psdInfo)) {
228 Jmsg(NULL, M_ERROR, 0,
229 _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
230 plugin->file, sizeof(psdInfo), info->size);
239 * Create a new instance of each plugin for this Job
241 void new_plugins(JCR *jcr)
246 Dmsg0(dbglvl, "=== enter new_plugins ===\n");
248 Dmsg0(dbglvl, "No sd plugin list!\n");
251 if (jcr->is_job_canceled()) {
255 int num = bplugin_list->size();
257 Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
262 jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
264 bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
265 Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
266 foreach_alist_index(i, plugin, bplugin_list) {
267 /* Start a new instance of each plugin */
268 bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
269 memset(b_ctx, 0, sizeof(bacula_ctx));
271 plugin_ctx_list[i].bContext = (void *)b_ctx;
272 plugin_ctx_list[i].pContext = NULL;
273 if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
274 b_ctx->disabled = true;
280 * Free the plugin instances for this Job
282 void free_plugins(JCR *jcr)
287 if (!bplugin_list || !jcr->plugin_ctx_list) {
291 bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
292 Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
293 foreach_alist_index(i, plugin, bplugin_list) {
294 /* Free the plugin instance */
295 sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
296 free(plugin_ctx_list[i].bContext); /* free Bacula private context */
298 free(plugin_ctx_list);
299 jcr->plugin_ctx_list = NULL;
303 /* ==============================================================
305 * Callbacks from the plugin
307 * ==============================================================
309 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
315 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
324 *((int *)value) = jcr->JobId;
325 Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
328 *((char **)value) = jcr->Job;
329 Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
337 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
340 if (!value || !ctx) {
343 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
344 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
348 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
349 /* Nothing implemented yet */
350 Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
354 static bRC baculaRegisterEvents(bpContext *ctx, ...)
360 while ((event = va_arg(args, uint32_t))) {
361 Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
367 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
368 int type, utime_t mtime, const char *fmt, ...)
375 jcr = ((bacula_ctx *)ctx->bContext)->jcr;
380 va_start(arg_ptr, fmt);
381 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
383 Jmsg(jcr, type, mtime, "%s", buf);
387 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
388 int level, const char *fmt, ...)
393 va_start(arg_ptr, fmt);
394 bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
396 d_msg(file, line, level, "%s", buf);
400 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg,
401 const char *imsg, const char *cmd)
403 return edit_device_codes(dcr, omsg, imsg, cmd);
408 int main(int argc, char *argv[])
410 char plugin_dir[1000];
415 strcpy(my_name, "test-dir");
417 getcwd(plugin_dir, sizeof(plugin_dir)-1);
418 load_sd_plugins(plugin_dir);
426 generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
427 generate_plugin_event(jcr1, bsdEventJobEnd);
428 generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
430 generate_plugin_event(jcr2, bsdEventJobEnd);
435 Dmsg0(dbglvl, "sd-plugin: OK ...\n");
441 #endif /* TEST_PROGRAM */