]> git.sur5r.net Git - bacula/bacula/commitdiff
Done with item 9 = Implement new {Client}Run{Before|After}Job feature.
authorEric Bollengier <eric@eb.homelinux.org>
Sat, 27 May 2006 09:35:38 +0000 (09:35 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Sat, 27 May 2006 09:35:38 +0000 (09:35 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3031 91ce42f0-d328-0410-95d8-f526ca767f89

14 files changed:
bacula/src/dird/backup.c
bacula/src/dird/dird.c
bacula/src/dird/dird.h
bacula/src/dird/dird_conf.c
bacula/src/dird/dird_conf.h
bacula/src/dird/fd_cmds.c
bacula/src/dird/job.c
bacula/src/dird/protos.h
bacula/src/dird/restore.c
bacula/src/dird/verify.c
bacula/src/filed/filed.h
bacula/src/filed/job.c
bacula/src/jcr.h
bacula/src/lib/Makefile.in

index dc889976ecfd6c2b49da117abd4cd0a78a7a9468..83e51fc1b94d9c4869eced56b47723036b5f9b30 100644 (file)
@@ -222,7 +222,7 @@ bool do_backup(JCR *jcr)
    }
 
 
-   if (!send_run_before_and_after_commands(jcr)) {
+   if (!send_runscripts_commands(jcr)) {
       goto bail_out;
    }
 
index 57b5fee1ed324029be9074be3dcef3ce4bd5ea28..a5f65266e83498457140763b06a95d71b2f48aaf 100644 (file)
@@ -555,6 +555,19 @@ static int check_resources()
                job->storage->append(st);
             }
          }
