]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/runscript.c
kes Fix python compiler string warning. Note, IMO the GNU C++
[bacula/bacula] / bacula / src / lib / runscript.c
index 4b851ed5767e7252e8a73c308f3c9eea6225ab26..39e10a0117037fc49517bc9498c45d081ed15c53 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2006-2007 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 two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   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 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 John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
  * Manipulation routines for RunScript list
  *
  *  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()
 {
@@ -50,8 +70,10 @@ void RUNSCRIPT::reset_default(bool free_strings)
    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)
@@ -64,7 +86,7 @@ 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;   
@@ -89,7 +111,16 @@ int run_scripts(JCR *jcr, alist *runscripts, const char *label)
    
    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");
@@ -98,48 +129,52 @@ 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))
+            )
+         {
+            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))
+             || (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->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;
@@ -155,7 +190,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));
 
@@ -168,12 +203,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;
@@ -186,41 +222,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_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: 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_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name,
-         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) {
+      set_jcr_job_status(jcr, JS_ErrorTerminated);
+   }
+   Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
+   return false;
 }
 
 void free_runscripts(alist *runscripts)
@@ -241,6 +298,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;
+}