]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dir_plugins.c
ebl Add writable variable to director plugin interface
[bacula/bacula] / bacula / src / dird / dir_plugins.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2008 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 two of the GNU 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 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 "dird.h"
36
37 const int dbglvl = 0;
38 const char *plugin_type = "-dir.so";
39
40
41 /* Forward referenced functions */
42 static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value);
43 static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value);
44 static bRC baculaRegisterEvents(bpContext *ctx, ...);
45 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
46   int type, time_t mtime, const char *msg);
47 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
48   int level, const char *msg);
49
50
51 /* Bacula info */
52 static bInfo binfo = {
53    sizeof(bFuncs),
54    DIR_PLUGIN_INTERFACE_VERSION,
55 };
56
57 /* Bacula entry points */
58 static bFuncs bfuncs = {
59    sizeof(bFuncs),
60    DIR_PLUGIN_INTERFACE_VERSION,
61    baculaRegisterEvents,
62    baculaGetValue,
63    baculaSetValue,
64    baculaJobMsg,
65    baculaDebugMsg
66 };
67
68 /*
69  * Create a plugin event 
70  */
71 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
72 {
73    bEvent event;
74    Plugin *plugin;
75    int i = 0;
76
77    if (!plugin_list || !jcr || !jcr->plugin_ctx_list) {
78       return;
79    }
80
81    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
82    jcr->eventType = event.eventType = eventType;
83
84    Dmsg2(dbglvl, "plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
85
86    foreach_alist(plugin, plugin_list) {
87       bRC rc;
88       rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
89       if (rc != bRC_OK) {
90          break;
91       }
92    }
93
94    return;
95 }
96
97 static void dump_dir_plugin(Plugin *plugin, FILE *fp)
98 {
99    if (!plugin) {
100       return ;
101    }
102    pInfo *info = (pInfo *) plugin->pinfo;
103    fprintf(fp, "\tversion=%d\n", info->version);
104    fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
105    fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
106    fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
107    fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
108    fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
109    fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
110 }
111
112 void load_dir_plugins(const char *plugin_dir)
113 {
114    if (!plugin_dir) {
115       return;
116    }
117
118    plugin_list = New(alist(10, not_owned_by_alist));
119    load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
120    dbg_plugin_add_hook(dump_dir_plugin);
121 }
122
123 /*
124  * Create a new instance of each plugin for this Job
125  */
126 void new_plugins(JCR *jcr)
127 {
128    Plugin *plugin;
129    int i = 0;
130
131    if (!plugin_list) {
132       return;
133    }
134
135    int num = plugin_list->size();
136
137    if (num == 0) {
138       return;
139    }
140
141    jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
142
143    bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
144    Dmsg2(dbglvl, "Instantiate plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
145    foreach_alist(plugin, plugin_list) {
146       /* Start a new instance of each plugin */
147       plugin_ctx_list[i].bContext = (void *)jcr;
148       plugin_ctx_list[i].pContext = NULL;
149       plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
150    }
151 }
152
153 /*
154  * Free the plugin instances for this Job
155  */
156 void free_plugins(JCR *jcr)
157 {
158    Plugin *plugin;
159    int i = 0;
160
161    if (!plugin_list || !jcr->plugin_ctx_list) {
162       return;
163    }
164
165    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
166    Dmsg2(dbglvl, "Free instance plugin_ctx_list=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
167    foreach_alist(plugin, plugin_list) {
168       /* Free the plugin instance */
169       plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
170    }
171    free(plugin_ctx_list);
172    jcr->plugin_ctx_list = NULL;
173 }
174
175 /* ==============================================================
176  *
177  * Callbacks from the plugin
178  *
179  * ==============================================================
180  */
181 static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value)
182 {
183    bRC ret=bRC_OK;
184
185    if (!ctx) {
186       return bRC_Error;
187    }
188    JCR *jcr = (JCR *)(ctx->bContext);
189 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
190    if (!jcr || !value) {
191       return bRC_Error;
192    }
193 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
194    switch (var) {
195    case bVarJobId:
196       *((int *)value) = jcr->JobId;
197       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
198       break;
199    case bVarJobName:
200       *((char **)value) = jcr->Job;
201       Dmsg1(dbglvl, "Bacula: return bVarJobName=%s\n", jcr->Job);
202       break;
203    case bVarJob:
204       *((char **)value) = jcr->job->hdr.name;
205       Dmsg1(dbglvl, "Bacula: return bVarJob=%s\n", jcr->job->hdr.name);
206       break;
207    case bVarLevel:
208       *((int *)value) = jcr->get_JobLevel();
209       Dmsg1(dbglvl, "Bacula: return bVarLevel=%c\n", jcr->get_JobLevel());
210       break;
211    case bVarType:
212       *((int *)value) = jcr->get_JobType();
213       Dmsg1(dbglvl, "Bacula: return bVarType=%c\n", jcr->get_JobType());
214       break;
215    case bVarClient:
216       *((char **)value) = jcr->client->hdr.name;
217       Dmsg1(dbglvl, "Bacula: return bVarClient=%s\n", jcr->client->hdr.name);
218       break;
219    case bVarNumVols:
220       POOL_DBR pr;
221       memset(&pr, 0, sizeof(pr));
222       bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
223       if (!db_get_pool_record(jcr, jcr->db, &pr)) {
224          ret=bRC_Error;
225       }
226       *((int *)value) = pr.NumVols;
227       Dmsg1(dbglvl, "Bacula: return bVarNumVols=%d\n", pr.NumVols);
228       break;
229    case bVarPool:
230       *((char **)value) = jcr->pool->hdr.name;
231       Dmsg1(dbglvl, "Bacula: return bVarPool=%s\n", jcr->pool->hdr.name);
232       break;
233    case bVarStorage:
234       if (jcr->wstore) {
235          *((char **)value) = jcr->wstore->hdr.name;
236       } else if (jcr->rstore) {
237          *((char **)value) = jcr->rstore->hdr.name;
238       } else {
239          *((char **)value) = NULL;
240          ret=bRC_Error;
241       }
242       Dmsg1(dbglvl, "Bacula: return bVarStorage=%s\n", NPRT(*((char **)value)));
243       break;
244    case bVarWriteStorage:
245       if (jcr->wstore) {
246          *((char **)value) = jcr->wstore->hdr.name;
247       } else {
248          *((char **)value) = NULL;
249          ret=bRC_Error;
250       }
251       Dmsg1(dbglvl, "Bacula: return bVarWriteStorage=%s\n", NPRT(*((char **)value)));
252       break;
253    case bVarReadStorage:
254       if (jcr->rstore) {
255          *((char **)value) = jcr->rstore->hdr.name;
256       } else {
257          *((char **)value) = NULL;
258          ret=bRC_Error;
259       }
260       Dmsg1(dbglvl, "Bacula: return bVarReadStorage=%s\n", NPRT(*((char **)value)));
261       break;
262    case bVarCatalog:
263       *((char **)value) = jcr->catalog->hdr.name;
264       Dmsg1(dbglvl, "Bacula: return bVarCatalog=%s\n", jcr->catalog->hdr.name);
265       break;
266    case bVarMediaType:
267       if (jcr->wstore) {
268          *((char **)value) = jcr->wstore->media_type;
269       } else if (jcr->rstore) {
270          *((char **)value) = jcr->rstore->media_type;
271       } else {
272          *((char **)value) = NULL;
273          ret=bRC_Error;
274       }
275       Dmsg1(dbglvl, "Bacula: return bVarMediaType=%s\n", NPRT(*((char **)value)));
276       break;
277    case bVarJobStatus:
278       *((int *)value) = jcr->JobStatus;
279       Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%c\n", jcr->JobStatus);
280       break;
281    case bVarPriority:
282       *((int *)value) = jcr->JobPriority;
283       Dmsg1(dbglvl, "Bacula: return bVarPriority=%d\n", jcr->JobPriority);
284       break;
285    case bVarVolumeName:
286       *((char **)value) = jcr->VolumeName;
287       Dmsg1(dbglvl, "Bacula: return bVarVolumeName=%s\n", jcr->VolumeName);
288       break;
289    case bVarCatalogRes:
290       ret = bRC_Error;
291       break;
292    case bVarJobErrors:
293       *((int *)value) = jcr->JobErrors;
294       Dmsg1(dbglvl, "Bacula: return bVarErrors=%d\n", jcr->JobErrors);
295       break;
296    case bVarJobFiles:
297       *((int *)value) = jcr->JobFiles;
298       Dmsg1(dbglvl, "Bacula: return bVarFiles=%d\n", jcr->JobFiles);
299       break;
300    case bVarSDJobFiles:
301       *((int *)value) = jcr->SDJobFiles;
302       Dmsg1(dbglvl, "Bacula: return bVarSDFiles=%d\n", jcr->SDJobFiles);
303       break;
304    case bVarSDErrors:
305       *((int *)value) = jcr->SDErrors;
306       Dmsg1(dbglvl, "Bacula: return bVarSDErrors=%d\n", jcr->SDErrors);
307       break;
308    case bVarFDJobStatus:
309       *((int *)value) = jcr->FDJobStatus;
310       Dmsg1(dbglvl, "Bacula: return bVarFDJobStatus=%c\n", jcr->FDJobStatus);
311       break;      
312    case bVarSDJobStatus:
313       *((int *)value) = jcr->SDJobStatus;
314       Dmsg1(dbglvl, "Bacula: return bVarSDJobStatus=%c\n", jcr->SDJobStatus);
315       break;      
316    default:
317       ret = bRC_Error;
318       break;
319    }
320    return ret;
321 }
322
323 extern struct s_jl joblevels[];
324
325 static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value)
326 {
327    bRC ret=bRC_OK;
328
329    if (!ctx || !var || !value) {
330       return bRC_Error;
331    }
332    
333    JCR *jcr = (JCR *)ctx->bContext;
334    int intval = *(int*)value;
335    char *strval = (char *)value;
336    bool ok;
337
338    switch (var) {
339    case bwVarJobReport:
340       Jmsg(jcr, M_INFO, 0, "%s", (char *)value);
341       break;
342    
343    case bwVarVolumeName:
344       /* Make sure VolumeName is valid and we are in VolumeName event */
345       if (jcr->eventType == bEventNewVolume &&
346           is_volume_name_legal(NULL, strval))
347       {
348          pm_strcpy(jcr->VolumeName, strval);
349          Dmsg1(100, "Set Vol=%s\n", strval);
350       } else {
351          jcr->VolumeName[0] = 0;
352          ret = bRC_Error;
353       }
354       break;
355
356    case bwVarPriority:
357       Dmsg1(000, "Set priority=%d\n", intval);
358       if (intval >= 1 && intval <= 100) {
359          jcr->JobPriority = intval;
360       } else {
361          ret = bRC_Error;
362       }
363       break;
364
365    case bwVarJobLevel:
366       ok=true;
367       if (jcr->eventType == bEventJobInit) {
368          for (int i=0; ok && joblevels[i].level_name; i++) {
369             if (strcasecmp(strval, joblevels[i].level_name) == 0) {
370                if (joblevels[i].job_type == jcr->get_JobType()) {
371                   jcr->set_JobLevel(joblevels[i].level);
372                   jcr->jr.JobLevel = jcr->get_JobLevel();
373                   ok = false;
374                }
375             }
376          }
377       } else {
378          ret = bRC_Error;
379       }
380       break;
381    default:
382       ret = bRC_Error;
383       break;
384    }
385    Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
386    return ret;
387 }
388
389 static bRC baculaRegisterEvents(bpContext *ctx, ...)
390 {
391    va_list args;
392    uint32_t event;
393
394    va_start(args, ctx);
395    while ((event = va_arg(args, uint32_t))) {
396       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
397    }
398    va_end(args);
399    return bRC_OK;
400 }
401
402 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
403   int type, time_t mtime, const char *msg)
404 {
405    Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
406       file, line, type, mtime, msg);
407    return bRC_OK;
408 }
409
410 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
411   int level, const char *msg)
412 {
413    Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
414       file, line, level, msg);
415    return bRC_OK;
416 }
417
418 #ifdef TEST_PROGRAM
419
420
421 int main(int argc, char *argv[])
422 {
423    char plugin_dir[1000];
424    JCR mjcr1, mjcr2;
425    JCR *jcr1 = &mjcr1;
426    JCR *jcr2 = &mjcr2;
427
428    strcpy(my_name, "test-dir");
429     
430    getcwd(plugin_dir, sizeof(plugin_dir)-1);
431    load_dir_plugins(plugin_dir);
432
433    jcr1->JobId = 111;
434    new_plugins(jcr1);
435
436    jcr2->JobId = 222;
437    new_plugins(jcr2);
438
439    generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
440    generate_plugin_event(jcr1, bEventJobEnd);
441    generate_plugin_event(jcr2, bEventJobInit, (void *)"Start Job 1");
442    generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 1");
443    free_plugins(jcr1);
444    generate_plugin_event(jcr2, bEventJobEnd);
445    free_plugins(jcr2);
446
447    unload_plugins();
448
449    Dmsg0(dbglvl, "bacula: OK ...\n");
450    close_memory_pool();
451    sm_dump(false);
452    return 0;
453 }
454
455 #endif /* TEST_PROGRAM */