+         /* Handle RunScripts alists specifically */
+         if (jobdefs->RunScripts) {
+            RUNSCRIPT *rs, *elt;
+           
+           if (!job->RunScripts) {
+              job->RunScripts = New(alist(10, not_owned_by_alist));
+           }
+          
+           foreach_alist(rs, jobdefs->RunScripts) {
+              elt = copy_runscript(rs);
+               job->RunScripts->append(elt); /* we have to free it */
+            }
+         }
 
          /* Transfer default items from JobDefs Resource */
          for (i=0; job_items[i].name; i++) {
index 2dbcd73d1fb94471458b30b1ee7898953d0c2e61..ce83228b701ee2985dfe7a8ade3df2082b3283ec 100644 (file)
@@ -37,6 +37,7 @@
 #include "protos.h"
 
 #include "jobq.h"
+#include "lib/runscript.h"
 
 /* Globals that dird.c exports */
 extern DIRRES *director;                     /* Director resource */
index 1ce92662d8513f0e1e8c86141b7be577974508c4..8a2ae6ef78dcb7540f255a05d8cc12eeab7829b5 100644 (file)
@@ -62,7 +62,10 @@ void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
-
+static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
 
 /* We build the current resource here as we are
  * scanning the resource configuration definition,
@@ -266,11 +269,11 @@ RES_ITEM job_items[] = {
    {"spooldata",   store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
    {"rerunfailedlevels",   store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
    {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
-   {"runbeforejob", store_str,  ITEM(res_job.RunBeforeJob), 0, 0, 0},
-   {"runafterjob",  store_str,  ITEM(res_job.RunAfterJob),  0, 0, 0},
-   {"runafterfailedjob",  store_str,  ITEM(res_job.RunAfterFailedJob),  0, 0, 0},
-   {"clientrunbeforejob", store_str,  ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
-   {"clientrunafterjob",  store_str,  ITEM(res_job.ClientRunAfterJob),  0, 0, 0},
+   {"runbeforejob", store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
+   {"runafterjob",  store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
+   {"runafterfailedjob",  store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
+   {"clientrunbeforejob", store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
+   {"clientrunafterjob",  store_short_runscript,  ITEM(res_job.RunScripts),  0, 0, 0},
    {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
    {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
    {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
@@ -279,6 +282,7 @@ RES_ITEM job_items[] = {
    {"writepartafterjob",   store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
    {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
    {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
+   {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
    {NULL, NULL, NULL, 0, 0, 0}
 };
 
@@ -589,15 +593,6 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
       if (res->res_job.RestoreBootstrap) {
          sendit(sock, _("  --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
       }
-      if (res->res_job.RunBeforeJob) {
-         sendit(sock, _("  --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
-      }
-      if (res->res_job.RunAfterJob) {
-         sendit(sock, _("  --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
-      }
-      if (res->res_job.RunAfterFailedJob) {
-         sendit(sock, _("  --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
-      }
       if (res->res_job.WriteBootstrap) {
          sendit(sock, _("  --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
       }
@@ -608,6 +603,18 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
             dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
          }
       }
+      if (res->res_job.RunScripts) {
+        RUNSCRIPT *script;
+        foreach_alist(script, res->res_job.RunScripts) {
+           sendit(sock, _(" --> RunScript\n"));
+           sendit(sock, _("  --> Command=%s\n"), NPRT(script->command));
+           sendit(sock, _("  --> Target=%s\n"),  NPRT(script->target));
+           sendit(sock, _("  --> RunOnSuccess=%u\n"),  script->on_success);
+           sendit(sock, _("  --> RunOnFailure=%u\n"),  script->on_failure);
+           sendit(sock, _("  --> AbortJobOnError=%u\n"),  script->abort_on_error);
+           sendit(sock, _("  --> RunWhen=%u\n"),  script->when);
+        }
+      }
       if (res->res_job.pool) {
          sendit(sock, _("  --> "));
          dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
@@ -1096,21 +1103,6 @@ void free_resource(RES *sres, int type)
       if (res->res_job.WriteBootstrap) {
          free(res->res_job.WriteBootstrap);
       }
-      if (res->res_job.RunBeforeJob) {
-         free(res->res_job.RunBeforeJob);
-      }
-      if (res->res_job.RunAfterJob) {
-         free(res->res_job.RunAfterJob);
-      }
-      if (res->res_job.RunAfterFailedJob) {
-         free(res->res_job.RunAfterFailedJob);
-      }
-      if (res->res_job.ClientRunBeforeJob) {
-         free(res->res_job.ClientRunBeforeJob);
-      }
-      if (res->res_job.ClientRunAfterJob) {
-         free(res->res_job.ClientRunAfterJob);
-      }
       if (res->res_job.selection_pattern) {
          free(res->res_job.selection_pattern);
       }
@@ -1120,6 +1112,10 @@ void free_resource(RES *sres, int type)
       if (res->res_job.storage) {
          delete res->res_job.storage;
       }
+      if (res->res_job.RunScripts) {
+         free_runscripts(res->res_job.RunScripts);
+         delete res->res_job.RunScripts;
+      }
       break;
    case R_MSGS:
       if (res->res_msgs.mail_cmd) {
@@ -1255,6 +1251,7 @@ void save_resource(int type, RES_ITEM *items, int pass)
          res->res_job.verify_job = res_all.res_job.verify_job;
          res->res_job.jobdefs    = res_all.res_job.jobdefs;
          res->res_job.run_cmds   = res_all.res_job.run_cmds;
+         res->res_job.RunScripts = res_all.res_job.RunScripts;
          break;
       case R_COUNTER:
          if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
@@ -1544,3 +1541,194 @@ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
    }
    set_bit(index, res_all.hdr.item_present);
 }
+
+
+/* Store a runscript->when in a bit field */
+static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   lex_get_token(lc, T_NAME);
+
+   if (strcasecmp(lc->str, "before") == 0) {
+      *(int *)(item->value) = SCRIPT_Before ;
+   } else if (strcasecmp(lc->str, "after") == 0) {
+      *(int *)(item->value) = SCRIPT_After;
+   } else if (strcasecmp(lc->str, "always") == 0) {
+      *(int *)(item->value) = SCRIPT_Any;
+   } else {
+      scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
+   }
+   scan_to_eol(lc);
+}
+
+/* Store a runscript->target
+ * 
+ */
+static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   lex_get_token(lc, T_STRING);
+
+   if (pass == 2) {
+      if (strcmp(lc->str, "%c") == 0) {
+        ((RUNSCRIPT*) item->value)->set_target(lc->str);
+      } else if (strcmp(lc->str, "yes") == 0) {
+        ((RUNSCRIPT*) item->value)->set_target("%c");
+      } else if (strcmp(lc->str, "no") == 0) {
+        /* store nothing, run on director */
+      } else {
+        RES *res = GetResWithName(R_CLIENT, lc->str);
+        if (res == NULL) {
+           scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
+                     lc->str, lc->line_no, lc->line);
+        }
+
+        ((RUNSCRIPT*) item->value)->set_target(lc->str);
+      }
+   }
+   scan_to_eol(lc);
+}
+
+/* Store a runscript->command in a bit field
+ * 
+ */
+static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   lex_get_token(lc, T_STRING);
+
+   if (pass == 2) {
+      ((RUNSCRIPT*) item->value)->set_command(lc->str);
+   }
+   scan_to_eol(lc);
+}
+
+static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   lex_get_token(lc, T_STRING);
+   alist **runscripts = (alist **)(item->value) ;
+
+   if (pass == 2) {
+      RUNSCRIPT *script = new_runscript();
+
+      script->set_command(lc->str);
+
+      if (strcmp(item->name, "runbeforejob") == 0) {
+        script->when = SCRIPT_Before;
+        script->abort_on_error = true;
+
+      } else if (strcmp(item->name, "runafterjob") == 0) {
+        script->when = SCRIPT_After;
+        script->on_success = true;
+        script->on_failure = false;
+        
+      } else if (strcmp(item->name, "clientrunafterjob") == 0) {
+        script->when = SCRIPT_After;
+        script->set_target("%c");
+        script->on_success = true;
+        script->on_failure = false;
+
+      } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
+        script->when = SCRIPT_Before;
+        script->set_target("%c");
+        script->abort_on_error = true;
+
+      } else if (strcmp(item->name, "runafterfailedjob") == 0) {
+        script->when = SCRIPT_After;
+        script->on_failure = true;
+        script->on_success = false;
+      }
+
+      if (*runscripts == NULL) {
+        *runscripts = New(alist(10, not_owned_by_alist));
+      }
+      
+      (*runscripts)->append(script);
+      script->debug();
+   }
+
+   scan_to_eol(lc);
+}
+
+static RUNSCRIPT  res_runscript;
+
+/*
+ * new RunScript items
+ *   name             handler         value                                code flags default_value
+ */
+static RES_ITEM runscript_items[] = {
+   {"command", store_runscript_cmd,   (char **)&res_runscript,            0,  ITEM_REQUIRED, 0}, 
+   {"target", store_runscript_target, (char **)&res_runscript,            0,  0, 0}, 
+   {"runsonsuccess",    store_bool,   (char **)&res_runscript.on_success, 0,  0, 0},
+   {"runsonfailure",    store_bool,   (char **)&res_runscript.on_failure, 0,  0, 0},
+   {"abortjobonerror", store_bool,    (char **)&res_runscript.abort_on_error, 0, 0,   0},
+   {"runswhen", store_runscript_when, (char **)&res_runscript.when,       0,  0, 0},
+   {"runsonclient", store_runscript_target, (char **)&res_runscript,       0,  0, 0}, /* TODO */
+
+   {NULL, NULL, NULL, 0, 0, 0}
+};
+
+/*
+ * Store RunScript info
+ *
+ *  Note, when this routine is called, we are inside a Job
+ *  resource.  We treat the RunScript like a sort of
+ *  mini-resource within the Job resource.
+ */
+static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token, i;
+   alist **runscripts = (alist **)(item->value) ;
+
+   Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
+
+   res_runscript.reset_default();      /* setting on_success, on_failure, abort_on_error */
+   
+   token = lex_get_token(lc, T_SKIP_EOL);
+   
+   if (token != T_BOB) {
+      scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
+   }
+   
+   while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
+      if (token == T_EOB) {
+        break;
+      }
+      if (token != T_IDENTIFIER) {
+        scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
+      }
+      for (i=0; runscript_items[i].name; i++) {
+        if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
+           token = lex_get_token(lc, T_SKIP_EOL);
+           if (token != T_EQUALS) {
+              scan_err1(lc, _("expected an equals, got: %s"), lc->str);
+           }
+           
+           /* Call item handler */
+           runscript_items[i].handler(lc, &runscript_items[i], i, pass);
+           i = -1;
+           break;
+        }
+      }
+      
+      if (i >=0) {
+        scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
+      }
+   }
+
+   if (pass == 2) {
+      if (res_runscript.command == NULL) {
+        scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
+                  "command", "runscript");
+      }
+      RUNSCRIPT *script = new_runscript();
+      memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
+      
+      if (*runscripts == NULL) {
+        *runscripts = New(alist(10, not_owned_by_alist));
+      }
+      
+      (*runscripts)->append(script);
+      script->debug();
+   }
+
+   scan_to_eol(lc);
+   set_bit(index, res_all.hdr.item_present);
+}
index 7117c38fe1f4f478290bc4e42782f38bfc291ac1..3b67dbb06e292702e1003cd4222af316fef73634 100644 (file)
@@ -83,6 +83,7 @@ struct FILESET;
 struct POOL;
 struct RUN;
 struct DEVICE;
