]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/runscript.c
Implement RestoreObject for sqlite + cleanups
[bacula/bacula] / bacula / src / lib / runscript.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2011 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 three of the GNU Affero 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 Affero 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  */
34
35
36 #include "bacula.h"
37 #include "jcr.h"
38 #include "runscript.h"
39                
40 /*
41  * This function pointer is set only by the Director (dird.c),
42  * and is not set in the File daemon, because the File
43  * daemon cannot run console commands.
44  */
45 bool (*console_command)(JCR *jcr, const char *cmd) = NULL;
46
47
48 RUNSCRIPT *new_runscript()
49 {
50    Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
51    RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
52    memset(cmd, 0, sizeof(RUNSCRIPT));
53    cmd->reset_default();
54    
55    return cmd;
56 }
57
58 void RUNSCRIPT::reset_default(bool free_strings)
59 {
60    if (free_strings && command) {
61      free_pool_memory(command);
62    }
63    if (free_strings && target) {
64      free_pool_memory(target);
65    }
66    
67    target = NULL;
68    command = NULL;
69    on_success = true;
70    on_failure = false;
71    fail_on_error = true;
72    when = SCRIPT_Never;
73    old_proto = false;        /* TODO: drop this with bacula 1.42 */
74    job_code_callback = NULL;
75 }
76
77 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
78 {
79    Dmsg0(500, "runscript: creating new RUNSCRIPT object from other\n");
80
81    RUNSCRIPT *dst = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
82    memcpy(dst, src, sizeof(RUNSCRIPT));
83
84    dst->command = NULL;
85    dst->target = NULL;
86
87    dst->set_command(src->command, src->cmd_type);
88    dst->set_target(src->target);
89
90    return dst;   
91 }
92
93 void free_runscript(RUNSCRIPT *script)
94 {
95    Dmsg0(500, "runscript: freeing RUNSCRIPT object\n");
96
97    if (script->command) {
98       free_pool_memory(script->command);
99    }
100    if (script->target) {
101       free_pool_memory(script->target);
102    }
103    free(script);
104 }
105
106 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
107 {
108    Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
109    
110    RUNSCRIPT *script;
111    bool runit;
112
113    int when;
114
115    if (strstr(label, NT_("Before"))) {
116       when = SCRIPT_Before;
117    } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
118       when = SCRIPT_AfterVSS;
119    } else {
120       when = SCRIPT_After;
121    }
122
123    if (runscripts == NULL) {
124       Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
125       return 0;
126    }
127
128    foreach_alist(script, runscripts) {
129       Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
130       runit = false;
131
132       if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
133          if ((script->on_success && 
134               (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
135             || (script->on_failure && 
136                 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
137             )
138          {
139             Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", 
140                   script->command, script->on_success, script->on_failure,
141                   jcr->JobStatus );
142             runit = true;
143          }
144       }
145
146       if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
147          if ((script->on_success && (jcr->JobStatus == JS_Blocked))
148             || (script->on_failure && job_canceled(jcr))
149             )
150          {
151             Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", 
152                   script->command, script->on_success, script->on_failure,
153                   jcr->JobStatus );
154             runit = true;
155          }
156       }
157
158       if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
159          if ((script->on_success &&
160               (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
161             || (script->on_failure && 
162                 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
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       jcr->setJobStatus(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 }