X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Ffd_plugins.c;h=066541b2c508ea80ba976ad4753de40cef491480;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=2e4767ccb2fad1821903bc43b8e0a7717c38d700;hpb=a6cbf13edea14e16e1331f1ed62a4ad023ea4dcf;p=bacula%2Fbacula diff --git a/bacula/src/filed/fd_plugins.c b/bacula/src/filed/fd_plugins.c index 2e4767ccb2..066541b2c5 100644 --- a/bacula/src/filed/fd_plugins.c +++ b/bacula/src/filed/fd_plugins.c @@ -1,29 +1,20 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2007-2012 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. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version three of the GNU Affero General Public - License as published by the Free Software Foundation, which is - listed in the file LICENSE. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - - Bacula® is a registered trademark of Kern Sibbald. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2015 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. */ /** * Main program to test loading and running Bacula plugins. @@ -38,7 +29,6 @@ extern CLIENT *me; extern DLL_IMP_EXP char *exepath; extern DLL_IMP_EXP char *version; extern DLL_IMP_EXP char *dist_name; -extern DLL_IMP_EXP int beef; const int dbglvl = 150; #ifdef HAVE_WIN32 @@ -51,7 +41,7 @@ extern int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level); extern bool check_changes(JCR *jcr, FF_PKT *ff_pkt); /* Function pointers to be set here */ -extern DLL_IMP_EXP int (*plugin_bopen)(BFILE *bfd, const char *fname, int flags, mode_t mode); +extern DLL_IMP_EXP int (*plugin_bopen)(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode); extern DLL_IMP_EXP int (*plugin_bclose)(BFILE *bfd); extern DLL_IMP_EXP ssize_t (*plugin_bread)(BFILE *bfd, void *buf, size_t count); extern DLL_IMP_EXP ssize_t (*plugin_bwrite)(BFILE *bfd, void *buf, size_t count); @@ -86,7 +76,7 @@ static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp); * These will be plugged into the global pointer structure for * the findlib. */ -static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode); +static int my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode); static int my_plugin_bclose(BFILE *bfd); static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count); static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count); @@ -96,7 +86,7 @@ static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence); /* Bacula info */ static bInfo binfo = { sizeof(bInfo), - FD_PLUGIN_INTERFACE_VERSION + FD_PLUGIN_INTERFACE_VERSION }; /* Bacula entry points */ @@ -122,7 +112,7 @@ static bFuncs bfuncs = { baculaAcceptFile }; -/* +/* * Bacula private context */ struct bacula_ctx { @@ -148,7 +138,7 @@ static bool for_this_plugin(Plugin *plugin, char *name, int len) } if (strcmp("*all*", name) == 0) { /* new v6.0 name for VSS job metadata */ return true; - } + } /* Check if this is the correct plugin */ if (len == plugin->file_len && strncmp(plugin->file, name, len) == 0) { return true; @@ -180,7 +170,7 @@ bool is_plugin_disabled(JCR *jcr) * Create a plugin event When receiving bEventCancelCommand, this function is * called by an other thread. */ -void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) +void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) { bpContext *plugin_ctx; bEvent event; @@ -192,10 +182,10 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) restore_object_pkt *rop; Dsm_check(999); - if (!bplugin_list || !jcr || !jcr->plugin_ctx_list) { + if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list) { return; /* Return if no plugins loaded */ } - + /* * Some events are sent to only a particular plugin or must be * called even if the job is canceled @@ -225,7 +215,7 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) call_if_canceled = true; /* plugin *must* see this call */ break; case bEventStartRestoreJob: - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { plugin->restoreFileStarted = false; plugin->createFileCalled = false; } @@ -251,19 +241,20 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) * Pass event to every plugin (except if name is set). If name * is set, we pass it only to the plugin with that name. */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { if (!for_this_plugin(plugin, name, len)) { - Dmsg2(dbglvl, "Not for this plugin name=%s NULL=%d\n", + Dmsg2(dbglvl, "Not for this plugin name=%s NULL=%d\n", name, name==NULL?1:0); continue; } /* - * Note, at this point do not change + * Note, at this point do not change * jcr->plugin or jcr->plugin_ctx */ Dsm_check(999); plugin_ctx = &plugin_ctx_list[i]; if (is_plugin_disabled(plugin_ctx)) { + Dmsg1(50, "Plugin %s disabled\n", plugin->file); continue; } if (eventType == bEventEndRestoreJob) { @@ -291,7 +282,7 @@ bool plugin_check_file(JCR *jcr, char *fname) int i; Dsm_check(999); - if (!bplugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + if (!b_plugin_list || !jcr || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { return false; /* Return if no plugins loaded */ } @@ -300,7 +291,7 @@ bool plugin_check_file(JCR *jcr, char *fname) Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId); /* Pass event to every plugin */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; if (is_plugin_disabled(jcr)) { @@ -322,7 +313,7 @@ bool plugin_check_file(JCR *jcr, char *fname) } /* Get the first part of the the plugin command - * systemstate:/@SYSTEMSTATE/ + * systemstate:/@SYSTEMSTATE/ * => ret = 11 * => can use for_this_plugin(plug, cmd, ret); * @@ -371,14 +362,14 @@ static void update_ff_pkt(FF_PKT *ff_pkt, struct save_pkt *sp) ff_pkt->flags &= ~FO_DELTA; /* clean delta sequence number */ ff_pkt->delta_seq = 0; } - + if (sp->flags & FO_OFFSETS) { ff_pkt->flags |= FO_OFFSETS; } else { ff_pkt->flags &= ~FO_OFFSETS; } /* Sparse code doesn't work with plugins - * that use FIFO or STDOUT/IN to communicate + * that use FIFO or STDOUT/IN to communicate */ if (sp->flags & FO_SPARSE) { ff_pkt->flags |= FO_SPARSE; @@ -399,6 +390,7 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) { Plugin *plugin; bRC ret = bRC_Error; + bool found=false; char *cmd = ff_pkt->plugin; int len; int i=0; @@ -418,7 +410,7 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) sp->delta_seq = ff_pkt->delta_seq; sp->accurate_found = ff_pkt->accurate_found; - if (!bplugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); goto bail_out; /* Return if no plugins loaded */ } @@ -428,12 +420,14 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); if (!for_this_plugin(plugin, cmd, len)) { continue; } + found=true; + Dsm_check(999); if (is_plugin_disabled(&plugin_ctx_list[i])) { goto bail_out; @@ -441,10 +435,10 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) jcr->plugin_ctx = &plugin_ctx_list[i]; jcr->plugin = plugin; - - ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], + + ret = plug_func(plugin)->handlePluginEvent(&plugin_ctx_list[i], &event, sp); - + /* TODO: would be better to set this in save_file() */ if (ret == bRC_OK) { jcr->opt_plugin = true; @@ -463,11 +457,14 @@ bRC plugin_option_handle_file(JCR *jcr, FF_PKT *ff_pkt, struct save_pkt *sp) goto bail_out; } /* end foreach loop */ bail_out: + if (!found) { + Jmsg1(jcr, M_FATAL, 0, "Options plugin \"%s\" not found.\n", cmd); + } Dsm_check(999); return ret; } -/** +/** * Sequence of calls for a backup: * 1. plugin_save() here is called with ff_pkt * 2. we find the plugin requested on the command string @@ -494,7 +491,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) POOL_MEM link(PM_FNAME); Dsm_check(999); - if (!bplugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { + if (!b_plugin_list || !jcr->plugin_ctx_list || jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); return 1; /* Return if no plugins loaded */ } @@ -508,12 +505,12 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); if (!for_this_plugin(plugin, cmd, len)) { continue; } - /* + /* * We put the current plugin pointer, and the plugin context * into the jcr, because during save_file(), the plugin * will be called many times and these values are needed. @@ -531,7 +528,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) goto bail_out; } /* Loop getting filenames to backup then saving them */ - while (!jcr->is_job_canceled()) { + while (!jcr->is_job_canceled()) { memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); sp.pkt_end = sizeof(sp); @@ -554,7 +551,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) jcr->plugin_sp = &sp; ff_pkt = jcr->ff; /* - * Copy fname and link because save_file() zaps them. This + * Copy fname and link because save_file() zaps them. This * avoids zaping the plugin's strings. */ ff_pkt->type = sp.type; @@ -590,7 +587,7 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) Dmsg2(dbglvl, "startBackup returned type=%d, fname=%s\n", sp.type, sp.fname); if (sp.object) { Dmsg2(dbglvl, "index=%d object=%s\n", sp.index, sp.object); - } + } /* Call Bacula core code to backup the plugin's file */ save_file(jcr, ff_pkt, true); bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx); @@ -616,7 +613,7 @@ bail_out: } -/** +/** * Sequence of calls for a estimate: * 1. plugin_estimate() here is called with ff_pkt * 2. we find the plugin requested on the command string @@ -639,7 +636,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) ATTR attr; Dsm_check(999); - if (!bplugin_list || !jcr->plugin_ctx_list) { + if (!b_plugin_list || !jcr->plugin_ctx_list) { Jmsg1(jcr, M_FATAL, 0, "Command plugin \"%s\" requested, but is not loaded.\n", cmd); return 1; /* Return if no plugins loaded */ } @@ -653,12 +650,12 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } /* Note, we stop the loop on the first plugin that matches the name */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dmsg4(dbglvl, "plugin=%s plen=%d cmd=%s len=%d\n", plugin->file, plugin->file_len, cmd, len); if (!for_this_plugin(plugin, cmd, len)) { continue; } - /* + /* * We put the current plugin pointer, and the plugin context * into the jcr, because during save_file(), the plugin * will be called many times and these values are needed. @@ -676,7 +673,7 @@ int plugin_estimate(JCR *jcr, FF_PKT *ff_pkt, bool top_level) goto bail_out; } /* Loop getting filenames to backup then saving them */ - while (!jcr->is_job_canceled()) { + while (!jcr->is_job_canceled()) { Dsm_check(999); memset(&sp, 0, sizeof(sp)); sp.pkt_size = sizeof(sp); @@ -778,7 +775,7 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) if (jcr->is_job_canceled()) { return false; } - + if (start) { index++; /* JobFiles not incremented yet */ } @@ -819,7 +816,7 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) * Returns: true if start of stream * false if end of steam */ -bool plugin_name_stream(JCR *jcr, char *name) +bool plugin_name_stream(JCR *jcr, char *name) { char *p = name; char *cmd; @@ -844,7 +841,7 @@ bool plugin_name_stream(JCR *jcr, char *name) cmd = p; } else { /* - * End of plugin data, notify plugin, then clear flags + * End of plugin data, notify plugin, then clear flags */ Dmsg2(dbglvl, "End plugin data plugin=%p ctx=%p\n", jcr->plugin, jcr->plugin_ctx); if (jcr->plugin && jcr->plugin->restoreFileStarted) { @@ -862,7 +859,7 @@ bool plugin_name_stream(JCR *jcr, char *name) if (!plugin_ctx_list) { goto bail_out; } - + /* * After this point, we are dealing with a restore start */ @@ -871,10 +868,10 @@ bool plugin_name_stream(JCR *jcr, char *name) } /* - * Search for correct plugin as specified on the command + * Search for correct plugin as specified on the command */ Dsm_check(999); - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { bEvent event; Dmsg3(dbglvl, "plugin=%s cmd=%s len=%d\n", plugin->file, cmd, len); if (!for_this_plugin(plugin, cmd, len)) { @@ -888,8 +885,8 @@ bool plugin_name_stream(JCR *jcr, char *name) goto bail_out; } Dmsg1(dbglvl, "Restore Command plugin = %s\n", cmd); - event.eventType = bEventRestoreCommand; - if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, + event.eventType = bEventRestoreCommand; + if (plug_func(plugin)->handlePluginEvent(jcr->plugin_ctx, &event, cmd) != bRC_OK) { Dmsg1(dbglvl, "Handle event failed. Plugin=%s\n", cmd); goto bail_out; @@ -939,7 +936,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) int rc; Dsm_check(999); - if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr) || jcr->is_job_canceled()) { + if (!plugin || !plugin_ctx || jcr->is_job_canceled()) { return CF_ERROR; } @@ -960,7 +957,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) rp.RegexWhere = jcr->RegexWhere; rp.replace = jcr->replace; rp.create_status = CF_ERROR; - Dmsg4(dbglvl, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n", + Dmsg4(dbglvl, "call plugin createFile stream=%d type=%d LinkFI=%d File=%s\n", rp.stream, rp.type, rp.LinkFI, rp.ofname); if (rp.attrEx) { Dmsg1(dbglvl, "attrEx=\"%s\"\n", rp.attrEx); @@ -992,6 +989,9 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) return CF_CORE; /* Let Bacula core handle the file creation */ } + /* Use the bfile for plugin */ + set_cmd_plugin(bfd, jcr); + /* Created link or directory? */ if (rp.create_status == CF_CREATED) { return rp.create_status; /* yes, no need to bopen */ @@ -1055,7 +1055,7 @@ bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) rp.create_status = CF_ERROR; plug_func(plugin)->setFileAttributes(jcr->plugin_ctx, &rp); - + if (rp.create_status == CF_CORE) { set_attributes(jcr, attr, ofd); } else { @@ -1069,6 +1069,206 @@ bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } +/* + * The Plugin ACL data backup. We are using a new Plugin callback: + * handleXACLdata() for that. The new callback get a pointer to + * struct xacl_pkt as a main argument which consist of the following + * data: + * xacl.func - could be the one of BACL_BACKUP, BACL_RESTORE, + * BXATTR_BACKUP, BXATTR_RESTORE + * xacl.count - the length of data at the content buffer + * xacl.content - the buffer itself + * The buffer (xacl.content) is supplied by Bacula during restore and has to + * be supplied by a Plugin during backup. + * The new callback should return bRC_OK on success and bRC_Error on + * any error. + * + * in: + * jcr - Job Control Record + * ff_pkt - file save packet + * data is a pointer to variable returned + * out: + * data - the pointer to data buffer returned from plugin + * 0 - Success, no more data to save + * > 0 - Success and the number of bytes returned in **data buffer + * -1 - Error, no acls data to backup + */ +int plugin_backup_acl(JCR *jcr, FF_PKT *ff_pkt, char **data) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_backup_acl\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data) { + return 0; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BACL_BACKUP; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return -1; + } + if (xacl.count > 0){ + /* we have something to save, so prepare return data */ + *data = xacl.content; + return xacl.count; + } + + return 0; +} + +/* + * Called here when Bacula got ACL stream to restore but not every stream but + * a specific one: STREAM_XACL_PLUGIN_ACL which means a plugin has to + * be called. + * + * in: + * jcr - Job Control Record + * data - content to restore + * length - the length of the content to restore + * out: + * true - when successful + * false - on any Error + */ +bool plugin_restore_acl(JCR *jcr, char *data, uint32_t length) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_restore_acl\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data || length == 0) { + return true; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BACL_RESTORE; + xacl.content = data; + xacl.count = length; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return false; + } + + return true; +} + +/* + * The Plugin XATTR data backup. We are using a new Plugin callback: + * handleXACLdata() for that. Check plugin_backup_acl for new callback + * description. + * + * in: + * jcr - Job Control Record + * ff_pkt - file save packet + * data is a pointer to variable returned + * out: + * data - the pointer to data buffer returned from plugin + * 0 - Success, no more data to save + * >0 - Success and the number of bytes returned in **data buffer + * <0 - Error + */ +int plugin_backup_xattr(JCR *jcr, FF_PKT *ff_pkt, char **data) +{ + + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_backup_xattr\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data) { + return 0; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BXATTR_BACKUP; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return -1; + } + if (xacl.count > 0){ + /* we have something to save, so prepare return data */ + *data = xacl.content; + return xacl.count; + } + + return 0; +} + +/* + * Called here when Bacula got XATTR stream to restore but not every stream but + * a specific one: STREAM_XACL_PLUGIN_XATTR which means a plugin has to + * be called. + * + * in: + * jcr - Job Control Record + * data - content to restore + * length - the length of the content to restore + * out: + * true - when successful + * false - on any Error + */ +bool plugin_restore_xattr(JCR *jcr, char *data, uint32_t length) +{ + struct xacl_pkt xacl; + Plugin *plugin = (Plugin *)jcr->plugin; + bRC rc; + + Dmsg0(dbglvl, "plugin_restore_xattr\n"); + + /* check of input variables */ + if (!plugin || !jcr->plugin_ctx || !data || length == 0) { + return true; + } + + /* prepare the xacl packet */ + memset(&xacl, 0, sizeof(xacl)); + xacl.pkt_size = sizeof(xacl); + xacl.pkt_end = sizeof(xacl); + xacl.func = BXATTR_RESTORE; + xacl.content = data; + xacl.count = length; + + rc = plug_func(plugin)->handleXACLdata(jcr->plugin_ctx, &xacl); + + /* check out status */ + if (rc != bRC_OK){ + Dmsg0(dbglvl, "plugin->handleXACLdata returned error\n"); + return false; + } + + return true; +} + /* * Print to file the plugin info. */ @@ -1101,14 +1301,14 @@ void load_fd_plugins(const char *plugin_dir) return; } - bplugin_list = New(alist(10, not_owned_by_alist)); + b_plugin_list = New(alist(10, not_owned_by_alist)); Dsm_check(999); if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, is_plugin_compatible)) { /* Either none found, or some error */ - if (bplugin_list->size() == 0) { - delete bplugin_list; - bplugin_list = NULL; + if (b_plugin_list->size() == 0) { + delete b_plugin_list; + b_plugin_list = NULL; Dmsg0(dbglvl, "No plugins loaded\n"); return; } @@ -1122,11 +1322,11 @@ void load_fd_plugins(const char *plugin_dir) plugin_blseek = my_plugin_blseek; Dsm_check(999); - /* + /* * Verify that the plugin is acceptable, and print information * about it. */ - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file); Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file); } @@ -1144,7 +1344,7 @@ static bool is_plugin_compatible(Plugin *plugin) pInfo *info = (pInfo *)plugin->pinfo; Dmsg0(dbglvl, "is_plugin_compatible called\n"); Dsm_check(999); - if (debug_level >= 50) { + if (chk_dbglvl(50)) { dump_fd_plugin(plugin, stdin); } if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) { @@ -1164,6 +1364,7 @@ static bool is_plugin_compatible(Plugin *plugin) } if (strcmp(info->plugin_license, "Bacula AGPLv3") != 0 && strcmp(info->plugin_license, "AGPLv3") != 0 && + strcmp(info->plugin_license, "Bacula Systems(R) SA") != 0) { Jmsg(NULL, M_ERROR, 0, _("Plugin license incompatible. Plugin=%s license=%s\n"), plugin->file, info->plugin_license); Dmsg2(50, "Plugin license incompatible. Plugin=%s license=%s\n", @@ -1176,7 +1377,7 @@ static bool is_plugin_compatible(Plugin *plugin) plugin->file, sizeof(pInfo), info->size); return false; } - + Dsm_check(999); return true; } @@ -1184,7 +1385,7 @@ static bool is_plugin_compatible(Plugin *plugin) /** * Create a new instance of each plugin for this Job - * Note, bplugin_list can exist but jcr->plugin_ctx_list can + * Note, b_plugin_list can exist but jcr->plugin_ctx_list can * be NULL if no plugins were loaded. */ void new_plugins(JCR *jcr) @@ -1193,7 +1394,7 @@ void new_plugins(JCR *jcr) int i; Dsm_check(999); - if (!bplugin_list) { + if (!b_plugin_list) { Dmsg0(dbglvl, "plugin list is NULL\n"); return; } @@ -1201,7 +1402,7 @@ void new_plugins(JCR *jcr) return; } - int num = bplugin_list->size(); + int num = b_plugin_list->size(); if (num == 0) { Dmsg0(dbglvl, "No plugins loaded\n"); @@ -1212,7 +1413,7 @@ void new_plugins(JCR *jcr) bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; Dmsg2(dbglvl, "Instantiate plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId); - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { Dsm_check(999); /* Start a new instance of each plugin */ bacula_ctx *b_ctx = (bacula_ctx *)malloc(sizeof(bacula_ctx)); @@ -1221,6 +1422,7 @@ void new_plugins(JCR *jcr) plugin_ctx_list[i].bContext = (void *)b_ctx; /* Bacula private context */ plugin_ctx_list[i].pContext = NULL; if (plug_func(plugin)->newPlugin(&plugin_ctx_list[i]) != bRC_OK) { + Dmsg1(000, "Plugin %s will be disabled\n", plugin->file); b_ctx->disabled = true; } } @@ -1239,14 +1441,14 @@ void free_plugins(JCR *jcr) Plugin *plugin; int i; - if (!bplugin_list || !jcr->plugin_ctx_list) { + if (!b_plugin_list || !jcr->plugin_ctx_list) { return; /* no plugins, nothing to do */ } Dsm_check(999); bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; Dmsg2(dbglvl, "Free instance plugin_ctx=%p JobId=%d\n", plugin_ctx_list, jcr->JobId); - foreach_alist_index(i, plugin, bplugin_list) { + foreach_alist_index(i, plugin, b_plugin_list) { /* Free the plugin instance */ plug_func(plugin)->freePlugin(&plugin_ctx_list[i]); free(plugin_ctx_list[i].bContext); /* free Bacula private context */ @@ -1257,7 +1459,7 @@ void free_plugins(JCR *jcr) jcr->plugin_ctx_list = NULL; } -static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) +static int my_plugin_bopen(BFILE *bfd, const char *fname, uint64_t flags, mode_t mode) { JCR *jcr = bfd->jcr; Plugin *plugin = (Plugin *)jcr->plugin; @@ -1278,6 +1480,7 @@ static int my_plugin_bopen(BFILE *bfd, const char *fname, int flags, mode_t mode io.mode = mode; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1309,6 +1512,7 @@ static int my_plugin_bclose(BFILE *bfd) io.buf = NULL; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1341,6 +1545,7 @@ static ssize_t my_plugin_bread(BFILE *bfd, void *buf, size_t count) io.win32 = false; io.offset = 0; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->offset = io.offset; bfd->berrno = io.io_errno; @@ -1373,6 +1578,7 @@ static ssize_t my_plugin_bwrite(BFILE *bfd, void *buf, size_t count) io.buf = (char *)buf; io.win32 = false; io.lerror = 0; + io.status = -1; plug_func(plugin)->pluginIO(jcr->plugin_ctx, &io); bfd->berrno = io.io_errno; if (io.win32) { @@ -1445,8 +1651,11 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) case bVarDistName: *(char **)value = dist_name; break; - case bVarBEEF: - *((int *)value) = beef; + case bVarPrevJobName: + break; + case bVarPrefixLinks: + break; + case bVarxxx: break; default: break; @@ -1498,22 +1707,26 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) *((int *)value) = (int)jcr->accurate; Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate); break; + case bVarInteractiveSession: + *(int *)value = (int)jcr->interactive_session; + break; + case bVarFileIndex: + *(int *)value = (int)jcr->JobFiles; + break; case bVarFileSeen: break; /* a write only variable, ignore read request */ case bVarVssObject: #ifdef HAVE_WIN32 - if (g_pVSSClient) { - *(void **)value = g_pVSSClient->GetVssObject(); + if (jcr->pVSSClient) { + *(void **)value = jcr->pVSSClient->GetVssObject(); break; } #endif return bRC_Error; case bVarVssDllHandle: #ifdef HAVE_WIN32 - if (g_pVSSClient) { - *(void **)value = g_pVSSClient->GetVssDllHandle(); - break; - } + *(void **)value = vsslib; + break; #endif return bRC_Error; case bVarWhere: @@ -1525,12 +1738,16 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) case bVarPrefixLinks: *(int *)value = (int)jcr->prefix_links; break; + case bVarReplace: + *((int*)value) = jcr->replace; + Dmsg1(dbglvl, "Bacula: return replace=%c\n", jcr->replace); + break; case bVarFDName: /* get warning with g++ if we missed one */ case bVarWorkingDir: case bVarExePath: case bVarVersion: case bVarDistName: - case bVarBEEF: + case bVarxxx: break; } Dsm_check(999); @@ -1549,12 +1766,15 @@ static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value) if (!jcr) { return bRC_Error; } -// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); +// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); switch (var) { case bVarFileSeen: if (!accurate_mark_file_as_seen(jcr, (char *)value)) { return bRC_Error; - } + } + break; + case bVarInteractiveSession: + jcr->interactive_session = (((intptr_t) value) == 1); break; default: break; @@ -1680,7 +1900,7 @@ static bRC baculaAddExclude(bpContext *ctx, const char *file) return bRC_Error; } - if (!bctx->exclude) { + if (!bctx->exclude) { bctx->exclude = new_exclude(jcr); } @@ -1831,7 +2051,7 @@ static bRC baculaNewPreInclude(bpContext *ctx) return bRC_OK; } -/* +/* * Check if a file have to be backuped using Accurate code */ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) @@ -1848,10 +2068,10 @@ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) if (!sp) { goto bail_out; } - + ff_pkt = jcr->ff; /* - * Copy fname and link because save_file() zaps them. This + * Copy fname and link because save_file() zaps them. This * avoids zaping the plugin's strings. */ ff_pkt->type = sp->type; @@ -1871,7 +2091,7 @@ static bRC baculaCheckChanges(bpContext *ctx, struct save_pkt *sp) } /* check_changes() can update delta sequence number, return it to the - * plugin + * plugin */ sp->delta_seq = ff_pkt->delta_seq; sp->accurate_found = ff_pkt->accurate_found; @@ -1882,7 +2102,7 @@ bail_out: return ret; } -/* +/* * Check if a file would be saved using current Include/Exclude code */ static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp) @@ -1902,7 +2122,7 @@ static bRC baculaAcceptFile(bpContext *ctx, struct save_pkt *sp) if (!sp) { goto bail_out; } - + ff_pkt = jcr->ff; /* Probably not needed, but keep a copy */ @@ -1927,7 +2147,7 @@ bail_out: #ifdef TEST_PROGRAM -int (*plugin_bopen)(JCR *jcr, const char *fname, int flags, mode_t mode) = NULL; +int (*plugin_bopen)(JCR *jcr, const char *fname, uint64_t flags, mode_t mode) = NULL; int (*plugin_bclose)(JCR *jcr) = NULL; ssize_t (*plugin_bread)(JCR *jcr, void *buf, size_t count) = NULL; ssize_t (*plugin_bwrite)(JCR *jcr, void *buf, size_t count) = NULL; @@ -1951,7 +2171,7 @@ int main(int argc, char *argv[]) JCR *jcr2 = &mjcr2; strcpy(my_name, "test-fd"); - + getcwd(plugin_dir, sizeof(plugin_dir)-1); load_fd_plugins(plugin_dir);