]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_cmds.c
Patch to add MySQL ssl access
[bacula/bacula] / bacula / src / dird / ua_cmds.c
index 32a1aea5bdde2355ae3565df888330ec536f4605..33b93afcb4a1ddaca063998a6e9f2da62384bca7 100644 (file)
@@ -1,29 +1,21 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2015 Kern Sibbald
+   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  *
  *
  *     Kern Sibbald, September MM
  *
- *   Version $Id$
  */
+
 #include "bacula.h"
 #include "dird.h"
 
-#ifdef HAVE_PYTHON
-
-#undef _POSIX_C_SOURCE
-#include <Python.h>
-
-#include "lib/pythonlib.h"
-
-/* Imported Functions */
-extern PyObject *job_getattr(PyObject *self, char *attrname);
-extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
-
-#endif /* HAVE_PYTHON */
-
 /* Imported subroutines */
 
 /* Imported variables */
@@ -64,7 +42,8 @@ extern int list_cmd(UAContext *ua, const char *cmd);
 extern int llist_cmd(UAContext *ua, const char *cmd);
 extern int messagescmd(UAContext *ua, const char *cmd);
 extern int prunecmd(UAContext *ua, const char *cmd);
-extern int purgecmd(UAContext *ua, const char *cmd);
+extern int purge_cmd(UAContext *ua, const char *cmd);
+extern int truncate_cmd(UAContext *ua, const char *cmd);  /* in ua_purge.c */
 extern int querycmd(UAContext *ua, const char *cmd);
 extern int relabel_cmd(UAContext *ua, const char *cmd);
 extern int restore_cmd(UAContext *ua, const char *cmd);
@@ -86,10 +65,10 @@ static int estimate_cmd(UAContext *ua, const char *cmd);
 static int help_cmd(UAContext *ua, const char *cmd);
 static int memory_cmd(UAContext *ua, const char *cmd);
 static int mount_cmd(UAContext *ua, const char *cmd);
-static int python_cmd(UAContext *ua, const char *cmd);
 static int release_cmd(UAContext *ua, const char *cmd);
 static int reload_cmd(UAContext *ua, const char *cmd);
 static int setdebug_cmd(UAContext *ua, const char *cmd);
+static int setbwlimit_cmd(UAContext *ua, const char *cmd);
 static int setip_cmd(UAContext *ua, const char *cmd);
 static int time_cmd(UAContext *ua, const char *cmd);
 static int trace_cmd(UAContext *ua, const char *cmd);
@@ -100,69 +79,144 @@ static int version_cmd(UAContext *ua, const char *cmd);
 static int wait_cmd(UAContext *ua, const char *cmd);
 
 static void do_job_delete(UAContext *ua, JobId_t JobId);
-static void delete_job_id_range(UAContext *ua, char *tok);
 static int delete_volume(UAContext *ua);
 static int delete_pool(UAContext *ua);
 static void delete_job(UAContext *ua);
+static void do_storage_cmd(UAContext *ua, const char *command);
 
 int qhelp_cmd(UAContext *ua, const char *cmd);
 int quit_cmd(UAContext *ua, const char *cmd);
 
 /* not all in alphabetical order.  New commands are added after existing commands with similar letters
    to prevent breakage of existing user scripts.  */
-struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; const bool use_in_rs;};
+struct cmdstruct {
+   const char *key;                             /* command */
+   int (*func)(UAContext *ua, const char *cmd); /* handler */
+   const char *help;            /* main purpose */
+   const char *usage;           /* all arguments to build usage */
+   const bool use_in_rs;        /* Can use it in Console RunScript */
+};
 static struct cmdstruct commands[] = {                                      /* Can use it in Console RunScript*/
- { NT_("add"),        add_cmd,         _("add [pool=<pool-name> storage=<storage> jobid=<JobId>] -- add media to a pool"),                      false},
- { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages"),false},
- { NT_("automount"),   automount_cmd,  _("automount [on|off] -- after label"),        false},
- { NT_("cancel"),     cancel_cmd,    _("cancel [jobid=<number> job=<job-name> ujobid=<unique-jobid>] -- cancel a job"), false},
- { NT_("create"),     create_cmd,    _("create [pool=<pool-name>] -- create DB Pool from resource"),               false},
- { NT_("delete"),     delete_cmd,    _("delete [volume=<vol-name> pool=<pool-name> job jobid=<id>]"), true},
- { NT_("disable"),    disable_cmd,   _("disable <job=name> -- disable a job"),        true},
- { NT_("enable"),     enable_cmd,    _("enable <job=name> -- enable a job"),          true},
- { NT_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing"), true},
- { NT_("exit"),       quit_cmd,      _("exit = quit"),                                false},
- { NT_("gui"),        gui_cmd,       _("gui [on|off] -- non-interactive gui mode"),   false},
- { NT_("help"),       help_cmd,      _("print this command"),                         false},
- { NT_("label"),      label_cmd,     _("label a tape"),                               false},
- { NT_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn> | copies <jobid=nn>]; from catalog"), true},
- { NT_("llist"),      llist_cmd,     _("full or long list like list command"),        true},
- { NT_("messages"),   messagescmd,   _("messages"),                                   false},
- { NT_("memory"),     memory_cmd,    _("print current memory usage"),                 true},
- { NT_("mount"),      mount_cmd,     _("mount storage=<storage-name> [ slot=<num> ] [ drive=<num> ] or mount [ jobid=<id> | job=<job-name> ]"),                       false},
- { NT_("prune"),      prunecmd,      _("prune files|jobs|volume client=<client-name> volume=<volume-name> prune expired records from catalog"),         true},
- { NT_("purge"),      purgecmd,      _("purge records from catalog"),                 true},
- { NT_("python"),     python_cmd,    _("python control commands"),                    false},
- { NT_("quit"),       quit_cmd,      _("quit"),                                       false},
- { NT_("query"),      querycmd,      _("query catalog"),                              false},
- { NT_("restore"),    restore_cmd,   _("restore files"),                              false},
- { NT_("relabel"),    relabel_cmd,   _("relabel storage=<storage-name> oldvolume=<old-volume-name> volume=<newvolume-name> -- relabel a tape"),                             false},
- { NT_("release"),    release_cmd,   _("release <storage-name>"),                     false},
- { NT_("reload"),     reload_cmd,    _("reload conf file"),                           true},
- { NT_("run"),        run_cmd,       _("run job=<job-name> client=<client-name> fileset=<FileSet-name> level=<level-keyword> storage=<storage-name> where=<directory-prefix> when=<universal-time-specification> yes"),                             false}, /* need to be check */
- { NT_("status"),     status_cmd,    _("status [all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> | days=nnn]"),           true},
- { NT_("setdebug"),   setdebug_cmd,  _("setdebug level=nn [trace=0/1 client=<client-name> | dir | director | storage=<storage-name> | all]  -- sets debug level"),                           true},
- { NT_("setip"),      setip_cmd,     _("sets new client address -- if authorized"),   false},
- { NT_("show"),       show_cmd,      _("show (resource records) [jobs | pools | ... | all]"), true},
- { NT_("sqlquery"),   sqlquerycmd,   _("use SQL to query catalog"),                   false},
- { NT_("time"),       time_cmd,      _("print current time"),                         true},
- { NT_("trace"),      trace_cmd,     _("turn on/off trace to file"),                  true},
- { NT_("unmount"),    unmount_cmd,   _("unmount storage=<storage-name> [ drive=<num> ] or unmount [ jobid=<id> | job=<job-name> ]"),                     false},
- { NT_("umount"),     unmount_cmd,   _("umount - for old-time Unix guys, see unmount"),false},
- { NT_("update"),     update_cmd,    _("update Volume, Pool or slots"),               true},
- { NT_("use"),        use_cmd,       _("use <database-name> -- catalog xxx"),                            false},
- { NT_("var"),        var_cmd,       _("does variable expansion"),                    false},
- { NT_("version"),    version_cmd,   _("print Director version"),                     true},
- { NT_("wait"),       wait_cmd,      _("wait [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>] -- wait until no jobs are running"), false},
-             };
-#define comsize (sizeof(commands)/sizeof(struct cmdstruct))
+ { NT_("add"),        add_cmd,     _("Add media to a pool"),   NT_("pool=<pool-name> storage=<storage> jobid=<JobId>"),  false},
+ { NT_("autodisplay"), autodisplay_cmd,_("Autodisplay console messages"), NT_("on | off"),    false},
+ { NT_("automount"),   automount_cmd,  _("Automount after label"),        NT_("on | off"),    false},
+ { NT_("cancel"),     cancel_cmd,    _("Cancel a job"), NT_("jobid=<number-list> | job=<job-name> | ujobid=<unique-jobid> | inactive client=<client-name> storage=<storage-name> | all"), false},
+ { NT_("create"),     create_cmd,    _("Create DB Pool from resource"), NT_("pool=<pool-name>"),                    false},
+ { NT_("delete"),     delete_cmd,    _("Delete volume, pool or job"), NT_("volume=<vol-name> | pool=<pool-name> | jobid=<id> | snapshot"), true},
+ { NT_("disable"),    disable_cmd,   _("Disable a job, attributes batch process"), NT_("job=<name> | batch"),  true},
+ { NT_("enable"),     enable_cmd,    _("Enable a job, attributes batch process"), NT_("job=<name> | batch"),   true},
+ { NT_("estimate"),   estimate_cmd,  _("Performs FileSet estimate, listing gives full listing"),
+   NT_("fileset=<fs> client=<cli> level=<level> accurate=<yes/no> job=<job> listing"), true},
+
+ { NT_("exit"),       quit_cmd,      _("Terminate Bconsole session"), NT_(""),         false},
+ { NT_("gui"),        gui_cmd,       _("Non-interactive gui mode"),   NT_("on | off"), false},
+ { NT_("help"),       help_cmd,      _("Print help on specific command"),
+   NT_("add autodisplay automount cancel create delete disable\n\tenable estimate exit gui label list llist"
+       "\n\tmessages memory mount prune purge quit query\n\trestore relabel release reload run status"
+       "\n\tsetbandwidth setdebug setip show sqlquery time trace unmount\n\tumount update use var version wait"
+       "\n\tsnapshot"),         false},
+
+ { NT_("label"),      label_cmd,     _("Label a tape"), NT_("storage=<storage> volume=<vol> pool=<pool> slot=<slot> barcodes"), false},
+ { NT_("list"),       list_cmd,      _("List objects from catalog"),
+   NT_("jobs [client=<cli>] [jobid=<nn>] [ujobid=<name>] [job=<name>] [joberrors] [jobstatus=<s>] [limit=<n>]|\n"
+       "\tjobtotals | pools | volume | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn> |\n"
+       "\tjoblog jobid=<nn> | pluginrestoreconf jobid=<nn> restoreobjectid=<nn> | snapshot"), false},
+
+ { NT_("llist"),      llist_cmd,     _("Full or long list like list command"),
+   NT_("jobs [client=<cli>] [jobid=<nn>] [ujobid=<name>] [job=<name>] [joberrors] [jobstatus=<s>] [limit=<n>]|\n"
+       "\tjobtotals | pools | volume | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn> |\n"
+       "\tjoblog jobid=<nn> | pluginrestoreconf jobid=<nn> restoreobjectid=<nn> | snapshot"), false},
+
+ { NT_("messages"),   messagescmd,   _("Display pending messages"),   NT_(""),    false},
+ { NT_("memory"),     memory_cmd,    _("Print current memory usage"), NT_(""),    true},
+ { NT_("mount"),      mount_cmd,     _("Mount storage"),
+   NT_("storage=<storage-name> slot=<num> drive=<num> [ device=<device-name> ] [ jobid=<id> | job=<job-name> ]"), false},
+
+ { NT_("prune"),      prunecmd,      _("Prune expired records from catalog"),
+   NT_("files | jobs | pool=<pool> | snapshot  [client=<client-name>] | client=<client-name> | [ expired ] volume=<volume-name> "), true},
+
+ { NT_("purge"),      purge_cmd,     _("Purge records from catalog"), NT_("files jobs volume=<vol> [mediatype=<type> pool=<pool> allpools storage=<st> drive=<num>]"),  true},
+ { NT_("quit"),       quit_cmd,      _("Terminate Bconsole session"), NT_(""),              false},
+ { NT_("query"),      querycmd,      _("Query catalog"),              NT_(""),              false},
+ { NT_("restore"),    restore_cmd,   _("Restore files"),
+   NT_("where=</path> client=<client> storage=<storage> bootstrap=<file> "
+       "restorejob=<job>"
+       "\n\tcomment=<text> jobid=<jobid> copies done select all"), false},
+
+ { NT_("relabel"),    relabel_cmd,   _("Relabel a tape"),
+   NT_("storage=<storage-name> oldvolume=<old-volume-name>\n\tvolume=<newvolume-name> pool=<pool>"), false},
+
+ { NT_("release"),    release_cmd,   _("Release storage"),  NT_("storage=<storage-name> [ device=<device-name> ] "),      false},
+ { NT_("reload"),     reload_cmd,    _("Reload conf file"), NT_(""),                  true},
+ { NT_("run"),        run_cmd,       _("Run a job"),
+   NT_("job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
+       " where=<directory-prefix>\n\twhen=<universal-time-specification> pool=<pool-name>\n\t"
+       " nextpool=<next-pool-name> comment=<text> accurate=<bool> spooldata=<bool> yes"), false},
+
+ { NT_("restart"),    restart_cmd,   _("Restart a job"),
+   NT_("incomplete job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
+       "when=<universal-time-specification>\n\tcomment=<text> spooldata=<bool> jobid=<jobid>"), false},
+
+ { NT_("resume"),    restart_cmd,   _("Resume a job"),
+   NT_("incomplete job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
+       "when=<universal-time-specification>\n\tcomment=<text> spooldata=<bool> jobid=<jobid>"), false},
+
+ { NT_("status"),     status_cmd,    _("Report status"),
+   NT_("all | dir=<dir-name> | director | client=<client-name> |\n"
+       "\tstorage=<storage-name> slots |\n"
+       "\tschedule [job=<job-name>] [days=<nn>] [limit=<nn>]\n"
+       "\t\t[time=<universal-time-specification>]"), true},
+
+ { NT_("stop"),       cancel_cmd,    _("Stop a job"), NT_("jobid=<number-list> job=<job-name> ujobid=<unique-jobid> all"), false},
+ { NT_("setdebug"),   setdebug_cmd,  _("Sets debug level"),
+   NT_("level=<nn> tags=<tags> trace=0/1 options=<0tTc> tags=<tags> | client=<client-name> | dir | storage=<storage-name> | all"), true},
+
+ { NT_("setbandwidth"),   setbwlimit_cmd,  _("Sets bandwidth"),
+   NT_("limit=<nn-kbs> client=<client-name> jobid=<number> job=<job-name> ujobid=<unique-jobid>"), true},
+
+ { NT_("snapshot"),   snapshot_cmd,  _("Handle snapshots"), 
+   NT_("[client=<client-name> | job=<job-name> | jobid=<jobid>] [delete | list | listclient | prune | sync | update]"), true},
+
+ { NT_("setip"),      setip_cmd,     _("Sets new client address -- if authorized"), NT_(""),   false},
+ { NT_("show"),       show_cmd,      _("Show resource records"),
+   NT_("job=<xxx> |  pool=<yyy> | fileset=<aaa> | schedule=<sss> | client=<zzz> | storage=<sss> | disabled | all"), true},
+
+ { NT_("sqlquery"),   sqlquerycmd,   _("Use SQL to query catalog"), NT_(""),          false},
+ { NT_("time"),       time_cmd,      _("Print current time"),       NT_(""),          true},
+ { NT_("trace"),      trace_cmd,     _("Turn on/off trace to file"), NT_("on | off"), true},
+ { NT_("truncate"),   truncate_cmd,  _("Truncate one or more Volumes"), NT_("volume=<vol> [mediatype=<type> pool=<pool> allpools storage=<st> drive=<num>]"),  true},
+ { NT_("unmount"),    unmount_cmd,   _("Unmount storage"),
+   NT_("storage=<storage-name> [ drive=<num> ] | jobid=<id> | job=<job-name>"), false},
+
+ { NT_("umount"),     unmount_cmd,   _("Umount - for old-time Unix guys, see unmount"),
+   NT_("storage=<storage-name> [ drive=<num> ] [ device=<dev-name> ]| jobid=<id> | job=<job-name>"), false},
+
+ { NT_("update"),     update_cmd,    _("Update volume, pool or stats"),
+   NT_("stats\n\tsnapshot\n\tpool=<poolname>\n\tslots storage=<storage> scan"
+       "\n\tvolume=<volname> volstatus=<status> volretention=<time-def>"
+       "\n\t pool=<pool> recycle=<yes/no> slot=<number>\n\t inchanger=<yes/no>"
+       "\n\t maxvolbytes=<size> maxvolfiles=<nb> maxvoljobs=<nb>"
+       "\n\t enabled=<yes/no> recyclepool=<pool> actiononpurge=<action>"
+       "\n\t allfrompool=<pool> fromallpools"),true},
+ { NT_("use"),        use_cmd,       _("Use catalog xxx"), NT_("catalog=<catalog>"),     false},
+ { NT_("var"),        var_cmd,       _("Does variable expansion"), NT_(""),  false},
+ { NT_("version"),    version_cmd,   _("Print Director version"),  NT_(""),  true},
+ { NT_("wait"),       wait_cmd,      _("Wait until no jobs are running"),
+   NT_("jobname=<name> | jobid=<nnn> | ujobid=<complete_name>"), false}
+};
+
+#define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
+
+const char *get_command(int index) {
+   return commands[index].key;
+}
 
 /*
  * Execute a command from the UA
  */
 bool do_a_command(UAContext *ua)
 {
-   unsigned int i;
+   int i;
    int len;
    bool ok = false;
    bool found = false;
@@ -181,6 +235,7 @@ bool do_a_command(UAContext *ua)
    len = strlen(ua->argk[0]);
    for (i=0; i<comsize; i++) {     /* search for command */
       if (strncasecmp(ua->argk[0],  commands[i].key, len) == 0) {
+         ua->cmd_index = i;
          /* Check if command permitted, but "quit" is always OK */
          if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
@@ -194,7 +249,7 @@ bool do_a_command(UAContext *ua)
          if (ua->api) user->signal(BNET_CMD_BEGIN);
          ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
          if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
-         found = true;
+         found = (user && user->is_stop()) ? false : true;
          break;
       }
    }
@@ -217,6 +272,7 @@ void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
    mr->Recycle = pr->Recycle;
    mr->VolRetention = pr->VolRetention;
    mr->VolUseDuration = pr->VolUseDuration;
+   mr->ActionOnPurge = pr->ActionOnPurge;
    mr->RecyclePoolId = pr->RecyclePoolId;
    mr->MaxVolJobs = pr->MaxVolJobs;
    mr->MaxVolFiles = pr->MaxVolFiles;
@@ -234,7 +290,6 @@ static int add_cmd(UAContext *ua, const char *cmd)
    POOL_DBR pr;
    MEDIA_DBR mr;
    int num, i, max, startnum;
-   int first_id = 0;
    char name[MAX_NAME_LENGTH];
    STORE *store;
    int Slot = 0, InChanger = 0;
@@ -249,7 +304,6 @@ static int add_cmd(UAContext *ua, const char *cmd)
    }
 
    memset(&pr, 0, sizeof(pr));
-   memset(&mr, 0, sizeof(mr));
 
    if (!get_pool_dbr(ua, &pr)) {
       return 1;
@@ -353,16 +407,16 @@ static int add_cmd(UAContext *ua, const char *cmd)
       bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
       mr.Slot = Slot++;
       mr.InChanger = InChanger;
-      mr.StorageId = store->StorageId;
       mr.Enabled = 1;
+      set_storageid_in_mr(store, &mr);
       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
       if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
          ua->error_msg("%s", db_strerror(ua->db));
          return 1;
       }
-      if (i == startnum) {
-         first_id = mr.PoolId;
-      }
+//    if (i == startnum) {
+//       first_id = mr.PoolId;
+//    }
    }
    pr.NumVols += num;
    Dmsg0(200, "Update pool record.\n");
