]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dir_plugins.c
Remove old Bacula Systems notices
[bacula/bacula] / bacula / src / dird / dir_plugins.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Main program to test loading and running Bacula plugins.
21  *   Destined to become Bacula pluginloader, ...
22  *
23  * Kern Sibbald, October 2007
24  */
25 #include "bacula.h"
26 #include "dird.h"
27 #include "dir_plugins.h"
28
29 const int dbglvl = 50;
30 const char *plugin_type = "-dir.so";
31
32
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);
42
43
44 /* Bacula info */
45 static bDirInfo binfo = {
46    sizeof(bDirFuncs),
47    DIR_PLUGIN_INTERFACE_VERSION
48 };
49
50 /* Bacula entry points */
51 static bDirFuncs bfuncs = {
52    sizeof(bDirFuncs),
53    DIR_PLUGIN_INTERFACE_VERSION,
54    baculaRegisterEvents,
55    baculaGetValue,
56    baculaSetValue,
57    baculaJobMsg,
58    baculaDebugMsg
59 };
60
61 /*
62  * Bacula private context
63  */
64 struct bacula_ctx {
65    JCR *jcr;                             /* jcr for plugin */
66    bRC  rc;                              /* last return code */
67    bool disabled;                        /* set if plugin disabled */
68 };
69
70 static bool is_plugin_disabled(bpContext *plugin_ctx)
71 {
72    bacula_ctx *b_ctx;
73    if (!plugin_ctx) {
74       return true;
75    }
76    b_ctx = (bacula_ctx *)plugin_ctx->bContext;
77    return b_ctx->disabled;
78 }
79
80 #ifdef needed
81 static bool is_plugin_disabled(JCR *jcr)
82 {
83    return is_plugin_disabled(jcr->plugin_ctx);
84 }
85 #endif
86
87 /*
88  * Create a plugin event
89  */
90 int generate_plugin_event(JCR *jcr, bDirEventType eventType, void *value)
91 {
92    bpContext *plugin_ctx;
93    bDirEvent event;
94    Plugin *plugin;
95    int i = 0;
96    bRC rc = bRC_OK;
97
98    if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list) {
99       return bRC_OK;                  /* Return if no plugins loaded */
100    }
101    if (jcr->is_job_canceled()) {
102       return bRC_Cancel;
103    }
104
105    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
106    event.eventType = eventType;
107
108    Dmsg2(dbglvl, "dir-plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
109
110    foreach_alist_index(i, plugin, b_plugin_list) {
111       plugin_ctx = &plugin_ctx_list[i];
112       if (is_plugin_disabled(plugin_ctx)) {
113          continue;
114       }
115       rc = dirplug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
116       if (rc != bRC_OK) {
117          break;
118       }
119    }
120
121    return rc;
122 }
123
124 /*
125  * Print to file the plugin info.
126  */
127 void dump_dir_plugin(Plugin *plugin, FILE *fp)
128 {
129    if (!plugin) {
130       return ;
131    }
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));
140 }
141
142 /**
143  * This entry point is called internally by Bacula to ensure
144  *  that the plugin IO calls come into this code.
145  */
146 void load_dir_plugins(const char *plugin_dir)
147 {
148    Plugin *plugin;
149    int i;
150
151    Dmsg0(dbglvl, "Load Director plugins\n");
152    if (!plugin_dir) {
153       Dmsg0(dbglvl, "No Director plugin directory!\n");
154       return;
155    }
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");
164          return;
165       }
166    }
167    /*
168     * Verify that the plugin is acceptable, and print information
169     *  about it.
170     */
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);
174    }
175
176    Dmsg1(dbglvl, "num plugins=%d\n", b_plugin_list->size());
177    dbg_plugin_add_hook(dump_dir_plugin);
178 }
179
180 /**
181  * Check if a plugin is compatible.  Called by the load_plugin function
182  *  to allow us to verify the plugin.
183  */
184 static bool is_plugin_compatible(Plugin *plugin)
185 {
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);
190    }
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);
196
197       return false;
198    }
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);
204       return false;
205    }
206    if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
207        strcmp(info->plugin_license, "AGPLv3") != 0 &&
208        strcmp(info->plugin_license, "Bacula") != 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);
213       return false;
214    }
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);
219       return false;
220    }
221
222    return true;
223 }
224
225
226 /*
227  * Create a new instance of each plugin for this Job
228  */
229 void new_plugins(JCR *jcr)
230 {
231    Plugin *plugin;
232    int i = 0;
233
234    Dmsg0(dbglvl, "=== enter new_plugins ===\n");
235    if (!b_plugin_list) {
236       Dmsg0(dbglvl, "No Director plugin list!\n");
237       return;
238    }
239    if (jcr->is_job_canceled()) {
240       return;
241    }
242
243    int num = b_plugin_list->size();
244
245    Dmsg1(dbglvl, "dir-plugin-list size=%d\n", num);
246    if (num == 0) {
247       return;
248    }
249
250    jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
251
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));
258       b_ctx->jcr = jcr;
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;
263       }
264    }
265 }
266
267 /*
268  * Free the plugin instances for this Job
269  */
270 void free_plugins(JCR *jcr)
271 {
272    Plugin *plugin;
273    int i = 0;
274
275    if (!b_plugin_list || !jcr->plugin_ctx_list) {
276       return;
277    }
278
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 */
285    }
286    free(plugin_ctx_list);
287    jcr->plugin_ctx_list = NULL;
288 }
289
290
291 /* ==============================================================
292  *
293  * Callbacks from the plugin
294  *
295  * ==============================================================
296  */
297 static bRC baculaGetValue(bpContext *ctx, brDirVariable var, void *value)
298 {
299    JCR *jcr;
300    bRC ret = bRC_OK;
301
302    if (!ctx) {
303       return bRC_Error;
304    }
305    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
306    if (!jcr) {
307       return bRC_Error;
308    }
309    if (!value) {
310       return bRC_Error;
311    }
312    switch (var) {
313    case bDirVarJobId:
314       *((int *)value) = jcr->JobId;
315       Dmsg1(dbglvl, "dir-plugin: return bDirVarJobId=%d\n", jcr->JobId);
316       break;
317    case bDirVarJobName:
318       *((char **)value) = jcr->Job;
319       Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
320       break;
321    case bDirVarJob:
322       *((char **)value) = jcr->job->hdr.name;
323       Dmsg1(dbglvl, "Bacula: return bDirVarJob=%s\n", jcr->job->hdr.name);
324       break;
325    case bDirVarLevel:
326       *((int *)value) = jcr->getJobLevel();
327       Dmsg1(dbglvl, "Bacula: return bDirVarLevel=%c\n", jcr->getJobLevel());
328       break;
329    case bDirVarType:
330       *((int *)value) = jcr->getJobType();
331       Dmsg1(dbglvl, "Bacula: return bDirVarType=%c\n", jcr->getJobType());
332       break;
333    case bDirVarClient:
334       *((char **)value) = jcr->client->hdr.name;
335       Dmsg1(dbglvl, "Bacula: return bDirVarClient=%s\n", jcr->client->hdr.name);
336       break;
337    case bDirVarNumVols:
338       POOL_DBR pr;
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)) {
342          ret=bRC_Error;
343       }
344       *((int *)value) = pr.NumVols;
345       Dmsg1(dbglvl, "Bacula: return bDirVarNumVols=%d\n", pr.NumVols);
346       break;
347    case bDirVarPool:
348       *((char **)value) = jcr->pool->hdr.name;
349       Dmsg1(dbglvl, "Bacula: return bDirVarPool=%s\n", jcr->pool->hdr.name);
350       break;
351    case bDirVarStorage:
352       if (jcr->wstore) {
353          *((char **)value) = jcr->wstore->hdr.name;
354       } else if (jcr->rstore) {
355          *((char **)value) = jcr->rstore->hdr.name;
356       } else {
357          *((char **)value) = NULL;
358          ret=bRC_Error;
359       }
360       Dmsg1(dbglvl, "Bacula: return bDirVarStorage=%s\n", NPRT(*((char **)value)));
361       break;
362    case bDirVarWriteStorage:
363       if (jcr->wstore) {
364          *((char **)value) = jcr->wstore->hdr.name;
365       } else {
366          *((char **)value) = NULL;
367          ret=bRC_Error;
368       }
369       Dmsg1(dbglvl, "Bacula: return bDirVarWriteStorage=%s\n", NPRT(*((char **)value)));
370       break;
371    case bDirVarReadStorage:
372       if (jcr->rstore) {
373          *((char **)value) = jcr->rstore->hdr.name;
374       } else {
375          *((char **)value) = NULL;
376          ret=bRC_Error;
377       }
378       Dmsg1(dbglvl, "Bacula: return bDirVarReadStorage=%s\n", NPRT(*((char **)value)));
379       break;
380    case bDirVarCatalog:
381       *((char **)value) = jcr->catalog->hdr.name;
382       Dmsg1(dbglvl, "Bacula: return bDirVarCatalog=%s\n", jcr->catalog->hdr.name);
383       break;
384    case bDirVarMediaType:
385       if (jcr->wstore) {
386          *((char **)value) = jcr->wstore->media_type;
387       } else if (jcr->rstore) {
388          *((char **)value) = jcr->rstore->media_type;
389       } else {
390          *((char **)value) = NULL;
391          ret=bRC_Error;
392       }
393       Dmsg1(dbglvl, "Bacula: return bDirVarMediaType=%s\n", NPRT(*((char **)value)));
394       break;
395    case bDirVarJobStatus:
396       *((int *)value) = jcr->JobStatus;
397       Dmsg1(dbglvl, "Bacula: return bDirVarJobStatus=%c\n", jcr->JobStatus);
398       break;
399    case bDirVarPriority:
400       *((int *)value) = jcr->JobPriority;
401       Dmsg1(dbglvl, "Bacula: return bDirVarPriority=%d\n", jcr->JobPriority);
402       break;
403    case bDirVarVolumeName:
404       *((char **)value) = jcr->VolumeName;
405       Dmsg1(dbglvl, "Bacula: return bDirVarVolumeName=%s\n", jcr->VolumeName);
406       break;
407    case bDirVarCatalogRes:
408       ret = bRC_Error;
409       break;
410    case bDirVarJobErrors:
411       *((int *)value) = jcr->JobErrors;
412       Dmsg1(dbglvl, "Bacula: return bDirVarErrors=%d\n", jcr->JobErrors);
413       break;
414    case bDirVarJobFiles:
415       *((int *)value) = jcr->JobFiles;
416       Dmsg1(dbglvl, "Bacula: return bDirVarFiles=%d\n", jcr->JobFiles);
417       break;
418    case bDirVarSDJobFiles:
419       *((int *)value) = jcr->SDJobFiles;
420       Dmsg1(dbglvl, "Bacula: return bDirVarSDFiles=%d\n", jcr->SDJobFiles);
421       break;
422    case bDirVarSDErrors:
423       *((int *)value) = jcr->SDErrors;
424       Dmsg1(dbglvl, "Bacula: return bDirVarSDErrors=%d\n", jcr->SDErrors);
425       break;
426    case bDirVarFDJobStatus:
427       *((int *)value) = jcr->FDJobStatus;
428       Dmsg1(dbglvl, "Bacula: return bDirVarFDJobStatus=%c\n", jcr->FDJobStatus);
429       break;
430    case bDirVarSDJobStatus:
431       *((int *)value) = jcr->SDJobStatus;
432       Dmsg1(dbglvl, "Bacula: return bDirVarSDJobStatus=%c\n", jcr->SDJobStatus);
433       break;
434    default:
435       break;
436    }
437    return ret;
438 }
439
440 static bRC baculaSetValue(bpContext *ctx, bwDirVariable var, void *value)
441 {
442    JCR *jcr;
443    if (!value || !ctx) {
444       return bRC_Error;
445    }
446 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
447    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
448    if (!jcr) {
449       return bRC_Error;
450    }
451 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
452    /* Nothing implemented yet */
453    Dmsg1(dbglvl, "dir-plugin: baculaSetValue var=%d\n", var);
454    return bRC_OK;
455 }
456
457 static bRC baculaRegisterEvents(bpContext *ctx, ...)
458 {
459    va_list args;
460    uint32_t event;
461
462    va_start(args, ctx);
463    while ((event = va_arg(args, uint32_t))) {
464       Dmsg1(dbglvl, "dir-Plugin wants event=%u\n", event);
465    }
466    va_end(args);
467    return bRC_OK;
468 }
469
470 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
471   int type, utime_t mtime, const char *fmt, ...)
472 {
473    va_list arg_ptr;
474    char buf[2000];
475    JCR *jcr;
476
477    if (ctx) {
478       jcr = ((bacula_ctx *)ctx->bContext)->jcr;
479    } else {
480       jcr = NULL;
481    }
482
483    va_start(arg_ptr, fmt);
484    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
485    va_end(arg_ptr);
486    Jmsg(jcr, type, mtime, "%s", buf);
487    return bRC_OK;
488 }
489
490 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
491   int level, const char *fmt, ...)
492 {
493    va_list arg_ptr;
494    char buf[2000];
495
496    va_start(arg_ptr, fmt);
497    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
498    va_end(arg_ptr);
499    d_msg(file, line, level, "%s", buf);
500    return bRC_OK;
501 }
502
503 #ifdef TEST_PROGRAM
504
505 int main(int argc, char *argv[])
506 {
507    char plugin_dir[1000];
508    JCR mjcr1, mjcr2;
509    JCR *jcr1 = &mjcr1;
510    JCR *jcr2 = &mjcr2;
511
512    strcpy(my_name, "test-dir");
513
514    getcwd(plugin_dir, sizeof(plugin_dir)-1);
515    load_dir_plugins(plugin_dir);
516
517    jcr1->JobId = 111;
518    new_plugins(jcr1);
519
520    jcr2->JobId = 222;
521    new_plugins(jcr2);
522
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");
526    free_plugins(jcr1);
527    generate_plugin_event(jcr2, bDirEventJobEnd);
528    free_plugins(jcr2);
529
530    unload_plugins();
531
532    Dmsg0(dbglvl, "dir-plugin: OK ...\n");
533    close_memory_pool();
534    sm_dump(false);
535    return 0;
536 }
537
538 #endif /* TEST_PROGRAM */