1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2016 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 /** @file
27  * BAREOS pluginloader
28  */
29 #include "include/bareos.h"
30 #include "dird.h"
31 #include "dird/dird_globals.h"
32 #include "dird/jcr_private.h"
33 #include "dir_plugins.h"
34 #include "lib/edit.h"
35 
36 namespace directordaemon {
37 
38 const int debuglevel = 150;
39 #ifdef HAVE_WIN32
40 const char* plugin_type = "-dir.dll";
41 #else
42 const char* plugin_type = "-dir.so";
43 #endif
44 
45 static alist* dird_plugin_list;
46 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
47 
48 /* Forward referenced functions */
49 static bRC bareosGetValue(bpContext* ctx, brDirVariable var, void* value);
50 static bRC bareosSetValue(bpContext* ctx, bwDirVariable var, void* value);
51 static bRC bareosRegisterEvents(bpContext* ctx, int nr_events, ...);
52 static bRC bareosUnRegisterEvents(bpContext* ctx, int nr_events, ...);
53 static bRC bareosGetInstanceCount(bpContext* ctx, int* ret);
54 static bRC bareosJobMsg(bpContext* ctx,
55                         const char* file,
56                         int line,
57                         int type,
58                         utime_t mtime,
59                         const char* fmt,
60                         ...);
61 static bRC bareosDebugMsg(bpContext* ctx,
62                           const char* file,
63                           int line,
64                           int level,
65                           const char* fmt,
66                           ...);
67 static bool IsPluginCompatible(Plugin* plugin);
68 
69 /* BAREOS info */
70 static bDirInfo binfo = {sizeof(bDirFuncs), DIR_PLUGIN_INTERFACE_VERSION};
71 
72 /* BAREOS entry points */
73 static bDirFuncs bfuncs = {sizeof(bDirFuncs),      DIR_PLUGIN_INTERFACE_VERSION,
74                            bareosRegisterEvents,   bareosUnRegisterEvents,
75                            bareosGetInstanceCount, bareosGetValue,
76                            bareosSetValue,         bareosJobMsg,
77                            bareosDebugMsg};
78 
79 /*
80  * BAREOS private context
81  */
82 struct b_plugin_ctx {
83   JobControlRecord* jcr;                         /* jcr for plugin */
84   bRC rc;                                        /* last return code */
85   bool disabled;                                 /* set if plugin disabled */
86   char events[NbytesForBits(DIR_NR_EVENTS + 1)]; /* enabled events bitmask */
87   Plugin* plugin; /* pointer to plugin of which this is an instance off */
88 };
89 
IsEventEnabled(bpContext * ctx,bDirEventType eventType)90 static inline bool IsEventEnabled(bpContext* ctx, bDirEventType eventType)
91 {
92   b_plugin_ctx* b_ctx;
93   if (!ctx) { return false; }
94   b_ctx = (b_plugin_ctx*)ctx->bContext;
95   if (!b_ctx) { return false; }
96   return BitIsSet(eventType, b_ctx->events);
97 }
98 
IsPluginDisabled(bpContext * ctx)99 static inline bool IsPluginDisabled(bpContext* ctx)
100 {
101   b_plugin_ctx* b_ctx;
102   if (!ctx) { return true; }
103   b_ctx = (b_plugin_ctx*)ctx->bContext;
104   if (!b_ctx) { return true; }
105   return b_ctx->disabled;
106 }
107 
IsCtxGood(bpContext * ctx,JobControlRecord * & jcr,b_plugin_ctx * & bctx)108 static bool IsCtxGood(bpContext* ctx,
109                       JobControlRecord*& jcr,
110                       b_plugin_ctx*& bctx)
111 {
112   if (!ctx) { return false; }
113 
114   bctx = (b_plugin_ctx*)ctx->bContext;
115   if (!bctx) { return false; }
116 
117   jcr = bctx->jcr;
118   if (!jcr) { return false; }
119 
120   return true;
121 }
122 
trigger_plugin_event(JobControlRecord * jcr,bDirEventType eventType,bDirEvent * event,bpContext * ctx,void * value,alist * plugin_ctx_list,int * index,bRC * rc)123 static inline bool trigger_plugin_event(JobControlRecord* jcr,
124                                         bDirEventType eventType,
125                                         bDirEvent* event,
126                                         bpContext* ctx,
127                                         void* value,
128                                         alist* plugin_ctx_list,
129                                         int* index,
130                                         bRC* rc)
131 {
132   bool stop = false;
133 
134   if (!IsEventEnabled(ctx, eventType)) {
135     Dmsg1(debuglevel, "Event %d disabled for this plugin.\n", eventType);
136     goto bail_out;
137   }
138 
139   if (IsPluginDisabled(ctx)) {
140     Dmsg0(debuglevel, "Plugin disabled.\n");
141     goto bail_out;
142   }
143 
144   /*
145    * See if we should care about the return code.
146    */
147   if (rc) {
148     *rc = DirplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
149     switch (*rc) {
150       case bRC_OK:
151         break;
152       case bRC_Stop:
153       case bRC_Error:
154         stop = true;
155         break;
156       case bRC_More:
157         break;
158       case bRC_Term:
159         /*
160          * Request to unload this plugin.
161          * As we remove the plugin from the list of plugins we decrement
162          * the running index value so the next plugin gets triggered as
163          * that moved back a position in the alist.
164          */
165         if (index) {
166           UnloadPlugin(plugin_ctx_list, ctx->plugin, *index);
167           *index = ((*index) - 1);
168         }
169         break;
170       case bRC_Seen:
171         break;
172       case bRC_Core:
173         break;
174       case bRC_Skip:
175         stop = true;
176         break;
177       case bRC_Cancel:
178         break;
179       default:
180         break;
181     }
182   } else {
183     DirplugFunc(ctx->plugin)->handlePluginEvent(ctx, event, value);
184   }
185 
186 bail_out:
187   return stop;
188 }
189 
190 /*
191  * Create a plugin event
192  */
GeneratePluginEvent(JobControlRecord * jcr,bDirEventType eventType,void * value,bool reverse)193 bRC GeneratePluginEvent(JobControlRecord* jcr,
194                         bDirEventType eventType,
195                         void* value,
196                         bool reverse)
197 {
198   int i;
199   bDirEvent event;
200   alist* plugin_ctx_list;
201   bRC rc = bRC_OK;
202 
203   if (!dird_plugin_list) {
204     Dmsg0(debuglevel, "No bplugin_list: GeneratePluginEvent ignored.\n");
205     goto bail_out;
206   }
207 
208   if (!jcr) {
209     Dmsg0(debuglevel, "No jcr: GeneratePluginEvent ignored.\n");
210     goto bail_out;
211   }
212 
213   /*
214    * Return if no plugins loaded
215    */
216   if (!jcr->plugin_ctx_list) {
217     Dmsg0(debuglevel, "No plugin_ctx_list: GeneratePluginEvent ignored.\n");
218     goto bail_out;
219   }
220 
221   plugin_ctx_list = jcr->plugin_ctx_list;
222   event.eventType = eventType;
223 
224   Dmsg2(debuglevel, "dir-plugin_ctx_list=%p JobId=%d\n", plugin_ctx_list,
225         jcr->JobId);
226 
227   /*
228    * See if we need to trigger the loaded plugins in reverse order.
229    */
230   if (reverse) {
231     bpContext* ctx;
232 
233     foreach_alist_rindex (i, ctx, plugin_ctx_list) {
234       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
235                                plugin_ctx_list, &i, &rc)) {
236         break;
237       }
238     }
239   } else {
240     bpContext* ctx;
241 
242     foreach_alist_index (i, ctx, plugin_ctx_list) {
243       if (trigger_plugin_event(jcr, eventType, &event, ctx, value,
244                                plugin_ctx_list, &i, &rc)) {
245         break;
246       }
247     }
248   }
249 
250   if (jcr->IsJobCanceled()) {
251     Dmsg0(debuglevel, "Cancel return from GeneratePluginEvent\n");
252     rc = bRC_Cancel;
253   }
254 
255 bail_out:
256   return rc;
257 }
258 
259 /**
260  * Print to file the plugin info.
261  */
DumpDirPlugin(Plugin * plugin,FILE * fp)262 void DumpDirPlugin(Plugin* plugin, FILE* fp)
263 {
264   genpInfo* info;
265 
266   if (!plugin) { return; }
267 
268   info = (genpInfo*)plugin->pinfo;
269   fprintf(fp, "\tversion=%d\n", info->version);
270   fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date));
271   fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic));
272   fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author));
273   fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license));
274   fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version));
275   fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description));
276 }
277 
DumpDirPlugins(FILE * fp)278 static void DumpDirPlugins(FILE* fp) { DumpPlugins(dird_plugin_list, fp); }
279 
280 /**
281  * This entry point is called internally by BAREOS to ensure
282  *  that the plugin IO calls come into this code.
283  */
LoadDirPlugins(const char * plugin_dir,alist * plugin_names)284 void LoadDirPlugins(const char* plugin_dir, alist* plugin_names)
285 {
286   Plugin* plugin;
287   int i;
288 
289   Dmsg0(debuglevel, "Load dir plugins\n");
290   if (!plugin_dir) {
291     Dmsg0(debuglevel, "No dir plugin dir!\n");
292     return;
293   }
294 
295   dird_plugin_list = new alist(10, not_owned_by_alist);
296   if (!LoadPlugins((void*)&binfo, (void*)&bfuncs, dird_plugin_list, plugin_dir,
297                    plugin_names, plugin_type, IsPluginCompatible)) {
298     /* Either none found, or some error */
299     if (dird_plugin_list->size() == 0) {
300       delete dird_plugin_list;
301       dird_plugin_list = NULL;
302       Dmsg0(debuglevel, "No plugins loaded\n");
303       return;
304     }
305   }
306   /*
307    * Verify that the plugin is acceptable, and print information
308    *  about it.
309    */
310   foreach_alist_index (i, plugin, dird_plugin_list) {
311     Dmsg1(debuglevel, "Loaded plugin: %s\n", plugin->file);
312   }
313 
314   Dmsg1(debuglevel, "num plugins=%d\n", dird_plugin_list->size());
315   DbgPluginAddHook(DumpDirPlugin);
316   DbgPrintPluginAddHook(DumpDirPlugins);
317 }
318 
UnloadDirPlugins(void)319 void UnloadDirPlugins(void)
320 {
321   UnloadPlugins(dird_plugin_list);
322   delete dird_plugin_list;
323   dird_plugin_list = NULL;
324 }
325 
ListDirPlugins(PoolMem & msg)326 int ListDirPlugins(PoolMem& msg) { return ListPlugins(dird_plugin_list, msg); }
327 
328 /**
329  * Check if a plugin is compatible.  Called by the load_plugin function
330  *  to allow us to verify the plugin.
331  */
IsPluginCompatible(Plugin * plugin)332 static bool IsPluginCompatible(Plugin* plugin)
333 {
334   genpInfo* info = (genpInfo*)plugin->pinfo;
335 
336   Dmsg0(50, "IsPluginCompatible called\n");
337   if (debug_level >= 50) { DumpDirPlugin(plugin, stdin); }
338   if (!bstrcmp(info->plugin_magic, DIR_PLUGIN_MAGIC)) {
339     Jmsg(NULL, M_ERROR, 0,
340          _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"), plugin->file,
341          DIR_PLUGIN_MAGIC, info->plugin_magic);
342     Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n", plugin->file,
343           DIR_PLUGIN_MAGIC, info->plugin_magic);
344 
345     return false;
346   }
347   if (info->version != DIR_PLUGIN_INTERFACE_VERSION) {
348     Jmsg(NULL, M_ERROR, 0,
349          _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"),
350          plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
351     Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n",
352           plugin->file, DIR_PLUGIN_INTERFACE_VERSION, info->version);
353     return false;
354   }
355   if (!Bstrcasecmp(info->plugin_license, "Bareos AGPLv3") &&
356       !Bstrcasecmp(info->plugin_license, "AGPLv3")) {
357     Jmsg(NULL, M_ERROR, 0,
358          _("Plugin license incompatible. Plugin=%s license=%s\n"), plugin->file,
359          info->plugin_license);
360     Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n",
361           plugin->file, info->plugin_license);
362     return false;
363   }
364   if (info->size != sizeof(genpInfo)) {
365     Jmsg(NULL, M_ERROR, 0,
366          _("Plugin size incorrect. Plugin=%s wanted=%d got=%d\n"), plugin->file,
367          sizeof(genpInfo), info->size);
368     return false;
369   }
370 
371   return true;
372 }
373 
374 /**
375  * Instantiate a new plugin instance.
376  */
instantiate_plugin(JobControlRecord * jcr,Plugin * plugin,uint32_t instance)377 static inline bpContext* instantiate_plugin(JobControlRecord* jcr,
378                                             Plugin* plugin,
379                                             uint32_t instance)
380 {
381   bpContext* ctx;
382   b_plugin_ctx* b_ctx;
383 
384   b_ctx = (b_plugin_ctx*)malloc(sizeof(b_plugin_ctx));
385   memset(b_ctx, 0, sizeof(b_plugin_ctx));
386   b_ctx->jcr = jcr;
387   b_ctx->plugin = plugin;
388 
389   Dmsg2(debuglevel, "Instantiate dir-plugin_ctx_list=%p JobId=%d\n",
390         jcr->plugin_ctx_list, jcr->JobId);
391 
392   ctx = (bpContext*)malloc(sizeof(bpContext));
393   ctx->instance = instance;
394   ctx->plugin = plugin;
395   ctx->bContext = (void*)b_ctx;
396   ctx->pContext = NULL;
397 
398   jcr->plugin_ctx_list->append(ctx);
399 
400   if (DirplugFunc(plugin)->newPlugin(ctx) != bRC_OK) { b_ctx->disabled = true; }
401 
402   return ctx;
403 }
404 
405 /**
406  * Send a bDirEventNewPluginOptions event to all plugins configured in
407  * jcr->impl_->res.Job.DirPluginOptions
408  */
DispatchNewPluginOptions(JobControlRecord * jcr)409 void DispatchNewPluginOptions(JobControlRecord* jcr)
410 {
411   int i, j, len;
412   Plugin* plugin;
413   bpContext* ctx = nullptr;
414   uint32_t instance;
415   bDirEvent event;
416   bDirEventType eventType;
417   char *bp, *plugin_name, *option;
418   const char* plugin_options;
419   PoolMem priv_plugin_options(PM_MESSAGE);
420 
421   if (!dird_plugin_list || dird_plugin_list->empty()) { return; }
422 
423   if (jcr->impl->res.job && jcr->impl->res.job->DirPluginOptions &&
424       jcr->impl->res.job->DirPluginOptions->size()) {
425     eventType = bDirEventNewPluginOptions;
426     event.eventType = eventType;
427 
428     foreach_alist_index (i, plugin_options,
429                          jcr->impl->res.job->DirPluginOptions) {
430       /*
431        * Make a private copy of plugin options.
432        */
433       PmStrcpy(priv_plugin_options, plugin_options);
434 
435       plugin_name = priv_plugin_options.c_str();
436       if (!(bp = strchr(plugin_name, ':'))) {
437         Jmsg(NULL, M_ERROR, 0,
438              _("Illegal DIR plugin options encountered, %s skipping\n"),
439              priv_plugin_options.c_str());
440         continue;
441       }
442       *bp++ = '\0';
443 
444       /*
445        * See if there is any instance named in the options string.
446        */
447       instance = 0;
448       option = bp;
449       while (option) {
450         bp = strchr(bp, ':');
451         if (bp) { *bp++ = '\0'; }
452 
453         if (bstrncasecmp(option, "instance=", 9)) {
454           instance = str_to_int64(option + 9);
455           break;
456         }
457 
458         option = bp;
459       }
460 
461       if (instance < LOWEST_PLUGIN_INSTANCE ||
462           instance > HIGHEST_PLUGIN_INSTANCE) {
463         Jmsg(NULL, M_ERROR, 0,
464              _("Illegal DIR plugin options encountered, %s instance %d "
465                "skipping\n"),
466              plugin_options, instance);
467         continue;
468       }
469 
470       len = strlen(plugin_name);
471 
472       /*
473        * See if this plugin options are for an already instantiated plugin
474        * instance.
475        */
476       if (jcr->plugin_ctx_list) {
477         foreach_alist (ctx, jcr->plugin_ctx_list) {
478           if (ctx->instance == instance && ctx->plugin->file_len == len &&
479               bstrncasecmp(ctx->plugin->file, plugin_name, len)) {
480             break;
481           }
482         }
483 
484         /*
485          * Found a context in the previous loop ?
486          */
487         if (!ctx) {
488           foreach_alist_index (j, plugin, dird_plugin_list) {
489             if (plugin->file_len == len &&
490                 bstrncasecmp(plugin->file, plugin_name, len)) {
491               ctx = instantiate_plugin(jcr, plugin, instance);
492               break;
493             }
494           }
495         }
496 
497         if (ctx) {
498           trigger_plugin_event(jcr, eventType, &event, ctx,
499                                (void*)plugin_options, NULL, NULL, NULL);
500         }
501       }
502     }
503   }
504 }
505 
506 /**
507  * Create a new instance of each plugin for this Job
508  */
NewPlugins(JobControlRecord * jcr)509 void NewPlugins(JobControlRecord* jcr)
510 {
511   int i, num;
512   Plugin* plugin;
513 
514   Dmsg0(debuglevel, "=== enter NewPlugins ===\n");
515   if (!dird_plugin_list) {
516     Dmsg0(debuglevel, "No dir plugin list!\n");
517     return;
518   }
519   if (jcr->IsJobCanceled()) { return; }
520 
521   num = dird_plugin_list->size();
522   Dmsg1(debuglevel, "dir-plugin-list size=%d\n", num);
523   if (num == 0) { return; }
524 
525   jcr->plugin_ctx_list = new alist(10, owned_by_alist);
526   foreach_alist_index (i, plugin, dird_plugin_list) {
527     /*
528      * Start a new instance of each plugin
529      */
530     instantiate_plugin(jcr, plugin, 0);
531   }
532 }
533 
534 /**
535  * Free the plugin instances for this Job
536  */
FreePlugins(JobControlRecord * jcr)537 void FreePlugins(JobControlRecord* jcr)
538 {
539   bpContext* ctx = nullptr;
540 
541   if (!dird_plugin_list || !jcr->plugin_ctx_list) { return; }
542 
543   Dmsg2(debuglevel, "Free instance dir-plugin_ctx_list=%p JobId=%d\n",
544         jcr->plugin_ctx_list, jcr->JobId);
545   foreach_alist (ctx, jcr->plugin_ctx_list) {
546     /*
547      * Free the plugin instance
548      */
549     DirplugFunc(ctx->plugin)->freePlugin(ctx);
550     free(ctx->bContext); /* Free BAREOS private context */
551   }
552 
553   delete jcr->plugin_ctx_list;
554   jcr->plugin_ctx_list = NULL;
555 }
556 
557 /**
558  *
559  * Callbacks from the plugin
560  *
561  */
bareosGetValue(bpContext * ctx,brDirVariable var,void * value)562 static bRC bareosGetValue(bpContext* ctx, brDirVariable var, void* value)
563 {
564   JobControlRecord* jcr = NULL;
565   bRC retval = bRC_OK;
566 
567   if (!value) { return bRC_Error; }
568 
569   switch (var) { /* General variables, no need of ctx */
570     case bDirVarPluginDir:
571       *((char**)value) = me->plugin_directory;
572       Dmsg1(debuglevel, "dir-plugin: return bDirVarPluginDir=%s\n",
573             NPRT(*((char**)value)));
574       break;
575     default:
576       if (!ctx) { return bRC_Error; }
577       jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
578       if (!jcr) { return bRC_Error; }
579       break;
580   }
581 
582   if (jcr) {
583     switch (var) {
584       case bDirVarJobId:
585         *((int*)value) = jcr->JobId;
586         Dmsg1(debuglevel, "dir-plugin: return bDirVarJobId=%d\n", jcr->JobId);
587         break;
588       case bDirVarJobName:
589         *((char**)value) = jcr->Job;
590         Dmsg1(debuglevel, "dir-plugin: return Job name=%s\n",
591               NPRT(*((char**)value)));
592         break;
593       case bDirVarJob:
594         *((char**)value) = jcr->impl->res.job->resource_name_;
595         Dmsg1(debuglevel, "dir-plugin: return bDirVarJob=%s\n",
596               NPRT(*((char**)value)));
597         break;
598       case bDirVarLevel:
599         *((int*)value) = jcr->getJobLevel();
600         Dmsg1(debuglevel, "dir-plugin: return bDirVarLevel=%c\n",
601               jcr->getJobLevel());
602         break;
603       case bDirVarType:
604         *((int*)value) = jcr->getJobType();
605         Dmsg1(debuglevel, "dir-plugin: return bDirVarType=%c\n",
606               jcr->getJobType());
607         break;
608       case bDirVarClient:
609         *((char**)value) = jcr->impl->res.client->resource_name_;
610         Dmsg1(debuglevel, "dir-plugin: return bDirVarClient=%s\n",
611               NPRT(*((char**)value)));
612         break;
613       case bDirVarNumVols: {
614         PoolDbRecord pr;
615 
616         bstrncpy(pr.Name, jcr->impl->res.pool->resource_name_,
617                  sizeof(pr.Name));
618         if (!jcr->db->GetPoolRecord(jcr, &pr)) { retval = bRC_Error; }
619         *((int*)value) = pr.NumVols;
620         Dmsg1(debuglevel, "dir-plugin: return bDirVarNumVols=%d\n", pr.NumVols);
621         break;
622       }
623       case bDirVarPool:
624         *((char**)value) = jcr->impl->res.pool->resource_name_;
625         Dmsg1(debuglevel, "dir-plugin: return bDirVarPool=%s\n",
626               NPRT(*((char**)value)));
627         break;
628       case bDirVarStorage:
629         if (jcr->impl->res.write_storage) {
630           *((char**)value) = jcr->impl->res.write_storage->resource_name_;
631         } else if (jcr->impl->res.read_storage) {
632           *((char**)value) = jcr->impl->res.read_storage->resource_name_;
633         } else {
634           *((char**)value) = NULL;
635           retval = bRC_Error;
636         }
637         Dmsg1(debuglevel, "dir-plugin: return bDirVarStorage=%s\n",
638               NPRT(*((char**)value)));
639         break;
640       case bDirVarWriteStorage:
641         if (jcr->impl->res.write_storage) {
642           *((char**)value) = jcr->impl->res.write_storage->resource_name_;
643         } else {
644           *((char**)value) = NULL;
645           retval = bRC_Error;
646         }
647         Dmsg1(debuglevel, "dir-plugin: return bDirVarWriteStorage=%s\n",
648               NPRT(*((char**)value)));
649         break;
650       case bDirVarReadStorage:
651         if (jcr->impl->res.read_storage) {
652           *((char**)value) = jcr->impl->res.read_storage->resource_name_;
653         } else {
654           *((char**)value) = NULL;
655           retval = bRC_Error;
656         }
657         Dmsg1(debuglevel, "dir-plugin: return bDirVarReadStorage=%s\n",
658               NPRT(*((char**)value)));
659         break;
660       case bDirVarCatalog:
661         *((char**)value) = jcr->impl->res.catalog->resource_name_;
662         Dmsg1(debuglevel, "dir-plugin: return bDirVarCatalog=%s\n",
663               NPRT(*((char**)value)));
664         break;
665       case bDirVarMediaType:
666         if (jcr->impl->res.write_storage) {
667           *((char**)value) = jcr->impl->res.write_storage->media_type;
668         } else if (jcr->impl->res.read_storage) {
669           *((char**)value) = jcr->impl->res.read_storage->media_type;
670         } else {
671           *((char**)value) = NULL;
672           retval = bRC_Error;
673         }
674         Dmsg1(debuglevel, "dir-plugin: return bDirVarMediaType=%s\n",
675               NPRT(*((char**)value)));
676         break;
677       case bDirVarJobStatus:
678         *((int*)value) = jcr->JobStatus;
679         Dmsg1(debuglevel, "dir-plugin: return bDirVarJobStatus=%c\n",
680               jcr->JobStatus);
681         break;
682       case bDirVarPriority:
683         *((int*)value) = jcr->JobPriority;
684         Dmsg1(debuglevel, "dir-plugin: return bDirVarPriority=%d\n",
685               jcr->JobPriority);
686         break;
687       case bDirVarVolumeName:
688         *((char**)value) = jcr->VolumeName;
689         Dmsg1(debuglevel, "dir-plugin: return bDirVarVolumeName=%s\n",
690               NPRT(*((char**)value)));
691         break;
692       case bDirVarCatalogRes:
693         retval = bRC_Error;
694         break;
695       case bDirVarJobErrors:
696         *((int*)value) = jcr->JobErrors;
697         Dmsg1(debuglevel, "dir-plugin: return bDirVarErrors=%d\n",
698               jcr->JobErrors);
699         break;
700       case bDirVarJobFiles:
701         *((int*)value) = jcr->JobFiles;
702         Dmsg1(debuglevel, "dir-plugin: return bDirVarFiles=%d\n",
703               jcr->JobFiles);
704         break;
705       case bDirVarSDJobFiles:
706         *((int*)value) = jcr->impl->SDJobFiles;
707         Dmsg1(debuglevel, "dir-plugin: return bDirVarSDFiles=%d\n",
708               jcr->impl->SDJobFiles);
709         break;
710       case bDirVarSDErrors:
711         *((int*)value) = jcr->impl->SDErrors;
712         Dmsg1(debuglevel, "dir-plugin: return bDirVarSDErrors=%d\n",
713               jcr->impl->SDErrors);
714         break;
715       case bDirVarFDJobStatus:
716         *((int*)value) = jcr->impl->FDJobStatus;
717         Dmsg1(debuglevel, "dir-plugin: return bDirVarFDJobStatus=%c\n",
718               jcr->impl->FDJobStatus);
719         break;
720       case bDirVarSDJobStatus:
721         *((int*)value) = jcr->impl->SDJobStatus;
722         Dmsg1(debuglevel, "dir-plugin: return bDirVarSDJobStatus=%c\n",
723               jcr->impl->SDJobStatus);
724         break;
725       case bDirVarLastRate:
726         *((int*)value) = jcr->LastRate;
727         Dmsg1(debuglevel, "dir-plugin: return bDirVarLastRate=%d\n",
728               jcr->LastRate);
729         break;
730       case bDirVarJobBytes:
731         *((uint64_t*)value) = jcr->JobBytes;
732         Dmsg1(debuglevel, "dir-plugin: return bDirVarJobBytes=%u\n",
733               jcr->JobBytes);
734         break;
735       case bDirVarReadBytes:
736         *((uint64_t*)value) = jcr->ReadBytes;
737         Dmsg1(debuglevel, "dir-plugin: return bDirVarReadBytes=%u\n",
738               jcr->ReadBytes);
739         break;
740       default:
741         break;
742     }
743   }
744 
745   return retval;
746 }
747 
bareosSetValue(bpContext * ctx,bwDirVariable var,void * value)748 static bRC bareosSetValue(bpContext* ctx, bwDirVariable var, void* value)
749 {
750   JobControlRecord* jcr;
751 
752   if (!value || !ctx) { return bRC_Error; }
753 
754   jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
755   if (!jcr) { return bRC_Error; }
756 
757   Dmsg1(debuglevel, "dir-plugin: bareosSetValue var=%d\n", var);
758   switch (var) {
759     case bwDirVarVolumeName:
760       PmStrcpy(jcr->VolumeName, ((char*)value));
761       break;
762     case bwDirVarPriority:
763       jcr->JobPriority = *((int*)value);
764       break;
765     case bwDirVarJobLevel:
766       jcr->setJobLevel(*((int*)value));
767       break;
768     default:
769       break;
770   }
771 
772   return bRC_OK;
773 }
774 
bareosRegisterEvents(bpContext * ctx,int nr_events,...)775 static bRC bareosRegisterEvents(bpContext* ctx, int nr_events, ...)
776 {
777   int i;
778   va_list args;
779   uint32_t event;
780   b_plugin_ctx* b_ctx;
781 
782   if (!ctx) { return bRC_Error; }
783   b_ctx = (b_plugin_ctx*)ctx->bContext;
784   va_start(args, nr_events);
785   for (i = 0; i < nr_events; i++) {
786     event = va_arg(args, uint32_t);
787     Dmsg1(debuglevel, "dir-plugin: Plugin registered event=%u\n", event);
788     SetBit(event, b_ctx->events);
789   }
790   va_end(args);
791 
792   return bRC_OK;
793 }
794 
bareosUnRegisterEvents(bpContext * ctx,int nr_events,...)795 static bRC bareosUnRegisterEvents(bpContext* ctx, int nr_events, ...)
796 {
797   int i;
798   va_list args;
799   uint32_t event;
800   b_plugin_ctx* b_ctx;
801 
802   if (!ctx) { return bRC_Error; }
803   b_ctx = (b_plugin_ctx*)ctx->bContext;
804   va_start(args, nr_events);
805   for (i = 0; i < nr_events; i++) {
806     event = va_arg(args, uint32_t);
807     Dmsg1(debuglevel, "dir-plugin: Plugin unregistered event=%u\n", event);
808     ClearBit(event, b_ctx->events);
809   }
810   va_end(args);
811 
812   return bRC_OK;
813 }
814 
bareosGetInstanceCount(bpContext * ctx,int * ret)815 static bRC bareosGetInstanceCount(bpContext* ctx, int* ret)
816 {
817   int cnt;
818   JobControlRecord *jcr, *njcr;
819   bpContext* nctx;
820   b_plugin_ctx* bctx;
821   bRC retval = bRC_Error;
822 
823   if (!IsCtxGood(ctx, jcr, bctx)) { goto bail_out; }
824 
825   P(mutex);
826 
827   cnt = 0;
828   foreach_jcr (njcr) {
829     if (jcr->plugin_ctx_list) {
830       foreach_alist (nctx, jcr->plugin_ctx_list) {
831         if (nctx->plugin == bctx->plugin) { cnt++; }
832       }
833     }
834   }
835   endeach_jcr(njcr);
836 
837   V(mutex);
838 
839   *ret = cnt;
840   retval = bRC_OK;
841 
842 bail_out:
843   return retval;
844 }
845 
bareosJobMsg(bpContext * ctx,const char * file,int line,int type,utime_t mtime,const char * fmt,...)846 static bRC bareosJobMsg(bpContext* ctx,
847                         const char* file,
848                         int line,
849                         int type,
850                         utime_t mtime,
851                         const char* fmt,
852                         ...)
853 {
854   JobControlRecord* jcr;
855   va_list arg_ptr;
856   PoolMem buffer(PM_MESSAGE);
857 
858   if (ctx) {
859     jcr = ((b_plugin_ctx*)ctx->bContext)->jcr;
860   } else {
861     jcr = NULL;
862   }
863 
864   va_start(arg_ptr, fmt);
865   buffer.Bvsprintf(fmt, arg_ptr);
866   va_end(arg_ptr);
867   Jmsg(jcr, type, mtime, "%s", buffer.c_str());
868 
869   return bRC_OK;
870 }
871 
bareosDebugMsg(bpContext * ctx,const char * file,int line,int level,const char * fmt,...)872 static bRC bareosDebugMsg(bpContext* ctx,
873                           const char* file,
874                           int line,
875                           int level,
876                           const char* fmt,
877                           ...)
878 {
879   va_list arg_ptr;
880   PoolMem buffer(PM_MESSAGE);
881 
882   va_start(arg_ptr, fmt);
883   buffer.Bvsprintf(fmt, arg_ptr);
884   va_end(arg_ptr);
885   d_msg(file, line, level, "%s", buffer.c_str());
886 
887   return bRC_OK;
888 }
889 } /* namespace directordaemon */
890