]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/tools/bpluginfo.c
Remove installation of manpage for bplugininfo
[bacula/bacula] / bacula / src / tools / bpluginfo.c
1 /*
2  * Contributed in 2012 by Inteos sp. z o.o.
3  *
4  * Utility tool display various information about Bacula plugin,
5  * including but not limited to:
6  * - Name and Author of the plugin
7  * - Plugin License
8  * - Description
9  * - API version
10  * - Enabled functions, etc.
11  */
12 /*
13    Bacula® - The Network Backup Solution
14
15    Copyright (C) 2006-2014 Free Software Foundation Europe e.V.
16
17    The main author of Bacula is Kern Sibbald, with contributions from many
18    others, a complete list can be found in the file AUTHORS.
19
20    You may use this file and others of this release according to the
21    license defined in the LICENSE file, which includes the Affero General
22    Public License, v3.0 ("AGPLv3") and some additional permissions and
23    terms pursuant to its AGPLv3 Section 7.
24
25    Bacula® is a registered trademark of Kern Sibbald.
26 */
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdint.h>
34 #ifndef __WIN32__
35 #include <dlfcn.h>
36 #endif
37 #include "bacula.h"
38 #include "../filed/fd_plugins.h"
39 #include "../dird/dir_plugins.h"
40 // I can't include sd_plugins.h here ...
41 #include "../stored/stored.h"
42 #include "assert_macro.h"
43
44 extern "C" {
45    typedef int (*loadPlugin) (void *binfo, void *bfuncs, void **pinfo,
46                void **pfuncs);
47    typedef int (*unloadPlugin) (void);
48 }
49 #define DEFAULT_API_VERSION   1
50 enum plugintype {
51    DIRPLUGIN,
52    FDPLUGIN,
53    SDPLUGIN,
54    ERRORPLUGIN,
55 };
56
57 /*
58  * pDirInfo
59  * pInfo
60  * psdInfo
61  */
62 typedef union _pluginfo pluginfo;
63 union _pluginfo {
64    pDirInfo pdirinfo;
65    pInfo pfdinfo;
66    psdInfo psdinfo;
67 };
68
69 /*
70  * pDirFuncs
71  * pFuncs
72  * psdFuncs
73  */
74 typedef union _plugfuncs plugfuncs;
75 union _plugfuncs {
76    pDirFuncs pdirfuncs;
77    pFuncs pfdfuncs;
78    psdFuncs psdfuncs;
79 };
80
81 /*
82  * bDirFuncs
83  * bFuncs
84  * bsdFuncs
85  */
86 /*
87  * TODO: change to union
88  *
89 typedef union _baculafuncs baculafuncs;
90 union _baculafuncs {
91    bDirFuncs bdirfuncs;
92    bFuncs bfdfuncs;
93    bsdFuncs bsdfuncs;
94 };
95 */
96 typedef struct _baculafuncs baculafuncs;
97 struct _baculafuncs {
98    uint32_t size;
99    uint32_t version;
100    int (*registerBaculaEvents) (void *ctx, ...);
101    int (*getBaculaValue) (void *ctx, int var, void *value);
102    int (*setBaculaValue) (void *ctx, int var, void *value);
103    int (*JobMessage) (void *ctx, const char *file, int line, int type, int64_t mtime,
104             const char *fmt, ...);
105    int (*DebugMessage) (void *ctx, const char *file, int line, int level,
106          const char *fmt, ...);
107    void *(*baculaMalloc) (void *ctx, const char *file, int line, size_t size);
108    void (*baculaFree) (void *ctx, const char *file, int line, void *mem);
109 };
110
111 /*
112  * bDirInfo
113  * bInfo
114  * bsdInfo
115  */
116 typedef union _baculainfos baculainfos;
117 union _baculainfos {
118    bDirInfo bdirinfo;
119    bInfo bfdinfo;
120    bsdInfo bsdinfo;
121 };
122
123 /*
124 typedef struct _baculainfos baculainfos;
125 struct _baculainfos {
126    uint32_t size;
127    uint32_t version;
128 };
129 */
130
131 typedef struct _progdata progdata;
132 struct _progdata {
133    int verbose;
134    int listinfo;
135    int listfunc;
136    char *pluginfile;
137    void *pluginhandle;
138    int bapiversion;
139    int bplugtype;
140    pluginfo *pinfo;
141    plugfuncs *pfuncs;
142 };
143
144 /* memory allocation/deallocation */
145 #define MALLOC(size) \
146    (char *) bmalloc ( size );
147
148 #define ASSERT_MEMORY(m) \
149    if ( m == NULL ){ \
150       printf ( "Error: memory allocation error!\n" ); \
151       exit (10); \
152    }
153
154 #define FREE(ptr) \
155    if ( ptr != NULL ){ \
156       bfree ( ptr ); \
157       ptr = NULL; \
158    }
159
160 int registerBaculaEvents(void *ctx, ...)
161 {
162    return 0;
163 };
164
165 int getBaculaValue(void *ctx, int var, void *value)
166 {
167    return 0;
168 };
169
170 int setBaculaValue(void *ctx, int var, void *value)
171 {
172    return 0;
173 };
174
175 int DebugMessage(void *ctx, const char *file, int line, int level, const char *fmt, ...)
176 {
177 #ifdef DEBUGMSG
178    printf("DG: %s:%d %s\n", file, line, fmt);
179 #endif
180    return 0;
181 };
182
183 int JobMessage(void *ctx, const char *file, int line, int type, int64_t mtime,
184           const char *fmt, ...)
185 {
186 #ifdef DEBUGMSG
187    printf("JM: %s:%d <%d> %s\n", file, line, type, fmt);
188 #endif
189    return 0;
190 };
191
192 void *baculaMalloc(void *ctx, const char *file, int line, size_t size)
193 {
194    return MALLOC(size);
195 };
196
197 void baculaFree(void *ctx, const char *file, int line, void *mem)
198 {
199    FREE(mem);
200 };
201
202 /*
203  * displays a short help
204  */
205 void print_help(int argc, char *argv[])
206 {
207
208    printf("\n"
209      "Usage: bpluginfo [options] <plugin_file.so>\n"
210      "       -v          verbose\n"
211      "       -i          list plugin header information only (default)\n"
212      "       -f          list plugin functions information only\n"
213      "       -a <api>    bacula api version (default %d)\n"
214      "       -h          help screen\n" "\n", DEFAULT_API_VERSION);
215 }
216
217 /* allocates and resets a main program data variable */
218 progdata *allocpdata(void)
219 {
220
221    progdata *pdata;
222
223    pdata = (progdata *) bmalloc(sizeof(progdata));
224    ASSERT_MEMORY(pdata);
225    memset(pdata, 0, sizeof(progdata));
226
227    return pdata;
228 }
229
230 /* releases all allocated program data resources */
231 void freepdata(progdata * pdata)
232 {
233
234    if (pdata->pluginfile) {
235       FREE(pdata->pluginfile);
236    }
237    FREE(pdata);
238 }
239
240 /*
241  * parse execution arguments and fills required pdata structure fields
242  *
243  * input:
244  *    pdata - pointer to program data structure
245  *    argc, argv - execution envinroment variables
246  * output:
247  *    pdata - required structure fields
248  *
249  * supported options:
250  * -v    verbose flag
251  * -i    list plugin header info only (default)
252  * -f    list implemented functions only
253  * -a    bacula api version (default 1)
254  * -h    help screen
255  */
256 void parse_args(progdata * pdata, int argc, char *argv[])
257 {
258
259    int i;
260    char *dirtmp;
261    char *progdir;
262    int api;
263    int s;
264
265    if (argc < 2) {
266       /* TODO - add a real help screen */
267       printf("\nNot enough parameters!\n");
268       print_help(argc, argv);
269       exit(1);
270    }
271
272    if (argc > 5) {
273       /* TODO - add a real help screen */
274       printf("\nToo many parameters!\n");
275       print_help(argc, argv);
276       exit(1);
277    }
278
279    for (i = 1; i < argc; i++) {
280       if (strcmp(argv[i], "-h") == 0) {
281          /* help screen */
282          print_help(argc, argv);
283          exit(0);
284       }
285       if (strcmp(argv[i], "-v") == 0) {
286           /* verbose option */
287           pdata->verbose = 1;
288           continue;
289       }
290       if (strcmp(argv[i], "-f") == 0) {
291          /* functions list */
292          pdata->listfunc = 1;
293          continue;
294       }
295       if (strcmp(argv[i], "-i") == 0) {
296          /* header list */
297          pdata->listinfo = 1;
298          continue;
299       }
300       if (strcmp(argv[i], "-a") == 0) {
301          /* bacula api version */
302          if (i < argc - 1) {
303             s = sscanf(argv[i + 1], "%d", &api);
304             if (s == 1) {
305                pdata->bapiversion = api;
306                i++;
307                continue;
308             }
309          }
310          printf("\nAPI version number required!\n");
311          print_help(argc, argv);
312          exit(1);
313       }
314       if (!pdata->pluginfile) {
315           if (argv[i][0] != '/') {
316              dirtmp = MALLOC(PATH_MAX);
317              ASSERT_MEMORY(dirtmp);
318              progdir = MALLOC(PATH_MAX);
319              ASSERT_MEMORY(progdir);
320              dirtmp = getcwd(dirtmp, PATH_MAX);
321
322              strcat(dirtmp, "/");
323              strcat(dirtmp, argv[i]);
324
325              if (realpath(dirtmp, progdir) == NULL) {
326                 /* error in resolving path */
327                 FREE(progdir);
328                 progdir = bstrdup(argv[i]);
329              }
330              pdata->pluginfile = bstrdup(progdir);
331              FREE(dirtmp);
332              FREE(progdir);
333           } else {
334              pdata->pluginfile = bstrdup(argv[i]);
335           }
336     continue;
337       }
338    }
339 }
340
341 /*
342  * checks a plugin type based on a plugin magic string
343  *
344  * input:
345  *    pdata - program data with plugin info structure
346  * output:
347  *    int - enum plugintype
348  */
349 int getplugintype(progdata * pdata)
350 {
351
352    ASSERT_NVAL_RET_V(pdata, ERRORPLUGIN);
353
354    pluginfo *pinfo = pdata->pinfo;
355
356    ASSERT_NVAL_RET_V(pinfo, ERRORPLUGIN);
357
358    if (pinfo->pdirinfo.plugin_magic &&
359        strcmp(pinfo->pdirinfo.plugin_magic, DIR_PLUGIN_MAGIC) == 0) {
360       return DIRPLUGIN;
361    } else
362       if (pinfo->pfdinfo.plugin_magic &&
363      strcmp(pinfo->pfdinfo.plugin_magic, FD_PLUGIN_MAGIC) == 0) {
364       return FDPLUGIN;
365    } else
366       if (pinfo->psdinfo.plugin_magic &&
367      strcmp(pinfo->psdinfo.plugin_magic, SD_PLUGIN_MAGIC) == 0) {
368       return SDPLUGIN;
369    } else {
370       return ERRORPLUGIN;
371    }
372 }
373
374 /*
375  * prints any available information about a plugin
376  *
377  * input:
378  *    pdata - program data with plugin info structure
379  * output:
380  *    printed info
381  */
382 void dump_pluginfo(progdata * pdata)
383 {
384
385    ASSERT_NVAL_RET(pdata);
386
387    pluginfo *pinfo = pdata->pinfo;
388
389    ASSERT_NVAL_RET(pinfo);
390
391    plugfuncs *pfuncs = pdata->pfuncs;
392
393    ASSERT_NVAL_RET(pfuncs);
394
395    switch (pdata->bplugtype) {
396    case DIRPLUGIN:
397       printf("\nPlugin type:\t\tBacula Director plugin\n");
398       if (pdata->verbose) {
399          printf("Plugin magic:\t\t%s\n", NPRT(pinfo->pdirinfo.plugin_magic));
400       }
401       printf("Plugin version:\t\t%s\n", pinfo->pdirinfo.plugin_version);
402       printf("Plugin release date:\t%s\n", NPRT(pinfo->pdirinfo.plugin_date));
403       printf("Plugin author:\t\t%s\n", NPRT(pinfo->pdirinfo.plugin_author));
404       printf("Plugin licence:\t\t%s\n", NPRT(pinfo->pdirinfo.plugin_license));
405       printf("Plugin description:\t%s\n", NPRT(pinfo->pdirinfo.plugin_description));
406       printf("Plugin API version:\t%d\n", pinfo->pdirinfo.version);
407       break;
408    case FDPLUGIN:
409       printf("\nPlugin type:\t\tFile Daemon plugin\n");
410       if (pdata->verbose) {
411          printf("Plugin magic:\t\t%s\n", NPRT(pinfo->pfdinfo.plugin_magic));
412       }
413       printf("Plugin version:\t\t%s\n", pinfo->pfdinfo.plugin_version);
414       printf("Plugin release date:\t%s\n", NPRT(pinfo->pfdinfo.plugin_date));
415       printf("Plugin author:\t\t%s\n", NPRT(pinfo->pfdinfo.plugin_author));
416       printf("Plugin licence:\t\t%s\n", NPRT(pinfo->pfdinfo.plugin_license));
417       printf("Plugin description:\t%s\n", NPRT(pinfo->pfdinfo.plugin_description));
418       printf("Plugin API version:\t%d\n", pinfo->pfdinfo.version);
419       break;
420    case SDPLUGIN:
421       printf("\nPlugin type:\t\tBacula Storage plugin\n");
422       if (pdata->verbose) {
423          printf("Plugin magic:\t\t%s\n", NPRT(pinfo->psdinfo.plugin_magic));
424       }
425       printf("Plugin version:\t\t%s\n", pinfo->psdinfo.plugin_version);
426       printf("Plugin release date:\t%s\n", NPRT(pinfo->psdinfo.plugin_date));
427       printf("Plugin author:\t\t%s\n", NPRT(pinfo->psdinfo.plugin_author));
428       printf("Plugin licence:\t\t%s\n", NPRT(pinfo->psdinfo.plugin_license));
429       printf("Plugin description:\t%s\n", NPRT(pinfo->psdinfo.plugin_description));
430       printf("Plugin API version:\t%d\n", pinfo->psdinfo.version);
431       break;
432    default:
433       printf("\nUnknown plugin type or other Error\n\n");
434    }
435 }
436
437 /*
438  * prints any available information about plugin' functions
439  *
440  * input:
441  *    pdata - program data with plugin info structure
442  * output:
443  *    printed info
444  */
445 void dump_plugfuncs(progdata * pdata)
446 {
447
448    ASSERT_NVAL_RET(pdata);
449
450    plugfuncs *pfuncs = pdata->pfuncs;
451
452    ASSERT_NVAL_RET(pfuncs);
453
454    printf("\nPlugin functions:\n");
455
456    switch (pdata->bplugtype) {
457    case DIRPLUGIN:
458       if (pdata->verbose) {
459           if (pfuncs->pdirfuncs.newPlugin) {
460              printf(" newPlugin()\n");
461           }
462           if (pfuncs->pdirfuncs.freePlugin) {
463              printf(" freePlugin()\n");
464           }
465       }
466       if (pfuncs->pdirfuncs.getPluginValue) {
467          printf(" getPluginValue()\n");
468       }
469       if (pfuncs->pdirfuncs.setPluginValue) {
470          printf(" setPluginValue()\n");
471       }
472       if (pfuncs->pdirfuncs.handlePluginEvent) {
473          printf(" handlePluginEvent()\n");
474       }
475       break;
476    case FDPLUGIN:
477       if (pdata->verbose) {
478           if (pfuncs->pfdfuncs.newPlugin) {
479              printf(" newPlugin()\n");
480           }
481           if (pfuncs->pfdfuncs.freePlugin) {
482              printf(" freePlugin()\n");
483           }
484       }
485       if (pfuncs->pfdfuncs.getPluginValue) {
486          printf(" getPluginValue()\n");
487       }
488       if (pfuncs->pfdfuncs.setPluginValue) {
489          printf(" setPluginValue()\n");
490       }
491       if (pfuncs->pfdfuncs.handlePluginEvent) {
492          printf(" handlePluginEvent()\n");
493       }
494       if (pfuncs->pfdfuncs.startBackupFile) {
495          printf(" startBackupFile()\n");
496       }
497       if (pfuncs->pfdfuncs.endBackupFile) {
498          printf(" endBackupFile()\n");
499       }
500       if (pfuncs->pfdfuncs.startRestoreFile) {
501          printf(" startRestoreFile()\n");
502       }
503       if (pfuncs->pfdfuncs.endRestoreFile) {
504          printf(" endRestoreFile()\n");
505       }
506       if (pfuncs->pfdfuncs.pluginIO) {
507          printf(" pluginIO()\n");
508       }
509       if (pfuncs->pfdfuncs.createFile) {
510          printf(" createFile()\n");
511       }
512       if (pfuncs->pfdfuncs.setFileAttributes) {
513          printf(" setFileAttributes()\n");
514       }
515       if (pfuncs->pfdfuncs.checkFile) {
516          printf(" checkFile()\n");
517       }
518       break;
519    case SDPLUGIN:
520       if (pdata->verbose) {
521           if (pfuncs->psdfuncs.newPlugin) {
522              printf(" newPlugin()\n");
523           }
524           if (pfuncs->psdfuncs.freePlugin) {
525              printf(" freePlugin()\n");
526           }
527       }
528       if (pfuncs->psdfuncs.getPluginValue) {
529          printf(" getPluginValue()\n");
530       }
531       if (pfuncs->psdfuncs.setPluginValue) {
532          printf(" setPluginValue()\n");
533       }
534       if (pfuncs->psdfuncs.handlePluginEvent) {
535          printf(" handlePluginEvent()\n");
536       }
537       break;
538    default:
539       printf("\nUnknown plugin type or other Error\n\n");
540    }
541 }
542
543 /*
544  * input parameters:
545  *    argv[0] [options] <plugin_filename.so>
546  *
547  * exit codes:
548  *    0 - success
549  *    1 - cannot load a plugin
550  *    2 - cannot find a loadPlugin function
551  *    3 - cannot find an unloadPlugin function
552  *    10 - not enough memory
553  */
554 int main(int argc, char *argv[])
555 {
556
557    progdata *pdata;
558    loadPlugin loadplugfunc;
559    unloadPlugin unloadplugfunc;
560    baculafuncs bfuncs = {
561       sizeof(bfuncs),
562       1,
563       registerBaculaEvents,
564       getBaculaValue,
565       setBaculaValue,
566       JobMessage,
567       DebugMessage,
568       baculaMalloc,
569       baculaFree,
570    };
571    baculainfos binfos;
572
573    pdata = allocpdata();
574    parse_args(pdata, argc, argv);
575
576    binfos.bfdinfo.size = sizeof(binfos);
577    binfos.bfdinfo.version = DEFAULT_API_VERSION;
578
579    pdata->pluginhandle = dlopen(pdata->pluginfile, RTLD_LAZY);
580    if (pdata->pluginhandle == NULL) {
581       printf("\nCannot load a plugin: %s\n\n", dlerror());
582       freepdata(pdata);
583       exit(1);
584    }
585
586    loadplugfunc = (loadPlugin) dlsym(pdata->pluginhandle, "loadPlugin");
587    if (loadplugfunc == NULL) {
588       printf("\nCannot find loadPlugin function: %s\n", dlerror());
589       printf("\nWhether the file is a really Bacula plugin?\n\n");
590       freepdata(pdata);
591       exit(2);
592    }
593
594    unloadplugfunc = (unloadPlugin) dlsym(pdata->pluginhandle, "unloadPlugin");
595    if (unloadplugfunc == NULL) {
596       printf("\nCannot find unloadPlugin function: %s\n", dlerror());
597       printf("\nWhether the file is a really Bacula plugin?\n\n");
598       freepdata(pdata);
599       exit(3);
600    }
601
602    if (pdata->bapiversion > 0) {
603       binfos.bdirinfo.version = pdata->bapiversion;
604    }
605
606    loadplugfunc(&binfos, &bfuncs, (void **)&pdata->pinfo, (void **)&pdata->pfuncs);
607
608    pdata->bplugtype = getplugintype(pdata);
609
610    if (!pdata->listfunc) {
611       dump_pluginfo(pdata);
612    }
613    if ((!pdata->listinfo && pdata->listfunc) || pdata->verbose) {
614       dump_plugfuncs(pdata);
615    }
616    printf("\n");
617
618    unloadplugfunc();
619
620    dlclose(pdata->pluginhandle);
621
622    freepdata(pdata);
623
624    return 0;
625 }