]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/plugins/fd/bpipe-fd.c
start to tweak prune algo
[bacula/bacula] / bacula / src / plugins / fd / bpipe-fd.c
index c083b1361f78ce3f7a2396339d657bf8e6abbca8..d6091fce93863fbe248b59391cd03c1bff967f74 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2007-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
  *  Kern Sibbald, October 2007
  *
  */
+#include "bacula.h"
 #include "fd_plugins.h"
 
 #undef malloc
 #undef free
 #undef strdup
 
+#define fi __FILE__
+#define li __LINE__
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define PLUGIN_LICENSE      "GPLv2"
+static const int dbglvl = 150;
+
+#define PLUGIN_LICENSE      "Bacula GPLv2"
 #define PLUGIN_AUTHOR       "Kern Sibbald"
 #define PLUGIN_DATE         "January 2008"
 #define PLUGIN_VERSION      "1"
-#define PLUGIN_DESCRIPTION  "Pipe File Daemon Plugin"
+#define PLUGIN_DESCRIPTION  "Bacula Pipe File Daemon Plugin"
 
 /* Forward referenced functions */
 static bRC newPlugin(bpContext *ctx);
@@ -61,6 +67,7 @@ static bRC endRestoreFile(bpContext *ctx);
 static bRC createFile(bpContext *ctx, struct restore_pkt *rp);
 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp);
 
+static char *apply_rp_codes(struct plugin_ctx * p_ctx);
 
 /* Pointers to Bacula functions */
 static bFuncs *bfuncs = NULL;
@@ -152,6 +159,9 @@ bRC unloadPlugin()
 static bRC newPlugin(bpContext *ctx)
 {
    struct plugin_ctx *p_ctx = (struct plugin_ctx *)malloc(sizeof(struct plugin_ctx));
+   if (!p_ctx) {
+      return bRC_Error;
+   }
    memset(p_ctx, 0, sizeof(struct plugin_ctx));
    ctx->pContext = (void *)p_ctx;        /* set our context pointer */
    return bRC_OK;
@@ -163,10 +173,14 @@ static bRC newPlugin(bpContext *ctx)
 static bRC freePlugin(bpContext *ctx)
 {
    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
+   if (!p_ctx) {
+      return bRC_Error;
+   }
    if (p_ctx->cmd) {
       free(p_ctx->cmd);                  /* free any allocated command string */
    }
    free(p_ctx);                          /* free our private context */
+   p_ctx = NULL;
    return bRC_OK;
 }
 
@@ -192,20 +206,33 @@ static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
 static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
 {
    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
+   if (!p_ctx) {
+      return bRC_Error;
+   }
+
 // char *name;
 
+   /*
+    * Most events don't interest us so we ignore them.
+    *   the printfs are so that plugin writers can enable them to see
+    *   what is really going on.
+    */
    switch (event->eventType) {
+   case bEventPluginCommand:
+      bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
+                           "bpipe-fd: PluginCommand=%s\n", (char *)value);
+      break;
    case bEventJobStart:
-//    printf("bpipe-fd: JobStart=%s\n", (char *)value);
+      bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: JobStart=%s\n", (char *)value);
       break;
    case bEventJobEnd:
 //    printf("bpipe-fd: JobEnd\n");
       break;
    case bEventStartBackupJob:
-//    printf("bpipe-fd: BackupStart\n");
+//    printf("bpipe-fd: StartBackupJob\n");
       break;
    case bEventEndBackupJob:
-//    printf("bpipe-fd: BackupEnd\n");
+//    printf("bpipe-fd: EndBackupJob\n");
       break;
    case bEventLevel:
 //    printf("bpipe-fd: JobLevel=%c %d\n", (int)value, (int)value);
@@ -215,45 +242,49 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
       break;
 
    case bEventStartRestoreJob:
+//    printf("bpipe-fd: StartRestoreJob\n");
       break;
 
    case bEventEndRestoreJob:
+//    printf("bpipe-fd: EndRestoreJob\n");
       break;
 
    /* Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */
    case bEventRestoreCommand:
-      printf("bpipe-fd: EventRestoreCommand cmd=%s\n", (char *)value);
+//    printf("bpipe-fd: EventRestoreCommand cmd=%s\n", (char *)value);
+      /* Fall-through wanted */
    case bEventBackupCommand:
       char *p;
-      printf("bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
+      bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: pluginEvent cmd=%s\n", (char *)value);
       p_ctx->cmd = strdup((char *)value);
       p = strchr(p_ctx->cmd, ':');
       if (!p) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s\n", (char *)value);
          return bRC_Error;
       }
       *p++ = 0;           /* terminate plugin */
       p_ctx->fname = p;
       p = strchr(p, ':');
       if (!p) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s\n", (char *)value);
          return bRC_Error;
       }
       *p++ = 0;           /* terminate file */
       p_ctx->reader = p;
       p = strchr(p, ':');
       if (!p) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s\n", (char *)value);
          return bRC_Error;
       }
       *p++ = 0;           /* terminate reader string */
       p_ctx->writer = p;