+struct RUNSCRIPT;
 
 /*
  *   Director Resource
@@ -280,11 +281,7 @@ public:
    int   RestoreJobId;                /* What -- JobId to restore */
    char *RestoreWhere;                /* Where on disk to restore -- directory */
    char *RestoreBootstrap;            /* Bootstrap file */
-   char *RunBeforeJob;                /* Run program before Job */
-   char *RunAfterJob;                 /* Run program after Job */
-   char *RunAfterFailedJob;           /* Run program after Job that errs */
-   char *ClientRunBeforeJob;          /* Run client program before Job */
-   char *ClientRunAfterJob;           /* Run client program after Job */
+   alist *RunScripts;                 /* Run {client} program {after|before} Job */
    union {
       char *WriteBootstrap;           /* Where to write bootstrap Job updates */
       char *WriteVerifyList;          /* List of changed files */
index 6c262a73416d6d751db8fd7ebceb7a4aac556e98..febd1873d82c44b4dfb6ccd09ae672327e9046f5 100644 (file)
@@ -36,16 +36,15 @@ static char filesetcmd[]  = "fileset%s\n"; /* set full fileset */
 static char jobcmd[]      = "JobId=%s Job=%s SDid=%u SDtime=%u Authorization=%s\n";
 /* Note, mtime_only is not used here -- implemented as file option */
 static char levelcmd[]    = "level = %s%s mtime_only=%d\n";
-static char runbefore[]   = "RunBeforeJob %s\n";
-static char runafter[]    = "RunAfterJob %s\n";
-
+static char runscript[]   = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
+static char runbeforenow[]= "RunBeforeNow\n";
 
 /* Responses received from File daemon */
-static char OKinc[]       = "2000 OK include\n";
-static char OKjob[]       = "2000 OK Job";
-static char OKlevel[]     = "2000 OK level\n";
-static char OKRunBefore[] = "2000 OK RunBefore\n";
-static char OKRunAfter[]  = "2000 OK RunAfter\n";
+static char OKinc[]          = "2000 OK include\n";
+static char OKjob[]          = "2000 OK Job";
+static char OKlevel[]        = "2000 OK level\n";
+static char OKRunScript[]    = "2000 OK RunScript\n";
+static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
 
 /* Forward referenced functions */
 
@@ -458,33 +457,64 @@ bool send_bootstrap_file(JCR *jcr, BSOCK *sock)
 }
 
 /*
- * Send ClientRunBeforeJob and ClientRunAfterJob to File daemon
+ * Send RunScripts to File daemon
  */
