From: Kern Sibbald Date: Sat, 6 Sep 2003 10:17:22 +0000 (+0000) Subject: Implement ClientRunBeforeJob and ClientRunAfterJob X-Git-Tag: Release-1.32~31 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c2cfadce592f9f911fe2d0c3dd629fc1b06e32ab;p=bacula%2Fbacula Implement ClientRunBeforeJob and ClientRunAfterJob git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@688 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/ChangeLog b/bacula/ChangeLog index dcfad2ea2c..8e8e0b8732 100644 --- a/bacula/ChangeLog +++ b/bacula/ChangeLog @@ -1,4 +1,16 @@ -2003-08-02 Version 1.32 02Sep03 Beta +2003-08-02 Version 1.32 06Sep03 Beta +- Implement ClientRunBeforeJob and ClientRunAfterJob. +- Corrected BSRatEOF to be BSFatEOF in btape -- + reported by Lars Koller. +- Documented BSFatEof +- Eliminated save_level in FD replaced by JobLevel. +- Increased MAX_RES_ITEMS from 35 to 50 to handle + new ClientRunBeforeJob ... +- Add line number in error message for restore from file. +- Correct editing of jobids (misplaced comma). +- Implement restore files. +- Quickie patch to allow Purged Volumes to be mounted. + Must review algorithm. - Eliminate a duplicated query from query.sql - Restructure ua_restore.c so that I can add restore files. - Correct positioning problem at beginning of a second volume diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index ee48485945..76a9a971a2 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,15 +1,17 @@ Release Notes for Bacula 1.32 - Bacula code: Total files = 259 Total lines = 76,690 (*.h *.c *.in) + Bacula code: Total files = 259 Total lines = 77,120 (*.h *.c *.in) Major Changes this Release: - Fixed gnome-console to compile with RH9 (Gnome 2.0) - Implemented a single routine to read_records. It also returns a different record packet for each session. This means that multiple simultaneous jobs should work. -- Implemented forward space file/block whenever possible. +- Implemented forward space file/block whenever possible + during restore. - Added SDConnectTimeout to FD. +- Added ClientRunBeforeJob and ClientRunAfterJob. Other Changes this Release: diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 43f7513c1a..8d547b4065 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -198,6 +198,10 @@ int do_backup(JCR *jcr) goto bail_out; } + if (!send_run_before_and_after_commands(jcr)) { + goto bail_out; + } + /* Send backup command */ bnet_fsend(fd, backupcmd); if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) { diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 25cab2dc79..2170928f4e 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -208,6 +208,8 @@ static struct res_items job_items[] = { {"prunevolumes", store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0}, {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0}, {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0}, + {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0}, + {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0}, {"spoolattributes", store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0}, {"writebootstrap", store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0}, {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, @@ -815,12 +817,20 @@ void free_resource(int type) if (res->res_job.RunAfterJob) { free(res->res_job.RunAfterJob); } + if (res->res_job.ClientRunBeforeJob) { + free(res->res_job.ClientRunBeforeJob); + } + if (res->res_job.ClientRunAfterJob) { + free(res->res_job.ClientRunAfterJob); + } break; case R_MSGS: - if (res->res_msgs.mail_cmd) + if (res->res_msgs.mail_cmd) { free(res->res_msgs.mail_cmd); - if (res->res_msgs.operator_cmd) + } + if (res->res_msgs.operator_cmd) { free(res->res_msgs.operator_cmd); + } free_msgs_res((MSGS *)res); /* free message resource */ res = NULL; break; diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 247610f1a5..717805ff3a 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -185,6 +185,8 @@ struct JOB { char *RestoreBootstrap; /* Bootstrap file */ char *RunBeforeJob; /* Run program before Job */ char *RunAfterJob; /* Run program after Job */ + char *ClientRunBeforeJob; /* Run client program before Job */ + char *ClientRunAfterJob; /* Run client program after Job */ char *WriteBootstrap; /* Where to write bootstrap Job updates */ int replace; /* How (overwrite, ..) */ utime_t MaxRunTime; /* max run time in seconds */ diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 09c62413b9..0c53376ca6 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -40,6 +40,8 @@ static char inc[] = "include\n"; static char exc[] = "exclude\n"; static char jobcmd[] = "JobId=%d Job=%s SDid=%u SDtime=%u Authorization=%s\n"; static char levelcmd[] = "level = %s%s mtime_only=%d\n"; +static char runbefore[] = "RunBeforeJob %s\n"; +static char runafter[] = "RunAfterJob %s\n"; /* Responses received from File daemon */ @@ -48,6 +50,8 @@ static char OKexc[] = "2000 OK exclude\n"; static char OKjob[] = "2000 OK Job"; static char OKbootstrap[] = "2000 OK bootstrap\n"; static char OKlevel[] = "2000 OK level\n"; +static char OKRunBefore[] = "2000 OK RunBefore\n"; +static char OKRunAfter[] = "2000 OK RunAfter\n"; /* Forward referenced functions */ @@ -328,7 +332,7 @@ bail_out: int send_include_list(JCR *jcr) { BSOCK *fd = jcr->file_bsock; - fd->msglen = sprintf(fd->msg, inc); + fd->msglen = pm_strcpy(&fd->msg, inc); bnet_send(fd); return send_list(jcr, INC_LIST); } @@ -340,7 +344,7 @@ int send_include_list(JCR *jcr) int send_exclude_list(JCR *jcr) { BSOCK *fd = jcr->file_bsock; - fd->msglen = sprintf(fd->msg, exc); + fd->msglen = pm_strcpy(&fd->msg, exc); bnet_send(fd); return send_list(jcr, EXC_LIST); } @@ -368,12 +372,9 @@ int send_bootstrap_file(JCR *jcr) set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } - strcpy(fd->msg, bootstrap); - fd->msglen = strlen(fd->msg); - bnet_send(fd); + bnet_fsend(fd, bootstrap); while (fgets(buf, sizeof(buf), bs)) { - fd->msglen = Mmsg(&fd->msg, "%s", buf); - bnet_send(fd); + bnet_fsend(fd, "%s", buf); } bnet_sig(fd, BNET_EOD); fclose(bs); @@ -384,6 +385,37 @@ int send_bootstrap_file(JCR *jcr) return 1; } +/* + * Send ClientRunBeforeJob and ClientRunAfterJob to File daemon + */ +int send_run_before_and_after_commands(JCR *jcr) +{ + POOLMEM *msg = get_pool_memory(PM_FNAME); + BSOCK *fd = jcr->file_bsock; + if (jcr->job->ClientRunBeforeJob) { + pm_strcpy(&msg, jcr->job->ClientRunBeforeJob); + bash_spaces(msg); + bnet_fsend(fd, runbefore, msg); + if (!response(jcr, fd, OKRunBefore, "ClientRunBeforeJob", DISPLAY_ERROR)) { + set_jcr_job_status(jcr, JS_ErrorTerminated); + free_pool_memory(msg); + return 0; + } + } + if (jcr->job->ClientRunAfterJob) { + fd->msglen = pm_strcpy(&msg, jcr->job->ClientRunAfterJob); + bash_spaces(msg); + bnet_fsend(fd, runafter, msg); + if (!response(jcr, fd, OKRunAfter, "ClientRunAfterJob", DISPLAY_ERROR)) { + set_jcr_job_status(jcr, JS_ErrorTerminated); + free_pool_memory(msg); + return 0; + } + } + free_pool_memory(msg); + return 1; +} + /* * Read the attributes from the File daemon for diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index a53a94820a..5ec7d8d6ce 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -72,6 +72,7 @@ extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId); extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname, char *link, char *attr, int stream); extern void get_level_since_time(JCR *jcr, char *since, int since_len); +extern int send_run_before_and_after_commands(JCR *jcr); /* getmsg.c */ enum e_prtmsg { diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 341ac3aa33..a8459d7ad2 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -219,6 +219,11 @@ int do_restore(JCR *jcr) } } + if (!send_run_before_and_after_commands(jcr)) { + restore_cleanup(jcr, JS_ErrorTerminated); + return 0; + } + /* Send restore command */ char replace, *where; diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 31ab1f3ffd..40faac1e41 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -267,6 +267,10 @@ int do_verify(JCR *jcr) goto bail_out; } + if (!send_run_before_and_after_commands(jcr)) { + goto bail_out; + } + /* * Send verify command/level to File daemon */ diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index e23828c37f..dd7c4856df 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -54,6 +54,9 @@ static int response(JCR *jcr, BSOCK *sd, char *resp, char *cmd); static void filed_free_jcr(JCR *jcr); static int open_sd_read_session(JCR *jcr); static int send_bootstrap_file(JCR *jcr); +static int runbefore_cmd(JCR *jcr); +static int runafter_cmd(JCR *jcr); +static int run_cmd(JCR *jcr, char *cmd, char *name); /* Exported functions */ @@ -67,21 +70,23 @@ struct s_cmds { * The following are the recognized commands from the Director. */ static struct s_cmds cmds[] = { - {"backup", backup_cmd}, - {"cancel", cancel_cmd}, - {"setdebug=", setdebug_cmd}, - {"estimate", estimate_cmd}, - {"exclude", exclude_cmd}, - {"Hello", hello_cmd}, - {"include", include_cmd}, - {"JobId=", job_cmd}, - {"level = ", level_cmd}, - {"restore", restore_cmd}, - {"session", session_cmd}, - {"status", status_cmd}, - {"storage ", storage_cmd}, - {"verify", verify_cmd}, - {"bootstrap",bootstrap_cmd}, + {"backup", backup_cmd}, + {"cancel", cancel_cmd}, + {"setdebug=", setdebug_cmd}, + {"estimate", estimate_cmd}, + {"exclude", exclude_cmd}, + {"Hello", hello_cmd}, + {"include", include_cmd}, + {"JobId=", job_cmd}, + {"level = ", level_cmd}, + {"restore", restore_cmd}, + {"session", session_cmd}, + {"status", status_cmd}, + {"storage ", storage_cmd}, + {"verify", verify_cmd}, + {"bootstrap", bootstrap_cmd}, + {"RunBeforeJob", runbefore_cmd}, + {"RunAfterJob", runafter_cmd}, {NULL, NULL} /* list terminator */ }; @@ -93,6 +98,8 @@ static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n"; static char verifycmd[] = "verify level=%30s\n"; static char estimatecmd[] = "estimate listing=%d\n"; +static char runbefore[] = "RunBeforeJob %s\n"; +static char runafter[] = "RunAfterJob %s\n"; /* Responses sent to Director */ static char errmsg[] = "2999 Invalid command\n"; @@ -111,6 +118,8 @@ static char OKjob[] = "2000 OK Job " HOST_OS "," DISTNAME "," DISTVER; static char OKsetdebug[] = "2000 OK setdebug=%d\n"; static char BADjob[] = "2901 Bad Job\n"; static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s JobBytes=%s Errors=%u\n"; +static char OKRunBefore[] = "2000 OK RunBefore\n"; +static char OKRunAfter[] = "2000 OK RunAfter\n"; /* Responses received from Storage Daemon */ static char OK_end[] = "3000 OK end\n"; @@ -201,6 +210,10 @@ void *handle_client_request(void *dirp) bnet_sig(jcr->store_bsock, BNET_TERMINATE); } + if (jcr->RunAfterJob && !job_canceled(jcr)) { + run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob"); + } + /* Inform Director that we are done */ bnet_sig(dir, BNET_TERMINATE); @@ -323,6 +336,81 @@ static int job_cmd(JCR *jcr) return bnet_fsend(dir, OKjob); } +static int runbefore_cmd(JCR *jcr) +{ + int stat; + BSOCK *dir = jcr->dir_bsock; + POOLMEM *cmd = get_memory(dir->msglen+1); + + Dmsg1(100, "runbefore_cmd: %s", dir->msg); + if (sscanf(dir->msg, runbefore, cmd) != 1) { + pm_strcpy(&jcr->errmsg, dir->msg); + Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg); + bnet_fsend(dir, "2905 Bad RunBeforeJob command.\n"); + free_memory(cmd); + return 0; + } + unbash_spaces(cmd); + + /* Run the command now */ + stat = run_cmd(jcr, cmd, "ClientRunBeforeJob"); + free_memory(cmd); + if (stat) { + bnet_fsend(dir, OKRunBefore); + return 1; + } else { + bnet_fsend(dir, "2905 Bad RunBeforeJob command.\n"); + return 0; + } +} + +static int runafter_cmd(JCR *jcr) +{ + BSOCK *dir = jcr->dir_bsock; + POOLMEM *msg = get_memory(dir->msglen+1); + + Dmsg1(100, "runafter_cmd: %s", dir->msg); + if (sscanf(dir->msg, runafter, msg) != 1) { + pm_strcpy(&jcr->errmsg, dir->msg); + Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg); + bnet_fsend(dir, "2905 Bad RunAfterJob command.\n"); + free_memory(msg); + return 0; + } + unbash_spaces(msg); + if (jcr->RunAfterJob) { + free_pool_memory(jcr->RunAfterJob); + } + jcr->RunAfterJob = get_pool_memory(PM_FNAME); + pm_strcpy(&jcr->RunAfterJob, msg); + free_pool_memory(msg); + return bnet_fsend(dir, OKRunAfter); +} + +static int run_cmd(JCR *jcr, char *cmd, char *name) +{ + POOLMEM *ecmd = get_pool_memory(PM_FNAME); + int status; + BPIPE *bpipe; + char line[MAXSTRING]; + + ecmd = edit_job_codes(jcr, ecmd, cmd, ""); + bpipe = open_bpipe(ecmd, 0, "r"); + free_pool_memory(ecmd); + while (fgets(line, sizeof(line), bpipe->rfd)) { + Jmsg(jcr, M_INFO, 0, _("%s: %s"), name, line); + } + status = close_bpipe(bpipe); + if (status != 0) { + Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d\n"), name, + status); + set_jcr_job_status(jcr, JS_FatalError); + return 0; + } + return 1; +} + + #define INC_LIST 0 #define EXC_LIST 1 @@ -443,16 +531,16 @@ static int level_cmd(JCR *jcr) } /* Base backup requested? */ if (strcmp(level, "base") == 0) { - jcr->save_level = L_BASE; + jcr->JobLevel = L_BASE; /* Full backup requested? */ } else if (strcmp(level, "full") == 0) { - jcr->save_level = L_FULL; + jcr->JobLevel = L_FULL; /* * Backup requested since