-      printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
-         p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
+//    printf("bpipe-fd: plugin=%s fname=%s reader=%s writer=%s\n", 
+//         p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer);
       break;
 
    default:
-      printf("bpipe-fd: unknown event=%d\n", event->eventType);
+//    printf("bpipe-fd: unknown event=%d\n", event->eventType);
+      break;
    }
    return bRC_OK;
 }
@@ -264,8 +295,12 @@ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
 static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
 {
    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
+   if (!p_ctx) {
+      return bRC_Error;
+   }
    time_t now = time(NULL);
    sp->fname = p_ctx->fname;
+   sp->type = FT_REG;
    sp->statp.st_mode = 0700 | S_IFREG;
    sp->statp.st_ctime = now;
    sp->statp.st_mtime = now;
@@ -290,93 +325,6 @@ static bRC endBackupFile(bpContext *ctx)
    return bRC_OK;
 }
 
-/*
- * Apply codes in writer command:
- * %w -> "where"
- * %r -> "replace"
- *
- * Replace:
- * 'always' => 'a', chr(97)
- * 'ifnewer' => 'w', chr(119)
- * 'ifolder' => 'o', chr(111)
- * 'never' => 'n', chr(110)
- *
- * This function will allocate the required amount of memory with malloc.
- * Need to be free()d manually.
- * Inspired by edit_job_codes in lib/util.c
- */
-
-char *apply_rp_codes(struct plugin_ctx * p_ctx)
-{
-   char *p, *q;
-   const char *str;
-   char add[10];
-   int w_count = 0, r_count = 0;
-   char *omsg;
-
-   char *imsg = p_ctx->writer;
-
-   if (!imsg) {
-      return NULL;
-   }
-
-   if ((p = imsg)) {
-      while ((q = strstr(p, "%w"))) {
-         w_count++;
-         p=q+1;
-      }
-
-      p = imsg;
-      while ((q = strstr(p, "%r"))) {
-         r_count++;
-         p=q+1;
-      }
-   }
-
-   /* Required mem: 
-    * len(imsg) 
-    * + number of "where" codes * (len(where)-2) 
-    * - number of "replace" codes
-    */
-   omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
-   if (!omsg) {
-      fprintf(stderr, "Out of memory.");
-      exit(1);
-   }
-
-   *omsg = 0;
-   //printf("apply_rp_codes: %s\n", imsg);
-   for (p=imsg; *p; p++) {
-      if (*p == '%') {
-         switch (*++p) {
-         case '%':
-            str = "%";
-            break;
-         case 'w':
-            str = p_ctx->where;
-             break;
-         case 'r':
-           snprintf(add, 2, "%c", p_ctx->replace);
-           str = add;
-            break;
-         default:
-            add[0] = '%';
-            add[1] = *p;
-            add[2] = 0;
-            str = add;
-            break;
-         }
-      } else {
-         add[0] = *p;
-         add[1] = 0;
-         str = add;
-      }
-      //printf("add_str %s\n", str);
-      strcat(omsg, str);
-      //printf("omsg=%s\n", omsg);
-   }
-   return omsg;
-}
 
 /*
  * Bacula is calling us to do the actual I/O
@@ -384,20 +332,24 @@ char *apply_rp_codes(struct plugin_ctx * p_ctx)
 static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
 {
    struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
+   if (!p_ctx) {
+      return bRC_Error;
+   }
     
    io->status = 0;
    io->io_errno = 0;
    switch(io->func) {
    case IO_OPEN:
-//    printf("bpipe-fd: IO_OPEN\n");
+      bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN\n");
       if (io->flags & (O_CREAT | O_WRONLY)) {
-        char *writer_codes = apply_rp_codes(p_ctx);
+         char *writer_codes = apply_rp_codes(p_ctx);
 
          p_ctx->fd = popen(writer_codes, "w");
-         printf("bpipe-fd: IO_OPEN writer=%s\n", writer_codes);
+         bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%d writer=%s\n", 
+             p_ctx->fd, writer_codes);
          if (!p_ctx->fd) {
             io->io_errno = errno;
-            bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, 
+            bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
                "Open pipe writer=%s failed: ERR=%s\n", writer_codes, strerror(errno));
             if (writer_codes) {
                free(writer_codes);
@@ -409,10 +361,11 @@ static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
          }
       } else {
          p_ctx->fd = popen(p_ctx->reader, "r");
-//       printf("bpipe-fd: IO_OPEN reader=%s\n", p_ctx->reader);
+         bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%p reader=%s\n", 
+            p_ctx->fd, p_ctx->reader);
          if (!p_ctx->fd) {
             io->io_errno = errno;
-            bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, 
+            bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
                "Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
             return bRC_Error;
          }
@@ -422,38 +375,40 @@ static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
 
    case IO_READ:
       if (!p_ctx->fd) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "Logic error: NULL read FD\n");
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD\n");
          return bRC_Error;
       }
       io->status = fread(io->buf, 1, io->count, p_ctx->fd);
-//    printf("bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
+//    bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_READ buf=%p len=%d\n", io->buf, io->status);
       if (io->status == 0 && ferror(p_ctx->fd)) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, 
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
+            "Pipe read error: ERR=%s\n", strerror(errno));
+         bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
             "Pipe read error: ERR=%s\n", strerror(errno));
-//       printf("Error reading pipe\n");
          return bRC_Error;
       }
       break;
 
    case IO_WRITE:
       if (!p_ctx->fd) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "Logic error: NULL write FD\n");
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD\n");
          return bRC_Error;
       }
 //    printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d\n", p_ctx->fd, io->buf, io->count);
       io->status = fwrite(io->buf, 1, io->count, p_ctx->fd);
 //    printf("bpipe-fd: IO_WRITE buf=%p len=%d\n", io->buf, io->status);
       if (io->status == 0 && ferror(p_ctx->fd)) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, 
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, 
             "Pipe write error\n");
-//       printf("Error writing pipe\n");
+         bfuncs->DebugMessage(ctx, fi, li, dbglvl, 
+            "Pipe read error: ERR=%s\n", strerror(errno));
          return bRC_Error;
       }
       break;
 
    case IO_CLOSE:
       if (!p_ctx->fd) {
-         bfuncs->JobMessage(ctx, __FILE__, __LINE__, M_FATAL, 0, "Logic error: NULL FD\n");
+         bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close\n");
          return bRC_Error;
       }
       io->status = pclose(p_ctx->fd);
@@ -466,18 +421,36 @@ static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
    return bRC_OK;
 }
 
+/*
+ * Bacula is notifying us that a plugin name string was found, and
+ *   passing us the plugin command, so we can prepare for a restore.
+ */
 static bRC startRestoreFile(bpContext *ctx, const char *cmd)
 {
 // printf("bpipe-fd: startRestoreFile cmd=%s\n", cmd);
    return bRC_OK;
 }
 
