]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dir_plugins.c
Fix bug #1764 plugin_list shadows global variable of mysql 5.5
[bacula/bacula] / bacula / src / dird / dir_plugins.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2009 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 "dird.h"
36
37 const int dbglvl = 100;
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, utime_t mtime, const char *fmt, ...);
47 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
48                           int level, const char *fmt, ...);
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 (!bplugin_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, bplugin_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    bplugin_list = New(alist(10, not_owned_by_alist));
119    load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, NULL);
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 (!bplugin_list) {
132       return;
133    }
134
135    int num = bplugin_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, bplugin_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 (!bplugin_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, bplugin_list) {
168       /* Free the plugin instance */
169       plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
170       plugin_ctx_list[i].bContext = NULL;
171       plugin_ctx_list[i].pContext = NULL;
172       i++;
173    }
174    free(plugin_ctx_list);
175    jcr->plugin_ctx_list = NULL;
176 }
177
178 /* ==============================================================
179  *
180  * Callbacks from the plugin
181  *
182  * ==============================================================
183  */
184 static bRC baculaGetValue(bpContext *ctx, brVariable var, void *value)
185 {
186    bRC ret=bRC_OK;
187
188    if (!ctx) {
189       return bRC_Error;
190    }
191    JCR *jcr = (JCR *)(ctx->bContext);
192 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
193    if (!jcr || !value) {
194       return bRC_Error;
195    }
196 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
197    switch (var) {
198    case bVarJobId:
199       *((int *)value) = jcr->JobId;
200       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
201       break;
202    case bVarJobName:
203       *((char **)value) = jcr->Job;
204       Dmsg1(dbglvl, "Bacula: return bVarJobName=%s\n", jcr->Job);
205       break;
206    case bVarJob:
207       *((char **)value) = jcr->job->hdr.name;
208       Dmsg1(dbglvl, "Bacula: return bVarJob=%s\n", jcr->job->hdr.name);
209       break;
210    case bVarLevel:
211       *((int *)value) = jcr->getJobLevel();
212       Dmsg1(dbglvl, "Bacula: return bVarLevel=%c\n", jcr->getJobLevel());
213       break;
214    case bVarType:
215       *((int *)value) = jcr->getJobType();
216       Dmsg1(dbglvl, "Bacula: return bVarType=%c\n", jcr->getJobType());
217       break;
218    case bVarClient:
219       *((char **)value) = jcr->client->hdr.name;
220       Dmsg1(dbglvl, "Bacula: return bVarClient=%s\n", jcr->client->hdr.name);
221       break;
222    case bVarNumVols:
223       POOL_DBR pr;
224       memset(&pr, 0, sizeof(pr));
225       bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
226       if (!db_get_pool_record(jcr, jcr->db, &pr)) {
227          ret=bRC_Error;
228       }
229       *((int *)value) = pr.NumVols;
230       Dmsg1(dbglvl, "Bacula: return bVarNumVols=%d\n", pr.NumVols);
231       break;
232    case bVarPool:
233       *((char **)value) = jcr->pool->hdr.name;
234       Dmsg1(dbglvl, "Bacula: return bVarPool=%s\n", jcr->pool->hdr.name);
235       break;
236    case bVarStorage:
237       if (jcr->wstore) {
238          *((char **)value) = jcr->wstore->hdr.name;
239       } else if (jcr->rstore) {
240          *((char **)value) = jcr->rstore->hdr.name;
241       } else {
242          *((char **)value) = NULL;
243          ret=bRC_Error;
244       }
245       Dmsg1(dbglvl, "Bacula: return bVarStorage=%s\n", NPRT(*((char **)value)));
246       break;
247    case bVarWriteStorage:
248       if (jcr->wstore) {
249          *((char **)value) = jcr->wstore->hdr.name;
250       } else {
251          *((char **)value) = NULL;
252          ret=bRC_Error;
253       }
254       Dmsg1(dbglvl, "Bacula: return bVarWriteStorage=%s\n", NPRT(*((char **)value)));
255       break;
256    case bVarReadStorage:
257       if (jcr->rstore) {
258          *((char **)value) = jcr->rstore->hdr.name;
259       } else {
260          *((char **)value) = NULL;
261          ret=bRC_Error;
262       }
263       Dmsg1(dbglvl, "Bacula: return bVarReadStorage=%s\n", NPRT(*((char **)value)));
264       break;
265    case bVarCatalog:
266       *((char **)value) = jcr->catalog->hdr.name;
267       Dmsg1(dbglvl, "Bacula: return bVarCatalog=%s\n", jcr->catalog->hdr.name);
268       break;
269    case bVarMediaType:
270       if (jcr->wstore) {
271          *((char **)value) = jcr->wstore->media_type;
272       } else if (jcr->rstore) {
273          *((char **)value) = jcr->rstore->media_type;
274       } else {
275          *((char **)value) = NULL;
276          ret=bRC_Error;
277       }
278       Dmsg1(dbglvl, "Bacula: return bVarMediaType=%s\n", NPRT(*((char **)value)));
279       break;
280    case bVarJobStatus:
281       *((int *)value) = jcr->JobStatus;
282       Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%c\n", jcr->JobStatus);
283       break;
284    case bVarPriority:
285       *((int *)value) = jcr->JobPriority;
286       Dmsg1(dbglvl, "Bacula: return bVarPriority=%d\n", jcr->JobPriority);
287       break;
288    case bVarVolumeName:
289       *((char **)value) = jcr->VolumeName;
290       Dmsg1(dbglvl, "Bacula: return bVarVolumeName=%s\n", jcr->VolumeName);
291       break;
292    case bVarCatalogRes:
293       ret = bRC_Error;
294       break;
295    case bVarJobErrors:
296       *((int *)value) = jcr->JobErrors;
297       Dmsg1(dbglvl, "Bacula: return bVarErrors=%d\n", jcr->JobErrors);
298       break;
299    case bVarJobFiles:
300       *((int *)value) = jcr->JobFiles;
301       Dmsg1(dbglvl, "Bacula: return bVarFiles=%d\n", jcr->JobFiles);
302       break;
303    case bVarSDJobFiles:
304       *((int *)value) = jcr->SDJobFiles;
305       Dmsg1(dbglvl, "Bacula: return bVarSDFiles=%d\n", jcr->SDJobFiles);
306       break;
307    case bVarSDErrors:
308       *((int *)value) = jcr->SDErrors;
309       Dmsg1(dbglvl, "Bacula: return bVarSDErrors=%d\n", jcr->SDErrors);
310       break;
311    case bVarFDJobStatus:
312       *((int *)value) = jcr->FDJobStatus;
313       Dmsg1(dbglvl, "Bacula: return bVarFDJobStatus=%c\n", jcr->FDJobStatus);
314       break;      
315    case bVarSDJobStatus:
316       *((int *)value) = jcr->SDJobStatus;
317       Dmsg1(dbglvl, "Bacula: return bVarSDJobStatus=%c\n", jcr->SDJobStatus);
318       break;      
319    default:
320       ret = bRC_Error;
321       break;
322    }
323    return ret;
324 }
325
326 extern struct s_jl joblevels[];
327
328 static bRC baculaSetValue(bpContext *ctx, bwVariable var, void *value)
329 {
330    bRC ret=bRC_OK;
331
332    if (!ctx || !var || !value) {
333       return bRC_Error;
334    }
335    
336    JCR *jcr = (JCR *)ctx->bContext;
337    int intval = *(int*)value;
338    char *strval = (char *)value;
339    bool ok;
340
341    switch (var) {
342    case bwVarJobReport:
343       Jmsg(jcr, M_INFO, 0, "%s", (char *)value);
344       break;
345    
346    case bwVarVolumeName:
347       /* Make sure VolumeName is valid and we are in VolumeName event */
348       if (jcr->eventType == bEventNewVolume &&
349           is_volume_name_legal(NULL, strval))
350       {
351          pm_strcpy(jcr->VolumeName, strval);
352          Dmsg1(100, "Set Vol=%s\n", strval);
353       } else {
354          jcr->VolumeName[0] = 0;
355          ret = bRC_Error;
356       }
357       break;
358
359    case bwVarPriority:
360       Dmsg1(000, "Set priority=%d\n", intval);
361       if (intval >= 1 && intval <= 100) {
362          jcr->JobPriority = intval;
363       } else {
364          ret = bRC_Error;
365       }
366       break;
367
368    case bwVarJobLevel:
369       ok=true;
370       if (jcr->eventType == bEventJobInit) {
371          for (int i=0; ok && joblevels[i].level_name; i++) {
372             if (strcasecmp(strval, joblevels[i].level_name) == 0) {
373                if (joblevels[i].job_type == jcr->getJobType()) {
374                   jcr->setJobLevel(joblevels[i].level);
375                   jcr->jr.JobLevel = jcr->getJobLevel();
376                   ok = false;
377                }
378             }
379          }
380       } else {
381          ret = bRC_Error;
382       }
383       break;
384    default:
385       ret = bRC_Error;
386       break;
387    }
388    Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
389    return ret;
390 }
391
392 static bRC baculaRegisterEvents(bpContext *ctx, ...)
393 {
394    va_list args;
395    uint32_t event;
396
397    va_start(args, ctx);
398    while ((event = va_arg(args, uint32_t))) {
399       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
400    }
401    va_end(args);
402    return bRC_OK;
403 }
404
405 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
406                         int type, utime_t mtime, const char *fmt, ...)
407 {
408    va_list arg_ptr;
409    char buf[2000];
410    JCR *jcr;
411
412    if (ctx) {
413       jcr = (JCR *)ctx->bContext;
414    } else {
415       jcr = NULL;
416    }
417
418    va_start(arg_ptr, fmt);
419    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
420    va_end(arg_ptr);
421    Jmsg(jcr, type, mtime, "%s", buf);
422    return bRC_OK;
423 }
424
425 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
426                           int level, const char *fmt, ...)
427 {
428    va_list arg_ptr;
429    char buf[2000];
430
431    va_start(arg_ptr, fmt);
432    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
433    va_end(arg_ptr);
434    d_msg(file, line, level, "%s", buf);
435    return bRC_OK;
436 }
437
438 #ifdef TEST_PROGRAM
439
440
441 int main(int argc, char *argv[])
442 {
443    char plugin_dir[1000];
444    JCR mjcr1, mjcr2;
445    JCR *jcr1 = &mjcr1;
446    JCR *jcr2 = &mjcr2;
447
448    strcpy(my_name, "test-dir");
449     
450    getcwd(plugin_dir, sizeof(plugin_dir)-1);
451    load_dir_plugins(plugin_dir);
452
453    jcr1->JobId = 111;
454    new_plugins(jcr1);
455
456    jcr2->JobId = 222;
457    new_plugins(jcr2);
458
459    generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
460    generate_plugin_event(jcr1, bEventJobEnd);
461    generate_plugin_event(jcr2, bEventJobInit, (void *)"Start Job 1");
462    generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 1");
463    free_plugins(jcr1);
464    generate_plugin_event(jcr2, bEventJobEnd);
465    free_plugins(jcr2);
466
467    unload_plugins();
468
469    Dmsg0(dbglvl, "bacula: OK ...\n");
470    close_memory_pool();
471    sm_dump(false);
472    return 0;
473 }
474
475 #endif /* TEST_PROGRAM */