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