]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/fd_plugins.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / filed / fd_plugins.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2007-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /**
21  * Main program to test loading and running Bacula plugins.
22  *   Destined to become Bacula pluginloader, ...
23  *
24  * Kern Sibbald, October 2007
25  */
26 #include "bacula.h"
27 #include "filed.h"
28
29 extern CLIENT *me;
30 extern DLL_IMP_EXP char *exepath;
31 extern DLL_IMP_EXP char *version;
32 extern DLL_IMP_EXP char *dist_name;
33
34 const int dbglvl = 150;
35 const char *plugin_type = "-fd.so";
36
37 extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
38 extern bool check_changes(JCR *jcr, FF_PKT *ff_pkt);
39
40 /* Function pointers to be set here */
41 extern DLL_IMP_EXP int     (*plugin_bopen)(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode);
42 extern DLL_IMP_EXP int     (*plugin_bclose)(BFILE *bfd);
43 extern DLL_IMP_EXP ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count);
44 extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count);
45 extern DLL_IMP_EXP boffset_t (*plugin_blseek)(BFILE *bfd, boffset_t offset, int whence);
46
47
48 /* Forward referenced functions */
49 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
50 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
51 static bRC baculaRegisterEvents(bpContext *ctx, ...);
52 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
53   int type, utime_t mtime, const char *fmt, ...);
54 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
55   int level, const char *fmt, ...);
56 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
57               size_t size);
58 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem);
59 static bRC  baculaAddExclude(bpContext *ctx, const char *file);
60 static bRC baculaAddInclude(bpContext *ctx, const char *file);
61 static bRC baculaAddOptions(bpContext *ctx, const char *opts);
62 static bRC baculaAddRegex(bpContext *ctx, const char *item, int type);
63 static bRC baculaAddWild(bpContext *ctx, const char *item, int type);
64 static bRC baculaNewOptions(bpContext *ctx);
65 static bRC baculaNewInclude(bpContext *ctx);
66 static bRC baculaNewPreInclude(bpContext *ctx);
67 static bool is_plugin_compatible(Plugin *plugin);
68 static bool get_plugin_name(JCR *jcr, char *cmd, int *ret);
69 static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp);
70 static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp);
71
72 /*
73  * These will be plugged into the global pointer structure for
74  *  the findlib.
75  */
76 static int     my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode);
77 static int     my_plugin_bclose(BFILE *bfd);
78 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count);
79 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count);
80 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence);
81
82
83 /* Bacula info */
84 static bInfo binfo = {
85    sizeof(bInfo),
86    FD_PLUGIN_INTERFACE_VERSION
87 };
88
89 /* Bacula entry points */
90 static bFuncs bfuncs = {
91    sizeof(bFuncs),
92    FD_PLUGIN_INTERFACE_VERSION,
93    baculaRegisterEvents,
94    baculaGetValue,
95    baculaSetValue,
96    baculaJobMsg,
97    baculaDebugMsg,
98    baculaMalloc,
99    baculaFree,
100    baculaAddExclude,
101    baculaAddInclude,
102    baculaAddOptions,
103    baculaAddRegex,
104    baculaAddWild,
105    baculaNewOptions,
106    baculaNewInclude,
107    baculaNewPreInclude,
108    baculaCheckChanges,
109    baculaAcceptFile
110 };
111
112 /*
113  * Bacula private context
114  */
115 struct bacula_ctx {
116    JCR *jcr;                             /* jcr for plugin */
117    bRC  rc;                              /* last return code */
118    bool disabled;                        /* set if plugin disabled */
119    findINCEXE *exclude;                  /* pointer to exclude files */
120    findINCEXE *include;                  /* pointer to include/exclude files */
121 };
122
123 /*
124  * Test if event is for this plugin
125  */
126 static bool for_this_plugin(Plugin *plugin, char *name, int len)
127 {
128    Dmsg4(dbglvl, "name=%s len=%d plugin=%s plen=%d\n", name, len, plugin->file, plugin->file_len);
129    if (!name) {   /* if no plugin name, all plugins get it */
130       return true;
131    }
132    /* Return global VSS job metadata to all plugins */
133    if (strcmp("job", name) == 0) {  /* old V4.0 name for VSS job metadata */
134       return true;
135    }
136    if (strcmp("*all*", name) == 0) { /* new v6.0 name for VSS job metadata */
137       return true;
138    }
139    /* Check if this is the correct plugin */
140    if (len == plugin->file_len && strncmp(plugin->file, name, len) == 0) {
141       return true;
142    }
143    return false;
144 }
145
146
147 bool is_plugin_disabled(bpContext *plugin_ctx)
148 {
149    bacula_ctx *b_ctx;
150    Dsm_check(999);
151    if (!plugin_ctx) {
152       return true;
153    }
154    b_ctx = (bacula_ctx *)plugin_ctx->bContext;
155    if (!b_ctx) {
156       return true;
157    }
158    return b_ctx->disabled;
159 }
160
161 bool is_plugin_disabled(JCR *jcr)
162 {
163    return is_plugin_disabled(jcr->plugin_ctx);
164 }
165
166 /**
167  * Create a plugin event When receiving bEventCancelCommand, this function is
168  * called by an other thread.
169  */
170 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)
171 {
172    bpContext *plugin_ctx;
173    bEvent event;
174    Plugin *plugin;
175    char *name = NULL;
176    int i;
177    int len = 0;
178    bool call_if_canceled = false;
179    restore_object_pkt *rop;
180
181    Dsm_check(999);
182    if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list) {
183       return;                         /* Return if no plugins loaded */
184    }
185
186    /*
187     * Some events are sent to only a particular plugin or must be
188     *  called even if the job is canceled
189     */
190    switch(eventType) {
191    case bEventPluginCommand:
192    case bEventOptionPlugin:
193       name = (char *)value;
194       if (!get_plugin_name(jcr, name, &len)) {
195          return;
196       }
197       break;
198    case bEventRestoreObject:
199       /* After all RestoreObject, we have it one more time with value=NULL */
200       if (value) {
201          /* Some RestoreObjects may not have a plugin name */
202          rop = (restore_object_pkt *)value;
203          if (*rop->plugin_name) {
204             name = rop->plugin_name;
205             get_plugin_name(jcr, name, &len);
206          }
207       }
208
209       break;
210    case bEventEndBackupJob:
211    case bEventEndVerifyJob:
212       call_if_canceled = true; /* plugin *must* see this call */
213       break;
214    case bEventStartRestoreJob:
215       foreach_alist_index(i, plugin, b_plugin_list) {
216          plugin->restoreFileStarted = false;
217          plugin->createFileCalled = false;
218       }
219       break;
220    case bEventEndRestoreJob:
221       call_if_canceled = true; /* plugin *must* see this call */
222       break;
223    default:
224       break;
225    }
226
227    /* If call_if_canceled is set, we call the plugin anyway */
228    if (!call_if_canceled && jcr->is_job_canceled()) {
229       return;
230    }
231
232    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
233    event.eventType = eventType;
234
235    Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
236
237    /*
238     * Pass event to every plugin (except if name is set). If name
239     *   is set, we pass it only to the plugin with that name.
240     */
241    foreach_alist_index(i, plugin, b_plugin_list) {
242       if (!for_this_plugin(plugin, name, len)) {
243          Dmsg2(dbglvl, "Not for this plugin name=%s NULL=%d\n",
244             name, name==NULL?1:0);
245          continue;
246       }
247       /*
248        * Note, at this point do not change
249        *   jcr->plugin or jcr->plugin_ctx
250        */
251       Dsm_check(999);
252       plugin_ctx = &plugin_ctx_list[i];
253       if (is_plugin_disabled(plugin_ctx)) {
254          Dmsg1(50, "Plugin %s disabled\n", plugin->file);
255          continue;
256       }
257       if (eventType == bEventEndRestoreJob) {
258          Dmsg0(50, "eventType==bEventEndRestoreJob\n");
259          if (jcr->plugin && jcr->plugin->restoreFileStarted) {
260             plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
261          }
262          if (jcr->plugin) {
263             jcr->plugin->restoreFileStarted = false;
264             jcr->plugin->createFileCalled = false;
265          }
266       }
267       plug_func(plugin)->handlePluginEvent(plugin_ctx, &event, value);
268    }
269    return;
270 }
271
272 /**
273  * Check if file was seen for accurate
274  */
275 bool plugin_check_file(JCR *jcr, char *fname)
276 {
277    Plugin *plugin;
278    int rc = bRC_OK;
279    int i;
280
281    Dsm_check(999);
282    if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
283       return false;                      /* Return if no plugins loaded */
284    }
285
286    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
287
288    Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
289
290    /* Pass event to every plugin */
291    foreach_alist_index(i, plugin, b_plugin_list) {
292       jcr->plugin_ctx = &plugin_ctx_list[i];
293       jcr->plugin = plugin;
294       if (is_plugin_disabled(jcr)) {
295          continue;
296       }
297       if (plug_func(plugin)->checkFile == NULL) {
298          continue;
299       }
300       rc = plug_func(plugin)->checkFile(jcr->plugin_ctx, fname);
301       if (rc == bRC_Seen) {
302          break;
303       }
304    }
305
306    Dsm_check(999);
307    jcr->plugin = NULL;
308    jcr->plugin_ctx = NULL;
309    return rc == bRC_Seen;
310 }
311
312 /* Get the first part of the the plugin command
313  *  systemstate:/@SYSTEMSTATE/
314  * => ret = 11
315  * => can use for_this_plugin(plug, cmd, ret);
316  *
317  * The plugin command can contain only the plugin name
318  *  Plugin = alldrives
319  * => ret = 9
320  */
321 static bool get_plugin_name(JCR *jcr, char *cmd, int *ret)
322 {
323    char *p;
324    int len;
325    Dsm_check(999);
326    if (!cmd || (*cmd == '\0')) {
327       return false;
328    }
329    /* Handle plugin command here backup */
330    Dmsg1(dbglvl, "plugin cmd=%s\n", cmd);
331    if ((p = strchr(cmd, ':')) == NULL) {
332       if (strchr(cmd, ' ') == NULL) { /* we have just the plugin name */
333          len = strlen(cmd);
334       } else {
335          Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
336          return false;
337       }
338    } else {                     /* plugin:argument */
339       len = p - cmd;
340       if (len <= 0) {
341          return false;
342       }
343    }
344    *ret = len;
345    Dsm_check(999);
346    return true;
347 }
348
349
350 static void update_ff_pkt(FF_PKT *ff_pkt, struct save_pkt *sp)
351 {
352    Dsm_check(999);
353    ff_pkt->no_read = sp->no_read;
354    ff_pkt->delta_seq = sp->delta_seq;
355    if (sp->flags & FO_DELTA) {
356       ff_pkt->flags |= FO_DELTA;
357       ff_pkt->delta_seq++;          /* make new delta sequence number */
358    } else {
359       ff_pkt->flags &= ~FO_DELTA;   /* clean delta sequence number */
360       ff_pkt->delta_seq = 0;
361    }
362
363    if (sp->flags & FO_OFFSETS) {
364       ff_pkt->flags |= FO_OFFSETS;
365    } else {
366       ff_pkt->flags &= ~FO_OFFSETS;
367    }
368    /* Sparse code doesn't work with plugins
369     * that use FIFO or STDOUT/IN to communicate
370     */
371    if (sp->flags & FO_SPARSE) {
372       ff_pkt->flags |= FO_SPARSE;
373    } else {
374       ff_pkt->flags &= ~FO_SPARSE;
375    }
376    if (sp->flags & FO_PORTABLE_DATA) {
377       ff_pkt->flags |= FO_PORTABLE_DATA;
378    } else {
379       ff_pkt->flags &= ~FO_PORTABLE_DATA;
380    }
381    ff_pkt->flags |= FO_PLUGIN;       /* data from plugin */
382    Dsm_check(999);
383 }
384
385 /* Ask to a Option Plugin what to do with the current file */
386 bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp)
387 {
388    Plugin *plugin;
389    bRC ret = bRC_Error;
390    bool found=false;
391    char *cmd = ff_pkt->plugin;
392    int len;
393    int i=0;
394    bEvent event;
395    event.eventType = bEventHandleBackupFile;
396
397    Dsm_check(999);
398    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
399    memset(sp, 0, sizeof(struct save_pkt));
400    sp->pkt_size = sp->pkt_end = sizeof(struct save_pkt);
401    sp->portable = true;
402    sp->cmd = cmd;
403    sp->link = ff_pkt->link;
404    sp->cmd = ff_pkt->plugin;
405    sp->statp = ff_pkt->statp;
406    sp->fname = ff_pkt->fname;
407    sp->delta_seq = ff_pkt->delta_seq;
408    sp->accurate_found = ff_pkt->accurate_found;
409
410    if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
411       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
412       goto bail_out;         /* Return if no plugins loaded */
413    }
414
415    if (!get_plugin_name(jcr, cmd, &len)) {
416       goto bail_out;
417    }
418
419    /* Note, we stop the loop on the first plugin that matches the name */
420    foreach_alist_index(i, plugin, b_plugin_list) {
421       Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len);
422       if (!for_this_plugin(plugin, cmd, len)) {
423          continue;
424       }
425
426       found=true;
427
428       Dsm_check(999);
429       if (is_plugin_disabled(&plugin_ctx_list[i])) {
430          goto bail_out;
431       }
432
433       jcr->plugin_ctx = &plugin_ctx_list[i];
434       jcr->plugin = plugin;
435
436       ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i],
437                                                  &event, sp);
438
439       /* TODO: would be better to set this in save_file() */
440       if (ret == bRC_OK) {
441          jcr->opt_plugin = true;
442          jcr->plugin = plugin;
443          jcr->plugin_sp = sp;      /* Unset sp in save_file */
444          jcr->plugin_ctx = &plugin_ctx_list[i];
445
446          update_ff_pkt(ff_pkt, sp);
447
448       /* reset plugin in JCR if not used this time */
449       } else {
450          jcr->plugin_ctx = NULL;
451          jcr->plugin = NULL;
452       }
453
454       goto bail_out;
455    } /* end foreach loop */
456 bail_out:
457    if (!found) {
458       Jmsg1(jcr, M_FATAL, 0, "Options plugin \"%s\" not found.\n", cmd);
459    }
460    Dsm_check(999);
461    return ret;
462 }
463
464 /**
465  * Sequence of calls for a backup:
466  * 1. plugin_save() here is called with ff_pkt
467  * 2. we find the plugin requested on the command string
468  * 3. we generate a bEventBackupCommand event to the specified plugin
469  *    and pass it the command string.
470  * 4. we make a startPluginBackup call to the plugin, which gives
471  *    us the data we need in save_pkt
472  * 5. we call Bacula's save_file() subroutine to save the specified
473  *    file.  The plugin will be called at pluginIO() to supply the
474  *    file data.
475  *
476  * Sequence of calls for restore:
477  *   See subroutine plugin_name_stream() below.
478  */
479 int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
480 {
481    Plugin *plugin;
482    int len;
483    int i;
484    char *cmd = ff_pkt->top_fname;
485    struct save_pkt sp;
486    bEvent event;
487    POOL_MEM fname(PM_FNAME);
488    POOL_MEM link(PM_FNAME);
489
490    Dsm_check(999);
491    if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) {
492       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
493       return 1;                            /* Return if no plugins loaded */
494    }
495
496    jcr->cmd_plugin = true;
497    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
498    event.eventType = bEventBackupCommand;
499
500    if (!get_plugin_name(jcr, cmd, &len)) {
501       goto bail_out;
502    }
503
504    /* Note, we stop the loop on the first plugin that matches the name */
505    foreach_alist_index(i, plugin, b_plugin_list) {
506       Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len);
507       if (!for_this_plugin(plugin, cmd, len)) {
508          continue;
509       }
510       /*
511        * We put the current plugin pointer, and the plugin context
512        *  into the jcr, because during save_file(), the plugin
513        *  will be called many times and these values are needed.
514        */
515       Dsm_check(999);
516       jcr->plugin_ctx = &plugin_ctx_list[i];
517       jcr->plugin = plugin;
518       if (is_plugin_disabled(jcr)) {
519          goto bail_out;
520       }
521
522       Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
523       /* Send the backup command to the right plugin*/
524       if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
525          goto bail_out;
526       }
527       /* Loop getting filenames to backup then saving them */
528       while (!jcr->is_job_canceled()) {
529          memset(&sp, 0, sizeof(sp));
530          sp.pkt_size = sizeof(sp);
531          sp.pkt_end = sizeof(sp);
532          sp.portable = true;
533          sp.no_read = false;
534          sp.flags = 0;
535          sp.cmd = cmd;
536          Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
537                 &sp);
538          Dsm_check(999);
539          /* Get the file save parameters. I.e. the stat pkt ... */
540          if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) {
541             goto bail_out;
542          }
543          if (sp.type == 0) {
544             Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"),
545                cmd);
546             goto bail_out;
547          }
548          jcr->plugin_sp = &sp;
549          ff_pkt = jcr->ff;
550          /*
551           * Copy fname and link because save_file() zaps them.  This
552           *  avoids zaping the plugin's strings.
553           */
554          ff_pkt->type = sp.type;
555          if (IS_FT_OBJECT(sp.type)) {
556             if (!sp.object_name) {
557                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no object_name in startBackupFile packet.\n"),
558                   cmd);
559                goto bail_out;
560             }
561             ff_pkt->fname = cmd;                 /* full plugin string */
562             ff_pkt->object_name = sp.object_name;
563             ff_pkt->object_index = sp.index;     /* restore object index */
564             ff_pkt->object_compression = 0;      /* no compression for now */
565             ff_pkt->object = sp.object;
566             ff_pkt->object_len = sp.object_len;
567          } else {
568             Dsm_check(999);
569             if (!sp.fname) {
570                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"),
571                   cmd);
572                goto bail_out;
573             }
574             pm_strcpy(fname, sp.fname);
575             pm_strcpy(link, sp.link);
576
577
578             ff_pkt->fname = fname.c_str();
579             ff_pkt->link = link.c_str();
580             update_ff_pkt(ff_pkt, &sp);
581          }
582
583          memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp));
584          Dmsg2(dbglvl, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
585          if (sp.object) {
586             Dmsg2(dbglvl, "index=%d object=%s\n", sp.index, sp.object);
587          }
588          /* Call Bacula core code to backup the plugin's file */
589          save_file(jcr, ff_pkt, true);
590          bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx);
591          if (rc == bRC_More || rc == bRC_OK) {
592             accurate_mark_file_as_seen(jcr, fname.c_str());
593          }
594          Dsm_check(999);
595          if (rc == bRC_More) {
596             continue;
597          }
598          goto bail_out;
599       } /* end while loop */
600       goto bail_out;
601    } /* end loop over all plugins */
602    Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
603
604 bail_out:
605    Dsm_check(999);
606    jcr->cmd_plugin = false;
607    jcr->plugin = NULL;
608    jcr->plugin_ctx = NULL;
609    return 1;
610 }
611
612
613 /**
614  * Sequence of calls for a estimate:
615  * 1. plugin_estimate() here is called with ff_pkt
616  * 2. we find the plugin requested on the command string
617  * 3. we generate a bEventEstimateCommand event to the specified plugin
618  *    and pass it the command string.
619  * 4. we make a startPluginBackup call to the plugin, which gives
620  *    us the data we need in save_pkt
621  *
622  */
623 int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
624 {
625    Plugin *plugin;
626    int len;
627    int i;
628    char *cmd = ff_pkt->top_fname;
629    struct save_pkt sp;
630    bEvent event;
631    POOL_MEM fname(PM_FNAME);
632    POOL_MEM link(PM_FNAME);
633    ATTR attr;
634
635    Dsm_check(999);
636    if (!b_plugin_list || !jcr->plugin_ctx_list) {
637       Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd);
638       return 1;                            /* Return if no plugins loaded */
639    }
640
641    jcr->cmd_plugin = true;
642    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
643    event.eventType = bEventEstimateCommand;
644
645    if (!get_plugin_name(jcr, cmd, &len)) {
646       goto bail_out;
647    }
648
649    /* Note, we stop the loop on the first plugin that matches the name */
650    foreach_alist_index(i, plugin, b_plugin_list) {
651       Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len);
652       if (!for_this_plugin(plugin, cmd, len)) {
653          continue;
654       }
655       /*
656        * We put the current plugin pointer, and the plugin context
657        *  into the jcr, because during save_file(), the plugin
658        *  will be called many times and these values are needed.
659        */
660       Dsm_check(999);
661       jcr->plugin_ctx = &plugin_ctx_list[i];
662       jcr->plugin = plugin;
663       if (is_plugin_disabled(jcr)) {
664          goto bail_out;
665       }
666
667       Dmsg1(dbglvl, "Command plugin = %s\n", cmd);
668       /* Send the backup command to the right plugin*/
669       if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) {
670          goto bail_out;
671       }
672       /* Loop getting filenames to backup then saving them */
673       while (!jcr->is_job_canceled()) {
674          Dsm_check(999);
675          memset(&sp, 0, sizeof(sp));
676          sp.pkt_size = sizeof(sp);
677          sp.pkt_end = sizeof(sp);
678          sp.portable = true;
679          sp.flags = 0;
680          sp.cmd = cmd;
681          Dmsg3(dbglvl, "startBackup st_size=%p st_blocks=%p sp=%p\n", &sp.statp.st_size, &sp.statp.st_blocks,
682                 &sp);
683          /* Get the file save parameters. I.e. the stat pkt ... */
684          if (plug_func(plugin)->startBackupFile(jcr->plugin_ctx, &sp) != bRC_OK) {
685             goto bail_out;
686          }
687          if (sp.type == 0) {
688             Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no type in startBackupFile packet.\n"),
689                cmd);
690             goto bail_out;
691          }
692
693          if (!IS_FT_OBJECT(sp.type)) {
694             if (!sp.fname) {
695                Jmsg1(jcr, M_FATAL, 0, _("Command plugin \"%s\": no fname in startBackupFile packet.\n"),
696                   cmd);
697                goto bail_out;
698             }
699
700             /* Count only files backed up */
701             switch (sp.type) {
702             case FT_REGE:
703             case FT_REG:
704             case FT_LNK:
705             case FT_DIREND:
706             case FT_SPEC:
707             case FT_RAW:
708             case FT_FIFO:
709             case FT_LNKSAVED:
710                jcr->JobFiles++;        /* increment number of files backed up */
711                break;
712             default:
713                break;
714             }
715             jcr->num_files_examined++;
716
717             if (sp.type != FT_LNKSAVED && S_ISREG(sp.statp.st_mode)) {
718                if (sp.statp.st_size > 0) {
719                   jcr->JobBytes += sp.statp.st_size;
720                }
721             }
722
723             if (jcr->listing) {
724                memcpy(&attr.statp, &sp.statp, sizeof(struct stat));
725                attr.type = sp.type;
726                attr.ofname = (POOLMEM *)sp.fname;
727                attr.olname = (POOLMEM *)sp.link;
728                print_ls_output(jcr, &attr);
729             }
730          }
731
732          Dmsg2(dbglvl, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname);
733          if (sp.object) {
734             Dmsg2(dbglvl, "index=%d object=%s\n", sp.index, sp.object);
735          }
736          bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx);
737          if (rc == bRC_More || rc == bRC_OK) {
738             accurate_mark_file_as_seen(jcr, sp.fname);
739          }
740          Dsm_check(999);
741          if (rc == bRC_More) {
742             continue;
743          }
744          goto bail_out;
745       } /* end while loop */
746       goto bail_out;
747    } /* end loop over all plugins */
748    Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
749
750 bail_out:
751    Dsm_check(999);
752    jcr->cmd_plugin = false;
753    jcr->plugin = NULL;
754    jcr->plugin_ctx = NULL;
755    return 1;
756 }
757
758 /**
759  * Send plugin name start/end record to SD
760  */
761 bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start)
762 {
763    int stat;
764    int index = jcr->JobFiles;
765    struct save_pkt *sp = (struct save_pkt *)jcr->plugin_sp;
766
767    Dsm_check(999);
768    if (!sp) {
769       Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n"));
770       return false;
771    }
772    if (jcr->is_job_canceled()) {
773       return false;
774    }
775
776    if (start) {
777       index++;                  /* JobFiles not incremented yet */
778    }
779    Dmsg1(dbglvl, "send_plugin_name=%s\n", sp->cmd);
780    /* Send stream header */
781    Dsm_check(999);
782    if (!sd->fsend("%ld %d 0", index, STREAM_PLUGIN_NAME)) {
783      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
784            sd->bstrerror());
785      return false;
786    }
787    Dmsg1(dbglvl, "send plugin name hdr: %s\n", sd->msg);
788
789    Dsm_check(999);
790    if (start) {
791       /* Send data -- not much */
792       stat = sd->fsend("%ld 1 %d %s%c", index, sp->portable, sp->cmd, 0);
793    } else {
794       /* Send end of data */
795       stat = sd->fsend("%ld 0", jcr->JobFiles);
796    }
797    Dsm_check(999);
798    if (!stat) {
799       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
800             sd->bstrerror());
801          return false;
802    }
803    Dmsg1(dbglvl, "send plugin start/end: %s\n", sd->msg);
804    sd->signal(BNET_EOD);            /* indicate end of plugin name data */
805    Dsm_check(999);
806    return true;
807 }
808
809 /**
810  * Plugin name stream found during restore.  The record passed in
811  *  argument name was generated in send_plugin_name() above.
812  *
813  * Returns: true  if start of stream
814  *          false if end of steam
815  */
816 bool plugin_name_stream(JCR *jcr, char *name)
817 {
818    char *p = name;
819    char *cmd;
820    bool start;
821    Plugin *plugin;
822    int len;
823    int i;
824    bpContext *plugin_ctx_list = jcr->plugin_ctx_list;
825
826    Dsm_check(999);
827    Dmsg1(dbglvl, "Read plugin stream string=%s\n", name);
828    skip_nonspaces(&p);             /* skip over jcr->JobFiles */
829    skip_spaces(&p);
830    start = *p == '1';
831    if (start) {
832       /* Start of plugin data */
833       skip_nonspaces(&p);          /* skip start/end flag */
834       skip_spaces(&p);
835 //    portable = *p == '1';
836       skip_nonspaces(&p);          /* skip portable flag */
837       skip_spaces(&p);
838       cmd = p;
839    } else {
840       /*
841        * End of plugin data, notify plugin, then clear flags
842        */
843       Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx);
844       if (jcr->plugin && jcr->plugin->restoreFileStarted) {
845          plug_func(jcr->plugin)->endRestoreFile(jcr->plugin_ctx);
846       }
847       if (jcr->plugin) {
848          jcr->plugin->restoreFileStarted = false;
849          jcr->plugin->createFileCalled = false;
850       }
851       jcr->plugin_ctx = NULL;
852       jcr->plugin = NULL;
853       goto bail_out;
854    }
855    Dsm_check(999);
856    if (!plugin_ctx_list) {
857       goto bail_out;
858    }
859
860    /*
861     * After this point, we are dealing with a restore start
862     */
863    if (!get_plugin_name(jcr, cmd, &len)) {
864       goto bail_out;
865    }
866
867    /*
868     * Search for correct plugin as specified on the command
869     */
870    Dsm_check(999);
871    foreach_alist_index(i, plugin, b_plugin_list) {
872       bEvent event;
873       Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
874       if (!for_this_plugin(plugin, cmd, len)) {
875          continue;
876       }
877       Dsm_check(999);
878       jcr->plugin_ctx = &plugin_ctx_list[i];
879       jcr->plugin = plugin;
880       if (is_plugin_disabled(jcr)) {
881          Dmsg1(dbglvl, "Plugin %s disabled\n", cmd);
882          goto bail_out;
883       }
884       Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd);
885       event.eventType = bEventRestoreCommand;
886       if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx,
887             &event, cmd) != bRC_OK) {
888          Dmsg1(dbglvl, "Handle event failed. Plugin=%s\n", cmd);
889          goto bail_out;
890       }
891       if (plugin->restoreFileStarted) {
892          Jmsg2(jcr, M_FATAL, 0, "Second call to startRestoreFile. plugin=%s cmd=%s\n", plugin->file, cmd);
893          plugin->restoreFileStarted = false;
894          goto bail_out;
895       }
896       if (plug_func(plugin)->startRestoreFile(jcr->plugin_ctx, cmd) == bRC_OK) {
897          plugin->restoreFileStarted = true;
898          goto ok_out;
899       } else {
900          Dmsg1(dbglvl, "startRestoreFile failed. plugin=%s\n", cmd);
901       }
902       goto bail_out;
903    }
904    Jmsg1(jcr, M_WARNING, 0, _("Plugin=%s not found.\n"), cmd);
905    goto bail_out;
906
907 ok_out:
908    return start;
909
910 bail_out:
911    Dsm_check(999);
912    jcr->plugin = NULL;
913    jcr->plugin_ctx = NULL;
914    return start;
915 }
916
917 /**
918  * Tell the plugin to create the file.  Return values are
919  *   This is called only during Restore
920  *
921  *  CF_ERROR    -- error
922  *  CF_SKIP     -- skip processing this file
923  *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
924  *  CF_CREATED  -- created, but no content to extract (typically directories)
925  *
926  */
927 int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace)
928 {
929    bpContext *plugin_ctx = jcr->plugin_ctx;
930    Plugin *plugin = jcr->plugin;
931    struct restore_pkt rp;
932    int flags;
933    int rc;
934
935    Dsm_check(999);
936    if (!plugin || !plugin_ctx || jcr->is_job_canceled()) {
937       return CF_ERROR;
938    }
939
940    rp.pkt_size = sizeof(rp);
941    rp.pkt_end = sizeof(rp);
942    rp.delta_seq = attr->delta_seq;
943    rp.stream = attr->stream;
944    rp.data_stream = attr->data_stream;
945    rp.type = attr->type;
946    rp.file_index = attr->file_index;
947    rp.LinkFI = attr->LinkFI;
948    rp.uid = attr->uid;
949    rp.statp = attr->statp;                /* structure assignment */
950    rp.attrEx = attr->attrEx;
951    rp.ofname = attr->ofname;
952    rp.olname = attr->olname;
953    rp.where = jcr->where;
954    rp.RegexWhere = jcr->RegexWhere;
955    rp.replace = jcr->replace;
956    rp.create_status = CF_ERROR;
957    Dmsg4(dbglvl, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n",
958          rp.stream, rp.type, rp.LinkFI, rp.ofname);
959    if (rp.attrEx) {
960       Dmsg1(dbglvl, "attrEx=\"%s\"\n", rp.attrEx);
961    }
962    Dsm_check(999);
963    if (!plugin->restoreFileStarted || plugin->createFileCalled) {
964       Jmsg2(jcr, M_FATAL, 0, "Unbalanced call to createFile=%d %d\n",
965          plugin->createFileCalled, plugin->restoreFileStarted);
966       plugin->createFileCalled = false;
967       return CF_ERROR;
968    }
969    rc = plug_func(plugin)->createFile(plugin_ctx, &rp);
970    if (rc != bRC_OK) {
971       Qmsg2(jcr, M_ERROR, 0, _("Plugin createFile call failed. Stat=%d file=%s\n"),
972             rc, attr->ofname);
973       return CF_ERROR;
974    }
975    if (rp.create_status == CF_ERROR) {
976       Qmsg1(jcr, M_ERROR, 0, _("Plugin createFile call failed. Returned CF_ERROR file=%s\n"),
977             attr->ofname);
978       return CF_ERROR;
979    }
980
981    if (rp.create_status == CF_SKIP) {
982       return CF_SKIP;
983    }
984
985    if (rp.create_status == CF_CORE) {
986       return CF_CORE;           /* Let Bacula core handle the file creation */
987    }
988
989    /* Use the bfile for plugin */
990    set_cmd_plugin(bfd, jcr);
991
992    /* Created link or directory? */
993    if (rp.create_status == CF_CREATED) {
994       return rp.create_status;        /* yes, no need to bopen */
995    }
996
997    Dsm_check(999);
998
999    flags =  O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
1000    Dmsg0(dbglvl, "call bopen\n");
1001    int stat = bopen(bfd, attr->ofname, flags, S_IRUSR | S_IWUSR);
1002    Dmsg1(dbglvl, "bopen status=%d\n", stat);
1003    if (stat < 0) {
1004       berrno be;
1005       be.set_errno(bfd->berrno);
1006       Qmsg2(jcr, M_ERROR, 0, _("Could not create %s: ERR=%s\n"),
1007             attr->ofname, be.bstrerror());
1008       Dmsg2(dbglvl,"Could not bopen file %s: ERR=%s\n", attr->ofname, be.bstrerror());
1009       return CF_ERROR;
1010    }
1011
1012    if (!is_bopen(bfd)) {
1013       Dmsg0(000, "===== BFD is not open!!!!\n");
1014    }
1015    Dsm_check(999);
1016    return CF_EXTRACT;
1017 }
1018
1019 /**
1020  * Reset the file attributes after all file I/O is done -- this allows
1021  *  the previous access time/dates to be set properly, and it also allows
1022  *  us to properly set directory permissions.
1023  *  Not currently Implemented.
1024  */
1025 bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
1026 {
1027    Plugin *plugin = (Plugin *)jcr->plugin;
1028    struct restore_pkt rp;
1029
1030    Dmsg0(dbglvl, "plugin_set_attributes\n");
1031
1032    if (!plugin || !jcr->plugin_ctx) {
1033       return false;
1034    }
1035
1036    memset(&rp, 0, sizeof(rp));
1037    rp.pkt_size = sizeof(rp);
1038    rp.pkt_end = sizeof(rp);
1039    rp.stream = attr->stream;
1040    rp.data_stream = attr->data_stream;
1041    rp.type = attr->type;
1042    rp.file_index = attr->file_index;
1043    rp.LinkFI = attr->LinkFI;
1044    rp.uid = attr->uid;
1045    rp.statp = attr->statp;                /* structure assignment */
1046    rp.attrEx = attr->attrEx;
1047    rp.ofname = attr->ofname;
1048    rp.olname = attr->olname;
1049    rp.where = jcr->where;
1050    rp.RegexWhere = jcr->RegexWhere;
1051    rp.replace = jcr->replace;
1052    rp.create_status = CF_ERROR;
1053
1054    plug_func(plugin)->setFileAttributes(jcr->plugin_ctx, &rp);
1055
1056    if (rp.create_status == CF_CORE) {
1057       set_attributes(jcr, attr, ofd);
1058    } else {
1059       if (is_bopen(ofd)) {
1060          bclose(ofd);
1061       }
1062       pm_strcpy(attr->ofname, "*none*");
1063    }
1064
1065    Dsm_check(999);
1066    return true;
1067 }
1068
1069 /*
1070  * Print to file the plugin info.
1071  */
1072 void dump_fd_plugin(Plugin *plugin, FILE *fp)
1073 {
1074    if (!plugin) {
1075       return ;
1076    }
1077    pInfo *info = (pInfo *)plugin->pinfo;
1078    fprintf(fp, "\tversion=%d\n", info->version);
1079    fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
1080    fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
1081    fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
1082    fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
1083    fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
1084    fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
1085 }
1086
1087 /**
1088  * This entry point is called internally by Bacula to ensure
1089  *  that the plugin IO calls come into this code.
1090  */
1091 void load_fd_plugins(const char *plugin_dir)
1092 {
1093    Plugin *plugin;
1094    int i;
1095
1096    if (!plugin_dir) {
1097       Dmsg0(dbglvl, "plugin dir is NULL\n");
1098       return;
1099    }
1100
1101    b_plugin_list = New(alist(10, not_owned_by_alist));
1102    Dsm_check(999);
1103    if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type,
1104                      is_plugin_compatible)) {
1105       /* Either none found, or some error */
1106       if (b_plugin_list->size() == 0) {
1107          delete b_plugin_list;
1108          b_plugin_list = NULL;
1109          Dmsg0(dbglvl, "No plugins loaded\n");
1110          return;
1111       }
1112    }
1113
1114    /* Plug entry points called from findlib */
1115    plugin_bopen  = my_plugin_bopen;
1116    plugin_bclose = my_plugin_bclose;
1117    plugin_bread  = my_plugin_bread;
1118    plugin_bwrite = my_plugin_bwrite;
1119    plugin_blseek = my_plugin_blseek;
1120    Dsm_check(999);
1121
1122    /*
1123     * Verify that the plugin is acceptable, and print information
1124     *  about it.
1125     */
1126    foreach_alist_index(i, plugin, b_plugin_list) {
1127       Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file);
1128       Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file);
1129    }
1130
1131    dbg_plugin_add_hook(dump_fd_plugin);
1132    Dsm_check(999);
1133 }
1134
1135 /**
1136  * Check if a plugin is compatible.  Called by the load_plugin function
1137  *  to allow us to verify the plugin.
1138  */
1139 static bool is_plugin_compatible(Plugin *plugin)
1140 {
1141    pInfo *info = (pInfo *)plugin->pinfo;
1142    Dmsg0(dbglvl, "is_plugin_compatible called\n");
1143    Dsm_check(999);
1144    if (chk_dbglvl(50)) {
1145       dump_fd_plugin(plugin, stdin);
1146    }
1147    if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) {
1148       Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"),
1149            plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1150       Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n",
1151            plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic);
1152
1153       return false;
1154    }
1155    if (info->version != FD_PLUGIN_INTERFACE_VERSION) {
1156       Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
1157            plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1158       Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
1159            plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version);
1160       return false;
1161    }
1162    if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 &&
1163        strcmp(info->plugin_license, "AGPLv3") != 0 &&
1164        strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) {
1165       Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"),
1166            plugin->file, info->plugin_license);
1167       Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
1168            plugin->file, info->plugin_license);
1169       return false;
1170    }
1171    if (info->size != sizeof(pInfo)) {
1172       Jmsg(NULL, M_ERROR, 0,
1173            _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"),
1174            plugin->file, sizeof(pInfo), info->size);
1175       return false;
1176    }
1177
1178    Dsm_check(999);
1179    return true;
1180 }
1181
1182
1183 /**
1184  * Create a new instance of each plugin for this Job
1185  *   Note, b_plugin_list can exist but jcr->plugin_ctx_list can
1186  *   be NULL if no plugins were loaded.
1187  */
1188 void new_plugins(JCR *jcr)
1189 {
1190    Plugin *plugin;
1191    int i;
1192
1193    Dsm_check(999);
1194    if (!b_plugin_list) {
1195       Dmsg0(dbglvl, "plugin list is NULL\n");
1196       return;
1197    }
1198    if (jcr->is_job_canceled()) {
1199       return;
1200    }
1201
1202    int num = b_plugin_list->size();
1203
1204    if (num == 0) {
1205       Dmsg0(dbglvl, "No plugins loaded\n");
1206       return;
1207    }
1208
1209    jcr->plugin_ctx_list = (bpContext *)malloc(sizeof(bpContext) * num);
1210
1211    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
1212    Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
1213    foreach_alist_index(i, plugin, b_plugin_list) {
1214       Dsm_check(999);
1215       /* Start a new instance of each plugin */
1216       bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx));
1217       memset(b_ctx, 0, sizeof(bacula_ctx));
1218       b_ctx->jcr = jcr;
1219       plugin_ctx_list[i].bContext = (void *)b_ctx;   /* Bacula private context */
1220       plugin_ctx_list[i].pContext = NULL;
1221       if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) {
1222          Dmsg1(000, "Plugin %s will be disabled\n", plugin->file);
1223          b_ctx->disabled = true;
1224       }
1225    }
1226    if (i > num) {
1227       Jmsg2(jcr, M_ABORT, 0, "Num plugins=%d exceeds list size=%d\n",
1228             i, num);
1229    }
1230    Dsm_check(999);
1231 }
1232
1233 /**
1234  * Free the plugin instances for this Job
1235  */
1236 void free_plugins(JCR *jcr)
1237 {
1238    Plugin *plugin;
1239    int i;
1240
1241    if (!b_plugin_list || !jcr->plugin_ctx_list) {
1242       return;                         /* no plugins, nothing to do */
1243    }
1244
1245    Dsm_check(999);
1246    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
1247    Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
1248    foreach_alist_index(i, plugin, b_plugin_list) {
1249       /* Free the plugin instance */
1250       plug_func(plugin)->freePlugin(&plugin_ctx_list[i]);
1251       free(plugin_ctx_list[i].bContext);     /* free Bacula private context */
1252       Dsm_check(999);
1253    }
1254    Dsm_check(999);
1255    free(plugin_ctx_list);
1256    jcr->plugin_ctx_list = NULL;
1257 }
1258
1259 static int my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode)
1260 {
1261    JCR *jcr = bfd->jcr;
1262    Plugin *plugin = (Plugin *)jcr->plugin;
1263    struct io_pkt io;
1264
1265    Dmsg1(dbglvl, "plugin_bopen flags=%x\n", flags);
1266    Dsm_check(999);
1267    if (!plugin || !jcr->plugin_ctx) {
1268       return 0;
1269    }
1270    io.pkt_size = sizeof(io);
1271    io.pkt_end = sizeof(io);
1272    io.func = IO_OPEN;
1273    io.count = 0;
1274    io.buf = NULL;
1275    io.fname = fname;
1276    io.flags = flags;
1277    io.mode = mode;
1278    io.win32 = false;
1279    io.lerror = 0;
1280    io.status = -1;
1281    plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
1282    bfd->berrno = io.io_errno;
1283    if (io.win32) {
1284       errno = b_errno_win32;
1285    } else {
1286       errno = io.io_errno;
1287       bfd->lerror = io.lerror;
1288    }
1289    Dmsg1(dbglvl, "Return from plugin open status=%d\n", io.status);
1290    Dsm_check(999);
1291    return io.status;
1292 }
1293
1294 static int my_plugin_bclose(BFILE *bfd)
1295 {
1296    JCR *jcr = bfd->jcr;
1297    Plugin *plugin = (Plugin *)jcr->plugin;
1298    struct io_pkt io;
1299
1300    Dsm_check(999);
1301    Dmsg0(dbglvl, "===== plugin_bclose\n");
1302    if (!plugin || !jcr->plugin_ctx) {
1303       return 0;
1304    }
1305    io.pkt_size = sizeof(io);
1306    io.pkt_end = sizeof(io);
1307    io.func = IO_CLOSE;
1308    io.count = 0;
1309    io.buf = NULL;
1310    io.win32 = false;
1311    io.lerror = 0;
1312    io.status = -1;
1313    plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
1314    bfd->berrno = io.io_errno;
1315    if (io.win32) {
1316       errno = b_errno_win32;
1317    } else {
1318       errno = io.io_errno;
1319       bfd->lerror = io.lerror;
1320    }
1321    Dmsg1(dbglvl, "plugin_bclose stat=%d\n", io.status);
1322    Dsm_check(999);
1323    return io.status;
1324 }
1325
1326 static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count)
1327 {
1328    JCR *jcr = bfd->jcr;
1329    Plugin *plugin = (Plugin *)jcr->plugin;
1330    struct io_pkt io;
1331
1332    Dsm_check(999);
1333    Dmsg0(dbglvl, "plugin_bread\n");
1334    if (!plugin || !jcr->plugin_ctx) {
1335       return 0;
1336    }
1337    io.pkt_size = sizeof(io);
1338    io.pkt_end = sizeof(io);
1339    io.func = IO_READ;
1340    io.count = count;
1341    io.buf = (char *)buf;
1342    io.win32 = false;
1343    io.offset = 0;
1344    io.lerror = 0;
1345    io.status = -1;
1346    plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
1347    bfd->offset = io.offset;
1348    bfd->berrno = io.io_errno;
1349    if (io.win32) {
1350       errno = b_errno_win32;
1351    } else {
1352       errno = io.io_errno;
1353       bfd->lerror = io.lerror;
1354    }
1355    Dsm_check(999);
1356    return (ssize_t)io.status;
1357 }
1358
1359 static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count)
1360 {
1361    JCR *jcr = bfd->jcr;
1362    Plugin *plugin = (Plugin *)jcr->plugin;
1363    struct io_pkt io;
1364
1365    Dsm_check(999);
1366    Dmsg0(dbglvl, "plugin_bwrite\n");
1367    if (!plugin || !jcr->plugin_ctx) {
1368       Dmsg0(0, "No plugin context\n");
1369       return 0;
1370    }
1371    io.pkt_size = sizeof(io);
1372    io.pkt_end = sizeof(io);
1373    io.func = IO_WRITE;
1374    io.count = count;
1375    io.buf = (char *)buf;
1376    io.win32 = false;
1377    io.lerror = 0;
1378    io.status = -1;
1379    plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
1380    bfd->berrno = io.io_errno;
1381    if (io.win32) {
1382       errno = b_errno_win32;
1383    } else {
1384       errno = io.io_errno;
1385       bfd->lerror = io.lerror;
1386    }
1387    Dsm_check(999);
1388    return (ssize_t)io.status;
1389 }
1390
1391 static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence)
1392 {
1393    JCR *jcr = bfd->jcr;
1394    Plugin *plugin = (Plugin *)jcr->plugin;
1395    struct io_pkt io;
1396
1397    Dsm_check(999);
1398    Dmsg0(dbglvl, "plugin_bseek\n");
1399    if (!plugin || !jcr->plugin_ctx) {
1400       return 0;
1401    }
1402    io.pkt_size = sizeof(io);
1403    io.pkt_end = sizeof(io);
1404    io.func = IO_SEEK;
1405    io.offset = offset;
1406    io.whence = whence;
1407    io.win32 = false;
1408    io.lerror = 0;
1409    plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io);
1410    bfd->berrno = io.io_errno;
1411    if (io.win32) {
1412       errno = b_errno_win32;
1413    } else {
1414       errno = io.io_errno;
1415       bfd->lerror = io.lerror;
1416    }
1417    Dsm_check(999);
1418    return (boffset_t)io.offset;
1419 }
1420
1421 /* ==============================================================
1422  *
1423  * Callbacks from the plugin
1424  *
1425  * ==============================================================
1426  */
1427 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
1428 {
1429    JCR *jcr;
1430    if (!value) {
1431       return bRC_Error;
1432    }
1433
1434    Dsm_check(999);
1435    switch (var) {               /* General variables, no need of ctx */
1436    case bVarFDName:
1437       *((char **)value) = my_name;
1438       break;
1439    case bVarWorkingDir:
1440       *(void **)value = me->working_directory;
1441       break;
1442    case bVarExePath:
1443       *(char **)value = exepath;
1444       break;
1445    case bVarVersion:
1446       *(char **)value = version;
1447       break;
1448    case bVarDistName:
1449       *(char **)value = dist_name;
1450       break;
1451    case bVarPrevJobName:
1452       break;
1453    case bVarPrefixLinks:
1454       break;
1455    case bVarxxx:
1456       break;
1457    default:
1458       break;
1459    }
1460
1461    if (!ctx) {                  /* Other variables need context */
1462       return bRC_Error;
1463    }
1464
1465    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
1466    if (!jcr) {
1467       return bRC_Error;
1468    }
1469
1470    switch (var) {
1471    case bVarJobId:
1472       *((int *)value) = jcr->JobId;
1473       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
1474       break;
1475    case bVarLevel:
1476       *((int *)value) = jcr->getJobLevel();
1477       Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->getJobLevel());
1478       break;
1479    case bVarType:
1480       *((int *)value) = jcr->getJobType();
1481       Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->getJobType());
1482       break;
1483    case bVarClient:
1484       *((char **)value) = jcr->client_name;
1485       Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name);
1486       break;
1487    case bVarJobName:
1488       *((char **)value) = jcr->Job;
1489       Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job);
1490       break;
1491    case bVarPrevJobName:
1492       *((char **)value) = jcr->PrevJob;
1493       Dmsg1(dbglvl, "Bacula: return Previous Job name=%s\n", jcr->PrevJob);
1494       break;
1495    case bVarJobStatus:
1496       *((int *)value) = jcr->JobStatus;
1497       Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus);
1498       break;
1499    case bVarSinceTime:
1500       *((int *)value) = (int)jcr->mtime;
1501       Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime);
1502       break;
1503    case bVarAccurate:
1504       *((int *)value) = (int)jcr->accurate;
1505       Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate);
1506       break;
1507    case bVarInteractiveSession:
1508       *(int *)value = (int)jcr->interactive_session;
1509       break;
1510    case bVarFileSeen:
1511       break;                 /* a write only variable, ignore read request */
1512    case bVarVssObject:
1513        return bRC_Error;
1514    case bVarVssDllHandle:
1515        return bRC_Error;
1516    case bVarWhere:
1517       *(char **)value = jcr->where;
1518       break;
1519    case bVarRegexWhere:
1520       *(char **)value = jcr->RegexWhere;
1521       break;
1522    case bVarPrefixLinks:
1523       *(int *)value = (int)jcr->prefix_links;
1524       break;
1525    case bVarFDName:             /* get warning with g++ if we missed one */
1526    case bVarWorkingDir:
1527    case bVarExePath:
1528    case bVarVersion:
1529    case bVarDistName:
1530    case bVarxxx:
1531       break;
1532    }
1533    Dsm_check(999);
1534    return bRC_OK;
1535 }
1536
1537 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
1538 {
1539    JCR *jcr;
1540    Dsm_check(999);
1541    if (!value || !ctx) {
1542       return bRC_Error;
1543    }
1544 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
1545    jcr = ((bacula_ctx *)ctx->bContext)->jcr;
1546    if (!jcr) {
1547       return bRC_Error;
1548    }
1549 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr);
1550    switch (var) {
1551    case bVarFileSeen:
1552       if (!accurate_mark_file_as_seen(jcr, (char *)value)) {
1553          return bRC_Error;
1554       }
1555       break;
1556    case bVarInteractiveSession:
1557       jcr->interactive_session = (((intptr_t) value) == 1);
1558       break;
1559    default:
1560       break;
1561    }
1562    Dsm_check(999);
1563    return bRC_OK;
1564 }
1565
1566 static bRC baculaRegisterEvents(bpContext *ctx, ...)
1567 {
1568    va_list args;
1569    uint32_t event;
1570
1571    Dsm_check(999);
1572    if (!ctx) {
1573       return bRC_Error;
1574    }
1575
1576    va_start(args, ctx);
1577    while ((event = va_arg(args, uint32_t))) {
1578       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
1579    }
1580    va_end(args);
1581    Dsm_check(999);
1582    return bRC_OK;
1583 }
1584
1585 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
1586   int type, utime_t mtime, const char *fmt, ...)
1587 {
1588    va_list arg_ptr;
1589    char buf[2000];
1590    JCR *jcr;
1591
1592    Dsm_check(999);
1593    if (ctx) {
1594       jcr = ((bacula_ctx *)ctx->bContext)->jcr;
1595    } else {
1596       jcr = NULL;
1597    }
1598
1599    va_start(arg_ptr, fmt);
1600    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
1601    va_end(arg_ptr);
1602    Jmsg(jcr, type, mtime, "%s", buf);
1603    Dsm_check(999);
1604    return bRC_OK;
1605 }
1606
1607 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
1608   int level, const char *fmt, ...)
1609 {
1610    va_list arg_ptr;
1611    char buf[2000];
1612
1613    Dsm_check(999);
1614    va_start(arg_ptr, fmt);
1615    bvsnprintf(buf, sizeof(buf), fmt, arg_ptr);
1616    va_end(arg_ptr);
1617    d_msg(file, line, level, "%s", buf);
1618    Dsm_check(999);
1619    return bRC_OK;
1620 }
1621
1622 static void *baculaMalloc(bpContext *ctx, const char *file, int line,
1623               size_t size)
1624 {
1625 #ifdef SMARTALLOC
1626    return sm_malloc(file, line, size);
1627 #else
1628    return malloc(size);
1629 #endif
1630 }
1631
1632 static void baculaFree(bpContext *ctx, const char *file, int line, void *mem)
1633 {
1634 #ifdef SMARTALLOC
1635    sm_free(file, line, mem);
1636 #else
1637    free(mem);
1638 #endif
1639 }
1640
1641 static bool is_ctx_good(bpContext *ctx, JCR *&jcr, bacula_ctx *&bctx)
1642 {
1643    Dsm_check(999);
1644    if (!ctx) {
1645       return false;
1646    }
1647    bctx = (bacula_ctx *)ctx->bContext;
1648    if (!bctx) {
1649       return false;
1650    }
1651    jcr = bctx->jcr;
1652    if (!jcr) {
1653       return false;
1654    }
1655    return true;
1656 }
1657
1658 /**
1659  * Let the plugin define files/directories to be excluded
1660  *  from the main backup.
1661  */
1662 static bRC baculaAddExclude(bpContext *ctx, const char *file)
1663 {
1664    JCR *jcr;
1665    findINCEXE *old;
1666    bacula_ctx *bctx;
1667    Dsm_check(999);
1668    if (!is_ctx_good(ctx, jcr, bctx)) {
1669       return bRC_Error;
1670    }
1671    if (!file) {
1672       return bRC_Error;
1673    }
1674
1675    /* Save the include context */
1676    old = get_incexe(jcr);
1677
1678    /* Not right time to add exlude */
1679    if (!old) {
1680       return bRC_Error;
1681    }
1682
1683    if (!bctx->exclude) {
1684       bctx->exclude = new_exclude(jcr);
1685    }
1686
1687    /* Set the Exclude context */
1688    set_incexe(jcr, bctx->exclude);
1689
1690    add_file_to_fileset(jcr, file, true);
1691
1692    /* Restore the current context */
1693    set_incexe(jcr, old);
1694
1695    Dmsg1(100, "Add exclude file=%s\n", file);
1696    Dsm_check(999);
1697    return bRC_OK;
1698 }
1699
1700 /**
1701  * Let the plugin define files/directories to be excluded
1702  *  from the main backup.
1703  */
1704 static bRC baculaAddInclude(bpContext *ctx, const char *file)
1705 {
1706    JCR *jcr;
1707    findINCEXE *old;
1708    bacula_ctx *bctx;
1709
1710    Dsm_check(999);
1711    if (!is_ctx_good(ctx, jcr, bctx)) {
1712       return bRC_Error;
1713    }
1714    if (!file) {
1715       return bRC_Error;
1716    }
1717
1718    /* Save the include context */
1719    old = get_incexe(jcr);
1720
1721    /* Not right time to add include */
1722    if (!old) {
1723       return bRC_Error;
1724    }
1725    if (!bctx->include) {
1726       bctx->include = old;
1727    }
1728
1729    set_incexe(jcr, bctx->include);
1730    add_file_to_fileset(jcr, file, true);
1731
1732    /* Restore the current context */
1733    set_incexe(jcr, old);
1734
1735    Dmsg1(100, "Add include file=%s\n", file);
1736    Dsm_check(999);
1737    return bRC_OK;
1738 }
1739
1740 static bRC baculaAddOptions(bpContext *ctx, const char *opts)
1741 {
1742    JCR *jcr;
1743    bacula_ctx *bctx;
1744    Dsm_check(999);
1745    if (!is_ctx_good(ctx, jcr, bctx)) {
1746       return bRC_Error;
1747    }
1748    if (!opts) {
1749       return bRC_Error;
1750    }
1751    add_options_to_fileset(jcr, opts);
1752    Dsm_check(999);
1753    Dmsg1(1000, "Add options=%s\n", opts);
1754    return bRC_OK;
1755 }
1756
1757 static bRC baculaAddRegex(bpContext *ctx, const char *item, int type)
1758 {
1759    JCR *jcr;
1760    bacula_ctx *bctx;
1761    Dsm_check(999);
1762    if (!is_ctx_good(ctx, jcr, bctx)) {
1763       return bRC_Error;
1764    }
1765    if (!item) {
1766       return bRC_Error;
1767    }
1768    add_regex_to_fileset(jcr, item, type);
1769    Dmsg1(100, "Add regex=%s\n", item);
1770    Dsm_check(999);
1771    return bRC_OK;
1772 }
1773
1774 static bRC baculaAddWild(bpContext *ctx, const char *item, int type)
1775 {
1776    JCR *jcr;
1777    bacula_ctx *bctx;
1778    Dsm_check(999);
1779    if (!is_ctx_good(ctx, jcr, bctx)) {
1780       return bRC_Error;
1781    }
1782    if (!item) {
1783       return bRC_Error;
1784    }
1785    add_wild_to_fileset(jcr, item, type);
1786    Dmsg1(100, "Add wild=%s\n", item);
1787    Dsm_check(999);
1788    return bRC_OK;
1789 }
1790
1791 static bRC baculaNewOptions(bpContext *ctx)
1792 {
1793    JCR *jcr;
1794    bacula_ctx *bctx;
1795    Dsm_check(999);
1796    if (!is_ctx_good(ctx, jcr, bctx)) {
1797       return bRC_Error;
1798    }
1799    (void)new_options(jcr, NULL);
1800    Dsm_check(999);
1801    return bRC_OK;
1802 }
1803
1804 static bRC baculaNewInclude(bpContext *ctx)
1805 {
1806    JCR *jcr;
1807    bacula_ctx *bctx;
1808    Dsm_check(999);
1809    if (!is_ctx_good(ctx, jcr, bctx)) {
1810       return bRC_Error;
1811    }
1812    (void)new_include(jcr);
1813    Dsm_check(999);
1814    return bRC_OK;
1815 }
1816
1817 static bRC baculaNewPreInclude(bpContext *ctx)
1818 {
1819    JCR *jcr;
1820    bacula_ctx *bctx;
1821    Dsm_check(999);
1822    if (!is_ctx_good(ctx, jcr, bctx)) {
1823       return bRC_Error;
1824    }
1825
1826    bctx->include = new_preinclude(jcr);
1827    new_options(jcr, bctx->include);
1828    set_incexe(jcr, bctx->include);
1829
1830    Dsm_check(999);
1831    return bRC_OK;
1832 }
1833
1834 /*
1835  * Check if a file have to be backuped using Accurate code
1836  */
1837 static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp)
1838 {
1839    JCR *jcr;
1840    bacula_ctx *bctx;
1841    FF_PKT *ff_pkt;
1842    bRC ret = bRC_Error;
1843
1844    Dsm_check(999);
1845    if (!is_ctx_good(ctx, jcr, bctx)) {
1846       goto bail_out;
1847    }
1848    if (!sp) {
1849       goto bail_out;
1850    }
1851
1852    ff_pkt = jcr->ff;
1853    /*
1854     * Copy fname and link because save_file() zaps them.  This
1855     *  avoids zaping the plugin's strings.
1856     */
1857    ff_pkt->type = sp->type;
1858    if (!sp->fname) {
1859       Jmsg0(jcr, M_FATAL, 0, _("Command plugin: no fname in baculaCheckChanges packet.\n"));
1860       goto bail_out;
1861    }
1862
1863    ff_pkt->fname = sp->fname;
1864    ff_pkt->link = sp->link;
1865    memcpy(&ff_pkt->statp, &sp->statp, sizeof(ff_pkt->statp));
1866
1867    if (check_changes(jcr, ff_pkt))  {
1868       ret = bRC_OK;
1869    } else {
1870       ret = bRC_Seen;
1871    }
1872
1873    /* check_changes() can update delta sequence number, return it to the
1874     * plugin
1875     */
1876    sp->delta_seq = ff_pkt->delta_seq;
1877    sp->accurate_found = ff_pkt->accurate_found;
1878
1879 bail_out:
1880    Dsm_check(999);
1881    Dmsg1(100, "checkChanges=%i\n", ret);
1882    return ret;
1883 }
1884
1885 /*
1886  * Check if a file would be saved using current Include/Exclude code
1887  */
1888 static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp)
1889 {
1890    JCR *jcr;
1891    FF_PKT *ff_pkt;
1892    bacula_ctx *bctx;
1893
1894    char *old;
1895    struct stat oldstat;
1896    bRC ret = bRC_Error;
1897
1898    Dsm_check(999);
1899    if (!is_ctx_good(ctx, jcr, bctx)) {
1900       goto bail_out;
1901    }
1902    if (!sp) {
1903       goto bail_out;
1904    }
1905
1906    ff_pkt = jcr->ff;
1907
1908    /* Probably not needed, but keep a copy */
1909    old = ff_pkt->fname;
1910    oldstat = ff_pkt->statp;
1911
1912    ff_pkt->fname = sp->fname;
1913    ff_pkt->statp = sp->statp;
1914
1915    if (accept_file(ff_pkt)) {
1916       ret = bRC_OK;
1917    } else {
1918       ret = bRC_Skip;
1919    }
1920
1921    ff_pkt->fname = old;
1922    ff_pkt->statp = oldstat;
1923
1924 bail_out:
1925    return ret;
1926 }
1927
1928 #ifdef TEST_PROGRAM
1929
1930 int     (*plugin_bopen)(JCR *jcr, const char *fname, uint64_t flags, mode_t mode) = NULL;
1931 int     (*plugin_bclose)(JCR *jcr) = NULL;
1932 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
1933 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
1934 boffset_t (*plugin_blseek)(JCR *jcr, boffset_t offset, int whence) = NULL;
1935
1936 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
1937 {
1938    return 0;
1939 }
1940
1941 bool set_cmd_plugin(BFILE *bfd, JCR *jcr)
1942 {
1943    return true;
1944 }
1945
1946 int main(int argc, char *argv[])
1947 {
1948    char plugin_dir[1000];
1949    JCR mjcr1, mjcr2;
1950    JCR *jcr1 = &mjcr1;
1951    JCR *jcr2 = &mjcr2;
1952
1953    strcpy(my_name, "test-fd");
1954
1955    getcwd(plugin_dir, sizeof(plugin_dir)-1);
1956    load_fd_plugins(plugin_dir);
1957
1958    jcr1->JobId = 111;
1959    new_plugins(jcr1);
1960
1961    jcr2->JobId = 222;
1962    new_plugins(jcr2);
1963
1964    generate_plugin_event(jcr1, bEventJobStart, (void *)"Start Job 1");
1965    generate_plugin_event(jcr1, bEventJobEnd);
1966    generate_plugin_event(jcr2, bEventJobStart, (void *)"Start Job 2");
1967    free_plugins(jcr1);
1968    generate_plugin_event(jcr2, bEventJobEnd);
1969    free_plugins(jcr2);
1970
1971    unload_plugins();
1972
1973    Dmsg0(dbglvl, "bacula: OK ...\n");
1974    close_memory_pool();
1975    sm_dump(false);     /* unit test */
1976    return 0;
1977 }
1978
1979 #endif /* TEST_PROGRAM */