]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
8d243c888d9f9f831eed27403f31020854939149
[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 ammended 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, 0)) != 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 %d is not running.\n"),  JobId);
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, _("Job %s is not running.\n"), ua->argv[i]);
385             return 1;
386          }
387          break;
388       }
389    }
390    /* If we still do not have a jcr,
391     *   throw up a list and ask the user to select one.
392     */
393    if (!jcr) {
394       char buf[1000];
395       /* Count Jobs running */
396       foreach_jcr(jcr) {
397          if (jcr->JobId == 0) {      /* this is us */
398             free_jcr(jcr);
399             continue;
400          }
401          free_jcr(jcr);
402          njobs++;
403       }
404
405       if (njobs == 0) {
406          bsendmsg(ua, _("No Jobs running.\n"));
407          return 1;
408       }
409       start_prompt(ua, _("Select Job:\n"));
410       foreach_jcr(jcr) {
411          if (jcr->JobId == 0) {      /* this is us */
412             free_jcr(jcr);
413             continue;
414          }
415          bsnprintf(buf, sizeof(buf), "JobId=%d Job=%s", jcr->JobId, jcr->Job);
416          add_prompt(ua, buf);
417          free_jcr(jcr);
418       }
419
420       if (do_prompt(ua, _("Job"),  _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
421          return 1;
422       }
423       if (njobs == 1) {
424          if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
425             return 1;
426          }
427       }
428       /* NOTE! This increments the ref_count */
429       sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
430       jcr = get_jcr_by_full_name(JobName);
431       if (!jcr) {
432          bsendmsg(ua, _("Job %s not found.\n"), JobName);
433          return 1;
434       }
435    }
436
437    ret = cancel_job(ua, jcr);
438    free_jcr(jcr);
439
440    return ret;
441 }
442
443 /*
444  * This is a common routine to create or update a
445  *   Pool DB base record from a Pool Resource. We handle
446  *   the setting of MaxVols and NumVols slightly differently
447  *   depending on if we are creating the Pool or we are
448  *   simply bringing it into agreement with the resource (updage).
449  */
450 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
451 {
452    bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
453    if (op == POOL_OP_CREATE) {
454       pr->MaxVols = pool->max_volumes;
455       pr->NumVols = 0;
456    } else {          /* update pool */
457       if (pr->MaxVols != pool->max_volumes) {
458          pr->MaxVols = pool->max_volumes;
459       }
460       if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
461          pr->MaxVols = pr->NumVols;
462       }
463    }
464    pr->LabelType = pool->LabelType;
465    pr->UseOnce = pool->use_volume_once;
466    pr->UseCatalog = pool->use_catalog;
467    pr->AcceptAnyVolume = pool->accept_any_volume;
468    pr->Recycle = pool->Recycle;
469    pr->VolRetention = pool->VolRetention;
470    pr->VolUseDuration = pool->VolUseDuration;
471    pr->MaxVolJobs = pool->MaxVolJobs;
472    pr->MaxVolFiles = pool->MaxVolFiles;
473    pr->MaxVolBytes = pool->MaxVolBytes;
474    pr->AutoPrune = pool->AutoPrune;
475    pr->Recycle = pool->Recycle;
476    if (pool->label_format) {
477       bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
478    } else {
479       bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat));    /* none */
480    }
481 }
482
483
484 /*
485  * Create a pool record from a given Pool resource
486  *   Also called from backup.c
487  * Returns: -1  on error
488  *           0  record already exists
489  *           1  record created
490  */
491
492 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
493 {
494    POOL_DBR  pr;
495
496    memset(&pr, 0, sizeof(POOL_DBR));
497
498    bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
499
500    if (db_get_pool_record(jcr, db, &pr)) {
501       /* Pool Exists */
502       if (op == POOL_OP_UPDATE) {  /* update request */
503          set_pooldbr_from_poolres(&pr, pool, op);
504          db_update_pool_record(jcr, db, &pr);
505       }
506       return 0;                       /* exists */
507    }
508
509    set_pooldbr_from_poolres(&pr, pool, op);
510
511    if (!db_create_pool_record(jcr, db, &pr)) {
512       return -1;                      /* error */
513    }
514    return 1;
515 }
516
517
518
519 /*
520  * Create a Pool Record in the database.
521  *  It is always created from the Resource record.
522  */
523 static int create_cmd(UAContext *ua, const char *cmd)
524 {
525    POOL *pool;
526
527    if (!open_db(ua)) {
528       return 1;
529    }
530
531    pool = get_pool_resource(ua);
532    if (!pool) {
533       return 1;
534    }
535
536    switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
537    case 0:
538       bsendmsg(ua, _("Error: Pool %s already exists.\n"
539                "Use update to change it.\n"), pool->hdr.name);
540       break;
541
542    case -1:
543       bsendmsg(ua, "%s", db_strerror(ua->db));
544       break;
545
546    default:
547      break;
548    }
549    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
550    return 1;
551 }
552
553
554 extern DIRRES *director;
555
556 /*
557  * Python control command
558  *  python restart (restarts interpreter)
559  */
560 static int python_cmd(UAContext *ua, const char *cmd)
561 {
562    if (strcasecmp(ua->argk[1], _("restart")) == 0) {
563       term_python_interpreter();
564       init_python_interpreter(director->hdr.name, 
565          director->scripts_directory, "DirStartUp");
566       bsendmsg(ua, _("Python interpreter restarted.\n"));
567    } else {
568       bsendmsg(ua, _("Nothing done.\n"));
569    }
570    return 1;
571 }
572
573
574 /*
575  * Set a new address in a Client resource. We do this only
576  *  if the Console name is the same as the Client name
577  *  and the Console can access the client.
578  */
579 static int setip_cmd(UAContext *ua, const char *cmd)
580 {
581    CLIENT *client;
582    char buf[1024];
583    if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->hdr.name)) {
584       bsendmsg(ua, _("Illegal command from this console.\n"));
585       return 1;
586    }
587    LockRes();
588    client = (CLIENT *)GetResWithName(R_CLIENT, ua->cons->hdr.name);
589
590    if (!client) {
591       bsendmsg(ua, _("Client \"%s\" not found.\n"), ua->cons->hdr.name);
592       goto get_out;
593    }
594    if (client->address) {
595       free(client->address);
596    }
597    /* MA Bug 6 remove ifdef */
598    sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
599    client->address = bstrdup(buf);
600    bsendmsg(ua, _("Client \"%s\" address set to %s\n"),
601             client->hdr.name, client->address);
602 get_out:
603    UnlockRes();
604    return 1;
605 }
606
607
608 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
609 {
610    BSOCK *sd;
611    JCR *jcr = ua->jcr;
612
613    set_storage(jcr, store);
614    /* Try connecting for up to 15 seconds */
615    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
616       store->hdr.name, store->address, store->SDport);
617    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
618       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
619       return;
620    }
621    Dmsg0(120, _("Connected to storage daemon\n"));
622    sd = jcr->store_bsock;
623    bnet_fsend(sd, "setdebug=%d trace=%d\n", level, trace_flag);
624    if (bnet_recv(sd) >= 0) {
625       bsendmsg(ua, "%s", sd->msg);
626    }
627    bnet_sig(sd, BNET_TERMINATE);
628    bnet_close(sd);
629    jcr->store_bsock = NULL;
630    return;
631 }
632
633 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
634 {
635    BSOCK *fd;
636
637    /* Connect to File daemon */
638
639    ua->jcr->client = client;
640    /* Try to connect for 15 seconds */
641    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
642       client->hdr.name, client->address, client->FDport);
643    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
644       bsendmsg(ua, _("Failed to connect to Client.\n"));
645       return;
646    }
647    Dmsg0(120, "Connected to file daemon\n");
648    fd = ua->jcr->file_bsock;
649    bnet_fsend(fd, "setdebug=%d trace=%d\n", level, trace_flag);
650    if (bnet_recv(fd) >= 0) {
651       bsendmsg(ua, "%s", fd->msg);
652    }
653    bnet_sig(fd, BNET_TERMINATE);
654    bnet_close(fd);
655    ua->jcr->file_bsock = NULL;
656    return;
657 }
658
659
660 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
661 {
662    STORE *store, **unique_store;
663    CLIENT *client, **unique_client;
664    int i, j, found;
665
666    /* Director */
667    debug_level = level;
668
669    /* Count Storage items */
670    LockRes();
671    store = NULL;
672    i = 0;
673    foreach_res(store, R_STORAGE) {
674       i++;
675    }
676    unique_store = (STORE **) malloc(i * sizeof(STORE));
677    /* Find Unique Storage address/port */
678    store = (STORE *)GetNextRes(R_STORAGE, NULL);
679    i = 0;
680    unique_store[i++] = store;
681    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
682       found = 0;
683       for (j=0; j<i; j++) {
684          if (strcmp(unique_store[j]->address, store->address) == 0 &&
685              unique_store[j]->SDport == store->SDport) {
686             found = 1;
687             break;
688          }
689       }
690       if (!found) {
691          unique_store[i++] = store;
692          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
693       }
694    }
695    UnlockRes();
696
697    /* Call each unique Storage daemon */
698    for (j=0; j<i; j++) {
699       do_storage_setdebug(ua, unique_store[j], level, trace_flag);
700    }
701    free(unique_store);
702
703    /* Count Client items */
704    LockRes();
705    client = NULL;
706    i = 0;
707    foreach_res(client, R_CLIENT) {
708       i++;
709    }
710    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
711    /* Find Unique Client address/port */
712    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
713    i = 0;
714    unique_client[i++] = client;
715    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
716       found = 0;
717       for (j=0; j<i; j++) {
718          if (strcmp(unique_client[j]->address, client->address) == 0 &&
719              unique_client[j]->FDport == client->FDport) {
720             found = 1;
721             break;
722          }
723       }
724       if (!found) {
725          unique_client[i++] = client;
726          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
727       }
728    }
729    UnlockRes();
730
731    /* Call each unique File daemon */
732    for (j=0; j<i; j++) {
733       do_client_setdebug(ua, unique_client[j], level, trace_flag);
734    }
735    free(unique_client);
736 }
737
738 /*
739  * setdebug level=nn all trace=1/0
740  */
741 static int setdebug_cmd(UAContext *ua, const char *cmd)
742 {
743    STORE *store;
744    CLIENT *client;
745    int level;
746    int trace_flag = -1;
747    int i;
748
749    if (!open_db(ua)) {
750       return 1;
751    }
752    Dmsg1(120, "setdebug:%s:\n", cmd);
753
754    level = -1;
755    i = find_arg_with_value(ua, _("level"));
756    if (i >= 0) {
757       level = atoi(ua->argv[i]);
758    }
759    if (level < 0) {
760       if (!get_pint(ua, _("Enter new debug level: "))) {
761          return 1;
762       }
763       level = ua->pint32_val;
764    }
765
766    /* Look for trace flag. -1 => not change */
767    i = find_arg_with_value(ua, _("trace"));
768    if (i >= 0) {
769       trace_flag = atoi(ua->argv[i]);
770       if (trace_flag > 0) {
771          trace_flag = 1;
772       }
773    }
774
775    /* General debug? */
776    for (i=1; i<ua->argc; i++) {
777       if (strcasecmp(ua->argk[i], _("all")) == 0) {
778          do_all_setdebug(ua, level, trace_flag);
779          return 1;
780       }
781       if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
782           strcasecmp(ua->argk[i], _("director")) == 0) {
783          debug_level = level;
784          set_trace(trace_flag);
785          return 1;
786       }
787       if (strcasecmp(ua->argk[i], _("client")) == 0 ||
788           strcasecmp(ua->argk[i], _("fd")) == 0) {
789          client = NULL;
790          if (ua->argv[i]) {
791             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
792             if (client) {
793                do_client_setdebug(ua, client, level, trace_flag);
794                return 1;
795             }
796          }
797          client = select_client_resource(ua);
798          if (client) {
799             do_client_setdebug(ua, client, level, trace_flag);
800             return 1;
801          }
802       }
803
804       if (strcasecmp(ua->argk[i], _("store")) == 0 ||
805           strcasecmp(ua->argk[i], _("storage")) == 0 ||
806           strcasecmp(ua->argk[i], _("sd")) == 0) {
807          store = NULL;
808          if (ua->argv[i]) {
809             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
810             if (store) {
811                do_storage_setdebug(ua, store, level, trace_flag);
812                return 1;
813             }
814          }
815          store = get_storage_resource(ua, 0);
816          if (store) {
817             do_storage_setdebug(ua, store, level, trace_flag);
818             return 1;
819          }
820       }
821    }
822    /*
823     * We didn't find an appropriate keyword above, so
824     * prompt the user.
825     */
826    start_prompt(ua, _("Available daemons are: \n"));
827    add_prompt(ua, _("Director"));
828    add_prompt(ua, _("Storage"));
829    add_prompt(ua, _("Client"));
830    add_prompt(ua, _("All"));
831    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
832    case 0:                         /* Director */
833       debug_level = level;
834       set_trace(trace_flag);
835       break;
836    case 1:
837       store = get_storage_resource(ua, 0);
838       if (store) {
839          do_storage_setdebug(ua, store, level, trace_flag);
840       }
841       break;
842    case 2:
843       client = select_client_resource(ua);
844       if (client) {
845          do_client_setdebug(ua, client, level, trace_flag);
846       }
847       break;
848    case 3:
849       do_all_setdebug(ua, level, trace_flag);
850       break;
851    default:
852       break;
853    }
854    return 1;
855 }
856
857 /*
858  * Turn debug tracing to file on/off
859  */
860 static int trace_cmd(UAContext *ua, const char *cmd)
861 {
862    char *onoff;
863
864    if (ua->argc != 2) {
865       if (!get_cmd(ua, _("Turn on or off? "))) {
866             return 1;
867       }
868       onoff = ua->cmd;
869    } else {
870       onoff = ua->argk[1];
871    }
872
873    set_trace((strcasecmp(onoff, _("off")) == 0) ? false : true);
874    return 1;
875
876 }
877
878 static int var_cmd(UAContext *ua, const char *cmd)
879 {
880    POOLMEM *val = get_pool_memory(PM_FNAME);
881    char *var;
882
883    if (!open_db(ua)) {
884       return 1;
885    }
886    for (var=ua->cmd; *var != ' '; ) {    /* skip command */
887       var++;
888    }
889    while (*var == ' ') {                 /* skip spaces */
890       var++;
891    }
892    Dmsg1(100, "Var=%s:\n", var);
893    variable_expansion(ua->jcr, var, &val);
894    bsendmsg(ua, "%s\n", val);
895    free_pool_memory(val);
896    return 1;
897 }
898
899 static int estimate_cmd(UAContext *ua, const char *cmd)
900 {
901    JOB *job = NULL;
902    CLIENT *client = NULL;
903    FILESET *fileset = NULL;
904    FILESET_DBR fsr;
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, &fsr)) {
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, _("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
1249    if (!open_db(ua)) {
1250       return;
1251    }
1252    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1253
1254    store = get_storage_resource(ua, 1);
1255    if (!store) {
1256       return;
1257    }
1258
1259    Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1260       store->media_type, store->dev_name());
1261
1262    set_storage(jcr, store);
1263    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1264       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1265       return;
1266    }
1267    sd = jcr->store_bsock;
1268    bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1269    bash_spaces(dev_name);
1270    bnet_fsend(sd, "%s %s", command, dev_name);
1271    while (bnet_recv(sd) >= 0) {
1272       bsendmsg(ua, "%s", sd->msg);
1273    }
1274    bnet_sig(sd, BNET_TERMINATE);
1275    bnet_close(sd);
1276    jcr->store_bsock = NULL;
1277 }
1278
1279 /*
1280  * mount [storage | device] <name>
1281  */
1282 static int mount_cmd(UAContext *ua, const char *cmd)
1283 {
1284    do_mount_cmd(ua, "mount");          /* mount */
1285    return 1;
1286 }
1287
1288
1289 /*
1290  * unmount [storage | device] <name>
1291  */
1292 static int unmount_cmd(UAContext *ua, const char *cmd)
1293 {
1294    do_mount_cmd(ua, "unmount");          /* unmount */
1295    return 1;
1296 }
1297
1298
1299 /*
1300  * release [storage | device] <name>
1301  */
1302 static int release_cmd(UAContext *ua, const char *cmd)
1303 {
1304    do_mount_cmd(ua, "release");          /* release */
1305    return 1;
1306 }
1307
1308
1309 /*
1310  * Switch databases
1311  *   use catalog=<name>
1312  */
1313 static int use_cmd(UAContext *ua, const char *cmd)
1314 {
1315    CAT *oldcatalog, *catalog;
1316
1317
1318    close_db(ua);                      /* close any previously open db */
1319    oldcatalog = ua->catalog;
1320
1321    if (!(catalog = get_catalog_resource(ua))) {
1322       ua->catalog = oldcatalog;
1323    } else {
1324       ua->catalog = catalog;
1325    }
1326    if (open_db(ua)) {
1327       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1328          ua->catalog->hdr.name, ua->catalog->db_name);
1329    }
1330    return 1;
1331 }
1332
1333 int quit_cmd(UAContext *ua, const char *cmd)
1334 {
1335    ua->quit = TRUE;
1336    return 1;
1337 }
1338
1339 /*
1340  * Wait until no job is running
1341  */
1342 int wait_cmd(UAContext *ua, const char *cmd)
1343 {
1344    JCR *jcr;
1345    bmicrosleep(0, 200000);            /* let job actually start */
1346    for (bool running=true; running; ) {
1347       running = false;
1348       foreach_jcr(jcr) {
1349          if (jcr->JobId != 0) {
1350             running = true;
1351             free_jcr(jcr);
1352             break;
1353          }
1354          free_jcr(jcr);
1355       }
1356       if (running) {
1357          bmicrosleep(1, 0);
1358       }
1359    }
1360    return 1;
1361 }
1362
1363
1364 static int help_cmd(UAContext *ua, const char *cmd)
1365 {
1366    unsigned int i;
1367
1368    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1369    for (i=0; i<comsize; i++) {
1370       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1371    }
1372    bsendmsg(ua, _("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1373    return 1;
1374 }
1375
1376 int qhelp_cmd(UAContext *ua, const char *cmd)
1377 {
1378    unsigned int i;
1379
1380    for (i=0; i<comsize; i++) {
1381       bsendmsg(ua, _("%s %s\n"), _(commands[i].key), _(commands[i].help));
1382    }
1383    return 1;
1384 }
1385
1386 static int version_cmd(UAContext *ua, const char *cmd)
1387 {
1388    bsendmsg(ua, "%s Version: " VERSION " (" BDATE ")\n", my_name);
1389    return 1;
1390 }
1391
1392
1393 /* A bit brain damaged in that if the user has not done
1394  * a "use catalog xxx" command, we simply find the first
1395  * catalog resource and open it.
1396  */
1397 int open_db(UAContext *ua)
1398 {
1399    if (ua->db) {
1400       return 1;
1401    }
1402    if (!ua->catalog) {
1403       LockRes();
1404       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1405       UnlockRes();
1406       if (!ua->catalog) {
1407          bsendmsg(ua, _("Could not find a Catalog resource\n"));
1408          return 0;
1409       } else {
1410          bsendmsg(ua, _("Using default Catalog name=%s DB=%s\n"),
1411             ua->catalog->hdr.name, ua->catalog->db_name);
1412       }
1413    }
1414
1415    ua->jcr->catalog = ua->catalog;
1416
1417    Dmsg0(150, "Open database\n");
1418    ua->db = db_init_database(ua->jcr, ua->catalog->db_name, ua->catalog->db_user,
1419                              ua->catalog->db_password, ua->catalog->db_address,
1420                              ua->catalog->db_port, ua->catalog->db_socket,
1421                              ua->catalog->mult_db_connections);
1422    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1423       bsendmsg(ua, _("Could not open database \"%s\".\n"),
1424                  ua->catalog->db_name);
1425       if (ua->db) {
1426          bsendmsg(ua, "%s", db_strerror(ua->db));
1427       }
1428       close_db(ua);
1429       return 0;
1430    }
1431    ua->jcr->db = ua->db;
1432    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1433    return 1;
1434 }
1435
1436 void close_db(UAContext *ua)
1437 {
1438    if (ua->db) {
1439       db_close_database(ua->jcr, ua->db);
1440       ua->db = NULL;
1441       if (ua->jcr) {
1442          ua->jcr->db = NULL;
1443       }
1444    }
1445 }