@@ -398,127 +452,29 @@ int automount_cmd(UAContext *ua, const char *cmd)
    return 1;
 }
 
-
 /*
- * Cancel a job
+ * Cancel/Stop a job -- Stop marks it as Incomplete
+ *   so that it can be restarted.
  */
 static int cancel_cmd(UAContext *ua, const char *cmd)
 {
-   int i, ret;
-   int njobs = 0;
-   JCR *jcr = NULL;
-   char JobName[MAX_NAME_LENGTH];
+   JCR    *jcr;
+   bool    ret = true;
+   int     nb;
+   bool    cancel = strcasecmp(commands[ua->cmd_index].key, "cancel") == 0;
+   alist  *jcrs = New(alist(5, not_owned_by_alist));
 
-   for (i=1; i<ua->argc; i++) {
-      if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
-         uint32_t JobId;
-         if (!ua->argv[i]) {
-            break;
-         }
-         JobId = str_to_int64(ua->argv[i]);
-         if (!(jcr=get_jcr_by_id(JobId))) {
-            ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"),  ua->argv[i]);
-            return 1;
-         }
-         break;
-      } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
-         if (!ua->argv[i]) {
-            break;
-         }
-         if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
-            ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
-            jcr = new_jcr(sizeof(JCR), dird_free_jcr);
-            bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
-         }
-         break;
-      } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
-         if (!ua->argv[i]) {
-            break;
-         }
-         if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
-            ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
-            jcr = new_jcr(sizeof(JCR), dird_free_jcr);
-            bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
-         }
-         break;
-      }
+   nb = select_running_jobs(ua, jcrs, commands[ua->cmd_index].key);
 
-   }
-   if (jcr) {
-      if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
-         ua->error_msg(_("Unauthorized command from this console.\n"));
-         return 1;
-      }
-   } else {
-     /*
-      * If we still do not have a jcr,
-      *   throw up a list and ask the user to select one.
-      */
-      char buf[1000];
-      int tjobs = 0;                  /* total # number jobs */
-      /* Count Jobs running */
-      foreach_jcr(jcr) {
-         if (jcr->JobId == 0) {      /* this is us */
-            continue;
-         }
-         tjobs++;                    /* count of all jobs */
-         if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
-            continue;               /* skip not authorized */
-         }
-         njobs++;                   /* count of authorized jobs */
-      }
-      endeach_jcr(jcr);
-
-      if (njobs == 0) {            /* no authorized */
-         if (tjobs == 0) {
-            ua->send_msg(_("No Jobs running.\n"));
-         } else {
-            ua->send_msg(_("None of your jobs are running.\n"));
-         }
-         return 1;
-      }
-
-      start_prompt(ua, _("Select Job:\n"));
-      foreach_jcr(jcr) {
-         char ed1[50];
-         if (jcr->JobId == 0) {      /* this is us */
-            continue;
-         }
-         if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
-            continue;               /* skip not authorized */
-         }
-         bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
-         add_prompt(ua, buf);
-      }
-      endeach_jcr(jcr);
-
-      if (do_prompt(ua, _("Job"),  _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
-         return 1;
-      }
-      if (ua->api && njobs == 1) {
-         char nbuf[1000];
-         bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,  
-                   _("Confirm cancel?"));
-         if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
-            return 1;
-         }
-      } else {
-         if (njobs == 1) {
-            if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
-               return 1;
-            }
-         }
-      }
-      sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
-      jcr = get_jcr_by_full_name(JobName);
-      if (!jcr) {
-         ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
-         return 1;
+   foreach_alist(jcr, jcrs) {
+      /* Execute the cancel command only if we don't have an error */
+      if (nb != -1) {
+         ret &= cancel_job(ua, jcr, cancel);
       }
+      free_jcr(jcr);
    }
 
-   ret = cancel_job(ua, jcr);
-   free_jcr(jcr);
+   delete jcrs;
    return ret;
 }
 
@@ -557,6 +513,7 @@ void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
    pr->MaxVolFiles = pool->MaxVolFiles;
    pr->MaxVolBytes = pool->MaxVolBytes;
    pr->AutoPrune = pool->AutoPrune;
+   pr->ActionOnPurge = pool->action_on_purge;
    pr->Recycle = pool->Recycle;
    if (pool->label_format) {
       bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
@@ -566,7 +523,7 @@ void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
 }
 
 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
