2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2006-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Manipulation routines for RunScript list
23 * Eric Bollengier, May 2006
30 #include "runscript.h"
33 * This function pointer is set only by the Director (dird.c),
34 * and is not set in the File daemon, because the File
35 * daemon cannot run console commands.
37 bool (*console_command)(JCR *jcr, const char *cmd) = NULL;
40 RUNSCRIPT *new_runscript()
42 Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
43 RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
44 memset(cmd, 0, sizeof(RUNSCRIPT));
50 void RUNSCRIPT::reset_default(bool free_strings)
52 if (free_strings && command) {
53 free_pool_memory(command);
55 if (free_strings && target) {
56 free_pool_memory(target);
65 old_proto = false; /* TODO: drop this with bacula 1.42 */
66 job_code_callback = NULL;
69 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
71 Dmsg0(500, "runscript: creating new RUNSCRIPT object from other\n");
73 RUNSCRIPT *dst = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
74 memcpy(dst, src, sizeof(RUNSCRIPT));
79 dst->set_command(src->command, src->cmd_type);
80 dst->set_target(src->target);
85 void free_runscript(RUNSCRIPT *script)
87 Dmsg0(500, "runscript: freeing RUNSCRIPT object\n");
89 if (script->command) {
90 free_pool_memory(script->command);
93 free_pool_memory(script->target);
98 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
100 Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
107 if (strstr(label, NT_("Before"))) {
108 when = SCRIPT_Before;
109 } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
110 when = SCRIPT_AfterVSS;
115 if (runscripts == NULL) {
116 Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
120 foreach_alist(script, runscripts) {
121 Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
124 if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
125 if ((script->on_success &&
126 (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
127 || (script->on_failure &&
128 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
131 Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n",
132 script->command, script->on_success, script->on_failure,
138 if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
139 if ((script->on_success && (jcr->JobStatus == JS_Blocked))
140 || (script->on_failure && job_canceled(jcr))
143 Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n",
144 script->command, script->on_success, script->on_failure,
150 if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
151 if ((script->on_success &&
152 (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
153 || (script->on_failure &&
154 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
157 Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n",
158 script->command, script->on_success, script->on_failure,
164 if (!script->is_local()) {
170 script->run(jcr, label);
176 bool RUNSCRIPT::is_local()
178 if (!target || (strcmp(target, "") == 0)) {
185 /* set this->command to cmd */
186 void RUNSCRIPT::set_command(const char *cmd, int acmd_type)
188 Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
195 command = get_pool_memory(PM_FNAME);
198 pm_strcpy(command, cmd);
199 cmd_type = acmd_type;
202 /* set this->target to client_name */
203 void RUNSCRIPT::set_target(const char *client_name)
205 Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
212 target = get_pool_memory(PM_FNAME);
215 pm_strcpy(target, client_name);
218 bool RUNSCRIPT::run(JCR *jcr, const char *name)
220 Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
221 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
224 char line[MAXSTRING];
226 ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
227 Dmsg1(100, "runscript: running '%s'...\n", ecmd);
228 Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"),
229 cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);
233 bpipe = open_bpipe(ecmd, 0, "r");
234 free_pool_memory(ecmd);
237 Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
241 while (fgets(line, sizeof(line), bpipe->rfd)) {
242 int len = strlen(line);
243 if (len > 0 && line[len-1] == '\n') {
246 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
248 status = close_bpipe(bpipe);
251 Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
252 be.code(status), be.bstrerror(status));
255 Dmsg0(100, "runscript OK\n");
258 if (console_command) { /* can we run console command? */
259 if (!console_command(jcr, ecmd)) { /* yes, do so */
268 /* cancel running job properly */
270 jcr->setJobStatus(JS_ErrorTerminated);
272 Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
276 void free_runscripts(alist *runscripts)
278 Dmsg0(500, "runscript: freeing all RUNSCRIPTS object\n");
281 foreach_alist(elt, runscripts) {
286 void RUNSCRIPT::debug()
288 Dmsg0(200, "runscript: debug\n");
289 Dmsg0(200, _(" --> RunScript\n"));
290 Dmsg1(200, _(" --> Command=%s\n"), NPRT(command));
291 Dmsg1(200, _(" --> Target=%s\n"), NPRT(target));
292 Dmsg1(200, _(" --> RunOnSuccess=%u\n"), on_success);
293 Dmsg1(200, _(" --> RunOnFailure=%u\n"), on_failure);
294 Dmsg1(200, _(" --> FailJobOnError=%u\n"), fail_on_error);
295 Dmsg1(200, _(" --> RunWhen=%u\n"), when);
298 void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback)
300 this->job_code_callback = arg_job_code_callback;