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 and Pool.ScratchPoolId in Catalog */
569 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
573 if (!pool->RecyclePool && !pool->ScratchPool) {
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_references(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 and POOL_DBR.ScratchPoolId from Pool resource
597 * works with set_pooldbr_from_poolres
599 bool set_pooldbr_references(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;
622 if (pool->ScratchPool) {
623 memset(&rpool, 0, sizeof(POOL_DBR));
625 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
626 if (db_get_pool_record(jcr, db, &rpool)) {
627 pr->ScratchPoolId = rpool.PoolId;
629 Jmsg(jcr, M_WARNING, 0,
630 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
631 "Try to update it with 'update pool=%s'\n"),
632 pool->name(), rpool.Name, rpool.Name,pool->name());
635 } else { /* no ScratchPool used, set it to 0 */
636 pr->ScratchPoolId = 0;
644 * Create a pool record from a given Pool resource
645 * Also called from backup.c
646 * Returns: -1 on error
647 * 0 record already exists
651 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
655 memset(&pr, 0, sizeof(POOL_DBR));
657 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
659 if (db_get_pool_record(jcr, db, &pr)) {
661 if (op == POOL_OP_UPDATE) { /* update request */
662 set_pooldbr_from_poolres(&pr, pool, op);
663 set_pooldbr_references(jcr, db, &pr, pool);
664 db_update_pool_record(jcr, db, &pr);
666 return 0; /* exists */
669 set_pooldbr_from_poolres(&pr, pool, op);
670 set_pooldbr_references(jcr, db, &pr, pool);
672 if (!db_create_pool_record(jcr, db, &pr)) {
673 return -1; /* error */
681 * Create a Pool Record in the database.
682 * It is always created from the Resource record.
684 static int create_cmd(UAContext *ua, const char *cmd)
688 if (!open_client_db(ua)) {
692 pool = get_pool_resource(ua);
697 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
699 ua->error_msg(_("Error: Pool %s already exists.\n"
700 "Use update to change it.\n"), pool->name());
704 ua->error_msg("%s", db_strerror(ua->db));
710 ua->send_msg(_("Pool %s created.\n"), pool->name());
715 extern DIRRES *director;
716 extern char *configfile;
719 * Python control command
720 * python restart (restarts interpreter)
722 static int python_cmd(UAContext *ua, const char *cmd)
725 init_python_interpreter_args python_args;
727 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
728 term_python_interpreter();
730 python_args.progname = director->name();
731 python_args.scriptdir = director->scripts_directory;
732 python_args.modulename = "DirStartUp";
733 python_args.configfile = configfile;
734 python_args.workingdir = director->working_directory;
735 python_args.job_getattr = job_getattr;
736 python_args.job_setattr = job_setattr;
738 init_python_interpreter(&python_args);
740 ua->send_msg(_("Python interpreter restarted.\n"));
742 #endif /* HAVE_PYTHON */
743 ua->warning_msg(_("Nothing done.\n"));
746 #endif /* HAVE_PYTHON */
752 * Set a new address in a Client resource. We do this only
753 * if the Console name is the same as the Client name
754 * and the Console can access the client.
756 static int setip_cmd(UAContext *ua, const char *cmd)
760 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
761 ua->error_msg(_("Unauthorized command from this console.\n"));
765 client = GetClientResWithName(ua->cons->name());
768 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
771 if (client->address) {
772 free(client->address);
774 /* MA Bug 6 remove ifdef */
775 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
776 client->address = bstrdup(buf);
777 ua->send_msg(_("Client \"%s\" address set to %s\n"),
778 client->name(), client->address);
785 static void do_en_disable_cmd(UAContext *ua, bool setting)
790 i = find_arg_with_value(ua, NT_("job"));
792 job = select_job_resource(ua);
798 job = GetJobResWithName(ua->argv[i]);
802 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
806 if (!acl_access_ok(ua, Job_ACL, job->name())) {
807 ua->error_msg(_("Unauthorized command from this console.\n"));
810 job->enabled = setting;
811 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
815 static int enable_cmd(UAContext *ua, const char *cmd)
817 do_en_disable_cmd(ua, true);
821 static int disable_cmd(UAContext *ua, const char *cmd)
823 do_en_disable_cmd(ua, false);
828 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
834 lstore.store = store;
835 pm_strcpy(lstore.store_source, _("unknown source"));
836 set_wstorage(jcr, &lstore);
837 /* Try connecting for up to 15 seconds */
838 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
839 store->name(), store->address, store->SDport);
840 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
841 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
844 Dmsg0(120, _("Connected to storage daemon\n"));
845 sd = jcr->store_bsock;
846 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
847 if (sd->recv() >= 0) {
848 ua->send_msg("%s", sd->msg);
850 sd->signal(BNET_TERMINATE);
852 jcr->store_bsock = NULL;
856 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
860 /* Connect to File daemon */
862 ua->jcr->client = client;
863 /* Try to connect for 15 seconds */
864 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
865 client->name(), client->address, client->FDport);
866 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
867 ua->error_msg(_("Failed to connect to Client.\n"));
870 Dmsg0(120, "Connected to file daemon\n");
871 fd = ua->jcr->file_bsock;
872 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
873 if (fd->recv() >= 0) {
874 ua->send_msg("%s", fd->msg);
876 fd->signal(BNET_TERMINATE);
878 ua->jcr->file_bsock = NULL;
883 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
885 STORE *store, **unique_store;
886 CLIENT *client, **unique_client;
892 /* Count Storage items */
896 foreach_res(store, R_STORAGE) {
899 unique_store = (STORE **) malloc(i * sizeof(STORE));
900 /* Find Unique Storage address/port */
901 store = (STORE *)GetNextRes(R_STORAGE, NULL);
903 unique_store[i++] = store;
904 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
906 for (j=0; j<i; j++) {
907 if (strcmp(unique_store[j]->address, store->address) == 0 &&
908 unique_store[j]->SDport == store->SDport) {
914 unique_store[i++] = store;
915 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
920 /* Call each unique Storage daemon */
921 for (j=0; j<i; j++) {
922 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
926 /* Count Client items */
930 foreach_res(client, R_CLIENT) {
933 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
934 /* Find Unique Client address/port */
935 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
937 unique_client[i++] = client;
938 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
940 for (j=0; j<i; j++) {
941 if (strcmp(unique_client[j]->address, client->address) == 0 &&
942 unique_client[j]->FDport == client->FDport) {
948 unique_client[i++] = client;
949 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
954 /* Call each unique File daemon */
955 for (j=0; j<i; j++) {
956 do_client_setdebug(ua, unique_client[j], level, trace_flag);
962 * setdebug level=nn all trace=1/0
964 static int setdebug_cmd(UAContext *ua, const char *cmd)
972 Dmsg1(120, "setdebug:%s:\n", cmd);
975 i = find_arg_with_value(ua, "level");
977 level = atoi(ua->argv[i]);
980 if (!get_pint(ua, _("Enter new debug level: "))) {
983 level = ua->pint32_val;
986 /* Look for trace flag. -1 => not change */
987 i = find_arg_with_value(ua, "trace");
989 trace_flag = atoi(ua->argv[i]);
990 if (trace_flag > 0) {
996 for (i=1; i<ua->argc; i++) {
997 if (strcasecmp(ua->argk[i], "all") == 0) {
998 do_all_setdebug(ua, level, trace_flag);
1001 if (strcasecmp(ua->argk[i], "dir") == 0 ||
1002 strcasecmp(ua->argk[i], "director") == 0) {
1003 debug_level = level;
1004 set_trace(trace_flag);
1007 if (strcasecmp(ua->argk[i], "client") == 0 ||
1008 strcasecmp(ua->argk[i], "fd") == 0) {
1011 client = GetClientResWithName(ua->argv[i]);
1013 do_client_setdebug(ua, client, level, trace_flag);
1017 client = select_client_resource(ua);
1019 do_client_setdebug(ua, client, level, trace_flag);
1024 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1025 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1026 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1029 store = GetStoreResWithName(ua->argv[i]);
1031 do_storage_setdebug(ua, store, level, trace_flag);
1035 store = get_storage_resource(ua, false/*no default*/);
1037 do_storage_setdebug(ua, store, level, trace_flag);
1043 * We didn't find an appropriate keyword above, so
1046 start_prompt(ua, _("Available daemons are: \n"));
1047 add_prompt(ua, _("Director"));
1048 add_prompt(ua, _("Storage"));
1049 add_prompt(ua, _("Client"));
1050 add_prompt(ua, _("All"));
1051 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1052 case 0: /* Director */
1053 debug_level = level;
1054 set_trace(trace_flag);
1057 store = get_storage_resource(ua, false/*no default*/);
1059 do_storage_setdebug(ua, store, level, trace_flag);
1063 client = select_client_resource(ua);
1065 do_client_setdebug(ua, client, level, trace_flag);
1069 do_all_setdebug(ua, level, trace_flag);
1078 * Turn debug tracing to file on/off
1080 static int trace_cmd(UAContext *ua, const char *cmd)
1084 if (ua->argc != 2) {
1085 if (!get_cmd(ua, _("Turn on or off? "))) {
1090 onoff = ua->argk[1];
1093 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1098 static int var_cmd(UAContext *ua, const char *cmd)
1100 POOLMEM *val = get_pool_memory(PM_FNAME);
1103 if (!open_client_db(ua)) {
1106 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1109 while (*var == ' ') { /* skip spaces */
1112 Dmsg1(100, "Var=%s:\n", var);
1113 variable_expansion(ua->jcr, var, &val);
1114 ua->send_msg("%s\n", val);
1115 free_pool_memory(val);
1119 static int estimate_cmd(UAContext *ua, const char *cmd)
1122 CLIENT *client = NULL;
1123 FILESET *fileset = NULL;
1125 char since[MAXSTRING];
1128 jcr->set_JobLevel(L_FULL);
1129 for (int i=1; i<ua->argc; i++) {
1130 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1131 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1133 client = GetClientResWithName(ua->argv[i]);
1135 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1140 ua->error_msg(_("Client name missing.\n"));
1144 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1146 job = GetJobResWithName(ua->argv[i]);
1148 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1151 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1152 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1157 ua->error_msg(_("Job name missing.\n"));
1162 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1164 fileset = GetFileSetResWithName(ua->argv[i]);
1166 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1169 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1170 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1175 ua->error_msg(_("Fileset name missing.\n"));
1179 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1183 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1185 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1186 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1190 ua->error_msg(_("Level value missing.\n"));
1195 if (!job && !(client && fileset)) {
1196 if (!(job = select_job_resource(ua))) {
1201 job = GetJobResWithName(ua->argk[1]);
1203 ua->error_msg(_("No job specified.\n"));
1206 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1207 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1212 client = job->client;
1215 fileset = job->fileset;
1217 jcr->client = client;
1218 jcr->fileset = fileset;
1220 if (job->pool->catalog) {
1221 ua->catalog = job->pool->catalog;
1223 ua->catalog = client->catalog;
1231 jcr->set_JobType(JT_BACKUP);
1232 init_jcr_job_record(jcr);
1234 if (!get_or_create_client_record(jcr)) {
1237 if (!get_or_create_fileset_record(jcr)) {
1241 get_level_since_time(ua->jcr, since, sizeof(since));
1243 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1244 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1245 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1246 ua->error_msg(_("Failed to connect to Client.\n"));
1250 if (!send_include_list(jcr)) {
1251 ua->error_msg(_("Error sending include list.\n"));
1255 if (!send_exclude_list(jcr)) {
1256 ua->error_msg(_("Error sending exclude list.\n"));
1260 if (!send_level_command(jcr)) {
1264 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1265 while (bnet_recv(jcr->file_bsock) >= 0) {
1266 ua->send_msg("%s", jcr->file_bsock->msg);
1270 if (jcr->file_bsock) {
1271 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1272 bnet_close(jcr->file_bsock);
1273 jcr->file_bsock = NULL;
1282 static int time_cmd(UAContext *ua, const char *cmd)
1285 time_t ttime = time(NULL);
1287 (void)localtime_r(&ttime, &tm);
1288 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1289 ua->send_msg("%s\n", sdt);
1294 * reload the conf file
1296 extern "C" void reload_config(int sig);
1298 static int reload_cmd(UAContext *ua, const char *cmd)
1305 * Delete Pool records (should purge Media with it).
1307 * delete pool=<pool-name>
1308 * delete volume pool=<pool-name> volume=<name>
1311 static int delete_cmd(UAContext *ua, const char *cmd)
1313 static const char *keywords[] = {
1319 if (!open_client_db(ua)) {
1323 switch (find_arg_keyword(ua, keywords)) {
1332 while ((i=find_arg(ua, "jobid")) > 0) {
1334 *ua->argk[i] = 0; /* zap keyword already visited */
1342 "In general it is not a good idea to delete either a\n"
1343 "Pool or a Volume since they may contain data.\n\n"));
1345 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1356 ua->warning_msg(_("Nothing done.\n"));
1364 * delete_job has been modified to parse JobID lists like the
1366 * delete JobID=3,4,6,7-11,14
1368 * Thanks to Phil Stracchino for the above addition.
1371 static void delete_job(UAContext *ua)
1376 int i = find_arg_with_value(ua, NT_("jobid"));
1378 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1379 s = bstrdup(ua->argv[i]);
1382 * We could use strtok() here. But we're not going to, because:
1383 * (a) strtok() is deprecated, having been replaced by strsep();
1384 * (b) strtok() is broken in significant ways.
1385 * we could use strsep() instead, but it's not universally available.
1386 * so we grow our own using strchr().
1388 sep = strchr(tok, ',');
1389 while (sep != NULL) {
1391 if (strchr(tok, '-')) {
1392 delete_job_id_range(ua, tok);
1394 JobId = str_to_int64(tok);
1395 do_job_delete(ua, JobId);
1398 sep = strchr(tok, ',');
1400 /* pick up the last token */
1401 if (strchr(tok, '-')) {
1402 delete_job_id_range(ua, tok);
1404 JobId = str_to_int64(tok);
1405 do_job_delete(ua, JobId);
1410 JobId = str_to_int64(ua->argv[i]);
1411 do_job_delete(ua, JobId);
1413 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1416 JobId = ua->int64_val;
1417 do_job_delete(ua, JobId);
1422 * we call delete_job_id_range to parse range tokens and iterate over ranges
1424 static void delete_job_id_range(UAContext *ua, char *tok)
1429 tok2 = strchr(tok, '-');
1432 j1 = str_to_int64(tok);
1433 j2 = str_to_int64(tok2);
1434 for (j=j1; j<=j2; j++) {
1435 do_job_delete(ua, j);
1440 * do_job_delete now performs the actual delete operation atomically
1442 static void do_job_delete(UAContext *ua, JobId_t JobId)
1446 edit_int64(JobId, ed1);
1447 purge_jobs_from_catalog(ua, ed1);
1448 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1452 * Delete media records from database -- dangerous
1454 static int delete_volume(UAContext *ua)
1459 if (!select_media_dbr(ua, &mr)) {
1462 ua->warning_msg(_("\nThis command will delete volume %s\n"
1463 "and all Jobs saved on that volume from the Catalog\n"),
1466 if (find_arg(ua, "yes") >= 0) {
1467 ua->pint32_val = 1; /* Have "yes" on command line already" */
1469 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1471 if (!get_yesno(ua, buf)) {
1475 if (ua->pint32_val) {
1476 db_delete_media_record(ua->jcr, ua->db, &mr);
1482 * Delete a pool record from the database -- dangerous
1484 static int delete_pool(UAContext *ua)
1489 memset(&pr, 0, sizeof(pr));
1491 if (!get_pool_dbr(ua, &pr)) {
1494 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1496 if (!get_yesno(ua, buf)) {
1499 if (ua->pint32_val) {
1500 db_delete_pool_record(ua->jcr, ua->db, &pr);
1505 int memory_cmd(UAContext *ua, const char *cmd)
1507 list_dir_status_header(ua);
1508 sm_dump(false, true);
1512 static void do_mount_cmd(UAContext *ua, const char *command)
1517 char dev_name[MAX_NAME_LENGTH];
1521 if (!open_client_db(ua)) {
1524 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1526 store.store = get_storage_resource(ua, true/*arg is storage*/);
1530 pm_strcpy(store.store_source, _("unknown source"));
1531 set_wstorage(jcr, &store);
1532 drive = get_storage_drive(ua, store.store);
1533 if (strcmp(command, "mount") == 0) {
1534 slot = get_storage_slot(ua, store.store);
1537 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1538 store.store->media_type, store.store->dev_name(), drive);
1540 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1541 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1544 sd = jcr->store_bsock;
1545 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1546 bash_spaces(dev_name);
1548 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1550 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1552 while (bnet_recv(sd) >= 0) {
1553 ua->send_msg("%s", sd->msg);
1555 bnet_sig(sd, BNET_TERMINATE);
1557 jcr->store_bsock = NULL;
1561 * mount [storage=<name>] [drive=nn] [slot=mm]
1563 static int mount_cmd(UAContext *ua, const char *cmd)
1565 do_mount_cmd(ua, "mount"); /* mount */
1571 * unmount [storage=<name>] [drive=nn]
1573 static int unmount_cmd(UAContext *ua, const char *cmd)
1575 do_mount_cmd(ua, "unmount"); /* unmount */
1581 * release [storage=<name>] [drive=nn]
1583 static int release_cmd(UAContext *ua, const char *cmd)
1585 do_mount_cmd(ua, "release"); /* release */
1592 * use catalog=<name>
1594 static int use_cmd(UAContext *ua, const char *cmd)
1596 CAT *oldcatalog, *catalog;
1599 close_db(ua); /* close any previously open db */
1600 oldcatalog = ua->catalog;
1602 if (!(catalog = get_catalog_resource(ua))) {
1603 ua->catalog = oldcatalog;
1605 ua->catalog = catalog;
1608 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1609 ua->catalog->name(), ua->catalog->db_name);
1614 int quit_cmd(UAContext *ua, const char *cmd)
1620 /* Handler to get job status */
1621 static int status_handler(void *ctx, int num_fields, char **row)
1623 char *val = (char *)ctx;
1628 *val = '?'; /* Unknown by default */
1635 * Wait until no job is running
1637 int wait_cmd(UAContext *ua, const char *cmd)
1641 time_t stop_time = 0;
1645 * Wait until no job is running
1647 if (ua->argc == 1) {
1648 bmicrosleep(0, 200000); /* let job actually start */
1649 for (bool running=true; running; ) {
1652 if (jcr->JobId != 0) {
1666 i = find_arg_with_value(ua, NT_("timeout"));
1667 if (i > 0 && ua->argv[i]) {
1668 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1671 /* we have jobid, jobname or ujobid argument */
1673 uint32_t jobid = 0 ;
1675 if (!open_client_db(ua)) {
1676 ua->error_msg(_("ERR: Can't open db\n")) ;
1680 for (int i=1; i<ua->argc; i++) {
1681 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1685 jobid = str_to_int64(ua->argv[i]);
1687 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1688 strcasecmp(ua->argk[i], "job") == 0) {
1692 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1694 jobid = jcr->JobId ;
1698 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1702 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1704 jobid = jcr->JobId ;
1708 /* Wait for a mount request */
1709 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1710 for (bool waiting=false; !waiting; ) {
1712 if (jcr->JobId != 0 &&
1713 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1722 if (stop_time && (time(NULL) >= stop_time)) {
1723 ua->warning_msg(_("Wait on mount timed out\n"));
1733 ua->error_msg(_("ERR: Job was not found\n"));
1738 * We wait the end of a specific job
1741 bmicrosleep(0, 200000); /* let job actually start */
1742 for (bool running=true; running; ) {
1745 jcr=get_jcr_by_id(jobid) ;
1758 * We have to get JobStatus
1762 char jobstatus = '?'; /* Unknown by default */
1765 bsnprintf(buf, sizeof(buf),
1766 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1769 db_sql_query(ua->db, buf,
1770 status_handler, (void *)&jobstatus);
1772 switch (jobstatus) {
1774 status = 1 ; /* Warning */
1778 case JS_ErrorTerminated:
1780 status = 2 ; /* Critical */
1784 status = 0 ; /* Ok */
1788 status = 3 ; /* Unknown */
1792 ua->send_msg("JobId=%i\n", jobid) ;
1793 ua->send_msg("JobStatus=%s (%c)\n",
1794 job_status_to_str(jobstatus),
1797 if (ua->gui || ua->api) {
1798 ua->send_msg("ExitStatus=%i\n", status) ;
1805 static int help_cmd(UAContext *ua, const char *cmd)
1809 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1810 for (i=0; i<comsize; i++) {
1811 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1813 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1817 int qhelp_cmd(UAContext *ua, const char *cmd)
1821 for (i=0; i<comsize; i++) {
1822 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1828 static int version_cmd(UAContext *ua, const char *cmd)
1830 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1831 NPRTB(director->verid), HOST_OS, DISTNAME, DISTVER);
1836 * Test code -- turned on only for debug testing
1838 static int version_cmd(UAContext *ua, const char *cmd)
1841 POOL_MEM query(PM_MESSAGE);
1843 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1844 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1845 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1846 for (int i=0; i < ids.num_ids; i++) {
1847 ua->send_msg("id=%d\n", ids.DBId[i]);
1855 * This call explicitly checks for a catalog=xxx and
1856 * if given, opens that catalog. It also checks for
1857 * client=xxx and if found, opens the catalog
1858 * corresponding to that client. If we still don't
1859 * have a catalog, look for a Job keyword and get the
1860 * catalog from its client record.
1862 bool open_client_db(UAContext *ua)
1869 /* Try for catalog keyword */
1870 i = find_arg_with_value(ua, NT_("catalog"));
1872 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1873 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1876 catalog = GetCatalogResWithName(ua->argv[i]);
1878 if (ua->catalog && ua->catalog != catalog) {
1881 ua->catalog = catalog;
1886 /* Try for client keyword */
1887 i = find_arg_with_value(ua, NT_("client"));
1889 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1890 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1893 client = GetClientResWithName(ua->argv[i]);
1895 catalog = client->catalog;
1896 if (ua->catalog && ua->catalog != catalog) {
1899 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1900 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1903 ua->catalog = catalog;
1908 /* Try for Job keyword */
1909 i = find_arg_with_value(ua, NT_("job"));
1911 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1912 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1915 job = GetJobResWithName(ua->argv[i]);
1917 catalog = job->client->catalog;
1918 if (ua->catalog && ua->catalog != catalog) {
1921 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1922 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1925 ua->catalog = catalog;
1935 * Open the catalog database.
1937 bool open_db(UAContext *ua)
1943 ua->catalog = get_catalog_resource(ua);
1945 ua->error_msg( _("Could not find a Catalog resource\n"));
1950 ua->jcr->catalog = ua->catalog;
1952 Dmsg0(100, "UA Open database\n");
1953 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1954 ua->catalog->db_user,
1955 ua->catalog->db_password, ua->catalog->db_address,
1956 ua->catalog->db_port, ua->catalog->db_socket,
1957 ua->catalog->mult_db_connections);
1958 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1959 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1960 ua->catalog->db_name);
1962 ua->error_msg("%s", db_strerror(ua->db));
1967 ua->jcr->db = ua->db;
1969 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
1971 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1975 void close_db(UAContext *ua)
1978 db_close_database(ua->jcr, ua->db);