-int send_run_before_and_after_commands(JCR *jcr)
+int send_runscripts_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;
-      }
+   RUNSCRIPT *cmd;
+   bool launch_before_cmd = false;
+   POOLMEM *ehost = get_pool_memory(PM_FNAME);
+
+   Dmsg0(120, "bdird: sending runscripts to fd\n");
+   
+   foreach_alist(cmd, jcr->job->RunScripts) {
+      
+      if (cmd->can_run_at_level(jcr->JobLevel) && cmd->target) {
+
+         ehost = edit_job_codes(jcr, ehost, cmd->target, "");
+         Dmsg2(200, "bdird: runscript %s -> %s\n", cmd->target, ehost);
+
+         if (strcmp(ehost, jcr->client->hdr.name) == 0) {
+            pm_strcpy(msg, cmd->command);
+            bash_spaces(msg);
+            bnet_fsend(fd, runscript, cmd->on_success, 
+                                      cmd->on_failure,
+                                      cmd->abort_on_error,
+                                      cmd->when,
+                                      msg);
+
+            Dmsg1(120, "bdird: sending runscripts to fd '%s'\n", cmd->command);
+
+            if (!response(jcr, fd, OKRunScript, "RunScript", DISPLAY_ERROR)) {
+               set_jcr_job_status(jcr, JS_ErrorTerminated);
+               free_pool_memory(msg);
+               free_pool_memory(ehost);
+               return 0;
+            }
+            launch_before_cmd=true;
+         }
+         /*
+           else {
+           send command to an other client
+           }
+         */
+      }        
    }
