]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/runscript.c
ebl Permit multiple command/console per runscript definition.
[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 #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 && job_canceled(jcr))
138             )
139          {
140             Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", 
141                   script->command, script->on_success, script->on_failure,
142                   jcr->JobStatus );
143             runit = true;
144          }
145       }
146
147       if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
148          if ((script->on_success && (jcr->JobStatus == JS_Blocked))
149             || (script->on_failure && job_canceled(jcr))
150             )
151          {
152             Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", 
153                   script->command, script->on_success, script->on_failure,
154                   jcr->JobStatus );
155             runit = true;
156          }
157       }
158
159       if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
160          if ((script->on_success && (jcr->JobStatus == JS_Terminated))
161              || (script->on_failure && job_canceled(jcr))
162             )
163          {
164             Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", 
165                   script->command, script->on_success, script->on_failure,
166                   jcr->JobStatus );
167             runit = true;
168          }
169       }
170
171       if (!script->is_local()) {
172          runit = false;
173       }
174
175       /* we execute it */
176       if (runit) {
177          script->run(jcr, label);
178       }
179    }
180    return 1;
181 }
182
183 bool RUNSCRIPT::is_local()
184 {
185    if (!target || (strcmp(target, "") == 0)) {
186       return true;
187    } else {
188       return false;
189    }
190 }
191
192 /* set this->command to cmd */
193 void RUNSCRIPT::set_command(const char *cmd, int acmd_type)
194 {
195    Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
196
197    if (!cmd) {
198       return;
199    }
200
201    if (!command) {
202       command = get_pool_memory(PM_FNAME);
203    }
204
205    pm_strcpy(command, cmd);
206    cmd_type = acmd_type;
207 }
208
209 /* set this->target to client_name */
210 void RUNSCRIPT::set_target(const char *client_name)
211 {
212    Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
213
214    if (!client_name) {
215       return;
216    }
217
218    if (!target) {
219       target = get_pool_memory(PM_FNAME);
220    }
221
222    pm_strcpy(target, client_name);
223 }
224
225 bool RUNSCRIPT::run(JCR *jcr, const char *name)
226 {
227    Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
228    POOLMEM *ecmd = get_pool_memory(PM_FNAME);
229    int status;
230    BPIPE *bpipe;
231    char line[MAXSTRING];
232
233    ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
234    Dmsg1(100, "runscript: running '%s'...\n", ecmd);
235    Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"), 
236         cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);
237
238    switch (cmd_type) {
239    case SHELL_CMD:
240       bpipe = open_bpipe(ecmd, 0, "r");
241       free_pool_memory(ecmd);
242       if (bpipe == NULL) {
243          berrno be;
244          Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
245             be.bstrerror());
246          goto bail_out;
247       }
248       while (fgets(line, sizeof(line), bpipe->rfd)) {
249          int len = strlen(line);
250          if (len > 0 && line[len-1] == '\n') {
251             line[len-1] = 0;
252          }
253          Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
254       }
255       status = close_bpipe(bpipe);
256       if (status != 0) {
257          berrno be;
258          Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
259             be.code(status), be.bstrerror(status));
260          goto bail_out;
261       }
262       Dmsg0(100, "runscript OK\n");
263       break;
264    case CONSOLE_CMD:
265       if (console_command) {                 /* can we run console command? */
266          if (!console_command(jcr, ecmd)) {  /* yes, do so */
267             goto bail_out;
268          }
269       }
270       break;
271    }
272    return true;
273
274 bail_out:
275    /* cancel running job properly */
276    if (fail_on_error) {
277       set_jcr_job_status(jcr, JS_ErrorTerminated);
278    }
279    Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
280    return false;
281 }
282
283 void free_runscripts(alist *runscripts)
284 {
285    Dmsg0(500, "runscript: freeing all RUNSCRIPTS object\n");
286
287    RUNSCRIPT *elt;
288    foreach_alist(elt, runscripts) {
289       free_runscript(elt);
290    }
291 }
292
293 void RUNSCRIPT::debug()
294 {
295    Dmsg0(200, "runscript: debug\n");
296    Dmsg0(200,  _(" --> RunScript\n"));
297    Dmsg1(200,  _("  --> Command=%s\n"), NPRT(command));
298    Dmsg1(200,  _("  --> Target=%s\n"),  NPRT(target));
299    Dmsg1(200,  _("  --> RunOnSuccess=%u\n"),  on_success);
300    Dmsg1(200,  _("  --> RunOnFailure=%u\n"),  on_failure);
301    Dmsg1(200,  _("  --> FailJobOnError=%u\n"),  fail_on_error);
302    Dmsg1(200,  _("  --> RunWhen=%u\n"),  when);
303 }
304
305 void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback) 
306 {
307    this->job_code_callback = arg_job_code_callback;
308 }