]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_cmds.c
Tweak restore path prompt
[bacula/bacula] / bacula / src / dird / ua_cmds.c
index d80e5de8593e86e975ca03cdcb81d1f5ee54b54b..9c37032325ca16861643014c9ea446ea31a40a32 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2012 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
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    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
+   You should have received a copy of the GNU Affero 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.
@@ -31,7 +31,6 @@
  *
  *     Kern Sibbald, September MM
  *
- *   Version $Id$
  */
  
 #include "bacula.h"
@@ -127,18 +126,18 @@ static struct cmdstruct commands[] = {                                      /* C
  { NT_("disable"),    disable_cmd,   _("Disable a job"), NT_("job=<name>"),        true},
  { NT_("enable"),     enable_cmd,    _("Enable a job"), NT_("job=<name>"),          true},
  { NT_("estimate"),   estimate_cmd,  _("Performs FileSet estimate, listing gives full listing"), 
-   NT_("fileset=<fs> client=<cli> accurate=<yes/no> job=<job> listing"), true},
+   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 python quit query\n\trestore relabel release reload run status"
-       "\n\tsetdebug setip show sqlquery time trace unmount umount\n\tupdate use var version wait"),         false},
+       "\n\tsetdebug setip show sqlquery time trace unmount\n\tumount update use var version wait"),         false},
 
- { NT_("label"),      label_cmd,     _("Label a tape"), NT_("storage=<storage> volume=<vol> pool=<pool>"), 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_("pools | jobs | jobtotals | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
+   NT_("pools | jobs | jobtotals | volume | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
 
  { NT_("llist"),      llist_cmd,     _("Full or long list like list command"),
    NT_("pools | jobs | jobtotals | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
@@ -149,24 +148,25 @@ static struct cmdstruct commands[] = {                                      /* C
    NT_("storage=<storage-name> slot=<num> drive=<num> [ jobid=<id> | job=<job-name> ]"), false},
 
  { NT_("prune"),      prunecmd,      _("Prune expired records from catalog"), 
-   NT_("files | jobs | client=<client-name> | volume=<volume-name> "), true},
+   NT_("files | jobs | pool=<pool> | client=<client-name> | volume=<volume-name> "), true},
 
- { NT_("purge"),      purgecmd,      _("Purge records from catalog"), NT_("volume=<vol>"),  true},
+ { NT_("purge"),      purgecmd,      _("Purge records from catalog"), NT_("files jobs volume=<vol> [action=<action> devicetype=<type> pool=<pool> allpools storage=<st> drive=<num>]"),  true},
  { NT_("python"),     python_cmd,    _("Python control commands"),    NT_(""),              false},
  { 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>"
-       "\n\tjobid=<jobid> done select all"), false},
+   NT_("where=</path> client=<client> storage=<storage> bootstrap=<file> "
+       "restorejob=<job>"
+       "\n\tcomment=<text> jobid=<jobid> 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-name"),      false},
+ { NT_("release"),    release_cmd,   _("Release storage"),  NT_("storage=<storage-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>\n\tyes"), false}, /* need to be check */
+       "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tcomment=<text> yes"), false}, 
 
  { NT_("status"),     status_cmd,    _("Report status"), 
    NT_("all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> slots | days=nnn"), true},
@@ -193,7 +193,7 @@ static struct cmdstruct commands[] = {                                      /* C
        "\n\t pool=<pool> recycle=<yes/no> slot=<number>\n\t inchanger=<yes/no>"
        "\n\t maxvolbytes=<size> maxvolfiles=<nb> maxvoljobs=<nb>"
        "\n\t enable=<yes/no> recyclepool=<pool> actiononpurge=<action>"),true},
- { NT_("use"),        use_cmd,       _("Use catalog xxx"), NT_(""),     false},
+ { 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"), 
@@ -280,7 +280,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;
@@ -295,7 +294,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;
@@ -399,16 +397,13 @@ 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;
-      }
    }
    pr.NumVols += num;
    Dmsg0(200, "Update pool record.\n");
@@ -458,10 +453,10 @@ static int cancel_cmd(UAContext *ua, const char *cmd)
    for (i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
          uint32_t JobId;
-         if (!ua->argv[i]) {
+         JobId = str_to_int64(ua->argv[i]);
+         if (!JobId) {
             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;
@@ -794,7 +789,6 @@ static int python_cmd(UAContext *ua, const char *cmd)
    return 1;
 }
 
-
 /*
  * Set a new address in a Client resource. We do this only
  *  if the Console name is the same as the Client name
@@ -871,7 +865,6 @@ static int disable_cmd(UAContext *ua, const char *cmd)
    return 1;
 }
 
-
 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
 {
    BSOCK *sd;
@@ -900,7 +893,16 @@ static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trac
    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
+ *  hangup = how many records to send to SD before hanging up
+ *    obviously this is most useful for testing restarting
+ *    failed jobs.
+ */
+static void do_client_setdebug(UAContext *ua, CLIENT *client, 
+              int level, int trace, int hangup)
 {
    BSOCK *fd;
 
@@ -916,7 +918,7 @@ static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int tra
    }
    Dmsg0(120, "Connected to file daemon\n");
    fd = ua->jcr->file_bsock;
-   fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
+   fd->fsend("setdebug=%d trace=%d hangup=%d\n", level, trace, hangup);
    if (fd->recv() >= 0) {
       ua->send_msg("%s", fd->msg);
    }
@@ -927,7 +929,7 @@ static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int tra
 }
 
 
