]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
47508a6e92cf23f63d3911ca5a5487fea1b330e6
[bacula/bacula] / bacula / src / dird / ua_cmds.c
1 /*
2  *
3  *   Bacula Director -- User Agent Commands
4  *
5  *     Kern Sibbald, September MM
6  *
7  *   Version $Id$
8  */
9 /*
10    Copyright (C) 2000-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Imported subroutines */
28
29 /* Imported variables */
30 extern int r_first;
31 extern int r_last;
32 extern struct s_res resources[];
33 extern char my_name[];
34 extern jobq_t job_queue;              /* job queue */
35
36
37 /* Imported functions */
38 extern int status_cmd(UAContext *ua, const char *cmd);
39 extern int list_cmd(UAContext *ua, const char *cmd);
40 extern int llist_cmd(UAContext *ua, const char *cmd);
41 extern int show_cmd(UAContext *ua, const char *cmd);
42 extern int messagescmd(UAContext *ua, const char *cmd);
43 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
44 extern int gui_cmd(UAContext *ua, const char *cmd);
45 extern int sqlquerycmd(UAContext *ua, const char *cmd);
46 extern int querycmd(UAContext *ua, const char *cmd);
47 extern int retentioncmd(UAContext *ua, const char *cmd);
48 extern int prunecmd(UAContext *ua, const char *cmd);
49 extern int purgecmd(UAContext *ua, const char *cmd);
50 extern int restore_cmd(UAContext *ua, const char *cmd);
51 extern int label_cmd(UAContext *ua, const char *cmd);
52 extern int relabel_cmd(UAContext *ua, const char *cmd);
53 extern int update_cmd(UAContext *ua, const char *cmd);
54
55 /* Forward referenced functions */
56 static int add_cmd(UAContext *ua, const char *cmd);
57 static int create_cmd(UAContext *ua, const char *cmd);
58 static int cancel_cmd(UAContext *ua, const char *cmd);
59 static int setdebug_cmd(UAContext *ua, const char *cmd);
60 static int trace_cmd(UAContext *ua, const char *cmd);
61 static int var_cmd(UAContext *ua, const char *cmd);
62 static int estimate_cmd(UAContext *ua, const char *cmd);
63 static int help_cmd(UAContext *ua, const char *cmd);
64 static int delete_cmd(UAContext *ua, const char *cmd);
65 static int use_cmd(UAContext *ua, const char *cmd);
66 static int unmount_cmd(UAContext *ua, const char *cmd);
67 static int version_cmd(UAContext *ua, const char *cmd);
68 static int automount_cmd(UAContext *ua, const char *cmd);
69 static int time_cmd(UAContext *ua, const char *cmd);
70 static int reload_cmd(UAContext *ua, const char *cmd);
71 static int delete_volume(UAContext *ua);
72 static int delete_pool(UAContext *ua);
73 static void delete_job(UAContext *ua);
74 static int mount_cmd(UAContext *ua, const char *cmd);
75 static int release_cmd(UAContext *ua, const char *cmd);
76 static int wait_cmd(UAContext *ua, const char *cmd);
77 static int setip_cmd(UAContext *ua, const char *cmd);
78 static int python_cmd(UAContext *ua, const char *cmd);
79 static void do_job_delete(UAContext *ua, JobId_t JobId);
80 static void delete_job_id_range(UAContext *ua, char *tok);
81
82 int qhelp_cmd(UAContext *ua, const char *cmd);
83 int quit_cmd(UAContext *ua, const char *cmd);
84
85
86 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; };
87 static struct cmdstruct commands[] = {
88  { N_("add"),        add_cmd,         _("add media to a pool")},
89  { N_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages")},
90  { N_("automount"),   automount_cmd,  _("automount [on|off] -- after label")},
91  { N_("cancel"),     cancel_cmd,    _("cancel [<jobid=nnn> | <job=name>] -- cancel a job")},
92  { N_("create"),     create_cmd,    _("create DB Pool from resource")},
93  { N_("delete"),     delete_cmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},
94  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate, listing gives full listing")},
95  { N_("exit"),       quit_cmd,      _("exit = quit")},
96  { N_("gui"),        gui_cmd,       _("gui [on|off] -- non-interactive gui mode")},
97  { N_("help"),       help_cmd,      _("print this command")},
98  { N_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog")},
99  { N_("label"),      label_cmd,     _("label a tape")},
100  { N_("llist"),      llist_cmd,     _("full or long list like list command")},
101  { N_("messages"),   messagescmd,   _("messages")},
102  { N_("mount"),      mount_cmd,     _("mount <storage-name>")},
103  { N_("prune"),      prunecmd,      _("prune expired records from catalog")},
104  { N_("purge"),      purgecmd,      _("purge records from catalog")},
105  { N_("python"),     python_cmd,    _("python control commands")},
106  { N_("quit"),       quit_cmd,      _("quit")},
107  { N_("query"),      querycmd,      _("query catalog")},
108  { N_("restore"),    restore_cmd,   _("restore files")},
109  { N_("relabel"),    relabel_cmd,   _("relabel a tape")},
110  { N_("release"),    release_cmd,   _("release <storage-name>")},
111  { N_("reload"),     reload_cmd,    _("reload conf file")},
112  { N_("run"),        run_cmd,       _("run <job-name>")},
113  { N_("status"),     status_cmd,    _("status [storage | client]=<name>")},
114  { N_("setdebug"),   setdebug_cmd,  _("sets debug level")},
115  { N_("setip"),      setip_cmd,     _("sets new client address -- if authorized")},
116  { N_("show"),       show_cmd,      _("show (resource records) [jobs | pools | ... | all]")},
117  { N_("sqlquery"),   sqlquerycmd,   _("use SQL to query catalog")},
118  { N_("time"),       time_cmd,      _("print current time")},
119  { N_("trace"),      trace_cmd,     _("turn on/off trace to file")},
120  { N_("unmount"),    unmount_cmd,   _("unmount <storage-name>")},
121  { N_("umount"),     unmount_cmd,   _("umount <storage-name> for old-time Unix guys")},
122  { N_("update"),     update_cmd,    _("update Volume, Pool or slots")},
123  { N_("use"),        use_cmd,       _("use catalog xxx")},
124  { N_("var"),        var_cmd,       _("does variable expansion")},
125  { N_("version"),    version_cmd,   _("print Director version")},
126  { N_("wait"),       wait_cmd,      _("wait until no jobs are running")},
127              };
128 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
129
130 /*
131  * Execute a command from the UA
132  */
133 int do_a_command(UAContext *ua, const char *cmd)
134 {
135    unsigned int i;
136    int len, stat;
137    bool found = false;
138
139    stat = 1;
140
141    Dmsg1(900, "Command: %s\n", ua->UA_sock->msg);
142    if (ua->argc == 0) {
143       return 1;
144    }
145
146    len = strlen(ua->argk[0]);
147    for (i=0; i<comsize; i++) {     /* search for command */
148       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
149          if (!acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
150             break;
151          }
152          stat = (*commands[i].func)(ua, cmd);   /* go execute command */
153          found = true;
154          break;
155       }
156    }
157    if (!found) {
158       bnet_fsend(ua->UA_sock, _("%s: is an illegal command.\n"), ua->argk[0]);
159    }
160    return stat;
161 }
162
163 /*
164  * This is a common routine used to stuff the Pool DB record defaults
165  *   into the Media DB record just before creating a media (Volume)
166  *   record.
167  */
168 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
169 {
170    mr->PoolId = pr->PoolId;
171    bstrncpy(mr->VolStatus, "Append", sizeof(mr->VolStatus));
172    mr->Recycle = pr->Recycle;
173    mr->VolRetention = pr->VolRetention;
174    mr->VolUseDuration = pr->VolUseDuration;
175    mr->MaxVolJobs = pr->MaxVolJobs;
176    mr->MaxVolFiles = pr->MaxVolFiles;
177    mr->MaxVolBytes = pr->MaxVolBytes;
178    mr->LabelType = pr->LabelType;
179 }
180
181
182 /*
183  *  Add Volumes to an existing Pool
184  */
185 static int add_cmd(UAContext *ua, const char *cmd)
186 {
187    POOL_DBR pr;
188    MEDIA_DBR mr;
189    int num, i, max, startnum;
190    int first_id = 0;
191    char name[MAX_NAME_LENGTH];
192    STORE *store;
193    int Slot = 0, InChanger = 0;
194
195    bsendmsg(ua, _(
196 "You probably don't want to be using this command since it\n"
197 "creates database records without labeling the Volumes.\n"
198 "You probably want to use the \"label\" command.\n\n"));
199
200    if (!open_db(ua)) {
201       return 1;
202    }
203
204    memset(&pr, 0, sizeof(pr));
205    memset(&mr, 0, sizeof(mr));
206
207    if (!get_pool_dbr(ua, &pr)) {
208       return 1;
209    }
210
211    Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
212       pr.MaxVols, pr.PoolType);
213
214    while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
215       bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
216       for (;;) {
217          if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
218             return 1;
219          }
220          pr.MaxVols = ua->pint32_val;
221       }
222    }
223
224    /* Get media type */
225    if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
226       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
227    } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
228       return 1;
229    }
230
231    if (pr.MaxVols == 0) {
232       max = 1000;
233    } else {
234       max = pr.MaxVols - pr.NumVols;
235    }
236    for (;;) {
237       char buf[100];
238       bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
239       if (!get_pint(ua, buf)) {
240          return 1;
241       }
242       num = ua->pint32_val;
243       if (num < 0 || num > max) {
244          bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
245          continue;
246       }
247       break;
248    }
249 getVolName:
250    if (num == 0) {
251       if (!get_cmd(ua, _("Enter Volume name: "))) {
252          return 1;
253       }
254    } else {
255       if (!get_cmd(ua, _("Enter base volume name: "))) {
256          return 1;
257       }
258    }
259    /* Don't allow | in Volume name because it is the volume separator character */
260    if (!is_volume_name_legal(ua, ua->cmd)) {
261       goto getVolName;
262    }
263    if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
264       bsendmsg(ua, _("Volume name too long.\n"));
265       goto getVolName;
266    }
267    if (strlen(ua->cmd) == 0) {
268       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
269       goto getVolName;
270    }
271
272    bstrncpy(name, ua->cmd, sizeof(name));
273    if (num > 0) {
274       bstrncat(name, "%04d", sizeof(name));
275
276       for (;;) {
277          if (!get_pint(ua, _("Enter the starting number: "))) {
278             return 1;
279          }
280          startnum = ua->pint32_val;
281          if (startnum < 1) {
282             bsendmsg(ua, _("Start number must be greater than zero.\n"));
283             continue;
284          }
285          break;
286       }
287    } else {
288       startnum = 1;
289       num = 1;
290    }
291
292    if (store && store->autochanger) {
293       if (!get_pint(ua, _("Enter slot (0 for none): "))) {
294          return 1;
295       }
296       Slot = ua->pint32_val;
297       if (!get_yesno(ua, _("InChanger? yes/no: "))) {
298          return 1;
299       }
300       InChanger = ua->pint32_val;
301    }
302
303    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
304    for (i=startnum; i < num+startnum; i++) {
305       bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
306       mr.Slot = Slot++;
307       mr.InChanger = InChanger;
308       mr.StorageId = store->StorageId;
309       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
310       if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
311          bsendmsg(ua, "%s", db_strerror(ua->db));
312          return 1;
313       }
314       if (i == startnum) {
315          first_id = mr.PoolId;
316       }
317    }
318    pr.NumVols += num;
319    Dmsg0(200, "Update pool record.\n");
320    if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
321       bsendmsg(ua, "%s", db_strerror(ua->db));
322       return 1;
323    }
324    bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
325
326    return 1;
327 }
328
329 /*
330  * Turn auto mount on/off
331  *
332  *  automount on
333  *  automount off
334  */
335 int automount_cmd(UAContext *ua, const char *cmd)
336 {
337    char *onoff;
338
339    if (ua->argc != 2) {
340       if (!get_cmd(ua, _("Turn on or off? "))) {
341             return 1;
342       }
343       onoff = ua->cmd;
344    } else {
345       onoff = ua->argk[1];
346    }
347
348    ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
349    return 1;
350 }
351
352
353 /*
354  * Cancel a job
355  */
356 static int cancel_cmd(UAContext *ua, const char *cmd)
357 {
358    int i, ret;
359    int njobs = 0;
360    JCR *jcr = NULL;
361    char JobName[MAX_NAME_LENGTH];
362
363    if (!open_db(ua)) {
364       return 1;
365    }
366
367    for (i=1; i<ua->argc; i++) {
368       if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
369          uint32_t JobId;
370          if (!ua->argv[i]) {
371             break;
372          }
373          JobId = str_to_int64(ua->argv[i]);
374          if (!(jcr=get_jcr_by_id(JobId))) {
375             bsendmsg(ua, _("JobId %s is not running. Use Job name to cancel inactive jobs.\n"),  ua->argv[i]);
376             return 1;
377          }
378          break;
379       } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
380          if (!ua->argv[i]) {
381             break;
382          }
383          if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
384             bsendmsg(ua, _("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
385             jcr = new_jcr(sizeof(JCR), dird_free_jcr);
386             bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
387          }
388          break;
389       }
390    }
391    /* If we still do not have a jcr,
392     *   throw up a list and ask the user to select one.
393     */
394    if (!jcr) {
395       char buf[1000];
396       /* Count Jobs running */
397       foreach_jcr(jcr) {
398          if (jcr->JobId == 0) {      /* this is us */
399             free_jcr(jcr);
400             continue;
401          }
402          free_jcr(jcr);
403          njobs++;
404       }
405
406       if (njobs == 0) {
407          bsendmsg(ua, _("No Jobs running.\n"));
408          return 1;
409       }
410       start_prompt(ua, _("Select Job:\n"));
411       foreach_jcr(jcr) {
412          char ed1[50];
413          if (jcr->JobId == 0) {      /* this is us */
414             free_jcr(jcr);
415             continue;
416          }
417          bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
418          add_prompt(ua, buf);
419          free_jcr(jcr);
420       }
421
422       if (do_prompt(ua, _("Job"),  _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
423          return 1;
424       }
425       if (njobs == 1) {
426          if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
427             return 1;
428          }
429       }
430       /* NOTE! This increments the ref_count */
431       sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
432       jcr = get_jcr_by_full_name(JobName);
433       if (!jcr) {
434          bsendmsg(ua, _("Job %s not found.\n"), JobName);
435          return 1;
436       }
437    }
438
439    ret = cancel_job(ua, jcr);
440    free_jcr(jcr);
441    return ret;
442 }
443
444 /*
445  * This is a common routine to create or update a
446  *   Pool DB base record from a Pool Resource. We handle
447  *   the setting of MaxVols and NumVols slightly differently
448  *   depending on if we are creating the Pool or we are
449  *   simply bringing it into agreement with the resource (updage).
450  */
451 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
452 {
453    bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
454    if (op == POOL_OP_CREATE) {
455       pr->MaxVols = pool->max_volumes;
456       pr->NumVols = 0;
457    } else {          /* update pool */
458       if (pr->MaxVols != pool->max_volumes) {
459          pr->MaxVols = pool->max_volumes;
460       }
461       if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
462          pr->MaxVols = pr->NumVols;
463       }
464    }
465    pr->LabelType = pool->LabelType;
466    pr->UseOnce = pool->use_volume_once;
467    pr->UseCatalog = pool->use_catalog;
468    pr->AcceptAnyVolume = pool->accept_any_volume;
469    pr->Recycle = pool->Recycle;
470    pr->VolRetention = pool->VolRetention;
471    pr->VolUseDuration = pool->VolUseDuration;
472    pr->MaxVolJobs = pool->MaxVolJobs;
473    pr->MaxVolFiles = pool->MaxVolFiles;
474    pr->MaxVolBytes = pool->MaxVolBytes;
475    pr->AutoPrune = pool->AutoPrune;
476    pr->Recycle = pool->Recycle;
477    if (pool->label_format) {
478       bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
479    } else {
480       bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat));    /* none */
481    }
482 }
483
484
485 /*
486  * Create a pool record from a given Pool resource
487  *   Also called from backup.c
488  * Returns: -1  on error
489  *           0  record already exists
490  *           1  record created
491  */
492
493 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
494 {
495    POOL_DBR  pr;
496
497    memset(&pr, 0, sizeof(POOL_DBR));
498
499    bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
500
501    if (db_get_pool_record(jcr, db, &pr)) {
502       /* Pool Exists */
503       if (op == POOL_OP_UPDATE) {  /* update request */
504          set_pooldbr_from_poolres(&pr, pool, op);
505          db_update_pool_record(jcr, db, &pr);
506       }
507       return 0;                       /* exists */
508    }
509
510    set_pooldbr_from_poolres(&pr, pool, op);
511
512    if (!db_create_pool_record(jcr, db, &pr)) {
513       return -1;                      /* error */
514    }
515    return 1;
516 }
517
518
519
520 /*
521  * Create a Pool Record in the database.
522  *  It is always created from the Resource record.
523  */
524 static int create_cmd(UAContext *ua, const char *cmd)
525 {
526    POOL *pool;
527
528    if (!open_db(ua)) {
529       return 1;
530    }
531
532    pool = get_pool_resource(ua);
533    if (!pool) {
534       return 1;
535    }
536
537    switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
538    case 0:
539       bsendmsg(ua, _("Error: Pool %s already exists.\n"
540                "Use update to change it.\n"), pool->hdr.name);
541       break;
542
543    case -1:
544       bsendmsg(ua, "%s", db_strerror(ua->db));
545       break;
546
547    default:
548      break;
549    }
550    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
551    return 1;
552 }
553
554
555 extern DIRRES *director;
556
557 /*
558  * Python control command
559  *  python restart (restarts interpreter)
560  */
561 static int python_cmd(UAContext *ua, const char *cmd)
562 {
563    if (ua->argc >= 1 && strcasecmp(ua->argk[1], _("restart")) == 0) {
564       term_python_interpreter();
565       init_python_interpreter(director->hdr.name, 
566          director->scripts_directory, "DirStartUp");
567       bsendmsg(ua, _("Python interpreter restarted.\n"));
568    } else {
569       bsendmsg(ua, _("Nothing done.\n"));
570    }
571    return 1;
572 }
573
574
575 /*
576  * Set a new address in a Client resource. We do this only
577  *  if the Console name is the same as the Client name
578  *  and the Console can access the client.
579  */
580 static int setip_cmd(UAContext *ua, const char *cmd)
581 {
582    CLIENT *client;
583    char buf[1024];
584    if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->hdr.name)) {
585       bsendmsg(ua, _("Illegal command from this console.\n"));
586       return 1;
587    }
588    LockRes();
589    client = (CLIENT *)GetResWithName(R_CLIENT, ua->cons->hdr.name);
590
591    if (!client) {
592       bsendmsg(ua, _("Client \"%s\" not found.\n"), ua->cons->hdr.name);
593       goto get_out;
594    }
595    if (client->address) {
596       free(client->address);
597    }
598    /* MA Bug 6 remove ifdef */
599    sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
600    client->address = bstrdup(buf);
601    bsendmsg(ua, _("Client \"%s\" address set to %s\n"),
602             client->hdr.name, client->address);
603 get_out:
604    UnlockRes();
605    return 1;
606 }
607
608
609 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
610 {
611    BSOCK *sd;
612    JCR *jcr = ua->jcr;
613
614    set_storage(jcr, store);
615    /* Try connecting for up to 15 seconds */
616    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
617       store->hdr.name, store->address, store->SDport);
618    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
619       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
620       return;
621    }
622    Dmsg0(120, _("Connected to storage daemon\n"));
623    sd = jcr->store_bsock;
624    bnet_fsend(sd, "setdebug=%d trace=%d\n", level, trace_flag);
625    if (bnet_recv(sd) >= 0) {
626       bsendmsg(ua, "%s", sd->msg);
627    }
628    bnet_sig(sd, BNET_TERMINATE);
629    bnet_close(sd);
630    jcr->store_bsock = NULL;
631    return;
632 }
633
634 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
635 {
636    BSOCK *fd;
637
638    /* Connect to File daemon */
639
640    ua->jcr->client = client;
641    /* Try to connect for 15 seconds */
642    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
643       client->hdr.name, client->address, client->FDport);
644    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
645       bsendmsg(ua, _("Failed to connect to Client.\n"));
646       return;
647    }
648    Dmsg0(120, "Connected to file daemon\n");
649    fd = ua->jcr->file_bsock;
650    bnet_fsend(fd, "setdebug=%d trace=%d\n", level, trace_flag);
651    if (bnet_recv(fd) >= 0) {
652       bsendmsg(ua, "%s", fd->msg);
653    }
654    bnet_sig(fd, BNET_TERMINATE);
655    bnet_close(fd);
656    ua->jcr->file_bsock = NULL;
657    return;
658 }
659
660
661 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
662 {
663    STORE *store, **unique_store;
664    CLIENT *client, **unique_client;
665    int i, j, found;
666
667    /* Director */
668    debug_level = level;
669
670    /* Count Storage items */
671    LockRes();
672    store = NULL;
673    i = 0;
674    foreach_res(store, R_STORAGE) {
675       i++;
676    }
677    unique_store = (STORE **) malloc(i * sizeof(STORE));
678    /* Find Unique Storage address/port */
679    store = (STORE *)GetNextRes(R_STORAGE, NULL);
680    i = 0;
681    unique_store[i++] = store;
682    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
683       found = 0;
684       for (j=0; j<i; j++) {
685          if (strcmp(unique_store[j]->address, store->address) == 0 &&
686              unique_store[j]->SDport == store->SDport) {
687             found = 1;
688             break;
689          }
690       }
691       if (!found) {
692          unique_store[i++] = store;
693          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
694       }
695    }
696    UnlockRes();
697
698    /* Call each unique Storage daemon */
699    for (j=0; j<i; j++) {
700       do_storage_setdebug(ua, unique_store[j], level, trace_flag);
701    }
702    free(unique_store);
703
704    /* Count Client items */
705    LockRes();
706    client = NULL;
707    i = 0;
708    foreach_res(client, R_CLIENT) {
709       i++;
710    }
711    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
712    /* Find Unique Client address/port */
713    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
714    i = 0;
715    unique_client[i++] = client;
716    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
717       found = 0;
718       for (j=0; j<i; j++) {
719          if (strcmp(unique_client[j]->address, client->address) == 0 &&
720              unique_client[j]->FDport == client->FDport) {
721             found = 1;
722             break;
723          }
724       }
725       if (!found) {
726          unique_client[i++] = client;
727          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
728       }
729    }
730    UnlockRes();
731
732    /* Call each unique File daemon */
733    for (j=0; j<i; j++) {
734       do_client_setdebug(ua, unique_client[j], level, trace_flag);
735    }
736    free(unique_client);
737 }
738
739 /*
740  * setdebug level=nn all trace=1/0
741  */
742 static int setdebug_cmd(UAContext *ua, const char *cmd)
743 {
744    STORE *store;
745    CLIENT *client;
746    int level;
747    int trace_flag = -1;
748    int i;
749
750    if (!open_db(ua)) {
751       return 1;
752    }
753    Dmsg1(120, "setdebug:%s:\n", cmd);
754
755    level = -1;
756    i = find_arg_with_value(ua, "level");
757    if (i >= 0) {
758       level = atoi(ua->argv[i]);
759    }
760    if (level < 0) {
761       if (!get_pint(ua, _("Enter new debug level: "))) {
762          return 1;
763       }
764       level = ua->pint32_val;
765    }
766
767    /* Look for trace flag. -1 => not change */
768    i = find_arg_with_value(ua, "trace");
769    if (i >= 0) {
770       trace_flag = atoi(ua->argv[i]);
771       if (trace_flag > 0) {
772          trace_flag = 1;
773       }
774    }
775
776    /* General debug? */
777    for (i=1; i<ua->argc; i++) {
778       if (strcasecmp(ua->argk[i], "all") == 0) {
779          do_all_setdebug(ua, level, trace_flag);
780          return 1;
781       }
782       if (strcasecmp(ua->argk[i], "dir") == 0 ||
783           strcasecmp(ua->argk[i], "director") == 0) {
784          debug_level = level;
785          set_trace(trace_flag);
786          return 1;
787       }
788       if (strcasecmp(ua->argk[i], "client") == 0 ||
789           strcasecmp(ua->argk[i], "fd") == 0) {
790          client = NULL;
791          if (ua->argv[i]) {
792             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
793             if (client) {
794                do_client_setdebug(ua, client, level, trace_flag);
795                return 1;
796             }
797          }
798          client = select_client_resource(ua);
799          if (client) {
800             do_client_setdebug(ua, client, level, trace_flag);
801             return 1;
802          }
803       }
804
805       if (strcasecmp(ua->argk[i], "store") == 0 ||
806           strcasecmp(ua->argk[i], "storage") == 0 ||
807           strcasecmp(ua->argk[i], "sd") == 0) {
808          store = NULL;
809          if (ua->argv[i]) {
810             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
811             if (store) {
812                do_storage_setdebug(ua, store, level, trace_flag);
813                return 1;
814             }
815          }
816          store = get_storage_resource(ua, false/*no default*/);
817          if (store) {
818             do_storage_setdebug(ua, store, level, trace_flag);
819             return 1;
820          }
821       }
822    }
823    /*
824     * We didn't find an appropriate keyword above, so
825     * prompt the user.
826     */
827    start_prompt(ua, _("Available daemons are: \n"));
828    add_prompt(ua, "Director");
829    add_prompt(ua, "Storage");
830    add_prompt(ua, "Client");
831    add_prompt(ua, "All");
832    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
833    case 0:                         /* Director */
834       debug_level = level;
835       set_trace(trace_flag);
836       break;
837    case 1:
838       store = get_storage_resource(ua, false/*no default*/);
839       if (store) {
840          do_storage_setdebug(ua, store, level, trace_flag);
841       }
842       break;
843    case 2:
844       client = select_client_resource(ua);
845       if (client) {
846          do_client_setdebug(ua, client, level, trace_flag);
847       }
848       break;
849    case 3:
850       do_all_setdebug(ua, level, trace_flag);
851       break;
852    default:
853       break;
854    }
855    return 1;
856 }
857
858 /*
859  * Turn debug tracing to file on/off
860  */
861 static int trace_cmd(UAContext *ua, const char *cmd)
862 {
863    char *onoff;
864
865    if (ua->argc != 2) {
866       if (!get_cmd(ua, _("Turn on or off? "))) {
867             return 1;
868       }
869       onoff = ua->cmd;
870    } else {
871       onoff = ua->argk[1];
872    }
873
874    set_trace((strcasecmp(onoff, _("off")) == 0) ? false : true);
875    return 1;
876
877 }
878
879 static int var_cmd(UAContext *ua, const char *cmd)
880 {
881    POOLMEM *val = get_pool_memory(PM_FNAME);
882    char *var;
883
884    if (!open_db(ua)) {
885       return 1;
886    }
887    for (var=ua->cmd; *var != ' '; ) {    /* skip command */
888       var++;
889    }
890    while (*var == ' ') {                 /* skip spaces */
891       var++;
892    }
893    Dmsg1(100, "Var=%s:\n", var);
894    variable_expansion(ua->jcr, var, &val);
895    bsendmsg(ua, "%s\n", val);
896    free_pool_memory(val);
897    return 1;
898 }
899
900 static int estimate_cmd(UAContext *ua, const char *cmd)
901 {
902    JOB *job = NULL;
903    CLIENT *client = NULL;
904    FILESET *fileset = NULL;
905    int listing = 0;
906    char since[MAXSTRING];
907    JCR *jcr = ua->jcr;
908
909    jcr->JobLevel = L_FULL;
910    for (int i=1; i<ua->argc; i++) {
911       if (strcasecmp(ua->argk[i], "client") == 0 ||
912           strcasecmp(ua->argk[i], "fd") == 0) {
913          if (ua->argv[i]) {
914             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
915             continue;
916          }
917       }
918       if (strcasecmp(ua->argk[i], "job") == 0) {
919          if (ua->argv[i]) {
920             job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
921             continue;
922          }
923       }
924       if (strcasecmp(ua->argk[i], "fileset") == 0) {
925          if (ua->argv[i]) {
926             fileset = (FILESET *)GetResWithName(R_FILESET, ua->argv[i]);
927             continue;
928          }
929       }
930       if (strcasecmp(ua->argk[i], "listing") == 0) {
931          listing = 1;
932          continue;
933       }
934       if (strcasecmp(ua->argk[i], "level") == 0) {
935          if (!get_level_from_name(ua->jcr, ua->argv[i])) {
936             bsendmsg(ua, _("Level %s not valid.\n"), ua->argv[i]);
937          }
938          continue;
939       }
940    }
941    if (!job && !(client && fileset)) {
942       if (!(job = select_job_resource(ua))) {
943          return 1;
944       }
945    }
946    if (!job) {
947       job = (JOB *)GetResWithName(R_JOB, ua->argk[1]);
948       if (!job) {
949          bsendmsg(ua, _("No job specified.\n"));
950          return 1;
951       }
952    }
953    if (!client) {
954       client = job->client;
955    }
956    if (!fileset) {
957       fileset = job->fileset;
958    }
959    jcr->client = client;
960    jcr->fileset = fileset;
961    close_db(ua);
962    ua->catalog = client->catalog;
963
964    if (!open_db(ua)) {
965       return 1;
966    }
967
968    jcr->job = job;
969    jcr->JobType = JT_BACKUP;
970    init_jcr_job_record(jcr);
971
972    if (!get_or_create_client_record(jcr)) {
973       return 1;
974    }
975    if (!get_or_create_fileset_record(jcr)) {
976       return 1;
977    }
978
979    get_level_since_time(ua->jcr, since, sizeof(since));
980
981    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
982       job->client->hdr.name, job->client->address, job->client->FDport);
983    if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
984       bsendmsg(ua, _("Failed to connect to Client.\n"));
985       return 1;
986    }
987
988    if (!send_include_list(jcr)) {
989       bsendmsg(ua, _("Error sending include list.\n"));
990       goto bail_out;
991    }
992
993    if (!send_exclude_list(jcr)) {
994       bsendmsg(ua, _("Error sending exclude list.\n"));
995       goto bail_out;
996    }
997
998    if (!send_level_command(jcr)) {
999       goto bail_out;
1000    }
1001
1002    bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1003    while (bnet_recv(jcr->file_bsock) >= 0) {
1004       bsendmsg(ua, "%s", jcr->file_bsock->msg);
1005    }
1006
1007 bail_out:
1008    if (jcr->file_bsock) {
1009       bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1010       bnet_close(jcr->file_bsock);
1011       jcr->file_bsock = NULL;
1012    }
1013    return 1;
1014 }
1015
1016
1017 /*
1018  * print time
1019  */
1020 static int time_cmd(UAContext *ua, const char *cmd)
1021 {
1022    char sdt[50];
1023    time_t ttime = time(NULL);
1024    struct tm tm;
1025    localtime_r(&ttime, &tm);
1026    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1027    bsendmsg(ua, "%s\n", sdt);
1028    return 1;
1029 }
1030
1031 /*
1032  * reload the conf file
1033  */
1034 extern "C" void reload_config(int sig);
1035
1036 static int reload_cmd(UAContext *ua, const char *cmd)
1037 {
1038    reload_config(1);
1039    return 1;
1040 }
1041
1042 /*
1043  * Delete Pool records (should purge Media with it).
1044  *
1045  *  delete pool=<pool-name>
1046  *  delete volume pool=<pool-name> volume=<name>
1047  *  delete jobid=xxx
1048  */
1049 static int delete_cmd(UAContext *ua, const char *cmd)
1050 {
1051    static const char *keywords[] = {
1052       N_("volume"),
1053       N_("pool"),
1054       N_("jobid"),
1055       NULL};
1056
1057    if (!open_db(ua)) {
1058       return 1;
1059    }
1060
1061    switch (find_arg_keyword(ua, keywords)) {
1062    case 0:
1063       delete_volume(ua);
1064       return 1;
1065    case 1:
1066       delete_pool(ua);
1067       return 1;
1068    case 2:
1069       int i;
1070       while ((i=find_arg(ua, "jobid")) > 0) {
1071          delete_job(ua);
1072          *ua->argk[i] = 0;         /* zap keyword already visited */
1073       }
1074       return 1;
1075    default:
1076       break;
1077    }
1078
1079    bsendmsg(ua, _(
1080 "In general it is not a good idea to delete either a\n"
1081 "Pool or a Volume since they may contain data.\n\n"));
1082
1083    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1084    case 0:
1085       delete_volume(ua);
1086       break;
1087    case 1:
1088       delete_pool(ua);
1089       break;
1090    case 2:
1091       delete_job(ua);
1092       return 1;
1093    default:
1094       bsendmsg(ua, _("Nothing done.\n"));
1095       break;
1096    }
1097    return 1;
1098 }
1099
1100
1101 /*
1102  * delete_job has been modified to parse JobID lists like the
1103  * following:
1104  * delete JobID=3,4,6,7-11,14
1105  *
1106  * Thanks to Phil Stracchino for the above addition.
1107  */
1108
1109 static void delete_job(UAContext *ua)
1110 {
1111    JobId_t JobId;
1112    char *s,*sep,*tok;
1113
1114    int i = find_arg_with_value(ua, N_("jobid"));
1115    if (i >= 0) {
1116       if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1117         s = bstrdup(ua->argv[i]);
1118         tok = s;
1119         /*
1120          * We could use strtok() here.  But we're not going to, because:
1121          * (a) strtok() is deprecated, having been replaced by strsep();
1122          * (b) strtok() is broken in significant ways.
1123          * we could use strsep() instead, but it's not universally available.
1124          * so we grow our own using strchr().
1125          */
1126         sep = strchr(tok, ',');
1127         while (sep != NULL) {
1128            *sep = '\0';
1129            if (strchr(tok, '-')) {
1130                delete_job_id_range(ua, tok);
1131            } else {
1132               JobId = str_to_int64(tok);
1133               do_job_delete(ua, JobId);
1134            }
1135            tok = ++sep;
1136            sep = strchr(tok, ',');
1137         }
1138         /* pick up the last token */
1139         if (strchr(tok, '-')) {
1140             delete_job_id_range(ua, tok);
1141         } else {
1142             JobId = str_to_int64(tok);
1143             do_job_delete(ua, JobId);
1144         }
1145
1146          free(s);
1147       } else {
1148          JobId = str_to_int64(ua->argv[i]);
1149         do_job_delete(ua, JobId);
1150       }
1151    } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1152       return;
1153    } else {
1154       JobId = ua->int64_val;
1155       do_job_delete(ua, JobId);
1156    }
1157 }
1158
1159 /*
1160  * we call delete_job_id_range to parse range tokens and iterate over ranges
1161  */
1162 static void delete_job_id_range(UAContext *ua, char *tok)
1163 {
1164    char *tok2;
1165    JobId_t j,j1,j2;
1166
1167    tok2 = strchr(tok, '-');
1168    *tok2 = '\0';
1169    tok2++;
1170    j1 = str_to_int64(tok);
1171    j2 = str_to_int64(tok2);
1172    for (j=j1; j<=j2; j++) {
1173       do_job_delete(ua, j);
1174    }
1175 }
1176
1177 /*
1178  * do_job_delete now performs the actual delete operation atomically
1179  * we always return 1 because C++ is pissy about void functions
1180  */
1181
1182 static void do_job_delete(UAContext *ua, JobId_t JobId)
1183 {
1184    POOLMEM *query = get_pool_memory(PM_MESSAGE);
1185    char ed1[50];
1186
1187    Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(JobId, ed1));
1188    db_sql_query(ua->db, query, NULL, (void *)NULL);
1189    Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(JobId, ed1));
1190    db_sql_query(ua->db, query, NULL, (void *)NULL);
1191    Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(JobId, ed1));
1192    db_sql_query(ua->db, query, NULL, (void *)NULL);
1193    free_pool_memory(query);
1194    bsendmsg(ua, _("Job %s and associated records deleted from the catalog.\n"), edit_int64(JobId, ed1));
1195 }
1196
1197 /*
1198  * Delete media records from database -- dangerous
1199  */
1200 static int delete_volume(UAContext *ua)
1201 {
1202    MEDIA_DBR mr;
1203
1204    if (!select_media_dbr(ua, &mr)) {
1205       return 1;
1206    }
1207    bsendmsg(ua, _("\nThis command will delete volume %s\n"
1208       "and all Jobs saved on that volume from the Catalog\n"),
1209       mr.VolumeName);
1210
1211    if (!get_yesno(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1212       return 1;
1213    }
1214    if (ua->pint32_val) {
1215       db_delete_media_record(ua->jcr, ua->db, &mr);
1216    }
1217    return 1;
1218 }
1219
1220 /*
1221  * Delete a pool record from the database -- dangerous
1222  */
1223 static int delete_pool(UAContext *ua)
1224 {
1225    POOL_DBR  pr;
1226
1227    memset(&pr, 0, sizeof(pr));
1228
1229    if (!get_pool_dbr(ua, &pr)) {
1230       return 1;
1231    }
1232    if (!get_yesno(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1233       return 1;
1234    }
1235    if (ua->pint32_val) {
1236       db_delete_pool_record(ua->jcr, ua->db, &pr);
1237    }
1238    return 1;
1239 }
1240
1241
1242 static void do_mount_cmd(UAContext *ua, const char *command)
1243 {
1244    STORE *store;
1245    BSOCK *sd;
1246    JCR *jcr = ua->jcr;
1247    char dev_name[MAX_NAME_LENGTH];
1248    int drive;
1249
1250    if (!open_db(ua)) {
1251       return;
1252    }
1253    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1254
1255    store = get_storage_resource(ua, true/*use default*/);
1256    if (!store) {
1257       return;
1258    }
1259    drive = ua->int32_val;
1260
1261    Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1262       store->media_type, store->dev_name(), drive);
1263
1264    set_storage(jcr, store);
1265    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1266       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1267       return;
1268    }
1269    sd = jcr->store_bsock;
1270    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1271    bash_spaces(dev_name);
1272    bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1273    while (bnet_recv(sd) >= 0) {
1274       bsendmsg(ua, "%s", sd->msg);
1275    }
1276    bnet_sig(sd, BNET_TERMINATE);
1277    bnet_close(sd);
1278    jcr->store_bsock = NULL;
1279 }
1280
1281 /*
1282  * mount [storage=<name>] [drive=nn]
1283  */
1284 static int mount_cmd(UAContext *ua, const char *cmd)
1285 {
1286    do_mount_cmd(ua, "mount");          /* mount */
1287    return 1;
1288 }
1289
1290
1291 /*
1292  * unmount [storage=<name>] [drive=nn]
1293  */
1294 static int unmount_cmd(UAContext *ua, const char *cmd)
1295 {
1296    do_mount_cmd(ua, "unmount");          /* unmount */
1297    return 1;
1298 }
1299
1300
1301 /*
1302  * release [storage=<name>] [drive=nn]
1303  */
1304 static int release_cmd(UAContext *ua, const char *cmd)
1305 {
1306    do_mount_cmd(ua, "release");          /* release */
1307    return 1;
1308 }
1309
1310
1311 /*
1312  * Switch databases
1313  *   use catalog=<name>
1314  */
1315 static int use_cmd(UAContext *ua, const char *cmd)
1316 {
1317    CAT *oldcatalog, *catalog;
1318
1319
1320    close_db(ua);                      /* close any previously open db */
1321    oldcatalog = ua->catalog;
1322
1323    if (!(catalog = get_catalog_resource(ua))) {
1324       ua->catalog = oldcatalog;
1325    } else {
1326       ua->catalog = catalog;
1327    }
1328    if (open_db(ua)) {
1329       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1330          ua->catalog->hdr.name, ua->catalog->db_name);
1331    }
1332    return 1;
1333 }
1334
1335 int quit_cmd(UAContext *ua, const char *cmd)
1336 {
1337    ua->quit = TRUE;
1338    return 1;
1339 }
1340
1341 /*
1342  * Wait until no job is running
1343  */
1344 int wait_cmd(UAContext *ua, const char *cmd)
1345 {
1346    JCR *jcr;
1347    bmicrosleep(0, 200000);            /* let job actually start */
1348    for (bool running=true; running; ) {
1349       running = false;
1350       foreach_jcr(jcr) {
1351          if (jcr->JobId != 0) {
1352             running = true;
1353             free_jcr(jcr);
1354             break;
1355          }
1356          free_jcr(jcr);
1357       }
1358       if (running) {
1359          bmicrosleep(1, 0);
1360       }
1361    }
1362    return 1;
1363 }
1364
1365
1366 static int help_cmd(UAContext *ua, const char *cmd)
1367 {
1368    unsigned int i;
1369
1370    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1371    for (i=0; i<comsize; i++) {
1372       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1373    }
1374    bsendmsg(ua, _("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1375    return 1;
1376 }
1377
1378 int qhelp_cmd(UAContext *ua, const char *cmd)
1379 {
1380    unsigned int i;
1381
1382    for (i=0; i<comsize; i++) {
1383       bsendmsg(ua, "%s %s\n", _(commands[i].key), _(commands[i].help));
1384    }
1385    return 1;
1386 }
1387
1388 static int version_cmd(UAContext *ua, const char *cmd)
1389 {
1390    bsendmsg(ua, _("%s Version: %s (%s)\n"), my_name, VERSION, BDATE);
1391    return 1;
1392 }
1393
1394
1395 /* A bit brain damaged in that if the user has not done
1396  * a "use catalog xxx" command, we simply find the first
1397  * catalog resource and open it.
1398  */
1399 int open_db(UAContext *ua)
1400 {
1401    if (ua->db) {
1402       return 1;
1403    }
1404    if (!ua->catalog) {
1405       LockRes();
1406       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1407       UnlockRes();
1408       if (!ua->catalog) {
1409          bsendmsg(ua, _("Could not find a Catalog resource\n"));
1410          return 0;
1411       } else {
1412          bsendmsg(ua, _("Using default Catalog name=%s DB=%s\n"),
1413             ua->catalog->hdr.name, ua->catalog->db_name);
1414       }
1415    }
1416
1417    ua->jcr->catalog = ua->catalog;
1418
1419    Dmsg0(150, "Open database\n");
1420    ua->db = db_init_database(ua->jcr, ua->catalog->db_name, ua->catalog->db_user,
1421                              ua->catalog->db_password, ua->catalog->db_address,
1422                              ua->catalog->db_port, ua->catalog->db_socket,
1423                              ua->catalog->mult_db_connections);
1424    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1425       bsendmsg(ua, _("Could not open database \"%s\".\n"),
1426                  ua->catalog->db_name);
1427       if (ua->db) {
1428          bsendmsg(ua, "%s", db_strerror(ua->db));
1429       }
1430       close_db(ua);
1431       return 0;
1432    }
1433    ua->jcr->db = ua->db;
1434    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1435    return 1;
1436 }
1437
1438 void close_db(UAContext *ua)
1439 {
1440    if (ua->db) {
1441       db_close_database(ua->jcr, ua->db);
1442       ua->db = NULL;
1443       if (ua->jcr) {
1444          ua->jcr->db = NULL;
1445       }
1446    }
1447 }