-   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;
+   
+   /* TODO : we have to play with other client */
+   if (launch_before_cmd) {
+      bnet_fsend(fd, runbeforenow);
+      if (!response(jcr, fd, OKRunBeforeNow, "RunBeforeNow", DISPLAY_ERROR)) {
+        set_jcr_job_status(jcr, JS_ErrorTerminated);
+        free_pool_memory(msg);
+        free_pool_memory(ehost);
+        return 0;
       }
    }
    free_pool_memory(msg);
+   free_pool_memory(ehost);
    return 1;
 }
 
index 511581d3874f20f2053922bac8305da6bf5edd07..670270b7c8161f3337bc3d489ec8109321d2db09 100644 (file)
@@ -184,6 +184,13 @@ static void *job_thread(void *arg)
       set_jcr_job_status(jcr, JS_Canceled);
    }
 
+   /* TODO : check if it is used somewhere */
+   if (jcr->job->RunScripts == NULL)
+   {
+      Dmsg0(200, "Warning, job->RunScripts is empty\n");
+      jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
+   }
+
    /*                                
     * Note, we continue, even if the job is canceled above. This
     *  will permit proper setting of the job start record and
@@ -243,28 +250,9 @@ static void *job_thread(void *arg)
 
    } else {
 
-      /* Run Job */
-      if (jcr->job->RunBeforeJob) {
-         POOLMEM *before = get_pool_memory(PM_FNAME);
-         int status;
-         BPIPE *bpipe;
-         char line[MAXSTRING];
-
-         before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
-         bpipe = open_bpipe(before, 0, "r");
-         free_pool_memory(before);
-         while (fgets(line, sizeof(line), bpipe->rfd)) {
-            Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
-         }
-         status = close_bpipe(bpipe);
-         if (status != 0) {
-            berrno be;
-            Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
-            set_jcr_job_status(jcr, JS_FatalError);
-            update_job_end_record(jcr);
-            goto bail_out;
-         }
-      }
+      /* Run any script BeforeJob on dird */
+      run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
+
       /*
        * We re-update the job start record so that the start
        *  time is set after the run before job.  This avoids
@@ -324,37 +312,9 @@ static void *job_thread(void *arg)
          Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
          break;
       }
-      if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
-          (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
-         POOLMEM *after = get_pool_memory(PM_FNAME);
-         int status;
-         BPIPE *bpipe;
-         char line[MAXSTRING];
-
-         if (jcr->JobStatus == JS_Terminated) {
-            after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
-         } else {
-            after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
-         }
-         bpipe = open_bpipe(after, 0, "r");
-         free_pool_memory(after);
-         while (fgets(line, sizeof(line), bpipe->rfd)) {
-            Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
-         }
-         status = close_bpipe(bpipe);
-         /*
-          * Note, if we get an error here, do not mark the
-          *  job in error, simply report the error condition.
-          */
-         if (status != 0) {
-            berrno be;
-            if (jcr->JobStatus == JS_Terminated) {
-               Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
-            } else {
-               Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
-            }
-         }
-      }
+
+      run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
+
       /* Send off any queued messages */
       if (jcr->msg_queue->size() > 0) {
          dequeue_messages(jcr);
index 03b4e4d45f14c88076925c167d699ff642bb6857..212abb247af84a62e598a3a355cd0025e52399d5 100644 (file)
@@ -79,7 +79,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);
+extern int send_runscripts_commands(JCR *jcr);
 
 /* getmsg.c */
 enum e_prtmsg {
index c3e193980ce892c1bad18fca7c6fb64169876105..90fdb42a63756ad764dc9118199a03da85d77aab 100644 (file)
@@ -149,7 +149,7 @@ bool do_restore(JCR *jcr)
    }
 
 