-static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
+static void do_all_setdebug(UAContext *ua, int level, int trace_flag, int hangup)
 {
    STORE *store, **unique_store;
    CLIENT *client, **unique_client;
@@ -1000,7 +1002,7 @@ 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);
    }
    free(unique_client);
 }
@@ -1014,6 +1016,7 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
    CLIENT *client;
    int level;
    int trace_flag = -1;
+   int hangup = -1;
    int i;
 
    Dmsg1(120, "setdebug:%s:\n", cmd);
@@ -1039,10 +1042,17 @@ 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]);
+   }
+
+
    /* 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);
          return 1;
       }
       if (strcasecmp(ua->argk[i], "dir") == 0 ||
@@ -1057,13 +1067,13 @@ 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);
                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);
             return 1;
          }
       }
@@ -1109,11 +1119,11 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
    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);
       }
       break;
    case 3:
-      do_all_setdebug(ua, level, trace_flag);
+      do_all_setdebug(ua, level, trace_flag, hangup);
       break;
    default:
       break;
@@ -1173,7 +1183,7 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
    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) {
@@ -1286,7 +1296,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)) {
@@ -1305,16 +1316,6 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       return 1;
    }
 
-   if (!send_include_list(jcr)) {
-      ua->error_msg(_("Error sending include list.\n"));
-      goto bail_out;
-   }
-
-   if (!send_exclude_list(jcr)) {
-      ua->error_msg(_("Error sending exclude list.\n"));
-      goto bail_out;
-   }
-
    /* The level string change if accurate mode is enabled */
    if (accurate >= 0) {
       jcr->accurate = accurate;
@@ -1326,6 +1327,16 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       goto bail_out;
    }
 
+   if (!send_include_list(jcr)) {
+      ua->error_msg(_("Error sending include list.\n"));
+      goto bail_out;
+   }
+
+   if (!send_exclude_list(jcr)) {
+      ua->error_msg(_("Error sending exclude list.\n"));
+      goto bail_out;
+   }
+
    /*
     * If the job is in accurate mode, we send the list of
     * all files to FD.
@@ -1335,15 +1346,15 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       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->signal(BNET_TERMINATE);
+      jcr->file_bsock->close();
       jcr->file_bsock = NULL;
    }
    return 1;
@@ -1529,6 +1540,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;
@@ -1546,9 +1558,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;
 }
 
@@ -1578,6 +1603,7 @@ 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;
@@ -1619,15 +1645,15 @@ static void do_mount_cmd(UAContext *ua, const char *command)
    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);
+      sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
    } else {
-      bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
+      sd->fsend("%s %s drive=%d", command, dev_name, drive);
    }
-   while (bnet_recv(sd) >= 0) {
+   while (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
-   bnet_sig(sd, BNET_TERMINATE);
-   bnet_close(sd);
+   sd->signal(BNET_TERMINATE);
+   sd->close();
    jcr->store_bsock = NULL;
 }
 
@@ -1955,6 +1981,22 @@ 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 */
+   close_db(ua);
+   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
@@ -2040,6 +2082,8 @@ bool open_client_db(UAContext *ua)
  */
 bool open_db(UAContext *ua)
 {
+   bool mult_db_conn;
+
    if (ua->db) {
       return true;
    }
@@ -2051,14 +2095,20 @@ 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);
+                             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);