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 bnet_fsend(sd, "setdebug=%d trace=%d\n", level, trace_flag);
794 if (bnet_recv(sd) >= 0) {
795 ua->send_msg("%s", sd->msg);
797 bnet_sig(sd, 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 bnet_fsend(fd, "setdebug=%d trace=%d\n", level, trace_flag);
820 if (bnet_recv(fd) >= 0) {
821 ua->send_msg("%s", fd->msg);
823 bnet_sig(fd, 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 if (!open_client_db(ua)) {
922 Dmsg1(120, "setdebug:%s:\n", cmd);
925 i = find_arg_with_value(ua, "level");
927 level = atoi(ua->argv[i]);
930 if (!get_pint(ua, _("Enter new debug level: "))) {
933 level = ua->pint32_val;
936 /* Look for trace flag. -1 => not change */
937 i = find_arg_with_value(ua, "trace");
939 trace_flag = atoi(ua->argv[i]);
940 if (trace_flag > 0) {
946 for (i=1; i<ua->argc; i++) {
947 if (strcasecmp(ua->argk[i], "all") == 0) {
948 do_all_setdebug(ua, level, trace_flag);
951 if (strcasecmp(ua->argk[i], "dir") == 0 ||
952 strcasecmp(ua->argk[i], "director") == 0) {
954 set_trace(trace_flag);
957 if (strcasecmp(ua->argk[i], "client") == 0 ||
958 strcasecmp(ua->argk[i], "fd") == 0) {
961 client = GetClientResWithName(ua->argv[i]);
963 do_client_setdebug(ua, client, level, trace_flag);
967 client = select_client_resource(ua);
969 do_client_setdebug(ua, client, level, trace_flag);
974 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
975 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
976 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
979 store = GetStoreResWithName(ua->argv[i]);
981 do_storage_setdebug(ua, store, level, trace_flag);
985 store = get_storage_resource(ua, false/*no default*/);
987 do_storage_setdebug(ua, store, level, trace_flag);
993 * We didn't find an appropriate keyword above, so
996 start_prompt(ua, _("Available daemons are: \n"));
997 add_prompt(ua, _("Director"));
998 add_prompt(ua, _("Storage"));
999 add_prompt(ua, _("Client"));
1000 add_prompt(ua, _("All"));
1001 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1002 case 0: /* Director */
1003 debug_level = level;
1004 set_trace(trace_flag);
1007 store = get_storage_resource(ua, false/*no default*/);
1009 do_storage_setdebug(ua, store, level, trace_flag);
1013 client = select_client_resource(ua);
1015 do_client_setdebug(ua, client, level, trace_flag);
1019 do_all_setdebug(ua, level, trace_flag);
1028 * Turn debug tracing to file on/off
1030 static int trace_cmd(UAContext *ua, const char *cmd)
1034 if (ua->argc != 2) {
1035 if (!get_cmd(ua, _("Turn on or off? "))) {
1040 onoff = ua->argk[1];
1043 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1048 static int var_cmd(UAContext *ua, const char *cmd)
1050 POOLMEM *val = get_pool_memory(PM_FNAME);
1053 if (!open_client_db(ua)) {
1056 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1059 while (*var == ' ') { /* skip spaces */
1062 Dmsg1(100, "Var=%s:\n", var);
1063 variable_expansion(ua->jcr, var, &val);
1064 ua->send_msg("%s\n", val);
1065 free_pool_memory(val);
1069 static int estimate_cmd(UAContext *ua, const char *cmd)
1072 CLIENT *client = NULL;
1073 FILESET *fileset = NULL;
1075 char since[MAXSTRING];
1078 jcr->set_JobLevel(L_FULL);
1079 for (int i=1; i<ua->argc; i++) {
1080 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1081 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1083 client = GetClientResWithName(ua->argv[i]);
1085 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1090 ua->error_msg(_("Client name missing.\n"));
1094 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1096 job = GetJobResWithName(ua->argv[i]);
1098 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1101 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1102 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1107 ua->error_msg(_("Job name missing.\n"));
1112 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1114 fileset = GetFileSetResWithName(ua->argv[i]);
1116 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1119 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1120 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1125 ua->error_msg(_("Fileset name missing.\n"));
1129 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1133 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1135 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1136 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1140 ua->error_msg(_("Level value missing.\n"));
1145 if (!job && !(client && fileset)) {
1146 if (!(job = select_job_resource(ua))) {
1151 job = GetJobResWithName(ua->argk[1]);
1153 ua->error_msg(_("No job specified.\n"));
1156 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1157 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1162 client = job->client;
1165 fileset = job->fileset;
1167 jcr->client = client;
1168 jcr->fileset = fileset;
1170 if (job->pool->catalog) {
1171 ua->catalog = job->pool->catalog;
1173 ua->catalog = client->catalog;
1181 jcr->set_JobType(JT_BACKUP);
1182 init_jcr_job_record(jcr);
1184 if (!get_or_create_client_record(jcr)) {
1187 if (!get_or_create_fileset_record(jcr)) {
1191 get_level_since_time(ua->jcr, since, sizeof(since));
1193 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1194 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1195 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1196 ua->error_msg(_("Failed to connect to Client.\n"));
1200 if (!send_include_list(jcr)) {
1201 ua->error_msg(_("Error sending include list.\n"));
1205 if (!send_exclude_list(jcr)) {
1206 ua->error_msg(_("Error sending exclude list.\n"));
1210 if (!send_level_command(jcr)) {
1214 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1215 while (bnet_recv(jcr->file_bsock) >= 0) {
1216 ua->send_msg("%s", jcr->file_bsock->msg);
1220 if (jcr->file_bsock) {
1221 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1222 bnet_close(jcr->file_bsock);
1223 jcr->file_bsock = NULL;
1232 static int time_cmd(UAContext *ua, const char *cmd)
1235 time_t ttime = time(NULL);
1237 (void)localtime_r(&ttime, &tm);
1238 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1239 ua->send_msg("%s\n", sdt);
1244 * reload the conf file
1246 extern "C" void reload_config(int sig);
1248 static int reload_cmd(UAContext *ua, const char *cmd)
1255 * Delete Pool records (should purge Media with it).
1257 * delete pool=<pool-name>
1258 * delete volume pool=<pool-name> volume=<name>
1261 static int delete_cmd(UAContext *ua, const char *cmd)
1263 static const char *keywords[] = {
1269 if (!open_client_db(ua)) {
1273 switch (find_arg_keyword(ua, keywords)) {
1282 while ((i=find_arg(ua, "jobid")) > 0) {
1284 *ua->argk[i] = 0; /* zap keyword already visited */
1292 "In general it is not a good idea to delete either a\n"
1293 "Pool or a Volume since they may contain data.\n\n"));
1295 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1306 ua->warning_msg(_("Nothing done.\n"));
1314 * delete_job has been modified to parse JobID lists like the
1316 * delete JobID=3,4,6,7-11,14
1318 * Thanks to Phil Stracchino for the above addition.
1321 static void delete_job(UAContext *ua)
1326 int i = find_arg_with_value(ua, NT_("jobid"));
1328 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1329 s = bstrdup(ua->argv[i]);
1332 * We could use strtok() here. But we're not going to, because:
1333 * (a) strtok() is deprecated, having been replaced by strsep();
1334 * (b) strtok() is broken in significant ways.
1335 * we could use strsep() instead, but it's not universally available.
1336 * so we grow our own using strchr().
1338 sep = strchr(tok, ',');
1339 while (sep != NULL) {
1341 if (strchr(tok, '-')) {
1342 delete_job_id_range(ua, tok);
1344 JobId = str_to_int64(tok);
1345 do_job_delete(ua, JobId);
1348 sep = strchr(tok, ',');
1350 /* pick up the last token */
1351 if (strchr(tok, '-')) {
1352 delete_job_id_range(ua, tok);
1354 JobId = str_to_int64(tok);
1355 do_job_delete(ua, JobId);
1360 JobId = str_to_int64(ua->argv[i]);
1361 do_job_delete(ua, JobId);
1363 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1366 JobId = ua->int64_val;
1367 do_job_delete(ua, JobId);
1372 * we call delete_job_id_range to parse range tokens and iterate over ranges
1374 static void delete_job_id_range(UAContext *ua, char *tok)
1379 tok2 = strchr(tok, '-');
1382 j1 = str_to_int64(tok);
1383 j2 = str_to_int64(tok2);
1384 for (j=j1; j<=j2; j++) {
1385 do_job_delete(ua, j);
1390 * do_job_delete now performs the actual delete operation atomically
1392 static void do_job_delete(UAContext *ua, JobId_t JobId)
1396 edit_int64(JobId, ed1);
1397 purge_jobs_from_catalog(ua, ed1);
1398 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1402 * Delete media records from database -- dangerous
1404 static int delete_volume(UAContext *ua)
1409 if (!select_media_dbr(ua, &mr)) {
1412 ua->warning_msg(_("\nThis command will delete volume %s\n"
1413 "and all Jobs saved on that volume from the Catalog\n"),
1416 if (find_arg(ua, "yes") >= 0) {
1417 ua->pint32_val = 1; /* Have "yes" on command line already" */
1419 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1421 if (!get_yesno(ua, buf)) {
1425 if (ua->pint32_val) {
1426 db_delete_media_record(ua->jcr, ua->db, &mr);
1432 * Delete a pool record from the database -- dangerous
1434 static int delete_pool(UAContext *ua)
1439 memset(&pr, 0, sizeof(pr));
1441 if (!get_pool_dbr(ua, &pr)) {
1444 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1446 if (!get_yesno(ua, buf)) {
1449 if (ua->pint32_val) {
1450 db_delete_pool_record(ua->jcr, ua->db, &pr);
1455 int memory_cmd(UAContext *ua, const char *cmd)
1457 list_dir_status_header(ua);
1458 sm_dump(false, true);
1462 static void do_mount_cmd(UAContext *ua, const char *command)
1467 char dev_name[MAX_NAME_LENGTH];
1471 if (!open_client_db(ua)) {
1474 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1476 store.store = get_storage_resource(ua, true/*arg is storage*/);
1480 pm_strcpy(store.store_source, _("unknown source"));
1481 set_wstorage(jcr, &store);
1482 drive = get_storage_drive(ua, store.store);
1483 if (strcmp(command, "mount") == 0) {
1484 slot = get_storage_slot(ua, store.store);
1487 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1488 store.store->media_type, store.store->dev_name(), drive);
1490 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1491 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1494 sd = jcr->store_bsock;
1495 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1496 bash_spaces(dev_name);
1498 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1500 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1502 while (bnet_recv(sd) >= 0) {
1503 ua->send_msg("%s", sd->msg);
1505 bnet_sig(sd, BNET_TERMINATE);
1507 jcr->store_bsock = NULL;
1511 * mount [storage=<name>] [drive=nn] [slot=mm]
1513 static int mount_cmd(UAContext *ua, const char *cmd)
1515 do_mount_cmd(ua, "mount"); /* mount */
1521 * unmount [storage=<name>] [drive=nn]
1523 static int unmount_cmd(UAContext *ua, const char *cmd)
1525 do_mount_cmd(ua, "unmount"); /* unmount */
1531 * release [storage=<name>] [drive=nn]
1533 static int release_cmd(UAContext *ua, const char *cmd)
1535 do_mount_cmd(ua, "release"); /* release */
1542 * use catalog=<name>
1544 static int use_cmd(UAContext *ua, const char *cmd)
1546 CAT *oldcatalog, *catalog;
1549 close_db(ua); /* close any previously open db */
1550 oldcatalog = ua->catalog;
1552 if (!(catalog = get_catalog_resource(ua))) {
1553 ua->catalog = oldcatalog;
1555 ua->catalog = catalog;
1558 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1559 ua->catalog->name(), ua->catalog->db_name);
1564 int quit_cmd(UAContext *ua, const char *cmd)
1570 /* Handler to get job status */
1571 static int status_handler(void *ctx, int num_fields, char **row)
1573 char *val = (char *)ctx;
1578 *val = '?'; /* Unknown by default */
1585 * Wait until no job is running
1587 int wait_cmd(UAContext *ua, const char *cmd)
1591 time_t stop_time = 0;
1595 * Wait until no job is running
1597 if (ua->argc == 1) {
1598 bmicrosleep(0, 200000); /* let job actually start */
1599 for (bool running=true; running; ) {
1602 if (jcr->JobId != 0) {
1616 i = find_arg_with_value(ua, NT_("timeout"));
1617 if (i > 0 && ua->argv[i]) {
1618 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1621 /* we have jobid, jobname or ujobid argument */
1623 uint32_t jobid = 0 ;
1625 if (!open_client_db(ua)) {
1626 ua->error_msg(_("ERR: Can't open db\n")) ;
1630 for (int i=1; i<ua->argc; i++) {
1631 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1635 jobid = str_to_int64(ua->argv[i]);
1637 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1638 strcasecmp(ua->argk[i], "job") == 0) {
1642 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1644 jobid = jcr->JobId ;
1648 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1652 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1654 jobid = jcr->JobId ;
1658 /* Wait for a mount request */
1659 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1660 for (bool waiting=false; !waiting; ) {
1662 if (jcr->JobId != 0 &&
1663 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1672 if (stop_time && (time(NULL) >= stop_time)) {
1673 ua->warning_msg(_("Wait on mount timed out\n"));
1683 ua->error_msg(_("ERR: Job was not found\n"));
1688 * We wait the end of a specific job
1691 bmicrosleep(0, 200000); /* let job actually start */
1692 for (bool running=true; running; ) {
1695 jcr=get_jcr_by_id(jobid) ;
1708 * We have to get JobStatus
1712 char jobstatus = '?'; /* Unknown by default */
1715 bsnprintf(buf, sizeof(buf),
1716 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1719 db_sql_query(ua->db, buf,
1720 status_handler, (void *)&jobstatus);
1722 switch (jobstatus) {
1724 status = 1 ; /* Warning */
1728 case JS_ErrorTerminated:
1730 status = 2 ; /* Critical */
1734 status = 0 ; /* Ok */
1738 status = 3 ; /* Unknown */
1742 ua->send_msg("JobId=%i\n", jobid) ;
1743 ua->send_msg("JobStatus=%s (%c)\n",
1744 job_status_to_str(jobstatus),
1747 if (ua->gui || ua->api) {
1748 ua->send_msg("ExitStatus=%i\n", status) ;
1755 static int help_cmd(UAContext *ua, const char *cmd)
1759 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1760 for (i=0; i<comsize; i++) {
1761 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1763 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1767 int qhelp_cmd(UAContext *ua, const char *cmd)
1771 for (i=0; i<comsize; i++) {
1772 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1778 static int version_cmd(UAContext *ua, const char *cmd)
1780 ua->send_msg(_("%s Version: %s (%s) %s %s %s\n"), my_name, VERSION, BDATE,
1781 HOST_OS, DISTNAME, DISTVER);
1786 * Test code -- turned on only for debug testing
1788 static int version_cmd(UAContext *ua, const char *cmd)
1791 POOL_MEM query(PM_MESSAGE);
1793 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1794 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1795 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1796 for (int i=0; i < ids.num_ids; i++) {
1797 ua->send_msg("id=%d\n", ids.DBId[i]);
1805 * This call explicitly checks for a catalog=xxx and
1806 * if given, opens that catalog. It also checks for
1807 * client=xxx and if found, opens the catalog
1808 * corresponding to that client. If we still don't
1809 * have a catalog, look for a Job keyword and get the
1810 * catalog from its client record.
1812 bool open_client_db(UAContext *ua)
1819 /* Try for catalog keyword */
1820 i = find_arg_with_value(ua, NT_("catalog"));
1822 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1823 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1826 catalog = GetCatalogResWithName(ua->argv[i]);
1828 if (ua->catalog && ua->catalog != catalog) {
1831 ua->catalog = catalog;
1836 /* Try for client keyword */
1837 i = find_arg_with_value(ua, NT_("client"));
1839 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1840 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1843 client = GetClientResWithName(ua->argv[i]);
1845 catalog = client->catalog;
1846 if (ua->catalog && ua->catalog != catalog) {
1849 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1850 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1853 ua->catalog = catalog;
1858 /* Try for Job keyword */
1859 i = find_arg_with_value(ua, NT_("job"));
1861 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1862 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1865 job = GetJobResWithName(ua->argv[i]);
1867 catalog = job->client->catalog;
1868 if (ua->catalog && ua->catalog != catalog) {
1871 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1872 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1875 ua->catalog = catalog;
1885 * Open the catalog database.
1887 bool open_db(UAContext *ua)
1893 ua->catalog = get_catalog_resource(ua);
1895 ua->error_msg( _("Could not find a Catalog resource\n"));
1900 ua->jcr->catalog = ua->catalog;
1902 Dmsg0(100, "UA Open database\n");
1903 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1904 ua->catalog->db_user,
1905 ua->catalog->db_password, ua->catalog->db_address,
1906 ua->catalog->db_port, ua->catalog->db_socket,
1907 ua->catalog->mult_db_connections);
1908 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1909 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1910 ua->catalog->db_name);
1912 ua->error_msg("%s", db_strerror(ua->db));
1917 ua->jcr->db = ua->db;
1919 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
1921 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1925 void close_db(UAContext *ua)
1928 db_close_database(ua->jcr, ua->db);