-   if (!send_run_before_and_after_commands(jcr)) {
+   if (!send_runscripts_commands(jcr)) {
       restore_cleanup(jcr, JS_ErrorTerminated);
       return false;
    }
index f1ab6776316e2fb3f62c49d2d68979b40f1a834e..3a46402ba65c1966d1794609eaf0669fc280c306 100644 (file)
@@ -262,7 +262,7 @@ bool do_verify(JCR *jcr)
       return false;
    }
 
-   if (!send_run_before_and_after_commands(jcr)) {
+   if (!send_runscripts_commands(jcr)) {
       return false;
    }
 
index 906aab7c6c657267b3cd6e2c80ee7bb124e18d7d..2c59f340c180545e0627b44f37483b9e409ee0b7 100644 (file)
@@ -26,6 +26,7 @@
 #include "jcr.h"
 #include "acl.h"
 #include "protos.h"                   /* file daemon prototypes */
+#include "lib/runscript.h"
 #ifdef HAVE_LIBZ
 #include <zlib.h>                     /* compression headers */
 #else
index 755c55163b42e1000146ff46944bc53ec5a8f506..1e6835c780f8a1733f3f7695e5287be53c418da8 100644 (file)
@@ -55,9 +55,10 @@ static int response(JCR *jcr, BSOCK *sd, char *resp, const 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 runscript_cmd(JCR *jcr);
 static int runbefore_cmd(JCR *jcr);
 static int runafter_cmd(JCR *jcr);
-static bool run_cmd(JCR *jcr, char *cmd, const char *name);
+static int runbeforenow_cmd(JCR *jcr);
 static void set_options(findFOPTS *fo, const char *opts);
 
 
@@ -88,8 +89,10 @@ static struct s_cmds cmds[] = {
    {"storage ",     storage_cmd,   0},
    {"verify",       verify_cmd,    0},
    {"bootstrap",    bootstrap_cmd, 0},
+   {"RunBeforeNow", runbeforenow_cmd, 0},
    {"RunBeforeJob", runbefore_cmd, 0},
    {"RunAfterJob",  runafter_cmd,  0},
+   {"Run",          runscript_cmd, 0},
    {NULL,       NULL}                  /* list terminator */
 };
 
@@ -103,7 +106,7 @@ 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";
-
+static char runscript[]   = "Run OnSuccess=%u OnFailure=%u AbortOnError=%u When=%u Command=%s\n";
 /* Responses sent to Director */
 static char errmsg[]      = "2999 Invalid command\n";
 static char no_auth[]     = "2998 No Authorization\n";
@@ -122,7 +125,10 @@ 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 OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
 static char OKRunAfter[]  = "2000 OK RunAfter\n";
+static char OKRunScript[] = "2000 OK RunScript\n";
+
 
 /* Responses received from Storage Daemon */
 static char OK_end[]       = "3000 OK end\n";
@@ -130,7 +136,7 @@ static char OK_close[]     = "3000 OK close Status = %d\n";
 static char OK_open[]      = "3000 OK open ticket = %d\n";
 static char OK_data[]      = "3000 OK data\n";
 static char OK_append[]    = "3000 OK append data\n";
-static char OKSDbootstrap[] = "3000 OK bootstrap\n";
+static char OKSDbootstrap[]= "3000 OK bootstrap\n";
 
 
 /* Commands sent to Storage Daemon */
@@ -170,6 +176,7 @@ void *handle_client_request(void *dirp)
    jcr->dir_bsock = dir;
    jcr->ff = init_find_files();
    jcr->start_time = time(NULL);
+   jcr->RunScripts = New(alist(10, not_owned_by_alist));
    jcr->last_fname = get_pool_memory(PM_FNAME);
    jcr->last_fname[0] = 0;
    jcr->client_name = get_memory(strlen(my_name) + 1);
@@ -227,9 +234,9 @@ 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");
-   }
+   /* run after job */
+   run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
+
    generate_daemon_event(jcr, "JobEnd");
 
    dequeue_messages(jcr);             /* send any queued messages */
@@ -415,6 +422,7 @@ static int runbefore_cmd(JCR *jcr)
    bool ok;
    BSOCK *dir = jcr->dir_bsock;
    POOLMEM *cmd = get_memory(dir->msglen+1);
+   RUNSCRIPT *script;
 
    Dmsg1(100, "runbefore_cmd: %s", dir->msg);
    if (sscanf(dir->msg, runbefore, cmd) != 1) {
@@ -427,7 +435,12 @@ static int runbefore_cmd(JCR *jcr)
    unbash_spaces(cmd);
 
    /* Run the command now */
-   ok = run_cmd(jcr, cmd, "ClientRunBeforeJob");
+   script = new_runscript();
+   script->set_command(cmd);
+   script->when = SCRIPT_Before;
+   ok = script->run(jcr, "ClientRunBeforeJob");
+   free_runscript(script);
+
    free_memory(cmd);
    if (ok) {
       bnet_fsend(dir, OKRunBefore);
@@ -438,10 +451,19 @@ static int runbefore_cmd(JCR *jcr)
    }
 }
 
+static int runbeforenow_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
+   return  bnet_fsend(dir, OKRunBeforeNow);
+}
+
 static int runafter_cmd(JCR *jcr)
 {
    BSOCK *dir = jcr->dir_bsock;
    POOLMEM *msg = get_memory(dir->msglen+1);
+   RUNSCRIPT *cmd;
 
    Dmsg1(100, "runafter_cmd: %s", dir->msg);
    if (sscanf(dir->msg, runafter, msg) != 1) {
@@ -452,48 +474,50 @@ static int runafter_cmd(JCR *jcr)
       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);
+
+   cmd = new_runscript();
+   cmd->set_command(msg);
+   cmd->on_success = true;
+   cmd->on_failure = false;
+   cmd->when = SCRIPT_After;
+
+   jcr->RunScripts->append(cmd);
+
    free_pool_memory(msg);
    return bnet_fsend(dir, OKRunAfter);
 }
 
