]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Fix #9968 Enhance restricted Console support
authorEric Bollengier <eric@baculasystems.com>
Thu, 16 Mar 2023 08:52:49 +0000 (09:52 +0100)
committerEric Bollengier <eric@baculasystems.com>
Tue, 2 May 2023 07:07:18 +0000 (09:07 +0200)
 - Limit job list in restore menu 1 and 2
 - Adapt restore menu 3 jobid selection
 - Adapt restore menu 11 jobid selection
 - Adapt restore jobid= parameter
 - Add checks on restore file parameter
 - Adapt purge commands

bacula/src/cats/bdb.h
bacula/src/cats/cats.h
bacula/src/cats/protos.h
bacula/src/cats/sql.c
bacula/src/cats/sql_cmds.c
bacula/src/cats/sql_list.c
bacula/src/dird/autoprune.c
bacula/src/dird/mac.c
bacula/src/dird/ua_purge.c
bacula/src/dird/ua_restore.c
bacula/src/stored/bsdjson.c

index 52e277cb1737ca47b5799d742497225576818e65..03f0cfd136efe4f2be002aa08a6bae2e5f1daacc 100644 (file)
@@ -214,6 +214,7 @@ public:
    bool bdb_create_batch_file_attributes_record(JCR *jcr, ATTR_DBR *ar);
 
    /* sql_get.c */
+   char *bdb_get_jobids(const char *jobids, POOLMEM **ret, bool append);
    bool bdb_get_file_record(JCR *jcr, JOB_DBR *jr, FILE_DBR *fdbr);
    bool bdb_get_snapshot_record(JCR *jcr, SNAPSHOT_DBR *snap);
    bool bdb_get_volume_jobids(JCR *jcr,
@@ -256,6 +257,7 @@ public:
 /* sql_list.c */
    void bdb_list_pool_records(JCR *jcr, POOL_DBR *pr, DB_LIST_HANDLER sendit, void *ctx, e_list_type type);
    alist *bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx, e_list_type type);