-int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
+int update_pool_references(JCR *jcr, BDB *db, POOL *pool)
 {
    POOL_DBR  pr;
 
@@ -577,6 +534,7 @@ int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
    memset(&pr, 0, sizeof(POOL_DBR));
    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
 
+   /* Don't compute NumVols here */
    if (!db_get_pool_record(jcr, db, &pr)) {
       return -1;                       /* not exists in database */
    }
@@ -587,16 +545,17 @@ int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
       return -1;                      /* error */
    }
 
+   /* NumVols is updated here */
    if (!db_update_pool_record(jcr, db, &pr)) {
       return -1;                      /* error */
    }
    return 1;
 }
 
-/* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource 
+/* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
  * works with set_pooldbr_from_poolres
  */
-bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
+bool set_pooldbr_references(JCR *jcr, BDB *db, POOL_DBR *pr, POOL *pool)
 {
    POOL_DBR rpool;
    bool ret = true;
@@ -635,7 +594,7 @@ bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
    } else {                    /* no ScratchPool used, set it to 0 */
       pr->ScratchPoolId = 0;
    }
+
    return ret;
 }
 
@@ -648,12 +607,10 @@ bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
  *           1  record created
  */
 
-int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
+int create_pool(JCR *jcr, BDB *db, POOL *pool, e_pool_op op)
 {
    POOL_DBR  pr;
-
    memset(&pr, 0, sizeof(POOL_DBR));
-
    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
 
    if (db_get_pool_record(jcr, db, &pr)) {
@@ -715,38 +672,99 @@ static int create_cmd(UAContext *ua, const char *cmd)
 extern DIRRES *director;
 extern char *configfile;
 
-/*
- * Python control command
- *  python restart (restarts interpreter)
- */
-static int python_cmd(UAContext *ua, const char *cmd)
+static int setbwlimit_client(UAContext *ua, CLIENT *client, char *Job, int64_t limit)
 {
-#ifdef HAVE_PYTHON
-   init_python_interpreter_args python_args;
+   CLIENT *old_client;
+
+   if (!client) {
+      return 1;
+   }
 
-   if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
-      term_python_interpreter();
+   /* Connect to File daemon */
+   old_client = ua->jcr->client;
+   ua->jcr->client = client;
+   ua->jcr->max_bandwidth = limit;
 
-      python_args.progname = director->name();
-      python_args.scriptdir = director->scripts_directory;
-      python_args.modulename = "DirStartUp";
-      python_args.configfile = configfile;
-      python_args.workingdir = director->working_directory;
-      python_args.job_getattr = job_getattr;
-      python_args.job_setattr = job_setattr;
+   /* Try to connect for 15 seconds */
+   ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
+      client->name(), client->address, client->FDport);
+   if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
+      ua->error_msg(_("Failed to connect to Client.\n"));
+      goto bail_out;
+   }
+   Dmsg0(120, "Connected to file daemon\n");
 
-      init_python_interpreter(&python_args);
+   if (!send_bwlimit(ua->jcr, Job)) {
+      ua->error_msg(_("Failed to set bandwidth limit to Client.\n"));
 
-      ua->send_msg(_("Python interpreter restarted.\n"));
    } else {
-#endif /* HAVE_PYTHON */
-      ua->warning_msg(_("Nothing done.\n"));
-#ifdef HAVE_PYTHON
+      /* Note, we add 2000 OK that was sent by FD to us to message */
+      ua->info_msg(_("2000 OK Limiting bandwidth to %lldkb/s %s\n"),
+                   limit/1024, *Job?Job:_("on running and future jobs"));
    }
-#endif /* HAVE_PYTHON */
+
+   ua->jcr->file_bsock->signal(BNET_TERMINATE);
+   free_bsock(ua->jcr->file_bsock);
+   ua->jcr->max_bandwidth = 0;
+
+bail_out:
+   ua->jcr->client = old_client;
    return 1;
 }
 
+static int setbwlimit_cmd(UAContext *ua, const char *cmd)
+{
+   int action = -1;
+   CLIENT *client = NULL;
+   char Job[MAX_NAME_LENGTH];
+   *Job=0;
+   int64_t limit = -1;
+   JCR *jcr = NULL;
+   int i;
+
+   const char *lst_all[] = { "job", "jobid", "jobname", "client", NULL };
+   if (find_arg_keyword(ua, lst_all) < 0) {
+       start_prompt(ua, _("Set Bandwidth choice:\n"));
+       add_prompt(ua, _("Running Job")); /* 0 */
+       add_prompt(ua, _("Running and future Jobs for a Client")); /* 1 */
+       action = do_prompt(ua, "item", _("Choose where to limit the bandwidth"),
+                          NULL, 0);
+       if (action < 0) {
+          return 1;
+       }
+   }
+
+   i = find_arg_with_value(ua, "limit");
+   if (i >= 0) {
+      limit = atoi(ua->argv[i]) * 1024LL;
+   }
+   if (limit < 0) {
+      if (!get_pint(ua, _("Enter new bandwidth limit kb/s: "))) {
+         return 1;
+      }
+      limit = ua->pint32_val * 1024LL; /* kb/s */
+   }
+
+   const char *lst[] = { "job", "jobid", "jobname", NULL };
+   if (action == 0 || find_arg_keyword(ua, lst) > 0) {
+      alist *jcrs = New(alist(10, not_owned_by_alist));
+      select_running_jobs(ua, jcrs, "limit");
+      foreach_alist(jcr, jcrs) {
+         jcr->max_bandwidth = limit; /* TODO: see for locking (Should be safe)*/
+         bstrncpy(Job, jcr->Job, sizeof(Job));
+         client = jcr->client;
+         setbwlimit_client(ua, client, Job, limit);
+         free_jcr(jcr);
+      }
+
+   } else {
+      client = get_client_resource(ua);
+      if (client) {
+         setbwlimit_client(ua, client, Job, limit);
+      }
+   }
+   return 1;
+}
 
 /*
  * Set a new address in a Client resource. We do this only
@@ -772,7 +790,8 @@ static int setip_cmd(UAContext *ua, const char *cmd)
       free(client->address);
    }
    /* MA Bug 6 remove ifdef */
-   sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
+   sockaddr_to_ascii(&(ua->UA_sock->client_addr),
+         sizeof(ua->UA_sock->client_addr), buf, sizeof(buf));
    client->address = bstrdup(buf);
    ua->send_msg(_("Client \"%s\" address set to %s\n"),
             client->name(), client->address);
@@ -781,113 +800,218 @@ get_out:
    return 1;
 }
 
