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