+   void bdb_list_jobs_for_file(JCR *jcr, const char *client, const char *fname, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
    void bdb_list_job_totals(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER sendit, void *ctx);
    void bdb_list_files_for_job(JCR *jcr, uint32_t jobid, int deleted, DB_LIST_HANDLER sendit, void *ctx);
    void bdb_list_media_records(JCR *jcr, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
index c1197188f59e7da1025011a257888d76a5e0d534..b124208cd4adc266bad80732da7c04781fad222b 100644 (file)
@@ -676,7 +676,8 @@ enum e_list_type {
    ARG_LIST,                    /* key1=v1 key2=v2 key3=v3 */
    JSON_LIST,
    FAILED_JOBS,
-   INCOMPLETE_JOBS
+   INCOMPLETE_JOBS,
+   LAST_JOBS
 };
  
 #include "bdb.h"
index 53e6682518a3760602ed643a63dfeb793ba9baf4..28ff00cc153a31ec174de1cf564c42b36fa82526 100644 (file)
@@ -81,6 +81,7 @@ BDB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name,
         if (mdb)  mdb->bdb_thread_cleanup()
 
 /* sql.c */
+int db_jobids_handler(void *ctx, int num_fields, char **row);
 int db_mint64_handler(void *ctx, int num_fields, char **row);
 int db_int64_handler(void *ctx, int num_fields, char **row);
 int db_strtime_handler(void *ctx, int num_fields, char **row);
@@ -109,6 +110,9 @@ void bdb_free_restoreobject_record(JCR *jcr, ROBJECT_DBR *rr);
 #define db_get_client_pool(jcr, mdb, results)    \
    mdb->bdb_get_client_pool(jcr, results)
 
+#define db_get_jobids(jcr, mdb, jobids, ret, append)   \
+           mdb->bdb_get_jobids(jobids, ret, append)
+
 /* sql_create.c */
 #define db_create_log_record(jcr, mdb, jobid, mtime, msg)        \
            mdb->bdb_create_log_record(jcr, jobid, mtime, msg)
@@ -263,6 +267,8 @@ void bdb_free_restoreobject_record(JCR *jcr, ROBJECT_DBR *rr);
 #define db_get_job_statistics(jcr, mdb, jr)      \
            mdb->bdb_get_job_statistics(jcr, jr)
 /* sql_list.c */
+#define db_list_jobs_for_file(jcr, mdb, cli, fname, result_handler, ctx, type) \
+           mdb->bdb_list_jobs_for_file(jcr, cli, fname, result_handler, ctx, type)
 #define db_list_pool_records(jcr, mdb, pr, sendit, ctx, type) \
            mdb->bdb_list_pool_records(jcr, pr, sendit, ctx, type)
 #define db_list_job_records(jcr, mdb, jr, sendit, ctx, type) \
index 85bda0ae8c64e03a343f9b892f14dd8ff6c78987..558e35d6ddaade4ed3578bc8b265b17110a1ca0c 100644 (file)
@@ -57,9 +57,9 @@ dbid_list::~dbid_list()
    free(DBId); 
 } 
  
-/* 
- * Called here to retrieve an resource name (e.g. Storage name) from the database 
- */ 
+/*
+ * Called here to retrieve a resource name (e.g. Storage name) from the database
+ */
 int db_name_handler(void *ctx, int num_fields, char **row) 
 {
    char *name = (char *)ctx;
@@ -74,6 +74,21 @@ int db_name_handler(void *ctx, int num_fields, char **row)
    return 0;
 }
 
+/*
+ * Called here to retrieve a list of jobid x,y,z from the database
+ */
+int db_jobids_handler(void *ctx, int num_fields, char **row) 
+{
+   POOLMEM **ret = (POOLMEM **)ctx;
+   if (row[0]) {
+      if (**ret) {
+         pm_strcat(ret, ",");
+      }
+      pm_strcat(ret, row[0]);
+   }
+   return 0;
+}
+
 /* 
  * Called here to retrieve an string list from the database 
  */ 
@@ -226,7 +241,6 @@ BDB::~BDB()
  */
 char *BDB::get_acls(int tables, bool where /* use WHERE or AND */)
 {
-   POOL_MEM tmp;
    pm_strcpy(acl_where, "");
 
    for (int i=0 ;  i < DB_ACL_LAST; i++) {
@@ -238,6 +252,58 @@ char *BDB::get_acls(int tables, bool where /* use WHERE or AND */)
    return acl_where;
 }
 
+char *BDB::bdb_get_jobids(const char *jobids, POOLMEM **ret, bool append)
+{
+   if (!ret || !*ret) {
+      return NULL;
+   }
+   
+   if (!append) {     // Return empty list if append = false
+      pm_strcpy(ret, "");
+   }
+
+   if (!jobids || !*jobids || !is_a_number_list(jobids)) {
+      return *ret;
+   }
+
+   bdb_lock();
+   /* Get optional filters for the SQL query */
+   const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                DB_ACL_BIT(DB_ACL_CLIENT) |
+                                DB_ACL_BIT(DB_ACL_FILESET), false);
+
+   const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_CLIENT)  |
+                                                   DB_ACL_BIT(DB_ACL_FILESET)) : "";
+   /* No filters, no need to run the query */
+   if (!*where && !*join) {
+      if (*ret[0]) {
+         pm_strcat(ret, ",");
+      }
+      pm_strcat(ret, jobids);
+      goto bail_out;
+   }
+   Mmsg(cmd, "SELECT Job.JobId as JobId "
+        "FROM Job %s WHERE JobId IN (%s%s%s) %s ORDER BY JobTDate ASC",
+        join,
+        *ret /* previous list */,
+        *ret[0] ? "," : "" /* comma to separate from the new list */,
+        jobids,
+        where);
+
+   /* We start from a fresh list, previous entries will be listed */
+   pm_strcpy(ret, "");
+
+   Dmsg1(50|DT_SQL, "q=%s\n", cmd);
+   if(!bdb_sql_query(cmd, db_jobids_handler, ret)) {
+      goto bail_out;
+   }
+
+bail_out:
+   sql_free_result();
+   bdb_unlock();
+   return *ret;
+}
+
 /* Create the JOIN string that will help to filter queries results */
 char *BDB::get_acl_join_filter(int tables)
 {
index ae799dc6f2ce08325f911817fa194efa49996391..af0e203eb13587b397fbe5d0b33b685c51a37c55 100644 (file)
@@ -101,13 +101,6 @@ const char *create_delindex = "CREATE INDEX DelInx1 ON DelCandidates (JobId)";
 const char *uar_count_files =
    "SELECT JobFiles FROM Job WHERE JobId=%s";
 
-/* List last 20 Jobs */
-const char *uar_list_jobs =
-   "SELECT JobId,Client.Name as Client,Job.Name as Name,StartTime,Level as "
-   "JobLevel,JobFiles,JobBytes "
-   "FROM Client,Job WHERE Client.ClientId=Job.ClientId AND JobStatus IN ('T','W') "
-   "AND Type='B' ORDER BY StartTime DESC LIMIT 20";
-
 const char *uar_print_jobs = 
    "SELECT DISTINCT JobId,Level,JobFiles,JobBytes,StartTime,VolumeName"
    " FROM Job JOIN JobMedia USING (JobId) JOIN Media USING (MediaId) "
@@ -248,9 +241,11 @@ const char *uar_jobids_fileindex =
    "AND Path.PathId=File.PathId "
    "ORDER BY Job.StartTime DESC LIMIT 1";
 
-/* Query to get list of files from table -- presuably built by an external program */
+/* Query to get list of files from table -- presuably built by an external program
+ * we expect filters on join and where
+ */
 const char *uar_jobid_fileindex_from_table = 
-   "SELECT JobId, FileIndex FROM %s ORDER BY JobId, FileIndex ASC";
+   "SELECT JobId, FileIndex FROM %s %s %s ORDER BY JobId, FileIndex ASC"; 
 
 /* Get the list of the last recent version per Delta with a given
  *  jobid list. This is a tricky part because with SQL the result of:
@@ -553,40 +548,6 @@ const char *uap_upgrade_copies_oldest_job[] =
  
 /* ======= ua_restore.c ====== */
 
-/* List Jobs where a particular file is saved */
-const char *uar_file[] =
-{
-   /* MySQL */
-   "SELECT Job.JobId as JobId,"
-   "CONCAT(Path.Path,File.Filename) as Name, "
-   "StartTime,Type as JobType,JobStatus,JobFiles,JobBytes "
-   "FROM Client,Job,File,Path WHERE Client.Name='%s' "
-   "AND Client.ClientId=Job.ClientId "
-   "AND Job.JobId=File.JobId AND File.FileIndex > 0 "
-   "AND Path.PathId=File.PathId "
-   "AND File.Filename='%s' ORDER BY StartTime DESC LIMIT 20",
-   /* PostgreSQL */
-   "SELECT Job.JobId as JobId,"
-   "Path.Path||File.Filename as Name, "
-   "StartTime,Type as JobType,JobStatus,JobFiles,JobBytes "
-   "FROM Client,Job,File,Path WHERE Client.Name='%s' "
-   "AND Client.ClientId=Job.ClientId "
-   "AND Job.JobId=File.JobId AND File.FileIndex > 0 "
-   "AND Path.PathId=File.PathId "
-   "AND File.Filename='%s' ORDER BY StartTime DESC LIMIT 20",
-   /* SQLite */
-   "SELECT Job.JobId as JobId,"
-   "Path.Path||File.Filename as Name, "
-   "StartTime,Type as JobType,JobStatus,JobFiles,JobBytes "
-   "FROM Client,Job,File,Path WHERE Client.Name='%s' "
-   "AND Client.ClientId=Job.ClientId "
-   "AND Job.JobId=File.JobId AND File.FileIndex > 0 "
-   "AND Path.PathId=File.PathId "
-   "AND File.Filename='%s' ORDER BY StartTime DESC LIMIT 20"
-}; 
 const char *uar_create_temp[] =
 {
    /* MySQL */
index 06b8f8d8f5473da078bc80114502de37736ca246..ef16acb3c1d43b843206dca3ac0734287ea89b68 100644 (file)
@@ -797,6 +797,13 @@ alist *BDB::bdb_list_job_records(JCR *jcr, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
              "FROM Job %s %s ORDER BY StartTime %s,JobId %s %s",
            join, where, order, order, limit);
       break;
+   case LAST_JOBS:
+      Mmsg(cmd,
+           "SELECT JobId,Client1.Name as Client,Job.Name as Name,StartTime,Level as "
+           "JobLevel,JobFiles,JobBytes "
+           "FROM Client AS Client1 JOIN Job USING (ClientId) %s %s AND JobStatus IN ('T','W') "
+           "ORDER BY StartTime %s %s", join, where, order, limit);
+
    default:
       break;
    }
@@ -1135,4 +1142,55 @@ void BDB::bdb_list_tag_records(JCR *jcr, TAG_DBR *tag, DB_LIST_HANDLER *result_h
    bdb_unlock();
 }
 
+/* List all file records from a job
+ * "deleted" values are described just below
+ */
+void BDB::bdb_list_jobs_for_file(JCR *jcr, const char *client, const char *fname, DB_LIST_HANDLER *sendit, void *ctx,  e_list_type type)
+{
+   if (!client || !*client || !fname || !*fname) {
+      return;
+   }
+   const char *concat="Path.Path||File.Filename";
+
+   if (bdb_get_type_index() == SQL_TYPE_MYSQL) {
+      concat = " CONCAT(Path.Path,File.Filename) ";
+   }
+
+   bdb_lock();
+   /* Get optional filters for the SQL query */
+   const char *where = get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                DB_ACL_BIT(DB_ACL_CLIENT) |
+                                DB_ACL_BIT(DB_ACL_FILESET), false);
+
+   const char *join = *where ? get_acl_join_filter(DB_ACL_BIT(DB_ACL_FILESET)) : "";
+   
+   int len = strlen(fname);
+   char *esc = (char *)malloc(len * 2 + 1);
+   bdb_escape_string(jcr, esc, (char *)fname, len);
+
+   len = strlen(client);
+   char *esc2 = (char *)malloc(len * 2 + 1);
+   bdb_escape_string(jcr, esc2, (char *)client, len);
+
+   Mmsg(cmd,    "SELECT Job.JobId as JobId,"
+        "%s as Name, "          // Concat of the filename
+        "StartTime, Type as JobType, JobStatus,JobFiles,JobBytes "
+        "FROM Client JOIN Job USING (ClientId) JOIN File USING (JobId) JOIN Path USING (PathId) %s "
+        "WHERE Client.Name = '%s' "
+        "AND File.FileIndex > 0 "
+        "AND File.Filename='%s' %s ORDER BY StartTime DESC LIMIT 20", concat, join, esc2, esc, where);
+
+   free(esc);
+   free(esc2);
+   Dmsg1(DT_SQL|50, "q=%s\n", cmd);
+   if (!QueryDB(jcr, cmd)) {
+      goto bail_out;
+   }
+
+   list_result(jcr, this, "job", sendit, ctx, HORZ_LIST);
+bail_out:
+   sql_free_result();
+   bdb_unlock();
+}
+
 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */
