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