X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Ffd_plugins.c;h=ef24d0520e718993d6150072e25e033d6a57f0fa;hb=f9201647d5ecc4a1b0a2d1de7ca339f50fc5d77b;hp=12679e806f7cb8cf7a7b0578fb9c15b50cd1bb01;hpb=88c4368a5e22d2099cbb0c50e5ec7212be45727d;p=bacula%2Fbacula diff --git a/bacula/src/filed/fd_plugins.c b/bacula/src/filed/fd_plugins.c index 12679e806f..ef24d0520e 100644 --- a/bacula/src/filed/fd_plugins.c +++ b/bacula/src/filed/fd_plugins.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2007-2008 Free Software Foundation Europe e.V. + Copyright (C) 2007-2009 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. @@ -34,7 +34,7 @@ #include "bacula.h" #include "filed.h" -const int dbglvl = 50; +const int dbglvl = 150; #ifdef HAVE_WIN32 const char *plugin_type = "-fd.dll"; #else @@ -56,12 +56,13 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value); static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value); static bRC baculaRegisterEvents(bpContext *ctx, ...); static bRC baculaJobMsg(bpContext *ctx, const char *file, int line, - int type, time_t mtime, const char *fmt, ...); + int type, utime_t mtime, const char *fmt, ...); static bRC baculaDebugMsg(bpContext *ctx, const char *file, int line, int level, const char *fmt, ...); static void *baculaMalloc(bpContext *ctx, const char *file, int line, size_t size); static void baculaFree(bpContext *ctx, const char *file, int line, void *mem); +static bool is_plugin_compatible(Plugin *plugin); /* * These will be plugged into the global pointer structure for @@ -122,7 +123,7 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) Plugin *plugin; int i = 0; - if (!plugin_list || !jcr->plugin_ctx_list) { + if (!plugin_list || !jcr || !jcr->plugin_ctx_list || job_canceled(jcr)) { return; /* Return if no plugins loaded */ } @@ -150,6 +151,45 @@ void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) return; } +/* + * Check if file was seen for accurate + */ +bool plugin_check_file(JCR *jcr, char *fname) +{ + Plugin *plugin; + int rc = bRC_OK; + int i = 0; + + if (!plugin_list || !jcr || !jcr->plugin_ctx_list || job_canceled(jcr)) { + return false; /* Return if no plugins loaded */ + } + + bpContext *plugin_ctx_list = (bpContext *)jcr->plugin_ctx_list; + + Dmsg2(dbglvl, "plugin_ctx=%p JobId=%d\n", jcr->plugin_ctx_list, jcr->JobId); + + /* Pass event to every plugin */ + foreach_alist(plugin, plugin_list) { + jcr->plugin_ctx = &plugin_ctx_list[i++]; + jcr->plugin = plugin; + if (is_plugin_disabled(jcr)) { + continue; + } + if (plug_func(plugin)->checkFile == NULL) { + continue; + } + rc = plug_func(plugin)->checkFile(jcr->plugin_ctx, fname); + if (rc == bRC_Seen) { + break; + } + } + + jcr->plugin = NULL; + jcr->plugin_ctx = NULL; + return rc == bRC_Seen; +} + + /* * Sequence of calls for a backup: * 1. plugin_save() here is called with ff_pkt @@ -174,8 +214,10 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) char *cmd = ff_pkt->top_fname; struct save_pkt sp; bEvent event; + POOL_MEM fname(PM_FNAME); + POOL_MEM link(PM_FNAME); - if (!plugin_list || !jcr->plugin_ctx_list) { + if (!plugin_list || !jcr->plugin_ctx_list || job_canceled(jcr)) { return 1; /* Return if no plugins loaded */ } @@ -237,13 +279,22 @@ int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } jcr->plugin_sp = &sp; ff_pkt = jcr->ff; - ff_pkt->fname = sp.fname; - ff_pkt->link = sp.link; + /* + * Copy fname and link because save_file() zaps them. This + * avoids zaping the plugin's strings. + */ + pm_strcpy(fname, sp.fname); + pm_strcpy(link, sp.link); + ff_pkt->fname = fname.c_str(); + ff_pkt->link = link.c_str(); ff_pkt->type = sp.type; memcpy(&ff_pkt->statp, &sp.statp, sizeof(ff_pkt->statp)); - Dmsg1(dbglvl, "Save_file: file=%s\n", ff_pkt->fname); + Dmsg1(dbglvl, "Save_file: file=%s\n", fname.c_str()); save_file(jcr, ff_pkt, true); bRC rc = plug_func(plugin)->endBackupFile(jcr->plugin_ctx); + if (rc == bRC_More || rc == bRC_OK) { + accurate_mark_file_as_seen(jcr, fname.c_str()); + } if (rc == bRC_More) { continue; } @@ -273,6 +324,9 @@ bool send_plugin_name(JCR *jcr, BSOCK *sd, bool start) Jmsg0(jcr, M_FATAL, 0, _("Plugin save packet not found.\n")); return false; } + if (job_canceled(jcr)) { + return false; + } if (start) { index++; /* JobFiles not incremented yet */ @@ -396,6 +450,7 @@ bail_out: /* * Tell the plugin to create the file. Return values are + * This is called only during Restore * * CF_ERROR -- error * CF_SKIP -- skip processing this file @@ -411,7 +466,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) int flags; int rc; - if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr)) { + if (!plugin || !plugin_ctx || !set_cmd_plugin(bfd, jcr) || job_canceled(jcr)) { return CF_ERROR; } rp.pkt_size = sizeof(rp); @@ -470,6 +525,7 @@ int plugin_create_file(JCR *jcr, ATTR *attr, BFILE *bfd, int replace) * Reset the file attributes after all file I/O is done -- this allows * the previous access time/dates to be set properly, and it also allows * us to properly set directory permissions. + * Not currently Implemented. */ bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) { @@ -481,6 +537,24 @@ bool plugin_set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } +/* + * Print to file the plugin info. + */ +void dump_fd_plugin(Plugin *plugin, FILE *fp) +{ + if (!plugin) { + return ; + } + pInfo *info = (pInfo *)plugin->pinfo; + fprintf(fp, "\tversion=%d\n", info->version); + fprintf(fp, "\tdate=%s\n", NPRTB(info->plugin_date)); + fprintf(fp, "\tmagic=%s\n", NPRTB(info->plugin_magic)); + fprintf(fp, "\tauthor=%s\n", NPRTB(info->plugin_author)); + fprintf(fp, "\tlicence=%s\n", NPRTB(info->plugin_license)); + fprintf(fp, "\tversion=%s\n", NPRTB(info->plugin_version)); + fprintf(fp, "\tdescription=%s\n", NPRTB(info->plugin_description)); +} + /* * This entry point is called internally by Bacula to ensure * that the plugin IO calls come into this code. @@ -495,7 +569,8 @@ void load_fd_plugins(const char *plugin_dir) } plugin_list = New(alist(10, not_owned_by_alist)); - if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type)) { + if (!load_plugins((void *)&binfo, (void *)&bfuncs, plugin_dir, plugin_type, + is_plugin_compatible)) { /* Either none found, or some error */ if (plugin_list->size() == 0) { delete plugin_list; @@ -511,13 +586,58 @@ void load_fd_plugins(const char *plugin_dir) plugin_bread = my_plugin_bread; plugin_bwrite = my_plugin_bwrite; plugin_blseek = my_plugin_blseek; + + /* + * Verify that the plugin is acceptable, and print information + * about it. + */ foreach_alist(plugin, plugin_list) { Jmsg(NULL, M_INFO, 0, _("Loaded plugin: %s\n"), plugin->file); Dmsg1(dbglvl, "Loaded plugin: %s\n", plugin->file); + } + + dbg_plugin_add_hook(dump_fd_plugin); +} +/* + * Check if a plugin is compatible. Called by the load_plugin function + * to allow us to verify the plugin. + */ +static bool is_plugin_compatible(Plugin *plugin) +{ + pInfo *info = (pInfo *)plugin->pinfo; + Dmsg0(50, "is_plugin_compatible called\n"); + if (debug_level >= 50) { + dump_fd_plugin(plugin, stdin); } + if (strcmp(info->plugin_magic, FD_PLUGIN_MAGIC) != 0) { + Jmsg(NULL, M_ERROR, 0, _("Plugin magic wrong. Plugin=%s wanted=%s got=%s\n"), + plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic); + Dmsg3(50, "Plugin magic wrong. Plugin=%s wanted=%s got=%s\n", + plugin->file, FD_PLUGIN_MAGIC, info->plugin_magic); + + return false; + } + if (info->version != FD_PLUGIN_INTERFACE_VERSION) { + Jmsg(NULL, M_ERROR, 0, _("Plugin version incorrect. Plugin=%s wanted=%d got=%d\n"), + plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version); + Dmsg3(50, "Plugin version incorrect. Plugin=%s wanted=%d got=%d\n", + plugin->file, FD_PLUGIN_INTERFACE_VERSION, info->version); + return false; + } + if (strcmp(info->plugin_license, "Bacula GPLv2") != 0 && + strcmp(info->plugin_license, "GPLv2") != 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", + plugin->file, info->plugin_license); + return false; + } + + return true; } + /* * Create a new instance of each plugin for this Job * Note, plugin_list can exist but jcr->plugin_ctx_list can @@ -532,6 +652,9 @@ void new_plugins(JCR *jcr) Dmsg0(dbglvl, "plugin list is NULL\n"); return; } + if (job_canceled(jcr)) { + return; + } int num = plugin_list->size(); @@ -715,12 +838,12 @@ static boffset_t my_plugin_blseek(BFILE *bfd, boffset_t offset, int whence) static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) { JCR *jcr; - jcr = ((bacula_ctx *)ctx->bContext)->jcr; -// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var); if (!value || !ctx) { return bRC_Error; } jcr = ((bacula_ctx *)ctx->bContext)->jcr; +// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var); + jcr = ((bacula_ctx *)ctx->bContext)->jcr; if (!jcr) { return bRC_Error; } @@ -735,22 +858,61 @@ static bRC baculaGetValue(bpContext *ctx, bVariable var, void *value) Dmsg1(dbglvl, "Bacula: return my_name=%s\n", my_name); break; case bVarLevel: + *((int *)value) = jcr->get_JobLevel(); + Dmsg1(dbglvl, "Bacula: return bVarJobLevel=%d\n", jcr->get_JobLevel()); + break; case bVarType: + *((int *)value) = jcr->get_JobType(); + Dmsg1(dbglvl, "Bacula: return bVarJobType=%d\n", jcr->get_JobType()); + break; case bVarClient: + *((char **)value) = jcr->client_name; + Dmsg1(dbglvl, "Bacula: return Client_name=%s\n", jcr->client_name); + break; case bVarJobName: + *((char **)value) = jcr->Job; + Dmsg1(dbglvl, "Bacula: return Job name=%s\n", jcr->Job); + break; case bVarJobStatus: + *((int *)value) = jcr->JobStatus; + Dmsg1(dbglvl, "Bacula: return bVarJobStatus=%d\n", jcr->JobStatus); + break; case bVarSinceTime: + *((int *)value) = (int)jcr->mtime; + Dmsg1(dbglvl, "Bacula: return since=%d\n", (int)jcr->mtime); + break; + case bVarAccurate: + *((int *)value) = (int)jcr->accurate; + Dmsg1(dbglvl, "Bacula: return accurate=%d\n", (int)jcr->accurate); break; + case bVarFileSeen: + break; /* a write only variable, ignore read request */ } return bRC_OK; } static bRC baculaSetValue(bpContext *ctx, bVariable var, void *value) { + JCR *jcr; if (!value || !ctx) { return bRC_Error; } - Dmsg1(dbglvl, "bacula: baculaSetValue var=%d\n", var); + jcr = ((bacula_ctx *)ctx->bContext)->jcr; +// Dmsg1(dbglvl, "bacula: baculaGetValue var=%d\n", var); + jcr = ((bacula_ctx *)ctx->bContext)->jcr; + if (!jcr) { + return bRC_Error; + } +// Dmsg1(dbglvl, "Bacula: jcr=%p\n", jcr); + switch (var) { + case bVarFileSeen: + if (!accurate_mark_file_as_seen(jcr, (char *)value)) { + return bRC_Error; + } + break; + default: + break; + } return bRC_OK; } @@ -772,7 +934,7 @@ static bRC baculaRegisterEvents(bpContext *ctx, ...) } static bRC baculaJobMsg(bpContext *ctx, const char *file, int line, - int type, time_t mtime, const char *fmt, ...) + int type, utime_t mtime, const char *fmt, ...) { va_list arg_ptr; char buf[2000];