index a5fc1c99a5ab17627852e3789f44ef65e01b546e..3ce6b7269d3480431ce509bf18bcd063ded4e0de 100644 (file)
@@ -181,7 +181,7 @@ void prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr,
          count = get_prune_list_for_volume(ua, &lmr, &prune_list);
          Dmsg1(100, "Num pruned = %d\n", count);
          if (count != 0) {
-            purge_job_list_from_catalog(ua, prune_list);
+            purge_job_list_from_catalog(ua, prune_list); /* JobId list not coming from outside */
             prune_list.num_ids = 0;             /* reset count */
          }
          if (!is_volume_purged(ua, &lmr)) {
index bb63c1603f80dffe850b6d14af61a76b1fa42e67..52c79bb01fbff31f522a5b2471247edd918eebc0 100644 (file)
@@ -775,10 +775,10 @@ void mac_cleanup(JCR *jcr, int TermCode, int writeTermCode)
 
          if (jcr->job->PurgeMigrateJob) {
             /* Purge old Job record */
-            purge_jobs_from_catalog(ua, old_jobid);
+            purge_jobs_from_catalog(ua, old_jobid); // JobId is safe
          } else {
             /* Purge all old file records, but leave Job record */
-            purge_files_from_jobs(ua, old_jobid);
+            purge_files_from_jobs(ua, old_jobid); // JobId is safe
          }
 
          free_ua_context(ua);
index 64df5f7e07ecdb4bfcc6fcf18101d3a0fa077efd..a8c23b7c9b0eb4e6658eb6dec64386023edbe64b 100644 (file)
@@ -37,13 +37,13 @@ static int purge_jobs_from_client(UAContext *ua, CLIENT *client, char *job);
 int truncate_cmd(UAContext *ua, const char *cmd);
 
 static const char *select_jobsfiles_from_client =
-   "SELECT JobId FROM Job "
-   "WHERE ClientId=%s "
+   "SELECT JobId FROM Job %s "
+   "WHERE ClientId=%s %s "
    "AND PurgedFiles=0";
 
 static const char *select_jobs_from_client =
-   "SELECT JobId, PurgedFiles FROM Job "
-   "WHERE ClientId=%s";
+   "SELECT JobId, PurgedFiles FROM Job %s "
+   "WHERE ClientId=%s %s";
 
 /*
  *   Purge records from database
@@ -105,9 +105,11 @@ int purge_cmd(UAContext *ua, const char *cmd)
       case 0:                         /* Job */
       case 1:                         /* JobId */
          if (get_job_dbr(ua, &jr)) {
-            char jobid[50];
-            edit_int64(jr.JobId, jobid);
-            purge_files_from_jobs(ua, jobid);
+            if (acl_access_ok(ua, Job_ACL, jr.Name)) {
+               char jobid[50];
+               edit_int64(jr.JobId, jobid);
+               purge_files_from_jobs(ua, jobid);
+            }
          }
          return 1;
       case 2:                         /* client */
@@ -233,9 +235,22 @@ static int purge_files_from_client(UAContext *ua, CLIENT *client)
    ua->send_events("DC0001", EVENTS_TYPE_COMMAND, "purge files client=%s", cr.Name);
    ua->info_msg(_("Begin purging files for Client \"%s\"\n"), cr.Name);
 
-   Mmsg(query, select_jobsfiles_from_client, edit_int64(cr.ClientId, ed1));
-   Dmsg1(050, "select sql=%s\n", query.c_str());
-   db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);
+   db_lock(ua->db);
+   {
+      /* Get optional filters for the SQL query */
+      const char *where = ua->db->get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                           DB_ACL_BIT(DB_ACL_CLIENT) |
+                                           DB_ACL_BIT(DB_ACL_FILESET), false);
+
+      const char *join = *where ? ua->db->get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) |
+                                                              DB_ACL_BIT(DB_ACL_CLIENT)  |
+                                                              DB_ACL_BIT(DB_ACL_FILESET)) : "";
+
+      Mmsg(query, select_jobsfiles_from_client, join, edit_int64(cr.ClientId, ed1), where);
+      Dmsg1(050, "select sql=%s\n", query.c_str());
+      db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del);
+   }
+   db_unlock(ua->db);
 
    purge_files_from_job_list(ua, del);
 
