]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/fd-plugins.c
Plugin update
[bacula/bacula] / bacula / src / filed / fd-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 John Walker.
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 "filed.h"
36
37 const int dbglvl = 50;
38 const char *plugin_type = "-fd.so";
39
40 extern int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level);
41
42
43 /* Function pointers to be set here */
44 extern int     (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode);
45 extern int     (*plugin_bclose)(JCR *jcr);
46 extern ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count);
47 extern ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count);
48 extern boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence);
49
50
51 /* Forward referenced functions */
52 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
53 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
54 static bRC baculaRegisterEvents(bpContext *ctx, ...);
55 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
56   int type, time_t mtime, const char *msg);
57 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
58   int level, const char *msg);
59
60 static int     my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode);
61 static int     my_plugin_bclose(JCR *jcr);
62 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count);
63 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count);
64 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence);
65
66
67 /* Bacula info */
68 static bInfo binfo = {
69    sizeof(bFuncs),
70    PLUGIN_INTERFACE_VERSION 
71 };
72
73 /* Bacula entry points */
74 static bFuncs bfuncs = {
75    sizeof(bFuncs),
76    PLUGIN_INTERFACE_VERSION,
77    baculaRegisterEvents,
78    baculaGetValue,
79    baculaSetValue,
80    baculaJobMsg,
81    baculaDebugMsg
82 };
83
84
85 /*
86  * Create a plugin event 
87  */
88 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)     
89 {
90    bEvent event;
91    Plugin *plugin;
92    int i = 0;
93    int len;
94    char *p;
95    char *cmd = (char *)value;
96
97    if (!plugin_list) {
98       return;
99    }
100
101    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
102    event.eventType = eventType;
103
104    Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
105    if (eventType != bEventPluginCommand) {
106       /* Pass event to every plugin */
107       foreach_alist(plugin, plugin_list) {
108          plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
109       }
110       goto bail_out;
111    }
112
113    /* Handle plugin command here (backup/restore of file) */
114    Dmsg1(000, "plugin cmd=%s\n", cmd);
115    if (!(p = strchr(cmd, ':'))) {
116       Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
117       goto bail_out;
118    }
119    len = p - cmd;
120    if (len <= 0) {
121       goto bail_out;
122    }
123
124    foreach_alist(plugin, plugin_list) {
125       Dmsg3(000, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
126       if (strncmp(plugin->file, cmd, len) == 0) {
127          struct save_pkt sp;
128          FF_PKT *ff_pkt;
129          Dmsg1(000, "Command plugin = %s\n", cmd);
130          if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, value) != bRC_OK) {
131             goto bail_out;
132          }
133          memset(&sp, 0, sizeof(sp));
134          sp.type = FT_REG;
135          sp.portable = true;
136          sp.cmd = cmd;
137          Dmsg0(000, "Plugin startBackup\n");
138          if (plug_func(plugin)->startPluginBackup(&plugin_ctx_list[i], &sp) != bRC_OK) {
139             goto bail_out;
140          }
141          jcr->plugin_ctx = &plugin_ctx_list[i];
142          jcr->plugin = plugin;
143          jcr->plugin_sp = &sp;
144          ff_pkt = jcr->ff;
145          ff_pkt->fname = sp.fname;
146          ff_pkt->type = sp.type;
147          memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
148          Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname);
149          save_file(ff_pkt, (void *)jcr, true);
150          goto bail_out;
151       }
152       i++;
153    }
154       
155 bail_out:
156    return;
157 }
158
159 /* 
160  * Send plugin name record to SD
161  */
162 bool send_plugin_name(JCR *jcr, BSOCK *sd)
163 {
164    int stat;
165    struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
166    Plugin *plugin = (Plugin *)jcr->plugin;
167    if (!sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_PLUGIN_NAME)) {
168      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
169            sd->bstrerror());
170      return false;
171    }
172    stat = sd->fsend("%ld %d %s%c%s%c", jcr->JobFiles, sp->portable, 0, plugin->file,
173             sp->cmd, 0);
174    if (!stat) {
175       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
176             sd->bstrerror());
177          return false;
178    }
179    sd->signal(BNET_EOD);            /* indicate end of plugin name data */
180    return true;
181 }
182
183
184 void load_fd_plugins(const char *plugin_dir)
185 {
186    if (!plugin_dir) {
187       return;
188    }
189
190    plugin_list = New(alist(10, not_owned_by_alist));
191    load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
192    plugin_bopen  = my_plugin_bopen;
193    plugin_bclose = my_plugin_bclose;
194    plugin_bread  = my_plugin_bread;
195    plugin_bwrite = my_plugin_bwrite;
196    plugin_blseek = my_plugin_blseek;
197
198 }
199
200 /*
201  * Create a new instance of each plugin for this Job
202  */
203 void new_plugins(JCR *jcr)
204 {
205    Plugin *plugin;
206    int i = 0;
207
208    if (!plugin_list) {
209       return;
210    }
211
212    int num = plugin_list->size();
213
214    if (num == 0) {
215       return;
216    }
217
218    jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
219
220    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
221    Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
222    foreach_alist(plugin, plugin_list) {
223       /* Start a new instance of each plugin */
224       plugin_ctx_list[i].bContext = (void *)jcr;
225       plugin_ctx_list[i].pContext = NULL;
226       plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
227    }
228 }
229
230 /*
231  * Free the plugin instances for this Job
232  */
233 void free_plugins(JCR *jcr)
234 {
235    Plugin *plugin;
236    int i = 0;
237
238    if (!plugin_list) {
239       return;
240    }
241
242    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
243    Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
244    foreach_alist(plugin, plugin_list) {
245       /* Free the plugin instance */
246       plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
247    }
248    free(plugin_ctx_list);
249    jcr->plugin_ctx_list = NULL;
250 }
251
252 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode)
253 {
254    Plugin *plugin = (Plugin *)jcr->plugin;
255    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
256    struct io_pkt io;
257    Dmsg0(000, "plugin_bopen\n");
258    io.func = IO_OPEN;
259    io.count = 0;
260    io.buf = NULL;
261    plug_func(plugin)->pluginIO(plugin_ctx, &io);
262    return io.status;
263 }
264
265 static int my_plugin_bclose(JCR *jcr)
266 {
267    Plugin *plugin = (Plugin *)jcr->plugin;
268    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
269    struct io_pkt io;
270    Dmsg0(000, "plugin_bclose\n");
271    io.func = IO_CLOSE;
272    io.count = 0;
273    io.buf = NULL;
274    plug_func(plugin)->pluginIO(plugin_ctx, &io);
275    return io.status;
276 }
277
278 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count)
279 {
280    Plugin *plugin = (Plugin *)jcr->plugin;
281    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
282    struct io_pkt io;
283    Dmsg0(000, "plugin_bread\n");
284    io.func = IO_READ;
285    io.count = count;
286    io.buf = (char *)buf;
287    plug_func(plugin)->pluginIO(plugin_ctx, &io);
288    return (ssize_t)io.status;
289 }
290
291 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count)
292 {
293    Plugin *plugin = (Plugin *)jcr->plugin;
294    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
295    struct io_pkt io;
296    Dmsg0(000, "plugin_bwrite\n");
297    io.func = IO_WRITE;
298    io.count = count;
299    io.buf = (char *)buf;
300    plug_func(plugin)->pluginIO(plugin_ctx, &io);
301    return (ssize_t)io.status;
302 }
303
304 static boffset_t my_plugin_blseek(JCR *jcr, boffset_t offset, int whence)
305 {
306    Plugin *plugin = (Plugin *)jcr->plugin;
307    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
308    struct io_pkt io;
309    Dmsg0(000, "plugin_bseek\n");
310    io.func = IO_SEEK;
311    io.offset = offset;
312    io.whence = whence;
313    plug_func(plugin)->pluginIO(plugin_ctx, &io);
314    return (boffset_t)io.offset;
315 }
316
317 /* ==============================================================
318  *
319  * Callbacks from the plugin
320  *
321  * ==============================================================
322  */
323 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
324 {
325    JCR *jcr = (JCR *)(ctx->bContext);
326 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
327    if (!value) {
328       return bRC_Error;
329    }
330 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
331    switch (var) {
332    case bVarJobId:
333       *((int *)value) = jcr->JobId;
334       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
335       break;
336    case bVarFDName:
337       *((char **)value) = my_name;
338       Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
339       break;
340    case bVarLevel:
341    case bVarType:
342    case bVarClient:
343    case bVarJobName:
344    case bVarJobStatus:
345    case bVarSinceTime:
346       break;
347    }
348    return bRC_OK;
349 }
350
351 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
352 {
353    Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
354    return bRC_OK;
355 }
356
357 static bRC baculaRegisterEvents(bpContext *ctx, ...)
358 {
359    va_list args;
360    uint32_t event;
361
362    va_start(args, ctx);
363    while ((event = va_arg(args, uint32_t))) {
364       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
365    }
366    va_end(args);
367    return bRC_OK;
368 }
369
370 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
371   int type, time_t mtime, const char *msg)
372 {
373    Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
374       file, line, type, mtime, msg);
375    return bRC_OK;
376 }
377
378 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
379   int level, const char *msg)
380 {
381    Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
382       file, line, level, msg);
383    return bRC_OK;
384 }
385
386 #ifdef TEST_PROGRAM
387
388 int     (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
389 int     (*plugin_bclose)(JCR *jcr) = NULL;
390 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
391 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
392 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
393
394 int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
395 {
396    return 0;
397 }
398
399 int main(int argc, char *argv[])
400 {
401    char plugin_dir[1000];
402    JCR mjcr1, mjcr2;
403    JCR *jcr1 = &mjcr1;
404    JCR *jcr2 = &mjcr2;
405
406    strcpy(my_name, "test-fd");
407     
408    getcwd(plugin_dir, sizeof(plugin_dir)-1);
409    load_fd_plugins(plugin_dir);
410
411    jcr1->JobId = 111;
412    new_plugins(jcr1);
413
414    jcr2->JobId = 222;
415    new_plugins(jcr2);
416
417    generate_plugin_event(jcr1, bEventJobStart);
418    generate_plugin_event(jcr1, bEventJobEnd);
419    generate_plugin_event(jcr2, bEventJobStart);
420    free_plugins(jcr1);
421    generate_plugin_event(jcr2, bEventJobEnd);
422    free_plugins(jcr2);
423
424    unload_plugins();
425
426    Dmsg0(dbglvl, "bacula: OK ...\n");
427    close_memory_pool();
428    sm_dump(false);
429    return 0;
430 }
431
432 #endif /* TEST_PROGRAM */