]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/runscript.c
Fix #1526 about verify jobs and runscript
[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 Kern Sibbald.
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 #include "runscript.h"
41                
42 /*
43  * This function pointer is set only by the Director (dird.c),
44  * and is not set in the File daemon, because the File
45  * daemon cannot run console commands.
46  */
47 bool (*console_command)(JCR *jcr, const char *cmd) = NULL;
48
49
50 RUNSCRIPT *new_runscript()
51 {
52    Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
53    RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
54    memset(cmd, 0, sizeof(RUNSCRIPT));
55    cmd->reset_default();
56    
57    return cmd;
58 }
59
60 void RUNSCRIPT::reset_default(bool free_strings)
61 {
62    if (free_strings && command) {
63      free_pool_memory(command);
64    }
65    if (free_strings && target) {
66      free_pool_memory(target);
67    }
68    
69    target = NULL;
70    command = NULL;
71    on_success = true;
72    on_failure = false;
73    fail_on_error = true;
74    when = SCRIPT_Never;
75    old_proto = false;        /* TODO: drop this with bacula 1.42 */
76    job_code_callback = NULL;
77 }
78
79 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
80 {
81    Dmsg0(500, "runscript: creating new RUNSCRIPT object from other\n");
82
83    RUNSCRIPT *dst = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
84    memcpy(dst, src, sizeof(RUNSCRIPT));
85
86    dst->command = NULL;
87    dst->target = NULL;
88
89    dst->set_command(src->command, src->cmd_type);
90    dst->set_target(src->target);
91
92    return dst;   
93 }
94
95 void free_runscript(RUNSCRIPT *script)
96 {
97    Dmsg0(500, "runscript: freeing RUNSCRIPT object\n");
98
99    if (script->command) {
100       free_pool_memory(script->command);
101    }
102    if (script->target) {
103       free_pool_memory(script->target);
104    }
105    free(script);
106 }
107
108 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
109 {
110    Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
111    
112    RUNSCRIPT *script;
113    bool runit;
114
115    int when;
116
117    if (strstr(label, NT_("Before"))) {
118       when = SCRIPT_Before;
119    } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
120       when = SCRIPT_AfterVSS;
121    } else {
122       when = SCRIPT_After;
123    }
124
125    if (runscripts == NULL) {
126       Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
127       return 0;
128    }
129
130    foreach_alist(script, runscripts) {
131       Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
132       runit = false;
133
134       if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
135          if ((script->on_success && 
136               (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
137             || (script->on_failure && 
138                 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
139             )
140          {
141             Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", 
142                   script->command, script->on_success, script->on_failure,
143                   jcr->JobStatus );
144             runit = true;
145          }
146       }
147
148       if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
149          if ((script->on_success && (jcr->JobStatus == JS_Blocked))
150             || (script->on_failure && job_canceled(jcr))
151             )
152          {
153             Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", 
154                   script->command, script->on_success, script->on_failure,
155                   jcr->JobStatus );
156             runit = true;
157          }
158       }
159
160       if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
161          if ((script->on_success &&
162               (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
163             || (script->on_failure && 
164                 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
165             )
166          {
167             Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", 
168                   script->command, script->on_success, script->on_failure,
169                   jcr->JobStatus );
170             runit = true;
171          }
172       }
173
174       if (!script->is_local()) {
175          runit = false;
176       }
177
178       /* we execute it */
179       if (runit) {
180          script->run(jcr, label);
181       }
182    }
183    return 1;
184 }
185
186 bool RUNSCRIPT::is_local()
187 {
188    if (!target || (strcmp(target, "") == 0)) {
189       return true;
190    } else {
191       return false;
192    }
193 }
194
195 /* set this->command to cmd */
196 void RUNSCRIPT::set_command(const char *cmd, int acmd_type)
197 {
198    Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
199
200    if (!cmd) {
201       return;
202    }
203
204    if (!command) {
205       command = get_pool_memory(PM_FNAME);
206    }
207
208    pm_strcpy(command, cmd);
209    cmd_type = acmd_type;
210 }
211
212 /* set this->target to client_name */
213 void RUNSCRIPT::set_target(const char *client_name)
214 {
215    Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
216
217    if (!client_name) {
218       return;
219    }
220
221    if (!target) {
222       target = get_pool_memory(PM_FNAME);
223    }
224
225    pm_strcpy(target, client_name);
226 }
227
228 bool RUNSCRIPT::run(JCR *jcr, const char *name)
229 {
230    Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
231    POOLMEM *ecmd = get_pool_memory(PM_FNAME);
232    int status;
233    BPIPE *bpipe;
234    char line[MAXSTRING];
235
236    ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
237    Dmsg1(100, "runscript: running '%s'...\n", ecmd);
238    Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"), 
239         cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);
240
241    switch (cmd_type) {
242    case SHELL_CMD:
243       bpipe = open_bpipe(ecmd, 0, "r");
244       free_pool_memory(ecmd);
245       if (bpipe == NULL) {
246          berrno be;
247          Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
248             be.bstrerror());
249          goto bail_out;
250       }
251       while (fgets(line, sizeof(line), bpipe->rfd)) {
252          int len = strlen(line);
253          if (len > 0 && line[len-1] == '\n') {
254             line[len-1] = 0;
255          }
256          Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
257       }
258       status = close_bpipe(bpipe);
259       if (status != 0) {
260          berrno be;
261          Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
262             be.code(status), be.bstrerror(status));
263          goto bail_out;
264       }
265       Dmsg0(100, "runscript OK\n");
266       break;
267    case CONSOLE_CMD:
268       if (console_command) {                 /* can we run console command? */
269          if (!console_command(jcr, ecmd)) {  /* yes, do so */
270             goto bail_out;
271          }
272       }
273       break;
274    }
275    return true;
276
277 bail_out:
278    /* cancel running job properly */
279    if (fail_on_error) {
280       set_jcr_job_status(jcr, JS_ErrorTerminated);
281    }
282    Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
283    return false;
284 }
285
286 void free_runscripts(alist *runscripts)
287 {
288    Dmsg0(500, "runscript: freeing all RUNSCRIPTS object\n");
289
290    RUNSCRIPT *elt;
291    foreach_alist(elt, runscripts) {
292       free_runscript(elt);
293    }
294 }
295
296 void RUNSCRIPT::debug()
297 {
298    Dmsg0(200, "runscript: debug\n");
299    Dmsg0(200,  _(" --> RunScript\n"));
300    Dmsg1(200,  _("  --> Command=%s\n"), NPRT(command));
301    Dmsg1(200,  _("  --> Target=%s\n"),  NPRT(target));
302    Dmsg1(200,  _("  --> RunOnSuccess=%u\n"),  on_success);
303    Dmsg1(200,  _("  --> RunOnFailure=%u\n"),  on_failure);
304    Dmsg1(200,  _("  --> FailJobOnError=%u\n"),  fail_on_error);
305    Dmsg1(200,  _("  --> RunWhen=%u\n"),  when);
306 }
307
308 void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback) 
309 {
310    this->job_code_callback = arg_job_code_callback;
311 }