]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_output.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / dird / ua_output.c
index 00a6c3be89a5cdcbc358f4d43f43e0f9cc0d762f..c8e156a39547aa07bb78896ddef9cd75835e443b 100644 (file)
@@ -1,26 +1,26 @@
 /*
-   Bacula® - The Network Backup Solution
+   Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2017 Kern Sibbald
 
-   The main author of Bacula is Kern Sibbald, with contributions from many
-   others, a complete list can be found in the file AUTHORS.
+   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.
 
-   Bacula® is a registered trademark of Kern Sibbald.
+   This notice must be preserved when any source code is
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
- *
  *   Bacula Director -- User Agent Output Commands
  *     I.e. messages, listing database, showing resources, ...
  *
  *     Kern Sibbald, September MM
- *
- *   Version $Id$
  */
 
 #include "bacula.h"
@@ -95,7 +95,7 @@ static void show_disabled_jobs(UAContext *ua)
       if (!acl_access_ok(ua, Job_ACL, job->name())) {
          continue;
       }
-      if (!job->enabled) {
+      if (!job->is_enabled()) {
          if (first) {
             first = false;
             ua->send_msg(_("Disabled Jobs:\n"));
@@ -121,6 +121,9 @@ static struct showstruct reses[] = {
    {NT_("filesets"),   R_FILESET},
    {NT_("pools"),      R_POOL},
    {NT_("messages"),   R_MSGS},
+// {NT_("consoles"),   R_CONSOLE},
+// {NT_("jobdefs"),    R_JOBDEFS},
+// {NT_{"autochangers"), R_AUTOCHANGER},
    {NT_("all"),        -1},
    {NT_("help"),       -2},
    {NULL,           0}
@@ -141,6 +144,7 @@ int show_cmd(UAContext *ua, const char *cmd)
    int i, j, type, len;
    int recurse;
    char *res_name;
+   RES_HEAD *reshead = NULL;
    RES *res = NULL;
 
    Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
@@ -148,23 +152,27 @@ int show_cmd(UAContext *ua, const char *cmd)
 
    LockRes();
    for (i=1; i<ua->argc; i++) {
-      if (strcasecmp(ua->argk[i], _("disabled")) == 0) {
+      if (strcasecmp(ua->argk[i], NT_("disabled")) == 0) {
          show_disabled_jobs(ua);
          goto bail_out;
       }
+
+      res = NULL;
+      reshead = NULL;
       type = 0;
+
       res_name = ua->argk[i];
       if (!ua->argv[i]) {             /* was a name given? */
          /* No name, dump all resources of specified type */
          recurse = 1;
          len = strlen(res_name);
          for (j=0; reses[j].res_name; j++) {
-            if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
+            if (strncasecmp(res_name, reses[j].res_name, len) == 0) {
                type = reses[j].type;
                if (type > 0) {
-                  res = res_head[type-r_first];
+                  reshead = res_head[type-r_first];
                } else {
-                  res = NULL;
+                  reshead = NULL;
                }
                break;
             }
@@ -175,7 +183,7 @@ int show_cmd(UAContext *ua, const char *cmd)
          recurse = 0;
          len = strlen(res_name);
          for (j=0; reses[j].res_name; j++) {
-            if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
+            if (strncasecmp(res_name, reses[j].res_name, len) == 0) {
                type = reses[j].type;
                res = (RES *)GetResWithName(type, ua->argv[i]);
                if (!res) {
@@ -187,28 +195,38 @@ int show_cmd(UAContext *ua, const char *cmd)
       }
 
       switch (type) {
-      case -1:                           /* all */
+      /* All resources */
+      case -1:
          for (j=r_first; j<=r_last; j++) {
             /* Skip R_DEVICE since it is really not used or updated */
             if (j != R_DEVICE) {
-               dump_resource(j, res_head[j-r_first], bsendmsg, ua);
+               dump_each_resource(j, bsendmsg, ua);
             }
          }
          break;
+      /* Help */
       case -2:
          ua->send_msg(_("Keywords for the show command are:\n"));
          for (j=0; reses[j].res_name; j++) {
-            ua->error_msg("%s\n", _(reses[j].res_name));
+            ua->error_msg("%s\n", reses[j].res_name);
          }
          goto bail_out;
+      /* Resource not found */
       case -3:
          ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]);
          goto bail_out;
+      /* Resource not found */
       case 0:
          ua->error_msg(_("Resource %s not found\n"), res_name);
          goto bail_out;
+      /* Dump a specific type */
       default:
-         dump_resource(recurse?type:-type, res, bsendmsg, ua);
+         if (res) {             /* keyword and argument, ie: show job=name */
+            dump_resource(recurse?type:-type, res, bsendmsg, ua);
+
+         } else if (reshead) {  /* keyword only, ie: show job */
+            dump_each_resource(-type, bsendmsg, ua);
+         }
          break;
       }
    }
@@ -217,8 +235,72 @@ bail_out:
    return 1;
 }
 
+/*
+ * Check if the access is permitted for a list of jobids
+ *
+ * Not in ua_acl.c because it's using db access, and tools such
+ * as bdirjson are not linked with cats.
+ */
+bool acl_access_jobid_ok(UAContext *ua, const char *jobids)
+{
+   char     *tmp=NULL, *p;
+   bool      ret=false;
+   JOB_DBR   jr;
+   uint32_t  jid;
 
+   if (!jobids) {
+      return false;
+   }
+
+   if (!is_a_number_list(jobids)) {
+      return false;
+   }
+
+   /* If no console resource => default console and all is permitted */
+   if (!ua || !ua->cons) {
+      Dmsg0(1400, "Root cons access OK.\n");
+      return true;     /* No cons resource -> root console OK for everything */
+   }
+
+   alist *list = ua->cons->ACL_lists[Job_ACL];
+   if (!list) {                       /* empty list */
+      return false;                   /* List empty, reject everything */
+   }
+
+   /* Special case *all* gives full access */
+   if (list->size() == 1 && strcasecmp("*all*", (char *)list->get(0)) == 0) {
+      return true;
+   }
+
+   /* If we can't open the database, just say no */
+   if (!open_new_client_db(ua)) {
+      return false;
+   }
 
+   p = tmp = bstrdup(jobids);
+
+   while (get_next_jobid_from_list(&p, &jid) > 0) {
+      memset(&jr, 0, sizeof(jr));
+      jr.JobId = jid;
+
+      if (db_get_job_record(ua->jcr, ua->db, &jr)) {
+         for (int i=0; i<list->size(); i++) {
+            if (strcasecmp(jr.Name, (char *)list->get(i)) == 0) {
+               Dmsg3(1400, "ACL found %s in %d %s\n", jr.Name,
+                     Job_ACL, (char *)list->get(i));
+               ret = true;
+               goto bail_out;
+            }
+         }
+      }
+   }
+
+bail_out:
+   if (tmp) {
+      free(tmp);
+   }
+   return ret;
+}
 
 /*
  *  List contents of database
@@ -232,8 +314,8 @@ bail_out:
  *  list jobmedia job=name
  *  list joblog jobid=<nn>
  *  list joblog job=name
- *  list files jobid=<nn> - list files saved for job nn
- *  list files job=name
+ *  list files [type=<deleted|all>] jobid=<nn> - list files saved for job nn
+ *  list files [type=<deleted|all>] job=name
  *  list pools          - list pool records
  *  list jobtotals      - list totals for all jobs
  *  list media          - list media for given pool (deprecated)
@@ -242,7 +324,10 @@ bail_out:
  *  list nextvol job=xx  - list the next vol to be used by job
  *  list nextvolume job=xx - same as above.
  *  list copies jobid=x,y,z
+ *  list pluginrestoreconf jobid=x,y,z [id=k]
  *
+ *  Note: keyword "long" is before the first command on the command 
+ *    line results in doing a llist (long listing).
  */
 
 /* Do long or full listing */
@@ -254,19 +339,23 @@ int llist_cmd(UAContext *ua, const char *cmd)
 /* Do short or summary listing */
 int list_cmd(UAContext *ua, const char *cmd)
 {
-   return do_list_cmd(ua, cmd, HORZ_LIST);
+   if (find_arg(ua, "long") > 0) {
+      return do_list_cmd(ua, cmd, VERT_LIST);  /* do a long list */
+   } else {
+      return do_list_cmd(ua, cmd, HORZ_LIST);  /* do a short list */
+   }
 }
 
 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
 {
    POOLMEM *VolumeName;
-   int jobid, n;
+   int jobid=0, n;
    int i, j;
    JOB_DBR jr;
    POOL_DBR pr;
    MEDIA_DBR mr;
 
-   if (!open_client_db(ua))
+   if (!open_new_client_db(ua))
       return 1;
 
    memset(&jr, 0, sizeof(jr));
@@ -277,11 +366,54 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
    if (!ua->db) {
       ua->error_msg(_("Hey! DB is NULL\n"));
    }
-
    /* Apply any limit */
-   j = find_arg_with_value(ua, NT_("limit"));
-   if (j >= 0) {
-      jr.limit = atoi(ua->argv[j]);
+   for (j = 1; j < ua->argc ; j++) {
+      if (strcasecmp(ua->argk[j], NT_("joberrors")) == 0) {
+         jr.JobErrors = 1;
+      } else if (!ua->argv[j]) {
+         /* skip */
+      } else if (strcasecmp(ua->argk[j], NT_("order")) == 0) {
+         if ((strcasecmp(ua->argv[j], NT_("desc")) == 0) ||
+            strcasecmp(ua->argv[j], NT_("descending")) == 0) {
+            jr.order = 1;
+         } else if ((strcasecmp(ua->argv[j], NT_("asc")) == 0) ||
+            strcasecmp(ua->argv[j], NT_("ascending")) == 0) {
+            jr.order = 0;
+         } else {
+            ua->error_msg(_("Unknown order type %s\n"), ua->argv[j]);
+            return 1;
+         }
+      } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0) {
+         jr.limit = atoi(ua->argv[j]);
+
+      } else if (strcasecmp(ua->argk[j], NT_("jobstatus")) == 0) {
+         if (B_ISALPHA(ua->argv[j][0])) {
+            jr.JobStatus = ua->argv[j][0]; /* TODO: Check if the code is correct */
+         }
+      } else if (strcasecmp(ua->argk[j], NT_("jobtype")) == 0) {
+         if (B_ISALPHA(ua->argv[j][0])) {
+            jr.JobType = ua->argv[j][0]; /* TODO: Check if the code is correct */
+         }
+      } else if (strcasecmp(ua->argk[j], NT_("level")) == 0) {
+         if (strlen(ua->argv[j]) > 1) {
+            jr.JobLevel = get_level_code_from_name(ua->argv[j]);
+
+         } else if (B_ISALPHA(ua->argv[j][0])) {
+            jr.JobLevel = ua->argv[j][0]; /* TODO: Check if the code is correct */
+         }
+      } else if (strcasecmp(ua->argk[j], NT_("level")) == 0) {
+
+
+      } else if (strcasecmp(ua->argk[j], NT_("client")) == 0) {
+         if (is_name_valid(ua->argv[j], NULL)) {
+            CLIENT_DBR cr;
+            memset(&cr, 0, sizeof(cr));
+            /* Both Backup & Restore wants to list jobs for this client */
+            if(get_client_dbr(ua, &cr, JT_BACKUP_RESTORE)) {
+               jr.ClientId = cr.ClientId;
+            }
+         }
+      }
    }
 
    /* Scan arguments looking for things to do */
@@ -338,20 +470,29 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
 
       /* List FILES */
       } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
-
+         int deleted = 0;       /* see only backed up files */
          for (j=i+1; j<ua->argc; j++) {
             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
                jr.JobId = 0;
                db_get_job_record(ua->jcr, ua->db, &jr);
                jobid = jr.JobId;
+
             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
                jobid = str_to_int64(ua->argv[j]);
+
+            } else if (strcasecmp(ua->argk[j], NT_("type")) == 0 && ua->argv[j]) {
+               if (strcasecmp(ua->argv[j], NT_("deleted")) == 0) {
+                  deleted = 1;
+               } else if (strcasecmp(ua->argv[j], NT_("all")) == 0) {
+                  deleted = -1;
+               }
+               continue;        /* Type should be before the jobid... */
             } else {
                continue;
             }
             if (jobid > 0) {
-               db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
+               db_list_files_for_job(ua->jcr, ua->db, jobid, deleted, prtit, ua);
             }
          }
 
@@ -413,6 +554,83 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
       } else if (strcasecmp(ua->argk[i], NT_("clients")) == 0) {
          db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
 
+      } else if (strcasecmp(ua->argk[i], NT_("pluginrestoreconf")) == 0) {
+         ROBJECT_DBR rr;
+         memset(&rr, 0, sizeof(rr));
+         rr.FileType = FT_PLUGIN_CONFIG;
+
+         for (j=i+1; j<ua->argc; j++) {
+            if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
+               bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
+               jr.JobId = 0;
+
+            } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
+
+               if (acl_access_jobid_ok(ua, ua->argv[j])) {
+
+                  if (is_a_number(ua->argv[j])) {
+                     rr.JobId = str_to_uint64(ua->argv[j]);
+
+                  } else if (is_a_number_list(ua->argv[j])) {
+                     /* In this case, loop directly to find if all jobids are
+                      * accessible */
+                     rr.JobIds = ua->argv[j];
+                  }
+
+               } else {
+                  ua->error_msg(_("Invalid jobid argument\n"));
+                  return 1;
+               }
+
+            } else if (((strcasecmp(ua->argk[j], NT_("id")) == 0) ||
+                        (strcasecmp(ua->argk[j], NT_("restoreobjectid")) == 0))
+                       && ua->argv[j])
+            {
+               rr.RestoreObjectId = str_to_uint64(ua->argv[j]);
+
+            } else if (strcasecmp(ua->argk[j], NT_("objecttype")) == 0 && ua->argv[j]) {
+               if (strcasecmp(ua->argv[j], NT_("PLUGIN_CONFIG")) == 0) {
+                  rr.FileType = FT_PLUGIN_CONFIG;
+
+               } else if (strcasecmp(ua->argv[j], NT_("PLUGIN_CONFIG_FILLED")) == 0) {
+                  rr.FileType = FT_PLUGIN_CONFIG_FILLED;
+
+               } else if (strcasecmp(ua->argv[j], NT_("RESTORE_FIRST")) == 0) {
+                  rr.FileType = FT_RESTORE_FIRST;
+
+               } else if (strcasecmp(ua->argv[j], NT_("ALL")) == 0) {
+                  rr.FileType = 0;
+
+               } else {
+                  ua->error_msg(_("Unknown ObjectType %s\n"), ua->argv[j]);
+                  return 1;
+               }
+
+            } else {
+               continue;
+            }
+         }
+
+         if (!rr.JobId && !rr.JobIds) {
+            ua->error_msg(_("list pluginrestoreconf requires jobid argument\n"));
+            return 1;
+         }
+
+          /* Display the content of the restore object */
+         if (rr.RestoreObjectId > 0) {
+            /* Here, the JobId and the RestoreObjectId are set */
+            if (db_get_restoreobject_record(ua->jcr, ua->db, &rr)) {
+               ua->send_msg("%s\n", NPRTB(rr.object));
+            } else {
+               Dmsg0(200, "Object not found\n");
+            }
+
+         } else {
+            db_list_restore_objects(ua->jcr, ua->db, &rr, prtit, ua, llist);
+         }
+
+         db_free_restoreobject_record(ua->jcr, &rr);
+         return 1;
 
       /* List MEDIA or VOLUMES */
       } else if (strcasecmp(ua->argk[i], NT_("media")) == 0 ||
@@ -442,7 +660,7 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
             int num_pools;
             uint32_t *ids;
             /* List a specific volume? */
-            if (ua->argv[i]) {
+            if (ua->argv[i] && *ua->argv[i]) {
                bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
                return 1;
@@ -507,8 +725,23 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
          }
          db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist);
       } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
-                 || strcasecmp(ua->argk[i], NT_("days")) == 0) {
+                 || strcasecmp(ua->argk[i], NT_("days")) == 0
+                 || strcasecmp(ua->argk[i], NT_("joberrors")) == 0
+                 || strcasecmp(ua->argk[i], NT_("order")) == 0
+                 || strcasecmp(ua->argk[i], NT_("jobstatus")) == 0
+                 || strcasecmp(ua->argk[i], NT_("client")) == 0
+                 || strcasecmp(ua->argk[i], NT_("type")) == 0
+                 || strcasecmp(ua->argk[i], NT_("level")) == 0
+                 || strcasecmp(ua->argk[i], NT_("jobtype")) == 0
+                 || strcasecmp(ua->argk[i], NT_("long")) == 0
+         ) {
          /* Ignore it */
+      } else if (strcasecmp(ua->argk[i], NT_("snapshot")) == 0 ||
+                 strcasecmp(ua->argk[i], NT_("snapshots")) == 0) 
+      {
+         snapshot_list(ua, i, prtit, llist);
+         return 1;
+
       } else {
          ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
       }
@@ -573,10 +806,8 @@ static bool list_nextvol(UAContext *ua, int ndays)
    }
 
 get_out:
-   if (jcr->db) {
-      db_close_database(jcr, jcr->db);
-      jcr->db = NULL;
-   }
+   if (jcr->db) db_close_database(jcr, jcr->db);
+   jcr->db = NULL;
    free_jcr(jcr);
    if (!found) {
       ua->error_msg(_("Could not find next Volume for Job %s.\n"),
@@ -602,7 +833,8 @@ RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
    bool is_scheduled;
 
    sched = job->schedule;
-   if (sched == NULL) {            /* scheduled? */
+   if (!sched || !job->is_enabled() || (sched && !sched->is_enabled()) ||
+       (job->client && !job->client->is_enabled())) {
       return NULL;                 /* no nothing to report */
    }
 
@@ -705,11 +937,13 @@ bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
 
    Dmsg0(100, "complete_jcr open db\n");
    jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
-                              jcr->catalog->db_user,
-                              jcr->catalog->db_password, jcr->catalog->db_address,
-                              jcr->catalog->db_port, jcr->catalog->db_socket,
-                              jcr->catalog->mult_db_connections,
-                              jcr->catalog->disable_batch_insert);
+                jcr->catalog->db_user,
+                jcr->catalog->db_password, jcr->catalog->db_address,
+                jcr->catalog->db_port, jcr->catalog->db_socket,
+                jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
+                jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
+                jcr->catalog->mult_db_connections,
+                jcr->catalog->disable_batch_insert);
    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
                  jcr->catalog->db_name);
@@ -751,6 +985,9 @@ void do_messages(UAContext *ua, const char *cmd)
    int mlen;
    bool do_truncate = false;
 
+   if (ua->jcr) {
+      dequeue_messages(ua->jcr);
+   }
    Pw(con_lock);
    pthread_cleanup_push(con_lock_release, (void *)NULL);
    rewind(con_fd);
@@ -797,7 +1034,7 @@ void prtit(void *ctx, const char *msg)
 {
    UAContext *ua = (UAContext *)ctx;
 
-   ua->UA_sock->fsend("%s", msg);
+   if (ua) ua->send_msg("%s", msg);
 }
 
 /*