2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Manipulation routines for RunScript list
22 * Eric Bollengier, May 2006
29 #include "runscript.h"
32 * This function pointer is set only by the Director (dird.c),
33 * and is not set in the File daemon, because the File
34 * daemon cannot run console commands.
36 bool (*console_command)(JCR *jcr, const char *cmd) = NULL;
39 RUNSCRIPT *new_runscript()
41 Dmsg0(500, "runscript: creating new RUNSCRIPT object\n");
42 RUNSCRIPT *cmd = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
43 memset(cmd, 0, sizeof(RUNSCRIPT));
49 void RUNSCRIPT::reset_default(bool free_strings)
51 if (free_strings && command) {
52 free_pool_memory(command);
54 if (free_strings && target) {
55 free_pool_memory(target);
64 old_proto = false; /* TODO: drop this with bacula 1.42 */
65 job_code_callback = NULL;
68 RUNSCRIPT *copy_runscript(RUNSCRIPT *src)
70 Dmsg0(500, "runscript: creating new RUNSCRIPT object from other\n");
72 RUNSCRIPT *dst = (RUNSCRIPT *)malloc(sizeof(RUNSCRIPT));
73 memcpy(dst, src, sizeof(RUNSCRIPT));
78 dst->set_command(src->command, src->cmd_type);
79 dst->set_target(src->target);
84 void free_runscript(RUNSCRIPT *script)
86 Dmsg0(500, "runscript: freeing RUNSCRIPT object\n");
88 if (script->command) {
89 free_pool_memory(script->command);
92 free_pool_memory(script->target);
97 int run_scripts(JCR *jcr, alist *runscripts, const char *label)
99 Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus);
106 if (strstr(label, NT_("Before"))) {
107 when = SCRIPT_Before;
108 } else if (bstrcmp(label, NT_("ClientAfterVSS"))) {
109 when = SCRIPT_AfterVSS;
114 if (runscripts == NULL) {
115 Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n");
119 foreach_alist(script, runscripts) {
120 Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command));
123 if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) {
124 if ((script->on_success &&
125 (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created))
126 || (script->on_failure &&
127 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
130 Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n",
131 script->command, script->on_success, script->on_failure,
137 if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) {
138 if ((script->on_success && (jcr->JobStatus == JS_Blocked))
139 || (script->on_failure && job_canceled(jcr))
142 Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n",
143 script->command, script->on_success, script->on_failure,
149 if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) {
150 if ((script->on_success &&
151 (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings))
152 || (script->on_failure &&
153 (job_canceled(jcr) || jcr->JobStatus == JS_Differences))
156 Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n",
157 script->command, script->on_success, script->on_failure,
163 if (!script->is_local()) {
169 script->run(jcr, label);
175 bool RUNSCRIPT::is_local()
177 if (!target || (strcmp(target, "") == 0)) {
184 /* set this->command to cmd */
185 void RUNSCRIPT::set_command(const char *cmd, int acmd_type)
187 Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd));
194 command = get_pool_memory(PM_FNAME);
197 pm_strcpy(command, cmd);
198 cmd_type = acmd_type;
201 /* set this->target to client_name */
202 void RUNSCRIPT::set_target(const char *client_name)
204 Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name));
211 target = get_pool_memory(PM_FNAME);
214 pm_strcpy(target, client_name);
217 bool RUNSCRIPT::run(JCR *jcr, const char *name)
219 Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type);
220 POOLMEM *ecmd = get_pool_memory(PM_FNAME);
223 char line[MAXSTRING];
225 ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback);
226 Dmsg1(100, "runscript: running '%s'...\n", ecmd);
227 Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"),
228 cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd);
232 bpipe = open_bpipe(ecmd, 0, "r");
233 free_pool_memory(ecmd);
236 Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name,
240 while (fgets(line, sizeof(line), bpipe->rfd)) {
241 int len = strlen(line);
242 if (len > 0 && line[len-1] == '\n') {
245 Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line);
247 status = close_bpipe(bpipe);
250 Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name,
251 be.code(status), be.bstrerror(status));
254 Dmsg0(100, "runscript OK\n");
257 if (console_command) { /* can we run console command? */
258 if (!console_command(jcr, ecmd)) { /* yes, do so */
267 /* cancel running job properly */
269 jcr->setJobStatus(JS_ErrorTerminated);
271 Dmsg1(100, "runscript failed. fail_on_error=%d\n", fail_on_error);
275 void free_runscripts(alist *runscripts)
277 Dmsg0(500, "runscript: freeing all RUNSCRIPTS object\n");
280 foreach_alist(elt, runscripts) {
285 void RUNSCRIPT::debug()
287 Dmsg0(200, "runscript: debug\n");
288 Dmsg0(200, _(" --> RunScript\n"));
289 Dmsg1(200, _(" --> Command=%s\n"), NPRT(command));
290 Dmsg1(200, _(" --> Target=%s\n"), NPRT(target));
291 Dmsg1(200, _(" --> RunOnSuccess=%u\n"), on_success);
292 Dmsg1(200, _(" --> RunOnFailure=%u\n"), on_failure);
293 Dmsg1(200, _(" --> FailJobOnError=%u\n"), fail_on_error);
294 Dmsg1(200, _(" --> RunWhen=%u\n"), when);
297 void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback)
299 this->job_code_callback = arg_job_code_callback;