]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/runscript.c
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / lib / runscript.c
index 740fbd37a39b3759d4b0ac8713dc42358b54a4c7..bbe7ce06379d4a1a28d7b78566c0aa596d9fe7c1 100644 (file)
@@ -1,39 +1,48 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2016 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.
+*/
 /*
  * Manipulation routines for RunScript list
  *
  *  Eric Bollengier, May 2006
  *
- *  Version $Id$
- *
- */
-/*
-   Copyright (C) 2000-2006 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   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 
-   the file LICENSE for additional details.
-
  */
 
 
 #include "bacula.h"
 #include "jcr.h"
-
 #include "runscript.h"
 
+/*
+ * This function pointer is set only by the Director (dird.c),
+ * and is not set in the File daemon, because the File
+ * daemon cannot run console commands.
+ */
+bool (*console_command)(JCR *jcr, const char *cmd) = NULL;
+
+
 RUNSCRIPT *new_runscript()
 {
    Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
    RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
    memset(cmd, 0, sizeof(RUNSCRIPT));
    cmd->reset_default();
-   
+
    return cmd;
 }
 
@@ -45,14 +54,15 @@ void RUNSCRIPT::reset_default(bool free_strings)
    if (free_strings && target) {
      free_pool_memory(target);
    }
-   
+
    target = NULL;
    command = NULL;
    on_success = true;
    on_failure = false;
-   abort_on_error = true;
+   fail_on_error = true;
    when = SCRIPT_Never;
    old_proto = false;        /* TODO: drop this with bacula 1.42 */
+   job_code_callback = NULL;
 }
 
 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
@@ -65,10 +75,10 @@ RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
    dst->command = NULL;
    dst->target = NULL;
 
-   dst->set_command(src->command);
+   dst->set_command(src->command, src->cmd_type);
    dst->set_target(src->target);
 
-   return dst;   
+   return dst;
 }
 
 void free_runscript(RUNSCRIPT *script)
