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