]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/fd_plugins.c
kes Implement build and install of bpipe-fd.so plugin.
[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 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 "filed.h"
36
37 const int dbglvl = 50;
38 #ifdef HAVE_WIN32
39 const char *plugin_type = "-fd.dll";
40 #else
41 const char *plugin_type = "-fd.so";
42 #endif
43
44 extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
45
46 /* Function pointers to be set here */
47 extern DLL_IMP_EXP int     (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode);
48 extern DLL_IMP_EXP int     (*plugin_bclose)(BFILE *bfd);
49 extern DLL_IMP_EXP ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count);
50 extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count);
51 extern DLL_IMP_EXP boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence);
52
53
54 /* Forward referenced functions */
55 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
56 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
57 static bRC baculaRegisterEvents(bpContext *ctx, ...);
58 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
59   int type, time_t mtime, const char *fmt, ...);
60 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
61   int level, const char *fmt, ...);
62
63 static int     my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode);
64 static int     my_plugin_bclose(BFILE *bfd);
65 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count);
66 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count);
67 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence);
68
69
70 /* Bacula info */
71 static bInfo binfo = {
72    sizeof(bFuncs),
73    FD_PLUGIN_INTERFACE_VERSION 
74 };
75
76 /* Bacula entry points */
77 static bFuncs bfuncs = {
78    sizeof(bFuncs),
79    FD_PLUGIN_INTERFACE_VERSION,
80    baculaRegisterEvents,
81    baculaGetValue,
82    baculaSetValue,
83    baculaJobMsg,
84    baculaDebugMsg
85 };
86
87
88 /*
89  * Create a plugin event 
90  */
91 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)     
92 {
93    bEvent event;
94    Plugin *plugin;
95    int i = 0;
96
97    if (!plugin_list || !jcr->plugin_ctx_list) {
98       return;                         /* Return if no plugins loaded */
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
106    /* Pass event to every plugin */
107    foreach_alist(plugin, plugin_list) {
108       bRC rc;
109       rc = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
110       if (rc != bRC_OK) {
111          break;
112       }
113    }
114
115    return;
116 }
117
118 /*   
119  * Sequence of calls for a backup:
120  * 1. plugin_save() here is called with ff_pkt
121  * 2. we find the plugin requested on the command string
122  * 3. we generate a bEventBackupCommand event to the specified plugin
123  *    and pass it the command string.
124  * 4. we make a startPluginBackup call to the plugin, which gives
125  *    us the data we need in save_pkt
126  * 5. we call Bacula's save_file() subroutine to save the specified
127  *    file.  The plugin will be called at pluginIO() to supply the
128  *    file data.
129  *
130  * Sequence of calls for restore:
131  *   See subroutine plugin_name_stream() below.
132  */
133 int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
134 {
135    Plugin *plugin;
136    int i = 0;
137    int len;
138    char *p;
139    char *cmd = ff_pkt->top_fname;
140    struct save_pkt sp;
141    bEvent event;
142
143    if (!plugin_list || !jcr->plugin_ctx_list) {
144       return 1;                            /* Return if no plugins loaded */
145    }
146
147    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
148    event.eventType = bEventBackupCommand;
149
150    /* Handle plugin command here backup */
151    Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
152    if (!(p = strchr(cmd, ':'))) {
153       Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
154       goto bail_out;
155    }
156    len = p - cmd;
157    if (len <= 0) {
158       goto bail_out;
159    }
160
161    foreach_alist(plugin, plugin_list) {
162       Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
163       if (strncmp(plugin->file, cmd, len) != 0) {
164          i++;
165          continue;
166       }
167       Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
168       /* Send the backup command */
169       if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, cmd) != bRC_OK) {
170          goto bail_out;
171       }
172       /* Loop getting filenames to backup then saving them */
173       while (!job_canceled(jcr)) { 
174          memset(&sp, 0, sizeof(sp));
175          sp.pkt_size = sizeof(sp);
176          sp.pkt_end = sizeof(sp);
177          sp.portable = true;
178          sp.cmd = cmd;
179          Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
180                 &sp);
181          /* Get the file save parameters */
182          if (plug_func(plugin)->startBackupFile(&plugin_ctx_list[i], &sp) != bRC_OK) {
183             goto bail_out;
184          }
185          if (sp.type == 0 || sp.fname == NULL) {
186             Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\" returned bad startBackupFile packet.\n"),
187                cmd);
188             goto bail_out;
189          }
190          jcr->plugin_ctx = &plugin_ctx_list[i];
191          jcr->plugin = plugin;
192          jcr->plugin_sp = &sp;
193          ff_pkt = jcr->ff;
194          ff_pkt->fname = sp.fname;
195          ff_pkt->type = sp.type;
196          memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
197          Dmsg1(dbglvl, "Save_file: file=%s\n", ff_pkt->fname);
198          save_file(jcr, ff_pkt, true);
199          bRC rc = plug_func(plugin)->endBackupFile(&plugin_ctx_list[i]);
200          if (rc == bRC_More) {
201             continue;
202          }
203          goto bail_out;
204       }
205    }
206    Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
207
208 bail_out:
209    return 1;
210 }
211
212 /* 
213  * Send plugin name start/end record to SD
214  */
215 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
216 {
217    int stat;
218    struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
219   
220    Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
221    /* Send stream header */
222    if (!sd->fsend("%ld %d 0", jcr->JobFiles+1, STREAM_PLUGIN_NAME)) {
223      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
224            sd->bstrerror());
225      return false;
226    }
227    Dmsg1(000, "send: %s\n", sd->msg);
228
229    if (start) {
230       /* Send data -- not much */
231       stat = sd->fsend("%ld 1 %d %s%c", jcr->JobFiles+1, sp->portable, sp->cmd, 0);
232    } else {
233       /* Send end of data */
234       stat = sd->fsend("0 0");
235    }
236    if (!stat) {
237       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
238             sd->bstrerror());
239          return false;
240    }
241    Dmsg1(dbglvl, "send: %s\n", sd->msg);
242    sd->signal(BNET_EOD);            /* indicate end of plugin name data */
243    return true;
244 }
245
246 /*
247  * Plugin name stream found during restore.  The record passed in
248  *  argument name was generated in send_plugin_name() above.
249  */
250 void plugin_name_stream(JCR *jcr, char *name)    
251 {
252    char *p = name;
253    char *cmd;
254    bool start, portable;
255    Plugin *plugin;
256    int len;
257    int i = 0;
258    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
259    if (!plugin_ctx_list) {
260       goto bail_out;
261    }
262
263    Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
264    skip_nonspaces(&p);             /* skip over jcr->JobFiles */
265    skip_spaces(&p);
266    start = *p == '1';
267    if (start) {
268       /* Start of plugin data */
269       skip_nonspaces(&p);          /* skip start/end flag */
270       skip_spaces(&p);
271       portable = *p == '1';
272       skip_nonspaces(&p);          /* skip portable flag */
273       skip_spaces(&p);
274       cmd = p;
275    } else {
276       /*
277        * End of plugin data, notify plugin, then clear flags   
278        */
279       plugin = (Plugin *)jcr->plugin;
280       plug_func(plugin)->endRestoreFile(&plugin_ctx_list[i]);
281       jcr->plugin_ctx = NULL;
282       jcr->plugin = NULL;
283       goto bail_out;
284    }
285       
286    /*
287     * After this point, we are dealing with a restore start
288     */
289
290    Dmsg1(dbglvl, "plugin restore cmd=%s\n", cmd);
291    if (!(p = strchr(cmd, ':'))) {
292       Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
293       goto bail_out;
294    }
295    len = p - cmd;
296    if (len <= 0) {
297       goto bail_out;
298    }
299
300    /*
301     * Search for correct plugin as specified on the command 
302     */
303    foreach_alist(plugin, plugin_list) {
304       bEvent event;
305       Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
306       if (strncmp(plugin->file, cmd, len) != 0) {
307          i++;
308          continue;
309       }
310       Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
311       event.eventType = bEventRestoreCommand;     
312       if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], 
313             &event, cmd) != bRC_OK) {
314          goto bail_out;
315       }
316       jcr->plugin_ctx = &plugin_ctx_list[i];
317       jcr->plugin = plugin;
318       goto bail_out;
319    }
320 bail_out:
321    return;
322 }
323
324 /*
325  * Tell the plugin to create the file.  Return values are
326  *
327  *  CF_ERROR    -- error
328  *  CF_SKIP     -- skip processing this file
329  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
330  *  CF_CREATED  -- created, but no content to extract (typically directories)
331  *
332  */
333 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
334 {
335    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
336    Plugin *plugin = (Plugin *)jcr->plugin;
337    struct restore_pkt rp;
338    struct io_pkt io;
339
340    if (!set_cmd_plugin(bfd, jcr)) {
341       return CF_ERROR;
342    }
343    rp.pkt_size = sizeof(rp);
344    rp.pkt_end = sizeof(rp);
345    rp.stream = attr->stream;
346    rp.data_stream = attr->data_stream;
347    rp.type = attr->type;
348    rp.file_index = attr->file_index;
349    rp.LinkFI = attr->LinkFI;
350    rp.uid = attr->uid;
351    rp.statp = attr->statp;                /* structure assignment */
352    rp.attrEx = attr->attrEx;
353    rp.ofname = attr->ofname;
354    rp.olname = attr->olname;
355    rp.where = jcr->where;
356    rp.RegexWhere = jcr->RegexWhere;
357    rp.replace = jcr->replace;
358    if (plug_func(plugin)->createFile(plugin_ctx, &rp) != bRC_OK) {
359       return CF_ERROR;
360    }
361    io.pkt_size = sizeof(io);
362    io.pkt_end = sizeof(io);
363    io.func = IO_OPEN;
364    io.count = 0;
365    io.buf = NULL;
366    io.mode = 0777 & attr->statp.st_mode;
367    io.flags = O_WRONLY;
368    if (plug_func(plugin)->pluginIO(plugin_ctx, &io) != bRC_OK) {
369       return CF_ERROR;
370    }
371    return CF_EXTRACT;
372 }
373
374 /*
375  * Reset the file attributes after all file I/O is done -- this allows
376  *  the previous access time/dates to be set properly, and it also allows
377  *  us to properly set directory permissions.
378  */
379 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
380 {
381    return true;
382 }
383
384 /*
385  * This entry point is called internally by Bacula to ensure
386  *  that the plugin IO calls come into this code.
387  */
388 void load_fd_plugins(const char *plugin_dir)
389 {
390    Plugin *plugin;
391
392    if (!plugin_dir) {
393       Dmsg0(dbglvl, "plugin dir is NULL\n");
394       return;
395    }
396
397    plugin_list = New(alist(10, not_owned_by_alist));
398    if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type)) {
399       /* Either none found, or some error */
400       if (plugin_list->size() == 0) {
401          delete plugin_list;
402          plugin_list = NULL;
403          Dmsg0(dbglvl, "No plugins loaded\n");
404          return;
405       }
406    }
407
408    /* Plug entry points called from findlib */
409    plugin_bopen  = my_plugin_bopen;
410    plugin_bclose = my_plugin_bclose;
411    plugin_bread  = my_plugin_bread;
412    plugin_bwrite = my_plugin_bwrite;
413    plugin_blseek = my_plugin_blseek;
414    foreach_alist(plugin, plugin_list) {
415       Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
416       Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
417
418    }
419 }
420
421 /*
422  * Create a new instance of each plugin for this Job
423  *   Note, plugin_list can exist but jcr->plugin_ctx_list can
424  *   be NULL if no plugins were loaded.
425  */
426 void new_plugins(JCR *jcr)
427 {
428    Plugin *plugin;
429    int i = 0;
430
431    if (!plugin_list) {
432       Dmsg0(dbglvl, "plugin list is NULL\n");
433       return;
434    }
435
436    int num = plugin_list->size();
437
438    if (num == 0) {
439       Dmsg0(dbglvl, "No plugins loaded\n");
440       return;
441    }
442
443    jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
444
445    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
446    Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
447    foreach_alist(plugin, plugin_list) {
448       /* Start a new instance of each plugin */
449       plugin_ctx_list[i].bContext = (void *)jcr;
450       plugin_ctx_list[i].pContext = NULL;
451       plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
452    }
453 }
454
455 /*
456  * Free the plugin instances for this Job
457  */
458 void free_plugins(JCR *jcr)
459 {
460    Plugin *plugin;
461    int i = 0;
462
463    if (!plugin_list || !jcr->plugin_ctx_list) {
464       return;                         /* no plugins, nothing to do */
465    }
466
467    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
468    Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
469    foreach_alist(plugin, plugin_list) {
470       /* Free the plugin instance */
471       plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
472    }
473    free(plugin_ctx_list);
474    jcr->plugin_ctx_list = NULL;
475 }
476
477 static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode)
478 {
479    JCR *jcr = bfd->jcr;
480    Plugin *plugin = (Plugin *)jcr->plugin;
481    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
482    struct io_pkt io;
483    Dmsg0(dbglvl, "plugin_bopen\n");
484    io.pkt_size = sizeof(io);
485    io.pkt_end = sizeof(io);
486    io.func = IO_OPEN;
487    io.count = 0;
488    io.buf = NULL;
489    io.fname = fname;
490    io.flags = flags;
491    io.mode = mode;
492    io.win32 = false;
493    io.lerror = 0;
494    plug_func(plugin)->pluginIO(plugin_ctx, &io);
495    bfd->berrno = io.io_errno;
496    if (io.win32) {
497       errno = b_errno_win32;
498    } else {
499       errno = io.io_errno;
500       bfd->lerror = io.lerror;
501    }
502    return io.status;
503 }
504
505 static int my_plugin_bclose(BFILE *bfd)
506 {
507    JCR *jcr = bfd->jcr;
508    Plugin *plugin = (Plugin *)jcr->plugin;
509    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
510    struct io_pkt io;
511    Dmsg0(dbglvl, "plugin_bclose\n");
512    io.pkt_size = sizeof(io);
513    io.pkt_end = sizeof(io);
514    io.func = IO_CLOSE;
515    io.count = 0;
516    io.buf = NULL;
517    io.win32 = false;
518    io.lerror = 0;
519    plug_func(plugin)->pluginIO(plugin_ctx, &io);
520    bfd->berrno = io.io_errno;
521    if (io.win32) {
522       errno = b_errno_win32;
523    } else {
524       errno = io.io_errno;
525       bfd->lerror = io.lerror;
526    }
527    return io.status;
528 }
529
530 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
531 {
532    JCR *jcr = bfd->jcr;
533    Plugin *plugin = (Plugin *)jcr->plugin;
534    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
535    struct io_pkt io;
536    Dmsg0(dbglvl, "plugin_bread\n");
537    io.pkt_size = sizeof(io);
538    io.pkt_end = sizeof(io);
539    io.func = IO_READ;
540    io.count = count;
541    io.buf = (char *)buf;
542    io.win32 = false;
543    io.lerror = 0;
544    plug_func(plugin)->pluginIO(plugin_ctx, &io);
545    bfd->berrno = io.io_errno;
546    if (io.win32) {
547       errno = b_errno_win32;
548    } else {
549       errno = io.io_errno;
550       bfd->lerror = io.lerror;
551    }
552    return (ssize_t)io.status;
553 }
554
555 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
556 {
557    JCR *jcr = bfd->jcr;
558    Plugin *plugin = (Plugin *)jcr->plugin;
559    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
560    struct io_pkt io;
561    Dmsg0(dbglvl, "plugin_bwrite\n");
562    io.pkt_size = sizeof(io);
563    io.pkt_end = sizeof(io);
564    io.func = IO_WRITE;
565    io.count = count;
566    io.buf = (char *)buf;
567    io.win32 = false;
568    io.lerror = 0;
569    plug_func(plugin)->pluginIO(plugin_ctx, &io);
570    bfd->berrno = io.io_errno;
571    if (io.win32) {
572       errno = b_errno_win32;
573    } else {
574       errno = io.io_errno;
575       bfd->lerror = io.lerror;
576    }
577    return (ssize_t)io.status;
578 }
579
580 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
581 {
582    JCR *jcr = bfd->jcr;
583    Plugin *plugin = (Plugin *)jcr->plugin;
584    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
585    struct io_pkt io;
586    Dmsg0(dbglvl, "plugin_bseek\n");
587    io.pkt_size = sizeof(io);
588    io.pkt_end = sizeof(io);
589    io.func = IO_SEEK;
590    io.offset = offset;
591    io.whence = whence;
592    io.win32 = false;
593    io.lerror = 0;
594    plug_func(plugin)->pluginIO(plugin_ctx, &io);
595    bfd->berrno = io.io_errno;
596    if (io.win32) {
597       errno = b_errno_win32;
598    } else {
599       errno = io.io_errno;
600       bfd->lerror = io.lerror;
601    }
602    return (boffset_t)io.offset;
603 }
604
605 /* ==============================================================
606  *
607  * Callbacks from the plugin
608  *
609  * ==============================================================
610  */
611 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
612 {
613    JCR *jcr = (JCR *)(ctx->bContext);
614 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
615    if (!value) {
616       return bRC_Error;
617    }
618 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
619    switch (var) {
620    case bVarJobId:
621       *((int *)value) = jcr->JobId;
622       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
623       break;
624    case bVarFDName:
625       *((char **)value) = my_name;
626       Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
627       break;
628    case bVarLevel:
629    case bVarType:
630    case bVarClient:
631    case bVarJobName:
632    case bVarJobStatus:
633    case bVarSinceTime:
634       break;
635    }
636    return bRC_OK;
637 }
638
639 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
640 {
641    Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
642    return bRC_OK;
643 }
644
645 static bRC baculaRegisterEvents(bpContext *ctx, ...)
646 {
647    va_list args;
648    uint32_t event;
649
650    va_start(args, ctx);
651    while ((event = va_arg(args, uint32_t))) {
652       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
653    }
654    va_end(args);
655    return bRC_OK;
656 }
657
658 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
659   int type, time_t mtime, const char *fmt, ...)
660 {
661    va_list arg_ptr;
662    char buf[2000];
663    JCR *jcr = (JCR *)(ctx->bContext);
664
665    va_start(arg_ptr, fmt);
666    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
667    va_end(arg_ptr);
668    Jmsg(jcr, type, mtime, "%s", buf);
669    return bRC_OK;
670 }
671
672 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
673   int level, const char *fmt, ...)
674 {
675    va_list arg_ptr;
676    char buf[2000];
677
678    va_start(arg_ptr, fmt);
679    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
680    va_end(arg_ptr);
681    d_msg(file, line, level, "%s", buf);
682    return bRC_OK;
683 }
684
685 #ifdef TEST_PROGRAM
686
687 int     (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
688 int     (*plugin_bclose)(JCR *jcr) = NULL;
689 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
690 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
691 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
692
693 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
694 {
695    return 0;
696 }
697
698 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
699 {
700    return true;
701 }
702
703 int main(int argc, char *argv[])
704 {
705    char plugin_dir[1000];
706    JCR mjcr1, mjcr2;
707    JCR *jcr1 = &mjcr1;
708    JCR *jcr2 = &mjcr2;
709
710    strcpy(my_name, "test-fd");
711     
712    getcwd(plugin_dir, sizeof(plugin_dir)-1);
713    load_fd_plugins(plugin_dir);
714
715    jcr1->JobId = 111;
716    new_plugins(jcr1);
717
718    jcr2->JobId = 222;
719    new_plugins(jcr2);
720
721    generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
722    generate_plugin_event(jcr1, bEventJobEnd);
723    generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
724    free_plugins(jcr1);
725    generate_plugin_event(jcr2, bEventJobEnd);
726    free_plugins(jcr2);
727
728    unload_plugins();
729
730    Dmsg0(dbglvl, "bacula: OK ...\n");
731    close_memory_pool();
732    sm_dump(false);
733    return 0;
734 }
735
736 #endif /* TEST_PROGRAM */