-
-static void do_en_disable_cmd(UAContext *ua, bool setting)
+/*
+ * Does all sorts of enable/disable commands: batch, scheduler (not implemented)
+ *  job, client, schedule, storage
+ */
+static void do_enable_disable_cmd(UAContext *ua, bool setting)
 {
-   JOB *job;
+   JOB *job = NULL;
+   CLIENT *client = NULL;
+   SCHED *sched = NULL;
    int i;
 
-   i = find_arg_with_value(ua, NT_("job")); 
-   if (i < 0) { 
-      job = select_job_resource(ua);
-      if (!job) {
+   if (find_arg(ua, NT_("batch")) > 0) {
+      ua->send_msg(_("Job Attributes Insertion %sabled\n"), setting?"en":"dis");
+      db_disable_batch_insert(setting);
+      return;
+   }
+
+   /*
+    * if (find_arg(ua, NT_("scheduler")) > 0) {
+    *    ua->send_msg(_("Job Scheduler %sabled\n"), setting?"en":"dis");
+    *    return;
+    * }
+    */
+
+   i = find_arg(ua, NT_("job"));
+   if (i >= 0) {
+      if (ua->argv[i]) {
+         LockRes();
+         job = GetJobResWithName(ua->argv[i]);
+         UnlockRes();
+      } else {
+         job = select_enable_disable_job_resource(ua, setting);
+         if (!job) {
+            return;
+         }
+      }
+   }
+   if (job) {
+      if (!acl_access_ok(ua, Job_ACL, job->name())) {
+         ua->error_msg(_("Unauthorized command from this console.\n"));
          return;
       }
-   } else {
-      LockRes();
-      job = GetJobResWithName(ua->argv[i]);
-      UnlockRes();
-   } 
-   if (!job) {
-      ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
-      return;
+      job->enabled = setting;
+      ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
    }
 
-   if (!acl_access_ok(ua, Job_ACL, job->name())) {
-      ua->error_msg(_("Unauthorized command from this console.\n"));
-      return;
+   i = find_arg(ua, NT_("client"));
+   if (i >= 0) {
+      if (ua->argv[i]) {
+         LockRes();
+         client = GetClientResWithName(ua->argv[i]);
+         UnlockRes();
+      } else {
+         client = select_enable_disable_client_resource(ua, setting);
+         if (!client) {
+            return;
+         }
+      }
    }
-   job->enabled = setting;
-   ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
+   if (client) {
+      if (!acl_access_ok(ua, Client_ACL, client->name())) {
+         ua->error_msg(_("Unauthorized command from this console.\n"));
+         return;
+      }
+      client->enabled = setting;
+      ua->send_msg(_("Client \"%s\" %sabled\n"), client->name(), setting?"en":"dis");
+   }
+
+   i = find_arg(ua, NT_("schedule"));
+   if (i >= 0) {
+      if (ua->argv[i]) {
+         LockRes();
+         sched = (SCHED *)GetResWithName(R_SCHEDULE, ua->argv[i]);
+         UnlockRes();
+      } else {
+         sched = select_enable_disable_schedule_resource(ua, setting);
+         if (!sched) {
+            return;
+         }
+      }
+   }
+   if (sched) {
+      if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
+         ua->error_msg(_("Unauthorized command from this console.\n"));
+         return;
+      }
+      sched->enabled = setting;
+      ua->send_msg(_("Schedule \"%s\" %sabled\n"), sched->name(), setting?"en":"dis");
+   }
+
+   i = find_arg(ua, NT_("storage"));
+   if (i >= 0) {
+      do_storage_cmd(ua, setting?"enable":"disable");
+   }
+
+   if (i < 0 && !sched && !client && !job) {
+      ua->error_msg(_("You must enter one of the following keywords: job, client, schedule, or storage.\n"));
+   }
+
    return;
 }
 
 static int enable_cmd(UAContext *ua, const char *cmd)
 {
-   do_en_disable_cmd(ua, true);
+   do_enable_disable_cmd(ua, true);
    return 1;
 }
 
 static int disable_cmd(UAContext *ua, const char *cmd)
 {
-   do_en_disable_cmd(ua, false);
+   do_enable_disable_cmd(ua, false);
    return 1;
 }
 
+static void do_dir_setdebug(UAContext *ua, int64_t level, int trace_flag, char *options, int64_t tags)
+{
+   debug_level = level;
+   debug_level_tags = tags;
+   set_trace(trace_flag);
+   set_debug_flags(options);
+}
 
-static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
+static void do_storage_setdebug(UAContext *ua, STORE *store,
+               int64_t level, int trace_flag, int hangup, int blowup,
+               char *options, char *tags)
 {
    BSOCK *sd;
-   JCR *jcr = ua->jcr;
    USTORE lstore;
-   
+
    lstore.store = store;
    pm_strcpy(lstore.store_source, _("unknown source"));
-   set_wstorage(jcr, &lstore);
+   set_wstorage(ua->jcr, &lstore);
    /* Try connecting for up to 15 seconds */
    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
       store->name(), store->address, store->SDport);
-   if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
+   if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
       return;
    }
    Dmsg0(120, _("Connected to storage daemon\n"));
-   sd = jcr->store_bsock;
-   sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
+   sd = ua->jcr->store_bsock;
+   sd->fsend("setdebug=%ld trace=%ld hangup=%ld blowup=%ld options=%s tags=%s\n",
+             (int32_t)level, trace_flag, hangup, blowup, options, NPRTB(tags));
    if (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
    sd->signal(BNET_TERMINATE);
-   sd->close();
-   jcr->store_bsock = NULL;
+   free_bsock(ua->jcr->store_bsock);
    return;
 }
 
-static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
+/*
+ * For the client, we have the following values that can be set
+ *  level = debug level
+ *  trace = send debug output to a file
+ *  options = various options for debug or specific FD behavior
+ *  hangup = how many records to send to FD before hanging up
+ *    obviously this is most useful for testing restarting
+ *    failed jobs.
+ *  blowup = how many records to send to FD before blowing up the FD.
+ */
+static void do_client_setdebug(UAContext *ua, CLIENT *client,
+               int64_t level, int trace, int hangup, int blowup,
+               char *options, char *tags)
 {
+   CLIENT *old_client;
    BSOCK *fd;
 
    /* Connect to File daemon */
 
+   old_client = ua->jcr->client;
    ua->jcr->client = client;
    /* Try to connect for 15 seconds */
    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
       client->name(), client->address, client->FDport);
    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
       ua->error_msg(_("Failed to connect to Client.\n"));
+      ua->jcr->client = old_client;
       return;
    }
    Dmsg0(120, "Connected to file daemon\n");
+
    fd = ua->jcr->file_bsock;
-   fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
+   if (ua->jcr->FDVersion <= 10) {
+      fd->fsend("setdebug=%ld trace=%d hangup=%d\n",
+                (int32_t)level, trace, hangup);
+   } else {
+      fd->fsend("setdebug=%ld trace=%d hangup=%d blowup=%d options=%s tags=%s\n",
+                (int32_t)level, trace, hangup, blowup, options, NPRTB(tags));
+   }
    if (fd->recv() >= 0) {
       ua->send_msg("%s", fd->msg);
    }
    fd->signal(BNET_TERMINATE);
-   fd->close();
-   ua->jcr->file_bsock = NULL;
+   free_bsock(ua->jcr->file_bsock);
+   ua->jcr->client = old_client;
    return;
 }
 
 
-static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
+static void do_all_setdebug(UAContext *ua, int64_t level,
+               int trace_flag, int hangup, int blowup,
+               char *options, char *tags)
 {
    STORE *store, **unique_store;
    CLIENT *client, **unique_client;
    int i, j, found;
+   int64_t t=0;
 
    /* Director */
-   debug_level = level;
+   debug_parse_tags(tags, &t);
+   do_dir_setdebug(ua, level, trace_flag, options, t);
 
    /* Count Storage items */
    LockRes();
@@ -919,7 +1043,8 @@ static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
 
    /* Call each unique Storage daemon */
    for (j=0; j<i; j++) {
-      do_storage_setdebug(ua, unique_store[j], level, trace_flag);
+      do_storage_setdebug(ua, unique_store[j], level, trace_flag,
+         hangup, blowup, options, tags);
    }
    free(unique_store);
 
@@ -953,7 +1078,8 @@ static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
 
    /* Call each unique File daemon */
    for (j=0; j<i; j++) {
-      do_client_setdebug(ua, unique_client[j], level, trace_flag);
+      do_client_setdebug(ua, unique_client[j], level, trace_flag,
+         hangup, blowup, options, tags);
    }
    free(unique_client);
 }
