2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- User Agent Commands
32 * Kern Sibbald, September MM
42 #undef _POSIX_C_SOURCE
45 #include "lib/pythonlib.h"
47 /* Imported Functions */
48 extern PyObject *job_getattr(PyObject *self, char *attrname);
49 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
51 #endif /* HAVE_PYTHON */
53 /* Imported subroutines */
55 /* Imported variables */
56 extern jobq_t job_queue; /* job queue */
59 /* Imported functions */
60 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
61 extern int gui_cmd(UAContext *ua, const char *cmd);
62 extern int label_cmd(UAContext *ua, const char *cmd);
63 extern int list_cmd(UAContext *ua, const char *cmd);
64 extern int llist_cmd(UAContext *ua, const char *cmd);
65 extern int messagescmd(UAContext *ua, const char *cmd);
66 extern int prunecmd(UAContext *ua, const char *cmd);
67 extern int purgecmd(UAContext *ua, const char *cmd);
68 extern int querycmd(UAContext *ua, const char *cmd);
69 extern int relabel_cmd(UAContext *ua, const char *cmd);
70 extern int restore_cmd(UAContext *ua, const char *cmd);
71 extern int retentioncmd(UAContext *ua, const char *cmd);
72 extern int show_cmd(UAContext *ua, const char *cmd);
73 extern int sqlquerycmd(UAContext *ua, const char *cmd);
74 extern int status_cmd(UAContext *ua, const char *cmd);
75 extern int update_cmd(UAContext *ua, const char *cmd);
77 /* Forward referenced functions */
78 static int add_cmd(UAContext *ua, const char *cmd);
79 static int automount_cmd(UAContext *ua, const char *cmd);
80 static int cancel_cmd(UAContext *ua, const char *cmd);
81 static int create_cmd(UAContext *ua, const char *cmd);
82 static int delete_cmd(UAContext *ua, const char *cmd);
83 static int disable_cmd(UAContext *ua, const char *cmd);
84 static int enable_cmd(UAContext *ua, const char *cmd);
85 static int estimate_cmd(UAContext *ua, const char *cmd);
86 static int help_cmd(UAContext *ua, const char *cmd);
87 static int memory_cmd(UAContext *ua, const char *cmd);
88 static int mount_cmd(UAContext *ua, const char *cmd);
89 static int python_cmd(UAContext *ua, const char *cmd);
90 static int release_cmd(UAContext *ua, const char *cmd);
91 static int reload_cmd(UAContext *ua, const char *cmd);
92 static int setdebug_cmd(UAContext *ua, const char *cmd);
93 static int setip_cmd(UAContext *ua, const char *cmd);
94 static int time_cmd(UAContext *ua, const char *cmd);
95 static int trace_cmd(UAContext *ua, const char *cmd);
96 static int unmount_cmd(UAContext *ua, const char *cmd);
97 static int use_cmd(UAContext *ua, const char *cmd);
98 static int var_cmd(UAContext *ua, const char *cmd);
99 static int version_cmd(UAContext *ua, const char *cmd);
100 static int wait_cmd(UAContext *ua, const char *cmd);
102 static void do_job_delete(UAContext *ua, JobId_t JobId);
103 static void delete_job_id_range(UAContext *ua, char *tok);
104 static int delete_volume(UAContext *ua);
105 static int delete_pool(UAContext *ua);
106 static void delete_job(UAContext *ua);
108 int qhelp_cmd(UAContext *ua, const char *cmd);
109 int quit_cmd(UAContext *ua, const char *cmd);
111 /* not all in alphabetical order. New commands are added after existing commands with similar letters
112 to prevent breakage of existing user scripts. */
113 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; const bool use_in_rs;};
114 static struct cmdstruct commands[] = { /* Can use it in Console RunScript*/
115 { NT_("add"), add_cmd, _("add [pool=<pool-name> storage=<storage> jobid=<JobId>] -- add media to a pool"), false},
116 { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages"),false},
117 { NT_("automount"), automount_cmd, _("automount [on|off] -- after label"), false},
118 { NT_("cancel"), cancel_cmd, _("cancel [jobid=<number> job=<job-name> ujobid=<unique-jobid>] -- cancel a job"), false},
119 { NT_("create"), create_cmd, _("create [pool=<pool-name>] -- create DB Pool from resource"), false},
120 { NT_("delete"), delete_cmd, _("delete [volume=<vol-name> pool=<pool-name> job jobid=<id>]"), true},
121 { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job"), true},
122 { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job"), true},
123 { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing"), true},
124 { NT_("exit"), quit_cmd, _("exit = quit"), false},
125 { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode"), false},
126 { NT_("help"), help_cmd, _("print this command"), false},
127 { NT_("label"), label_cmd, _("label a tape"), false},
128 { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn> | copies <jobid=nn>]; from catalog"), true},
129 { NT_("llist"), llist_cmd, _("full or long list like list command"), true},
130 { NT_("messages"), messagescmd, _("messages"), false},
131 { NT_("memory"), memory_cmd, _("print current memory usage"), true},
132 { NT_("mount"), mount_cmd, _("mount storage=<storage-name> [ slot=<num> ] [ drive=<num> ] or mount [ jobid=<id> | job=<job-name> ]"), false},
133 { NT_("prune"), prunecmd, _("prune files|jobs|volume client=<client-name> volume=<volume-name> prune expired records from catalog"), true},
134 { NT_("purge"), purgecmd, _("purge records from catalog"), true},
135 { NT_("python"), python_cmd, _("python control commands"), false},
136 { NT_("quit"), quit_cmd, _("quit"), false},
137 { NT_("query"), querycmd, _("query catalog"), false},
138 { NT_("restore"), restore_cmd, _("restore files"), false},
139 { NT_("relabel"), relabel_cmd, _("relabel storage=<storage-name> oldvolume=<old-volume-name> volume=<newvolume-name> -- relabel a tape"), false},
140 { NT_("release"), release_cmd, _("release <storage-name>"), false},
141 { NT_("reload"), reload_cmd, _("reload conf file"), true},
142 { NT_("run"), run_cmd, _("run job=<job-name> client=<client-name> fileset=<FileSet-name> level=<level-keyword> storage=<storage-name> where=<directory-prefix> when=<universal-time-specification> yes"), false}, /* need to be check */
143 { NT_("status"), status_cmd, _("status [all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> | days=nnn]"), true},
144 { NT_("setdebug"), setdebug_cmd, _("setdebug level=nn [trace=0/1 client=<client-name> | dir | director | storage=<storage-name> | all] -- sets debug level"), true},
145 { NT_("setip"), setip_cmd, _("sets new client address -- if authorized"), false},
146 { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]"), true},
147 { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog"), false},
148 { NT_("time"), time_cmd, _("print current time"), true},
149 { NT_("trace"), trace_cmd, _("turn on/off trace to file"), true},
150 { NT_("unmount"), unmount_cmd, _("unmount storage=<storage-name> [ drive=<num> ] or unmount [ jobid=<id> | job=<job-name> ]"), false},
151 { NT_("umount"), unmount_cmd, _("umount - for old-time Unix guys, see unmount"),false},
152 { NT_("update"), update_cmd, _("update Volume, Pool or slots"), true},
153 { NT_("use"), use_cmd, _("use <database-name> -- catalog xxx"), false},
154 { NT_("var"), var_cmd, _("does variable expansion"), false},
155 { NT_("version"), version_cmd, _("print Director version"), true},
156 { NT_("wait"), wait_cmd, _("wait [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>] -- wait until no jobs are running"), false},
158 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
161 * Execute a command from the UA
163 bool do_a_command(UAContext *ua)
169 BSOCK *user = ua->UA_sock;
172 Dmsg1(900, "Command: %s\n", ua->argk[0]);
177 while (ua->jcr->wstorage->size()) {
178 ua->jcr->wstorage->remove(0);
181 len = strlen(ua->argk[0]);
182 for (i=0; i<comsize; i++) { /* search for command */
183 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
184 /* Check if command permitted, but "quit" is always OK */
185 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
186 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
189 /* Check if this command is authorized in RunScript */
190 if (ua->runscript && !commands[i].use_in_rs) {
191 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
194 if (ua->api) user->signal(BNET_CMD_BEGIN);
195 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
201 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
204 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
209 * This is a common routine used to stuff the Pool DB record defaults
210 * into the Media DB record just before creating a media (Volume)
213 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
215 mr->PoolId = pr->PoolId;
216 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
217 mr->Recycle = pr->Recycle;
218 mr->VolRetention = pr->VolRetention;
219 mr->VolUseDuration = pr->VolUseDuration;
220 mr->RecyclePoolId = pr->RecyclePoolId;
221 mr->MaxVolJobs = pr->MaxVolJobs;
222 mr->MaxVolFiles = pr->MaxVolFiles;
223 mr->MaxVolBytes = pr->MaxVolBytes;
224 mr->LabelType = pr->LabelType;
230 * Add Volumes to an existing Pool
232 static int add_cmd(UAContext *ua, const char *cmd)
236 int num, i, max, startnum;
238 char name[MAX_NAME_LENGTH];
240 int Slot = 0, InChanger = 0;
243 "You probably don't want to be using this command since it\n"
244 "creates database records without labeling the Volumes.\n"
245 "You probably want to use the \"label\" command.\n\n"));
247 if (!open_client_db(ua)) {
251 memset(&pr, 0, sizeof(pr));
252 memset(&mr, 0, sizeof(mr));
254 if (!get_pool_dbr(ua, &pr)) {
258 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
259 pr.MaxVols, pr.PoolType);
261 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
262 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
263 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
266 pr.MaxVols = ua->pint32_val;
270 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
271 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
272 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
276 if (pr.MaxVols == 0) {
279 max = pr.MaxVols - pr.NumVols;
283 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
284 if (!get_pint(ua, buf)) {
287 num = ua->pint32_val;
288 if (num < 0 || num > max) {
289 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
297 if (!get_cmd(ua, _("Enter Volume name: "))) {
301 if (!get_cmd(ua, _("Enter base volume name: "))) {
305 /* Don't allow | in Volume name because it is the volume separator character */
306 if (!is_volume_name_legal(ua, ua->cmd)) {
309 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
310 ua->warning_msg(_("Volume name too long.\n"));
313 if (strlen(ua->cmd) == 0) {
314 ua->warning_msg(_("Volume name must be at least one character long.\n"));
320 bstrncpy(name, ua->cmd, sizeof(name));
322 bstrncat(name, "%04d", sizeof(name));
325 if (!get_pint(ua, _("Enter the starting number: "))) {
328 startnum = ua->pint32_val;
330 ua->warning_msg(_("Start number must be greater than zero.\n"));
340 if (store && store->autochanger) {
341 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
344 Slot = ua->pint32_val;
345 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
348 InChanger = ua->pint32_val;
351 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
352 for (i=startnum; i < num+startnum; i++) {
353 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
355 mr.InChanger = InChanger;
356 mr.StorageId = store->StorageId;
358 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
359 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
360 ua->error_msg("%s", db_strerror(ua->db));
364 first_id = mr.PoolId;
368 Dmsg0(200, "Update pool record.\n");
369 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
370 ua->warning_msg("%s", db_strerror(ua->db));
373 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
379 * Turn auto mount on/off
384 int automount_cmd(UAContext *ua, const char *cmd)
389 if (!get_cmd(ua, _("Turn on or off? "))) {
397 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
405 static int cancel_cmd(UAContext *ua, const char *cmd)
410 char JobName[MAX_NAME_LENGTH];
412 for (i=1; i<ua->argc; i++) {
413 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
418 JobId = str_to_int64(ua->argv[i]);
419 if (!(jcr=get_jcr_by_id(JobId))) {
420 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
424 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
428 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
429 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
430 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
431 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
434 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
438 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
439 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
440 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
441 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
448 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
449 ua->error_msg(_("Unauthorized command from this console.\n"));
454 * If we still do not have a jcr,
455 * throw up a list and ask the user to select one.
458 int tjobs = 0; /* total # number jobs */
459 /* Count Jobs running */
461 if (jcr->JobId == 0) { /* this is us */
464 tjobs++; /* count of all jobs */
465 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
466 continue; /* skip not authorized */
468 njobs++; /* count of authorized jobs */
472 if (njobs == 0) { /* no authorized */
474 ua->send_msg(_("No Jobs running.\n"));
476 ua->send_msg(_("None of your jobs are running.\n"));
481 start_prompt(ua, _("Select Job:\n"));
484 if (jcr->JobId == 0) { /* this is us */
487 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
488 continue; /* skip not authorized */
490 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
495 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
498 if (ua->api && njobs == 1) {
500 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
501 _("Confirm cancel?"));
502 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
507 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
512 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
513 jcr = get_jcr_by_full_name(JobName);
515 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
520 ret = cancel_job(ua, jcr);
526 * This is a common routine to create or update a
527 * Pool DB base record from a Pool Resource. We handle
528 * the setting of MaxVols and NumVols slightly differently
529 * depending on if we are creating the Pool or we are
530 * simply bringing it into agreement with the resource (updage).
532 * Caution : RecyclePoolId isn't setup in this function.
533 * You can use set_pooldbr_recyclepoolid();
536 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
538 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
539 if (op == POOL_OP_CREATE) {
540 pr->MaxVols = pool->max_volumes;
542 } else { /* update pool */
543 if (pr->MaxVols != pool->max_volumes) {
544 pr->MaxVols = pool->max_volumes;
546 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
547 pr->MaxVols = pr->NumVols;
550 pr->LabelType = pool->LabelType;
551 pr->UseOnce = pool->use_volume_once;
552 pr->UseCatalog = pool->use_catalog;
553 pr->Recycle = pool->Recycle;
554 pr->VolRetention = pool->VolRetention;
555 pr->VolUseDuration = pool->VolUseDuration;
556 pr->MaxVolJobs = pool->MaxVolJobs;
557 pr->MaxVolFiles = pool->MaxVolFiles;
558 pr->MaxVolBytes = pool->MaxVolBytes;
559 pr->AutoPrune = pool->AutoPrune;
560 pr->Recycle = pool->Recycle;
561 if (pool->label_format) {
562 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
564 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
568 /* set/update Pool.RecyclePoolId in Catalog */
569 int update_pool_recyclepool(JCR *jcr, B_DB *db, POOL *pool)
573 if (!pool->RecyclePool) {
577 memset(&pr, 0, sizeof(POOL_DBR));
578 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
580 if (!db_get_pool_record(jcr, db, &pr)) {
581 return -1; /* not exists in database */
584 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
586 if (!set_pooldbr_recyclepoolid(jcr, db, &pr, pool)) {
587 return -1; /* error */
590 if (!db_update_pool_record(jcr, db, &pr)) {
591 return -1; /* error */
596 /* set POOL_DBR.RecyclePoolId from Pool resource
597 * works with set_pooldbr_from_poolres
599 bool set_pooldbr_recyclepoolid(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
604 if (pool->RecyclePool) {
605 memset(&rpool, 0, sizeof(POOL_DBR));
607 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
608 if (db_get_pool_record(jcr, db, &rpool)) {
609 pr->RecyclePoolId = rpool.PoolId;
611 Jmsg(jcr, M_WARNING, 0,
612 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
613 "Try to update it with 'update pool=%s'\n"),
614 pool->name(), rpool.Name, rpool.Name,pool->name());
618 } else { /* no RecyclePool used, set it to 0 */
619 pr->RecyclePoolId = 0;
626 * Create a pool record from a given Pool resource
627 * Also called from backup.c
628 * Returns: -1 on error
629 * 0 record already exists
633 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
637 memset(&pr, 0, sizeof(POOL_DBR));
639 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
641 if (db_get_pool_record(jcr, db, &pr)) {
643 if (op == POOL_OP_UPDATE) { /* update request */
644 set_pooldbr_from_poolres(&pr, pool, op);
645 db_update_pool_record(jcr, db, &pr);
647 return 0; /* exists */
650 set_pooldbr_from_poolres(&pr, pool, op);
652 if (!db_create_pool_record(jcr, db, &pr)) {
653 return -1; /* error */
661 * Create a Pool Record in the database.
662 * It is always created from the Resource record.
664 static int create_cmd(UAContext *ua, const char *cmd)
668 if (!open_client_db(ua)) {
672 pool = get_pool_resource(ua);
677 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
679 ua->error_msg(_("Error: Pool %s already exists.\n"
680 "Use update to change it.\n"), pool->name());
684 ua->error_msg("%s", db_strerror(ua->db));
690 ua->send_msg(_("Pool %s created.\n"), pool->name());
695 extern DIRRES *director;
696 extern char *configfile;
699 * Python control command
700 * python restart (restarts interpreter)
702 static int python_cmd(UAContext *ua, const char *cmd)
705 init_python_interpreter_args python_args;
707 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
708 term_python_interpreter();
710 python_args.progname = director->name();
711 python_args.scriptdir = director->scripts_directory;
712 python_args.modulename = "DirStartUp";
713 python_args.configfile = configfile;
714 python_args.workingdir = director->working_directory;
715 python_args.job_getattr = job_getattr;
716 python_args.job_setattr = job_setattr;
718 init_python_interpreter(&python_args);
720 ua->send_msg(_("Python interpreter restarted.\n"));
722 #endif /* HAVE_PYTHON */
723 ua->warning_msg(_("Nothing done.\n"));
726 #endif /* HAVE_PYTHON */
732 * Set a new address in a Client resource. We do this only
733 * if the Console name is the same as the Client name
734 * and the Console can access the client.
736 static int setip_cmd(UAContext *ua, const char *cmd)
740 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
741 ua->error_msg(_("Unauthorized command from this console.\n"));
745 client = GetClientResWithName(ua->cons->name());
748 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
751 if (client->address) {
752 free(client->address);
754 /* MA Bug 6 remove ifdef */
755 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
756 client->address = bstrdup(buf);
757 ua->send_msg(_("Client \"%s\" address set to %s\n"),
758 client->name(), client->address);
765 static void do_en_disable_cmd(UAContext *ua, bool setting)
770 i = find_arg_with_value(ua, NT_("job"));
772 job = select_job_resource(ua);
778 job = GetJobResWithName(ua->argv[i]);
782 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
786 if (!acl_access_ok(ua, Job_ACL, job->name())) {
787 ua->error_msg(_("Unauthorized command from this console.\n"));
790 job->enabled = setting;
791 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
795 static int enable_cmd(UAContext *ua, const char *cmd)
797 do_en_disable_cmd(ua, true);
801 static int disable_cmd(UAContext *ua, const char *cmd)
803 do_en_disable_cmd(ua, false);
808 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
814 lstore.store = store;
815 pm_strcpy(lstore.store_source, _("unknown source"));
816 set_wstorage(jcr, &lstore);
817 /* Try connecting for up to 15 seconds */
818 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
819 store->name(), store->address, store->SDport);
820 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
821 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
824 Dmsg0(120, _("Connected to storage daemon\n"));
825 sd = jcr->store_bsock;
826 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
827 if (sd->recv() >= 0) {
828 ua->send_msg("%s", sd->msg);
830 sd->signal(BNET_TERMINATE);
832 jcr->store_bsock = NULL;
836 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
840 /* Connect to File daemon */
842 ua->jcr->client = client;
843 /* Try to connect for 15 seconds */
844 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
845 client->name(), client->address, client->FDport);
846 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
847 ua->error_msg(_("Failed to connect to Client.\n"));
850 Dmsg0(120, "Connected to file daemon\n");
851 fd = ua->jcr->file_bsock;
852 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
853 if (fd->recv() >= 0) {
854 ua->send_msg("%s", fd->msg);
856 fd->signal(BNET_TERMINATE);
858 ua->jcr->file_bsock = NULL;
863 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
865 STORE *store, **unique_store;
866 CLIENT *client, **unique_client;
872 /* Count Storage items */
876 foreach_res(store, R_STORAGE) {
879 unique_store = (STORE **) malloc(i * sizeof(STORE));
880 /* Find Unique Storage address/port */
881 store = (STORE *)GetNextRes(R_STORAGE, NULL);
883 unique_store[i++] = store;
884 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
886 for (j=0; j<i; j++) {
887 if (strcmp(unique_store[j]->address, store->address) == 0 &&
888 unique_store[j]->SDport == store->SDport) {
894 unique_store[i++] = store;
895 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
900 /* Call each unique Storage daemon */
901 for (j=0; j<i; j++) {
902 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
906 /* Count Client items */
910 foreach_res(client, R_CLIENT) {
913 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
914 /* Find Unique Client address/port */
915 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
917 unique_client[i++] = client;
918 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
920 for (j=0; j<i; j++) {
921 if (strcmp(unique_client[j]->address, client->address) == 0 &&
922 unique_client[j]->FDport == client->FDport) {
928 unique_client[i++] = client;
929 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
934 /* Call each unique File daemon */
935 for (j=0; j<i; j++) {
936 do_client_setdebug(ua, unique_client[j], level, trace_flag);
942 * setdebug level=nn all trace=1/0
944 static int setdebug_cmd(UAContext *ua, const char *cmd)
952 Dmsg1(120, "setdebug:%s:\n", cmd);
955 i = find_arg_with_value(ua, "level");
957 level = atoi(ua->argv[i]);
960 if (!get_pint(ua, _("Enter new debug level: "))) {
963 level = ua->pint32_val;
966 /* Look for trace flag. -1 => not change */
967 i = find_arg_with_value(ua, "trace");
969 trace_flag = atoi(ua->argv[i]);
970 if (trace_flag > 0) {
976 for (i=1; i<ua->argc; i++) {
977 if (strcasecmp(ua->argk[i], "all") == 0) {
978 do_all_setdebug(ua, level, trace_flag);
981 if (strcasecmp(ua->argk[i], "dir") == 0 ||
982 strcasecmp(ua->argk[i], "director") == 0) {
984 set_trace(trace_flag);
987 if (strcasecmp(ua->argk[i], "client") == 0 ||
988 strcasecmp(ua->argk[i], "fd") == 0) {
991 client = GetClientResWithName(ua->argv[i]);
993 do_client_setdebug(ua, client, level, trace_flag);
997 client = select_client_resource(ua);
999 do_client_setdebug(ua, client, level, trace_flag);
1004 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1005 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1006 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1009 store = GetStoreResWithName(ua->argv[i]);
1011 do_storage_setdebug(ua, store, level, trace_flag);
1015 store = get_storage_resource(ua, false/*no default*/);
1017 do_storage_setdebug(ua, store, level, trace_flag);
1023 * We didn't find an appropriate keyword above, so
1026 start_prompt(ua, _("Available daemons are: \n"));
1027 add_prompt(ua, _("Director"));
1028 add_prompt(ua, _("Storage"));
1029 add_prompt(ua, _("Client"));
1030 add_prompt(ua, _("All"));
1031 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1032 case 0: /* Director */
1033 debug_level = level;
1034 set_trace(trace_flag);
1037 store = get_storage_resource(ua, false/*no default*/);
1039 do_storage_setdebug(ua, store, level, trace_flag);
1043 client = select_client_resource(ua);
1045 do_client_setdebug(ua, client, level, trace_flag);
1049 do_all_setdebug(ua, level, trace_flag);
1058 * Turn debug tracing to file on/off
1060 static int trace_cmd(UAContext *ua, const char *cmd)
1064 if (ua->argc != 2) {
1065 if (!get_cmd(ua, _("Turn on or off? "))) {
1070 onoff = ua->argk[1];
1073 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1078 static int var_cmd(UAContext *ua, const char *cmd)
1080 POOLMEM *val = get_pool_memory(PM_FNAME);
1083 if (!open_client_db(ua)) {
1086 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1089 while (*var == ' ') { /* skip spaces */
1092 Dmsg1(100, "Var=%s:\n", var);
1093 variable_expansion(ua->jcr, var, &val);
1094 ua->send_msg("%s\n", val);
1095 free_pool_memory(val);
1099 static int estimate_cmd(UAContext *ua, const char *cmd)
1102 CLIENT *client = NULL;
1103 FILESET *fileset = NULL;
1105 char since[MAXSTRING];
1108 jcr->set_JobLevel(L_FULL);
1109 for (int i=1; i<ua->argc; i++) {
1110 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1111 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1113 client = GetClientResWithName(ua->argv[i]);
1115 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1120 ua->error_msg(_("Client name missing.\n"));
1124 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1126 job = GetJobResWithName(ua->argv[i]);
1128 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1131 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1132 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1137 ua->error_msg(_("Job name missing.\n"));
1142 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1144 fileset = GetFileSetResWithName(ua->argv[i]);
1146 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1149 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1150 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1155 ua->error_msg(_("Fileset name missing.\n"));
1159 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1163 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1165 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1166 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1170 ua->error_msg(_("Level value missing.\n"));
1175 if (!job && !(client && fileset)) {
1176 if (!(job = select_job_resource(ua))) {
1181 job = GetJobResWithName(ua->argk[1]);
1183 ua->error_msg(_("No job specified.\n"));
1186 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1187 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1192 client = job->client;
1195 fileset = job->fileset;
1197 jcr->client = client;
1198 jcr->fileset = fileset;
1200 if (job->pool->catalog) {
1201 ua->catalog = job->pool->catalog;
1203 ua->catalog = client->catalog;
1211 jcr->set_JobType(JT_BACKUP);
1212 init_jcr_job_record(jcr);
1214 if (!get_or_create_client_record(jcr)) {
1217 if (!get_or_create_fileset_record(jcr)) {
1221 get_level_since_time(ua->jcr, since, sizeof(since));
1223 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1224 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1225 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1226 ua->error_msg(_("Failed to connect to Client.\n"));
1230 if (!send_include_list(jcr)) {
1231 ua->error_msg(_("Error sending include list.\n"));
1235 if (!send_exclude_list(jcr)) {
1236 ua->error_msg(_("Error sending exclude list.\n"));
1240 if (!send_level_command(jcr)) {
1244 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1245 while (bnet_recv(jcr->file_bsock) >= 0) {
1246 ua->send_msg("%s", jcr->file_bsock->msg);
1250 if (jcr->file_bsock) {
1251 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1252 bnet_close(jcr->file_bsock);
1253 jcr->file_bsock = NULL;
1262 static int time_cmd(UAContext *ua, const char *cmd)
1265 time_t ttime = time(NULL);
1267 (void)localtime_r(&ttime, &tm);
1268 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1269 ua->send_msg("%s\n", sdt);
1274 * reload the conf file
1276 extern "C" void reload_config(int sig);
1278 static int reload_cmd(UAContext *ua, const char *cmd)
1285 * Delete Pool records (should purge Media with it).
1287 * delete pool=<pool-name>
1288 * delete volume pool=<pool-name> volume=<name>
1291 static int delete_cmd(UAContext *ua, const char *cmd)
1293 static const char *keywords[] = {
1299 if (!open_client_db(ua)) {
1303 switch (find_arg_keyword(ua, keywords)) {
1312 while ((i=find_arg(ua, "jobid")) > 0) {
1314 *ua->argk[i] = 0; /* zap keyword already visited */
1322 "In general it is not a good idea to delete either a\n"
1323 "Pool or a Volume since they may contain data.\n\n"));
1325 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1336 ua->warning_msg(_("Nothing done.\n"));
1344 * delete_job has been modified to parse JobID lists like the
1346 * delete JobID=3,4,6,7-11,14
1348 * Thanks to Phil Stracchino for the above addition.
1351 static void delete_job(UAContext *ua)
1356 int i = find_arg_with_value(ua, NT_("jobid"));
1358 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1359 s = bstrdup(ua->argv[i]);
1362 * We could use strtok() here. But we're not going to, because:
1363 * (a) strtok() is deprecated, having been replaced by strsep();
1364 * (b) strtok() is broken in significant ways.
1365 * we could use strsep() instead, but it's not universally available.
1366 * so we grow our own using strchr().
1368 sep = strchr(tok, ',');
1369 while (sep != NULL) {
1371 if (strchr(tok, '-')) {
1372 delete_job_id_range(ua, tok);
1374 JobId = str_to_int64(tok);
1375 do_job_delete(ua, JobId);
1378 sep = strchr(tok, ',');
1380 /* pick up the last token */
1381 if (strchr(tok, '-')) {
1382 delete_job_id_range(ua, tok);
1384 JobId = str_to_int64(tok);
1385 do_job_delete(ua, JobId);
1390 JobId = str_to_int64(ua->argv[i]);
1391 do_job_delete(ua, JobId);
1393 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1396 JobId = ua->int64_val;
1397 do_job_delete(ua, JobId);
1402 * we call delete_job_id_range to parse range tokens and iterate over ranges
1404 static void delete_job_id_range(UAContext *ua, char *tok)
1409 tok2 = strchr(tok, '-');
1412 j1 = str_to_int64(tok);
1413 j2 = str_to_int64(tok2);
1414 for (j=j1; j<=j2; j++) {
1415 do_job_delete(ua, j);
1420 * do_job_delete now performs the actual delete operation atomically
1422 static void do_job_delete(UAContext *ua, JobId_t JobId)
1426 edit_int64(JobId, ed1);
1427 purge_jobs_from_catalog(ua, ed1);
1428 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1432 * Delete media records from database -- dangerous
1434 static int delete_volume(UAContext *ua)
1439 if (!select_media_dbr(ua, &mr)) {
1442 ua->warning_msg(_("\nThis command will delete volume %s\n"
1443 "and all Jobs saved on that volume from the Catalog\n"),
1446 if (find_arg(ua, "yes") >= 0) {
1447 ua->pint32_val = 1; /* Have "yes" on command line already" */
1449 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1451 if (!get_yesno(ua, buf)) {
1455 if (ua->pint32_val) {
1456 db_delete_media_record(ua->jcr, ua->db, &mr);
1462 * Delete a pool record from the database -- dangerous
1464 static int delete_pool(UAContext *ua)
1469 memset(&pr, 0, sizeof(pr));
1471 if (!get_pool_dbr(ua, &pr)) {
1474 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1476 if (!get_yesno(ua, buf)) {
1479 if (ua->pint32_val) {
1480 db_delete_pool_record(ua->jcr, ua->db, &pr);
1485 int memory_cmd(UAContext *ua, const char *cmd)
1487 list_dir_status_header(ua);
1488 sm_dump(false, true);
1492 static void do_mount_cmd(UAContext *ua, const char *command)
1497 char dev_name[MAX_NAME_LENGTH];
1501 if (!open_client_db(ua)) {
1504 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1506 store.store = get_storage_resource(ua, true/*arg is storage*/);
1510 pm_strcpy(store.store_source, _("unknown source"));
1511 set_wstorage(jcr, &store);
1512 drive = get_storage_drive(ua, store.store);
1513 if (strcmp(command, "mount") == 0) {
1514 slot = get_storage_slot(ua, store.store);
1517 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1518 store.store->media_type, store.store->dev_name(), drive);
1520 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1521 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1524 sd = jcr->store_bsock;
1525 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1526 bash_spaces(dev_name);
1528 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1530 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1532 while (bnet_recv(sd) >= 0) {
1533 ua->send_msg("%s", sd->msg);
1535 bnet_sig(sd, BNET_TERMINATE);
1537 jcr->store_bsock = NULL;
1541 * mount [storage=<name>] [drive=nn] [slot=mm]
1543 static int mount_cmd(UAContext *ua, const char *cmd)
1545 do_mount_cmd(ua, "mount"); /* mount */
1551 * unmount [storage=<name>] [drive=nn]
1553 static int unmount_cmd(UAContext *ua, const char *cmd)
1555 do_mount_cmd(ua, "unmount"); /* unmount */
1561 * release [storage=<name>] [drive=nn]
1563 static int release_cmd(UAContext *ua, const char *cmd)
1565 do_mount_cmd(ua, "release"); /* release */
1572 * use catalog=<name>
1574 static int use_cmd(UAContext *ua, const char *cmd)
1576 CAT *oldcatalog, *catalog;
1579 close_db(ua); /* close any previously open db */
1580 oldcatalog = ua->catalog;
1582 if (!(catalog = get_catalog_resource(ua))) {
1583 ua->catalog = oldcatalog;
1585 ua->catalog = catalog;
1588 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1589 ua->catalog->name(), ua->catalog->db_name);
1594 int quit_cmd(UAContext *ua, const char *cmd)
1600 /* Handler to get job status */
1601 static int status_handler(void *ctx, int num_fields, char **row)
1603 char *val = (char *)ctx;
1608 *val = '?'; /* Unknown by default */
1615 * Wait until no job is running
1617 int wait_cmd(UAContext *ua, const char *cmd)
1621 time_t stop_time = 0;
1625 * Wait until no job is running
1627 if (ua->argc == 1) {
1628 bmicrosleep(0, 200000); /* let job actually start */
1629 for (bool running=true; running; ) {
1632 if (jcr->JobId != 0) {
1646 i = find_arg_with_value(ua, NT_("timeout"));
1647 if (i > 0 && ua->argv[i]) {
1648 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1651 /* we have jobid, jobname or ujobid argument */
1653 uint32_t jobid = 0 ;
1655 if (!open_client_db(ua)) {
1656 ua->error_msg(_("ERR: Can't open db\n")) ;
1660 for (int i=1; i<ua->argc; i++) {
1661 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1665 jobid = str_to_int64(ua->argv[i]);
1667 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1668 strcasecmp(ua->argk[i], "job") == 0) {
1672 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1674 jobid = jcr->JobId ;
1678 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1682 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1684 jobid = jcr->JobId ;
1688 /* Wait for a mount request */
1689 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1690 for (bool waiting=false; !waiting; ) {
1692 if (jcr->JobId != 0 &&
1693 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1702 if (stop_time && (time(NULL) >= stop_time)) {
1703 ua->warning_msg(_("Wait on mount timed out\n"));
1713 ua->error_msg(_("ERR: Job was not found\n"));
1718 * We wait the end of a specific job
1721 bmicrosleep(0, 200000); /* let job actually start */
1722 for (bool running=true; running; ) {
1725 jcr=get_jcr_by_id(jobid) ;
1738 * We have to get JobStatus
1742 char jobstatus = '?'; /* Unknown by default */
1745 bsnprintf(buf, sizeof(buf),
1746 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1749 db_sql_query(ua->db, buf,
1750 status_handler, (void *)&jobstatus);
1752 switch (jobstatus) {
1754 status = 1 ; /* Warning */
1758 case JS_ErrorTerminated:
1760 status = 2 ; /* Critical */
1764 status = 0 ; /* Ok */
1768 status = 3 ; /* Unknown */
1772 ua->send_msg("JobId=%i\n", jobid) ;
1773 ua->send_msg("JobStatus=%s (%c)\n",
1774 job_status_to_str(jobstatus),
1777 if (ua->gui || ua->api) {
1778 ua->send_msg("ExitStatus=%i\n", status) ;
1785 static int help_cmd(UAContext *ua, const char *cmd)
1789 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1790 for (i=0; i<comsize; i++) {
1791 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1793 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1797 int qhelp_cmd(UAContext *ua, const char *cmd)
1801 for (i=0; i<comsize; i++) {
1802 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1808 static int version_cmd(UAContext *ua, const char *cmd)
1810 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1811 NPRTB(director->verid), HOST_OS, DISTNAME, DISTVER);
1816 * Test code -- turned on only for debug testing
1818 static int version_cmd(UAContext *ua, const char *cmd)
1821 POOL_MEM query(PM_MESSAGE);
1823 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1824 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1825 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1826 for (int i=0; i < ids.num_ids; i++) {
1827 ua->send_msg("id=%d\n", ids.DBId[i]);
1835 * This call explicitly checks for a catalog=xxx and
1836 * if given, opens that catalog. It also checks for
1837 * client=xxx and if found, opens the catalog
1838 * corresponding to that client. If we still don't
1839 * have a catalog, look for a Job keyword and get the
1840 * catalog from its client record.
1842 bool open_client_db(UAContext *ua)
1849 /* Try for catalog keyword */
1850 i = find_arg_with_value(ua, NT_("catalog"));
1852 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1853 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1856 catalog = GetCatalogResWithName(ua->argv[i]);
1858 if (ua->catalog && ua->catalog != catalog) {
1861 ua->catalog = catalog;
1866 /* Try for client keyword */
1867 i = find_arg_with_value(ua, NT_("client"));
1869 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1870 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1873 client = GetClientResWithName(ua->argv[i]);
1875 catalog = client->catalog;
1876 if (ua->catalog && ua->catalog != catalog) {
1879 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1880 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1883 ua->catalog = catalog;
1888 /* Try for Job keyword */
1889 i = find_arg_with_value(ua, NT_("job"));
1891 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1892 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1895 job = GetJobResWithName(ua->argv[i]);
1897 catalog = job->client->catalog;
1898 if (ua->catalog && ua->catalog != catalog) {
1901 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1902 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1905 ua->catalog = catalog;
1915 * Open the catalog database.
1917 bool open_db(UAContext *ua)
1923 ua->catalog = get_catalog_resource(ua);
1925 ua->error_msg( _("Could not find a Catalog resource\n"));
1930 ua->jcr->catalog = ua->catalog;
1932 Dmsg0(100, "UA Open database\n");
1933 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1934 ua->catalog->db_user,
1935 ua->catalog->db_password, ua->catalog->db_address,
1936 ua->catalog->db_port, ua->catalog->db_socket,
1937 ua->catalog->mult_db_connections);
1938 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1939 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1940 ua->catalog->db_name);
1942 ua->error_msg("%s", db_strerror(ua->db));
1947 ua->jcr->db = ua->db;
1949 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
1951 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1955 void close_db(UAContext *ua)
1958 db_close_database(ua->jcr, ua->db);