1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * A simple pipe plugin for the Bacula File Daemon
21 *
22 * Kern Sibbald, October 2007
23 *
24 */
25 #include "bacula.h"
26 #define USE_FULL_WRITE
27 #include "fd_common.h"
28 #include "fd_plugins.h"
29 #include "lib/ini.h"
30
31 #undef malloc
32 #undef free
33 #undef strdup
34
35 #define fi __FILE__
36 #define li __LINE__
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 static const int dbglvl = 150;
43
44 #define PLUGIN_LICENSE "AGPLv3"
45 #define PLUGIN_AUTHOR "Kern Sibbald"
46 #define PLUGIN_DATE "January 2008"
47 #define PLUGIN_VERSION "1"
48 #define PLUGIN_DESCRIPTION "Bacula Pipe File Daemon Plugin"
49
50 /* Forward referenced functions */
51 static bRC newPlugin(bpContext *ctx);
52 static bRC freePlugin(bpContext *ctx);
53 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
54 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
55 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
56 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
57 static bRC endBackupFile(bpContext *ctx);
58 static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
59 static bRC startRestoreFile(bpContext *ctx, const char *cmd);
60 static bRC endRestoreFile(bpContext *ctx);
61 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
62 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
63 static bRC checkFile(bpContext *ctx, char *fname);
64 static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl);
65
66 static char *apply_rp_codes(struct plugin_ctx * p_ctx);
67
68 /* Pointers to Bacula functions */
69 static bFuncs *bfuncs = NULL;
70 static bInfo *binfo = NULL;
71
72 /* Plugin Information block */
73 static pInfo pluginInfo = {
74 sizeof(pluginInfo),
75 FD_PLUGIN_INTERFACE_VERSION,
76 FD_PLUGIN_MAGIC,
77 PLUGIN_LICENSE,
78 PLUGIN_AUTHOR,
79 PLUGIN_DATE,
80 PLUGIN_VERSION,
81 PLUGIN_DESCRIPTION
82 };
83
84 /* Plugin entry points for Bacula */
85 static pFuncs pluginFuncs = {
86 sizeof(pluginFuncs),
87 FD_PLUGIN_INTERFACE_VERSION,
88
89 /* Entry points into plugin */
90 newPlugin, /* new plugin instance */
91 freePlugin, /* free plugin instance */
92 getPluginValue,
93 setPluginValue,
94 handlePluginEvent,
95 startBackupFile,
96 endBackupFile,
97 startRestoreFile,
98 endRestoreFile,
99 pluginIO,
100 createFile,
101 setFileAttributes,
102 checkFile,
103 handleXACLdata,
104 NULL /* No checkStream */
105 };
106
107 /*
108 * Plugin private context
109 */
110 struct plugin_ctx {
111 boffset_t offset;
112 BPIPE *pfd; /* bpipe file descriptor */
113 int efd; /* stderr */
114 int rfd; /* stdout */
115 int wfd; /* stdin */
116 int maxfd; /* max(stderr, stdout) */
117 bool backup; /* set when the backup is done */
118 bool canceled;
119 char *cmd; /* plugin command line */
120 char *fname; /* filename to "backup/restore" */
121 char *reader; /* reader program for backup */
122 char *writer; /* writer program for backup */
123 char where[512];
124 int replace;
125 int job_level;
126 int estimate_mode;
127 int64_t total_bytes; /* number of bytes read/write */
128 };
129
130 /*
131 * loadPlugin() and unloadPlugin() are entry points that are
132 * exported, so Bacula can directly call these two entry points
133 * they are common to all Bacula plugins.
134 */
135 /*
136 * External entry point called by Bacula to "load the plugin
137 */
loadPlugin(bInfo * lbinfo,bFuncs * lbfuncs,pInfo ** pinfo,pFuncs ** pfuncs)138 bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
139 {
140 bfuncs = lbfuncs; /* set Bacula funct pointers */
141 binfo = lbinfo;
142 *pinfo = &pluginInfo; /* return pointer to our info */
143 *pfuncs = &pluginFuncs; /* return pointer to our functions */
144
145 return bRC_OK;
146 }
147
148 /*
149 * External entry point to unload the plugin
150 */
unloadPlugin()151 bRC unloadPlugin()
152 {
153 // printf("bpipe-fd: Unloaded\n");
154 return bRC_OK;
155 }
156
157 /*
158 * The following entry points are accessed through the function
159 * pointers we supplied to Bacula. Each plugin type (dir, fd, sd)
160 * has its own set of entry points that the plugin must define.
161 */
162 /*
163 * Create a new instance of the plugin i.e. allocate our private storage
164 */
newPlugin(bpContext * ctx)165 static bRC newPlugin(bpContext *ctx)
166 {
167 struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
168 if (!p_ctx) {
169 return bRC_Error;
170 }
171 memset(p_ctx, 0, sizeof(struct plugin_ctx));
172 ctx->pContext = (void *)p_ctx; /* set our context pointer */
173 return bRC_OK;
174 }
175
176 /*
177 * Free a plugin instance, i.e. release our private storage
178 */
freePlugin(bpContext * ctx)179 static bRC freePlugin(bpContext *ctx)
180 {
181 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
182 if (!p_ctx) {
183 return bRC_Error;
184 }
185 if (p_ctx->cmd) {
186 free(p_ctx->cmd); /* free any allocated command string */
187 }
188 free(p_ctx); /* free our private context */
189 p_ctx = NULL;
190 return bRC_OK;
191 }
192
193 /*
194 * Return some plugin value (none defined)
195 */
getPluginValue(bpContext * ctx,pVariable var,void * value)196 static bRC getPluginValue(bpContext *ctx, pVariable var, void *value)
197 {
198 return bRC_OK;
199 }
200
201 /*
202 * Set a plugin value (none defined)
203 */
setPluginValue(bpContext * ctx,pVariable var,void * value)204 static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
205 {
206 return bRC_OK;
207 }
208
209 /*
210 * Handle an event that was generated in Bacula
211 */
handlePluginEvent(bpContext * ctx,bEvent * event,void * value)212 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
213 {
214 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
215
216 if (!p_ctx) {
217 return bRC_Error;
218 }
219
220 // char *name;
221
222 /*
223 * Most events don't interest us so we ignore them.
224 * the printfs are so that plugin writers can enable them to see
225 * what is really going on.
226 */
227 switch (event->eventType) {
228 case bEventLevel:
229 p_ctx->job_level = ((intptr_t)value);
230 break;
231
232 case bEventCancelCommand:
233 p_ctx->canceled = true;
234 break;
235
236 case bEventPluginCommand:
237 bfuncs->DebugMessage(ctx, fi, li, dbglvl,
238 "bpipe-fd: PluginCommand=%s\n", (char *)value);
239 break;
240 case bEventJobStart:
241 bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: JobStart=%s\n", (char *)value);
242 break;
243 case bEventJobEnd:
244 // printf("bpipe-fd: JobEnd\n");
245 break;
246 case bEventStartBackupJob:
247 // printf("bpipe-fd: StartBackupJob\n");
248 break;
249 case bEventEndBackupJob:
250 // printf("bpipe-fd: EndBackupJob\n");
251 break;
252 case bEventSince:
253 // printf("bpipe-fd: since=%d\n", (int)value);
254 break;
255 case bEventStartRestoreJob:
256 // printf("bpipe-fd: StartRestoreJob\n");
257 break;
258
259 case bEventEndRestoreJob:
260 // printf("bpipe-fd: EndRestoreJob\n");
261 break;
262
263 /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
264 case bEventEstimateCommand:
265 p_ctx->estimate_mode = true;
266 /* Fall-through wanted */
267 case bEventRestoreCommand:
268 // printf("bpipe-fd: EventRestoreCommand cmd=%s\n", (char *)value);
269 /* Fall-through wanted */
270 case bEventBackupCommand:
271 char *p;
272 bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
273 p_ctx->backup = false;
274 p_ctx->cmd = strdup((char *)value);
275 p = strchr(p_ctx->cmd, ':');
276 if (!p) {
277 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
278 return bRC_Error;
279 }
280 *p++ = 0; /* terminate plugin */
281 p_ctx->fname = p;
282 p = strchr(p, ':');
283 if (!p) {
284 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
285 return bRC_Error;
286 }
287 *p++ = 0; /* terminate file */
288 p_ctx->reader = p;
289 p = strchr(p, ':');
290 if (!p) {
291 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
292 return bRC_Error;
293 }
294 *p++ = 0; /* terminate reader string */
295 p_ctx->writer = p;
296
297 // printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n",
298 // p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
299 break;
300
301 default:
302 // printf("bpipe-fd: unknown event=%d\n", event->eventType);
303 break;
304 }
305 return bRC_OK;
306 }
307
308
309 /*
310 * Start the backup of a specific file
311 */
startBackupFile(bpContext * ctx,struct save_pkt * sp)312 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
313 {
314 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
315 if (!p_ctx) {
316 return bRC_Error;
317 }
318
319 time_t now = time(NULL);
320 sp->fname = p_ctx->fname;
321 sp->type = FT_REG;
322 sp->statp.st_mode = 0700 | S_IFREG;
323 sp->statp.st_ctime = now;
324 sp->statp.st_mtime = now;
325 sp->statp.st_atime = now;
326 sp->statp.st_size = -1;
327 sp->statp.st_blksize = 4096;
328 sp->statp.st_blocks = 1;
329 p_ctx->backup = true;
330 // printf("bpipe-fd: startBackupFile\n");
331 return bRC_OK;
332 }
333
334 /*
335 * Done with backup of this file
336 */
endBackupFile(bpContext * ctx)337 static bRC endBackupFile(bpContext *ctx)
338 {
339 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
340 if (!p_ctx) {
341 return bRC_Error;
342 }
343
344 /*
345 * We would return bRC_More if we wanted startBackupFile to be
346 * called again to backup another file
347 */
348 if (!p_ctx->backup) {
349 return bRC_More;
350 }
351 return bRC_OK;
352 }
353
send_log(bpContext * ctx,char * buf)354 static void send_log(bpContext *ctx, char *buf)
355 {
356 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
357 strip_trailing_newline(buf);
358 bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "%s: %s\n", p_ctx->fname, buf);
359 }
360
361 /*
362 * Bacula is calling us to do the actual I/O
363 */
pluginIO(bpContext * ctx,struct io_pkt * io)364 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
365 {
366 fd_set rfds;
367 fd_set wfds;
368 bool ok=false;
369 char buf[1024];
370 struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
371 if (!p_ctx) {
372 return bRC_Error;
373 }
374
375 io->status = -1;
376 io->io_errno = 0;
377 switch(io->func) {
378 case IO_OPEN:
379 p_ctx->total_bytes = 0;
380 p_ctx->wfd = p_ctx->efd = p_ctx->rfd = -1;
381 bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
382 if (io->flags & (O_CREAT | O_WRONLY)) {
383 char *writer_codes = apply_rp_codes(p_ctx);
384
385 p_ctx->pfd = open_bpipe(writer_codes, 0, "rws");
386 bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p writer=%s\n",
387 p_ctx->pfd, writer_codes);
388 if (!p_ctx->pfd) {
389 io->io_errno = errno;
390 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
391 "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
392 if (writer_codes) {
393 free(writer_codes);
394 }
395 return bRC_Error;
396 }
397 if (writer_codes) {
398 free(writer_codes);
399 }
400 /* We need to read from stdout/stderr for messages to display to the user */
401 p_ctx->rfd = fileno(p_ctx->pfd->rfd);
402 p_ctx->wfd = fileno(p_ctx->pfd->wfd);
403 p_ctx->maxfd = MAX(p_ctx->wfd, p_ctx->rfd);
404 io->status = p_ctx->wfd;
405
406 } else {
407 /* Use shell mode and split stderr/stdout */
408 p_ctx->pfd = open_bpipe(p_ctx->reader, 0, "rse");
409 bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n",
410 p_ctx->pfd, p_ctx->reader);
411 if (!p_ctx->pfd) {
412 io->io_errno = errno;
413 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
414 "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
415 return bRC_Error;
416 }
417 /* We need to read from stderr for job log and stdout for the data */
418 p_ctx->efd = fileno(p_ctx->pfd->efd);
419 p_ctx->rfd = fileno(p_ctx->pfd->rfd);
420 p_ctx->maxfd = MAX(p_ctx->efd, p_ctx->rfd);
421 io->status = p_ctx->rfd;
422 }
423 sleep(1); /* let pipe connect */
424 break;
425
426 case IO_READ:
427 if (!p_ctx->pfd) {
428 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
429 return bRC_Error;
430 }
431
432 /* We first try to read stderr, but keep monitoring for data on stdout (when stderr is empty) */
433 while (!p_ctx->canceled) {
434 FD_ZERO(&rfds);
435 FD_SET(p_ctx->rfd, &rfds);
436 FD_SET(p_ctx->efd, &rfds);
437 select(p_ctx->maxfd+1, &rfds, NULL, NULL, NULL);
438
439 if (!FD_ISSET(p_ctx->efd, &rfds)) {
440 /* nothing in stderr, then we should have something in stdout */
441 break;
442 }
443 int ret = read(p_ctx->efd, buf, sizeof(buf));
444 if (ret <= 0) {
445 /* stderr is closed or in error, stdout should be in the same state */
446 /* let handle it at the stdout level */
447 break;
448 }
449 /* TODO: buffer and split lines */
450 buf[ret]=0;
451 send_log(ctx, buf);
452 }
453
454 io->status = read(p_ctx->rfd, io->buf, io->count);
455 // bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
456 if (io->status < 0) {
457 berrno be;
458 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
459 "Pipe read error: ERR=%s\n", be.bstrerror());
460 bfuncs->DebugMessage(ctx, fi, li, dbglvl,
461 "Pipe read error: count=%lld errno=%d ERR=%s\n",
462 p_ctx->total_bytes, (int)errno, be.bstrerror());
463 return bRC_Error;
464 }
465 p_ctx->total_bytes += io->status;
466 break;
467
468 case IO_WRITE:
469 if (!p_ctx->pfd) {
470 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
471 return bRC_Error;
472 }
473
474 /* When we write, we must check for the error channel (stdout+stderr) as well */
475 while (!ok && !p_ctx->canceled) {
476 FD_ZERO(&wfds);
477 FD_SET(p_ctx->wfd, &wfds);
478 FD_ZERO(&rfds);
479 FD_SET(p_ctx->rfd, &rfds);
480
481 select(p_ctx->maxfd+1, &rfds, &wfds, NULL, NULL);
482
483 if (FD_ISSET(p_ctx->rfd, &rfds)) {
484 int ret = read(p_ctx->rfd, buf, sizeof(buf)); /* TODO: simulate fgets() */
485 if (ret > 0) {
486 buf[ret]=0;
487 send_log(ctx, buf);
488 } else {
489 ok = true; /* nothing to read */
490 }
491 }
492
493 if (FD_ISSET(p_ctx->wfd, &wfds)) {
494 ok = true;
495 }
496 }
497
498 // printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
499 io->status = full_write(p_ctx->wfd, io->buf, io->count, &p_ctx->canceled);
500 // printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
501 if (io->status <= 0) {
502 berrno be;
503 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
504 "Pipe write error: ERR=%s\n", be.bstrerror());
505 bfuncs->DebugMessage(ctx, fi, li, dbglvl,
506 "Pipe write error: count=%lld errno=%d ERR=%s\n",
507 p_ctx->total_bytes, (int)errno, be.bstrerror());
508 return bRC_Error;
509 }
510 p_ctx->total_bytes += io->status;
511 break;
512
513 case IO_CLOSE:
514 if (!p_ctx->pfd) {
515 bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
516 return bRC_Error;
517 }
518
519 /* We inform the other side that we have nothing more to send */
520 if (p_ctx->wfd >= 0) {
521 int ret = close_wpipe(p_ctx->pfd);
522 if (ret == 0) {
523 bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "bpipe-fd: Error closing for file %s: %d\n",
524 p_ctx->fname, ret);
525 }
526 }
527
528 /* We flush what the other program has to say */
529 while (!ok && !p_ctx->canceled) {
530 struct timeval tv = {10, 0}; // sleep for 10secs
531 FD_ZERO(&rfds);
532 p_ctx->maxfd = -1;
533
534 if (p_ctx->rfd >= 0) {
535 FD_SET(p_ctx->rfd, &rfds);
536 p_ctx->maxfd = MAX(p_ctx->maxfd, p_ctx->rfd);
537 }
538
539 if (p_ctx->efd >= 0) {
540 FD_SET(p_ctx->efd, &rfds);
541 p_ctx->maxfd = MAX(p_ctx->maxfd, p_ctx->efd);
542 }
543
544 if (p_ctx->maxfd == -1) {
545 ok = true; /* exit the loop */
546 } else {
547 select(p_ctx->maxfd+1, &rfds, NULL, NULL, &tv);
548 }
549
550 if (p_ctx->rfd >= 0 && FD_ISSET(p_ctx->rfd, &rfds)) {
551 int ret = read(p_ctx->rfd, buf, sizeof(buf));
552 if (ret > 0) {
553 buf[ret]=0;
554 send_log(ctx, buf);
555 } else {
556 p_ctx->rfd = -1; /* closed, keep the reference in bpipe */
557 }
558 }
559
560 /* The stderr can be melted with stdout or not */
561 if (p_ctx->efd >= 0 && FD_ISSET(p_ctx->efd, &rfds)) {
562 int ret = read(p_ctx->efd, buf, sizeof(buf));
563 if (ret > 0) {
564 buf[ret]=0;
565 send_log(ctx, buf);
566 } else {
567 p_ctx->efd = -1; /* closed, keep the reference in bpipe */
568 }
569 }
570 }
571
572 io->status = close_bpipe(p_ctx->pfd);
573 if (io->status != 0) {
574 bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "bpipe-fd: Error closing for file %s: %d\n",
575 p_ctx->fname, io->status);
576 }
577 break;
578
579 case IO_SEEK:
580 io->offset = p_ctx->offset;
581 io->status = 0;
582 break;
583 }
584 return bRC_OK;
585 }
586
587 /*
588 * Bacula is notifying us that a plugin name string was found, and
589 * passing us the plugin command, so we can prepare for a restore.
590 */
startRestoreFile(bpContext * ctx,const char * cmd)591 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
592 {
593 // printf("bpipe-fd: startRestoreFile cmd=%s\n", cmd);
594 return bRC_OK;
595 }
596
597 /*
598 * Bacula is notifying us that the plugin data has terminated, so
599 * the restore for this particular file is done.
600 */
endRestoreFile(bpContext * ctx)601 static bRC endRestoreFile(bpContext *ctx)
602 {
603 // printf("bpipe-fd: endRestoreFile\n");
604 return bRC_OK;
605 }
606
607 /*
608 * This is called during restore to create the file (if necessary)
609 * We must return in rp->create_status:
610 *
611 * CF_ERROR -- error
612 * CF_SKIP -- skip processing this file
613 * CF_EXTRACT -- extract the file (i.e.call i/o routines)
614 * CF_CREATED -- created, but no content to extract (typically directories)
615 *
616 */
createFile(bpContext * ctx,struct restore_pkt * rp)617 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
618 {
619 // printf("bpipe-fd: createFile\n");
620 if (strlen(rp->where) > 512) {
621 printf("Restore target dir too long. Restricting to first 512 bytes.\n");
622 }
623 bstrncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 512);
624 ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
625 rp->create_status = CF_EXTRACT;
626 return bRC_OK;
627 }
628
629 /*
630 * We will get here if the File is a directory after everything
631 * is written in the directory.
632 */
setFileAttributes(bpContext * ctx,struct restore_pkt * rp)633 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
634 {
635 // printf("bpipe-fd: setFileAttributes\n");
636 return bRC_OK;
637 }
638
639 /* When using Incremental dump, all previous dumps are necessary */
checkFile(bpContext * ctx,char * fname)640 static bRC checkFile(bpContext *ctx, char *fname)
641 {
642 return bRC_OK;
643 }
644
645 /*
646 * New Bacula Plugin API require this
647 */
handleXACLdata(bpContext * ctx,struct xacl_pkt * xacl)648 static bRC handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl)
649 {
650 return bRC_OK;
651 }
652
653 /*************************************************************************
654 * Apply codes in writer command:
655 * %w -> "where"
656 * %r -> "replace"
657 *
658 * Replace:
659 * 'always' => 'a', chr(97)
660 * 'ifnewer' => 'w', chr(119)
661 * 'ifolder' => 'o', chr(111)
662 * 'never' => 'n', chr(110)
663 *
664 * This function will allocate the required amount of memory with malloc.
665 * Need to be free()d manually.
666 * Inspired by edit_job_codes in lib/util.c
667 */
668
apply_rp_codes(struct plugin_ctx * p_ctx)669 static char *apply_rp_codes(struct plugin_ctx * p_ctx)
670 {
671 char *p, *q;
672 const char *str;
673 char add[10];
674 int w_count = 0, r_count = 0;
675 char *omsg;
676
677 char *imsg = p_ctx->writer;
678
679 if (!imsg) {
680 return NULL;
681 }
682
683 if ((p = imsg)) {
684 while ((q = strstr(p, "%w"))) {
685 w_count++;
686 p=q+1;
687 }
688
689 p = imsg;
690 while ((q = strstr(p, "%r"))) {
691 r_count++;
692 p=q+1;
693 }
694 }
695
696 /* Required mem:
697 * len(imsg)
698 * + number of "where" codes * (len(where)-2)
699 * - number of "replace" codes
700 */
701 omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
702 if (!omsg) {
703 fprintf(stderr, "Out of memory.");
704 return NULL;
705 }
706
707 *omsg = 0;
708 //printf("apply_rp_codes: %s\n", imsg);
709 for (p=imsg; *p; p++) {
710 if (*p == '%') {
711 switch (*++p) {
712 case '%':
713 str = "%";
714 break;
715 case 'w':
716 str = p_ctx->where;
717 break;
718 case 'r':
719 snprintf(add, 2, "%c", p_ctx->replace);
720 str = add;
721 break;
722 default:
723 add[0] = '%';
724 add[1] = *p;
725 add[2] = 0;
726 str = add;
727 break;
728 }
729 } else {
730 add[0] = *p;
731 add[1] = 0;
732 str = add;
733 }
734 //printf("add_str %s\n", str);
735 strcat(omsg, str);
736 //printf("omsg=%s\n", omsg);
737 }
738 return omsg;
739 }
740
741 #ifdef __cplusplus
742 }
743 #endif
744