]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/runscript.c
Ensure that RunScript fails job on FD
[bacula/bacula] / bacula / src / lib / runscript.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Manipulation routines for RunScript list
30  *
31  *  Eric Bollengier, May 2006
32  *
33  *  Version $Id$
34  *
35  */
36
37
38 #include "bacula.h"
39 #include "jcr.h"
40
41 #include "runscript.h"
42
43 RUNSCRIPT *new_runscript()
44 {
45    Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
46    RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
47    memset(cmd, 0, sizeof(RUNSCRIPT));
48    cmd->reset_default();
49    
50    return cmd;
51 }
52
53 void RUNSCRIPT::reset_default(bool free_strings)
54 {
55    if (free_strings && command) {
56      free_pool_memory(command);
57    }
58    if (free_strings && target) {
59      free_pool_memory(target);
60    }
61    
62    target = NULL;
63    command = NULL;
64    on_success = true;
65    on_failure = false;
66    fail_on_error = true;
67    when = SCRIPT_Never;
68    old_proto = false;        /* TODO: drop this with bacula 1.42 */
69 }
70
71 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
72 {
73    Dmsg0(500, "runscript: creating new RUNSCRIPT object from other\n");
74
75    RUNSCRIPT *dst = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
76    memcpy(dst, src, sizeof(RUNSCRIPT));
77
78    dst->command = NULL;
79    dst->target = NULL;
80
81    dst->set_command(src->command);
82    dst->set_target(src->target);
83
84    return dst;   
85 }
86
87 void free_runscript(RUNSCRIPT *script)
88 {
89    Dmsg0(500, "runscript: freeing RUNSCRIPT object\n");
90
91    if (script->command) {
92       free_pool_memory(script->command);
93    }
94    if (script->target) {
95       free_pool_memory(script->target);
96    }
97    free(script);
98 }
99
100 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
101 {
102    Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
103    
104    RUNSCRIPT *script;
105    bool runit;
106
107    int when;
108
109    if (strstr(label, NT_("Before"))) {
110       when = SCRIPT_Before;
111    } else {
112       when = SCRIPT_After;
113    }
114
115    if (runscripts == NULL) {
116       Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
117       return 0;
118    }
119
120    foreach_alist(script, runscripts) {
121       Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
122       runit = false;
123
124       if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
125          if ((script->on_success 
126             && (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
127             || (script->on_failure && job_canceled(jcr))
128             )
129          {
130             Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", 
131                   script->command, script->on_success, script->on_failure,
132                   jcr->JobStatus );
133             runit = true;
134          }
135       }
136
137       if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
138          if ((script->on_success && (jcr->JobStatus == JS_Terminated))
139              || (script->on_failure && job_canceled(jcr))
140             )
141          {
142             Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", 
143                   script->command, script->on_success, script->on_failure,
144                   jcr->JobStatus );
145             runit = true;
146          }
147       }
148
149       if (!script->is_local()) {
150          runit = false;
151       }
152
153       /* we execute it */
154       if (runit) {
155          script->run(jcr, label);
156       }
157    }
158    return 1;
159 }
160
161 bool RUNSCRIPT::is_local()
162 {
163    if (!target || (strcmp(target, "") == 0)) {
164       return true;
165    } else {
166       return false;
167    }
168 }
169
170 /* set this->command to cmd */
171 void RUNSCRIPT::set_command(const POOLMEM *cmd)
172 {
173    Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
174
175    if (!cmd) {
176       return;
177    }
178
179    if (!command) {
180       command = get_pool_memory(PM_FNAME);
181    }
182
183    pm_strcpy(command, cmd);
184 }
185
186 /* set this->target to client_name */
187 void RUNSCRIPT::set_target(const POOLMEM *client_name)
188 {
189    Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
190
191    if (!client_name) {
192       return;
193    }
194
195    if (!target) {
196       target = get_pool_memory(PM_FNAME);
197    }
198
199    pm_strcpy(target, client_name);
200 }
201
202 bool RUNSCRIPT::run(JCR *jcr, const char *name)
203 {
204    Dmsg0(200, "runscript: running a RUNSCRIPT object\n");
205    POOLMEM *ecmd = get_pool_memory(PM_FNAME);
206    int status;
207    BPIPE *bpipe;
208    char line[MAXSTRING];
209
210    ecmd = edit_job_codes(jcr, ecmd, this->command, "");
211    Dmsg1(100, "runscript: running '%s'...\n", ecmd);
212    Jmsg(jcr, M_INFO, 0, _("%s: run command \"%s\"\n"), name, ecmd);
213
214    bpipe = open_bpipe(ecmd, 0, "r");
215    free_pool_memory(ecmd);
216    if (bpipe == NULL) {
217       berrno be;
218       Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
219          be.bstrerror());
220       goto bail_out;
221    }
222    while (fgets(line, sizeof(line), bpipe->rfd)) {
223       int len = strlen(line);
224       if (len > 0 && line[len-1] == '\n') {
225          line[len-1] = 0;
226       }
227       Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
228    }
229    status = close_bpipe(bpipe);
230    if (status != 0) {
231       berrno be;
232       Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
233          be.code(status), be.bstrerror(status));
234       goto bail_out;
235    }
236    return true;
237
238 bail_out:
239      /* cancel running job properly */
240      if (fail_on_error) {
241         set_jcr_job_status(jcr, JS_ErrorTerminated);
242      }
243      return false;
244 }
245
246 void free_runscripts(alist *runscripts)
247 {
248    Dmsg0(500, "runscript: freeing all RUNSCRIPTS object\n");
249
250    RUNSCRIPT *elt;
251    foreach_alist(elt, runscripts) {
252       free_runscript(elt);
253    }
254 }
255
256 void RUNSCRIPT::debug()
257 {
258    Dmsg0(200, "runscript: debug\n");
259    Dmsg0(200,  _(" --> RunScript\n"));
260    Dmsg1(200,  _("  --> Command=%s\n"), NPRT(command));
261    Dmsg1(200,  _("  --> Target=%s\n"),  NPRT(target));
262    Dmsg1(200,  _("  --> RunOnSuccess=%u\n"),  on_success);
263    Dmsg1(200,  _("  --> RunOnFailure=%u\n"),  on_failure);
264    Dmsg1(200,  _("  --> FailJobOnError=%u\n"),  fail_on_error);
265    Dmsg1(200,  _("  --> RunWhen=%u\n"),  when);
266 }