Moving this thread back onto the list.

On Thu, Jan 21, 2010 at 08:50, Kern Sibbald <[email protected]> wrote:

> No problem.  I have been working on Bacula for more than 10 years now, so a
> few more days to see what you have created is no problem :-)

There it is. Once again, this is under development and DWIM. Use, or
look at, at your own risk :)
Basically, it removes the ability of the SD to run any and all commands
on a client.


Also attached is a patch which I propose to be added ASAP. If there is
no plugin handling a command, it will mark the backup job as
erroneous instead of OK.


All code in this email is released under GPLv2+. If you need any other
licences on top let me know (no idea how hard the licence requirements
are so I thought it would be better to state it explicitly).


Richard
#include "bacula.h"
#include "fd_plugins.h"

#undef malloc
#undef free
#undef strdup

#ifdef CONFIG_FILE
#else
#define CONFIG_FILE "/usr/local/globalways/bacula/etc/client_mysql_credentials"
#endif

#ifdef RESTORE_FILE
#else
#define RESTORE_FILE "/root/mysql-restore.sql"
#endif

#define PLUGIN_TERMINATOR "mysql"
#define MAXLEN 5000

#define CMDSTRLEN 70000*sizeof(char)
#define DBPSTRLEN 62500*sizeof(char)


#define fi __FILE__
#define li __LINE__
#define DEBUG_LEVEL 150

/*Struktur Parameter Config-File*/
struct backup_parameters
{
        char username[MAXLEN];
        char password[MAXLEN];
        char options[MAXLEN];
}
backup_parameters;

/*Trimmfunktion für Leerzeichen in Configfile*/
char * trim (char * s)
{
        char *s1 = s, *s2 = &s[strlen (s) - 1];
        while ((isspace (*s2)) && (s2 >= s1))
        {
                s2--;
        }
        *(s2+1) = '\0';
        while ((isspace (*s1)) && (s1 < s2))
        {
                s1++;
        }
        strcpy (s, s1);
        return s;
}

/*Config-File Parser*/
int parse_config (bFuncs *bfuncs,bpContext *ctx, struct backup_parameters * parms)
{
        char *s, buff[256];
        
        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: using configfile '%s'\n", CONFIG_FILE);
        
        FILE *fp = fopen (CONFIG_FILE, "r");
        if (fp == NULL)
        {
                return(0);
        }
        while ((s = fgets (buff, sizeof buff, fp)) != NULL)
        {
                if (buff[0] == '\n' || buff[0] == '#')
                {
                        continue;
                }
                char name[MAXLEN], value[MAXLEN];
                s = strtok(buff, "=");
                if (s==NULL)
                {
                        continue;
                }
                strncpy (name, s, MAXLEN);
                s = strtok(NULL, "=");
                if (s==NULL)
                {
                        continue;
                }
                strncpy (value, s, MAXLEN);
                trim (value);
                if (strcmp(name, "username")==0)
                {
                        strncpy (parms->username, value, MAXLEN);
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: config: username='%s'\n", value);
                }
                else if (strcmp(name, "password")==0)
                {
                        strncpy (parms->password, value, MAXLEN);
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: config: password='%s'\n", value);
                }
                else if (strcmp(name, "options")==0)
                {
                        strncpy (parms->options, value, MAXLEN);
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: config: options='%s'\n", value);
                }
                else
                {
                        break;
                }
        }
        fclose(fp);
        return(1);
}

#define TRUE    1
#define FALSE   0

/*Entfernen von Sonderzeichen, zur Erhoehung der Sicherheit des Backup-Kommandos*/
char * removechars(bFuncs *bfuncs,bpContext *ctx, char *src,char *key)
{
        char   *dest;
        size_t len_src;
        size_t len_key;
        int    found;

        unsigned int i;
        unsigned int j;
        unsigned int k;

        i        = 0;
        j        = 0;
        k        = 0;
        len_src  = 0;
        len_key  = 0;
        dest     = NULL;

        len_src = strlen(src);
        len_key = strlen(key);
        
        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: removing special chars '%s' from string '%s'\n", CONFIG_FILE);

        dest =(char *)malloc(sizeof(char)*len_src + 1);
        if (NULL == dest)
        {
                return(0);
        }
        memset(dest, 0x00, sizeof(char)*len_src + 1);
        for(i = 0; i < len_src; i++)
        {
                found = FALSE;
                for (j = 0;j < len_key;j++)
                {
                        if (src[i] == key[j])
                        {
                                found = TRUE;
                        }
                }
                if (FALSE == found)
                {
                        dest[k] = src[i];
                        k++;
                }
        }
        
        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: removing special chars '%s' from string '%s': '%s'\n", key, src, dest);
        
        return(dest);
}


