1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation, which is
11    listed in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Kern Sibbald, October 2007
25  */
26 
27 /**
28  * @file
29  * Bareos pluginloader
30  */
31 #include "include/bareos.h"
32 #include "stored/stored.h"
33 #include "stored/stored_globals.h"
34 #include "stored/jcr_private.h"
35 #include "sd_plugins.h"
36 #include "lib/crypto_cache.h"
37 #include "stored/sd_stats.h"
38 #include "lib/edit.h"
39 #include "include/jcr.h"
40 
41 namespace storagedaemon {
42 
43 const int debuglevel = 250;
44 #ifdef HAVE_WIN32
45 const char* plugin_type = "-sd.dll";
46 #else
47 const char* plugin_type = "-sd.so";
48 #endif
49 static alist* sd_plugin_list = NULL;
50 
51 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
52 
53 /* Forward referenced functions */
54 static bRC bareosGetValue(bpContext* ctx, bsdrVariable var, void* value);
55 static bRC bareosSetValue(bpContext* ctx, bsdwVariable var, void* value);
56 static bRC bareosRegisterEvents(bpContext* ctx, int nr_events, ...);
57 static bRC bareosUnRegisterEvents(bpContext* ctx, int nr_events, ...);
58 static bRC bareosGetInstanceCount(bpContext* ctx, int* ret);
59 static bRC bareosJobMsg(bpContext* ctx,
60                         const char* file,
61                         int line,
62                         int type,
63                         utime_t mtime,
64                         const char* fmt,
65                         ...);
66 static bRC bareosDebugMsg(bpContext* ctx,
67                           const char* file,
68                           int line,
69                           int level,
70                           const char* fmt,
71                           ...);
72 static char* bareosEditDeviceCodes(DeviceControlRecord* dcr,
73                                    POOLMEM*& omsg,
74                                    const char* imsg,
75                                    const char* cmd);
76 static char* bareosLookupCryptoKey(const char* VolumeName);
77 static bool bareosUpdateVolumeInfo(DeviceControlRecord* dcr);
78 static void bareosUpdateTapeAlert(DeviceControlRecord* dcr, uint64_t flags);
79 static DeviceRecord* bareosNewRecord(bool with_data);
80 static void bareosCopyRecordState(DeviceRecord* dst, DeviceRecord* src);
81 static void bareosFreeRecord(DeviceRecord* rec);
82 static bool IsPluginCompatible(Plugin* plugin);
83 
84 /* Bareos info */
85 static bsdInfo binfo = {sizeof(bsdFuncs), SD_PLUGIN_INTERFACE_VERSION};
86 
87 /* Bareos entry points */
88 static bsdFuncs bfuncs = {sizeof(bsdFuncs),       SD_PLUGIN_INTERFACE_VERSION,
89                           bareosRegisterEvents,   bareosUnRegisterEvents,
90                           bareosGetInstanceCount, bareosGetValue,
91                           bareosSetValue,         bareosJobMsg,
92                           bareosDebugMsg,         bareosEditDeviceCodes,
93                           bareosLookupCryptoKey,  bareosUpdateVolumeInfo,
94                           bareosUpdateTapeAlert,  bareosNewRecord,
95                           bareosCopyRecordState,  bareosFreeRecord};
96 
97 /**
98  * Bareos private context
99  */
100 struct b_plugin_ctx {
101   JobControlRecord* jcr;                        /* jcr for plugin */
102   bRC rc;                                       /* last return code */
103   bool disabled;                                /* set if plugin disabled */
104   char events[NbytesForBits(SD_NR_EVENTS + 1)]; /* enabled events bitmask */
105   Plugin* plugin; /* pointer to plugin of which this is an instance off */
106 };
107 
IsEventEnabled(bpContext * ctx,bsdEventType eventType)108 static inline bool IsEventEnabled(bpContext* ctx, bsdEventType eventType)
109 {
110   b_plugin_ctx* b_ctx;
111   if (!ctx) { return false; }
112   b_ctx = (b_plugin_ctx*)ctx->bContext;
113   if (!b_ctx) { return false; }
114 
115   return BitIsSet(eventType, b_ctx->events);
116 }
117 
IsPluginDisabled(bpContext * ctx)118 static inline bool IsPluginDisabled(bpContext* ctx)
119 {
120   b_plugin_ctx* b_ctx;
121   if (!ctx) { return true; }
122   b_ctx = (b_plugin_ctx*)ctx->bContext;
123   if (!b_ctx) { return true; }
124   return b_ctx->disabled;
125 }
126 
IsCtxGood(bpContext * ctx,JobControlRecord * & jcr,b_plugin_ctx * & bctx)127 static bool IsCtxGood(bpContext* ctx,
128                       JobControlRecord*& jcr,
129                       b_plugin_ctx*& bctx)
130 {
131   if (!ctx) { return false; }
132 
133   bctx = (b_plugin_ctx*)ctx->bContext;
134   if (!bctx) { return false; }
135 
136   jcr = bctx->jcr;
137   if (!jcr) { return false; }
138 
139   return true;
140 }
141 
142 /**
143  * Edit codes into ChangerCommand
144  *  %% = %
145  *  %a = Archive device name
146  *  %c = Changer device name
147  *  %D = Diagnostic device name
148  *  %d = Changer drive index
149  *  %f = Client's name
150  *  %j = Job name
151  *  %o = Command
152  *  %s = Slot base 0
153  *  %S = Slot base 1
154  *  %v = Volume name
155  *
156  *
157  *  omsg = edited output message
158  *  imsg = input string containing edit codes (%x)
159  *  cmd = command string (load, unload, ...)
160  */
edit_device_codes(DeviceControlRecord * dcr,POOLMEM * & omsg,const char * imsg,const char * cmd)161 char* edit_device_codes(DeviceControlRecord* dcr,
162                         POOLMEM*& omsg,
163                         const char* imsg,
164                         const char* cmd)
165 {
166   const char* p;
167   const char* str;
168   char ed1[50];
169 
170   *omsg = 0;
171   Dmsg1(1800, "edit_device_codes: %s\n", imsg);
172   for (p = imsg; *p; p++) {
173     if (*p == '%') {
174       switch (*++p) {
175         case '%':
176           str = "%";
177           break;
178         case 'a':
179           str = dcr->dev->archive_name();
180           break;
181         case 'c':
182           str = NPRT(dcr->device->changer_name);
183           break;
184         case 'D':
185           str = NPRT(dcr->device->diag_device_name);
186           break;
187         case 'd':
188           str = edit_int64(dcr->dev->drive_index, ed1);
189           break;
190         case 'o':
191           str = NPRT(cmd);
192           break;
193         case 's':
194           str = edit_int64(dcr->VolCatInfo.Slot - 1, ed1);
195           break;
196         case 'S':
197           str = edit_int64(dcr->VolCatInfo.Slot, ed1);
198           break;
199         case 'j': /* Job name */
200           str = dcr->jcr->Job;
201           break;
202         case 'v':
203           if (dcr->VolCatInfo.VolCatName[0]) {
204             str = dcr->VolCatInfo.VolCatName;
205           } else if (dcr->VolumeName[0]) {
206             str = dcr->VolumeName;
207           } else if (dcr->dev->vol && dcr->dev->vol->vol_name) {
208             str = dcr->dev->vol->vol_name;
209           } else {
210             str = dcr->dev->VolHdr.VolumeName;
211           }
212           break;
213         case 'f':
214           str = NPRT(dcr->jcr->client_name);
215           break;
216         default:
217           ed1[0] = '%';
218           ed1[1] = *p;
219           ed1[2] = 0;
220           str = ed1;
221           break;
222       }
223     } else {
224       ed1[0] = *p;
225       ed1[1] = 0;
226       str = ed1;
227     }
228     Dmsg1(1900, "add_str %s\n", str);
229     PmStrcat(omsg, (char*)str);
230     Dmsg1(1800, "omsg=%s\n", omsg);
231   }
232   Dmsg1(800, "omsg=%s\n", omsg);
233 
234   return omsg;
235 }
236 
trigger_plugin_event(JobControlRecord * jcr,bsdEventType eventType,bsdEvent * event,bpContext * ctx,void * value,alist * plugin_ctx_list,int * index,bRC * rc)237 static inline bool trigger_plugin_event(JobControlRecord* jcr,
238                                         bsdEventType eventType,
239                                         bsdEvent* event,
240                                         bpContext* ctx,
241                                         void* value,
242                                         alist* plugin_ctx_list,
243                                         int* index,
244                                         bRC* rc)
245 {
246   bool stop = false;
247 
248   if (!IsEventEnabled(ctx, eventType)) {
249     Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
250     goto bail_out;
251   }
252 
253   if (IsPluginDisabled(ctx)) {
254     Dmsg0(debuglevel, "Plugin disabled.\n");
255     goto bail_out;
256   }
257 
258   /*
259    * See if we should care about the return code.
260    */
261   if (rc) {
262     *rc = SdplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
263     switch (*rc) {
264       case bRC_OK:
265         break;
266       case bRC_Stop:
267       case bRC_Error:
268         stop = true;
269         break;
270       case bRC_More:
271         break;
272       case bRC_Term:
273         /*
274          * Request to unload this plugin.
275          * As we remove the plugin from the list of plugins we decrement
276          * the running index value so the next plugin gets triggered as
277          * that moved back a position in the alist.
278          */
279         if (index) {
280           UnloadPlugin(plugin_ctx_list, ctx->plugin, *index);
281           *index = ((*index) - 1);
282         }
283         break;
284       case bRC_Seen:
285         break;
286       case bRC_Core:
287         break;
288       case bRC_Skip:
289         stop = true;
290         break;
291       case bRC_Cancel:
292         break;
293       default:
294         break;
295     }
296   } else {
297     SdplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
298   }
299 
300 bail_out:
301   return stop;
302 }
303 
304 /**
305  * Create a plugin event
306  */
GeneratePluginEvent(JobControlRecord * jcr,bsdEventType eventType,void * value,bool reverse)307 bRC GeneratePluginEvent(JobControlRecord* jcr,
308                         bsdEventType eventType,
309                         void* value,
310                         bool reverse)
311 {
312   int i;
313   bsdEvent event;
314   alist* plugin_ctx_list;
315   bRC rc = bRC_OK;
316 
317   if (!sd_plugin_list) {
318     Dmsg0(debuglevel, "No bplugin_list: GeneratePluginEvent ignored.\n");
319     goto bail_out;
320   }
321 
322   if (!jcr) {
323     Dmsg0(debuglevel, "No jcr: GeneratePluginEvent ignored.\n");
324     goto bail_out;
325   }
326 
327   /*
328    * Return if no plugins loaded
329    */
330   if (!jcr->plugin_ctx_list) {
331     Dmsg0(debuglevel, "No plugin_ctx_list: GeneratePluginEvent ignored.\n");
332     goto bail_out;
333   }
334 
335   plugin_ctx_list = jcr->plugin_ctx_list;
336   event.eventType = eventType;
337 
338   Dmsg2(debuglevel, "sd-plugin_ctx_list=%p JobId=%d\n", plugin_ctx_list,
339         jcr->JobId);
340 
341   /*
342    * See if we need to trigger the loaded plugins in reverse order.
343    */
344   if (reverse) {
345     bpContext* ctx;
346 
347     foreach_alist_rindex (i, ctx, plugin_ctx_list) {
348       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
349                                plugin_ctx_list, &i, &rc)) {
350         break;
351       }
352     }
353   } else {
354     bpContext* ctx;
355 
356     foreach_alist_index (i, ctx, plugin_ctx_list) {
357       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
358                                plugin_ctx_list, &i, &rc)) {
359         break;
360       }
361     }
362   }
363 
364   if (jcr->IsJobCanceled()) {
365     Dmsg0(debuglevel, "Cancel return from GeneratePluginEvent\n");
366     rc = bRC_Cancel;
367   }
368 
369 bail_out:
370   return rc;
371 }
372 
373 /**
374  * Print to file the plugin info.
375  */
DumpSdPlugin(Plugin * plugin,FILE * fp)376 void DumpSdPlugin(Plugin* plugin, FILE* fp)
377 {
378   genpInfo* info;
379 
380   if (!plugin) { return; }
381 
382   info = (genpInfo*)plugin->pinfo;
383   fprintf(fp, "\tversion=%d\n", info->version);
384   fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
385   fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
386   fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
387   fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
388   fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
389   fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
390 }
391 
DumpSdPlugins(FILE * fp)392 static void DumpSdPlugins(FILE* fp) { DumpPlugins(sd_plugin_list, fp); }
393 
394 /**
395  * This entry point is called internally by Bareos to ensure
396  *  that the plugin IO calls come into this code.
397  */
LoadSdPlugins(const char * plugin_dir,alist * plugin_names)398 void LoadSdPlugins(const char* plugin_dir, alist* plugin_names)
399 {
400   Plugin* plugin;
401   int i;
402 
403   Dmsg0(debuglevel, "Load sd plugins\n");
404   if (!plugin_dir) {
405     Dmsg0(debuglevel, "No sd plugin dir!\n");
406     return;
407   }
408   sd_plugin_list = new alist(10, not_owned_by_alist);
409   if (!LoadPlugins((void*)&binfo, (void*)&bfuncs, sd_plugin_list, plugin_dir,
410                    plugin_names, plugin_type, IsPluginCompatible)) {
411     /*
412      * Either none found, or some error
413      */
414     if (sd_plugin_list->size() == 0) {
415       delete sd_plugin_list;
416       sd_plugin_list = NULL;
417       Dmsg0(debuglevel, "No plugins loaded\n");
418       return;
419     }
420   }
421   /*
422    * Verify that the plugin is acceptable, and print information about it.
423    */
424   foreach_alist_index (i, plugin, sd_plugin_list) {
425     Dmsg1(debuglevel, "Loaded plugin: %s\n", plugin->file);
426   }
427 
428   Dmsg1(debuglevel, "num plugins=%d\n", sd_plugin_list->size());
429   DbgPluginAddHook(DumpSdPlugin);
430   DbgPrintPluginAddHook(DumpSdPlugins);
431 }
432 
UnloadSdPlugins(void)433 void UnloadSdPlugins(void)
434 {
435   UnloadPlugins(sd_plugin_list);
436   delete sd_plugin_list;
437   sd_plugin_list = NULL;
438 }
439 
ListSdPlugins(PoolMem & msg)440 int ListSdPlugins(PoolMem& msg) { return ListPlugins(sd_plugin_list, msg); }
441 
442 /**
443  * Check if a plugin is compatible.  Called by the load_plugin function
444  *  to allow us to verify the plugin.
445  */
IsPluginCompatible(Plugin * plugin)446 static bool IsPluginCompatible(Plugin* plugin)
447 {
448   genpInfo* info = (genpInfo*)plugin->pinfo;
449   Dmsg0(50, "IsPluginCompatible called\n");
450   if (debug_level >= 50) { DumpSdPlugin(plugin, stdin); }
451   if (!bstrcmp(info->plugin_magic, SD_PLUGIN_MAGIC)) {
452     Jmsg(NULL, M_ERROR, 0,
453          _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"), plugin->file,
454          SD_PLUGIN_MAGIC, info->plugin_magic);
455     Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n", plugin->file,
456           SD_PLUGIN_MAGIC, info->plugin_magic);
457 
458     return false;
459   }
460   if (info->version != SD_PLUGIN_INTERFACE_VERSION) {
461     Jmsg(NULL, M_ERROR, 0,
462          _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
463          plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
464     Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
465           plugin->file, SD_PLUGIN_INTERFACE_VERSION, info->version);
466     return false;
467   }
468   if (!Bstrcasecmp(info->plugin_license, "Bareos AGPLv3") &&
469       !Bstrcasecmp(info->plugin_license, "AGPLv3")) {
470     Jmsg(NULL, M_ERROR, 0,
471          _("Plugin license incompatible. Plugin=%s license=%s\n"), plugin->file,
472          info->plugin_license);
473     Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
474           plugin->file, info->plugin_license);
475     return false;
476   }
477   if (info->size != sizeof(genpInfo)) {
478     Jmsg(NULL, M_ERROR, 0,
479          _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"), plugin->file,
480          sizeof(genpInfo), info->size);
481     return false;
482   }
483 
484   return true;
485 }
486 
487 /**
488  * Instantiate a new plugin instance.
489  */
instantiate_plugin(JobControlRecord * jcr,Plugin * plugin,uint32_t instance)490 static inline bpContext* instantiate_plugin(JobControlRecord* jcr,
491                                             Plugin* plugin,
492                                             uint32_t instance)
493 {
494   bpContext* ctx;
495   b_plugin_ctx* b_ctx;
496 
497   b_ctx = (b_plugin_ctx*)malloc(sizeof(b_plugin_ctx));
498   memset(b_ctx, 0, sizeof(b_plugin_ctx));
499   b_ctx->jcr = jcr;
500   b_ctx->plugin = plugin;
501 
502   Dmsg2(debuglevel, "Instantiate dir-plugin_ctx_list=%p JobId=%d\n",
503         jcr->plugin_ctx_list, jcr->JobId);
504 
505   ctx = (bpContext*)malloc(sizeof(bpContext));
506   ctx->instance = instance;
507   ctx->plugin = plugin;
508   ctx->bContext = (void*)b_ctx;
509   ctx->pContext = NULL;
510 
511   jcr->plugin_ctx_list->append(ctx);
512 
513   if (SdplugFunc(plugin)->newPlugin(ctx) != bRC_OK) { b_ctx->disabled = true; }
514 
515   return ctx;
516 }
517 
518 /**
519  * Send a bsdEventNewPluginOptions event to all plugins configured in
520  * jcr->impl_->plugin_options.
521  */
DispatchNewPluginOptions(JobControlRecord * jcr)522 void DispatchNewPluginOptions(JobControlRecord* jcr)
523 {
524   int i, j, len;
525   Plugin* plugin;
526   bpContext* ctx = nullptr;
527   uint32_t instance;
528   bsdEvent event;
529   bsdEventType eventType;
530   char *bp, *plugin_name, *option;
531   const char* plugin_options;
532   PoolMem priv_plugin_options(PM_MESSAGE);
533 
534   if (!sd_plugin_list || sd_plugin_list->empty()) { return; }
535 
536   if (jcr->impl->plugin_options && jcr->impl->plugin_options->size()) {
537     eventType = bsdEventNewPluginOptions;
538     event.eventType = eventType;
539 
540     foreach_alist_index (i, plugin_options, jcr->impl->plugin_options) {
541       /*
542        * Make a private copy of plugin options.
543        */
544       PmStrcpy(priv_plugin_options, plugin_options);
545 
546       plugin_name = priv_plugin_options.c_str();
547       if (!(bp = strchr(plugin_name, ':'))) {
548         Jmsg(NULL, M_ERROR, 0,
549              _("Illegal SD plugin options encountered, %s skipping\n"),
550              priv_plugin_options.c_str());
551         continue;
552       }
553       *bp++ = '\0';
554 
555       /*
556        * See if there is any instance named in the options string.
557        */
558       instance = 0;
559       option = bp;
560       while (option) {
561         bp = strchr(bp, ':');
562         if (bp) { *bp++ = '\0'; }
563 
564         if (bstrncasecmp(option, "instance=", 9)) {
565           instance = str_to_int64(option + 9);
566           break;
567         }
568 
569         option = bp;
570       }
571 
572       if (instance < LOWEST_PLUGIN_INSTANCE ||
573           instance > HIGHEST_PLUGIN_INSTANCE) {
574         Jmsg(NULL, M_ERROR, 0,
575              _("Illegal SD plugin options encountered, %s instance %d "
576                "skipping\n"),
577              plugin_options, instance);
578         continue;
579       }
580 
581       len = strlen(plugin_name);
582 
583       /*
584        * See if this plugin options are for an already instantiated plugin
585        * instance.
586        */
587       if (jcr->plugin_ctx_list) {
588         foreach_alist (ctx, jcr->plugin_ctx_list) {
589           if (ctx->instance == instance && ctx->plugin->file_len == len &&
590               bstrncasecmp(ctx->plugin->file, plugin_name, len)) {
591             break;
592           }
593         }
594 
595         /*
596          * Found a context in the previous loop ?
597          */
598         if (!ctx) {
599           foreach_alist_index (j, plugin, sd_plugin_list) {
600             if (plugin->file_len == len &&
601                 bstrncasecmp(plugin->file, plugin_name, len)) {
602               ctx = instantiate_plugin(jcr, plugin, instance);
603               break;
604             }
605           }
606         }
607 
608         if (ctx) {
609           trigger_plugin_event(jcr, eventType, &event, ctx,
610                                (void*)plugin_options, NULL, NULL, NULL);
611         }
612       }
613     }
614   }
615 }
616 
617 /**
618  * Create a new instance of each plugin for this Job
619  */
NewPlugins(JobControlRecord * jcr)620 void NewPlugins(JobControlRecord* jcr)
621 {
622   Plugin* plugin;
623   int i, num;
624 
625   Dmsg0(debuglevel, "=== enter NewPlugins ===\n");
626   if (!sd_plugin_list) {
627     Dmsg0(debuglevel, "No sd plugin list!\n");
628     return;
629   }
630   if (jcr->IsJobCanceled()) { return; }
631   /*
632    * If plugins already loaded, just return
633    */
634   if (jcr->plugin_ctx_list) { return; }
635 
636   num = sd_plugin_list->size();
637   Dmsg1(debuglevel, "sd-plugin-list size=%d\n", num);
638   if (num == 0) { return; }
639 
640   jcr->plugin_ctx_list = new alist(10, owned_by_alist);
641   foreach_alist_index (i, plugin, sd_plugin_list) {
642     /*
643      * Start a new instance of each plugin
644      */
645     instantiate_plugin(jcr, plugin, 0);
646   }
647 }
648 
649 /**
650  * Free the plugin instances for this Job
651  */
FreePlugins(JobControlRecord * jcr)652 void FreePlugins(JobControlRecord* jcr)
653 {
654   bpContext* ctx = nullptr;
655 
656   if (!sd_plugin_list || !jcr->plugin_ctx_list) { return; }
657 
658   Dmsg2(debuglevel, "Free instance dir-plugin_ctx_list=%p JobId=%d\n",
659         jcr->plugin_ctx_list, jcr->JobId);
660   foreach_alist (ctx, jcr->plugin_ctx_list) {
661     /*
662      * Free the plugin instance
663      */
664     SdplugFunc(ctx->plugin)->freePlugin(ctx);
665     free(ctx->bContext); /* Free BAREOS private context */
666   }
667 
668   delete jcr->plugin_ctx_list;
669   jcr->plugin_ctx_list = NULL;
670 }
671 
672 /* ==============================================================
673  *
674  * Callbacks from the plugin
675  *
676  * ==============================================================
677  */
bareosGetValue(bpContext * ctx,bsdrVariable var,void * value)678 static bRC bareosGetValue(bpContext* ctx, bsdrVariable var, void* value)
679 {
680   JobControlRecord* jcr = NULL;
681   bRC retval = bRC_OK;
682 
683   if (!value) { return bRC_Error; }
684 
685   switch (var) { /* General variables, no need of ctx */
686     case bsdVarCompatible:
687       *((bool*)value) = me->compatible;
688       Dmsg1(debuglevel, "sd-plugin: return bsdVarCompatible=%s\n",
689             (me->compatible) ? "true" : "false");
690       break;
691     case bsdVarPluginDir:
692       *((char**)value) = me->plugin_directory;
693       Dmsg1(debuglevel, "sd-plugin: return bsdVarPluginDir=%s\n",
694             me->plugin_directory);
695       break;
696     default:
697       if (!ctx) { return bRC_Error; }
698 
699       jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
700       if (!jcr) { return bRC_Error; }
701       break;
702   }
703 
704   if (jcr) {
705     switch (var) {
706       case bsdVarJob:
707         *((char**)value) = jcr->impl->job_name;
708         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobName=%s\n",
709               NPRT(*((char**)value)));
710         break;
711       case bsdVarLevel:
712         *((int*)value) = jcr->getJobLevel();
713         Dmsg1(debuglevel, "sd-plugin: return bsdVarLevel=%c\n",
714               jcr->getJobLevel());
715         break;
716       case bsdVarType:
717         *((int*)value) = jcr->getJobType();
718         Dmsg1(debuglevel, "sd-plugin: return bsdVarType=%c\n",
719               jcr->getJobType());
720         break;
721       case bsdVarJobId:
722         *((int*)value) = jcr->JobId;
723         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobId=%d\n", jcr->JobId);
724         break;
725       case bsdVarClient:
726         *((char**)value) = jcr->client_name;
727         Dmsg1(debuglevel, "sd-plugin: return bsdVarClient=%s\n",
728               NPRT(*((char**)value)));
729         break;
730       case bsdVarPool:
731         if (jcr->impl->dcr) {
732           *((char**)value) = jcr->impl->dcr->pool_name;
733           Dmsg1(debuglevel, "sd-plugin: return bsdVarPool=%s\n",
734                 NPRT(*((char**)value)));
735         } else {
736           retval = bRC_Error;
737         }
738         break;
739       case bsdVarPoolType:
740         if (jcr->impl->dcr) {
741           *((char**)value) = jcr->impl->dcr->pool_type;
742           Dmsg1(debuglevel, "sd-plugin: return bsdVarPoolType=%s\n",
743                 NPRT(*((char**)value)));
744         } else {
745           retval = bRC_Error;
746         }
747         break;
748       case bsdVarStorage:
749         if (jcr->impl->dcr && jcr->impl->dcr->device) {
750           *((char**)value) = jcr->impl->dcr->device->resource_name_;
751           Dmsg1(debuglevel, "sd-plugin: return bsdVarStorage=%s\n",
752                 NPRT(*((char**)value)));
753         } else {
754           retval = bRC_Error;
755         }
756         break;
757       case bsdVarMediaType:
758         if (jcr->impl->dcr) {
759           *((char**)value) = jcr->impl->dcr->media_type;
760           Dmsg1(debuglevel, "sd-plugin: return bsdVarMediaType=%s\n",
761                 NPRT(*((char**)value)));
762         } else {
763           retval = bRC_Error;
764         }
765         break;
766       case bsdVarJobName:
767         *((char**)value) = jcr->Job;
768         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobName=%s\n",
769               NPRT(*((char**)value)));
770         break;
771       case bsdVarJobStatus:
772         *((int*)value) = jcr->JobStatus;
773         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobStatus=%c\n",
774               jcr->JobStatus);
775         break;
776       case bsdVarVolumeName:
777         if (jcr->impl->dcr) {
778           *((char**)value) = jcr->impl->dcr->VolumeName;
779           Dmsg1(debuglevel, "sd-plugin: return bsdVarVolumeName=%s\n",
780                 NPRT(*((char**)value)));
781         } else {
782           retval = bRC_Error;
783         }
784         Dmsg1(debuglevel, "sd-plugin: return bsdVarVolumeName=%s\n",
785               jcr->VolumeName);
786         break;
787       case bsdVarJobErrors:
788         *((int*)value) = jcr->JobErrors;
789         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobErrors=%d\n",
790               jcr->JobErrors);
791         break;
792       case bsdVarJobFiles:
793         *((int*)value) = jcr->JobFiles;
794         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobFiles=%d\n",
795               jcr->JobFiles);
796         break;
797       case bsdVarJobBytes:
798         *((uint64_t*)value) = jcr->JobBytes;
799         Dmsg1(debuglevel, "sd-plugin: return bsdVarJobBytes=%d\n",
800               jcr->JobBytes);
801         break;
802       default:
803         break;
804     }
805   }
806 
807   return retval;
808 }
809 
bareosSetValue(bpContext * ctx,bsdwVariable var,void * value)810 static bRC bareosSetValue(bpContext* ctx, bsdwVariable var, void* value)
811 {
812   JobControlRecord* jcr;
813   if (!value || !ctx) { return bRC_Error; }
814 
815   jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
816   if (!jcr) { return bRC_Error; }
817 
818   Dmsg1(debuglevel, "sd-plugin: bareosSetValue var=%d\n", var);
819   switch (var) {
820     case bsdwVarVolumeName:
821       PmStrcpy(jcr->VolumeName, ((char*)value));
822       break;
823     case bsdwVarPriority:
824       jcr->JobPriority = *((int*)value);
825       break;
826     case bsdwVarJobLevel:
827       jcr->setJobLevel(*((int*)value));
828       break;
829     default:
830       break;
831   }
832 
833   return bRC_OK;
834 }
835 
bareosRegisterEvents(bpContext * ctx,int nr_events,...)836 static bRC bareosRegisterEvents(bpContext* ctx, int nr_events, ...)
837 {
838   int i;
839   va_list args;
840   uint32_t event;
841   b_plugin_ctx* b_ctx;
842 
843   if (!ctx) { return bRC_Error; }
844   b_ctx = (b_plugin_ctx*)ctx->bContext;
845   va_start(args, nr_events);
846   for (i = 0; i < nr_events; i++) {
847     event = va_arg(args, uint32_t);
848     Dmsg1(debuglevel, "sd-plugin: Plugin registered event=%u\n", event);
849     SetBit(event, b_ctx->events);
850   }
851   va_end(args);
852   return bRC_OK;
853 }
854 
bareosUnRegisterEvents(bpContext * ctx,int nr_events,...)855 static bRC bareosUnRegisterEvents(bpContext* ctx, int nr_events, ...)
856 {
857   int i;
858   va_list args;
859   uint32_t event;
860   b_plugin_ctx* b_ctx;
861 
862   if (!ctx) { return bRC_Error; }
863   b_ctx = (b_plugin_ctx*)ctx->bContext;
864   va_start(args, nr_events);
865   for (i = 0; i < nr_events; i++) {
866     event = va_arg(args, uint32_t);
867     Dmsg1(debuglevel, "sd-plugin: Plugin unregistered event=%u\n", event);
868     ClearBit(event, b_ctx->events);
869   }
870   va_end(args);
871   return bRC_OK;
872 }
873 
bareosGetInstanceCount(bpContext * ctx,int * ret)874 static bRC bareosGetInstanceCount(bpContext* ctx, int* ret)
875 {
876   int cnt;
877   JobControlRecord *jcr, *njcr;
878   bpContext* nctx;
879   b_plugin_ctx* bctx;
880   bRC retval = bRC_Error;
881 
882   if (!IsCtxGood(ctx, jcr, bctx)) { goto bail_out; }
883 
884   P(mutex);
885 
886   cnt = 0;
887   foreach_jcr (njcr) {
888     if (jcr->plugin_ctx_list) {
889       foreach_alist (nctx, jcr->plugin_ctx_list) {
890         if (nctx->plugin == bctx->plugin) { cnt++; }
891       }
892     }
893   }
894   endeach_jcr(njcr);
895 
896   V(mutex);
897 
898   *ret = cnt;
899   retval = bRC_OK;
900 
901 bail_out:
902   return retval;
903 }
904 
bareosJobMsg(bpContext * ctx,const char * file,int line,int type,utime_t mtime,const char * fmt,...)905 static bRC bareosJobMsg(bpContext* ctx,
906                         const char* file,
907                         int line,
908                         int type,
909                         utime_t mtime,
910                         const char* fmt,
911                         ...)
912 {
913   JobControlRecord* jcr;
914   va_list arg_ptr;
915   PoolMem buffer(PM_MESSAGE);
916 
917   if (ctx) {
918     jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
919   } else {
920     jcr = NULL;
921   }
922 
923   va_start(arg_ptr, fmt);
924   buffer.Bvsprintf(fmt, arg_ptr);
925   va_end(arg_ptr);
926   Jmsg(jcr, type, mtime, "%s", buffer.c_str());
927 
928   return bRC_OK;
929 }
930 
bareosDebugMsg(bpContext * ctx,const char * file,int line,int level,const char * fmt,...)931 static bRC bareosDebugMsg(bpContext* ctx,
932                           const char* file,
933                           int line,
934                           int level,
935                           const char* fmt,
936                           ...)
937 {
938   va_list arg_ptr;
939   PoolMem buffer(PM_MESSAGE);
940 
941   va_start(arg_ptr, fmt);
942   buffer.Bvsprintf(fmt, arg_ptr);
943   va_end(arg_ptr);
944   d_msg(file, line, level, "%s", buffer.c_str());
945 
946   return bRC_OK;
947 }
948 
bareosEditDeviceCodes(DeviceControlRecord * dcr,POOLMEM * & omsg,const char * imsg,const char * cmd)949 static char* bareosEditDeviceCodes(DeviceControlRecord* dcr,
950                                    POOLMEM*& omsg,
951                                    const char* imsg,
952                                    const char* cmd)
953 {
954   return edit_device_codes(dcr, omsg, imsg, cmd);
955 }
956 
bareosLookupCryptoKey(const char * VolumeName)957 static char* bareosLookupCryptoKey(const char* VolumeName)
958 {
959   return lookup_crypto_cache_entry(VolumeName);
960 }
961 
bareosUpdateVolumeInfo(DeviceControlRecord * dcr)962 static bool bareosUpdateVolumeInfo(DeviceControlRecord* dcr)
963 {
964   return dcr->DirGetVolumeInfo(GET_VOL_INFO_FOR_READ);
965 }
966 
bareosUpdateTapeAlert(DeviceControlRecord * dcr,uint64_t flags)967 static void bareosUpdateTapeAlert(DeviceControlRecord* dcr, uint64_t flags)
968 {
969   utime_t now;
970   now = (utime_t)time(NULL);
971 
972   UpdateDeviceTapealert(dcr->device->resource_name_, flags, now);
973 }
974 
bareosNewRecord(bool with_data)975 static DeviceRecord* bareosNewRecord(bool with_data)
976 {
977   return new_record(with_data);
978 }
979 
bareosCopyRecordState(DeviceRecord * dst,DeviceRecord * src)980 static void bareosCopyRecordState(DeviceRecord* dst, DeviceRecord* src)
981 {
982   CopyRecordState(dst, src);
983 }
984 
bareosFreeRecord(DeviceRecord * rec)985 static void bareosFreeRecord(DeviceRecord* rec) { FreeRecord(rec); }
986 
987 } /* namespace storagedaemon */
988