@@ -87,10 +97,19 @@ void free_runscript(RUNSCRIPT *script)
 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
 {
    Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
-   
+
    RUNSCRIPT *script;
    bool runit;
-   bool status;
+
+   int when;
+
+   if (strstr(label, NT_("Before"))) {
+      when = SCRIPT_Before;
+   } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
+      when = SCRIPT_AfterVSS;
+   } else {
+      when = SCRIPT_After;
+   }
 
    if (runscripts == NULL) {
       Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
@@ -99,48 +118,55 @@ int run_scripts(JCR *jcr, alist *runscripts, const char *label)
 
    foreach_alist(script, runscripts) {
       Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
-      runit=false;
-
-      if ((script->when & SCRIPT_Before) && (jcr->JobStatus == JS_Created)) {
-        Dmsg0(200, "runscript: Run it because SCRIPT_Before\n");
-        runit = true;
+      runit = false;
+
+      if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
+         if ((script->on_success &&
+              (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
+            || (script->on_failure &&
+                (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
+            )
+         {
+            Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n",
+                  script->command, script->on_success, script->on_failure,
+                  jcr->JobStatus );
+            runit = true;
+         }
       }
 
-      if ((script->when & SCRIPT_Before) && (jcr->JobStatus == JS_Running)) {
-        Dmsg0(200, "runscript: Run it because SCRIPT_Before\n");
-        runit = true;
+      if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
+         if ((script->on_success && (jcr->JobStatus == JS_Blocked))
+            || (script->on_failure && job_canceled(jcr))
+            )
+         {
+            Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n",
+                  script->command, script->on_success, script->on_failure,
+                  jcr->JobStatus );
+            runit = true;
+         }
       }
 
-      if (script->when & SCRIPT_After) {
-        if (  (script->on_success && (jcr->JobStatus == JS_Terminated))
-            ||
-              (script->on_failure && job_canceled(jcr))
-           )
-        {
-           Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", script->command,
-                                                                                script->on_success,
-                                                                                script->on_failure,
-                                                                                jcr->JobStatus );
-           runit = true;
-        }
+      if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
+         if ((script->on_success &&
+              (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
+            || (script->on_failure &&
+                (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
+            )
+         {
+            Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n",
+                  script->command, script->on_success, script->on_failure,
+                  jcr->JobStatus );
+            runit = true;
+         }
       }
 
       if (!script->is_local()) {
-         runit=false;
+         runit = false;
       }
 
       /* we execute it */
       if (runit) {
-        status = script->run(jcr, label);
-
-        /* cancel running job properly */
-        if (   script->abort_on_error 
-            && (status == false) 
-            && (jcr->JobStatus == JS_Created)
-           )
-        {
-           set_jcr_job_status(jcr, JS_ErrorTerminated);
-        }
+         script->run(jcr, label);
       }
    }
    return 1;
@@ -156,7 +182,7 @@ bool RUNSCRIPT::is_local()
 }
 
 /* set this->command to cmd */
-void RUNSCRIPT::set_command(const POOLMEM *cmd)
+void RUNSCRIPT::set_command(const char *cmd, int acmd_type)
 {
    Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
 
@@ -169,12 +195,13 @@ void RUNSCRIPT::set_command(const POOLMEM *cmd)
    }
 
    pm_strcpy(command, cmd);
+   cmd_type = acmd_type;
 }
 
 /* set this->target to client_name */
-void RUNSCRIPT::set_target(const POOLMEM *client_name)
+void RUNSCRIPT::set_target(const char *client_name)
 {
-   Dmsg1(500, "runscript: setting target\n", NPRT(client_name));
+   Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
 
    if (!client_name) {
       return;
@@ -187,41 +214,62 @@ void RUNSCRIPT::set_target(const POOLMEM *client_name)
    pm_strcpy(target, client_name);
 }
 
-int RUNSCRIPT::run(JCR *jcr, const char *name)
+bool RUNSCRIPT::run(JCR *jcr, const char *name)
 {
-   Dmsg0(200, "runscript: running a RUNSCRIPT object\n");
+   Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
    POOLMEM *ecmd = get_pool_memory(PM_FNAME);
    int status;
    BPIPE *bpipe;
    char line[MAXSTRING];
 
-   ecmd = edit_job_codes(jcr, ecmd, this->command, "");
+   ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
    Dmsg1(100, "runscript: running '%s'...\n", ecmd);
-   Jmsg(jcr, M_INFO, 0, _("%s: run command \"%s\"\n"), name, ecmd);
-
-   bpipe = open_bpipe(ecmd, 0, "r");
-   free_pool_memory(ecmd);
-   if (bpipe == NULL) {
-      berrno be;
-      Jmsg(jcr, M_ERROR, 0, _("Runscript: %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: run %s \"%s\"\n"),
+        cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);
+
+   switch (cmd_type) {
+   case SHELL_CMD:
+      bpipe = open_bpipe(ecmd, 0, "r");
+      free_pool_memory(ecmd);
+      if (bpipe == NULL) {
+         berrno be;
+         Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
+            be.bstrerror());
+         goto bail_out;
       }
-      Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
-   }
-   status = close_bpipe(bpipe);
-   if (status != 0) {
-      berrno be;
-      Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
-         be.code(status), be.strerror(status));
-      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_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
+            be.code(status), be.bstrerror(status));
+         goto bail_out;
+      }
+      Dmsg0(100, "runscript OK\n");
+      break;
+   case CONSOLE_CMD:
+      if (console_command) {                 /* can we run console command? */
+         if (!console_command(jcr, ecmd)) {  /* yes, do so */
+            goto bail_out;
+         }
+      }
+      break;
    }
    return true;
+
+bail_out:
+   /* cancel running job properly */
+   if (fail_on_error) {
+      jcr->setJobStatus(JS_ErrorTerminated);
+   }
+   Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
+   return false;
 }
 
 void free_runscripts(alist *runscripts)
@@ -242,6 +290,11 @@ void RUNSCRIPT::debug()
    Dmsg1(200,  _("  --> Target=%s\n"),  NPRT(target));
    Dmsg1(200,  _("  --> RunOnSuccess=%u\n"),  on_success);
    Dmsg1(200,  _("  --> RunOnFailure=%u\n"),  on_failure);
-   Dmsg1(200,  _("  --> AbortJobOnError=%u\n"),  abort_on_error);
+   Dmsg1(200,  _("  --> FailJobOnError=%u\n"),  fail_on_error);
    Dmsg1(200,  _("  --> RunWhen=%u\n"),  when);
 }
+
+void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback)
+{
+   this->job_code_callback = arg_job_code_callback;
+}