@@ -283,24 +298,40 @@ static int purge_jobs_from_client(UAContext *ua, CLIENT *client, char* job)
    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
    del.PurgedFiles = (char *)malloc(del.max_ids);
 
+   /* We filter the JobId list with ACL console if any */
+   db_lock(ua->db);
+   {
+      /* Get optional filters for the SQL query */
+      const char *where = ua->db->get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                           DB_ACL_BIT(DB_ACL_CLIENT) |
+                                           DB_ACL_BIT(DB_ACL_FILESET), false);
+
+      const char *join = *where ? ua->db->get_acl_join_filter(DB_ACL_BIT(DB_ACL_CLIENT)  |
+                                                              DB_ACL_BIT(DB_ACL_FILESET)) : "";
+
+      if (job) {
+         /* Limit purged jobs to specified job's name */
+         char esc[MAX_ESCAPE_NAME_LENGTH];
+         db_escape_string(ua->jcr, ua->jcr->db, esc, job, strlen(job));
+         Mmsg(query, "SELECT JobId,PurgedFiles FROM Job %s WHERE ClientId=%s AND Name='%s' %s",
+              join, edit_int64(cr.ClientId, ed1), esc, where);
+
+      } else {
+         Mmsg(query, select_jobs_from_client, join, edit_int64(cr.ClientId, ed1), where);
+      }
+   }
+   db_unlock(ua->db);
 
    if (job) {
-      /* Limit purged jobs to specified job's name */
-      char esc[MAX_ESCAPE_NAME_LENGTH];
-      db_escape_string(ua->jcr, ua->jcr->db, esc, job, strlen(job));
-      Mmsg(query, "SELECT JobId,PurgedFiles FROM Job WHERE ClientId=%s AND Name='%s'",
-           edit_int64(cr.ClientId, ed1), esc);
       ua->info_msg(_("Begin purging jobs \"%s\" from Client \"%s\"\n"), job, cr.Name);
-
    } else {
-      Mmsg(query, select_jobs_from_client, edit_int64(cr.ClientId, ed1));
       ua->info_msg(_("Begin purging jobs from Client \"%s\"\n"), cr.Name);
    }
