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