]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_restore.c
ebl Work on copy jobs
[bacula/bacula] / bacula / src / dird / ua_restore.c
index 0320456e868db1d313cd9185d342ed18b1c360cc..f9430b9dad099860eba2fbdb3dab2e8e72d165da 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2002-2008 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.
@@ -20,7 +20,7 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Bacula® is a registered trademark of John Walker.
+   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.
@@ -58,7 +58,7 @@ static void free_name_list(NAME_LIST *name_list);
 static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date);
 static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx);
 static void free_rx(RESTORE_CTX *rx);
-static void split_path_and_filename(RESTORE_CTX *rx, char *fname);
+static void split_path_and_filename(UAContext *ua, RESTORE_CTX *rx, char *fname);
 static int jobid_fileindex_handler(void *ctx, int num_fields, char **row);
 static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file,
                                          char *date);
@@ -194,6 +194,8 @@ int restore_cmd(UAContext *ua, const char *cmd)
          ua->warning_msg(_("No files selected to be restored.\n"));
          goto bail_out;
       }
+      display_bsr_info(ua, rx);          /* display vols needed, etc */
+
       /* If no count of files, use bsr generated value (often wrong) */
       if (rx.selected_files == 0) {
          rx.selected_files = selected_files;
@@ -233,7 +235,7 @@ int restore_cmd(UAContext *ua, const char *cmd)
       escaped_where_name = escape_filename(rx.RegexWhere);
       Mmsg(ua->cmd,
           "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\""
-          " bootstrap=\"%s\" regexwhere=\"%s\" files=%d catalog=\"%s\"",
+          " bootstrap=\"%s\" regexwhere=\"%s\" files=%u catalog=\"%s\"",
           job->name(), rx.ClientName, rx.RestoreClientName, 
           rx.store?rx.store->name():"",
           escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap,
@@ -244,7 +246,7 @@ int restore_cmd(UAContext *ua, const char *cmd)
       escaped_where_name = escape_filename(rx.where);
       Mmsg(ua->cmd,
           "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\""
-          " bootstrap=\"%s\" where=\"%s\" files=%d catalog=\"%s\"",
+          " bootstrap=\"%s\" where=\"%s\" files=%u catalog=\"%s\"",
           job->name(), rx.ClientName, rx.RestoreClientName,
           rx.store?rx.store->name():"",
           escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap,
@@ -254,7 +256,7 @@ int restore_cmd(UAContext *ua, const char *cmd)
    } else {
       Mmsg(ua->cmd,
           "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\""
-          " bootstrap=\"%s\" files=%d catalog=\"%s\"",
+          " bootstrap=\"%s\" files=%u catalog=\"%s\"",
           job->name(), rx.ClientName, rx.RestoreClientName,
           rx.store?rx.store->name():"",
           escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap,
@@ -442,6 +444,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       "add_suffix",   /* 17 */
       "regexwhere",   /* 18 */
       "restoreclient", /* 19 */
+      "copies",        /* 20 */
       NULL
    };
 
@@ -581,8 +584,8 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          }
          len = strlen(ua->cmd);
          fname = (char *)malloc(len * 2 + 1);
-         db_escape_string(fname, ua->cmd, len);
-         Mmsg(rx->query, uar_file, rx->ClientName, fname);
+         db_escape_string(ua->jcr, ua->db, fname, ua->cmd, len);
+         Mmsg(rx->query, uar_file[db_type], rx->ClientName, fname);
          free(fname);
          gui_save = ua->jcr->gui;
          ua->jcr->gui = true;
@@ -868,7 +871,7 @@ static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *f
                                         char *date)
 {
    strip_trailing_newline(file);
-   split_path_and_filename(rx, file);
+   split_path_and_filename(ua, rx, file);
    if (*rx->JobIds == 0) {
       Mmsg(rx->query, uar_jobid_fileindex, date, rx->path, rx->fname, 
            rx->ClientName);
@@ -896,14 +899,13 @@ static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *f
  */
 static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *dir,
                                         char *date)
-{
+{  
    strip_trailing_junk(dir);
    if (*rx->JobIds == 0) {
       ua->error_msg(_("No JobId specified cannot continue.\n"));
       return false;
    } else {
-      Mmsg(rx->query, uar_jobid_fileindex_from_dir, rx->JobIds, 
-           dir, rx->ClientName);
+      Mmsg(rx->query, uar_jobid_fileindex_from_dir[db_type], rx->JobIds, dir, rx->ClientName);
    }
    rx->found = false;
    /* Find and insert jobid and File Index */
@@ -939,7 +941,7 @@ static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *
    return true;
 }
 
-static void split_path_and_filename(RESTORE_CTX *rx, char *name)
+static void split_path_and_filename(UAContext *ua, RESTORE_CTX *rx, char *name)
 {
    char *p, *f;
 
@@ -968,7 +970,7 @@ static void split_path_and_filename(RESTORE_CTX *rx, char *name)
    rx->fnl = p - f;
    if (rx->fnl > 0) {
       rx->fname = check_pool_memory_size(rx->fname, 2*(rx->fnl)+1);
-      db_escape_string(rx->fname, f, rx->fnl);
+      db_escape_string(ua->jcr, ua->db, rx->fname, f, rx->fnl);
    } else {
       rx->fname[0] = 0;
       rx->fnl = 0;
@@ -977,7 +979,7 @@ static void split_path_and_filename(RESTORE_CTX *rx, char *name)
    rx->pnl = f - name;
    if (rx->pnl > 0) {
       rx->path = check_pool_memory_size(rx->path, 2*(rx->pnl)+1);
-      db_escape_string(rx->path, name, rx->pnl);
+      db_escape_string(ua->jcr, ua->db, rx->path, name, rx->pnl);
    } else {
       rx->path[0] = 0;
       rx->pnl = 0;
@@ -986,6 +988,39 @@ static void split_path_and_filename(RESTORE_CTX *rx, char *name)
    Dmsg2(100, "split path=%s file=%s\n", rx->path, rx->fname);
 }
 
+static bool ask_for_fileregex(UAContext *ua, RESTORE_CTX *rx)
+{
+   ua->send_msg(_("\nThere were no files inserted into the tree, so file selection\n"
+                  "is not possible.Most likely your retention policy pruned the files\n"));
+   if (get_yesno(ua, _("\nDo you want to restore all the files? (yes|no): "))) {
+      if (ua->pint32_val == 1)
+         return true;
+      while (get_cmd(ua, _("\nRegexp matching files to restore? (empty to abort): "))) {
+         if (ua->cmd[0] == '\0') {
+            break;
+         } else {
+            regex_t *fileregex_re = NULL;
+            int rc;
+            char errmsg[500] = "";
+
+            fileregex_re = (regex_t *)bmalloc(sizeof(regex_t));
+            rc = regcomp(fileregex_re, ua->cmd, REG_EXTENDED|REG_NOSUB);
+            if (rc != 0)
+               regerror(rc, fileregex_re, errmsg, sizeof(errmsg));
+            regfree(fileregex_re);
+            free(fileregex_re);
+            if (*errmsg) {
+               ua->send_msg(_("Regex compile error: %s\n"), errmsg);
+            } else {
+               rx->bsr->fileregex = bstrdup(ua->cmd);
+               return true;
+            }
+         }
+      }
+   }
+   return false;
+}
+
 static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
 {
    TREE_CTX tree;
@@ -1006,7 +1041,6 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
     * For display purposes, the same JobId, with different volumes may
     * appear more than once, however, we only insert it once.
     */
-   int items = 0;
    p = rx->JobIds;
    tree.FileEstimate = 0;
    if (get_next_jobid_from_list(&p, &JobId) > 0) {
@@ -1021,6 +1055,16 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
          tree.DeltaCount = rx->JobId/50; /* print 50 ticks */
       }
    }
+
+   ua->info_msg(_("\nBuilding directory tree for JobId(s) %s ...  "),
+                rx->JobIds);
+
+#define new_get_file_list
+#ifdef new_get_file_list
+   if (!db_get_file_list(ua->jcr, ua->db, rx->JobIds, insert_tree_handler, (void *)&tree)) {
+      ua->error_msg("%s", db_strerror(ua->db));
+   }
+#else
    for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
       char ed1[50];
 
@@ -1028,9 +1072,6 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
          continue;                    /* eliminate duplicate JobIds */
       }
       last_JobId = JobId;
-      ua->info_msg(_("\nBuilding directory tree for JobId %s ...  "), 
-         edit_int64(JobId, ed1));
-      items++;
       /*
        * Find files for this JobId and insert them in the tree
        */
@@ -1039,42 +1080,26 @@ static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
          ua->error_msg("%s", db_strerror(ua->db));
       }
    }
+#endif
    if (tree.FileCount == 0) {
-      ua->send_msg(_("\nThere were no files inserted into the tree, so file selection\n"
-         "is not possible.Most likely your retention policy pruned the files\n"));
-      if (!get_yesno(ua, _("\nDo you want to restore all the files? (yes|no): "))) {
-         OK = false;
-      } else {
+      OK = ask_for_fileregex(ua, rx);
+      if (OK) {
          last_JobId = 0;
          for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
              if (JobId == last_JobId) {
                 continue;                    /* eliminate duplicate JobIds */
              }
              add_findex_all(rx->bsr, JobId);
-          }
-          OK = true;
+         }
       }
    } else {
       char ec1[50];
-      if (items==1) {
-         if (tree.all) {
-            ua->info_msg(_("\n1 Job, %s files inserted into the tree and marked for extraction.\n"),
-              edit_uint64_with_commas(tree.FileCount, ec1));
-         }
-         else {
-            ua->info_msg(_("\n1 Job, %s files inserted into the tree.\n"),
-              edit_uint64_with_commas(tree.FileCount, ec1));
-         }
-      }
-      else {
-         if (tree.all) {
-            ua->info_msg(_("\n%d Jobs, %s files inserted into the tree and marked for extraction.\n"),
-              items, edit_uint64_with_commas(tree.FileCount, ec1));
-         }
-         else {
-            ua->info_msg(_("\n%d Jobs, %s files inserted into the tree.\n"),
-              items, edit_uint64_with_commas(tree.FileCount, ec1));
-         }
+      if (tree.all) {
+         ua->info_msg(_("\n%s files inserted into the tree and marked for extraction.\n"),
+                      edit_uint64_with_commas(tree.FileCount, ec1));
+      } else {
+         ua->info_msg(_("\n%s files inserted into the tree.\n"),
+                      edit_uint64_with_commas(tree.FileCount, ec1));
       }
 
       if (find_arg(ua, NT_("done")) < 0) {
@@ -1114,18 +1139,19 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    bool ok = false;
    FILESET_DBR fsr;
    CLIENT_DBR cr;
+   POOL_MEM other_filter(PM_MESSAGE);
+   POOL_MEM temp_filter(PM_MESSAGE);
    char fileset_name[MAX_NAME_LENGTH];
    char ed1[50], ed2[50];
-   char pool_select[MAX_NAME_LENGTH];
    int i;
 
    /* Create temp tables */
    db_sql_query(ua->db, uar_del_temp, NULL, NULL);
    db_sql_query(ua->db, uar_del_temp1, NULL, NULL);
-   if (!db_sql_query(ua->db, uar_create_temp, NULL, NULL)) {
+   if (!db_sql_query(ua->db, uar_create_temp[db_type], NULL, NULL)) {
       ua->error_msg("%s\n", db_strerror(ua->db));
    }
-   if (!db_sql_query(ua->db, uar_create_temp1, NULL, NULL)) {
+   if (!db_sql_query(ua->db, uar_create_temp1[db_type], NULL, NULL)) {
       ua->error_msg("%s\n", db_strerror(ua->db));
    }
    /*
@@ -1172,23 +1198,32 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    }
 
    /* If Pool specified, add PoolId specification */
-   pool_select[0] = 0;
    if (rx->pool) {
       POOL_DBR pr;
       memset(&pr, 0, sizeof(pr));
       bstrncpy(pr.Name, rx->pool->name(), sizeof(pr.Name));
       if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
-         bsnprintf(pool_select, sizeof(pool_select), "AND Media.PoolId=%s ", 
-            edit_int64(pr.PoolId, ed1));
+         Mmsg(other_filter, " AND Media.PoolId=%s ", 
+              edit_int64(pr.PoolId, ed1));
       } else {
          ua->warning_msg(_("Pool \"%s\" not found, using any pool.\n"), pr.Name);
       }
    }
+   /* include copies or not in job selection */
+   if (find_arg(ua, NT_("copies")) > 0) {
+      Mmsg(temp_filter, "%s AND Job.Type IN ('%c', '%c') ", 
+           other_filter.c_str(), (char)JT_BACKUP, (char)JT_JOB_COPY);
+   } else {
+      Mmsg(temp_filter, "%s AND Job.Type = '%c' ", other_filter.c_str(),
+           (char)JT_BACKUP);
+   }
+   pm_strcpy(other_filter, temp_filter.c_str());
 
    /* Find JobId of last Full backup for this client, fileset */
    edit_int64(cr.ClientId, ed1);
    Mmsg(rx->query, uar_last_full, ed1, ed1, date, fsr.FileSet,
-         pool_select);
+        other_filter.c_str());
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->error_msg("%s\n", db_strerror(ua->db));
       goto bail_out;
@@ -1214,12 +1249,13 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find most recent Differental Job after Full save, if any */
    Mmsg(rx->query, uar_dif, edit_uint64(rx->JobTDate, ed1), date,
-        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, other_filter.c_str());
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
    /* Now update JobTDate to lock onto Differental, if any */
    rx->JobTDate = 0;
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, uar_sel_all_temp, last_full_handler, (void *)rx)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
@@ -1230,7 +1266,8 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find all Incremental Jobs after Full/dif save */
    Mmsg(rx->query, uar_inc, edit_uint64(rx->JobTDate, ed1), date,
-        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, other_filter.c_str());
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
@@ -1243,6 +1280,8 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    }
 
    if (rx->JobIds[0] != 0) {
+      /* Display a list of all copies */
+      db_list_copies_records(ua->jcr, ua->db, 0, rx->JobIds, prtit, ua, HORZ_LIST);
       /* Display a list of Jobs selected for this restore */
       db_list_sql_query(ua->jcr, ua->db, uar_list_temp, prtit, ua, 1, HORZ_LIST);
       ok = true;
@@ -1267,11 +1306,12 @@ bail_out:
  */
 int get_next_jobid_from_list(char **p, JobId_t *JobId)
 {
-   char jobid[30];
+   const int maxlen = 30;
+   char jobid[maxlen+1];
    char *q = *p;
 
    jobid[0] = 0;
-   for (int i=0; i<(int)sizeof(jobid); i++) {
+   for (int i=0; i<maxlen; i++) {
       if (*q == 0) {
          break;
       } else if (*q == ',') {
@@ -1436,6 +1476,8 @@ void find_storage_resource(UAContext *ua, RESTORE_CTX &rx, char *Storage, char *
 
    /* Take command line arg, or ask user if none */
    rx.store = get_storage_resource(ua, false /* don't use default */);
-   Dmsg1(200, "Set store=%s\n", rx.store->name());
+   if (rx.store) {
+      Dmsg1(200, "Set store=%s\n", rx.store->name());
+   }
 
 }