/*
- 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"
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"));
{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}
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);
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;
}
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) {
}
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;
}
}
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
* 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)
* 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 */
/* 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));
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 */
/* 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);
}
}
} 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 ||
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;
}
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]));
}
}
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"),
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 */
}
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);
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);
{
UAContext *ua = (UAContext *)ctx;
- ua->UA_sock->fsend("%s", msg);
+ if (ua) ua->send_msg("%s", msg);
}
/*