From 82d827763eef307b073a05bc3114a0d1e2b57b14 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 31 Dec 2007 12:51:49 +0000 Subject: [PATCH] Implement first cut running console commands in a RunScript. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6169 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/patches/2.2.7-old-postgresql.patch | 26 ++++++++ bacula/src/dird/dird.c | 2 + bacula/src/dird/dird_conf.c | 11 ++-- bacula/src/dird/job.c | 13 ++++ bacula/src/dird/migrate.c | 4 +- bacula/src/dird/protos.h | 5 +- bacula/src/dird/ua_cmds.c | 12 ++-- bacula/src/dird/ua_dotcmds.c | 16 ++--- bacula/src/dird/ua_server.c | 4 +- bacula/src/lib/runscript.c | 74 ++++++++++++++--------- bacula/src/lib/runscript.h | 10 ++- bacula/src/version.h | 4 +- bacula/technotes-2.3 | 2 + 13 files changed, 128 insertions(+), 55 deletions(-) create mode 100644 bacula/patches/2.2.7-old-postgresql.patch diff --git a/bacula/patches/2.2.7-old-postgresql.patch b/bacula/patches/2.2.7-old-postgresql.patch new file mode 100644 index 0000000000..d13b11865d --- /dev/null +++ b/bacula/patches/2.2.7-old-postgresql.patch @@ -0,0 +1,26 @@ + + If you have an old version of PostgreSQL, for example, + version 7.3 or older, it may not properly build with the current + Bacula release due to incompatible changes in the PostgreSQL + header files between version. Only in the case that build fails, + you might try applying this patch with: + + cd + patch -p1 <2.2.7-old-postgresql.patch + ./configure + make + ... + make install + + +diff -uNr bacula-2.2.7/src/cats/postgresql.c bacula-2.2.7-fixed/src/cats/postgresql.c +--- bacula-2.2.7/src/cats/postgresql.c 2007-12-08 04:54:55.000000000 -0500 ++++ bacula-2.2.7-fixed/src/cats/postgresql.c 2007-12-29 08:34:10.000000000 -0500 +@@ -47,7 +47,6 @@ + #ifdef HAVE_POSTGRESQL + + #include "postgres_ext.h" /* needed for NAMEDATALEN */ +-#include "pg_config_manual.h" /* get NAMEDATALEN on version 8.3 or later */ + + /* ----------------------------------------------------------------------- + * diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index fcfdb8debb..7a065582de 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -141,6 +141,8 @@ int main (int argc, char *argv[]) init_reload(); daemon_start_time = time(NULL); + console_command = run_console_command; + while ((ch = getopt(argc, argv, "c:d:fg:r:stu:v?")) != -1) { switch (ch) { case 'c': /* specify config file */ diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index e1f2a06d80..0b36d6d34a 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -1723,15 +1723,15 @@ static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass) scan_to_eol(lc); } -/* Store a runscript->command in a bit field - * +/* + * Store a runscript->command as a string */ static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass) { lex_get_token(lc, T_STRING); if (pass == 2) { - ((RUNSCRIPT*) item->value)->set_command(lc->str); + ((RUNSCRIPT*)item->value)->set_command(lc->str, item->code); } scan_to_eol(lc); } @@ -1809,10 +1809,11 @@ void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass) /* * new RunScript items - * name handler value code flags default_value + * name handler value code flags default_value */ static RES_ITEM runscript_items[] = { - {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0}, + {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0}, + {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0}, {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0}, {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0}, diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 3bdddaa818..2595688219 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -1231,3 +1231,16 @@ bool create_restore_bootstrap_file(JCR *jcr) jcr->needs_sd = true; return true; } + +bool run_console_command(JCR *jcr, const char *cmd){ + UAContext *ua; + bool ok; + + ua = new_ua_context(jcr); + Mmsg(ua->cmd, "%s", cmd); + Dmsg1(100, "Console command: %s\n", ua->cmd); + parse_ua_args(ua); + ok= do_a_command(ua); + free_ua_context(ua); + return ok; +} diff --git a/bacula/src/dird/migrate.c b/bacula/src/dird/migrate.c index e239197e35..5de5fe8697 100644 --- a/bacula/src/dird/migrate.c +++ b/bacula/src/dird/migrate.c @@ -855,11 +855,11 @@ static void start_migration_job(JCR *jcr) edit_uint64(jcr->MigrateJobId, ed1)); Dmsg1(dbglevel, "=============== Migration cmd=%s\n", ua->cmd); parse_ua_args(ua); /* parse command */ - int jobid = run_cmd(ua, ua->cmd); + JobId_t jobid = run_cmd(ua, ua->cmd); if (jobid == 0) { Jmsg(jcr, M_ERROR, 0, _("Could not start migration job.\n")); } else { - Jmsg(jcr, M_INFO, 0, _("Migration JobId %d started.\n"), jobid); + Jmsg(jcr, M_INFO, 0, _("Migration JobId %d started.\n"), (int)jobid); } free_ua_context(ua); } diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index e7d90728b9..893b980bb6 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -130,6 +130,7 @@ extern bool create_restore_bootstrap_file(JCR *jcr); extern void dird_free_jcr(JCR *jcr); extern void dird_free_jcr_pointers(JCR *jcr); extern void cancel_storage_daemon_job(JCR *jcr); +extern bool run_console_command(JCR *jcr, const char *cmd); /* migration.c */ extern bool do_migration(JCR *jcr); @@ -174,8 +175,8 @@ bool acl_access_ok(UAContext *ua, int acl, const char *item); bool acl_access_ok(UAContext *ua, int acl, const char *item, int len); /* ua_cmds.c */ -int do_a_command(UAContext *ua, const char *cmd); -int do_a_dot_command(UAContext *ua, const char *cmd); +bool do_a_command(UAContext *ua); +bool do_a_dot_command(UAContext *ua); int qmessagescmd(UAContext *ua, const char *cmd); bool open_client_db(UAContext *ua); bool open_db(UAContext *ua); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 98481052e4..72d331b484 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -149,19 +149,18 @@ static struct cmdstruct commands[] = { /* * Execute a command from the UA */ -int do_a_command(UAContext *ua, const char *cmd) +bool do_a_command(UAContext *ua) { unsigned int i; - int len, stat; + int len; bool ok = false; bool found = false; BSOCK *user = ua->UA_sock; - stat = 1; Dmsg1(900, "Command: %s\n", ua->UA_sock->msg); if (ua->argc == 0) { - return 1; + return false; } while (ua->jcr->wstorage->size()) { @@ -177,13 +176,14 @@ int do_a_command(UAContext *ua, const char *cmd) break; } if (ua->api) user->signal(BNET_CMD_BEGIN); - ok = (*commands[i].func)(ua, cmd); /* go execute command */ + ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ found = true; break; } } if (!found) { - user->fsend(_("%s: is an invalid command.\n"), ua->argk[0]); + ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]); + ok = false; } if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); return ok; diff --git a/bacula/src/dird/ua_dotcmds.c b/bacula/src/dird/ua_dotcmds.c index d8f4695074..1b1368b792 100644 --- a/bacula/src/dird/ua_dotcmds.c +++ b/bacula/src/dird/ua_dotcmds.c @@ -98,7 +98,7 @@ static struct cmdstruct commands[] = { /* * Execute a command from the UA */ -int do_a_dot_command(UAContext *ua, const char *cmd) +bool do_a_dot_command(UAContext *ua) { int i; int len; @@ -108,14 +108,14 @@ int do_a_dot_command(UAContext *ua, const char *cmd) Dmsg1(1400, "Dot command: %s\n", user->msg); if (ua->argc == 0) { - return 1; + return false; } len = strlen(ua->argk[0]); if (len == 1) { if (ua->api) user->signal(BNET_CMD_BEGIN); if (ua->api) user->signal(BNET_CMD_OK); - return 1; /* no op */ + return true; /* no op */ } for (i=0; iargk[0], _(commands[i].key), len) == 0) { @@ -125,10 +125,10 @@ int do_a_dot_command(UAContext *ua, const char *cmd) !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) { break; } - Dmsg1(100, "Cmd: %s\n", cmd); + Dmsg1(100, "Cmd: %s\n", ua->cmd); ua->gui = true; if (ua->api) user->signal(BNET_CMD_BEGIN); - ok = (*commands[i].func)(ua, cmd); /* go execute command */ + ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ ua->gui = gui; found = true; break; @@ -136,11 +136,11 @@ int do_a_dot_command(UAContext *ua, const char *cmd) } if (!found) { pm_strcat(user->msg, _(": is an invalid command.\n")); - user->msglen = strlen(user->msg); - user->send(); + ua->error_msg("%s", user->msg); + ok = false; } if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); - return 1; + return ok; } static bool dot_quit_cmd(UAContext *ua, const char *cmd) diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index 2cb78457a8..e7cb1002a6 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -142,9 +142,9 @@ static void *handle_UA_client_request(void *arg) pm_strcpy(ua->cmd, ua->UA_sock->msg); parse_ua_args(ua); if (ua->argc > 0 && ua->argk[0][0] == '.') { - do_a_dot_command(ua, ua->cmd); + do_a_dot_command(ua); } else { - do_a_command(ua, ua->cmd); + do_a_command(ua); } dequeue_messages(ua->jcr); if (!ua->quit) { diff --git a/bacula/src/lib/runscript.c b/bacula/src/lib/runscript.c index 1041be3245..7eaae64e55 100644 --- a/bacula/src/lib/runscript.c +++ b/bacula/src/lib/runscript.c @@ -38,6 +38,14 @@ #include "bacula.h" #include "jcr.h" #include "runscript.h" + +/* + * This function pointer is set only by the Director (dird.c), + * and is not set in the File daemon, because the File + * daemon cannot run console commands. + */ +bool (*console_command)(JCR *jcr, const char *cmd) = NULL; + RUNSCRIPT *new_runscript() { @@ -78,7 +86,7 @@ RUNSCRIPT *copy_runscript(RUNSCRIPT *src) dst->command = NULL; dst->target = NULL; - dst->set_command(src->command); + dst->set_command(src->command, src->cmd_type); dst->set_target(src->target); return dst; @@ -168,7 +176,7 @@ bool RUNSCRIPT::is_local() } /* set this->command to cmd */ -void RUNSCRIPT::set_command(const POOLMEM *cmd) +void RUNSCRIPT::set_command(const POOLMEM *cmd, int acmd_type) { Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd)); @@ -181,6 +189,7 @@ void RUNSCRIPT::set_command(const POOLMEM *cmd) } pm_strcpy(command, cmd); + cmd_type = acmd_type; } /* set this->target to client_name */ @@ -201,7 +210,7 @@ void RUNSCRIPT::set_target(const POOLMEM *client_name) bool RUNSCRIPT::run(JCR *jcr, const char *name) { - Dmsg0(200, "runscript: running a RUNSCRIPT object\n"); + Dmsg1(100, "runscript: running a RUNSCRIPT object type=%d\n", cmd_type); POOLMEM *ecmd = get_pool_memory(PM_FNAME); int status; BPIPE *bpipe; @@ -209,31 +218,43 @@ bool RUNSCRIPT::run(JCR *jcr, const char *name) ecmd = edit_job_codes(jcr, ecmd, this->command, "", this->job_code_callback); Dmsg1(100, "runscript: running '%s'...\n", ecmd); - Jmsg(jcr, M_INFO, 0, _("%s: run command \"%s\"\n"), name, ecmd); - - bpipe = open_bpipe(ecmd, 0, "r"); - free_pool_memory(ecmd); - if (bpipe == NULL) { - berrno be; - Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name, - be.bstrerror()); - goto bail_out; - } - while (fgets(line, sizeof(line), bpipe->rfd)) { - int len = strlen(line); - if (len > 0 && line[len-1] == '\n') { - line[len-1] = 0; + Jmsg(jcr, M_INFO, 0, _("%s: run %s \"%s\"\n"), + cmd_type==SHELL_CMD?"shell command":"console command", name, ecmd); + + switch (cmd_type) { + case SHELL_CMD: + bpipe = open_bpipe(ecmd, 0, "r"); + free_pool_memory(ecmd); + if (bpipe == NULL) { + berrno be; + Jmsg(jcr, M_ERROR, 0, _("Runscript: %s could not execute. ERR=%s\n"), name, + be.bstrerror()); + goto bail_out; } - Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line); - } - status = close_bpipe(bpipe); - if (status != 0) { - berrno be; - Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name, - be.code(status), be.bstrerror(status)); - goto bail_out; + while (fgets(line, sizeof(line), bpipe->rfd)) { + int len = strlen(line); + if (len > 0 && line[len-1] == '\n') { + line[len-1] = 0; + } + Jmsg(jcr, M_INFO, 0, _("%s: %s\n"), name, line); + } + status = close_bpipe(bpipe); + if (status != 0) { + berrno be; + Jmsg(jcr, M_ERROR, 0, _("Runscript: %s returned non-zero status=%d. ERR=%s\n"), name, + be.code(status), be.bstrerror(status)); + goto bail_out; + } + Dmsg0(100, "runscript OK\n"); + break; + case CONSOLE_CMD: + if (console_command) { /* can we run console command? */ + if (!console_command(jcr, ecmd)) { /* yes, do so */ + goto bail_out; + } + } + break; } - Dmsg0(100, "runscript OK\n"); return true; bail_out: @@ -268,7 +289,6 @@ void RUNSCRIPT::debug() } void RUNSCRIPT::set_job_code_callback(job_code_callback_t arg_job_code_callback) - { this->job_code_callback = arg_job_code_callback; } diff --git a/bacula/src/lib/runscript.h b/bacula/src/lib/runscript.h index b07e0852a7..5a6594f9a2 100644 --- a/bacula/src/lib/runscript.h +++ b/bacula/src/lib/runscript.h @@ -61,6 +61,11 @@ enum { SCRIPT_Any = SCRIPT_Before | SCRIPT_After }; +enum { + SHELL_CMD = 1, + CONSOLE_CMD = 2 +}; + /* * Structure for RunScript ressource */ @@ -69,6 +74,7 @@ public: POOLMEM *command; /* command string */ POOLMEM *target; /* host target */ int when; /* SCRIPT_Before|Script_After BEFORE/AFTER JOB*/ + int cmd_type; /* Command type -- Shell, Console */ char level; /* Base|Full|Incr...|All (NYI) */ bool on_success; /* execute command on job success (After) */ bool on_failure; /* execute command on job failure (After) */ @@ -80,7 +86,7 @@ public: bool run(JCR *job, const char *name=""); /* name must contain "Before" or "After" keyword */ bool can_run_at_level(int JobLevel) { return true;}; /* TODO */ - void set_command(const POOLMEM *cmd); + void set_command(const POOLMEM *cmd, int cmd_type = SHELL_CMD); void set_target(const POOLMEM *client_name); void reset_default(bool free_string = false); bool is_local(); /* true if running on local host */ @@ -104,4 +110,6 @@ void free_runscript(RUNSCRIPT *script); /* foreach_alist free RUNSCRIPT */ void free_runscripts(alist *runscripts); /* you have to free alist */ +extern bool (*console_command)(JCR *jcr, const char *cmd); + #endif /* __RUNSCRIPT_H_ */ diff --git a/bacula/src/version.h b/bacula/src/version.h index 7e219d6b03..2348c59310 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.3.8" -#define BDATE "24 December 2007" -#define LSMDATE "24Dec07" +#define BDATE "31 December 2007" +#define LSMDATE "31Dec07" #define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n" #define BYEAR "2007" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index 1962e40599..63fb28a6c2 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -1,6 +1,8 @@ Technical notes on version 2.3 General: +31Dec07 +kes Implement first cut running console commands in a RunScript. 29Dec07 ebl Fixes #1028 where "Selection Type" option was not usable with JobDefs. ebl Fixes #897 and #1005 where bacula doesn't display runscript -- 2.39.5