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
40 /* Imported subroutines */
42 /* Imported variables */
43 extern jobq_t job_queue; /* job queue */
46 /* Imported functions */
47 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
48 extern int gui_cmd(UAContext *ua, const char *cmd);
49 extern int label_cmd(UAContext *ua, const char *cmd);
50 extern int list_cmd(UAContext *ua, const char *cmd);
51 extern int llist_cmd(UAContext *ua, const char *cmd);
52 extern int messagescmd(UAContext *ua, const char *cmd);
53 extern int prunecmd(UAContext *ua, const char *cmd);
54 extern int purgecmd(UAContext *ua, const char *cmd);
55 extern int querycmd(UAContext *ua, const char *cmd);
56 extern int relabel_cmd(UAContext *ua, const char *cmd);
57 extern int restore_cmd(UAContext *ua, const char *cmd);
58 extern int retentioncmd(UAContext *ua, const char *cmd);
59 extern int show_cmd(UAContext *ua, const char *cmd);
60 extern int sqlquerycmd(UAContext *ua, const char *cmd);
61 extern int status_cmd(UAContext *ua, const char *cmd);
62 extern int update_cmd(UAContext *ua, const char *cmd);
64 /* Forward referenced functions */
65 static int add_cmd(UAContext *ua, const char *cmd);
66 static int automount_cmd(UAContext *ua, const char *cmd);
67 static int cancel_cmd(UAContext *ua, const char *cmd);
68 static int create_cmd(UAContext *ua, const char *cmd);
69 static int delete_cmd(UAContext *ua, const char *cmd);
70 static int disable_cmd(UAContext *ua, const char *cmd);
71 static int enable_cmd(UAContext *ua, const char *cmd);
72 static int estimate_cmd(UAContext *ua, const char *cmd);
73 static int help_cmd(UAContext *ua, const char *cmd);
74 static int memory_cmd(UAContext *ua, const char *cmd);
75 static int mount_cmd(UAContext *ua, const char *cmd);
76 static int python_cmd(UAContext *ua, const char *cmd);
77 static int release_cmd(UAContext *ua, const char *cmd);
78 static int reload_cmd(UAContext *ua, const char *cmd);
79 static int setdebug_cmd(UAContext *ua, const char *cmd);
80 static int setip_cmd(UAContext *ua, const char *cmd);
81 static int time_cmd(UAContext *ua, const char *cmd);
82 static int trace_cmd(UAContext *ua, const char *cmd);
83 static int unmount_cmd(UAContext *ua, const char *cmd);
84 static int use_cmd(UAContext *ua, const char *cmd);
85 static int var_cmd(UAContext *ua, const char *cmd);
86 static int version_cmd(UAContext *ua, const char *cmd);
87 static int wait_cmd(UAContext *ua, const char *cmd);
89 static void do_job_delete(UAContext *ua, JobId_t JobId);
90 static void delete_job_id_range(UAContext *ua, char *tok);
91 static int delete_volume(UAContext *ua);
92 static int delete_pool(UAContext *ua);
93 static void delete_job(UAContext *ua);
95 int qhelp_cmd(UAContext *ua, const char *cmd);
96 int quit_cmd(UAContext *ua, const char *cmd);
99 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; };
100 static struct cmdstruct commands[] = {
101 { NT_("add"), add_cmd, _("add media to a pool")},
102 { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages")},
103 { NT_("automount"), automount_cmd, _("automount [on|off] -- after label")},
104 { NT_("cancel"), cancel_cmd, _("cancel [<jobid=nnn> | <job=name>] -- cancel a job")},
105 { NT_("create"), create_cmd, _("create DB Pool from resource")},
106 { NT_("delete"), delete_cmd, _("delete [pool=<pool-name> | media volume=<volume-name>]")},
107 { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job")},
108 { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job")},
109 { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing")},
110 { NT_("exit"), quit_cmd, _("exit = quit")},
111 { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode")},
112 { NT_("help"), help_cmd, _("print this command")},
113 { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog")},
114 { NT_("label"), label_cmd, _("label a tape")},
115 { NT_("llist"), llist_cmd, _("full or long list like list command")},
116 { NT_("messages"), messagescmd, _("messages")},
117 { NT_("memory"), memory_cmd, _("print current memory usage")},
118 { NT_("mount"), mount_cmd, _("mount <storage-name>")},
119 { NT_("prune"), prunecmd, _("prune expired records from catalog")},
120 { NT_("purge"), purgecmd, _("purge records from catalog")},
121 { NT_("python"), python_cmd, _("python control commands")},
122 { NT_("quit"), quit_cmd, _("quit")},
123 { NT_("query"), querycmd, _("query catalog")},
124 { NT_("restore"), restore_cmd, _("restore files")},
125 { NT_("relabel"), relabel_cmd, _("relabel a tape")},
126 { NT_("release"), release_cmd, _("release <storage-name>")},
127 { NT_("reload"), reload_cmd, _("reload conf file")},
128 { NT_("run"), run_cmd, _("run <job-name>")},
129 { NT_("status"), status_cmd, _("status [storage | client]=<name>")},
130 { NT_("setdebug"), setdebug_cmd, _("sets debug level")},
131 { NT_("setip"), setip_cmd, _("sets new client address -- if authorized")},
132 { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]")},
133 { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")},
134 { NT_("time"), time_cmd, _("print current time")},
135 { NT_("trace"), trace_cmd, _("turn on/off trace to file")},
136 { NT_("unmount"), unmount_cmd, _("unmount <storage-name>")},
137 { NT_("umount"), unmount_cmd, _("umount <storage-name> for old-time Unix guys")},
138 { NT_("update"), update_cmd, _("update Volume, Pool or slots")},
139 { NT_("use"), use_cmd, _("use catalog xxx")},
140 { NT_("var"), var_cmd, _("does variable expansion")},
141 { NT_("version"), version_cmd, _("print Director version")},
142 { NT_("wait"), wait_cmd, _("wait until no jobs are running [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>]")},
144 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
147 * Execute a command from the UA
149 bool do_a_command(UAContext *ua)
155 BSOCK *user = ua->UA_sock;
158 Dmsg1(900, "Command: %s\n", ua->UA_sock->msg);
163 while (ua->jcr->wstorage->size()) {
164 ua->jcr->wstorage->remove(0);
167 len = strlen(ua->argk[0]);
168 for (i=0; i<comsize; i++) { /* search for command */
169 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
170 /* Check if command permitted, but "quit" is always OK */
171 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
172 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
175 if (ua->api) user->signal(BNET_CMD_BEGIN);
176 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
182 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
185 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
190 * This is a common routine used to stuff the Pool DB record defaults
191 * into the Media DB record just before creating a media (Volume)
194 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
196 mr->PoolId = pr->PoolId;
197 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
198 mr->Recycle = pr->Recycle;
199 mr->VolRetention = pr->VolRetention;
200 mr->VolUseDuration = pr->VolUseDuration;
201 mr->RecyclePoolId = pr->RecyclePoolId;
202 mr->MaxVolJobs = pr->MaxVolJobs;
203 mr->MaxVolFiles = pr->MaxVolFiles;
204 mr->MaxVolBytes = pr->MaxVolBytes;
205 mr->LabelType = pr->LabelType;
211 * Add Volumes to an existing Pool
213 static int add_cmd(UAContext *ua, const char *cmd)
217 int num, i, max, startnum;
219 char name[MAX_NAME_LENGTH];
221 int Slot = 0, InChanger = 0;
224 "You probably don't want to be using this command since it\n"
225 "creates database records without labeling the Volumes.\n"
226 "You probably want to use the \"label\" command.\n\n"));
228 if (!open_client_db(ua)) {
232 memset(&pr, 0, sizeof(pr));
233 memset(&mr, 0, sizeof(mr));
235 if (!get_pool_dbr(ua, &pr)) {
239 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
240 pr.MaxVols, pr.PoolType);
242 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
243 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
244 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
247 pr.MaxVols = ua->pint32_val;
251 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
252 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
253 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
257 if (pr.MaxVols == 0) {
260 max = pr.MaxVols - pr.NumVols;
264 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
265 if (!get_pint(ua, buf)) {
268 num = ua->pint32_val;
269 if (num < 0 || num > max) {
270 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
278 if (!get_cmd(ua, _("Enter Volume name: "))) {
282 if (!get_cmd(ua, _("Enter base volume name: "))) {
286 /* Don't allow | in Volume name because it is the volume separator character */
287 if (!is_volume_name_legal(ua, ua->cmd)) {
290 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
291 ua->warning_msg(_("Volume name too long.\n"));
294 if (strlen(ua->cmd) == 0) {
295 ua->warning_msg(_("Volume name must be at least one character long.\n"));
301 bstrncpy(name, ua->cmd, sizeof(name));
303 bstrncat(name, "%04d", sizeof(name));
306 if (!get_pint(ua, _("Enter the starting number: "))) {
309 startnum = ua->pint32_val;
311 ua->warning_msg(_("Start number must be greater than zero.\n"));
321 if (store && store->autochanger) {
322 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
325 Slot = ua->pint32_val;
326 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
329 InChanger = ua->pint32_val;
332 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
333 for (i=startnum; i < num+startnum; i++) {
334 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
336 mr.InChanger = InChanger;
337 mr.StorageId = store->StorageId;
339 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
340 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
341 ua->error_msg("%s", db_strerror(ua->db));
345 first_id = mr.PoolId;
349 Dmsg0(200, "Update pool record.\n");
350 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
351 ua->warning_msg("%s", db_strerror(ua->db));
354 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
360 * Turn auto mount on/off
365 int automount_cmd(UAContext *ua, const char *cmd)
370 if (!get_cmd(ua, _("Turn on or off? "))) {
378 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
386 static int cancel_cmd(UAContext *ua, const char *cmd)
391 char JobName[MAX_NAME_LENGTH];
393 for (i=1; i<ua->argc; i++) {
394 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
399 JobId = str_to_int64(ua->argv[i]);
400 if (!(jcr=get_jcr_by_id(JobId))) {
401 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
405 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
409 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
410 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
411 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
412 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
415 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
419 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
420 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
421 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
422 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
429 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
430 ua->error_msg(_("Unauthorized command from this console.\n"));
435 * If we still do not have a jcr,
436 * throw up a list and ask the user to select one.
439 int tjobs = 0; /* total # number jobs */
440 /* Count Jobs running */
442 if (jcr->JobId == 0) { /* this is us */
445 tjobs++; /* count of all jobs */
446 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
447 continue; /* skip not authorized */
449 njobs++; /* count of authorized jobs */
453 if (njobs == 0) { /* no authorized */
455 ua->send_msg(_("No Jobs running.\n"));
457 ua->send_msg(_("None of your jobs are running.\n"));
462 start_prompt(ua, _("Select Job:\n"));
465 if (jcr->JobId == 0) { /* this is us */
468 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
469 continue; /* skip not authorized */
471 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
476 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
479 if (ua->api && njobs == 1) {
481 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
482 _("Confirm cancel?"));
483 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
488 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
493 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
494 jcr = get_jcr_by_full_name(JobName);
496 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
501 ret = cancel_job(ua, jcr);
507 * This is a common routine to create or update a
508 * Pool DB base record from a Pool Resource. We handle
509 * the setting of MaxVols and NumVols slightly differently
510 * depending on if we are creating the Pool or we are
511 * simply bringing it into agreement with the resource (updage).
513 * Caution : RecyclePoolId isn't setup in this function.
514 * You can use set_pooldbr_recyclepoolid();
517 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
519 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
520 if (op == POOL_OP_CREATE) {
521 pr->MaxVols = pool->max_volumes;
523 } else { /* update pool */
524 if (pr->MaxVols != pool->max_volumes) {
525 pr->MaxVols = pool->max_volumes;
527 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
528 pr->MaxVols = pr->NumVols;
531 pr->LabelType = pool->LabelType;
532 pr->UseOnce = pool->use_volume_once;
533 pr->UseCatalog = pool->use_catalog;
534 pr->Recycle = pool->Recycle;
535 pr->VolRetention = pool->VolRetention;
536 pr->VolUseDuration = pool->VolUseDuration;
537 pr->MaxVolJobs = pool->MaxVolJobs;
538 pr->MaxVolFiles = pool->MaxVolFiles;
539 pr->MaxVolBytes = pool->MaxVolBytes;
540 pr->AutoPrune = pool->AutoPrune;
541 pr->Recycle = pool->Recycle;
542 if (pool->label_format) {
543 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
545 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
549 /* set/update Pool.RecyclePoolId in Catalog */
550 int update_pool_recyclepool(JCR *jcr, B_DB *db, POOL *pool)
554 if (!pool->RecyclePool) {
558 memset(&pr, 0, sizeof(POOL_DBR));
559 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
561 if (!db_get_pool_record(jcr, db, &pr)) {
562 return -1; /* not exists in database */
565 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
567 if (!set_pooldbr_recyclepoolid(jcr, db, &pr, pool)) {
568 return -1; /* error */
571 if (!db_update_pool_record(jcr, db, &pr)) {
572 return -1; /* error */
577 /* set POOL_DBR.RecyclePoolId from Pool resource
578 * works with set_pooldbr_from_poolres
580 bool set_pooldbr_recyclepoolid(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
585 if (pool->RecyclePool) {
586 memset(&rpool, 0, sizeof(POOL_DBR));
588 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
589 if (db_get_pool_record(jcr, db, &rpool)) {
590 pr->RecyclePoolId = rpool.PoolId;
592 Jmsg(jcr, M_WARNING, 0,
593 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
594 "Try to update it with 'update pool=%s'\n"),
595 pool->name(), rpool.Name, rpool.Name,pool->name());
599 } else { /* no RecyclePool used, set it to 0 */
600 pr->RecyclePoolId = 0;
607 * Create a pool record from a given Pool resource
608 * Also called from backup.c
609 * Returns: -1 on error
610 * 0 record already exists
614 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
618 memset(&pr, 0, sizeof(POOL_DBR));
620 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
622 if (db_get_pool_record(jcr, db, &pr)) {
624 if (op == POOL_OP_UPDATE) { /* update request */
625 set_pooldbr_from_poolres(&pr, pool, op);
626 db_update_pool_record(jcr, db, &pr);
628 return 0; /* exists */
631 set_pooldbr_from_poolres(&pr, pool, op);
633 if (!db_create_pool_record(jcr, db, &pr)) {
634 return -1; /* error */
642 * Create a Pool Record in the database.
643 * It is always created from the Resource record.
645 static int create_cmd(UAContext *ua, const char *cmd)
649 if (!open_client_db(ua)) {
653 pool = get_pool_resource(ua);
658 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
660 ua->error_msg(_("Error: Pool %s already exists.\n"
661 "Use update to change it.\n"), pool->name());
665 ua->error_msg("%s", db_strerror(ua->db));
671 ua->send_msg(_("Pool %s created.\n"), pool->name());
676 extern DIRRES *director;
679 * Python control command
680 * python restart (restarts interpreter)
682 static int python_cmd(UAContext *ua, const char *cmd)
684 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
685 term_python_interpreter();
686 init_python_interpreter(director->name(),
687 director->scripts_directory, "DirStartUp");
688 ua->send_msg(_("Python interpreter restarted.\n"));
690 ua->warning_msg(_("Nothing done.\n"));
697 * Set a new address in a Client resource. We do this only
698 * if the Console name is the same as the Client name
699 * and the Console can access the client.
701 static int setip_cmd(UAContext *ua, const char *cmd)
705 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
706 ua->error_msg(_("Unauthorized command from this console.\n"));
710 client = GetClientResWithName(ua->cons->name());
713 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
716 if (client->address) {
717 free(client->address);
719 /* MA Bug 6 remove ifdef */
720 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
721 client->address = bstrdup(buf);
722 ua->send_msg(_("Client \"%s\" address set to %s\n"),
723 client->name(), client->address);
730 static void do_en_disable_cmd(UAContext *ua, bool setting)
735 i = find_arg_with_value(ua, NT_("job"));
737 job = select_job_resource(ua);
743 job = GetJobResWithName(ua->argv[i]);
747 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
751 if (!acl_access_ok(ua, Job_ACL, job->name())) {
752 ua->error_msg(_("Unauthorized command from this console.\n"));
755 job->enabled = setting;
756 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
760 static int enable_cmd(UAContext *ua, const char *cmd)
762 do_en_disable_cmd(ua, true);
766 static int disable_cmd(UAContext *ua, const char *cmd)
768 do_en_disable_cmd(ua, false);
773 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
779 lstore.store = store;
780 pm_strcpy(lstore.store_source, _("unknown source"));
781 set_wstorage(jcr, &lstore);
782 /* Try connecting for up to 15 seconds */
783 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
784 store->name(), store->address, store->SDport);
785 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
786 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
789 Dmsg0(120, _("Connected to storage daemon\n"));
790 sd = jcr->store_bsock;
791 bnet_fsend(sd, "setdebug=%d trace=%d\n", level, trace_flag);
792 if (bnet_recv(sd) >= 0) {
793 ua->send_msg("%s", sd->msg);
795 bnet_sig(sd, BNET_TERMINATE);
797 jcr->store_bsock = NULL;
801 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
805 /* Connect to File daemon */
807 ua->jcr->client = client;
808 /* Try to connect for 15 seconds */
809 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
810 client->name(), client->address, client->FDport);
811 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
812 ua->error_msg(_("Failed to connect to Client.\n"));
815 Dmsg0(120, "Connected to file daemon\n");
816 fd = ua->jcr->file_bsock;
817 bnet_fsend(fd, "setdebug=%d trace=%d\n", level, trace_flag);
818 if (bnet_recv(fd) >= 0) {
819 ua->send_msg("%s", fd->msg);
821 bnet_sig(fd, BNET_TERMINATE);
823 ua->jcr->file_bsock = NULL;
828 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
830 STORE *store, **unique_store;
831 CLIENT *client, **unique_client;
837 /* Count Storage items */
841 foreach_res(store, R_STORAGE) {
844 unique_store = (STORE **) malloc(i * sizeof(STORE));
845 /* Find Unique Storage address/port */
846 store = (STORE *)GetNextRes(R_STORAGE, NULL);
848 unique_store[i++] = store;
849 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
851 for (j=0; j<i; j++) {
852 if (strcmp(unique_store[j]->address, store->address) == 0 &&
853 unique_store[j]->SDport == store->SDport) {
859 unique_store[i++] = store;
860 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
865 /* Call each unique Storage daemon */
866 for (j=0; j<i; j++) {
867 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
871 /* Count Client items */
875 foreach_res(client, R_CLIENT) {
878 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
879 /* Find Unique Client address/port */
880 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
882 unique_client[i++] = client;
883 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
885 for (j=0; j<i; j++) {
886 if (strcmp(unique_client[j]->address, client->address) == 0 &&
887 unique_client[j]->FDport == client->FDport) {
893 unique_client[i++] = client;
894 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
899 /* Call each unique File daemon */
900 for (j=0; j<i; j++) {
901 do_client_setdebug(ua, unique_client[j], level, trace_flag);
907 * setdebug level=nn all trace=1/0
909 static int setdebug_cmd(UAContext *ua, const char *cmd)
917 if (!open_client_db(ua)) {
920 Dmsg1(120, "setdebug:%s:\n", cmd);
923 i = find_arg_with_value(ua, "level");
925 level = atoi(ua->argv[i]);
928 if (!get_pint(ua, _("Enter new debug level: "))) {
931 level = ua->pint32_val;
934 /* Look for trace flag. -1 => not change */
935 i = find_arg_with_value(ua, "trace");
937 trace_flag = atoi(ua->argv[i]);
938 if (trace_flag > 0) {
944 for (i=1; i<ua->argc; i++) {
945 if (strcasecmp(ua->argk[i], "all") == 0) {
946 do_all_setdebug(ua, level, trace_flag);
949 if (strcasecmp(ua->argk[i], "dir") == 0 ||
950 strcasecmp(ua->argk[i], "director") == 0) {
952 set_trace(trace_flag);
955 if (strcasecmp(ua->argk[i], "client") == 0 ||
956 strcasecmp(ua->argk[i], "fd") == 0) {
959 client = GetClientResWithName(ua->argv[i]);
961 do_client_setdebug(ua, client, level, trace_flag);
965 client = select_client_resource(ua);
967 do_client_setdebug(ua, client, level, trace_flag);
972 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
973 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
974 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
977 store = GetStoreResWithName(ua->argv[i]);
979 do_storage_setdebug(ua, store, level, trace_flag);
983 store = get_storage_resource(ua, false/*no default*/);
985 do_storage_setdebug(ua, store, level, trace_flag);
991 * We didn't find an appropriate keyword above, so
994 start_prompt(ua, _("Available daemons are: \n"));
995 add_prompt(ua, _("Director"));
996 add_prompt(ua, _("Storage"));
997 add_prompt(ua, _("Client"));
998 add_prompt(ua, _("All"));
999 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1000 case 0: /* Director */
1001 debug_level = level;
1002 set_trace(trace_flag);
1005 store = get_storage_resource(ua, false/*no default*/);
1007 do_storage_setdebug(ua, store, level, trace_flag);
1011 client = select_client_resource(ua);
1013 do_client_setdebug(ua, client, level, trace_flag);
1017 do_all_setdebug(ua, level, trace_flag);
1026 * Turn debug tracing to file on/off
1028 static int trace_cmd(UAContext *ua, const char *cmd)
1032 if (ua->argc != 2) {
1033 if (!get_cmd(ua, _("Turn on or off? "))) {
1038 onoff = ua->argk[1];
1041 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1046 static int var_cmd(UAContext *ua, const char *cmd)
1048 POOLMEM *val = get_pool_memory(PM_FNAME);
1051 if (!open_client_db(ua)) {
1054 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1057 while (*var == ' ') { /* skip spaces */
1060 Dmsg1(100, "Var=%s:\n", var);
1061 variable_expansion(ua->jcr, var, &val);
1062 ua->send_msg("%s\n", val);
1063 free_pool_memory(val);
1067 static int estimate_cmd(UAContext *ua, const char *cmd)
1070 CLIENT *client = NULL;
1071 FILESET *fileset = NULL;
1073 char since[MAXSTRING];
1076 jcr->set_JobLevel(L_FULL);
1077 for (int i=1; i<ua->argc; i++) {
1078 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1079 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1081 client = GetClientResWithName(ua->argv[i]);
1083 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1088 ua->error_msg(_("Client name missing.\n"));
1092 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1094 job = GetJobResWithName(ua->argv[i]);
1096 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1099 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1100 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1105 ua->error_msg(_("Job name missing.\n"));
1110 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1112 fileset = GetFileSetResWithName(ua->argv[i]);
1114 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1117 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1118 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1123 ua->error_msg(_("Fileset name missing.\n"));
1127 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1131 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1133 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1134 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1138 ua->error_msg(_("Level value missing.\n"));
1143 if (!job && !(client && fileset)) {
1144 if (!(job = select_job_resource(ua))) {
1149 job = GetJobResWithName(ua->argk[1]);
1151 ua->error_msg(_("No job specified.\n"));
1154 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1155 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1160 client = job->client;
1163 fileset = job->fileset;
1165 jcr->client = client;
1166 jcr->fileset = fileset;
1168 if (job->pool->catalog) {
1169 ua->catalog = job->pool->catalog;
1171 ua->catalog = client->catalog;
1179 jcr->set_JobType(JT_BACKUP);
1180 init_jcr_job_record(jcr);
1182 if (!get_or_create_client_record(jcr)) {
1185 if (!get_or_create_fileset_record(jcr)) {
1189 get_level_since_time(ua->jcr, since, sizeof(since));
1191 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1192 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1193 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1194 ua->error_msg(_("Failed to connect to Client.\n"));
1198 if (!send_include_list(jcr)) {
1199 ua->error_msg(_("Error sending include list.\n"));
1203 if (!send_exclude_list(jcr)) {
1204 ua->error_msg(_("Error sending exclude list.\n"));
1208 if (!send_level_command(jcr)) {
1212 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1213 while (bnet_recv(jcr->file_bsock) >= 0) {
1214 ua->send_msg("%s", jcr->file_bsock->msg);
1218 if (jcr->file_bsock) {
1219 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1220 bnet_close(jcr->file_bsock);
1221 jcr->file_bsock = NULL;
1230 static int time_cmd(UAContext *ua, const char *cmd)
1233 time_t ttime = time(NULL);
1235 (void)localtime_r(&ttime, &tm);
1236 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1237 ua->send_msg("%s\n", sdt);
1242 * reload the conf file
1244 extern "C" void reload_config(int sig);
1246 static int reload_cmd(UAContext *ua, const char *cmd)
1253 * Delete Pool records (should purge Media with it).
1255 * delete pool=<pool-name>
1256 * delete volume pool=<pool-name> volume=<name>
1259 static int delete_cmd(UAContext *ua, const char *cmd)
1261 static const char *keywords[] = {
1267 if (!open_client_db(ua)) {
1271 switch (find_arg_keyword(ua, keywords)) {
1280 while ((i=find_arg(ua, "jobid")) > 0) {
1282 *ua->argk[i] = 0; /* zap keyword already visited */
1290 "In general it is not a good idea to delete either a\n"
1291 "Pool or a Volume since they may contain data.\n\n"));
1293 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1304 ua->warning_msg(_("Nothing done.\n"));
1312 * delete_job has been modified to parse JobID lists like the
1314 * delete JobID=3,4,6,7-11,14
1316 * Thanks to Phil Stracchino for the above addition.
1319 static void delete_job(UAContext *ua)
1324 int i = find_arg_with_value(ua, NT_("jobid"));
1326 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1327 s = bstrdup(ua->argv[i]);
1330 * We could use strtok() here. But we're not going to, because:
1331 * (a) strtok() is deprecated, having been replaced by strsep();
1332 * (b) strtok() is broken in significant ways.
1333 * we could use strsep() instead, but it's not universally available.
1334 * so we grow our own using strchr().
1336 sep = strchr(tok, ',');
1337 while (sep != NULL) {
1339 if (strchr(tok, '-')) {
1340 delete_job_id_range(ua, tok);
1342 JobId = str_to_int64(tok);
1343 do_job_delete(ua, JobId);
1346 sep = strchr(tok, ',');
1348 /* pick up the last token */
1349 if (strchr(tok, '-')) {
1350 delete_job_id_range(ua, tok);
1352 JobId = str_to_int64(tok);
1353 do_job_delete(ua, JobId);
1358 JobId = str_to_int64(ua->argv[i]);
1359 do_job_delete(ua, JobId);
1361 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1364 JobId = ua->int64_val;
1365 do_job_delete(ua, JobId);
1370 * we call delete_job_id_range to parse range tokens and iterate over ranges
1372 static void delete_job_id_range(UAContext *ua, char *tok)
1377 tok2 = strchr(tok, '-');
1380 j1 = str_to_int64(tok);
1381 j2 = str_to_int64(tok2);
1382 for (j=j1; j<=j2; j++) {
1383 do_job_delete(ua, j);
1388 * do_job_delete now performs the actual delete operation atomically
1390 static void do_job_delete(UAContext *ua, JobId_t JobId)
1394 edit_int64(JobId, ed1);
1395 purge_jobs_from_catalog(ua, ed1);
1396 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1400 * Delete media records from database -- dangerous
1402 static int delete_volume(UAContext *ua)
1407 if (!select_media_dbr(ua, &mr)) {
1410 ua->warning_msg(_("\nThis command will delete volume %s\n"
1411 "and all Jobs saved on that volume from the Catalog\n"),
1414 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1416 if (!get_yesno(ua, buf)) {
1419 if (ua->pint32_val) {
1420 db_delete_media_record(ua->jcr, ua->db, &mr);
1426 * Delete a pool record from the database -- dangerous
1428 static int delete_pool(UAContext *ua)
1433 memset(&pr, 0, sizeof(pr));
1435 if (!get_pool_dbr(ua, &pr)) {
1438 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1440 if (!get_yesno(ua, buf)) {
1443 if (ua->pint32_val) {
1444 db_delete_pool_record(ua->jcr, ua->db, &pr);
1449 int memory_cmd(UAContext *ua, const char *cmd)
1451 list_dir_status_header(ua);
1452 sm_dump(false, true);
1456 static void do_mount_cmd(UAContext *ua, const char *command)
1461 char dev_name[MAX_NAME_LENGTH];
1465 if (!open_client_db(ua)) {
1468 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1470 store.store = get_storage_resource(ua, true/*arg is storage*/);
1474 pm_strcpy(store.store_source, _("unknown source"));
1475 set_wstorage(jcr, &store);
1476 drive = get_storage_drive(ua, store.store);
1477 if (strcmp(command, "mount") == 0) {
1478 slot = get_storage_slot(ua, store.store);
1481 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1482 store.store->media_type, store.store->dev_name(), drive);
1484 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1485 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1488 sd = jcr->store_bsock;
1489 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1490 bash_spaces(dev_name);
1492 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1494 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1496 while (bnet_recv(sd) >= 0) {
1497 ua->send_msg("%s", sd->msg);
1499 bnet_sig(sd, BNET_TERMINATE);
1501 jcr->store_bsock = NULL;
1505 * mount [storage=<name>] [drive=nn] [slot=mm]
1507 static int mount_cmd(UAContext *ua, const char *cmd)
1509 do_mount_cmd(ua, "mount"); /* mount */
1515 * unmount [storage=<name>] [drive=nn]
1517 static int unmount_cmd(UAContext *ua, const char *cmd)
1519 do_mount_cmd(ua, "unmount"); /* unmount */
1525 * release [storage=<name>] [drive=nn]
1527 static int release_cmd(UAContext *ua, const char *cmd)
1529 do_mount_cmd(ua, "release"); /* release */
1536 * use catalog=<name>
1538 static int use_cmd(UAContext *ua, const char *cmd)
1540 CAT *oldcatalog, *catalog;
1543 close_db(ua); /* close any previously open db */
1544 oldcatalog = ua->catalog;
1546 if (!(catalog = get_catalog_resource(ua))) {
1547 ua->catalog = oldcatalog;
1549 ua->catalog = catalog;
1552 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1553 ua->catalog->name(), ua->catalog->db_name);
1558 int quit_cmd(UAContext *ua, const char *cmd)
1564 /* Handler to get job status */
1565 static int status_handler(void *ctx, int num_fields, char **row)
1567 char *val = (char *)ctx;
1572 *val = '?'; /* Unknown by default */
1579 * Wait until no job is running
1581 int wait_cmd(UAContext *ua, const char *cmd)
1585 time_t stop_time = 0;
1589 * Wait until no job is running
1591 if (ua->argc == 1) {
1592 bmicrosleep(0, 200000); /* let job actually start */
1593 for (bool running=true; running; ) {
1596 if (jcr->JobId != 0) {
1610 i = find_arg_with_value(ua, NT_("timeout"));
1611 if (i > 0 && ua->argv[i]) {
1612 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1615 /* we have jobid, jobname or ujobid argument */
1617 uint32_t jobid = 0 ;
1619 if (!open_client_db(ua)) {
1620 ua->error_msg(_("ERR: Can't open db\n")) ;
1624 for (int i=1; i<ua->argc; i++) {
1625 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1629 jobid = str_to_int64(ua->argv[i]);
1631 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1632 strcasecmp(ua->argk[i], "job") == 0) {
1636 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1638 jobid = jcr->JobId ;
1642 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1646 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1648 jobid = jcr->JobId ;
1652 /* Wait for a mount request */
1653 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1654 for (bool waiting=false; !waiting; ) {
1656 if (jcr->JobId != 0 &&
1657 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1666 if (stop_time && (time(NULL) >= stop_time)) {
1667 ua->warning_msg(_("Wait on mount timed out\n"));
1677 ua->error_msg(_("ERR: Job was not found\n"));
1682 * We wait the end of a specific job
1685 bmicrosleep(0, 200000); /* let job actually start */
1686 for (bool running=true; running; ) {
1689 jcr=get_jcr_by_id(jobid) ;
1702 * We have to get JobStatus
1706 char jobstatus = '?'; /* Unknown by default */
1709 bsnprintf(buf, sizeof(buf),
1710 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1713 db_sql_query(ua->db, buf,
1714 status_handler, (void *)&jobstatus);
1716 switch (jobstatus) {
1718 status = 1 ; /* Warning */
1722 case JS_ErrorTerminated:
1724 status = 2 ; /* Critical */
1728 status = 0 ; /* Ok */
1732 status = 3 ; /* Unknown */
1736 ua->send_msg("JobId=%i\n", jobid) ;
1737 ua->send_msg("JobStatus=%s (%c)\n",
1738 job_status_to_str(jobstatus),
1741 if (ua->gui || ua->api) {
1742 ua->send_msg("ExitStatus=%i\n", status) ;
1749 static int help_cmd(UAContext *ua, const char *cmd)
1753 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1754 for (i=0; i<comsize; i++) {
1755 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1757 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1761 int qhelp_cmd(UAContext *ua, const char *cmd)
1765 for (i=0; i<comsize; i++) {
1766 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1772 static int version_cmd(UAContext *ua, const char *cmd)
1774 ua->send_msg(_("%s Version: %s (%s) %s %s %s\n"), my_name, VERSION, BDATE,
1775 HOST_OS, DISTNAME, DISTVER);
1780 * Test code -- turned on only for debug testing
1782 static int version_cmd(UAContext *ua, const char *cmd)
1785 POOL_MEM query(PM_MESSAGE);
1787 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1788 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1789 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1790 for (int i=0; i < ids.num_ids; i++) {
1791 ua->send_msg("id=%d\n", ids.DBId[i]);
1799 * This call explicitly checks for a catalog=xxx and
1800 * if given, opens that catalog. It also checks for
1801 * client=xxx and if found, opens the catalog
1802 * corresponding to that client. If we still don't
1803 * have a catalog, look for a Job keyword and get the
1804 * catalog from its client record.
1806 bool open_client_db(UAContext *ua)
1813 /* Try for catalog keyword */
1814 i = find_arg_with_value(ua, NT_("catalog"));
1816 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1817 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1820 catalog = GetCatalogResWithName(ua->argv[i]);
1822 if (ua->catalog && ua->catalog != catalog) {
1825 ua->catalog = catalog;
1830 /* Try for client keyword */
1831 i = find_arg_with_value(ua, NT_("client"));
1833 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1834 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1837 client = GetClientResWithName(ua->argv[i]);
1839 catalog = client->catalog;
1840 if (ua->catalog && ua->catalog != catalog) {
1843 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1844 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1847 ua->catalog = catalog;
1852 /* Try for Job keyword */
1853 i = find_arg_with_value(ua, NT_("job"));
1855 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1856 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1859 job = GetJobResWithName(ua->argv[i]);
1861 catalog = job->client->catalog;
1862 if (ua->catalog && ua->catalog != catalog) {
1865 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1866 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1869 ua->catalog = catalog;
1879 * Open the catalog database.
1881 bool open_db(UAContext *ua)
1887 ua->catalog = get_catalog_resource(ua);
1889 ua->error_msg( _("Could not find a Catalog resource\n"));
1894 ua->jcr->catalog = ua->catalog;
1896 Dmsg0(100, "UA Open database\n");
1897 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1898 ua->catalog->db_user,
1899 ua->catalog->db_password, ua->catalog->db_address,
1900 ua->catalog->db_port, ua->catalog->db_socket,
1901 ua->catalog->mult_db_connections);
1902 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1903 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1904 ua->catalog->db_name);
1906 ua->error_msg("%s", db_strerror(ua->db));
1911 ua->jcr->db = ua->db;
1913 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
1915 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1919 void close_db(UAContext *ua)
1922 db_close_database(ua->jcr, ua->db);