-static bool run_cmd(JCR *jcr, char *cmd, const char *name)
+static int runscript_cmd(JCR *jcr)
 {
-   POOLMEM *ecmd = get_pool_memory(PM_FNAME);
-   int status;
-   BPIPE *bpipe;
-   char line[MAXSTRING];
+   BSOCK *dir = jcr->dir_bsock;
+   POOLMEM *msg = get_memory(dir->msglen+1);
 
-   ecmd = edit_job_codes(jcr, ecmd, cmd, "");
-   bpipe = open_bpipe(ecmd, 0, "r");
-   free_pool_memory(ecmd);
-   if (bpipe == NULL) {
-      berrno be;
-      Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name,
-         be.strerror());
-      return false;
-   }
-   while (fgets(line, sizeof(line), bpipe->rfd)) {
-      int len = strlen(line);
-      if (len > 0 && line[len-1] == '\n') {
-         line[len-1] = 0;
-      }
-      Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
-   }
-   status = close_bpipe(bpipe);
-   if (status != 0) {
-      berrno be;
-      Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
-         status, be.strerror(status));
-      return false;
+   RUNSCRIPT *cmd = new_runscript() ;
+
+   Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
+   if (sscanf(dir->msg, runscript, &cmd->on_success, 
+                                  &cmd->on_failure,
+                                  &cmd->abort_on_error,
+                                  &cmd->when,
+                                  msg) != 5) {
+      pm_strcpy(jcr->errmsg, dir->msg);
+      Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
+      bnet_fsend(dir, _("2905 Bad RunScript command.\n"));
+      free_runscript(cmd);
+      free_memory(msg);
+      return 0;
    }