-
+   
    Dmsg1(150, "select sql=%s\n", query.c_str());
    db_sql_query(ua->db, query.c_str(), job_delete_handler, (void *)&del);
 
-   purge_job_list_from_catalog(ua, del);
+   purge_job_list_from_catalog(ua, del); /* JobId list secured */
 
    if (del.num_del == 0) {
       ua->warning_msg(_("No Jobs found for client %s to purge from %s catalog.\n"),
@@ -319,9 +350,8 @@ static int purge_jobs_from_client(UAContext *ua, CLIENT *client, char* job)
    return 1;
 }
 
-
 /*
- * Remove File records from a list of JobIds
+ * Remove File records from a list of JobIds. Jobs must be secured.
  */
 void purge_files_from_jobs(UAContext *ua, char *jobs)
 {
@@ -361,6 +391,7 @@ void purge_files_from_jobs(UAContext *ua, char *jobs)
 /*
  * Delete jobs (all records) from the catalog in groups of 1000
  *  at a time.
+ * The JobId list must be secured when entering here
  */
 void purge_job_list_from_catalog(UAContext *ua, del_ctx &del)
 {
@@ -471,6 +502,8 @@ void upgrade_copies(UAContext *ua, char *jobs)
 
 /*
  * Remove all records from catalog for a list of JobIds
+ * The code in tools/dbcheck.c has to be updated as well
+ * jobs must be secured.
  */
 void purge_jobs_from_catalog(UAContext *ua, char *jobs)
 {
@@ -571,13 +604,24 @@ bool purge_jobs_from_volume(UAContext *ua, MEDIA_DBR *mr, bool force)
       jobids = lst.list;
    }
 
+   /* We filter out the list of JobId using the one we are allowed by ACL */
+   jobids = db_get_jobids(ua->jcr, ua->db, jobids, query.handle(), false);
+
+   /* Get the right count of job (count the number of , + 1) */
+   i = (*jobids == 0) ? 1 : 0;
+   for (char *p = jobids; *p ; p++) {
+      if (*p == ',') {
+         i++;
+      }
+   }
+   
    if (*jobids) {
       /* Keep track of this important event */
       ua->send_events("DC0003", EVENTS_TYPE_COMMAND, "purge volume=%s", mr->VolumeName);
 
-      purge_jobs_from_catalog(ua, jobids);
+      purge_jobs_from_catalog(ua, jobids); /* JobId list secured */
       ua->info_msg(_("%d Job%s on Volume \"%s\" purged from catalog.\n"),
-                   lst.count, lst.count<=1?"":"s", mr->VolumeName);
+                   i, i<=1?"":"s", mr->VolumeName);
    }
    purged = is_volume_purged(ua, mr, force);
 
index d46fb5ddc706c26c3248809699eff9571586acca..92626418414addf3c605489071c8a93c97558890 100644 (file)
@@ -730,10 +730,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          if (!has_value(ua, i)) {
             return 0;
          }
-         if (*rx->JobIds != 0) {
-            pm_strcat(rx->JobIds, ",");
-         }
-         pm_strcat(rx->JobIds, ua->argv[i]);
+         db_get_jobids(ua->jcr, ua->db, ua->argv[i], &rx->JobIds, true  /* append the result */);
          done = true;
          break;
       case 1:                            /* current */
@@ -825,7 +822,6 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
 
    /* If choice not already made above, prompt */
    for ( ; !done; ) {
-      char *fname;
       int len;
       bool gui_save;
       db_list_ctx jobids;
@@ -843,11 +839,18 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
             ua->error_msg(_("SQL query not authorized.\n"));
             return 0;
          }
-         gui_save = ua->jcr->gui;
-         ua->jcr->gui = true;
-         db_list_sql_query(ua->jcr, ua->db, "job", uar_list_jobs, prtit, ua, 1, HORZ_LIST);
-         ua->jcr->gui = gui_save;
-         done = false;
+         {
+            memset(&jr, 0, sizeof(jr));
+            jr.limit=20;
+            jr.JobType = 'B';
+            jr.order = 1;       // DESC
+            gui_save = ua->jcr->gui;
+            ua->jcr->gui = true;
+            /* db_list_job_records() has builtin console filters */
+            db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, LAST_JOBS);
+            ua->jcr->gui = gui_save;
+            done = false;
+         }
          break;
       case 1:                         /* list where a file is saved */
          if (!get_client_name(ua, rx)) {
@@ -856,14 +859,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          if (!get_cmd(ua, _("Enter Filename (no path):"))) {
             return 0;
          }
-         len = strlen(ua->cmd);
-         fname = (char *)malloc(len * 2 + 1);
-         db_escape_string(ua->jcr, ua->db, fname, ua->cmd, len);
-         Mmsg(rx->query, uar_file[db_get_type_index(ua->db)], rx->ClientName, fname);
-         free(fname);
          gui_save = ua->jcr->gui;
          ua->jcr->gui = true;
-         db_list_sql_query(ua->jcr, ua->db, "job", rx->query, prtit, ua, 1, HORZ_LIST);
+         db_list_jobs_for_file(ua->jcr, ua->db, rx->ClientName, ua->cmd, prtit, ua, HORZ_LIST);
          ua->jcr->gui = gui_save;
          done = false;
          break;
@@ -871,7 +869,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          if (!get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
             return 0;
          }
-         pm_strcpy(rx->JobIds, ua->cmd);
+         db_get_jobids(ua->jcr, ua->db, ua->cmd, &rx->JobIds, false /* clear */);
          break;
       case 3:                         /* Enter an SQL list command */
          if (!acl_access_ok(ua, Command_ACL, NT_("sqlquery"), 8)) {
@@ -923,6 +921,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
             if (len == 0) {
                break;
             }
+            if (ua->cmd[0] == '?') {
+               continue;        // We do not want to accept a SQL table here
+            }
             insert_one_file_or_dir(ua, rx, date, false);
          }
          return 2;
@@ -946,6 +947,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
             if (len == 0) {
                break;
             }
+            if (ua->cmd[0] == '?') {
+               continue;        // We do not want to accept a SQL table here
+            }
             insert_one_file_or_dir(ua, rx, date, false);
          }
          return 2;
@@ -976,15 +980,19 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
          if (*rx->JobIds != 0) {
             ua->send_msg(_("You have already selected the following JobIds: %s\n"),
                rx->JobIds);
+
          } else if (get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) {
-            if (*rx->JobIds != 0 && *ua->cmd) {
-               pm_strcat(rx->JobIds, ",");
+            if (*ua->cmd == '.') {
+               *rx->JobIds = 0;
+               return 0;                 /* nothing entered, return */
             }
-            pm_strcat(rx->JobIds, ua->cmd);
-         }
-         if (*rx->JobIds == 0 || *rx->JobIds == '.') {
-            *rx->JobIds = 0;
-            return 0;                 /* nothing entered, return */
+            db_get_jobids(ua->jcr, ua->db, ua->cmd, &rx->JobIds, false /* clear */);
+            if (*rx->JobIds == 0) {
+               ua->error_msg(_("No JobId selected\n"));
+               return 0;                 /* nothing entered, return */
+            }
+            ua->send_msg(_("You have selected the following JobIds: %s\n"),
+                         rx->JobIds);
          }
          if (!have_date) {
             bstrutime(date, sizeof(date), now);
@@ -1007,6 +1015,9 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
             if (ua->cmd[0] != '<' && !IsPathSeparator(ua->cmd[len-1])) {
                strcat(ua->cmd, "/");
             }
+            if (ua->cmd[0] == '?') {
+               continue;        // We do not want to accept a SQL table here
+            }
             insert_one_file_or_dir(ua, rx, date, true);
          }
          return 2;
@@ -1113,7 +1124,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
             }
 
             //TODO Validation if id entered matches one from list above would be nice...
-            if (!get_pint(ua, "Enter ID of Object to be restored: ")) {
+            if (!get_pint(ua, _("Enter ID of Object to be restored: "))) {
                ua->info_msg(_("Selection aborted, nothing done.\n"));
                break;
             }
@@ -1350,14 +1361,32 @@ bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table)
 {
    component_file_ctx ctx;
    strip_trailing_junk(table);
-   Mmsg(rx->query, uar_jobid_fileindex_from_table, table);
+   if (strcasecmp(table, "file") == 0 || !is_name_valid(table, NULL, "")) {
+      ua->error_msg(_("Incorrect table name\n"));
+      return false;
+   }
+   bool ret;
+   db_lock(ua->db);
+   {
+      /* Get optional filters for the SQL query */
+      const char *where = ua->db->get_acls(DB_ACL_BIT(DB_ACL_JOB) |
+                                           DB_ACL_BIT(DB_ACL_CLIENT) |
+                                           DB_ACL_BIT(DB_ACL_FILESET), true);
 
-   rx->found = false;
+      const char *join = *where ? ua->db->get_acl_join_filter(DB_ACL_BIT(DB_ACL_JOB) |
+                                                              DB_ACL_BIT(DB_ACL_CLIENT)  |
+                                                              DB_ACL_BIT(DB_ACL_FILESET)) : "";
 
-   /* Find and insert jobid and File Index. The JobIds are stored in rx->JobIds */
-   if (!db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx)) {
+      Mmsg(rx->query, uar_jobid_fileindex_from_table, table, join, where);
+      rx->found = false;
+
+      /* Find and insert jobid and File Index. The JobIds are stored in rx->JobIds */
+      ret = db_sql_query(ua->db, rx->query, jobid_fileindex_handler, (void *)rx);
+   }
+   db_unlock(ua->db);
+   if (!ret) {
       ua->error_msg(_("Query failed: %s. ERR=%s\n"),
-         rx->query, db_strerror(ua->db));
+                    rx->query, db_strerror(ua->db));
    }
    if (!rx->found) {
       ua->error_msg(_("No table found: %s\n"), table);
index a61599f981444a76f6ce73fa9dcde288ddaf7815..24a12c6646262e14c30aec2bc48d66ce0916ad62 100644 (file)
@@ -343,6 +343,7 @@ static void display_transfer_priority(HPKT &hpkt)
       }
    }
 }
+
 /*
  * Dump out all resources in json format.
  * Note!!!! This routine must be in this file rather