]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/sd_plugins.c
Tweak version date
[bacula/bacula] / bacula / src / stored / sd_plugins.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5
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.
12
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.
17
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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  * Main program to test loading and running Bacula plugins.
30  *   Destined to become Bacula pluginloader, ...
31  *
32  * Kern Sibbald, October 2007
33  */
34 #include "bacula.h"
35 #include "stored.h"
36 #include "sd_plugins.h"
37
38 const int dbglvl = 50;
39 const char *plugin_type = "-sd.so";
40
41
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);
53
54
55 /* Bacula info */
56 static bsdInfo binfo = {
57    sizeof(bsdFuncs),
58    SD_PLUGIN_INTERFACE_VERSION
59 };
60
61 /* Bacula entry points */
62 static bsdFuncs bfuncs = {
63    sizeof(bsdFuncs),
64    SD_PLUGIN_INTERFACE_VERSION,
65    baculaRegisterEvents,
66    baculaGetValue,
67    baculaSetValue,
68    baculaJobMsg,
69    baculaDebugMsg,
70    baculaEditDeviceCodes
71 };
72
73 /* 
74  * Bacula private context
75  */
76 struct bacula_ctx {
77    JCR *jcr;                             /* jcr for plugin */
78    bRC  rc;                              /* last return code */
79    bool disabled;                        /* set if plugin disabled */
80 };
81
82 static bool is_plugin_disabled(bpContext *plugin_ctx)
83 {
84    bacula_ctx *b_ctx;
85    if (!plugin_ctx) {
86       return true;
87    }
88    b_ctx = (bacula_ctx *)plugin_ctx->bContext;
89    return b_ctx->disabled;
90 }
91
92 #ifdef needed
93 static bool is_plugin_disabled(JCR *jcr)
94 {
95    return is_plugin_disabled(jcr->plugin_ctx);
96 }
97 #endif
98
99 /*
100  * Create a plugin event 
101  */
102 int generate_plugin_event(JCR *jcr, bsdEventType eventType, void *value)
103 {
104    bpContext *plugin_ctx;
105    bsdEvent event;
106    Plugin *plugin;
107    int i = 0;
108    bRC rc = bRC_OK;
109
110    if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) {
111       return bRC_OK;                  /* Return if no plugins loaded */
112    }
113    if (jcr->is_job_canceled()) {
114       return bRC_Cancel;
115    }
116
117    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
118    event.eventType = eventType;
119
120    Dmsg2(dbglvl, "sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
121
122    foreach_alist(plugin, bplugin_list) {
123       plugin_ctx = &plugin_ctx_list[i++];
124       if (is_plugin_disabled(plugin_ctx)) {
125          continue;
126       }
127       rc = sdplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
128       if (rc != bRC_OK) {
129          break;
130       }
131    }
132
133    return rc;
134 }
135
136 /*
137  * Print to file the plugin info.
138  */
139 void dump_sd_plugin(Plugin *plugin, FILE *fp)
140 {
141    if (!plugin) {
142       return ;
143    }
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));
152 }
153
154 /**
155  * This entry point is called internally by Bacula to ensure
156  *  that the plugin IO calls come into this code.
157  */
158 void load_sd_plugins(const char *plugin_dir)
159 {
160    Plugin *plugin;
161
162    Dmsg0(dbglvl, "Load sd plugins\n");
163    if (!plugin_dir) {
164       Dmsg0(dbglvl, "No sd plugin dir!\n");
165       return;
166    }
167    bplugin_list = New(alist(10, not_owned_by_alist));
168    if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, 
169                 is_plugin_compatible)) {
170       /* Either none found, or some error */
171       if (bplugin_list->size() == 0) {
172          delete bplugin_list;
173          bplugin_list = NULL;
174          Dmsg0(dbglvl, "No plugins loaded\n");
175          return;
176       }
177    }
178    /* 
179     * Verify that the plugin is acceptable, and print information
180     *  about it.
181     */
182    foreach_alist(plugin, bplugin_list) {
183       Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
184       Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
185    }
186
187    Dmsg1(dbglvl, "num plugins=%d\n", bplugin_list->size());
188    dbg_plugin_add_hook(dump_sd_plugin);
189 }
190
191 /**
192  * Check if a plugin is compatible.  Called by the load_plugin function
193  *  to allow us to verify the plugin.
194  */
195 static bool is_plugin_compatible(Plugin *plugin)
196 {
197    psdInfo *info = (psdInfo *)plugin->pinfo;
198    Dmsg0(50, "is_plugin_compatible called\n");
199    if (debug_level >= 50) {
200       dump_sd_plugin(plugin, stdin);
201    }
202    if (strcmp(info->plugin_magic, SD_PLUGIN_MAGIC) != 0) {
203       Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
204            plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
205       Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
206            plugin->file, SD_PLUGIN_MAGIC, info->plugin_magic);
207
208       return false;
209    }
210    if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
211       Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
212            plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
213       Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
214            plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
215       return false;
216    }
217    if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
218        strcmp(info->plugin_license, "AGPLv3") != 0 &&
219        strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
220       Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
221            plugin->file, info->plugin_license);
222       Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
223            plugin->file, info->plugin_license);
224       return false;
225    }
226    if (info->size != sizeof(psdInfo)) {
227       Jmsg(NULL, M_ERROR, 0,
228            _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
229            plugin->file, sizeof(psdInfo), info->size);
230       return false;
231    }
232       
233    return true;
234 }
235
236
237 /*
238  * Create a new instance of each plugin for this Job
239  */
240 void new_plugins(JCR *jcr)
241 {
242    Plugin *plugin;
243    int i = 0;
244
245    Dmsg0(dbglvl, "=== enter new_plugins ===\n");
246    if (!bplugin_list) {
247       Dmsg0(dbglvl, "No sd plugin list!\n");
248       return;
249    }
250    if (jcr->is_job_canceled()) {
251       return;
252    }
253
254    int num = bplugin_list->size();
255
256    Dmsg1(dbglvl, "sd-plugin-list size=%d\n", num);
257    if (num == 0) {
258       return;
259    }
260
261    jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
262
263    bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
264    Dmsg2(dbglvl, "Instantiate sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
265    foreach_alist(plugin, bplugin_list) {
266       /* Start a new instance of each plugin */
267       bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
268       memset(b_ctx, 0, sizeof(bacula_ctx));
269       b_ctx->jcr = jcr;
270       plugin_ctx_list[i].bContext = (void *)b_ctx;
271       plugin_ctx_list[i].pContext = NULL;
272       if (sdplug_func(plugin)->newPlugin(&plugin_ctx_list[i++]) != bRC_OK) {
273          b_ctx->disabled = true;
274       }
275    }
276 }
277
278 /*
279  * Free the plugin instances for this Job
280  */
281 void free_plugins(JCR *jcr)
282 {
283    Plugin *plugin;
284    int i = 0;
285
286    if (!bplugin_list || !jcr->plugin_ctx_list) {
287       return;
288    }
289
290    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
291    Dmsg2(dbglvl, "Free instance sd-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
292    foreach_alist(plugin, bplugin_list) {
293       /* Free the plugin instance */
294       sdplug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
295       free(plugin_ctx_list[i++].bContext);     /* free Bacula private context */
296    }
297    free(plugin_ctx_list);
298    jcr->plugin_ctx_list = NULL;
299 }
300
301
302 /* ==============================================================
303  *
304  * Callbacks from the plugin
305  *
306  * ==============================================================
307  */
308 static bRC baculaGetValue(bpContext *ctx, bsdrVariable var, void *value)
309 {
310    JCR *jcr;
311    if (!ctx) {
312       return bRC_Error;
313    }
314    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
315    if (!jcr) {
316       return bRC_Error;
317    }
318    if (!value) {
319       return bRC_Error;
320    }
321    switch (var) {
322    case bsdVarJobId:
323       *((int *)value) = jcr->JobId;
324       Dmsg1(dbglvl, "sd-plugin: return bVarJobId=%d\n", jcr->JobId);
325       break;
326    case bsdVarJobName:
327       *((char **)value) = jcr->Job;
328       Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
329       break;
330    default:
331       break;
332    }
333    return bRC_OK;
334 }
335
336 static bRC baculaSetValue(bpContext *ctx, bsdwVariable var, void *value)
337 {
338    JCR *jcr;   
339    if (!value || !ctx) {
340       return bRC_Error;
341    }
342 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
343    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
344    if (!jcr) {
345       return bRC_Error;
346    }
347 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
348    /* Nothing implemented yet */
349    Dmsg1(dbglvl, "sd-plugin: baculaSetValue var=%d\n", var);
350    return bRC_OK;
351 }
352
353 static bRC baculaRegisterEvents(bpContext *ctx, ...)
354 {
355    va_list args;
356    uint32_t event;
357
358    va_start(args, ctx);
359    while ((event = va_arg(args, uint32_t))) {
360       Dmsg1(dbglvl, "sd-Plugin wants event=%u\n", event);
361    }
362    va_end(args);
363    return bRC_OK;
364 }
365
366 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
367   int type, utime_t mtime, const char *fmt, ...)
368 {
369    va_list arg_ptr;
370    char buf[2000];
371    JCR *jcr;
372
373    if (ctx) {
374       jcr = ((bacula_ctx *)ctx->bContext)->jcr;
375    } else {
376       jcr = NULL;
377    }
378
379    va_start(arg_ptr, fmt);
380    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
381    va_end(arg_ptr);
382    Jmsg(jcr, type, mtime, "%s", buf);
383    return bRC_OK;
384 }
385
386 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
387   int level, const char *fmt, ...)
388 {
389    va_list arg_ptr;
390    char buf[2000];
391
392    va_start(arg_ptr, fmt);
393    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
394    va_end(arg_ptr);
395    d_msg(file, line, level, "%s", buf);
396    return bRC_OK;
397 }
398
399 static char *baculaEditDeviceCodes(DCR *dcr, char *omsg, 
400   const char *imsg, const char *cmd)
401 {
402    return edit_device_codes(dcr, omsg, imsg, cmd);
403 }
404
405 #ifdef TEST_PROGRAM
406
407 int main(int argc, char *argv[])
408 {
409    char plugin_dir[1000];
410    JCR mjcr1, mjcr2;
411    JCR *jcr1 = &mjcr1;
412    JCR *jcr2 = &mjcr2;
413
414    strcpy(my_name, "test-dir");
415     
416    getcwd(plugin_dir, sizeof(plugin_dir)-1);
417    load_sd_plugins(plugin_dir);
418
419    jcr1->JobId = 111;
420    new_plugins(jcr1);
421
422    jcr2->JobId = 222;
423    new_plugins(jcr2);
424
425    generate_plugin_event(jcr1, bsdEventJobStart, (void *)"Start Job 1");
426    generate_plugin_event(jcr1, bsdEventJobEnd);
427    generate_plugin_event(jcr2, bsdEventJobStart, (void *)"Start Job 1");
428    free_plugins(jcr1);
429    generate_plugin_event(jcr2, bsdEventJobEnd);
430    free_plugins(jcr2);
431
432    unload_plugins();
433
434    Dmsg0(dbglvl, "sd-plugin: OK ...\n");
435    close_memory_pool();
436    sm_dump(false);
437    return 0;
438 }
439
440 #endif /* TEST_PROGRAM */