]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/fd-plugins.c
Plugin implementation. First cut backup working
[bacula/bacula] / bacula / src / filed / fd-plugins.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Main program to test loading and running Bacula plugins.
30  *   Destined to become Bacula pluginloader, ...
31  *
32  * Kern Sibbald, October 2007
33  */
34 #include "bacula.h"
35 #include "filed.h"
36
37 const int dbglvl = 50;
38 const char *plugin_type = "-fd.so";
39
40 extern int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level);
41
42
43 /* Function pointers to be set here */
44 extern int     (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode);
45 extern int     (*plugin_bclose)(JCR *jcr);
46 extern ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count);
47 extern ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count);
48
49
50 /* Forward referenced functions */
51 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value);
52 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value);
53 static bRC baculaRegisterEvents(bpContext *ctx, ...);
54 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
55   int type, time_t mtime, const char *msg);
56 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
57   int level, const char *msg);
58
59 static int     my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode);
60 static int     my_plugin_bclose(JCR *jcr);
61 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count);
62 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count);
63
64
65 /* Bacula info */
66 static bInfo binfo = {
67    sizeof(bFuncs),
68    PLUGIN_INTERFACE_VERSION 
69 };
70
71 /* Bacula entry points */
72 static bFuncs bfuncs = {
73    sizeof(bFuncs),
74    PLUGIN_INTERFACE_VERSION,
75    baculaRegisterEvents,
76    baculaGetValue,
77    baculaSetValue,
78    baculaJobMsg,
79    baculaDebugMsg
80 };
81
82
83 /*
84  * Create a plugin event 
85  */
86 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value)     
87 {
88    bEvent event;
89    Plugin *plugin;
90    int i = 0;
91    int len;
92    char *p;
93    char *cmd = (char *)value;
94
95    if (!plugin_list) {
96       return;
97    }
98
99    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
100    event.eventType = eventType;
101
102    Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId);
103    if (eventType != bEventPluginCommand) {
104       /* Pass event to every plugin */
105       foreach_alist(plugin, plugin_list) {
106          plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i++], &event, value);
107       }
108       goto bail_out;
109    }
110
111    /* Handle plugin command here (backup/restore of file) */
112    Dmsg1(000, "plugin cmd=%s\n", cmd);
113    if (!(p = strchr(cmd, ':'))) {
114       Jmsg1(jcr, M_ERROR, 0, "Malformed plugin command: %s\n", cmd);
115       goto bail_out;
116    }
117    len = p - cmd;
118    if (len <= 0) {
119       goto bail_out;
120    }
121
122    foreach_alist(plugin, plugin_list) {
123       Dmsg3(000, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len);
124       if (strncmp(plugin->file, cmd, len) == 0) {
125          struct save_pkt sp;
126          FF_PKT *ff_pkt;
127          Dmsg1(000, "Command plugin = %s\n", cmd);
128          if (plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, value) != bRC_OK) {
129             goto bail_out;
130          }
131          memset(&sp, 0, sizeof(sp));
132          sp.type = FT_REG;
133          sp.portable = true;
134          Dmsg0(000, "Plugin startBackup\n");
135          if (plug_func(plugin)->startPluginBackup(&plugin_ctx_list[i], &sp) != bRC_OK) {
136             goto bail_out;
137          }
138          jcr->plugin_ctx = &plugin_ctx_list[i];
139          jcr->plugin = plugin;
140          ff_pkt = jcr->ff;
141          ff_pkt->fname = sp.fname;
142          ff_pkt->type = sp.type;
143          ff_pkt->statp = sp.statp;        /* structure copy */
144          Dmsg1(000, "Save_file: file=%s\n", ff_pkt->fname);
145          save_file(ff_pkt, (void *)jcr, true);
146          goto bail_out;
147       }
148       i++;
149    }
150       
151 bail_out:
152    return;
153 }
154
155 void load_fd_plugins(const char *plugin_dir)
156 {
157    if (!plugin_dir) {
158       return;
159    }
160
161    plugin_list = New(alist(10, not_owned_by_alist));
162    load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type);
163    plugin_bopen  = my_plugin_bopen;
164    plugin_bclose = my_plugin_bclose;
165    plugin_bread  = my_plugin_bread;
166    plugin_bwrite = my_plugin_bwrite;
167
168 }
169
170 /*
171  * Create a new instance of each plugin for this Job
172  */
173 void new_plugins(JCR *jcr)
174 {
175    Plugin *plugin;
176    int i = 0;
177
178    if (!plugin_list) {
179       return;
180    }
181
182    int num = plugin_list->size();
183
184    if (num == 0) {
185       return;
186    }
187
188    jcr->plugin_ctx_list = (void *)malloc(sizeof(bpContext) * num);
189
190    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
191    Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
192    foreach_alist(plugin, plugin_list) {
193       /* Start a new instance of each plugin */
194       plugin_ctx_list[i].bContext = (void *)jcr;
195       plugin_ctx_list[i].pContext = NULL;
196       plug_func(plugin)->newPlugin(&plugin_ctx_list[i++]);
197    }
198 }
199
200 /*
201  * Free the plugin instances for this Job
202  */
203 void free_plugins(JCR *jcr)
204 {
205    Plugin *plugin;
206    int i = 0;
207
208    if (!plugin_list) {
209       return;
210    }
211
212    bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list;
213    Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId);
214    foreach_alist(plugin, plugin_list) {
215       /* Free the plugin instance */
216       plug_func(plugin)->freePlugin(&plugin_ctx_list[i++]);
217    }
218    free(plugin_ctx_list);
219    jcr->plugin_ctx_list = NULL;
220 }
221
222 static int my_plugin_bopen(JCR *jcr, const char *fname, int flags, mode_t mode)
223 {
224    Plugin *plugin = (Plugin *)jcr->plugin;
225    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
226    struct io_pkt io;
227    Dmsg0(000, "plugin_bopen\n");
228    io.func = IO_OPEN;
229    io.count = 0;
230    io.buf = NULL;
231    plug_func(plugin)->pluginIO(plugin_ctx, &io);
232    return io.status;
233 }
234
235 static int my_plugin_bclose(JCR *jcr)
236 {
237    Plugin *plugin = (Plugin *)jcr->plugin;
238    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
239    struct io_pkt io;
240    Dmsg0(000, "plugin_bclose\n");
241    io.func = IO_CLOSE;
242    io.count = 0;
243    io.buf = NULL;
244    plug_func(plugin)->pluginIO(plugin_ctx, &io);
245    return io.status;
246 }
247
248 static ssize_t my_plugin_bread(JCR *jcr, void *buf, size_t count)
249 {
250    Plugin *plugin = (Plugin *)jcr->plugin;
251    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
252    struct io_pkt io;
253    Dmsg0(000, "plugin_bread\n");
254    io.func = IO_READ;
255    io.count = count;
256    io.buf = (char *)buf;
257    plug_func(plugin)->pluginIO(plugin_ctx, &io);
258    return (ssize_t)io.status;
259 }
260
261 static ssize_t my_plugin_bwrite(JCR *jcr, void *buf, size_t count)
262 {
263    Plugin *plugin = (Plugin *)jcr->plugin;
264    bpContext *plugin_ctx = (bpContext *)jcr->plugin_ctx;
265    struct io_pkt io;
266    Dmsg0(000, "plugin_bwrite\n");
267    io.func = IO_WRITE;
268    io.count = count;
269    io.buf = (char *)buf;
270    plug_func(plugin)->pluginIO(plugin_ctx, &io);
271    return (ssize_t)io.status;
272 }
273
274 /* ==============================================================
275  *
276  * Callbacks from the plugin
277  *
278  * ==============================================================
279  */
280 static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value)
281 {
282    JCR *jcr = (JCR *)(ctx->bContext);
283 // Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var);
284    if (!value) {
285       return bRC_Error;
286    }
287 // Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); 
288    switch (var) {
289    case bVarJobId:
290       *((int *)value) = jcr->JobId;
291       Dmsg1(dbglvl, "Bacula: return bVarJobId=%d\n", jcr->JobId);
292       break;
293    case bVarFDName:
294       *((char **)value) = my_name;
295       Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name);
296       break;
297    case bVarLevel:
298    case bVarType:
299    case bVarClient:
300    case bVarJobName:
301    case bVarJobStatus:
302    case bVarSinceTime:
303       break;
304    }
305    return bRC_OK;
306 }
307
308 static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value)
309 {
310    Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var);
311    return bRC_OK;
312 }
313
314 static bRC baculaRegisterEvents(bpContext *ctx, ...)
315 {
316    va_list args;
317    uint32_t event;
318
319    va_start(args, ctx);
320    while ((event = va_arg(args, uint32_t))) {
321       Dmsg1(dbglvl, "Plugin wants event=%u\n", event);
322    }
323    va_end(args);
324    return bRC_OK;
325 }
326
327 static bRC baculaJobMsg(bpContext *ctx, const char *file, int line,
328   int type, time_t mtime, const char *msg)
329 {
330    Dmsg5(dbglvl, "Job message: %s:%d type=%d time=%ld msg=%s\n",
331       file, line, type, mtime, msg);
332    return bRC_OK;
333 }
334
335 static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line,
336   int level, const char *msg)
337 {
338    Dmsg4(dbglvl, "Debug message: %s:%d level=%d msg=%s\n",
339       file, line, level, msg);
340    return bRC_OK;
341 }
342
343 #ifdef TEST_PROGRAM
344
345 int     (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL;
346 int     (*plugin_bclose)(JCR *jcr) = NULL;
347 ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL;
348 ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL;
349
350 int save_file(FF_PKT *ff_pkt, void *vjcr, bool top_level)
351 {
352    return 0;
353 }
354
355 int main(int argc, char *argv[])
356 {
357    char plugin_dir[1000];
358    JCR mjcr1, mjcr2;
359    JCR *jcr1 = &mjcr1;
360    JCR *jcr2 = &mjcr2;
361
362    strcpy(my_name, "test-fd");
363     
364    getcwd(plugin_dir, sizeof(plugin_dir)-1);
365    load_fd_plugins(plugin_dir);
366
367    jcr1->JobId = 111;
368    new_plugins(jcr1);
369
370    jcr2->JobId = 222;
371    new_plugins(jcr2);
372
373    generate_plugin_event(jcr1, bEventJobStart);
374    generate_plugin_event(jcr1, bEventJobEnd);
375    generate_plugin_event(jcr2, bEventJobStart);
376    free_plugins(jcr1);
377    generate_plugin_event(jcr2, bEventJobEnd);
378    free_plugins(jcr2);
379
380    unload_plugins();
381
382    Dmsg0(dbglvl, "bacula: OK ...\n");
383    close_memory_pool();
384    sm_dump(false);
385    return 0;
386 }
387
388 #endif /* TEST_PROGRAM */