@@ -965,16 +1091,25 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
 {
    STORE *store;
    CLIENT *client;
-   int level;
+   int64_t level=0, tags=0;
    int trace_flag = -1;
+   int hangup = -1;
+   int blowup = -1;
    int i;
+   char *tags_str=NULL;
+   char options[60];
 
    Dmsg1(120, "setdebug:%s:\n", cmd);
 
+   *options = 0;
+   i = find_arg_with_value(ua, "options");
+   if (i >= 0) {
+      bstrncpy(options, ua->argv[i], sizeof(options) - 1);
+   }
    level = -1;
    i = find_arg_with_value(ua, "level");
    if (i >= 0) {
-      level = atoi(ua->argv[i]);
+      level = str_to_int64(ua->argv[i]);
    }
    if (level < 0) {
       if (!get_pint(ua, _("Enter new debug level: "))) {
@@ -983,6 +1118,18 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
       level = ua->pint32_val;
    }
 
+   /* Better to send the tag string instead of tweaking the level
+    * in case where we extend the tag or change the representation
+    */
+   i = find_arg_with_value(ua, "tags");
+   if (i > 0) {
+      tags_str = ua->argv[i];
+      if (!debug_parse_tags(tags_str, &tags)) {
+         ua->error_msg(_("Incorrect tags found on command line %s\n"), tags_str);
+         return 1;
+      }
+   }
+
    /* Look for trace flag. -1 => not change */
    i = find_arg_with_value(ua, "trace");
    if (i >= 0) {
@@ -992,16 +1139,27 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
       }
    }
 
+   /* Look for hangup (debug only) flag. -1 => not change */
+   i = find_arg_with_value(ua, "hangup");
+   if (i >= 0) {
+      hangup = atoi(ua->argv[i]);
+   }
+
+   /* Look for blowup (debug only) flag. -1 => not change */
+   i = find_arg_with_value(ua, "blowup");
+   if (i >= 0) {
+      blowup = atoi(ua->argv[i]);
+   }
+
    /* General debug? */
    for (i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], "all") == 0) {
-         do_all_setdebug(ua, level, trace_flag);
+         do_all_setdebug(ua, level, trace_flag, hangup, blowup, options, tags_str);
          return 1;
       }
       if (strcasecmp(ua->argk[i], "dir") == 0 ||
           strcasecmp(ua->argk[i], "director") == 0) {
-         debug_level = level;
-         set_trace(trace_flag);
+         do_dir_setdebug(ua, level, trace_flag, options, tags);
          return 1;
       }
       if (strcasecmp(ua->argk[i], "client") == 0 ||
@@ -1010,13 +1168,15 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
          if (ua->argv[i]) {
             client = GetClientResWithName(ua->argv[i]);
             if (client) {
-               do_client_setdebug(ua, client, level, trace_flag);
+               do_client_setdebug(ua, client, level, trace_flag,
+                  hangup, blowup, options, tags_str);
                return 1;
             }
          }
          client = select_client_resource(ua);
          if (client) {
-            do_client_setdebug(ua, client, level, trace_flag);
+            do_client_setdebug(ua, client, level, trace_flag,
+               hangup, blowup, options, tags_str);
             return 1;
          }
       }
@@ -1028,13 +1188,15 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
          if (ua->argv[i]) {
             store = GetStoreResWithName(ua->argv[i]);
             if (store) {
-               do_storage_setdebug(ua, store, level, trace_flag);
+               do_storage_setdebug(ua, store, level, trace_flag,
+                  hangup, blowup, options, tags_str);
                return 1;
             }
          }
-         store = get_storage_resource(ua, false/*no default*/);
+         store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
          if (store) {
-            do_storage_setdebug(ua, store, level, trace_flag);
+            do_storage_setdebug(ua, store, level, trace_flag,
+               hangup, blowup, options, tags_str);
             return 1;
          }
       }
@@ -1050,23 +1212,24 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
    add_prompt(ua, _("All"));
    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
    case 0:                         /* Director */
-      debug_level = level;
-      set_trace(trace_flag);
+      do_dir_setdebug(ua, level, trace_flag, options, tags);
       break;
    case 1:
-      store = get_storage_resource(ua, false/*no default*/);
+      store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
       if (store) {
-         do_storage_setdebug(ua, store, level, trace_flag);
+         do_storage_setdebug(ua, store, level, trace_flag, hangup, blowup,
+            options, tags_str);
       }
       break;
    case 2:
       client = select_client_resource(ua);
       if (client) {
-         do_client_setdebug(ua, client, level, trace_flag);
+         do_client_setdebug(ua, client, level, trace_flag, hangup, blowup,
+            options, tags_str);
       }
       break;
    case 3:
-      do_all_setdebug(ua, level, trace_flag);
+      do_all_setdebug(ua, level, trace_flag, hangup, blowup, options, tags_str);
       break;
    default:
       break;
@@ -1083,7 +1246,7 @@ static int trace_cmd(UAContext *ua, const char *cmd)
 
    if (ua->argc != 2) {
       if (!get_cmd(ua, _("Turn on or off? "))) {
-            return 1;
+         return 1;
       }
       onoff = ua->cmd;
    } else {
@@ -1092,7 +1255,6 @@ static int trace_cmd(UAContext *ua, const char *cmd)
 
    set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
    return 1;
-
 }
 
 static int var_cmd(UAContext *ua, const char *cmd)
@@ -1124,8 +1286,9 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
    int listing = 0;
    char since[MAXSTRING];
    JCR *jcr = ua->jcr;
+   int accurate=-1;
 
-   jcr->set_JobLevel(L_FULL);
+   jcr->setJobLevel(L_FULL);
    for (int i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
           strcasecmp(ua->argk[i], NT_("fd")) == 0) {
@@ -1135,6 +1298,10 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
                ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
                return 1;
             }
+            if (!acl_access_ok(ua, Client_ACL, client->name())) {
+               ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
+               return 1;
+            }
             continue;
          } else {
             ua->error_msg(_("Client name missing.\n"));
@@ -1184,11 +1351,25 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
          if (ua->argv[i]) {
             if (!get_level_from_name(ua->jcr, ua->argv[i])) {
                ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
+               return 1;
             }
             continue;
          } else {
-           ua->error_msg(_("Level value missing.\n"));
-           return 1;
+            ua->error_msg(_("Level value missing.\n")); 
+            return 1; 
+         }
+      }
+      if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
+         if (ua->argv[i]) {
+            if (!is_yesno(ua->argv[i], &accurate)) {
+               ua->error_msg(_("Invalid value for accurate. "
+                               "It must be yes or no.\n"));
+               return 1;
+            }
+            continue;
+         } else {
+            ua->error_msg(_("Accurate value missing.\n"));
+            return 1; 
          }
       }
    }
@@ -1228,7 +1409,8 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
    }
 
    jcr->job = job;
-   jcr->set_JobType(JT_BACKUP);
+   jcr->setJobType(JT_BACKUP);
+   jcr->start_time = time(NULL);
    init_jcr_job_record(jcr);
 
    if (!get_or_create_client_record(jcr)) {
@@ -1247,6 +1429,17 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       return 1;
    }
 
+   /* The level string change if accurate mode is enabled */
+   if (accurate >= 0) {
+      jcr->accurate = accurate;
+   } else {
+      jcr->accurate = job->accurate;
+   }
+
+   if (!send_level_command(jcr)) {
+      goto bail_out;
+   }
+
    if (!send_include_list(jcr)) {
       ua->error_msg(_("Error sending include list.\n"));
       goto bail_out;
@@ -1257,25 +1450,28 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       goto bail_out;
    }
 
-   if (!send_level_command(jcr)) {
+   /*
+    * If the job is in accurate mode, we send the list of
+    * all files to FD.
+    */
+   Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
+   if (!send_accurate_current_files(jcr)) {
       goto bail_out;
    }
 
-   bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
-   while (bnet_recv(jcr->file_bsock) >= 0) {
+   jcr->file_bsock->fsend("estimate listing=%d\n", listing);
+   while (jcr->file_bsock->recv() >= 0) {
       ua->send_msg("%s", jcr->file_bsock->msg);
    }
 
 bail_out:
    if (jcr->file_bsock) {
-      bnet_sig(jcr->file_bsock, BNET_TERMINATE);
-      bnet_close(jcr->file_bsock);
-      jcr->file_bsock = NULL;
+      jcr->file_bsock->signal(BNET_TERMINATE);
+      free_bsock(ua->jcr->file_bsock);
    }
    return 1;
 }
 
-
 /*
  * print time
  */
@@ -1285,7 +1481,7 @@ static int time_cmd(UAContext *ua, const char *cmd)
    time_t ttime = time(NULL);
    struct tm tm;
    (void)localtime_r(&ttime, &tm);
-   strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
+   strftime(sdt, sizeof(sdt), "%a %d-%b-%Y %H:%M:%S", &tm);
    ua->send_msg("%s\n", sdt);
    return 1;
 }
@@ -1314,9 +1510,11 @@ static int delete_cmd(UAContext *ua, const char *cmd)
       NT_("volume"),
       NT_("pool"),
       NT_("jobid"),
+      NT_("snapshot"),
       NULL};
 
-   if (!open_client_db(ua)) {
+   /* Deleting large jobs can take time! */
+   if (!open_new_client_db(ua)) {
       return 1;
    }
 
@@ -1334,6 +1532,9 @@ static int delete_cmd(UAContext *ua, const char *cmd)
          *ua->argk[i] = 0;         /* zap keyword already visited */
       }
       return 1;