+/*
+ * Bacula is notifying us that the plugin data has terminated, so
+ *  the restore for this particular file is done.
+ */
 static bRC endRestoreFile(bpContext *ctx)
 {
 // printf("bpipe-fd: endRestoreFile\n");
    return bRC_OK;
 }
 
+/*
+ * This is called during restore to create the file (if necessary)
+ * We must return in rp->create_status:
+ *   
+ *  CF_ERROR    -- error
+ *  CF_SKIP     -- skip processing this file
+ *  CF_EXTRACT  -- extract the file (i.e.call i/o routines)
+ *  CF_CREATED  -- created, but no content to extract (typically directories)
+ *
+ */
 static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
 {
 // printf("bpipe-fd: createFile\n");
@@ -486,15 +459,108 @@ static bRC createFile(bpContext *ctx, struct restore_pkt *rp)
    }
    strncpy(((struct plugin_ctx *)ctx->pContext)->where, rp->where, 513);
    ((struct plugin_ctx *)ctx->pContext)->replace = rp->replace;
+   rp->create_status = CF_EXTRACT;
    return bRC_OK;
 }
 
+/*
+ * We will get here if the File is a directory after everything
+ * is written in the directory.
+ */
 static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
 {
 // printf("bpipe-fd: setFileAttributes\n");
    return bRC_OK;
 }
 
