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; const bool use_in_rs;};
100 static struct cmdstruct commands[] = { /* Can use it in Console RunScript*/
101 { NT_("add"), add_cmd, _("add media to a pool"), false},
102 { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages"),false},
103 { NT_("automount"), automount_cmd, _("automount [on|off] -- after label"), false},
104 { NT_("cancel"), cancel_cmd, _("cancel [<jobid=nnn> | <job=name>] -- cancel a job"), false},
105 { NT_("create"), create_cmd, _("create DB Pool from resource"), false},
106 { NT_("delete"), delete_cmd, _("delete [pool=<pool-name> | media volume=<volume-name>]"), true},
107 { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job"), true},
108 { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job"), true},
109 { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing"), true},
110 { NT_("exit"), quit_cmd, _("exit = quit"), false},
111 { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode"), false},
112 { NT_("help"), help_cmd, _("print this command"), false},
113 { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog"), true},
114 { NT_("label"), label_cmd, _("label a tape"), false},
115 { NT_("llist"), llist_cmd, _("full or long list like list command"), true},
116 { NT_("messages"), messagescmd, _("messages"), false},
117 { NT_("memory"), memory_cmd, _("print current memory usage"), true},
118 { NT_("mount"), mount_cmd, _("mount <storage-name>"), false},
119 { NT_("prune"), prunecmd, _("prune expired records from catalog"), true},
120 { NT_("purge"), purgecmd, _("purge records from catalog"), true},
121 { NT_("python"), python_cmd, _("python control commands"), false},
122 { NT_("quit"), quit_cmd, _("quit"), false},
123 { NT_("query"), querycmd, _("query catalog"), false},
124 { NT_("restore"), restore_cmd, _("restore files"), false},
125 { NT_("relabel"), relabel_cmd, _("relabel a tape"), false},
126 { NT_("release"), release_cmd, _("release <storage-name>"), false},
127 { NT_("reload"), reload_cmd, _("reload conf file"), true},
128 { NT_("run"), run_cmd, _("run <job-name>"), false}, /* need to be check */
129 { NT_("status"), status_cmd, _("status [storage | client]=<name>"), true},
130 { NT_("setdebug"), setdebug_cmd, _("sets debug level"), true},
131 { NT_("setip"), setip_cmd, _("sets new client address -- if authorized"), false},
132 { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]"), true},
133 { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog"), false},
134 { NT_("time"), time_cmd, _("print current time"), true},
135 { NT_("trace"), trace_cmd, _("turn on/off trace to file"), true},
136 { NT_("unmount"), unmount_cmd, _("unmount <storage-name>"), false},
137 { NT_("umount"), unmount_cmd, _("umount <storage-name> for old-time Unix guys"),false},
138 { NT_("update"), update_cmd, _("update Volume, Pool or slots"), true},
139 { NT_("use"), use_cmd, _("use catalog xxx"), false},
140 { NT_("var"), var_cmd, _("does variable expansion"), false},
141 { NT_("version"), version_cmd, _("print Director version"), true},
142 { NT_("wait"), wait_cmd, _("wait until no jobs are running [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>]"), false},
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]);
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 /* Check if this command is authorized in RunScript */
176 if (ua->runscript && !commands[i].use_in_rs) {
177 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
180 if (ua->api) user->signal(BNET_CMD_BEGIN);
181 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
187 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
190 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
195 * This is a common routine used to stuff the Pool DB record defaults
196 * into the Media DB record just before creating a media (Volume)
199 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
201 mr->PoolId = pr->PoolId;
202 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
203 mr->Recycle = pr->Recycle;
204 mr->VolRetention = pr->VolRetention;
205 mr->VolUseDuration = pr->VolUseDuration;
206 mr->RecyclePoolId = pr->RecyclePoolId;
207 mr->MaxVolJobs = pr->MaxVolJobs;
208 mr->MaxVolFiles = pr->MaxVolFiles;
209 mr->MaxVolBytes = pr->MaxVolBytes;
210 mr->LabelType = pr->LabelType;
216 * Add Volumes to an existing Pool
218 static int add_cmd(UAContext *ua, const char *cmd)
222 int num, i, max, startnum;
224 char name[MAX_NAME_LENGTH];
226 int Slot = 0, InChanger = 0;
229 "You probably don't want to be using this command since it\n"
230 "creates database records without labeling the Volumes.\n"
231 "You probably want to use the \"label\" command.\n\n"));
233 if (!open_client_db(ua)) {
237 memset(&pr, 0, sizeof(pr));
238 memset(&mr, 0, sizeof(mr));
240 if (!get_pool_dbr(ua, &pr)) {
244 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
245 pr.MaxVols, pr.PoolType);
247 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
248 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
249 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
252 pr.MaxVols = ua->pint32_val;
256 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
257 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
258 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
262 if (pr.MaxVols == 0) {
265 max = pr.MaxVols - pr.NumVols;
269 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
270 if (!get_pint(ua, buf)) {
273 num = ua->pint32_val;
274 if (num < 0 || num > max) {
275 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
283 if (!get_cmd(ua, _("Enter Volume name: "))) {
287 if (!get_cmd(ua, _("Enter base volume name: "))) {
291 /* Don't allow | in Volume name because it is the volume separator character */
292 if (!is_volume_name_legal(ua, ua->cmd)) {
295 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
296 ua->warning_msg(_("Volume name too long.\n"));
299 if (strlen(ua->cmd) == 0) {
300 ua->warning_msg(_("Volume name must be at least one character long.\n"));
306 bstrncpy(name, ua->cmd, sizeof(name));
308 bstrncat(name, "%04d", sizeof(name));
311 if (!get_pint(ua, _("Enter the starting number: "))) {
314 startnum = ua->pint32_val;
316 ua->warning_msg(_("Start number must be greater than zero.\n"));
326 if (store && store->autochanger) {
327 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
330 Slot = ua->pint32_val;
331 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
334 InChanger = ua->pint32_val;
337 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
338 for (i=startnum; i < num+startnum; i++) {
339 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
341 mr.InChanger = InChanger;
342 mr.StorageId = store->StorageId;
344 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
345 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
346 ua->error_msg("%s", db_strerror(ua->db));
350 first_id = mr.PoolId;
354 Dmsg0(200, "Update pool record.\n");
355 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
356 ua->warning_msg("%s", db_strerror(ua->db));
359 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
365 * Turn auto mount on/off
370 int automount_cmd(UAContext *ua, const char *cmd)
375 if (!get_cmd(ua, _("Turn on or off? "))) {
383 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
391 static int cancel_cmd(UAContext *ua, const char *cmd)
396 char JobName[MAX_NAME_LENGTH];
398 for (i=1; i<ua->argc; i++) {
399 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
404 JobId = str_to_int64(ua->argv[i]);
405 if (!(jcr=get_jcr_by_id(JobId))) {
406 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
410 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
414 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
415 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
416 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
417 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
420 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
424 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
425 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
426 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
427 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
434 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
435 ua->error_msg(_("Unauthorized command from this console.\n"));
440 * If we still do not have a jcr,
441 * throw up a list and ask the user to select one.
444 int tjobs = 0; /* total # number jobs */
445 /* Count Jobs running */
447 if (jcr->JobId == 0) { /* this is us */
450 tjobs++; /* count of all jobs */
451 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
452 continue; /* skip not authorized */
454 njobs++; /* count of authorized jobs */
458 if (njobs == 0) { /* no authorized */
460 ua->send_msg(_("No Jobs running.\n"));
462 ua->send_msg(_("None of your jobs are running.\n"));
467 start_prompt(ua, _("Select Job:\n"));
470 if (jcr->JobId == 0) { /* this is us */
473 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
474 continue; /* skip not authorized */
476 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
481 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
484 if (ua->api && njobs == 1) {
486 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
487 _("Confirm cancel?"));
488 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
493 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
498 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
499 jcr = get_jcr_by_full_name(JobName);
501 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
506 ret = cancel_job(ua, jcr);
512 * This is a common routine to create or update a
513 * Pool DB base record from a Pool Resource. We handle
514 * the setting of MaxVols and NumVols slightly differently
515 * depending on if we are creating the Pool or we are
516 * simply bringing it into agreement with the resource (updage).
518 * Caution : RecyclePoolId isn't setup in this function.
519 * You can use set_pooldbr_recyclepoolid();
522 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
524 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
525 if (op == POOL_OP_CREATE) {
526 pr->MaxVols = pool->max_volumes;
528 } else { /* update pool */
529 if (pr->MaxVols != pool->max_volumes) {
530 pr->MaxVols = pool->max_volumes;
532 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
533 pr->MaxVols = pr->NumVols;
536 pr->LabelType = pool->LabelType;
537 pr->UseOnce = pool->use_volume_once;
538 pr->UseCatalog = pool->use_catalog;
539 pr->Recycle = pool->Recycle;
540 pr->VolRetention = pool->VolRetention;
541 pr->VolUseDuration = pool->VolUseDuration;
542 pr->MaxVolJobs = pool->MaxVolJobs;
543 pr->MaxVolFiles = pool->MaxVolFiles;
544 pr->MaxVolBytes = pool->MaxVolBytes;
545 pr->AutoPrune = pool->AutoPrune;
546 pr->Recycle = pool->Recycle;
547 if (pool->label_format) {
548 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
550 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
554 /* set/update Pool.RecyclePoolId in Catalog */
555 int update_pool_recyclepool(JCR *jcr, B_DB *db, POOL *pool)
559 if (!pool->RecyclePool) {
563 memset(&pr, 0, sizeof(POOL_DBR));
564 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
566 if (!db_get_pool_record(jcr, db, &pr)) {
567 return -1; /* not exists in database */
570 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
572 if (!set_pooldbr_recyclepoolid(jcr, db, &pr, pool)) {
573 return -1; /* error */
576 if (!db_update_pool_record(jcr, db, &pr)) {
577 return -1; /* error */
582 /* set POOL_DBR.RecyclePoolId from Pool resource
583 * works with set_pooldbr_from_poolres
585 bool set_pooldbr_recyclepoolid(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
590 if (pool->RecyclePool) {
591 memset(&rpool, 0, sizeof(POOL_DBR));
593 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
594 if (db_get_pool_record(jcr, db, &rpool)) {
595 pr->RecyclePoolId = rpool.PoolId;
597 Jmsg(jcr, M_WARNING, 0,
598 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
599 "Try to update it with 'update pool=%s'\n"),
600 pool->name(), rpool.Name, rpool.Name,pool->name());
604 } else { /* no RecyclePool used, set it to 0 */
605 pr->RecyclePoolId = 0;
612 * Create a pool record from a given Pool resource
613 * Also called from backup.c
614 * Returns: -1 on error
615 * 0 record already exists
619 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
623 memset(&pr, 0, sizeof(POOL_DBR));
625 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
627 if (db_get_pool_record(jcr, db, &pr)) {
629 if (op == POOL_OP_UPDATE) { /* update request */
630 set_pooldbr_from_poolres(&pr, pool, op);
631 db_update_pool_record(jcr, db, &pr);
633 return 0; /* exists */
636 set_pooldbr_from_poolres(&pr, pool, op);
638 if (!db_create_pool_record(jcr, db, &pr)) {
639 return -1; /* error */
647 * Create a Pool Record in the database.
648 * It is always created from the Resource record.
650 static int create_cmd(UAContext *ua, const char *cmd)
654 if (!open_client_db(ua)) {
658 pool = get_pool_resource(ua);
663 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
665 ua->error_msg(_("Error: Pool %s already exists.\n"
666 "Use update to change it.\n"), pool->name());
670 ua->error_msg("%s", db_strerror(ua->db));
676 ua->send_msg(_("Pool %s created.\n"), pool->name());
681 extern DIRRES *director;
684 * Python control command
685 * python restart (restarts interpreter)
687 static int python_cmd(UAContext *ua, const char *cmd)
689 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
690 term_python_interpreter();
691 init_python_interpreter(director->name(),
692 director->scripts_directory, "DirStartUp");
693 ua->send_msg(_("Python interpreter restarted.\n"));
695 ua->warning_msg(_("Nothing done.\n"));
702 * Set a new address in a Client resource. We do this only
703 * if the Console name is the same as the Client name
704 * and the Console can access the client.
706 static int setip_cmd(UAContext *ua, const char *cmd)
710 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
711 ua->error_msg(_("Unauthorized command from this console.\n"));
715 client = GetClientResWithName(ua->cons->name());
718 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
721 if (client->address) {
722 free(client->address);
724 /* MA Bug 6 remove ifdef */
725 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
726 client->address = bstrdup(buf);
727 ua->send_msg(_("Client \"%s\" address set to %s\n"),
728 client->name(), client->address);
735 static void do_en_disable_cmd(UAContext *ua, bool setting)
740 i = find_arg_with_value(ua, NT_("job"));
742 job = select_job_resource(ua);
748 job = GetJobResWithName(ua->argv[i]);
752 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
756 if (!acl_access_ok(ua, Job_ACL, job->name())) {
757 ua->error_msg(_("Unauthorized command from this console.\n"));
760 job->enabled = setting;
761 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
765 static int enable_cmd(UAContext *ua, const char *cmd)
767 do_en_disable_cmd(ua, true);
771 static int disable_cmd(UAContext *ua, const char *cmd)
773 do_en_disable_cmd(ua, false);
778 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
784 lstore.store = store;
785 pm_strcpy(lstore.store_source, _("unknown source"));
786 set_wstorage(jcr, &lstore);
787 /* Try connecting for up to 15 seconds */
788 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
789 store->name(), store->address, store->SDport);
790 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
791 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
794 Dmsg0(120, _("Connected to storage daemon\n"));
795 sd = jcr->store_bsock;
796 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
797 if (sd->recv() >= 0) {
798 ua->send_msg("%s", sd->msg);
800 sd->signal(BNET_TERMINATE);
802 jcr->store_bsock = NULL;
806 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
810 /* Connect to File daemon */
812 ua->jcr->client = client;
813 /* Try to connect for 15 seconds */
814 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
815 client->name(), client->address, client->FDport);
816 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
817 ua->error_msg(_("Failed to connect to Client.\n"));
820 Dmsg0(120, "Connected to file daemon\n");
821 fd = ua->jcr->file_bsock;
822 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
823 if (fd->recv() >= 0) {
824 ua->send_msg("%s", fd->msg);
826 fd->signal(BNET_TERMINATE);
828 ua->jcr->file_bsock = NULL;
833 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
835 STORE *store, **unique_store;
836 CLIENT *client, **unique_client;
842 /* Count Storage items */
846 foreach_res(store, R_STORAGE) {
849 unique_store = (STORE **) malloc(i * sizeof(STORE));
850 /* Find Unique Storage address/port */
851 store = (STORE *)GetNextRes(R_STORAGE, NULL);
853 unique_store[i++] = store;
854 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
856 for (j=0; j<i; j++) {
857 if (strcmp(unique_store[j]->address, store->address) == 0 &&
858 unique_store[j]->SDport == store->SDport) {
864 unique_store[i++] = store;
865 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
870 /* Call each unique Storage daemon */
871 for (j=0; j<i; j++) {
872 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
876 /* Count Client items */
880 foreach_res(client, R_CLIENT) {
883 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
884 /* Find Unique Client address/port */
885 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
887 unique_client[i++] = client;
888 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
890 for (j=0; j<i; j++) {
891 if (strcmp(unique_client[j]->address, client->address) == 0 &&
892 unique_client[j]->FDport == client->FDport) {
898 unique_client[i++] = client;
899 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
904 /* Call each unique File daemon */
905 for (j=0; j<i; j++) {
906 do_client_setdebug(ua, unique_client[j], level, trace_flag);
912 * setdebug level=nn all trace=1/0
914 static int setdebug_cmd(UAContext *ua, const char *cmd)
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 %s\n"), my_name, VERSION, BDATE,
1781 NPRTB(director->verid), 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);