+   case 3:
+      delete_snapshot(ua);
+      return 1;
    default:
       break;
    }
@@ -1352,6 +1553,9 @@ static int delete_cmd(UAContext *ua, const char *cmd)
    case 2:
       delete_job(ua);
       return 1;
+   case 3:
+      delete_snapshot(ua);
+      return 1;
    default:
       ua->warning_msg(_("Nothing done.\n"));
       break;
@@ -1359,7 +1563,6 @@ static int delete_cmd(UAContext *ua, const char *cmd)
    return 1;
 }
 
-
 /*
  * delete_job has been modified to parse JobID lists like the
  * following:
@@ -1367,75 +1570,40 @@ static int delete_cmd(UAContext *ua, const char *cmd)
  *
  * Thanks to Phil Stracchino for the above addition.
  */
-
 static void delete_job(UAContext *ua)
 {
-   JobId_t JobId;
-   char *s,*sep,*tok;
+   int JobId;               /* not JobId_t because it's unsigned and not compatible with sellist */
+   char buf[256];
+   sellist sl;
 
    int i = find_arg_with_value(ua, NT_("jobid"));
    if (i >= 0) {
-      if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
-        s = bstrdup(ua->argv[i]);
-        tok = s;
-        /*
-         * We could use strtok() here.  But we're not going to, because:
-         * (a) strtok() is deprecated, having been replaced by strsep();
-         * (b) strtok() is broken in significant ways.
-         * we could use strsep() instead, but it's not universally available.
-         * so we grow our own using strchr().
-         */
-        sep = strchr(tok, ',');
-        while (sep != NULL) {
-           *sep = '\0';
-           if (strchr(tok, '-')) {
-               delete_job_id_range(ua, tok);
-           } else {
-              JobId = str_to_int64(tok);
-              do_job_delete(ua, JobId);
-           }
-           tok = ++sep;
-           sep = strchr(tok, ',');
-        }
-        /* pick up the last token */
-        if (strchr(tok, '-')) {
-            delete_job_id_range(ua, tok);
-        } else {
-            JobId = str_to_int64(tok);
-            do_job_delete(ua, JobId);
-        }
-
-         free(s);
-      } else {
-         JobId = str_to_int64(ua->argv[i]);
-        do_job_delete(ua, JobId);
+      if (!sl.set_string(ua->argv[i], true)) {
+         ua->warning_msg("%s", sl.get_errmsg());
+         return;
+      } 
+      if (sl.size() > 25 && (find_arg(ua, "yes") < 0)) {
+         bsnprintf(buf, sizeof(buf),
+                   _("Are you sure you want to delete %d JobIds ? (yes/no): "), sl.size());
+         if (!get_yesno(ua, buf)) {
+            return;
+         } 
+      }
+
+      foreach_sellist(JobId, &sl) {
+         do_job_delete(ua, JobId);
       }
+
    } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
       return;
+
    } else {
       JobId = ua->int64_val;
       do_job_delete(ua, JobId);
    }
 }
 
-/*
- * we call delete_job_id_range to parse range tokens and iterate over ranges
- */
-static void delete_job_id_range(UAContext *ua, char *tok)
-{
-   char *tok2;
-   JobId_t j,j1,j2;
-
-   tok2 = strchr(tok, '-');
-   *tok2 = '\0';
-   tok2++;
-   j1 = str_to_int64(tok);
-   j2 = str_to_int64(tok2);
-   for (j=j1; j<=j2; j++) {
-      do_job_delete(ua, j);
-   }
-}
-
 /*
  * do_job_delete now performs the actual delete operation atomically
  */
@@ -1445,7 +1613,7 @@ static void do_job_delete(UAContext *ua, JobId_t JobId)
 
    edit_int64(JobId, ed1);
    purge_jobs_from_catalog(ua, ed1);
-   ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
+   ua->send_msg(_("JobId=%s and associated records deleted from the catalog.\n"), ed1);
 }
 
 /*
@@ -1455,6 +1623,7 @@ static int delete_volume(UAContext *ua)
 {
    MEDIA_DBR mr;
    char buf[1000];
+   db_list_ctx lst;
 
    if (!select_media_dbr(ua, &mr)) {
       return 1;
@@ -1472,9 +1641,22 @@ static int delete_volume(UAContext *ua)
          return 1;
       }
    }
-   if (ua->pint32_val) {
-      db_delete_media_record(ua->jcr, ua->db, &mr);
+   if (!ua->pint32_val) {
+      return 1;
+   }
+
+   /* If not purged, do it */
+   if (strcmp(mr.VolStatus, "Purged") != 0) {
+      if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
+         ua->error_msg(_("Can't list jobs on this volume\n"));
+         return 1;
+      }
+      if (lst.count) {
+         purge_jobs_from_catalog(ua, lst.list);
+      }
    }
+
+   db_delete_media_record(ua->jcr, ua->db, &mr);
    return 1;
 }
 
@@ -1504,19 +1686,20 @@ static int delete_pool(UAContext *ua)
 
 int memory_cmd(UAContext *ua, const char *cmd)
 {
+   garbage_collect_memory();
    list_dir_status_header(ua);
    sm_dump(false, true);
    return 1;
 }
 
