1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2006-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2016 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 and included
11    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 /*
25  * Contributed in 2012 by Inteos sp. z o.o.
26  */
27 
28 /**
29  * Utility tool display various information about Bareos plugin,
30  * including but not limited to:
31  * - Name and Author of the plugin
32  * - Plugin License
33  * - Description
34  * - API version
35  * - Enabled functions, etc.
36  */
37 #include "include/bareos.h"
38 #include "filed/fd_plugins.h"
39 #include "dird/dir_plugins.h"
40 #include "stored/sd_plugins.h"
41 #include "assert_macro.h"
42 #ifndef __WIN32__
43 #include <dlfcn.h>
44 #endif
45 #ifndef PATH_MAX
46 #define PATH_MAX 4096
47 #endif
48 
49 extern "C" {
50 typedef int (*loadPlugin)(void* binfo,
51                           void* bfuncs,
52                           void** pinfo,
53                           void** pfuncs);
54 typedef int (*unloadPlugin)(void);
55 }
56 #define DEFAULT_API_VERSION 1
57 
58 enum plugintype
59 {
60   DIRPLUGIN,
61   FDPLUGIN,
62   SDPLUGIN,
63   ERRORPLUGIN
64 };
65 
66 /*
67  * pDirFuncs
68  * pFuncs
69  * psdFuncs
70  */
71 typedef union _plugfuncs plugfuncs;
72 union _plugfuncs {
73   directordaemon::pDirFuncs pdirfuncs;
74   filedaemon::pFuncs pfdfuncs;
75   storagedaemon::psdFuncs psdfuncs;
76 };
77 
78 /*
79  * bDirFuncs
80  * bFuncs
81  * bsdFuncs
82  */
83 typedef struct _bareosfuncs bareosfuncs;
84 struct _bareosfuncs {
85   uint32_t size;
86   uint32_t version;
87   int (*registerBareosEvents)(void* ctx, ...);
88   int (*getBareosValue)(void* ctx, int var, void* value);
89   int (*setBareosValue)(void* ctx, int var, void* value);
90   int (*JobMessage)(void* ctx,
91                     const char* file,
92                     int line,
93                     int type,
94                     int64_t mtime,
95                     const char* fmt,
96                     ...);
97   int (*DebugMessage)(void* ctx,
98                       const char* file,
99                       int line,
100                       int level,
101                       const char* fmt,
102                       ...);
103   void* (*bareosMalloc)(void* ctx, const char* file, int line, size_t size);
104   void (*bareosFree)(void* ctx, const char* file, int line, void* mem);
105 };
106 
107 /*
108  * bDirInfo
109  * bInfo
110  * bsdInfo
111  */
112 typedef union _bareosinfos bareosinfos;
113 union _bareosinfos {
114   directordaemon::bDirInfo bdirinfo;
115   filedaemon::bInfo bfdinfo;
116   storagedaemon::bsdInfo bsdinfo;
117 };
118 
119 typedef struct _progdata progdata;
120 struct _progdata {
121   bool verbose;
122   bool listinfo;
123   bool listfunc;
124   char* pluginfile;
125   void* pluginhandle;
126   int bapiversion;
127   int bplugtype;
128   gen_pluginInfo* pinfo;
129   plugfuncs* pfuncs;
130 };
131 
132 /* memory allocation/deallocation */
133 #define MALLOC(size) (char*)malloc(size);
134 
135 #define ASSERT_MEMORY(m)                         \
136   if (m == NULL) {                               \
137     printf("Error: memory allocation error!\n"); \
138     exit(10);                                    \
139   }
140 
141 #define FREE(ptr)    \
142   if (ptr != NULL) { \
143     free(ptr);      \
144     ptr = NULL;      \
145   }
146 
registerBareosEvents(void * ctx,...)147 int registerBareosEvents(void* ctx, ...) { return 0; };
148 
getBareosValue(void * ctx,int var,void * value)149 int getBareosValue(void* ctx, int var, void* value) { return 0; };
150 
setBareosValue(void * ctx,int var,void * value)151 int setBareosValue(void* ctx, int var, void* value) { return 0; };
152 
DebugMessage(void * ctx,const char * file,int line,int level,const char * fmt,...)153 int DebugMessage(void* ctx,
154                  const char* file,
155                  int line,
156                  int level,
157                  const char* fmt,
158                  ...)
159 {
160 #ifdef DEBUGMSG
161   printf("DG: %s:%d %s\n", file, line, fmt);
162 #endif
163   return 0;
164 };
165 
JobMessage(void * ctx,const char * file,int line,int type,int64_t mtime,const char * fmt,...)166 int JobMessage(void* ctx,
167                const char* file,
168                int line,
169                int type,
170                int64_t mtime,
171                const char* fmt,
172                ...)
173 {
174 #ifdef DEBUGMSG
175   printf("JM: %s:%d <%d> %s\n", file, line, type, fmt);
176 #endif
177   return 0;
178 };
179 
bareosMalloc(void * ctx,const char * file,int line,size_t size)180 void* bareosMalloc(void* ctx, const char* file, int line, size_t size)
181 {
182   return MALLOC(size);
183 };
184 
bareosFree(void * ctx,const char * file,int line,void * mem)185 void bareosFree(void* ctx, const char* file, int line, void* mem)
186 {
187   FREE(mem);
188 };
189 
190 /*
191  * displays a short help
192  */
PrintHelp(int argc,char * argv[])193 void PrintHelp(int argc, char* argv[])
194 {
195   printf(
196       "\n"
197       "Usage: bpluginfo [options] <plugin_file.so>\n"
198       "       -v          verbose\n"
199       "       -i          list plugin header information only (default)\n"
200       "       -f          list plugin functions information only\n"
201       "       -a <api>    bareos api version (default %d)\n"
202       "       -h          help screen\n"
203       "\n",
204       DEFAULT_API_VERSION);
205 }
206 
207 /* allocates and resets a main program data variable */
allocpdata(void)208 progdata* allocpdata(void)
209 {
210   progdata* pdata;
211 
212   pdata = (progdata*)malloc(sizeof(progdata));
213   ASSERT_MEMORY(pdata);
214   memset(pdata, 0, sizeof(progdata));
215 
216   return pdata;
217 }
218 
219 /* releases all allocated program data resources */
Freepdata(progdata * pdata)220 void Freepdata(progdata* pdata)
221 {
222   if (pdata->pluginfile) { FREE(pdata->pluginfile); }
223   FREE(pdata);
224 }
225 
226 /*
227  * parse execution arguments and fills required pdata structure fields
228  *
229  * input:
230  *    pdata - pointer to program data structure
231  *    argc, argv - execution envinroment variables
232  * output:
233  *    pdata - required structure fields
234  *
235  * supported options:
236  * -v    verbose flag
237  * -i    list plugin header info only (default)
238  * -f    list implemented functions only
239  * -a    bareos api version (default 1)
240  * -h    help screen
241  */
ParseArgs(progdata * pdata,int argc,char * argv[])242 void ParseArgs(progdata* pdata, int argc, char* argv[])
243 {
244   int ch;
245   char* dirtmp;
246   char* progdir;
247 
248   while ((ch = getopt(argc, argv, "a:fiv")) != -1) {
249     switch (ch) {
250       case 'a':
251         pdata->bapiversion = atoi(optarg);
252         break;
253 
254       case 'f':
255         pdata->listfunc = true;
256         break;
257 
258       case 'i':
259         pdata->listinfo = true;
260         break;
261 
262       case 'v':
263         pdata->verbose = true;
264         break;
265 
266       case '?':
267       default:
268         PrintHelp(argc, argv);
269         exit(0);
270     }
271   }
272   argc -= optind;
273   argv += optind;
274 
275   if (argc < 1) {
276     PrintHelp(argc, argv);
277     exit(0);
278   }
279 
280   if (!pdata->pluginfile) {
281     if (argv[0][0] != '/') {
282       dirtmp = MALLOC(PATH_MAX);
283       ASSERT_MEMORY(dirtmp);
284       progdir = MALLOC(PATH_MAX);
285       ASSERT_MEMORY(progdir);
286       dirtmp = getcwd(dirtmp, PATH_MAX);
287 
288       strcat(dirtmp, "/");
289       strcat(dirtmp, argv[0]);
290 
291       if (realpath(dirtmp, progdir) == NULL) {
292         /*
293          * Error in resolving path
294          */
295         FREE(progdir);
296         progdir = strdup(argv[0]);
297       }
298       pdata->pluginfile = strdup(progdir);
299       FREE(dirtmp);
300       FREE(progdir);
301     } else {
302       pdata->pluginfile = strdup(argv[0]);
303     }
304   }
305 }
306 
307 /*
308  * checks a plugin type based on a plugin magic string
309  *
310  * input:
311  *    pdata - program data with plugin info structure
312  * output:
313  *    int - enum plugintype
314  */
Getplugintype(progdata * pdata)315 int Getplugintype(progdata* pdata)
316 {
317   ASSERT_NVAL_RET_V(pdata, ERRORPLUGIN);
318 
319   gen_pluginInfo* pinfo = pdata->pinfo;
320 
321   ASSERT_NVAL_RET_V(pinfo, ERRORPLUGIN);
322 
323   if (pinfo->plugin_magic && bstrcmp(pinfo->plugin_magic, DIR_PLUGIN_MAGIC)) {
324     return DIRPLUGIN;
325   } else {
326     if (pinfo->plugin_magic && bstrcmp(pinfo->plugin_magic, FD_PLUGIN_MAGIC)) {
327       return FDPLUGIN;
328     } else {
329       if (pinfo->plugin_magic &&
330           bstrcmp(pinfo->plugin_magic, SD_PLUGIN_MAGIC)) {
331         return SDPLUGIN;
332       } else {
333         return ERRORPLUGIN;
334       }
335     }
336   }
337 }
338 
339 /*
340  * prints any available information about a plugin
341  *
342  * input:
343  *    pdata - program data with plugin info structure
344  * output:
345  *    printed info
346  */
DumpPluginfo(progdata * pdata)347 void DumpPluginfo(progdata* pdata)
348 {
349   ASSERT_NVAL_RET(pdata);
350 
351   gen_pluginInfo* pinfo = pdata->pinfo;
352 
353   ASSERT_NVAL_RET(pinfo);
354 
355   plugfuncs* pfuncs = pdata->pfuncs;
356 
357   ASSERT_NVAL_RET(pfuncs);
358 
359   switch (pdata->bplugtype) {
360     case DIRPLUGIN:
361       printf("\nPlugin type:\t\tBareos Director plugin\n");
362       break;
363     case FDPLUGIN:
364       printf("\nPlugin type:\t\tBareos File Daemon plugin\n");
365       break;
366     case SDPLUGIN:
367       printf("\nPlugin type:\t\tBareos Storage plugin\n");
368       break;
369     default:
370       printf("\nUnknown plugin type or other Error\n\n");
371       return;
372   }
373 
374   if (pdata->verbose) {
375     printf("Plugin magic:\t\t%s\n", NPRT(pinfo->plugin_magic));
376   }
377   printf("Plugin version:\t\t%s\n", pinfo->plugin_version);
378   printf("Plugin release date:\t%s\n", NPRT(pinfo->plugin_date));
379   printf("Plugin author:\t\t%s\n", NPRT(pinfo->plugin_author));
380   printf("Plugin licence:\t\t%s\n", NPRT(pinfo->plugin_license));
381   printf("Plugin description:\t%s\n", NPRT(pinfo->plugin_description));
382   printf("Plugin API version:\t%d\n", pinfo->version);
383   if (pinfo->plugin_usage) {
384     printf("Plugin usage:\n%s\n", pinfo->plugin_usage);
385   }
386 }
387 
388 /*
389  * prints any available information about plugin' functions
390  *
391  * input:
392  *    pdata - program data with plugin info structure
393  * output:
394  *    printed info
395  */
DumpPlugfuncs(progdata * pdata)396 void DumpPlugfuncs(progdata* pdata)
397 {
398   ASSERT_NVAL_RET(pdata);
399 
400   plugfuncs* pfuncs = pdata->pfuncs;
401 
402   ASSERT_NVAL_RET(pfuncs);
403 
404   printf("\nPlugin functions:\n");
405 
406   switch (pdata->bplugtype) {
407     case DIRPLUGIN:
408       if (pdata->verbose) {
409         if (pfuncs->pdirfuncs.newPlugin) { printf(" newPlugin()\n"); }
410         if (pfuncs->pdirfuncs.freePlugin) { printf(" freePlugin()\n"); }
411       }
412       if (pfuncs->pdirfuncs.getPluginValue) { printf(" getPluginValue()\n"); }
413       if (pfuncs->pdirfuncs.setPluginValue) { printf(" setPluginValue()\n"); }
414       if (pfuncs->pdirfuncs.handlePluginEvent) {
415         printf(" handlePluginEvent()\n");
416       }
417       break;
418     case FDPLUGIN:
419       if (pdata->verbose) {
420         if (pfuncs->pfdfuncs.newPlugin) { printf(" newPlugin()\n"); }
421         if (pfuncs->pfdfuncs.freePlugin) { printf(" freePlugin()\n"); }
422       }
423       if (pfuncs->pfdfuncs.getPluginValue) { printf(" getPluginValue()\n"); }
424       if (pfuncs->pfdfuncs.setPluginValue) { printf(" setPluginValue()\n"); }
425       if (pfuncs->pfdfuncs.handlePluginEvent) {
426         printf(" handlePluginEvent()\n");
427       }
428       if (pfuncs->pfdfuncs.startBackupFile) { printf(" startBackupFile()\n"); }
429       if (pfuncs->pfdfuncs.endBackupFile) { printf(" endBackupFile()\n"); }
430       if (pfuncs->pfdfuncs.startRestoreFile) {
431         printf(" startRestoreFile()\n");
432       }
433       if (pfuncs->pfdfuncs.endRestoreFile) { printf(" endRestoreFile()\n"); }
434       if (pfuncs->pfdfuncs.pluginIO) { printf(" pluginIO()\n"); }
435       if (pfuncs->pfdfuncs.createFile) { printf(" createFile()\n"); }
436       if (pfuncs->pfdfuncs.setFileAttributes) {
437         printf(" setFileAttributes()\n");
438       }
439       if (pfuncs->pfdfuncs.checkFile) { printf(" checkFile()\n"); }
440       break;
441     case SDPLUGIN:
442       if (pdata->verbose) {
443         if (pfuncs->psdfuncs.newPlugin) { printf(" newPlugin()\n"); }
444         if (pfuncs->psdfuncs.freePlugin) { printf(" freePlugin()\n"); }
445       }
446       if (pfuncs->psdfuncs.getPluginValue) { printf(" getPluginValue()\n"); }
447       if (pfuncs->psdfuncs.setPluginValue) { printf(" setPluginValue()\n"); }
448       if (pfuncs->psdfuncs.handlePluginEvent) {
449         printf(" handlePluginEvent()\n");
450       }
451       break;
452     default:
453       printf("\nUnknown plugin type or other Error\n\n");
454   }
455 }
456 
457 /*
458  * input parameters:
459  *    argv[0] [options] <plugin_filename.so>
460  *
461  * exit codes:
462  *    0 - success
463  *    1 - cannot load a plugin
464  *    2 - cannot find a loadPlugin function
465  *    3 - cannot find an unloadPlugin function
466  *    10 - not enough memory
467  */
main(int argc,char * argv[])468 int main(int argc, char* argv[])
469 {
470   progdata* pdata;
471   loadPlugin loadplugfunc;
472   unloadPlugin unloadplugfunc;
473   bareosfuncs bfuncs = {
474       sizeof(bfuncs), 1,          registerBareosEvents, getBareosValue,
475       setBareosValue, JobMessage, DebugMessage,         bareosMalloc,
476       bareosFree,
477   };
478   bareosinfos binfos;
479 
480   pdata = allocpdata();
481   ParseArgs(pdata, argc, argv);
482 
483   binfos.bfdinfo.size = sizeof(binfos);
484   binfos.bfdinfo.version = DEFAULT_API_VERSION;
485 
486   pdata->pluginhandle = dlopen(pdata->pluginfile, RTLD_LAZY);
487   if (pdata->pluginhandle == NULL) {
488     printf("\nCannot load a plugin: %s\n\n", dlerror());
489     Freepdata(pdata);
490     exit(1);
491   }
492 
493   loadplugfunc = (loadPlugin)dlsym(pdata->pluginhandle, "loadPlugin");
494   if (loadplugfunc == NULL) {
495     printf("\nCannot find loadPlugin function: %s\n", dlerror());
496     printf("\nWhether the file is a really Bareos plugin?\n\n");
497     Freepdata(pdata);
498     exit(2);
499   }
500 
501   unloadplugfunc = (unloadPlugin)dlsym(pdata->pluginhandle, "unloadPlugin");
502   if (unloadplugfunc == NULL) {
503     printf("\nCannot find unloadPlugin function: %s\n", dlerror());
504     printf("\nWhether the file is a really Bareos plugin?\n\n");
505     Freepdata(pdata);
506     exit(3);
507   }
508 
509   if (pdata->bapiversion > 0) { binfos.bdirinfo.version = pdata->bapiversion; }
510 
511   loadplugfunc(&binfos, &bfuncs, (void**)&pdata->pinfo, (void**)&pdata->pfuncs);
512 
513   pdata->bplugtype = Getplugintype(pdata);
514 
515   if (!pdata->listfunc) { DumpPluginfo(pdata); }
516   if ((!pdata->listinfo && pdata->listfunc) || pdata->verbose) {
517     DumpPlugfuncs(pdata);
518   }
519   printf("\n");
520 
521   unloadplugfunc();
522 
523   dlclose(pdata->pluginhandle);
524 
525   Freepdata(pdata);
526 
527   return 0;
528 }
529