zoukankan      html  css  js  c++  java
  • Bacula Plugins

    1. loadPlugin

    插件通过加载动态库loadPlugin函数开始,此函数包括bacula的回调和Plugin的注册

    bacula的回调

    typedef struct s_baculaFuncs {
       uint32_t size;
       uint32_t version;
       bRC (*registerBaculaEvents)(bpContext *ctx, ...);
       bRC (*getBaculaValue)(bpContext *ctx, bVariable var, void *value);
       bRC (*setBaculaValue)(bpContext *ctx, bVariable var, void *value);
       bRC (*JobMessage)(bpContext *ctx, const char *file, int line,
           int type, utime_t mtime, const char *fmt, ...);
       bRC (*DebugMessage)(bpContext *ctx, const char *file, int line,
           int level, const char *fmt, ...);
       void *(*baculaMalloc)(bpContext *ctx, const char *file, int line,
           size_t size);
       void (*baculaFree)(bpContext *ctx, const char *file, int line, void *mem);
       bRC (*AddExclude)(bpContext *ctx, const char *file);
       bRC (*AddInclude)(bpContext *ctx, const char *file);
       bRC (*AddOptions)(bpContext *ctx, const char *opts);
       bRC (*AddRegex)(bpContext *ctx, const char *item, int type);
       bRC (*AddWild)(bpContext *ctx, const char *item, int type);
       bRC (*NewOptions)(bpContext *ctx);
       bRC (*NewInclude)(bpContext *ctx);
       bRC (*NewPreInclude)(bpContext *ctx);
       bRC (*checkChanges)(bpContext *ctx, struct save_pkt *sp);
       bRC (*AcceptFile)(bpContext *ctx, struct save_pkt *sp); /* Need fname and statp */
    } bFuncs;
    
    bfuncs->getBaculaValue(ctx, bVarJobId, (void *)&JobId);     //获取相应插件的一些信息
    bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: JobId %d
    ", JobId);  //打印到窗口

    详细参考:手册或官网

    fd Plugin

    sd Plugin或dir Plugin各不同

    typedef struct s_pluginFuncs {
       uint32_t size;
       uint32_t version;
       bRC (*newPlugin)(bpContext *ctx);
       bRC (*freePlugin)(bpContext *ctx);
       bRC (*getPluginValue)(bpContext *ctx, pVariable var, void *value);
       bRC (*setPluginValue)(bpContext *ctx, pVariable var, void *value);
       bRC (*handlePluginEvent)(bpContext *ctx, bEvent *event, void *value);
       bRC (*startBackupFile)(bpContext *ctx, struct save_pkt *sp);
       bRC (*endBackupFile)(bpContext *ctx);
       bRC (*startRestoreFile)(bpContext *ctx, const char *cmd);
       bRC (*endRestoreFile)(bpContext *ctx);
       bRC (*pluginIO)(bpContext *ctx, struct io_pkt *io);
       bRC (*createFile)(bpContext *ctx, struct restore_pkt *rp);
       bRC (*setFileAttributes)(bpContext *ctx, struct restore_pkt *rp);
       bRC (*checkFile)(bpContext *ctx, char *fname);
    } pFuncs;

    注册到bacula之后,bacula会按着不同的需求去回调

    2. 插件配置

    bpipe-dir.so

    以下这种方式,bacula会自动加载bpipe-dir.so

    //默认加载路径配置
    # bacula-fd.conf
    FileDaemon {
        Plugin Directory = /usr/local/lib/
    }  
    //bpipe配置
    # vi bacula-dir.conf
    FileSet {
        Name = "Full Set"
        Include {
            Options {
                signature = MD5    
                Plugin = "bpipe:..."
            }
            File = /home
        } 
    }

    注:

    • Plugin如果写到Include,则备份失败
    • bpipe不能写成bpipe-fd

    此时,bacula会默认先去备份/home目录下的所有内容

    bpipe-fd.so

    FileSet {
        Name = "Full Set"
        Include {
            Options {
                signature = MD5    
            }
            Plugin = "bpipe:fuse.c:ls:cat >"
        } 
    }

    bpipe:插件名字,也就是bpipe-fd.so动态库
    fuse.c:备份时,存储的名字。恢复时候用到
    ls:备份时,会被打开。可以使管道、文件等,只要是流即可
    cat:还原时,会被打开
    注:

    • Plugin如果写到Options,则不会备份任何数据
    • 不管是重新编译.so,还是修改了.conf,都需要重新启动服务

    此时,fuse.c就是需要备份的文件。reader是pipe-readr,writer是pipe-writer

    3. 备份流程

    //handlePluginEvent()
    
    typedef enum {
      bEventJobStart                        = 1,
      bEventJobEnd                          = 2,
      bEventStartBackupJob                  = 3,
      bEventEndBackupJob                    = 4,
      bEventStartRestoreJob                 = 5,
      bEventEndRestoreJob                   = 6,
      bEventStartVerifyJob                  = 7,
      bEventEndVerifyJob                    = 8,
      bEventBackupCommand                   = 9,
      bEventRestoreCommand                  = 10,
      bEventEstimateCommand                 = 11,
      bEventLevel                           = 12,
      bEventSince                           = 13,
      bEventCancelCommand                   = 14, /* Executed by another thread */
      bEventVssBackupAddComponents          = 15, /* Just before bEventVssPrepareSnapshot */
      bEventVssRestoreLoadComponentMetadata = 16,
      bEventVssRestoreSetComponentsSelected = 17,
      bEventRestoreObject                   = 18,
      bEventEndFileSet                      = 19,
      bEventPluginCommand                   = 20, /* Sent during FileSet creation */
      bEventVssBeforeCloseRestore           = 21,
      bEventVssPrepareSnapshot              = 22,
      bEventOptionPlugin                    = 23,
      bEventHandleBackupFile                = 24, /* Used with Options Plugin */
      bEventComponentInfo                   = 25  /* Plugin component */
    } bEventType;

    如果配置的是上述bpipe-fd.so插件

    • 则bacula回调流程handlePluginEvent()
      1 –> 12 –> 20 –> 19 –> 3 –> 9 –> 4 –> 2
    • bEventBackupCommand()很重要
      它会读取Plugin的参数信息bpipe:之后的内容
    • 一切都配置完成后,在3 –> 4之间,也会有I/O读写操作
    //pluginIO()
    
    enum {
       IO_OPEN = 1,
       IO_READ = 2,
       IO_WRITE = 3,
       IO_CLOSE = 4,
       IO_SEEK = 5
    };

    备份的话,流程就是 1 –> 2 –> 4,如果一次读不完,则有多次2

    详细参考:main手册

    4. 实例

    bRC loadPlugin(bInfo *lbinfo, bFuncs *lbfuncs, pInfo **pinfo, pFuncs **pfuncs)
    {
       bfuncs = lbfuncs;                  /* set Bacula funct pointers */
       binfo  = lbinfo;
       *pinfo  = &pluginInfo;             /* return pointer to our info */
       *pfuncs = &pluginFuncs;            /* return pointer to our functions */
    
       return bRC_OK;
    }
    
    bRC unloadPlugin()
    {
       return bRC_OK;
    }
    
    static bRC newPlugin(bpContext *ctx)
    {
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: newPlugin
    ");
    
       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;
    }
    
    static bRC freePlugin(bpContext *ctx)
    {
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: freePlugin
    ");
    
       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;
    }
    
    static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
    {
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: handlePluginEvent %d
    ", event->eventType);
    
       struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
       if (!p_ctx) {
          return bRC_Error;
       }
    
       switch (event->eventType) {
       case bEventPluginCommand:
          bfuncs->DebugMessage(ctx, fi, li, dbglvl,
                               "bpipe-fd: PluginCommand=%s
    ", (char *)value);
          break;
       case bEventJobStart:
            bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: bEventJobStart=%s
    ", (char *)value); 
            break;
       case bEventJobEnd:
          break;
       case bEventStartBackupJob:
          break;
       case bEventEndBackupJob:
          break;
       case bEventLevel:
          break;
       case bEventSince:
          break;
       case bEventStartRestoreJob:
          break;
       case bEventEndRestoreJob:
          break;
       case bEventRestoreCommand:
       case bEventEstimateCommand:
       case bEventBackupCommand:
          char *p;
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: value=%s
    ", (char *)value);
          p_ctx->cmd = strdup((char *)value);
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: cmd=%c
    ", *p_ctx->cmd);
          p = strchr(p_ctx->cmd, ':');
          if (!p) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Plugin terminator not found: %s
    ", (char *)value);
             return bRC_Error;
          }
          *p++ = 0;           /* terminate plugin */
          p_ctx->fname = p;
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: fname=%c
    ", *p_ctx->fname);
          p = strchr(p, ':');
          if (!p) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "File terminator not found: %s
    ", (char *)value);
             return bRC_Error;
          }
          *p++ = 0;           /* terminate file */
          p_ctx->reader = p;
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: reader=%c
    ", *p_ctx->reader);
          p = strchr(p, ':');
          if (!p) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Reader terminator not found: %s
    ", (char *)value);
             return bRC_Error;
          }
          *p++ = 0;           /* terminate reader string */
          p_ctx->writer = p;
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: writer=%c
    ", *p_ctx->writer);
          break;
    
       default:
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: unknown event
    ");
    //  bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: unknown event%s
    ");      //一点小小的语法错误,运行才发现出来
          break;
       }
       return bRC_OK;
    }
    
    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;
       }
    
       bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: startBackupFile%s
    ", p_ctx->fname);
    
       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;
       sp->statp.st_atime = now;
       sp->statp.st_size = -1;
       sp->statp.st_blksize = 4096;
       sp->statp.st_blocks = 1;
       p_ctx->backup = true;
    
       return bRC_OK;
    }
    
    static bRC endBackupFile(bpContext *ctx)
    {
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: endBackupFile
    ");
       /*
        * We would return bRC_More if we wanted startBackupFile to be
        * called again to backup another file
        */
       return bRC_OK;
    }
    
    static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
    {
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: pluginIO %d
    ", io->func);
    
       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:        //需要的是fname 其他为空
          bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: fname %s
    ", io->fname);
          if (io->flags & (O_CREAT | O_WRONLY)) {
             char *writer_codes = apply_rp_codes(p_ctx);
             p_ctx->fd = popen(writer_codes, "w");
             bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: IO_OPEN fd=%d writer=%s
    ",
                 p_ctx->fd, writer_codes);
             if (!p_ctx->fd) {
                io->io_errno = errno;
                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
                   "Open pipe writer=%s failed: ERR=%s
    ", writer_codes, strerror(errno));
                if (writer_codes) {
                   free(writer_codes);
                }
                return bRC_Error;
             }
             if (writer_codes) {
                free(writer_codes);
             }
          } else {
             p_ctx->fd = popen(p_ctx->reader, "r");
             bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: IO_OPEN fd=%p reader=%s
    ", p_ctx->fd, p_ctx->reader);
             if (!p_ctx->fd) {
                io->io_errno = errno;
                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
                   "Open pipe reader=%s failed: ERR=%s
    ", p_ctx->reader, strerror(errno));
                return bRC_Error;
             }
          }
          sleep(1);                 /* let pipe connect */
          break;
    
       case IO_READ:    //需要的是count 其他为空
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: count %d 
    ", io->count);
          if (!p_ctx->fd) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL read FD
    ");
             return bRC_Error;
          }
          io->status = fread(io->buf, 1, io->count, p_ctx->fd);
        bfuncs->JobMessage(ctx, fi, li, M_INFO, 0, "bpipe-fd: IO_READ buf=%p len=%d
    ", io->buf, io->status);
          if (io->status == 0 && ferror(p_ctx->fd)) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
                "Pipe read error: ERR=%s
    ", strerror(errno));
             return bRC_Error;
          }
          break;
    
       case IO_WRITE:
          if (!p_ctx->fd) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL write FD
    ");
             return bRC_Error;
          }
        printf("bpipe-fd: IO_WRITE fd=%p buf=%p len=%d
    ", p_ctx->fd, io->buf, io->count);
          io->status = fwrite(io->buf, 1, io->count, p_ctx->fd);
          if (io->status == 0 && ferror(p_ctx->fd)) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0,
                "Pipe write error
    ");
             return bRC_Error;
          }
          break;
    
       case IO_CLOSE:       //什么都不需要,直接关闭
          if (!p_ctx->fd) {
             bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "Logic error: NULL FD on bpipe close
    ");
             return bRC_Error;
          }
          io->status = pclose(p_ctx->fd);
    
          /* Problem during execution */
          if (io->status < 0) {
             io->io_errno = errno;
             bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "bpipe-fd: Error closing stream for pseudo file %s: %d (%s)
    ",
                                p_ctx->fname, io->status, strerror(errno));
    
          /* Problem inside the subprogram */
          } else if (io->status > 0) {
             int status=1;
             if (WIFEXITED(io->status)) {    /* process exit()ed */
                status = WEXITSTATUS(io->status);
    
             } else if (WIFSIGNALED(io->status)) {  /* process died */
    #ifndef HAVE_WIN32
                status = WTERMSIG(io->status);
    #endif
             }
             bfuncs->DebugMessage(ctx, fi, li, dbglvl, "bpipe-fd: exit=%d
    ", io->status);
    //         bfuncs->JobMessage(ctx, fi, li, M_ERROR, 0, "bpipe-fd: Error closing stream for pseudo file %s: exit %d
    ", p_ctx->fname, status);
          }
          break;
    
       case IO_SEEK:
          io->offset = p_ctx->offset;
          break;
       }
       return bRC_OK;
    }
    
    static bRC startRestoreFile(bpContext *ctx, const char *cmd)
    {
       return bRC_OK;
    }
    
    static bRC endRestoreFile(bpContext *ctx)
    {
       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)
    {
       if (strlen(rp->where) > 512) {
          printf("Restore target dir too long. Restricting to first 512 bytes.
    ");
       }
       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)
    {
       return bRC_OK;
    }
    
    /* When using Incremental dump, all previous dumps are necessary */
    static bRC checkFile(bpContext *ctx, char *fname)
    {
       return bRC_OK;
    }
    
  • 相关阅读:
    Changing Icon File Of Push Button At Runtime In Oracle Forms 6i
    Set Font Properties On Mouse Hover Of Push Button And Text Items At Run time In Oracle Forms
    Change An Item Property Using Set_Item_Property In Oracle Forms
    Calling / Running a report in Oracle forms 10g / 11g
    Change Or Set Report Object Property At Run Time In Oracle Forms Using Set_Report_Object_Property Command
    Refresh / Updating a form screen in Oracle D2k Forms 6i
    Know How And When To Use System.Message_Level To Control Messages In Oracle Forms
    Perform Cut Copy Paste Operations Using Cut_Region Copy_Region Paste_Region Commands In Oracle Forms
    CHECKBOX_CHECKED built-in in Oracle D2k Forms
    Limiting To Select Only 5 Check Boxes Out Of Ten In Oracle Forms
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709967.html
Copyright © 2011-2022 走看看