-static void do_mount_cmd(UAContext *ua, const char *command)
+static void do_storage_cmd(UAContext *ua, const char *command)
 {
    USTORE store;
    BSOCK *sd;
    JCR *jcr = ua->jcr;
    char dev_name[MAX_NAME_LENGTH];
-   int drive;
-   int slot = -1;
+   int drive, i;
+   int slot;
 
    if (!open_client_db(ua)) {
       return;
@@ -1530,31 +1713,39 @@ static void do_mount_cmd(UAContext *ua, const char *command)
    pm_strcpy(store.store_source, _("unknown source"));
    set_wstorage(jcr, &store);
    drive = get_storage_drive(ua, store.store);
-   if (strcmp(command, "mount") == 0) {
-      slot = get_storage_slot(ua, store.store);
+   slot = get_storage_slot(ua, store.store);
+
+   /* Users may set a device name directly on the command line */
+   if ((i = find_arg_with_value(ua, "device")) > 0) {
+      POOLMEM *errmsg = get_pool_memory(PM_NAME);
+      if (!is_name_valid(ua->argv[i], &errmsg)) {
+         ua->error_msg(_("Invalid device name. %s"), errmsg);
+         free_pool_memory(errmsg);
+         return;
+      }
+      free_pool_memory(errmsg);
+      bstrncpy(dev_name, ua->argv[i], sizeof(dev_name));
+
+   } else {                     /* We take the default device name */
+      bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
    }
 
    Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
       store.store->media_type, store.store->dev_name(), drive);
+   Dmsg4(120, "Cmd: %s %s drive=%d slot=%d\n", command, dev_name, drive, slot);
 
    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
       return;
    }
    sd = jcr->store_bsock;
-   bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
    bash_spaces(dev_name);
-   if (slot > 0) {
-      bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
-   } else {
-      bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
-   }
-   while (bnet_recv(sd) >= 0) {
+   sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
+   while (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
-   bnet_sig(sd, BNET_TERMINATE);
-   bnet_close(sd);
-   jcr->store_bsock = NULL;
+   sd->signal(BNET_TERMINATE);
+   free_bsock(ua->jcr->store_bsock);
 }
 
 /*
@@ -1562,7 +1753,7 @@ static void do_mount_cmd(UAContext *ua, const char *command)
  */
 static int mount_cmd(UAContext *ua, const char *cmd)
 {
-   do_mount_cmd(ua, "mount");          /* mount */
+   do_storage_cmd(ua, "mount")  ;          /* mount */
    return 1;
 }
 
@@ -1572,7 +1763,7 @@ static int mount_cmd(UAContext *ua, const char *cmd)
  */
 static int unmount_cmd(UAContext *ua, const char *cmd)
 {
-   do_mount_cmd(ua, "unmount");          /* unmount */
+   do_storage_cmd(ua, "unmount");          /* unmount */
    return 1;
 }
 
@@ -1582,7 +1773,7 @@ static int unmount_cmd(UAContext *ua, const char *cmd)
  */
 static int release_cmd(UAContext *ua, const char *cmd)
 {
-   do_mount_cmd(ua, "release");          /* release */
+   do_storage_cmd(ua, "release");          /* release */
    return 1;
 }
 
@@ -1663,7 +1854,7 @@ int wait_cmd(UAContext *ua, const char *cmd)
       return 1;
    }
 
-   i = find_arg_with_value(ua, NT_("timeout")); 
+   i = find_arg_with_value(ua, NT_("timeout"));
    if (i > 0 && ua->argv[i]) {
       stop_time = time(NULL) + str_to_int64(ua->argv[i]);
    }
@@ -1709,7 +1900,7 @@ int wait_cmd(UAContext *ua, const char *cmd)
       } else if (strcasecmp(ua->argk[i], "mount") == 0) {
          for (bool waiting=false; !waiting; ) {
             foreach_jcr(jcr) {
-               if (jcr->JobId != 0 && 
+               if (jcr->JobId != 0 &&
                    (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
                   waiting = true;
                   break;
@@ -1766,14 +1957,14 @@ int wait_cmd(UAContext *ua, const char *cmd)
              "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
 
 
-   db_sql_query(ua->db, buf,
-                status_handler, (void *)&jobstatus);
+   db_sql_query(ua->db, buf, status_handler, (void *)&jobstatus);
 
    switch (jobstatus) {
    case JS_Error:
       status = 1 ;         /* Warning */
       break;
 
+   case JS_Incomplete:
    case JS_FatalError:
    case JS_ErrorTerminated:
    case JS_Canceled:
@@ -1791,9 +1982,9 @@ int wait_cmd(UAContext *ua, const char *cmd)
    }
 
    ua->send_msg("JobId=%i\n", jobid) ;
-   ua->send_msg("JobStatus=%s (%c)\n", 
-            job_status_to_str(jobstatus), 
-            jobstatus) ;
+   ua->send_msg("JobStatus=%s (%c)\n",
+                job_status_to_str(jobstatus, 0),
+                jobstatus) ;
 
    if (ua->gui || ua->api) {
       ua->send_msg("ExitStatus=%i\n", status) ;
@@ -1805,11 +1996,21 @@ int wait_cmd(UAContext *ua, const char *cmd)
 
 static int help_cmd(UAContext *ua, const char *cmd)
 {
-   unsigned int i;
-
-   ua->send_msg(_("  Command    Description\n  =======    ===========\n"));
+   int i;
+   ua->send_msg(_("  Command       Description\n  =======       ===========\n"));
    for (i=0; i<comsize; i++) {
-      ua->send_msg(_("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
+      if (ua->argc == 2) {
+         if (!strcasecmp(ua->argk[1], commands[i].key)) {
+            ua->send_msg(_("  %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key,
+                         commands[i].help, commands[i].usage);
+            break;
+         }
+      } else {
+         ua->send_msg(_("  %-13s %s\n"), commands[i].key, commands[i].help);
+      }
+   }
+   if (i == comsize && ua->argc == 2) {
+      ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
    }
    ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
    return 1;
@@ -1817,24 +2018,43 @@ static int help_cmd(UAContext *ua, const char *cmd)
 
 int qhelp_cmd(UAContext *ua, const char *cmd)
 {
-   unsigned int i;
-
+   int i,j;
+   /* Want to display only commands */
+   j = find_arg(ua, NT_("all"));
+   if (j >= 0) {
+      for (i=0; i<comsize; i++) {
+         ua->send_msg("%s\n", commands[i].key);
+      }
+      return 1;
+   }
+   /* Want to display a specific help section */
+   j = find_arg_with_value(ua, NT_("item"));
+   if (j >= 0 && ua->argk[j]) {
+      for (i=0; i<comsize; i++) {
+         if (bstrcmp(commands[i].key, ua->argv[j])) {
+            ua->send_msg("%s\n", commands[i].usage);
+            break;
+         }
+      }
+      return 1;
+   }
+   /* Want to display everything */
    for (i=0; i<comsize; i++) {
-      ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
+      ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
    }
    return 1;
 }
 
-#if 1 
+#if 1
 static int version_cmd(UAContext *ua, const char *cmd)
 {
    ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
-                NPRTB(director->verid), HOST_OS, DISTNAME, DISTVER);
+                HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
    return 1;
 }
 #else
 /*
- *  Test code -- turned on only for debug testing 
+ *  Test code -- turned on only for debug testing
  */
 static int version_cmd(UAContext *ua, const char *cmd)
 {
@@ -1852,11 +2072,27 @@ static int version_cmd(UAContext *ua, const char *cmd)
 }
 #endif
 
-/* 
+/*
+ * This call uses open_client_db() and force a
+ * new dedicated connection to the catalog
+ */
+bool open_new_client_db(UAContext *ua)
+{
+   bool ret;
+
+   /* Force a new dedicated connection */
+   ua->force_mult_db_connections = true;
+   ret = open_client_db(ua);
+   ua->force_mult_db_connections = false;
+
+   return ret;
+}
+
+/*
  * This call explicitly checks for a catalog=xxx and
  *  if given, opens that catalog.  It also checks for
- *  client=xxx and if found, opens the catalog 
- *  corresponding to that client. If we still don't 
+ *  client=xxx and if found, opens the catalog
+ *  corresponding to that client. If we still don't
  *  have a catalog, look for a Job keyword and get the
  *  catalog from its client record.
  */
@@ -1937,9 +2173,22 @@ bool open_client_db(UAContext *ua)
  */
 bool open_db(UAContext *ua)
 {
+   bool mult_db_conn;
+
+   /* The force_mult_db_connections is telling us if we modify the
+    * private or the shared link
+    */
+   if (ua->force_mult_db_connections) {
+      ua->db = ua->private_db;
+
+   } else {
+      ua->db = ua->shared_db;
+   }
+
    if (ua->db) {
       return true;
    }
+
    if (!ua->catalog) {
       ua->catalog = get_catalog_resource(ua);
       if (!ua->catalog) {
@@ -1948,14 +2197,24 @@ bool open_db(UAContext *ua)
       }
    }
 
+   /* Some modules like bvfs need their own catalog connection */
+   mult_db_conn = ua->catalog->mult_db_connections;
+   if (ua->force_mult_db_connections) {
+      mult_db_conn = true;
+   }
+
    ua->jcr->catalog = ua->catalog;
 
    Dmsg0(100, "UA Open database\n");
-   ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name, 
+   ua->db = db_init_database(ua->jcr, ua->catalog->db_driver,
+                             ua->catalog->db_name,
                              ua->catalog->db_user,
                              ua->catalog->db_password, ua->catalog->db_address,
                              ua->catalog->db_port, ua->catalog->db_socket,
-                             ua->catalog->mult_db_connections);
+                             ua->catalog->db_ssl_key, ua->catalog->db_ssl_cert,
+                             ua->catalog->db_ssl_ca, ua->catalog->db_ssl_capath,
+                             ua->catalog->db_ssl_cipher,
+                             mult_db_conn, ua->catalog->disable_batch_insert); 
    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
       ua->error_msg(_("Could not open catalog database \"%s\".\n"),
                  ua->catalog->db_name);
@@ -1966,8 +2225,17 @@ bool open_db(UAContext *ua)
       return false;
    }
    ua->jcr->db = ua->db;
+
+   /* Depending on the type of connection, we set the right variable */
+   if (ua->force_mult_db_connections) {
+      ua->private_db = ua->db;
+
+   } else {
+      ua->shared_db = ua->db;
+   }
+
    if (!ua->api) {
-      ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name()); 
+      ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
    }
    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
    return true;
@@ -1975,11 +2243,19 @@ bool open_db(UAContext *ua)
 
 void close_db(UAContext *ua)
 {
-   if (ua->db) {
-      db_close_database(ua->jcr, ua->db);
-      ua->db = NULL;
-      if (ua->jcr) {
-         ua->jcr->db = NULL;
-      }
+   if (ua->jcr) {
+      ua->jcr->db = NULL;
    }
+
+   if (ua->shared_db) {
+      db_close_database(ua->jcr, ua->shared_db);
+      ua->shared_db = NULL;
+   }
+
+   if (ua->private_db) {
+      db_close_database(ua->jcr, ua->private_db);
+      ua->private_db = NULL;
+   }
+
+   ua->db = NULL;
 }