-   return true;
+   unbash_spaces(msg);
+
+   cmd->set_command(msg);
+   cmd->debug();
+   jcr->RunScripts->append(cmd);
+
+   free_pool_memory(msg);
+   return bnet_fsend(dir, OKRunScript);
 }
 
+
 static bool init_fileset(JCR *jcr)
 {
    FF_PKT *ff;
@@ -1304,6 +1328,10 @@ static int backup_cmd(JCR *jcr)
       Dmsg0(110, "Error in blast_data.\n");
    } else {
       set_jcr_job_status(jcr, JS_Terminated);
+
+      /* run shortly after end of data transmission */ 
+      run_scripts(jcr, jcr->RunScripts, "ClientAfterJobShort");
+
       if (jcr->JobStatus != JS_Terminated) {
          bnet_suppress_error_messages(sd, 1);
          goto cleanup;                /* bail out now */
@@ -1618,10 +1646,8 @@ static void filed_free_jcr(JCR *jcr)
    if (jcr->last_fname) {
       free_pool_memory(jcr->last_fname);
    }
-   if (jcr->RunAfterJob) {
-      free_pool_memory(jcr->RunAfterJob);
-   }
-
+   free_runscripts(jcr->RunScripts);
+   delete jcr->RunScripts;
 
    return;
 }
index 3808952c04efd1a59cf838440937a613f2aa99e9..39a570820f4eba1e2d0f3f8135119c90f767ed61 100644 (file)
@@ -254,7 +254,7 @@ public:
    pthread_t heartbeat_id;            /* id of heartbeat thread */
    volatile BSOCK *hb_bsock;          /* duped SD socket */
    volatile BSOCK *hb_dir_bsock;      /* duped DIR socket */
-   POOLMEM *RunAfterJob;              /* Command to run after job */
+   alist *RunScripts;                 /* Commands to run before and after job */
    bool pki_sign;                     /* Enable PKI Signatures? */
    bool pki_encrypt;                  /* Enable PKI Encryption? */
    DIGEST *digest;                    /* Last file's digest context */
@@ -322,8 +322,6 @@ public:
 
 };
 
-
-
 /*
  * Structure for all daemons that keeps some summary
  *  info on the last job run.
index b7693cfc3b07aa1c455a15e71290e1cf155006f3..76097488f9b72745b476bba8015106a6d5a27a57 100644 (file)
@@ -23,7 +23,7 @@ first_rule: all
 dummy:
 
 LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \
-         bnet.c bnet_server.c \
+         bnet.c bnet_server.c runscript.c \
          bpipe.c bshm.c bsnprintf.c btime.c \
          cram-md5.c crc32.c crypto.c daemon.c edit.c fnmatch.c \
          hmac.c idcache.c jcr.c lex.c alist.c dlist.c \
@@ -36,7 +36,7 @@ LIBSRCS = alloc.c attr.c base64.c berrno.c bsys.c bget_msg.c \
 
 
 LIBOBJS = alloc.o attr.o base64.o berrno.o bsys.o bget_msg.o \
-         bnet.o bnet_server.o \
+         bnet.o bnet_server.o runscript.o \
          bpipe.o bshm.o bsnprintf.o btime.o \
          cram-md5.o crc32.o crypto.o daemon.o edit.o fnmatch.o \
          hmac.o idcache.o jcr.o lex.o alist.o dlist.o \