+/*************************************************************************
+ * Apply codes in writer command:
+ * %w -> "where"
+ * %r -> "replace"
+ *
+ * Replace:
+ * 'always' => 'a', chr(97)
+ * 'ifnewer' => 'w', chr(119)
+ * 'ifolder' => 'o', chr(111)
+ * 'never' => 'n', chr(110)
+ *
+ * This function will allocate the required amount of memory with malloc.
+ * Need to be free()d manually.
+ * Inspired by edit_job_codes in lib/util.c
+ */
+
+static char *apply_rp_codes(struct plugin_ctx * p_ctx)
+{
+   char *p, *q;
+   const char *str;
+   char add[10];
+   int w_count = 0, r_count = 0;
+   char *omsg;
+
+   char *imsg = p_ctx->writer;
+
+   if (!imsg) {
+      return NULL;
+   }
+
+   if ((p = imsg)) {
+      while ((q = strstr(p, "%w"))) {
+         w_count++;
+         p=q+1;
+      }
+
+      p = imsg;
+      while ((q = strstr(p, "%r"))) {
+         r_count++;
+         p=q+1;
+      }
+   }
+
+   /* Required mem: 
+    * len(imsg) 
+    * + number of "where" codes * (len(where)-2) 
+    * - number of "replace" codes
+    */
+   omsg = (char*)malloc(strlen(imsg) + (w_count * (strlen(p_ctx->where)-2)) - r_count + 1);
+   if (!omsg) {
+      fprintf(stderr, "Out of memory.");
+      return NULL;
+   }
+
+   *omsg = 0;
+   //printf("apply_rp_codes: %s\n", imsg);
+   for (p=imsg; *p; p++) {
+      if (*p == '%') {
+         switch (*++p) {
+         case '%':
+            str = "%";
+            break;
+         case 'w':
+             str = p_ctx->where;
+             break;
+         case 'r':
+            snprintf(add, 2, "%c", p_ctx->replace);
+            str = add;
+            break;
+         default:
+            add[0] = '%';
+            add[1] = *p;
+            add[2] = 0;
+            str = add;
+            break;
+         }
+      } else {
+         add[0] = *p;
+         add[1] = 0;
+         str = add;
+      }
+      //printf("add_str %s\n", str);
+      strcat(omsg, str);
+      //printf("omsg=%s\n", omsg);
+   }
+   return omsg;
+}
+
 
 #ifdef __cplusplus
 }