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->argk[0]);
164 while (ua->jcr->wstorage->size()) {
165 ua->jcr->wstorage->remove(0);
169 len = strlen(ua->argk[0]);
170 for (i=0; i<comsize; i++) { /* search for command */
171 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
172 /* Check if command permitted, but "quit" is always OK */
173 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
174 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
177 if (ua->api) user->signal(BNET_CMD_BEGIN);
178 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
184 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
187 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
192 * This is a common routine used to stuff the Pool DB record defaults
193 * into the Media DB record just before creating a media (Volume)
196 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
198 mr->PoolId = pr->PoolId;
199 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
200 mr->Recycle = pr->Recycle;
201 mr->VolRetention = pr->VolRetention;
202 mr->VolUseDuration = pr->VolUseDuration;
203 mr->RecyclePoolId = pr->RecyclePoolId;
204 mr->MaxVolJobs = pr->MaxVolJobs;
205 mr->MaxVolFiles = pr->MaxVolFiles;
206 mr->MaxVolBytes = pr->MaxVolBytes;
207 mr->LabelType = pr->LabelType;
213 * Add Volumes to an existing Pool
215 static int add_cmd(UAContext *ua, const char *cmd)
219 int num, i, max, startnum;
221 char name[MAX_NAME_LENGTH];
223 int Slot = 0, InChanger = 0;
226 "You probably don't want to be using this command since it\n"
227 "creates database records without labeling the Volumes.\n"
228 "You probably want to use the \"label\" command.\n\n"));
230 if (!open_client_db(ua)) {
234 memset(&pr, 0, sizeof(pr));
235 memset(&mr, 0, sizeof(mr));
237 if (!get_pool_dbr(ua, &pr)) {
241 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
242 pr.MaxVols, pr.PoolType);
244 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
245 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
246 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
249 pr.MaxVols = ua->pint32_val;
253 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
254 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
255 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
259 if (pr.MaxVols == 0) {
262 max = pr.MaxVols - pr.NumVols;
266 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
267 if (!get_pint(ua, buf)) {
270 num = ua->pint32_val;
271 if (num < 0 || num > max) {
272 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
280 if (!get_cmd(ua, _("Enter Volume name: "))) {
284 if (!get_cmd(ua, _("Enter base volume name: "))) {
288 /* Don't allow | in Volume name because it is the volume separator character */
289 if (!is_volume_name_legal(ua, ua->cmd)) {
292 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
293 ua->warning_msg(_("Volume name too long.\n"));
296 if (strlen(ua->cmd) == 0) {
297 ua->warning_msg(_("Volume name must be at least one character long.\n"));
303 bstrncpy(name, ua->cmd, sizeof(name));
305 bstrncat(name, "%04d", sizeof(name));
308 if (!get_pint(ua, _("Enter the starting number: "))) {
311 startnum = ua->pint32_val;
313 ua->warning_msg(_("Start number must be greater than zero.\n"));
323 if (store && store->autochanger) {
324 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
327 Slot = ua->pint32_val;
328 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
331 InChanger = ua->pint32_val;
334 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
335 for (i=startnum; i < num+startnum; i++) {
336 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
338 mr.InChanger = InChanger;
339 mr.StorageId = store->StorageId;
341 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
342 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
343 ua->error_msg("%s", db_strerror(ua->db));
347 first_id = mr.PoolId;
351 Dmsg0(200, "Update pool record.\n");
352 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
353 ua->warning_msg("%s", db_strerror(ua->db));
356 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
362 * Turn auto mount on/off
367 int automount_cmd(UAContext *ua, const char *cmd)
372 if (!get_cmd(ua, _("Turn on or off? "))) {
380 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
388 static int cancel_cmd(UAContext *ua, const char *cmd)
393 char JobName[MAX_NAME_LENGTH];
395 for (i=1; i<ua->argc; i++) {
396 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
401 JobId = str_to_int64(ua->argv[i]);
402 if (!(jcr=get_jcr_by_id(JobId))) {
403 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
407 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
411 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
412 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
413 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
414 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
417 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
421 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
422 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
423 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
424 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
431 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
432 ua->error_msg(_("Unauthorized command from this console.\n"));
437 * If we still do not have a jcr,
438 * throw up a list and ask the user to select one.
441 int tjobs = 0; /* total # number jobs */
442 /* Count Jobs running */
444 if (jcr->JobId == 0) { /* this is us */
447 tjobs++; /* count of all jobs */
448 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
449 continue; /* skip not authorized */
451 njobs++; /* count of authorized jobs */
455 if (njobs == 0) { /* no authorized */
457 ua->send_msg(_("No Jobs running.\n"));
459 ua->send_msg(_("None of your jobs are running.\n"));
464 start_prompt(ua, _("Select Job:\n"));
467 if (jcr->JobId == 0) { /* this is us */
470 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
471 continue; /* skip not authorized */
473 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
478 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
481 if (ua->api && njobs == 1) {
483 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
484 _("Confirm cancel?"));
485 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
490 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
495 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
496 jcr = get_jcr_by_full_name(JobName);
498 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
503 ret = cancel_job(ua, jcr);
509 * This is a common routine to create or update a
510 * Pool DB base record from a Pool Resource. We handle
511 * the setting of MaxVols and NumVols slightly differently
512 * depending on if we are creating the Pool or we are
513 * simply bringing it into agreement with the resource (updage).
515 * Caution : RecyclePoolId isn't setup in this function.
516 * You can use set_pooldbr_recyclepoolid();
519 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
521 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
522 if (op == POOL_OP_CREATE) {
523 pr->MaxVols = pool->max_volumes;
525 } else { /* update pool */
526 if (pr->MaxVols != pool->max_volumes) {
527 pr->MaxVols = pool->max_volumes;
529 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
530 pr->MaxVols = pr->NumVols;
533 pr->LabelType = pool->LabelType;
534 pr->UseOnce = pool->use_volume_once;
535 pr->UseCatalog = pool->use_catalog;
536 pr->Recycle = pool->Recycle;
537 pr->VolRetention = pool->VolRetention;
538 pr->VolUseDuration = pool->VolUseDuration;
539 pr->MaxVolJobs = pool->MaxVolJobs;
540 pr->MaxVolFiles = pool->MaxVolFiles;
541 pr->MaxVolBytes = pool->MaxVolBytes;
542 pr->AutoPrune = pool->AutoPrune;
543 pr->Recycle = pool->Recycle;
544 if (pool->label_format) {
545 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
547 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
551 /* set/update Pool.RecyclePoolId in Catalog */
552 int update_pool_recyclepool(JCR *jcr, B_DB *db, POOL *pool)
556 if (!pool->RecyclePool) {
560 memset(&pr, 0, sizeof(POOL_DBR));
561 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
563 if (!db_get_pool_record(jcr, db, &pr)) {
564 return -1; /* not exists in database */
567 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
569 if (!set_pooldbr_recyclepoolid(jcr, db, &pr, pool)) {
570 return -1; /* error */
573 if (!db_update_pool_record(jcr, db, &pr)) {
574 return -1; /* error */
579 /* set POOL_DBR.RecyclePoolId from Pool resource
580 * works with set_pooldbr_from_poolres
582 bool set_pooldbr_recyclepoolid(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
587 if (pool->RecyclePool) {
588 memset(&rpool, 0, sizeof(POOL_DBR));
590 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
591 if (db_get_pool_record(jcr, db, &rpool)) {
592 pr->RecyclePoolId = rpool.PoolId;
594 Jmsg(jcr, M_WARNING, 0,
595 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
596 "Try to update it with 'update pool=%s'\n"),
597 pool->name(), rpool.Name, rpool.Name,pool->name());
601 } else { /* no RecyclePool used, set it to 0 */
602 pr->RecyclePoolId = 0;
609 * Create a pool record from a given Pool resource
610 * Also called from backup.c
611 * Returns: -1 on error
612 * 0 record already exists
616 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
620 memset(&pr, 0, sizeof(POOL_DBR));
622 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
624 if (db_get_pool_record(jcr, db, &pr)) {
626 if (op == POOL_OP_UPDATE) { /* update request */
627 set_pooldbr_from_poolres(&pr, pool, op);
628 db_update_pool_record(jcr, db, &pr);
630 return 0; /* exists */
633 set_pooldbr_from_poolres(&pr, pool, op);
635 if (!db_create_pool_record(jcr, db, &pr)) {
636 return -1; /* error */
644 * Create a Pool Record in the database.
645 * It is always created from the Resource record.
647 static int create_cmd(UAContext *ua, const char *cmd)
651 if (!open_client_db(ua)) {
655 pool = get_pool_resource(ua);
660 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
662 ua->error_msg(_("Error: Pool %s already exists.\n"
663 "Use update to change it.\n"), pool->name());
667 ua->error_msg("%s", db_strerror(ua->db));
673 ua->send_msg(_("Pool %s created.\n"), pool->name());
678 extern DIRRES *director;
681 * Python control command
682 * python restart (restarts interpreter)
684 static int python_cmd(UAContext *ua, const char *cmd)
686 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
687 term_python_interpreter();
688 init_python_interpreter(director->name(),
689 director->scripts_directory, "DirStartUp");
690 ua->send_msg(_("Python interpreter restarted.\n"));
692 ua->warning_msg(_("Nothing done.\n"));
699 * Set a new address in a Client resource. We do this only
700 * if the Console name is the same as the Client name
701 * and the Console can access the client.
703 static int setip_cmd(UAContext *ua, const char *cmd)
707 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
708 ua->error_msg(_("Unauthorized command from this console.\n"));
712 client = GetClientResWithName(ua->cons->name());
715 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
718 if (client->address) {
719 free(client->address);
721 /* MA Bug 6 remove ifdef */
722 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
723 client->address = bstrdup(buf);
724 ua->send_msg(_("Client \"%s\" address set to %s\n"),
725 client->name(), client->address);
732 static void do_en_disable_cmd(UAContext *ua, bool setting)
737 i = find_arg_with_value(ua, NT_("job"));
739 job = select_job_resource(ua);
745 job = GetJobResWithName(ua->argv[i]);
749 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
753 if (!acl_access_ok(ua, Job_ACL, job->name())) {
754 ua->error_msg(_("Unauthorized command from this console.\n"));
757 job->enabled = setting;
758 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
762 static int enable_cmd(UAContext *ua, const char *cmd)
764 do_en_disable_cmd(ua, true);
768 static int disable_cmd(UAContext *ua, const char *cmd)
770 do_en_disable_cmd(ua, false);
775 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
781 lstore.store = store;
782 pm_strcpy(lstore.store_source, _("unknown source"));
783 set_wstorage(jcr, &lstore);
784 /* Try connecting for up to 15 seconds */
785 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
786 store->name(), store->address, store->SDport);
787 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
788 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
791 Dmsg0(120, _("Connected to storage daemon\n"));
792 sd = jcr->store_bsock;
793 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
794 if (sd->recv() >= 0) {
795 ua->send_msg("%s", sd->msg);
797 sd->signal(BNET_TERMINATE);
799 jcr->store_bsock = NULL;
803 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
807 /* Connect to File daemon */
809 ua->jcr->client = client;
810 /* Try to connect for 15 seconds */
811 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
812 client->name(), client->address, client->FDport);
813 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
814 ua->error_msg(_("Failed to connect to Client.\n"));
817 Dmsg0(120, "Connected to file daemon\n");
818 fd = ua->jcr->file_bsock;
819 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
820 if (fd->recv() >= 0) {
821 ua->send_msg("%s", fd->msg);
823 fd->signal(BNET_TERMINATE);
825 ua->jcr->file_bsock = NULL;
830 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
832 STORE *store, **unique_store;
833 CLIENT *client, **unique_client;
839 /* Count Storage items */
843 foreach_res(store, R_STORAGE) {
846 unique_store = (STORE **) malloc(i * sizeof(STORE));
847 /* Find Unique Storage address/port */
848 store = (STORE *)GetNextRes(R_STORAGE, NULL);
850 unique_store[i++] = store;
851 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
853 for (j=0; j<i; j++) {
854 if (strcmp(unique_store[j]->address, store->address) == 0 &&
855 unique_store[j]->SDport == store->SDport) {
861 unique_store[i++] = store;
862 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
867 /* Call each unique Storage daemon */
868 for (j=0; j<i; j++) {
869 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
873 /* Count Client items */
877 foreach_res(client, R_CLIENT) {
880 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
881 /* Find Unique Client address/port */
882 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
884 unique_client[i++] = client;
885 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
887 for (j=0; j<i; j++) {
888 if (strcmp(unique_client[j]->address, client->address) == 0 &&
889 unique_client[j]->FDport == client->FDport) {
895 unique_client[i++] = client;
896 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
901 /* Call each unique File daemon */
902 for (j=0; j<i; j++) {
903 do_client_setdebug(ua, unique_client[j], level, trace_flag);
909 * setdebug level=nn all trace=1/0
911 static int setdebug_cmd(UAContext *ua, const char *cmd)
919 Dmsg1(120, "setdebug:%s:\n", cmd);
922 i = find_arg_with_value(ua, "level");
924 level = atoi(ua->argv[i]);
927 if (!get_pint(ua, _("Enter new debug level: "))) {
930 level = ua->pint32_val;
933 /* Look for trace flag. -1 => not change */
934 i = find_arg_with_value(ua, "trace");
936 trace_flag = atoi(ua->argv[i]);
937 if (trace_flag > 0) {
943 for (i=1; i<ua->argc; i++) {
944 if (strcasecmp(ua->argk[i], "all") == 0) {
945 do_all_setdebug(ua, level, trace_flag);
948 if (strcasecmp(ua->argk[i], "dir") == 0 ||
949 strcasecmp(ua->argk[i], "director") == 0) {
951 set_trace(trace_flag);
954 if (strcasecmp(ua->argk[i], "client") == 0 ||
955 strcasecmp(ua->argk[i], "fd") == 0) {
958 client = GetClientResWithName(ua->argv[i]);
960 do_client_setdebug(ua, client, level, trace_flag);
964 client = select_client_resource(ua);
966 do_client_setdebug(ua, client, level, trace_flag);
971 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
972 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
973 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
976 store = GetStoreResWithName(ua->argv[i]);
978 do_storage_setdebug(ua, store, level, trace_flag);
982 store = get_storage_resource(ua, false/*no default*/);
984 do_storage_setdebug(ua, store, level, trace_flag);
990 * We didn't find an appropriate keyword above, so
993 start_prompt(ua, _("Available daemons are: \n"));
994 add_prompt(ua, _("Director"));
995 add_prompt(ua, _("Storage"));
996 add_prompt(ua, _("Client"));
997 add_prompt(ua, _("All"));
998 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
999 case 0: /* Director */
1000 debug_level = level;
1001 set_trace(trace_flag);
1004 store = get_storage_resource(ua, false/*no default*/);
1006 do_storage_setdebug(ua, store, level, trace_flag);
1010 client = select_client_resource(ua);
1012 do_client_setdebug(ua, client, level, trace_flag);
1016 do_all_setdebug(ua, level, trace_flag);
1025 * Turn debug tracing to file on/off
1027 static int trace_cmd(UAContext *ua, const char *cmd)
1031 if (ua->argc != 2) {
1032 if (!get_cmd(ua, _("Turn on or off? "))) {
1037 onoff = ua->argk[1];
1040 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1045 static int var_cmd(UAContext *ua, const char *cmd)
1047 POOLMEM *val = get_pool_memory(PM_FNAME);
1050 if (!open_client_db(ua)) {
1053 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1056 while (*var == ' ') { /* skip spaces */
1059 Dmsg1(100, "Var=%s:\n", var);
1060 variable_expansion(ua->jcr, var, &val);
1061 ua->send_msg("%s\n", val);
1062 free_pool_memory(val);
1066 static int estimate_cmd(UAContext *ua, const char *cmd)
1069 CLIENT *client = NULL;
1070 FILESET *fileset = NULL;
1072 char since[MAXSTRING];
1075 jcr->set_JobLevel(L_FULL);
1076 for (int i=1; i<ua->argc; i++) {
1077 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1078 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1080 client = GetClientResWithName(ua->argv[i]);
1082 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1087 ua->error_msg(_("Client name missing.\n"));
1091 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1093 job = GetJobResWithName(ua->argv[i]);
1095 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1098 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1099 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1104 ua->error_msg(_("Job name missing.\n"));
1109 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1111 fileset = GetFileSetResWithName(ua->argv[i]);
1113 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1116 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1117 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1122 ua->error_msg(_("Fileset name missing.\n"));
1126 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1130 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1132 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1133 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1137 ua->error_msg(_("Level value missing.\n"));
1142 if (!job && !(client && fileset)) {
1143 if (!(job = select_job_resource(ua))) {
1148 job = GetJobResWithName(ua->argk[1]);
1150 ua->error_msg(_("No job specified.\n"));
1153 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1154 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1159 client = job->client;
1162 fileset = job->fileset;
1164 jcr->client = client;
1165 jcr->fileset = fileset;
1167 if (job->pool->catalog) {
1168 ua->catalog = job->pool->catalog;
1170 ua->catalog = client->catalog;
1178 jcr->set_JobType(JT_BACKUP);
1179 init_jcr_job_record(jcr);
1181 if (!get_or_create_client_record(jcr)) {
1184 if (!get_or_create_fileset_record(jcr)) {
1188 get_level_since_time(ua->jcr, since, sizeof(since));
1190 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1191 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1192 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1193 ua->error_msg(_("Failed to connect to Client.\n"));
1197 if (!send_include_list(jcr)) {
1198 ua->error_msg(_("Error sending include list.\n"));
1202 if (!send_exclude_list(jcr)) {
1203 ua->error_msg(_("Error sending exclude list.\n"));
1207 if (!send_level_command(jcr)) {
1211 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1212 while (bnet_recv(jcr->file_bsock) >= 0) {
1213 ua->send_msg("%s", jcr->file_bsock->msg);
1217 if (jcr->file_bsock) {
1218 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1219 bnet_close(jcr->file_bsock);
1220 jcr->file_bsock = NULL;
1229 static int time_cmd(UAContext *ua, const char *cmd)
1232 time_t ttime = time(NULL);
1234 (void)localtime_r(&ttime, &tm);
1235 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1236 ua->send_msg("%s\n", sdt);
1241 * reload the conf file
1243 extern "C" void reload_config(int sig);
1245 static int reload_cmd(UAContext *ua, const char *cmd)
1252 * Delete Pool records (should purge Media with it).
1254 * delete pool=<pool-name>
1255 * delete volume pool=<pool-name> volume=<name>
1258 static int delete_cmd(UAContext *ua, const char *cmd)
1260 static const char *keywords[] = {
1266 if (!open_client_db(ua)) {
1270 switch (find_arg_keyword(ua, keywords)) {
1279 while ((i=find_arg(ua, "jobid")) > 0) {
1281 *ua->argk[i] = 0; /* zap keyword already visited */
1289 "In general it is not a good idea to delete either a\n"
1290 "Pool or a Volume since they may contain data.\n\n"));
1292 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1303 ua->warning_msg(_("Nothing done.\n"));
1311 * delete_job has been modified to parse JobID lists like the
1313 * delete JobID=3,4,6,7-11,14
1315 * Thanks to Phil Stracchino for the above addition.
1318 static void delete_job(UAContext *ua)
1323 int i = find_arg_with_value(ua, NT_("jobid"));
1325 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1326 s = bstrdup(ua->argv[i]);
1329 * We could use strtok() here. But we're not going to, because:
1330 * (a) strtok() is deprecated, having been replaced by strsep();
1331 * (b) strtok() is broken in significant ways.
1332 * we could use strsep() instead, but it's not universally available.
1333 * so we grow our own using strchr().
1335 sep = strchr(tok, ',');
1336 while (sep != NULL) {
1338 if (strchr(tok, '-')) {
1339 delete_job_id_range(ua, tok);
1341 JobId = str_to_int64(tok);
1342 do_job_delete(ua, JobId);
1345 sep = strchr(tok, ',');
1347 /* pick up the last token */
1348 if (strchr(tok, '-')) {
1349 delete_job_id_range(ua, tok);
1351 JobId = str_to_int64(tok);
1352 do_job_delete(ua, JobId);
1357 JobId = str_to_int64(ua->argv[i]);
1358 do_job_delete(ua, JobId);
1360 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1363 JobId = ua->int64_val;
1364 do_job_delete(ua, JobId);
1369 * we call delete_job_id_range to parse range tokens and iterate over ranges
1371 static void delete_job_id_range(UAContext *ua, char *tok)
1376 tok2 = strchr(tok, '-');
1379 j1 = str_to_int64(tok);
1380 j2 = str_to_int64(tok2);
1381 for (j=j1; j<=j2; j++) {
1382 do_job_delete(ua, j);
1387 * do_job_delete now performs the actual delete operation atomically
1389 static void do_job_delete(UAContext *ua, JobId_t JobId)
1393 edit_int64(JobId, ed1);
1394 purge_jobs_from_catalog(ua, ed1);
1395 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1399 * Delete media records from database -- dangerous
1401 static int delete_volume(UAContext *ua)
1406 if (!select_media_dbr(ua, &mr)) {
1409 ua->warning_msg(_("\nThis command will delete volume %s\n"
1410 "and all Jobs saved on that volume from the Catalog\n"),
1413 if (find_arg(ua, "yes") >= 0) {
1414 ua->pint32_val = 1; /* Have "yes" on command line already" */
1416 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1418 if (!get_yesno(ua, buf)) {
1422 if (ua->pint32_val) {
1423 db_delete_media_record(ua->jcr, ua->db, &mr);
1429 * Delete a pool record from the database -- dangerous
1431 static int delete_pool(UAContext *ua)
1436 memset(&pr, 0, sizeof(pr));
1438 if (!get_pool_dbr(ua, &pr)) {
1441 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1443 if (!get_yesno(ua, buf)) {
1446 if (ua->pint32_val) {
1447 db_delete_pool_record(ua->jcr, ua->db, &pr);
1452 int memory_cmd(UAContext *ua, const char *cmd)
1454 list_dir_status_header(ua);
1455 sm_dump(false, true);
1459 static void do_mount_cmd(UAContext *ua, const char *command)
1464 char dev_name[MAX_NAME_LENGTH];
1468 if (!open_client_db(ua)) {
1471 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1473 store.store = get_storage_resource(ua, true/*arg is storage*/);
1477 pm_strcpy(store.store_source, _("unknown source"));
1478 set_wstorage(jcr, &store);
1479 drive = get_storage_drive(ua, store.store);
1480 if (strcmp(command, "mount") == 0) {
1481 slot = get_storage_slot(ua, store.store);
1484 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1485 store.store->media_type, store.store->dev_name(), drive);
1487 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1488 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1491 sd = jcr->store_bsock;
1492 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1493 bash_spaces(dev_name);
1495 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1497 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1499 while (bnet_recv(sd) >= 0) {
1500 ua->send_msg("%s", sd->msg);
1502 bnet_sig(sd, BNET_TERMINATE);
1504 jcr->store_bsock = NULL;
1508 * mount [storage=<name>] [drive=nn] [slot=mm]
1510 static int mount_cmd(UAContext *ua, const char *cmd)
1512 do_mount_cmd(ua, "mount"); /* mount */
1518 * unmount [storage=<name>] [drive=nn]
1520 static int unmount_cmd(UAContext *ua, const char *cmd)
1522 do_mount_cmd(ua, "unmount"); /* unmount */
1528 * release [storage=<name>] [drive=nn]
1530 static int release_cmd(UAContext *ua, const char *cmd)
1532 do_mount_cmd(ua, "release"); /* release */
1539 * use catalog=<name>
1541 static int use_cmd(UAContext *ua, const char *cmd)
1543 CAT *oldcatalog, *catalog;
1546 close_db(ua); /* close any previously open db */
1547 oldcatalog = ua->catalog;
1549 if (!(catalog = get_catalog_resource(ua))) {
1550 ua->catalog = oldcatalog;
1552 ua->catalog = catalog;
1555 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1556 ua->catalog->name(), ua->catalog->db_name);
1561 int quit_cmd(UAContext *ua, const char *cmd)
1567 /* Handler to get job status */
1568 static int status_handler(void *ctx, int num_fields, char **row)
1570 char *val = (char *)ctx;
1575 *val = '?'; /* Unknown by default */
1582 * Wait until no job is running
1584 int wait_cmd(UAContext *ua, const char *cmd)
1588 time_t stop_time = 0;
1592 * Wait until no job is running
1594 if (ua->argc == 1) {
1595 bmicrosleep(0, 200000); /* let job actually start */
1596 for (bool running=true; running; ) {
1599 if (jcr->JobId != 0) {
1613 i = find_arg_with_value(ua, NT_("timeout"));
1614 if (i > 0 && ua->argv[i]) {
1615 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1618 /* we have jobid, jobname or ujobid argument */
1620 uint32_t jobid = 0 ;
1622 if (!open_client_db(ua)) {
1623 ua->error_msg(_("ERR: Can't open db\n")) ;
1627 for (int i=1; i<ua->argc; i++) {
1628 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1632 jobid = str_to_int64(ua->argv[i]);
1634 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1635 strcasecmp(ua->argk[i], "job") == 0) {
1639 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1641 jobid = jcr->JobId ;
1645 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1649 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1651 jobid = jcr->JobId ;
1655 /* Wait for a mount request */
1656 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1657 for (bool waiting=false; !waiting; ) {
1659 if (jcr->JobId != 0 &&
1660 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1669 if (stop_time && (time(NULL) >= stop_time)) {
1670 ua->warning_msg(_("Wait on mount timed out\n"));
1680 ua->error_msg(_("ERR: Job was not found\n"));
1685 * We wait the end of a specific job
1688 bmicrosleep(0, 200000); /* let job actually start */
1689 for (bool running=true; running; ) {
1692 jcr=get_jcr_by_id(jobid) ;
1705 * We have to get JobStatus
1709 char jobstatus = '?'; /* Unknown by default */
1712 bsnprintf(buf, sizeof(buf),
1713 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1716 db_sql_query(ua->db, buf,
1717 status_handler, (void *)&jobstatus);
1719 switch (jobstatus) {
1721 status = 1 ; /* Warning */
1725 case JS_ErrorTerminated:
1727 status = 2 ; /* Critical */
1731 status = 0 ; /* Ok */
1735 status = 3 ; /* Unknown */
1739 ua->send_msg("JobId=%i\n", jobid) ;
1740 ua->send_msg("JobStatus=%s (%c)\n",
1741 job_status_to_str(jobstatus),
1744 if (ua->gui || ua->api) {
1745 ua->send_msg("ExitStatus=%i\n", status) ;
1752 static int help_cmd(UAContext *ua, const char *cmd)
1756 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1757 for (i=0; i<comsize; i++) {
1758 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1760 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1764 int qhelp_cmd(UAContext *ua, const char *cmd)
1768 for (i=0; i<comsize; i++) {
1769 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1775 static int version_cmd(UAContext *ua, const char *cmd)
1777 ua->send_msg(_("%s Version: %s (%s) %s %s %s\n"), my_name, VERSION, BDATE,
1778 HOST_OS, DISTNAME, DISTVER);
1783 * Test code -- turned on only for debug testing
1785 static int version_cmd(UAContext *ua, const char *cmd)
1788 POOL_MEM query(PM_MESSAGE);
1790 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1791 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1792 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1793 for (int i=0; i < ids.num_ids; i++) {
1794 ua->send_msg("id=%d\n", ids.DBId[i]);
1802 * This call explicitly checks for a catalog=xxx and
1803 * if given, opens that catalog. It also checks for
1804 * client=xxx and if found, opens the catalog
1805 * corresponding to that client. If we still don't
1806 * have a catalog, look for a Job keyword and get the
1807 * catalog from its client record.
1809 bool open_client_db(UAContext *ua)
1816 /* Try for catalog keyword */
1817 i = find_arg_with_value(ua, NT_("catalog"));
1819 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1820 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1823 catalog = GetCatalogResWithName(ua->argv[i]);
1825 if (ua->catalog && ua->catalog != catalog) {
1828 ua->catalog = catalog;
1833 /* Try for client keyword */
1834 i = find_arg_with_value(ua, NT_("client"));
1836 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1837 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1840 client = GetClientResWithName(ua->argv[i]);
1842 catalog = client->catalog;
1843 if (ua->catalog && ua->catalog != catalog) {
1846 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1847 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1850 ua->catalog = catalog;
1855 /* Try for Job keyword */
1856 i = find_arg_with_value(ua, NT_("job"));
1858 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1859 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1862 job = GetJobResWithName(ua->argv[i]);
1864 catalog = job->client->catalog;
1865 if (ua->catalog && ua->catalog != catalog) {
1868 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1869 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1872 ua->catalog = catalog;
1882 * Open the catalog database.
1884 bool open_db(UAContext *ua)
1890 ua->catalog = get_catalog_resource(ua);
1892 ua->error_msg( _("Could not find a Catalog resource\n"));
1897 ua->jcr->catalog = ua->catalog;
1899 Dmsg0(100, "UA Open database\n");
1900 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1901 ua->catalog->db_user,
1902 ua->catalog->db_password, ua->catalog->db_address,
1903 ua->catalog->db_port, ua->catalog->db_socket,
1904 ua->catalog->mult_db_connections);
1905 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1906 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1907 ua->catalog->db_name);
1909 ua->error_msg("%s", db_strerror(ua->db));
1914 ua->jcr->db = ua->db;
1916 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
1918 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1922 void close_db(UAContext *ua)
1925 db_close_database(ua->jcr, ua->db);