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