#ifdef __cplusplus
extern "C" {
#endif

//        static const int dbglvl = DEBUG_LEVEL;

#define PLUGIN_LICENSE      "Bacula GPLv2"
#define PLUGIN_AUTHOR       "Globalways AG"
#define PLUGIN_DATE         "2009-01-18"
#define PLUGIN_VERSION      "1"
#define PLUGIN_DESCRIPTION  "Bacula mysqldump file daemon plugin"

        /*Zeiger auf Bacula-Funktionen*/
        static bFuncs *bfuncs = NULL;
        static bInfo  *binfo = NULL;

        /*Referenzierte Funktionen von Bacula*/
        static bRC newPlugin(bpContext *ctx);
        static bRC freePlugin(bpContext *ctx);
        static bRC getPluginValue(bpContext *ctx, pVariable var, void *value);
        static bRC setPluginValue(bpContext *ctx, pVariable var, void *value);
        static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value);
        static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp);
        static bRC endBackupFile(bpContext *ctx);
        static bRC pluginIO(bpContext *ctx, struct io_pkt *io);
        static bRC startRestoreFile(bpContext *ctx, const char *cmd);
        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);

        /*Plugin Informationen*/
        static pInfo pluginInfo = {
                        sizeof(pluginInfo),
                        FD_PLUGIN_INTERFACE_VERSION,
                        FD_PLUGIN_MAGIC,
                        PLUGIN_LICENSE,
                        PLUGIN_AUTHOR,
                        PLUGIN_DATE,
                        PLUGIN_VERSION,
                        PLUGIN_DESCRIPTION,
        };

        /*Plugin Startpunkte*/
        static pFuncs pluginFuncs = {
                        sizeof(pluginFuncs),
                        FD_PLUGIN_INTERFACE_VERSION,

                        newPlugin,
                        freePlugin,
                        getPluginValue,
                        setPluginValue,
                        handlePluginEvent,
                        startBackupFile,
                        endBackupFile,
                        startRestoreFile,
                        endRestoreFile,
                        pluginIO,
                        createFile,
                        setFileAttributes
        };

        /*Plugin privater Kontext*/
        struct plugin_ctx {
                boffset_t offset;
                FILE *fd;                          /* pipe file descriptor */
                bool backup;                       /* set for backup (not needed) */
                char *cmd;                         /* plugin command line */
                char *fname;                       /* filename to "backup/restore" */
                char *reader;                      /* reader program for backup */
                char *writer;                      /* writer program for backup */

                char where[1024];
                int replace;
        };

        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;
        }

        /*Neue Instanz des Plugins erstellen, Speicherbereich reservieren*/
        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;
        }

        /*Plugin aus Speicher entfernen, eigene Daten entfernen*/
        static bRC freePlugin(bpContext *ctx)
        {
                struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
                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 getPluginValue(bpContext *ctx, pVariable var, void *value)
        {
                return bRC_OK;
        }

        static bRC setPluginValue(bpContext *ctx, pVariable var, void *value)
        {
                return bRC_OK;
        }

        static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
        {
                struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;

                switch (event->eventType)
                {
                case bEventJobStart:
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: JobStart=%s\n", (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:
                        /*Durchfall erwuenscht*/
                case bEventBackupCommand:
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: bEventBackupCommand='%s'\n", (char *)value);

                        char *configfile;
                        configfile = CONFIG_FILE;

                        char *restorefile;
                        restorefile = RESTORE_FILE;

                        /*Speicher für Config-Parameter reservieren, Config-File einlesen*/
                        struct backup_parameters configparms;
                        
                        if(parse_config(bfuncs, ctx, &configparms)!=1)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Error reading config-file: '%s'", configfile);
                        }

                        char **databases;
                        char *databasesparm;
                        char *removalchars;
                        char *removalchars_dbparms;
                        char *cmdstring;
                        char *p;

                        /*Zeichen, die entfernt werden sollen, aus Sicherheitsgruenden*/
                        removalchars = "&;`'\\\"|*?~<>^()[]{}$\n\r#!\t\v\f=";
                        removalchars_dbparms = "&;`'\\\"|?~<>^()[]{}$\n\r#!\t\v\f=";

                        /*Parameter setzen, aus Config-File, sowie uebergebener Parameter und Parameter pruefen*/
                        cmdstring = (char *)malloc(CMDSTRLEN);
                        databasesparm = (char *)malloc(DBPSTRLEN);
                        
                        if(!cmdstring || !databasesparm)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Could not allocate memory!\n");
                                return bRC_Error;
                        }

                        if(strlen(configparms.username)!=0) { // sicheren String erstellen fuer Benutzername
                                strncpy(configparms.username, removechars(bfuncs, ctx, configparms.username, removalchars), MAXLEN*sizeof(char));
                        } else {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Username not found: '%s'\n", configfile);
                        }

                        if(strlen(configparms.password)!=0) { // sicheren String erstellen fuer Passwort
                                strncpy(configparms.password, removechars(bfuncs, ctx, configparms.password, removalchars), MAXLEN*sizeof(char));
                        } else if(strcmp(configparms.password, "blank")==0)     {
                                /*Es soll kein Passwort uebergeben werden -> nichts zu tun, da keine Zeichen entfernt werden muessen*/
                        } else {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Password not found: '%s'\n", configfile);
                        }

                        if(strlen(configparms.options)!=0) { // sicheren String erstellen fuer die Optionen
                                strncpy(configparms.options, removechars(bfuncs, ctx, configparms.options, removalchars), MAXLEN*sizeof(char));
                        } else {
                                strcpy(configparms.options, " ");
                        }

                        /* Pruefung des Aufbaus des vom Director uebergebenen Strings mit Parametern */
                        strncpy(cmdstring, (char *) value, CMDSTRLEN);
                        p = strtok(cmdstring, ":");
                        if (p == NULL) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Missing plugin parameters!\n", (char *) value);
                                return bRC_Error;
                        }
                        strcpy(cmdstring, p);
                        p = NULL;
                        if (strcmp(cmdstring, PLUGIN_TERMINATOR) != 0) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Plugin terminator not found: '%s'\n", (char *) value);
                                return bRC_Error;
                        }
                        p = strtok(NULL, ":");
                        if (p == NULL) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Database names missing!\n", (char *) value);
                                return bRC_Error;
                        }
                        strcpy(cmdstring, p);
                        p = NULL;
                        strcpy(cmdstring, removechars(bfuncs, ctx, cmdstring, removalchars_dbparms));
                        strncpy(databasesparm, cmdstring, DBPSTRLEN);
                        if (strlen(databasesparm) == 0) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Database names missing: '%s'\n", (char *) value);
                                free(cmdstring);
                                return bRC_Error;
                        }
                        strcpy(cmdstring, "");

                        /*Kommando-String aufbauen, nachdem Parameter geprueft wurden*/
                        strcat(
                                        cmdstring,
                                        "mysql:/__MYSQL__/mysql-backup.sql:/usr/bin/mysqldump --disable-keys --quote-names --single-transaction --complete-insert --extended-insert --create-options --user=\""
                        );
                        strcat(cmdstring, configparms.username);
                        strcat(cmdstring, "\"");
                        if (strcmp(configparms.password, "blank") != 0) {
                                strcat(cmdstring, " --password=\"");
                                strcat(cmdstring, configparms.password);
                                strcat(cmdstring, "\"");
                        }
                        strcat(cmdstring, " ");
                        strcat(cmdstring, configparms.options);
                        if (strcmp(databasesparm, "all-databases") == 0 || strcmp(databasesparm, "*") == 0) {
                                strcat(cmdstring, " --all-databases ");
                        } else {
                                int i;
                                i = 0;
                                databases = (char **) malloc(62500 * sizeof(char*)); //TODO: US: UNNÖTIGER MALLOC
                                databases[i] = (char *) malloc(250 * sizeof(char));
                                if (!databases || !databases[i]) {
                                        bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Could not allocate memory!\n");
                                        return bRC_Error;
                                }
                                p = strtok(databasesparm, ",");
                                if (p == NULL) {
                                        bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Database names not correctly specified!\n", (char *) value);
                                        return bRC_Error;
                                }
                                strncpy(databases[i], p, 250 * sizeof(char));
                                p = NULL;
                                i++;
                                for (;;) {
                                        char *m;
                                        m = strtok(NULL, ",");
                                        if (m == NULL) {
                                                break;
                                        }
                                        databases[i] = (char *) malloc(250 * sizeof(char));
                                        if (!databases[i]) {
                                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Could not allocate memory!\n");
                                                return bRC_Error;
                                        }
                                        strncpy(databases[i], m, 250 * sizeof(char));
                                        i++;
                                }
                                strcpy(databasesparm, "");
                                while (i > 0) { // FIXED, US, mögliche endlosschleife
                                        i--;
                                        strcat(databasesparm, databases[i]);
                                        strcat(databasesparm, " ");
                                        free(databases[i]);
                                }
                                free(databases);

                                strcat(cmdstring, " --databases ");
                                strcat(cmdstring, databasesparm);
                        }
                        strcat(cmdstring, ":/bin/cat - > ");
                        strcat(cmdstring, restorefile);
                        //bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "!!!! DEBUG CMDSTRING: %s\n", cmdstring);

                        free(databasesparm);

                        /*Kommando-String parsen und Elemente in Bacula-Funktionsspeicher uebergeben*/
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: bEventBackupCommand cmdstring='%s'\n", cmdstring);
                        
                        p_ctx->cmd = strdup((char *) cmdstring);
                        free(cmdstring);
                        p = strchr(p_ctx->cmd, ':');
                        if (!p) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Plugin terminator not found: '%s'\n", cmdstring);
                                return bRC_Error;
                        }
                        *p++ = 0; /* terminate plugin */
                        p_ctx->fname = p;
                        p = strchr(p, ':');
                        if (!p) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: File terminator not found: '%s'\n", cmdstring);
                                return bRC_Error;
                        }
                        *p++ = 0; /* terminate file */
                        p_ctx->reader = p;
                        p = strchr(p, ':');
                        if (!p) {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Reader terminator not found: '%s'\n", cmdstring);
                                return bRC_Error;
                        }
                        *p++ = 0; /* terminate reader string */
                        p_ctx->writer = p;
                        break;

                default:
                        break;
                }
                return bRC_OK;
        }

        static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
        {
                struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;
                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)
        {
                return bRC_OK;
        }


        static bRC pluginIO(bpContext *ctx, struct io_pkt *io)
        {
                struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext;

                io->status = 0;
                io->io_errno = 0;

                switch(io->func)
                {
                case IO_OPEN:
                        bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: IO_OPEN\n");
                        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, DEBUG_LEVEL, "mysql-fd: IO_OPEN fd=%d writer=%s\n", p_ctx->fd, writer_codes);
                                if (!p_ctx->fd)
                                {
                                        io->io_errno = errno;
                                        bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Open pipe writer=%s failed: ERR=%s\n", 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->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-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, fi, li, M_FATAL, 0, "mysql-fd: Open pipe reader=%s failed: ERR=%s\n", p_ctx->reader, strerror(errno));
                                        return bRC_Error;
                                }
                        }
                        sleep(1);                 /* let pipe connect */
                        break;

                case IO_READ:
                        if (!p_ctx->fd)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Logic error: NULL read FD\n");
                                return bRC_Error;
                        }
                        io->status = fread(io->buf, 1, io->count, p_ctx->fd);
                        if (io->status == 0 && ferror(p_ctx->fd))
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Pipe read error: ERR=%s\n", strerror(errno));
                                bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: Pipe read error: ERR=%s\n", strerror(errno));
                                return bRC_Error;
                        }
                        break;

                case IO_WRITE:
                        if (!p_ctx->fd)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Logic error: NULL write FD\n");
                                return bRC_Error;
                        }
                        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, "mysql-fd: Pipe write error\n");
                                bfuncs->DebugMessage(ctx, fi, li, DEBUG_LEVEL, "mysql-fd: Pipe read error: ERR=%s\n", strerror(errno));
                                return bRC_Error;
                        }
                        break;

                case IO_CLOSE:
                        if (!p_ctx->fd)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: Logic error: NULL FD on bpipe close\n");
                                return bRC_Error;
                        }
                        io->status = pclose(p_ctx->fd);
                        if(io->status != 0)
                        {
                                bfuncs->JobMessage(ctx, fi, li, M_FATAL, 0, "mysql-fd: !!!!!! ->Error returned by command executed for piping. Check username, password, configuration...!!!!!!<-\n");
                                return bRC_Error;
                        }
                        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("mysql-fd: Restore target dir too long. Restricting to first 512 bytes.\n");
                }
                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;
        }

        static bRC setFileAttributes(bpContext *ctx, struct restore_pkt *rp)
        {
                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;
                        }
                }

                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;
                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;
                        }
                        strcat(omsg, str);
                }
                return omsg;
        }

#ifdef __cplusplus
}
#endif

Index: src/filed/fd_plugins.c
===================================================================
--- src/filed/fd_plugins.c	(revision 1400)
+++ src/filed/fd_plugins.c	(revision 1401)
@@ -302,7 +302,7 @@
       }
       goto bail_out;
    }
-   Jmsg1(jcr, M_ERROR, 0, "Command plugin \"%s\" not found.\n", cmd);
+   Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" not found.\n", cmd);
 
 bail_out:
    jcr->cmd_plugin = false;
------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Bacula-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bacula-devel

Reply via email to