]> git.sur5r.net Git - bacula/bacula/commitdiff
Implement first cut running console commands in a RunScript.
authorKern Sibbald <kern@sibbald.com>
Mon, 31 Dec 2007 12:51:49 +0000 (12:51 +0000)
committerKern Sibbald <kern@sibbald.com>
Mon, 31 Dec 2007 12:51:49 +0000 (12:51 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6169 91ce42f0-d328-0410-95d8-f526ca767f89

13 files changed:
bacula/patches/2.2.7-old-postgresql.patch [new file with mode: 0644]
bacula/src/dird/dird.c
bacula/src/dird/dird_conf.c
bacula/src/dird/job.c
bacula/src/dird/migrate.c
bacula/src/dird/protos.h
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_dotcmds.c
bacula/src/dird/ua_server.c
bacula/src/lib/runscript.c
bacula/src/lib/runscript.h
bacula/src/version.h
bacula/technotes-2.3

diff --git a/bacula/patches/2.2.7-old-postgresql.patch b/bacula/patches/2.2.7-old-postgresql.patch
new file mode 100644 (file)
index 0000000..d13b118
--- /dev/null
@@ -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 <bacula-2.2.7-source>
+ patch -p1 <2.2.7-old-postgresql.patch
+ ./configure <your-options>
+ 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 */
+ /* -----------------------------------------------------------------------
+  *
index fcfdb8debb298df2d0f843b970c5833f530043dd..7a065582de910df0d482e7774509ce57e2a8707a 100644 (file)
@@ -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 */
index e1f2a06d80ec484155eae5306cfe6acf4cd0b573..0b36d6d34aee8fa2e82eeeb12bb1cb6a14166564 100644 (file)
@@ -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},
index 3bdddaa818a44a4a797e4e13e5cf595ee276a655..2595688219e114a7d95b155e63dfd5c038d95e6f 100644 (file)
@@ -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;
+}
index e239197e352f22d21c2c7377b7fa36ca50afd881..5de5fe8697bb21def16926ef40f1203c912c7beb 100644 (file)
@@ -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);
 }
index e7d90728b90981a96c8a2dcae01a6e86f736090b..893b980bb68d34d9f224b52692ebf0097aacab59 100644 (file)
@@ -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);
index 98481052e4ea72ef3acd2caef6fc03e78085d37d..72d331b484de7b3264f8cf17d2495aef845454ff 100644 (file)
@@ -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;
index d8f4695074ca79564e45dbebd2452359264eb7be..1b1368b792214c9b768e4546b813d9de20cc14f0 100644 (file)
@@ -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; i<comsize; i++) {     /* search for command */
       if (strncasecmp(ua->argk[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)
index 2cb78457a8d61be3d87412acfe341ca553c75b92..e7cb1002a6b3f1e903702d51b29097a48303395c 100644 (file)
@@ -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) {
index 1041be32450a222b4eef45eab7a67f92a5025bab..7eaae64e55267deab84323b37ab0cd1705828c95 100644 (file)
 #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;
 }
index b07e0852a7101bbc78930241a83bdd65ed4507e4..5a6594f9a268f4d07c36ebd8b93ad042f64ae8d4 100644 (file)
@@ -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_ */
index 7e219d6b036afa8835a7862a2dc5106b0ea5d4ff..2348c59310c637052979e4268f547ad2aa4d7c68 100644 (file)
@@ -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 */
index 1962e40599ee131a251d92f701235dc01b2baffa..63fb28a6c217d5cbebcba91c18dd1c48931bd9c2 100644 (file)
@@ -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