]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
Add indentation in lsmark command output
[bacula/bacula] / bacula / src / dird / ua_cmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
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 three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
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.
17
18    You should have received a copy of the GNU Affero 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
21    02110-1301, USA.
22
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.
27 */
28 /*
29  *
30  *   Bacula Director -- User Agent Commands
31  *
32  *     Kern Sibbald, September MM
33  *
34  *   Version $Id$
35  */
36  
37 #include "bacula.h"
38 #include "dird.h"
39
40 #ifdef HAVE_PYTHON
41
42 #undef _POSIX_C_SOURCE
43 #include <Python.h>
44
45 #include "lib/pythonlib.h"
46
47 /* Imported Functions */
48 extern PyObject *job_getattr(PyObject *self, char *attrname);
49 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
50
51 #endif /* HAVE_PYTHON */
52
53 /* Imported subroutines */
54
55 /* Imported variables */
56 extern jobq_t job_queue;              /* job queue */
57
58
59 /* Imported functions */
60 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
61 extern int gui_cmd(UAContext *ua, const char *cmd);
62 extern int label_cmd(UAContext *ua, const char *cmd);
63 extern int list_cmd(UAContext *ua, const char *cmd);
64 extern int llist_cmd(UAContext *ua, const char *cmd);
65 extern int messagescmd(UAContext *ua, const char *cmd);
66 extern int prunecmd(UAContext *ua, const char *cmd);
67 extern int purgecmd(UAContext *ua, const char *cmd);
68 extern int querycmd(UAContext *ua, const char *cmd);
69 extern int relabel_cmd(UAContext *ua, const char *cmd);
70 extern int restore_cmd(UAContext *ua, const char *cmd);
71 extern int retentioncmd(UAContext *ua, const char *cmd);
72 extern int show_cmd(UAContext *ua, const char *cmd);
73 extern int sqlquerycmd(UAContext *ua, const char *cmd);
74 extern int status_cmd(UAContext *ua, const char *cmd);
75 extern int update_cmd(UAContext *ua, const char *cmd);
76
77 /* Forward referenced functions */
78 static int add_cmd(UAContext *ua, const char *cmd);
79 static int automount_cmd(UAContext *ua, const char *cmd);
80 static int cancel_cmd(UAContext *ua, const char *cmd);
81 static int create_cmd(UAContext *ua, const char *cmd);
82 static int delete_cmd(UAContext *ua, const char *cmd);
83 static int disable_cmd(UAContext *ua, const char *cmd);
84 static int enable_cmd(UAContext *ua, const char *cmd);
85 static int estimate_cmd(UAContext *ua, const char *cmd);
86 static int help_cmd(UAContext *ua, const char *cmd);
87 static int memory_cmd(UAContext *ua, const char *cmd);
88 static int mount_cmd(UAContext *ua, const char *cmd);
89 static int python_cmd(UAContext *ua, const char *cmd);
90 static int release_cmd(UAContext *ua, const char *cmd);
91 static int reload_cmd(UAContext *ua, const char *cmd);
92 static int setdebug_cmd(UAContext *ua, const char *cmd);
93 static int setbwlimit_cmd(UAContext *ua, const char *cmd);
94 static int setip_cmd(UAContext *ua, const char *cmd);
95 static int time_cmd(UAContext *ua, const char *cmd);
96 static int trace_cmd(UAContext *ua, const char *cmd);
97 static int unmount_cmd(UAContext *ua, const char *cmd);
98 static int use_cmd(UAContext *ua, const char *cmd);
99 static int var_cmd(UAContext *ua, const char *cmd);
100 static int version_cmd(UAContext *ua, const char *cmd);
101 static int wait_cmd(UAContext *ua, const char *cmd);
102
103 static void do_job_delete(UAContext *ua, JobId_t JobId);
104 static bool delete_job_id_range(UAContext *ua, char *tok);
105 static int delete_volume(UAContext *ua);
106 static int delete_pool(UAContext *ua);
107 static void delete_job(UAContext *ua);
108
109 int qhelp_cmd(UAContext *ua, const char *cmd);
110 int quit_cmd(UAContext *ua, const char *cmd);
111
112 /* not all in alphabetical order.  New commands are added after existing commands with similar letters
113    to prevent breakage of existing user scripts.  */
114 struct cmdstruct { 
115    const char *key;                             /* command */
116    int (*func)(UAContext *ua, const char *cmd); /* handler */
117    const char *help;            /* main purpose */
118    const char *usage;           /* all arguments to build usage */
119    const bool use_in_rs;        /* Can use it in Console RunScript */
120 };
121 static struct cmdstruct commands[] = {                                      /* Can use it in Console RunScript*/
122  { NT_("add"),        add_cmd,     _("Add media to a pool"),   NT_("pool=<pool-name> storage=<storage> jobid=<JobId>"),  false},
123  { NT_("autodisplay"), autodisplay_cmd,_("Autodisplay console messages"), NT_("on | off"),    false},
124  { NT_("automount"),   automount_cmd,  _("Automount after label"),        NT_("on | off"),    false},
125  { NT_("cancel"),     cancel_cmd,    _("Cancel a job"), NT_("jobid=<number> job=<job-name> ujobid=<unique-jobid>"), false},
126  { NT_("create"),     create_cmd,    _("Create DB Pool from resource"), NT_("pool=<pool-name>"),                    false},
127  { NT_("delete"),     delete_cmd,    _("Delete volume, pool or job"), NT_("volume=<vol-name> pool=<pool-name> jobid=<id>"), true},
128  { NT_("disable"),    disable_cmd,   _("Disable a job"), NT_("job=<name>"),        true},
129  { NT_("enable"),     enable_cmd,    _("Enable a job"), NT_("job=<name>"),          true},
130  { NT_("estimate"),   estimate_cmd,  _("Performs FileSet estimate, listing gives full listing"), 
131    NT_("fileset=<fs> client=<cli> level=<level> accurate=<yes/no> job=<job> listing"), true},
132
133  { NT_("exit"),       quit_cmd,      _("Terminate Bconsole session"), NT_(""),         false},
134  { NT_("gui"),        gui_cmd,       _("Non-interactive gui mode"),   NT_("on | off"), false},
135  { NT_("help"),       help_cmd,      _("Print help on specific command"),  
136    NT_("add autodisplay automount cancel create delete disable\n\tenable estimate exit gui label list llist"
137        "\n\tmessages memory mount prune purge python quit query\n\trestore relabel release reload run status"
138        "\n\tsetbandwidth setdebug setip show sqlquery time trace unmount\n\tumount update use var version wait"),         false},
139
140  { NT_("label"),      label_cmd,     _("Label a tape"), NT_("storage=<storage> volume=<vol> pool=<pool>"), false},
141  { NT_("list"),       list_cmd,      _("List objects from catalog"), 
142    NT_("pools | jobs | jobtotals | volume | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
143
144  { NT_("llist"),      llist_cmd,     _("Full or long list like list command"),
145    NT_("pools | jobs | jobtotals | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
146
147  { NT_("messages"),   messagescmd,   _("Display pending messages"),   NT_(""),    false},
148  { NT_("memory"),     memory_cmd,    _("Print current memory usage"), NT_(""),    true},
149  { NT_("mount"),      mount_cmd,     _("Mount storage"), 
150    NT_("storage=<storage-name> slot=<num> drive=<num> [ jobid=<id> | job=<job-name> ]"), false},
151
152  { NT_("prune"),      prunecmd,      _("Prune expired records from catalog"), 
153    NT_("files | jobs | pool=<pool> | client=<client-name> | volume=<volume-name> "), true},
154
155  { NT_("purge"),      purgecmd,      _("Purge records from catalog"), NT_("files jobs volume=<vol> [action=<action> devicetype=<type> pool=<pool> allpools storage=<st> drive=<num>]"),  true},
156  { NT_("python"),     python_cmd,    _("Python control commands"),    NT_(""),              false},
157  { NT_("quit"),       quit_cmd,      _("Terminate Bconsole session"), NT_(""),              false},
158  { NT_("query"),      querycmd,      _("Query catalog"),              NT_(""),              false},
159  { NT_("restore"),    restore_cmd,   _("Restore files"), 
160    NT_("where=</path> client=<client> storage=<storage> bootstrap=<file>"
161        "\n\tcomment=<text> jobid=<jobid> done select all"), false},
162
163  { NT_("relabel"),    relabel_cmd,   _("Relabel a tape"), 
164    NT_("storage=<storage-name> oldvolume=<old-volume-name>\n\tvolume=<newvolume-name> pool=<pool>"), false},
165
166  { NT_("release"),    release_cmd,   _("Release storage"),  NT_("storage=<storage-name>"),      false},
167  { NT_("reload"),     reload_cmd,    _("Reload conf file"), NT_(""),                  true},
168  { NT_("run"),        run_cmd,       _("Run a job"), 
169    NT_("job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
170        "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tcomment=<text> yes"), false}, 
171
172  { NT_("status"),     status_cmd,    _("Report status"), 
173    NT_("all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> slots | days=nnn"), true},
174
175  { NT_("setdebug"),   setdebug_cmd,  _("Sets debug level"), 
176    NT_("level=<nn> trace=0/1 client=<client-name> | dir | storage=<storage-name> | all"), true},
177
178  { NT_("setbandwidth"),   setbwlimit_cmd,  _("Sets bandwidth"), 
179    NT_("limit=<nn-kbs> client=<client-name> jobid=<number> job=<job-name> ujobid=<unique-jobid>"), true},
180
181  { NT_("setip"),      setip_cmd,     _("Sets new client address -- if authorized"), NT_(""),   false},
182  { NT_("show"),       show_cmd,      _("Show resource records"), 
183    NT_("job=<xxx> |  pool=<yyy> | fileset=<aaa> schedule=<sss> | client=<zzz> | disabled | all"), true},
184
185  { NT_("sqlquery"),   sqlquerycmd,   _("Use SQL to query catalog"), NT_(""),          false},
186  { NT_("time"),       time_cmd,      _("Print current time"),       NT_(""),          true},
187  { NT_("trace"),      trace_cmd,     _("Turn on/off trace to file"), NT_("on | off"), true},
188  { NT_("unmount"),    unmount_cmd,   _("Unmount storage"), 
189    NT_("storage=<storage-name> [ drive=<num> ] | jobid=<id> | job=<job-name>"), false},
190
191  { NT_("umount"),     unmount_cmd,   _("Umount - for old-time Unix guys, see unmount"), 
192    NT_("storage=<storage-name> [ drive=<num> ] | jobid=<id> | job=<job-name>"), false},
193
194  { NT_("update"),     update_cmd,    _("Update volume, pool or stats"), 
195    NT_("stats\n\tpool=<poolname>\n\tslots storage=<storage> scan"
196        "\n\tvolume=<volname> volstatus=<status> volretention=<time-def>"
197        "\n\t pool=<pool> recycle=<yes/no> slot=<number>\n\t inchanger=<yes/no>"
198        "\n\t maxvolbytes=<size> maxvolfiles=<nb> maxvoljobs=<nb>"
199        "\n\t enable=<yes/no> recyclepool=<pool> actiononpurge=<action>"),true},
200  { NT_("use"),        use_cmd,       _("Use catalog xxx"), NT_(""),     false},
201  { NT_("var"),        var_cmd,       _("Does variable expansion"), NT_(""),  false},
202  { NT_("version"),    version_cmd,   _("Print Director version"),  NT_(""),  true},
203  { NT_("wait"),       wait_cmd,      _("Wait until no jobs are running"), 
204    NT_("jobname=<name> | jobid=<nnn> | ujobid=<complete_name>"), false}
205 };
206
207 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
208
209 /*
210  * Execute a command from the UA
211  */
212 bool do_a_command(UAContext *ua)
213 {
214    int i;
215    int len;
216    bool ok = false;
217    bool found = false;
218    BSOCK *user = ua->UA_sock;
219
220
221    Dmsg1(900, "Command: %s\n", ua->argk[0]);
222    if (ua->argc == 0) {
223       return false;
224    }
225
226    while (ua->jcr->wstorage->size()) {
227       ua->jcr->wstorage->remove(0);
228    }
229
230    len = strlen(ua->argk[0]);
231    for (i=0; i<comsize; i++) {     /* search for command */
232       if (strncasecmp(ua->argk[0],  commands[i].key, len) == 0) {
233          /* Check if command permitted, but "quit" is always OK */
234          if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
235              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
236             break;
237          }
238          /* Check if this command is authorized in RunScript */
239          if (ua->runscript && !commands[i].use_in_rs) {
240             ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
241             break;
242          }
243          if (ua->api) user->signal(BNET_CMD_BEGIN);
244          ok = (*commands[i].func)(ua, ua->cmd);   /* go execute command */
245          if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
246          found = true;
247          break;
248       }
249    }
250    if (!found) {
251       ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
252       ok = false;
253    }
254    return ok;
255 }
256
257 /*
258  * This is a common routine used to stuff the Pool DB record defaults
259  *   into the Media DB record just before creating a media (Volume)
260  *   record.
261  */
262 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
263 {
264    mr->PoolId = pr->PoolId;
265    bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
266    mr->Recycle = pr->Recycle;
267    mr->VolRetention = pr->VolRetention;
268    mr->VolUseDuration = pr->VolUseDuration;
269    mr->ActionOnPurge = pr->ActionOnPurge;
270    mr->RecyclePoolId = pr->RecyclePoolId;
271    mr->MaxVolJobs = pr->MaxVolJobs;
272    mr->MaxVolFiles = pr->MaxVolFiles;
273    mr->MaxVolBytes = pr->MaxVolBytes;
274    mr->LabelType = pr->LabelType;
275    mr->Enabled = 1;
276 }
277
278
279 /*
280  *  Add Volumes to an existing Pool
281  */
282 static int add_cmd(UAContext *ua, const char *cmd)
283 {
284    POOL_DBR pr;
285    MEDIA_DBR mr;
286    int num, i, max, startnum;
287    int first_id = 0;
288    char name[MAX_NAME_LENGTH];
289    STORE *store;
290    int Slot = 0, InChanger = 0;
291
292    ua->send_msg(_(
293 "You probably don't want to be using this command since it\n"
294 "creates database records without labeling the Volumes.\n"
295 "You probably want to use the \"label\" command.\n\n"));
296
297    if (!open_client_db(ua)) {
298       return 1;
299    }
300
301    memset(&pr, 0, sizeof(pr));
302    memset(&mr, 0, sizeof(mr));
303
304    if (!get_pool_dbr(ua, &pr)) {
305       return 1;
306    }
307
308    Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
309       pr.MaxVols, pr.PoolType);
310
311    while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
312       ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
313       if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
314          return 1;
315       }
316       pr.MaxVols = ua->pint32_val;
317    }
318
319    /* Get media type */
320    if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
321       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
322    } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
323       return 1;
324    }
325
326    if (pr.MaxVols == 0) {
327       max = 1000;
328    } else {
329       max = pr.MaxVols - pr.NumVols;
330    }
331    for (;;) {
332       char buf[100];
333       bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
334       if (!get_pint(ua, buf)) {
335          return 1;
336       }
337       num = ua->pint32_val;
338       if (num < 0 || num > max) {
339          ua->warning_msg(_("The number must be between 0 and %d\n"), max);
340          continue;
341       }
342       break;
343    }
344
345    for (;;) {
346       if (num == 0) {
347          if (!get_cmd(ua, _("Enter Volume name: "))) {
348             return 1;
349          }
350       } else {
351          if (!get_cmd(ua, _("Enter base volume name: "))) {
352             return 1;
353          }
354       }
355       /* Don't allow | in Volume name because it is the volume separator character */
356       if (!is_volume_name_legal(ua, ua->cmd)) {
357          continue;
358       }
359       if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
360          ua->warning_msg(_("Volume name too long.\n"));
361          continue;
362       }
363       if (strlen(ua->cmd) == 0) {
364          ua->warning_msg(_("Volume name must be at least one character long.\n"));
365          continue;
366       }
367       break;
368    }
369
370    bstrncpy(name, ua->cmd, sizeof(name));
371    if (num > 0) {
372       bstrncat(name, "%04d", sizeof(name));
373
374       for (;;) {
375          if (!get_pint(ua, _("Enter the starting number: "))) {
376             return 1;
377          }
378          startnum = ua->pint32_val;
379          if (startnum < 1) {
380             ua->warning_msg(_("Start number must be greater than zero.\n"));
381             continue;
382          }
383          break;
384       }
385    } else {
386       startnum = 1;
387       num = 1;
388    }
389
390    if (store && store->autochanger) {
391       if (!get_pint(ua, _("Enter slot (0 for none): "))) {
392          return 1;
393       }
394       Slot = ua->pint32_val;
395       if (!get_yesno(ua, _("InChanger? yes/no: "))) {
396          return 1;
397       }
398       InChanger = ua->pint32_val;
399    }
400
401    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
402    for (i=startnum; i < num+startnum; i++) {
403       bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
404       mr.Slot = Slot++;
405       mr.InChanger = InChanger;
406       mr.StorageId = store->StorageId;
407       mr.Enabled = 1;
408       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
409       if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
410          ua->error_msg("%s", db_strerror(ua->db));
411          return 1;
412       }
413       if (i == startnum) {
414          first_id = mr.PoolId;
415       }
416    }
417    pr.NumVols += num;
418    Dmsg0(200, "Update pool record.\n");
419    if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
420       ua->warning_msg("%s", db_strerror(ua->db));
421       return 1;
422    }
423    ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
424
425    return 1;
426 }
427
428 /*
429  * Turn auto mount on/off
430  *
431  *  automount on
432  *  automount off
433  */
434 int automount_cmd(UAContext *ua, const char *cmd)
435 {
436    char *onoff;
437
438    if (ua->argc != 2) {
439       if (!get_cmd(ua, _("Turn on or off? "))) {
440             return 1;
441       }
442       onoff = ua->cmd;
443    } else {
444       onoff = ua->argk[1];
445    }
446
447    ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
448    return 1;
449 }
450
451 /*
452  * Cancel a job
453  */
454 static int cancel_cmd(UAContext *ua, const char *cmd)
455 {
456    JCR *jcr = select_running_job(ua, "cancel");
457    if (!jcr) {
458       return 1;
459    }
460    int ret = cancel_job(ua, jcr);
461    free_jcr(jcr);
462    return ret;
463 }
464
465 /*
466  * This is a common routine to create or update a
467  *   Pool DB base record from a Pool Resource. We handle
468  *   the setting of MaxVols and NumVols slightly differently
469  *   depending on if we are creating the Pool or we are
470  *   simply bringing it into agreement with the resource (updage).
471  *
472  * Caution : RecyclePoolId isn't setup in this function.
473  *           You can use set_pooldbr_recyclepoolid();
474  *
475  */
476 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
477 {
478    bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
479    if (op == POOL_OP_CREATE) {
480       pr->MaxVols = pool->max_volumes;
481       pr->NumVols = 0;
482    } else {          /* update pool */
483       if (pr->MaxVols != pool->max_volumes) {
484          pr->MaxVols = pool->max_volumes;
485       }
486       if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
487          pr->MaxVols = pr->NumVols;
488       }
489    }
490    pr->LabelType = pool->LabelType;
491    pr->UseOnce = pool->use_volume_once;
492    pr->UseCatalog = pool->use_catalog;
493    pr->Recycle = pool->Recycle;
494    pr->VolRetention = pool->VolRetention;
495    pr->VolUseDuration = pool->VolUseDuration;
496    pr->MaxVolJobs = pool->MaxVolJobs;
497    pr->MaxVolFiles = pool->MaxVolFiles;
498    pr->MaxVolBytes = pool->MaxVolBytes;
499    pr->AutoPrune = pool->AutoPrune;
500    pr->ActionOnPurge = pool->action_on_purge;
501    pr->Recycle = pool->Recycle;
502    if (pool->label_format) {
503       bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
504    } else {
505       bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat));    /* none */
506    }
507 }
508
509 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
510 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
511 {
512    POOL_DBR  pr;
513
514    if (!pool->RecyclePool && !pool->ScratchPool) {
515       return 1;
516    }
517
518    memset(&pr, 0, sizeof(POOL_DBR));
519    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
520
521    if (!db_get_pool_record(jcr, db, &pr)) {
522       return -1;                       /* not exists in database */
523    }
524
525    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
526
527    if (!set_pooldbr_references(jcr, db, &pr, pool)) {
528       return -1;                      /* error */
529    }
530
531    if (!db_update_pool_record(jcr, db, &pr)) {
532       return -1;                      /* error */
533    }
534    return 1;
535 }
536
537 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource 
538  * works with set_pooldbr_from_poolres
539  */
540 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
541 {
542    POOL_DBR rpool;
543    bool ret = true;
544
545    if (pool->RecyclePool) {
546       memset(&rpool, 0, sizeof(POOL_DBR));
547
548       bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
549       if (db_get_pool_record(jcr, db, &rpool)) {
550         pr->RecyclePoolId = rpool.PoolId;
551       } else {
552         Jmsg(jcr, M_WARNING, 0,
553         _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
554           "Try to update it with 'update pool=%s'\n"),
555         pool->name(), rpool.Name, rpool.Name,pool->name());
556
557         ret = false;
558       }
559    } else {                    /* no RecyclePool used, set it to 0 */
560       pr->RecyclePoolId = 0;
561    }
562
563    if (pool->ScratchPool) {
564       memset(&rpool, 0, sizeof(POOL_DBR));
565
566       bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
567       if (db_get_pool_record(jcr, db, &rpool)) {
568         pr->ScratchPoolId = rpool.PoolId;
569       } else {
570         Jmsg(jcr, M_WARNING, 0,
571         _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
572           "Try to update it with 'update pool=%s'\n"),
573         pool->name(), rpool.Name, rpool.Name,pool->name());
574         ret = false;
575       }
576    } else {                    /* no ScratchPool used, set it to 0 */
577       pr->ScratchPoolId = 0;
578    }
579  
580    return ret;
581 }
582
583
584 /*
585  * Create a pool record from a given Pool resource
586  *   Also called from backup.c
587  * Returns: -1  on error
588  *           0  record already exists
589  *           1  record created
590  */
591
592 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
593 {
594    POOL_DBR  pr;
595
596    memset(&pr, 0, sizeof(POOL_DBR));
597
598    bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
599
600    if (db_get_pool_record(jcr, db, &pr)) {
601       /* Pool Exists */
602       if (op == POOL_OP_UPDATE) {  /* update request */
603          set_pooldbr_from_poolres(&pr, pool, op);
604          set_pooldbr_references(jcr, db, &pr, pool);
605          db_update_pool_record(jcr, db, &pr);
606       }
607       return 0;                       /* exists */
608    }
609
610    set_pooldbr_from_poolres(&pr, pool, op);
611    set_pooldbr_references(jcr, db, &pr, pool);
612
613    if (!db_create_pool_record(jcr, db, &pr)) {
614       return -1;                      /* error */
615    }
616    return 1;
617 }
618
619
620
621 /*
622  * Create a Pool Record in the database.
623  *  It is always created from the Resource record.
624  */
625 static int create_cmd(UAContext *ua, const char *cmd)
626 {
627    POOL *pool;
628
629    if (!open_client_db(ua)) {
630       return 1;
631    }
632
633    pool = get_pool_resource(ua);
634    if (!pool) {
635       return 1;
636    }
637
638    switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
639    case 0:
640       ua->error_msg(_("Error: Pool %s already exists.\n"
641                "Use update to change it.\n"), pool->name());
642       break;
643
644    case -1:
645       ua->error_msg("%s", db_strerror(ua->db));
646       break;
647
648    default:
649      break;
650    }
651    ua->send_msg(_("Pool %s created.\n"), pool->name());
652    return 1;
653 }
654
655
656 extern DIRRES *director;
657 extern char *configfile;
658
659 /*
660  * Python control command
661  *  python restart (restarts interpreter)
662  */
663 static int python_cmd(UAContext *ua, const char *cmd)
664 {
665 #ifdef HAVE_PYTHON
666    init_python_interpreter_args python_args;
667
668    if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
669       term_python_interpreter();
670
671       python_args.progname = director->name();
672       python_args.scriptdir = director->scripts_directory;
673       python_args.modulename = "DirStartUp";
674       python_args.configfile = configfile;
675       python_args.workingdir = director->working_directory;
676       python_args.job_getattr = job_getattr;
677       python_args.job_setattr = job_setattr;
678
679       init_python_interpreter(&python_args);
680
681       ua->send_msg(_("Python interpreter restarted.\n"));
682    } else {
683 #endif /* HAVE_PYTHON */
684       ua->warning_msg(_("Nothing done.\n"));
685 #ifdef HAVE_PYTHON
686    }
687 #endif /* HAVE_PYTHON */
688    return 1;
689 }
690
691 static int setbwlimit_cmd(UAContext *ua, const char *cmd)
692 {
693    CLIENT *client=NULL;
694    char Job[MAX_NAME_LENGTH];
695    *Job=0;
696    int32_t limit=-1;
697    int i;
698
699    i = find_arg_with_value(ua, "limit");
700    if (i >= 0) {
701       limit = atoi(ua->argv[i]) * 1024;
702    }
703    if (limit < 0) {
704       if (!get_pint(ua, _("Enter new bandwidth limit kb/s: "))) {
705          return 1;
706       }
707       limit = ua->pint32_val * 1024; /* kb/s */
708    }
709
710    const char *lst[] = { "job", "jobid", "jobname", NULL };
711    if (find_arg_keyword(ua, lst) > 0) {
712       JCR *jcr = select_running_job(ua, "limit");
713       if (jcr) {
714          jcr->max_bandwidth = limit; /* TODO: see for locking (Should be safe)*/
715          bstrncpy(Job, jcr->Job, sizeof(Job));
716          client = jcr->client;
717          free_jcr(jcr);
718       } else {
719          return 1;
720       }
721
722    } else {
723       client = get_client_resource(ua);
724    }
725
726    if (!client) {
727       return 1;
728    }
729
730    /* Connect to File daemon */
731    ua->jcr->client = client;
732    ua->jcr->max_bandwidth = limit;
733
734    /* Try to connect for 15 seconds */
735    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
736       client->name(), client->address, client->FDport);
737    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
738       ua->error_msg(_("Failed to connect to Client.\n"));
739       return 1;
740    }
741    Dmsg0(120, "Connected to file daemon\n");
742    if (!send_bwlimit(ua->jcr, Job)) {
743       ua->error_msg(_("Failed to set bandwidth limit to Client.\n"));
744
745    } else {
746       ua->info_msg(_("OK Limiting bandwidth to %lldkb/s %s\n"),
747                    limit/1024, Job);
748    }
749
750    ua->jcr->file_bsock->signal(BNET_TERMINATE);
751    ua->jcr->file_bsock->close();
752    ua->jcr->file_bsock = NULL;
753    ua->jcr->client = NULL;
754    ua->jcr->max_bandwidth = 0;
755    return 1;
756 }
757
758 /*
759  * Set a new address in a Client resource. We do this only
760  *  if the Console name is the same as the Client name
761  *  and the Console can access the client.
762  */
763 static int setip_cmd(UAContext *ua, const char *cmd)
764 {
765    CLIENT *client;
766    char buf[1024];
767    if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
768       ua->error_msg(_("Unauthorized command from this console.\n"));
769       return 1;
770    }
771    LockRes();
772    client = GetClientResWithName(ua->cons->name());
773
774    if (!client) {
775       ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
776       goto get_out;
777    }
778    if (client->address) {
779       free(client->address);
780    }
781    /* MA Bug 6 remove ifdef */
782    sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
783    client->address = bstrdup(buf);
784    ua->send_msg(_("Client \"%s\" address set to %s\n"),
785             client->name(), client->address);
786 get_out:
787    UnlockRes();
788    return 1;
789 }
790
791
792 static void do_en_disable_cmd(UAContext *ua, bool setting)
793 {
794    JOB *job;
795    int i;
796
797    i = find_arg_with_value(ua, NT_("job")); 
798    if (i < 0) { 
799       job = select_enable_disable_job_resource(ua, setting);
800       if (!job) {
801          return;
802       }
803    } else {
804       LockRes();
805       job = GetJobResWithName(ua->argv[i]);
806       UnlockRes();
807    } 
808    if (!job) {
809       ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
810       return;
811    }
812
813    if (!acl_access_ok(ua, Job_ACL, job->name())) {
814       ua->error_msg(_("Unauthorized command from this console.\n"));
815       return;
816    }
817    job->enabled = setting;
818    ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
819    return;
820 }
821
822 static int enable_cmd(UAContext *ua, const char *cmd)
823 {
824    do_en_disable_cmd(ua, true);
825    return 1;
826 }
827
828 static int disable_cmd(UAContext *ua, const char *cmd)
829 {
830    do_en_disable_cmd(ua, false);
831    return 1;
832 }
833
834
835 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
836 {
837    BSOCK *sd;
838    JCR *jcr = ua->jcr;
839    USTORE lstore;
840    
841    lstore.store = store;
842    pm_strcpy(lstore.store_source, _("unknown source"));
843    set_wstorage(jcr, &lstore);
844    /* Try connecting for up to 15 seconds */
845    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
846       store->name(), store->address, store->SDport);
847    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
848       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
849       return;
850    }
851    Dmsg0(120, _("Connected to storage daemon\n"));
852    sd = jcr->store_bsock;
853    sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
854    if (sd->recv() >= 0) {
855       ua->send_msg("%s", sd->msg);
856    }
857    sd->signal(BNET_TERMINATE);
858    sd->close();
859    jcr->store_bsock = NULL;
860    return;
861 }
862
863 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
864 {
865    BSOCK *fd;
866
867    /* Connect to File daemon */
868
869    ua->jcr->client = client;
870    /* Try to connect for 15 seconds */
871    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
872       client->name(), client->address, client->FDport);
873    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
874       ua->error_msg(_("Failed to connect to Client.\n"));
875       return;
876    }
877    Dmsg0(120, "Connected to file daemon\n");
878    fd = ua->jcr->file_bsock;
879    fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
880    if (fd->recv() >= 0) {
881       ua->send_msg("%s", fd->msg);
882    }
883    fd->signal(BNET_TERMINATE);
884    fd->close();
885    ua->jcr->file_bsock = NULL;
886    return;
887 }
888
889
890 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
891 {
892    STORE *store, **unique_store;
893    CLIENT *client, **unique_client;
894    int i, j, found;
895
896    /* Director */
897    debug_level = level;
898
899    /* Count Storage items */
900    LockRes();
901    store = NULL;
902    i = 0;
903    foreach_res(store, R_STORAGE) {
904       i++;
905    }
906    unique_store = (STORE **) malloc(i * sizeof(STORE));
907    /* Find Unique Storage address/port */
908    store = (STORE *)GetNextRes(R_STORAGE, NULL);
909    i = 0;
910    unique_store[i++] = store;
911    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
912       found = 0;
913       for (j=0; j<i; j++) {
914          if (strcmp(unique_store[j]->address, store->address) == 0 &&
915              unique_store[j]->SDport == store->SDport) {
916             found = 1;
917             break;
918          }
919       }
920       if (!found) {
921          unique_store[i++] = store;
922          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
923       }
924    }
925    UnlockRes();
926
927    /* Call each unique Storage daemon */
928    for (j=0; j<i; j++) {
929       do_storage_setdebug(ua, unique_store[j], level, trace_flag);
930    }
931    free(unique_store);
932
933    /* Count Client items */
934    LockRes();
935    client = NULL;
936    i = 0;
937    foreach_res(client, R_CLIENT) {
938       i++;
939    }
940    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
941    /* Find Unique Client address/port */
942    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
943    i = 0;
944    unique_client[i++] = client;
945    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
946       found = 0;
947       for (j=0; j<i; j++) {
948          if (strcmp(unique_client[j]->address, client->address) == 0 &&
949              unique_client[j]->FDport == client->FDport) {
950             found = 1;
951             break;
952          }
953       }
954       if (!found) {
955          unique_client[i++] = client;
956          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
957       }
958    }
959    UnlockRes();
960
961    /* Call each unique File daemon */
962    for (j=0; j<i; j++) {
963       do_client_setdebug(ua, unique_client[j], level, trace_flag);
964    }
965    free(unique_client);
966 }
967
968 /*
969  * setdebug level=nn all trace=1/0
970  */
971 static int setdebug_cmd(UAContext *ua, const char *cmd)
972 {
973    STORE *store;
974    CLIENT *client;
975    int level;
976    int trace_flag = -1;
977    int i;
978
979    Dmsg1(120, "setdebug:%s:\n", cmd);
980
981    level = -1;
982    i = find_arg_with_value(ua, "level");
983    if (i >= 0) {
984       level = atoi(ua->argv[i]);
985    }
986    if (level < 0) {
987       if (!get_pint(ua, _("Enter new debug level: "))) {
988          return 1;
989       }
990       level = ua->pint32_val;
991    }
992
993    /* Look for trace flag. -1 => not change */
994    i = find_arg_with_value(ua, "trace");
995    if (i >= 0) {
996       trace_flag = atoi(ua->argv[i]);
997       if (trace_flag > 0) {
998          trace_flag = 1;
999       }
1000    }
1001
1002    /* General debug? */
1003    for (i=1; i<ua->argc; i++) {
1004       if (strcasecmp(ua->argk[i], "all") == 0) {
1005          do_all_setdebug(ua, level, trace_flag);
1006          return 1;
1007       }
1008       if (strcasecmp(ua->argk[i], "dir") == 0 ||
1009           strcasecmp(ua->argk[i], "director") == 0) {
1010          debug_level = level;
1011          set_trace(trace_flag);
1012          return 1;
1013       }
1014       if (strcasecmp(ua->argk[i], "client") == 0 ||
1015           strcasecmp(ua->argk[i], "fd") == 0) {
1016          client = NULL;
1017          if (ua->argv[i]) {
1018             client = GetClientResWithName(ua->argv[i]);
1019             if (client) {
1020                do_client_setdebug(ua, client, level, trace_flag);
1021                return 1;
1022             }
1023          }
1024          client = select_client_resource(ua);
1025          if (client) {
1026             do_client_setdebug(ua, client, level, trace_flag);
1027             return 1;
1028          }
1029       }
1030
1031       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1032           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1033           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1034          store = NULL;
1035          if (ua->argv[i]) {
1036             store = GetStoreResWithName(ua->argv[i]);
1037             if (store) {
1038                do_storage_setdebug(ua, store, level, trace_flag);
1039                return 1;
1040             }
1041          }
1042          store = get_storage_resource(ua, false/*no default*/);
1043          if (store) {
1044             do_storage_setdebug(ua, store, level, trace_flag);
1045             return 1;
1046          }
1047       }
1048    }
1049    /*
1050     * We didn't find an appropriate keyword above, so
1051     * prompt the user.
1052     */
1053    start_prompt(ua, _("Available daemons are: \n"));
1054    add_prompt(ua, _("Director"));
1055    add_prompt(ua, _("Storage"));
1056    add_prompt(ua, _("Client"));
1057    add_prompt(ua, _("All"));
1058    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1059    case 0:                         /* Director */
1060       debug_level = level;
1061       set_trace(trace_flag);
1062       break;
1063    case 1:
1064       store = get_storage_resource(ua, false/*no default*/);
1065       if (store) {
1066          do_storage_setdebug(ua, store, level, trace_flag);
1067       }
1068       break;
1069    case 2:
1070       client = select_client_resource(ua);
1071       if (client) {
1072          do_client_setdebug(ua, client, level, trace_flag);
1073       }
1074       break;
1075    case 3:
1076       do_all_setdebug(ua, level, trace_flag);
1077       break;
1078    default:
1079       break;
1080    }
1081    return 1;
1082 }
1083
1084 /*
1085  * Turn debug tracing to file on/off
1086  */
1087 static int trace_cmd(UAContext *ua, const char *cmd)
1088 {
1089    char *onoff;
1090
1091    if (ua->argc != 2) {
1092       if (!get_cmd(ua, _("Turn on or off? "))) {
1093             return 1;
1094       }
1095       onoff = ua->cmd;
1096    } else {
1097       onoff = ua->argk[1];
1098    }
1099
1100    set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1101    return 1;
1102
1103 }
1104
1105 static int var_cmd(UAContext *ua, const char *cmd)
1106 {
1107    POOLMEM *val = get_pool_memory(PM_FNAME);
1108    char *var;
1109
1110    if (!open_client_db(ua)) {
1111       return 1;
1112    }
1113    for (var=ua->cmd; *var != ' '; ) {    /* skip command */
1114       var++;
1115    }
1116    while (*var == ' ') {                 /* skip spaces */
1117       var++;
1118    }
1119    Dmsg1(100, "Var=%s:\n", var);
1120    variable_expansion(ua->jcr, var, &val);
1121    ua->send_msg("%s\n", val);
1122    free_pool_memory(val);
1123    return 1;
1124 }
1125
1126 static int estimate_cmd(UAContext *ua, const char *cmd)
1127 {
1128    JOB *job = NULL;
1129    CLIENT *client = NULL;
1130    FILESET *fileset = NULL;
1131    int listing = 0;
1132    char since[MAXSTRING];
1133    JCR *jcr = ua->jcr;
1134    int accurate=-1;
1135
1136    jcr->set_JobLevel(L_FULL);
1137    for (int i=1; i<ua->argc; i++) {
1138       if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1139           strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1140          if (ua->argv[i]) {
1141             client = GetClientResWithName(ua->argv[i]);
1142             if (!client) {
1143                ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1144                return 1;
1145             }
1146             if (!acl_access_ok(ua, Client_ACL, client->name())) {
1147                ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
1148                return 1;
1149             }
1150             continue;
1151          } else {
1152             ua->error_msg(_("Client name missing.\n"));
1153             return 1;
1154          }
1155       }
1156       if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1157          if (ua->argv[i]) {
1158             job = GetJobResWithName(ua->argv[i]);
1159             if (!job) {
1160                ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1161                return 1;
1162             }
1163             if (!acl_access_ok(ua, Job_ACL, job->name())) {
1164                ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1165                return 1;
1166             }
1167             continue;
1168          } else {
1169             ua->error_msg(_("Job name missing.\n"));
1170             return 1;
1171          }
1172
1173       }
1174       if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1175          if (ua->argv[i]) {
1176             fileset = GetFileSetResWithName(ua->argv[i]);
1177             if (!fileset) {
1178                ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1179                return 1;
1180             }
1181             if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1182                ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1183                return 1;
1184             }
1185             continue;
1186          } else {
1187             ua->error_msg(_("Fileset name missing.\n"));
1188             return 1;
1189          }
1190       }
1191       if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1192          listing = 1;
1193          continue;
1194       }
1195       if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1196          if (ua->argv[i]) {
1197             if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1198                ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1199             }
1200             continue;
1201          } else {
1202            ua->error_msg(_("Level value missing.\n"));
1203            return 1;
1204          }
1205       }
1206       if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1207          if (!is_yesno(ua->argv[i], &accurate)) {
1208             ua->error_msg(_("Invalid value for accurate. " 
1209                             "It must be yes or no.\n"));
1210          }
1211       }
1212    }
1213    if (!job && !(client && fileset)) {
1214       if (!(job = select_job_resource(ua))) {
1215          return 1;
1216       }
1217    }
1218    if (!job) {
1219       job = GetJobResWithName(ua->argk[1]);
1220       if (!job) {
1221          ua->error_msg(_("No job specified.\n"));
1222          return 1;
1223       }
1224       if (!acl_access_ok(ua, Job_ACL, job->name())) {
1225          ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1226          return 1;
1227       }
1228    }
1229    if (!client) {
1230       client = job->client;
1231    }
1232    if (!fileset) {
1233       fileset = job->fileset;
1234    }
1235    jcr->client = client;
1236    jcr->fileset = fileset;
1237    close_db(ua);
1238    if (job->pool->catalog) {
1239       ua->catalog = job->pool->catalog;
1240    } else {
1241       ua->catalog = client->catalog;
1242    }
1243
1244    if (!open_db(ua)) {
1245       return 1;
1246    }
1247
1248    jcr->job = job;
1249    jcr->set_JobType(JT_BACKUP);
1250    init_jcr_job_record(jcr);
1251
1252    if (!get_or_create_client_record(jcr)) {
1253       return 1;
1254    }
1255    if (!get_or_create_fileset_record(jcr)) {
1256       return 1;
1257    }
1258
1259    get_level_since_time(ua->jcr, since, sizeof(since));
1260
1261    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1262       jcr->client->name(), jcr->client->address, jcr->client->FDport);
1263    if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1264       ua->error_msg(_("Failed to connect to Client.\n"));
1265       return 1;
1266    }
1267
1268    if (!send_include_list(jcr)) {
1269       ua->error_msg(_("Error sending include list.\n"));
1270       goto bail_out;
1271    }
1272
1273    if (!send_exclude_list(jcr)) {
1274       ua->error_msg(_("Error sending exclude list.\n"));
1275       goto bail_out;
1276    }
1277
1278    /* The level string change if accurate mode is enabled */
1279    if (accurate >= 0) {
1280       jcr->accurate = accurate;
1281    } else {
1282       jcr->accurate = job->accurate;
1283    }
1284
1285    if (!send_level_command(jcr)) {
1286       goto bail_out;
1287    }
1288
1289    /*
1290     * If the job is in accurate mode, we send the list of
1291     * all files to FD.
1292     */
1293    Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
1294    if (!send_accurate_current_files(jcr)) {
1295       goto bail_out;
1296    }
1297
1298    bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1299    while (bnet_recv(jcr->file_bsock) >= 0) {
1300       ua->send_msg("%s", jcr->file_bsock->msg);
1301    }
1302
1303 bail_out:
1304    if (jcr->file_bsock) {
1305       jcr->file_bsock->signal(BNET_TERMINATE);
1306       jcr->file_bsock->close();
1307       jcr->file_bsock = NULL;
1308    }
1309    return 1;
1310 }
1311
1312
1313 /*
1314  * print time
1315  */
1316 static int time_cmd(UAContext *ua, const char *cmd)
1317 {
1318    char sdt[50];
1319    time_t ttime = time(NULL);
1320    struct tm tm;
1321    (void)localtime_r(&ttime, &tm);
1322    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1323    ua->send_msg("%s\n", sdt);
1324    return 1;
1325 }
1326
1327 /*
1328  * reload the conf file
1329  */
1330 extern "C" void reload_config(int sig);
1331
1332 static int reload_cmd(UAContext *ua, const char *cmd)
1333 {
1334    reload_config(1);
1335    return 1;
1336 }
1337
1338 /*
1339  * Delete Pool records (should purge Media with it).
1340  *
1341  *  delete pool=<pool-name>
1342  *  delete volume pool=<pool-name> volume=<name>
1343  *  delete jobid=xxx
1344  */
1345 static int delete_cmd(UAContext *ua, const char *cmd)
1346 {
1347    static const char *keywords[] = {
1348       NT_("volume"),
1349       NT_("pool"),
1350       NT_("jobid"),
1351       NULL};
1352
1353    if (!open_client_db(ua)) {
1354       return 1;
1355    }
1356
1357    switch (find_arg_keyword(ua, keywords)) {
1358    case 0:
1359       delete_volume(ua);
1360       return 1;
1361    case 1:
1362       delete_pool(ua);
1363       return 1;
1364    case 2:
1365       int i;
1366       while ((i=find_arg(ua, "jobid")) > 0) {
1367          delete_job(ua);
1368          *ua->argk[i] = 0;         /* zap keyword already visited */
1369       }
1370       return 1;
1371    default:
1372       break;
1373    }
1374
1375    ua->warning_msg(_(
1376 "In general it is not a good idea to delete either a\n"
1377 "Pool or a Volume since they may contain data.\n\n"));
1378
1379    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1380    case 0:
1381       delete_volume(ua);
1382       break;
1383    case 1:
1384       delete_pool(ua);
1385       break;
1386    case 2:
1387       delete_job(ua);
1388       return 1;
1389    default:
1390       ua->warning_msg(_("Nothing done.\n"));
1391       break;
1392    }
1393    return 1;
1394 }
1395
1396
1397 /*
1398  * delete_job has been modified to parse JobID lists like the
1399  * following:
1400  * delete JobID=3,4,6,7-11,14
1401  *
1402  * Thanks to Phil Stracchino for the above addition.
1403  */
1404
1405 static void delete_job(UAContext *ua)
1406 {
1407    JobId_t JobId;
1408    char *s,*sep,*tok;
1409
1410    int i = find_arg_with_value(ua, NT_("jobid"));
1411    if (i >= 0) {
1412       if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1413         s = bstrdup(ua->argv[i]);
1414         tok = s;
1415         /*
1416          * We could use strtok() here.  But we're not going to, because:
1417          * (a) strtok() is deprecated, having been replaced by strsep();
1418          * (b) strtok() is broken in significant ways.
1419          * we could use strsep() instead, but it's not universally available.
1420          * so we grow our own using strchr().
1421          */
1422         sep = strchr(tok, ',');
1423         while (sep != NULL) {
1424            *sep = '\0';
1425            if (!delete_job_id_range(ua, tok)) {
1426               JobId = str_to_int64(tok);
1427               do_job_delete(ua, JobId);
1428            }
1429            tok = ++sep;
1430            sep = strchr(tok, ',');
1431         }
1432         /* pick up the last token */
1433         if (!delete_job_id_range(ua, tok)) {
1434             JobId = str_to_int64(tok);
1435             do_job_delete(ua, JobId);
1436         }
1437
1438          free(s);
1439       } else {
1440          JobId = str_to_int64(ua->argv[i]);
1441         do_job_delete(ua, JobId);
1442       }
1443    } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1444       return;
1445    } else {
1446       JobId = ua->int64_val;
1447       do_job_delete(ua, JobId);
1448    }
1449 }
1450
1451 /*
1452  * we call delete_job_id_range to parse range tokens and iterate over ranges
1453  */
1454 static bool delete_job_id_range(UAContext *ua, char *tok)
1455 {
1456    char *tok2;
1457    JobId_t j,j1,j2;
1458
1459    tok2 = strchr(tok, '-');
1460    if (!tok2) {
1461       return false;
1462    }
1463    *tok2 = '\0';
1464    tok2++;
1465    j1 = str_to_int64(tok);
1466    j2 = str_to_int64(tok2);
1467    for (j=j1; j<=j2; j++) {
1468       do_job_delete(ua, j);
1469    }
1470    return true;
1471 }
1472
1473 /*
1474  * do_job_delete now performs the actual delete operation atomically
1475  */
1476 static void do_job_delete(UAContext *ua, JobId_t JobId)
1477 {
1478    char ed1[50];
1479
1480    edit_int64(JobId, ed1);
1481    purge_jobs_from_catalog(ua, ed1);
1482    ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1483 }
1484
1485 /*
1486  * Delete media records from database -- dangerous
1487  */
1488 static int delete_volume(UAContext *ua)
1489 {
1490    MEDIA_DBR mr;
1491    char buf[1000];
1492    db_list_ctx lst;
1493
1494    if (!select_media_dbr(ua, &mr)) {
1495       return 1;
1496    }
1497    ua->warning_msg(_("\nThis command will delete volume %s\n"
1498       "and all Jobs saved on that volume from the Catalog\n"),
1499       mr.VolumeName);
1500
1501    if (find_arg(ua, "yes") >= 0) {
1502       ua->pint32_val = 1; /* Have "yes" on command line already" */
1503    } else {
1504       bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1505          mr.VolumeName);
1506       if (!get_yesno(ua, buf)) {
1507          return 1;
1508       }
1509    }
1510    if (!ua->pint32_val) {
1511       return 1;
1512    }
1513
1514    /* If not purged, do it */
1515    if (strcmp(mr.VolStatus, "Purged") != 0) {
1516       if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
1517          ua->error_msg(_("Can't list jobs on this volume\n"));
1518          return 1;
1519       }
1520       if (lst.count) {
1521          purge_jobs_from_catalog(ua, lst.list);
1522       }
1523    }
1524
1525    db_delete_media_record(ua->jcr, ua->db, &mr);
1526    return 1;
1527 }
1528
1529 /*
1530  * Delete a pool record from the database -- dangerous
1531  */
1532 static int delete_pool(UAContext *ua)
1533 {
1534    POOL_DBR  pr;
1535    char buf[200];
1536
1537    memset(&pr, 0, sizeof(pr));
1538
1539    if (!get_pool_dbr(ua, &pr)) {
1540       return 1;
1541    }
1542    bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1543       pr.Name);
1544    if (!get_yesno(ua, buf)) {
1545       return 1;
1546    }
1547    if (ua->pint32_val) {
1548       db_delete_pool_record(ua->jcr, ua->db, &pr);
1549    }
1550    return 1;
1551 }
1552
1553 int memory_cmd(UAContext *ua, const char *cmd)
1554 {
1555    list_dir_status_header(ua);
1556    sm_dump(false, true);
1557    return 1;
1558 }
1559
1560 static void do_mount_cmd(UAContext *ua, const char *command)
1561 {
1562    USTORE store;
1563    BSOCK *sd;
1564    JCR *jcr = ua->jcr;
1565    char dev_name[MAX_NAME_LENGTH];
1566    int drive;
1567    int slot = -1;
1568
1569    if (!open_client_db(ua)) {
1570       return;
1571    }
1572    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1573
1574    store.store = get_storage_resource(ua, true/*arg is storage*/);
1575    if (!store.store) {
1576       return;
1577    }
1578    pm_strcpy(store.store_source, _("unknown source"));
1579    set_wstorage(jcr, &store);
1580    drive = get_storage_drive(ua, store.store);
1581    if (strcmp(command, "mount") == 0) {
1582       slot = get_storage_slot(ua, store.store);
1583    }
1584
1585    Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1586       store.store->media_type, store.store->dev_name(), drive);
1587
1588    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1589       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1590       return;
1591    }
1592    sd = jcr->store_bsock;
1593    bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1594    bash_spaces(dev_name);
1595    if (slot > 0) {
1596       bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1597    } else {
1598       bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1599    }
1600    while (bnet_recv(sd) >= 0) {
1601       ua->send_msg("%s", sd->msg);
1602    }
1603    bnet_sig(sd, BNET_TERMINATE);
1604    bnet_close(sd);
1605    jcr->store_bsock = NULL;
1606 }
1607
1608 /*
1609  * mount [storage=<name>] [drive=nn] [slot=mm]
1610  */
1611 static int mount_cmd(UAContext *ua, const char *cmd)
1612 {
1613    do_mount_cmd(ua, "mount");          /* mount */
1614    return 1;
1615 }
1616
1617
1618 /*
1619  * unmount [storage=<name>] [drive=nn]
1620  */
1621 static int unmount_cmd(UAContext *ua, const char *cmd)
1622 {
1623    do_mount_cmd(ua, "unmount");          /* unmount */
1624    return 1;
1625 }
1626
1627
1628 /*
1629  * release [storage=<name>] [drive=nn]
1630  */
1631 static int release_cmd(UAContext *ua, const char *cmd)
1632 {
1633    do_mount_cmd(ua, "release");          /* release */
1634    return 1;
1635 }
1636
1637
1638 /*
1639  * Switch databases
1640  *   use catalog=<name>
1641  */
1642 static int use_cmd(UAContext *ua, const char *cmd)
1643 {
1644    CAT *oldcatalog, *catalog;
1645
1646
1647    close_db(ua);                      /* close any previously open db */
1648    oldcatalog = ua->catalog;
1649
1650    if (!(catalog = get_catalog_resource(ua))) {
1651       ua->catalog = oldcatalog;
1652    } else {
1653       ua->catalog = catalog;
1654    }
1655    if (open_db(ua)) {
1656       ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1657          ua->catalog->name(), ua->catalog->db_name);
1658    }
1659    return 1;
1660 }
1661
1662 int quit_cmd(UAContext *ua, const char *cmd)
1663 {
1664    ua->quit = true;
1665    return 1;
1666 }
1667
1668 /* Handler to get job status */
1669 static int status_handler(void *ctx, int num_fields, char **row)
1670 {
1671    char *val = (char *)ctx;
1672
1673    if (row[0]) {
1674       *val = row[0][0];
1675    } else {
1676       *val = '?';               /* Unknown by default */
1677    }
1678
1679    return 0;
1680 }
1681
1682 /*
1683  * Wait until no job is running
1684  */
1685 int wait_cmd(UAContext *ua, const char *cmd)
1686 {
1687    JCR *jcr;
1688    int i;
1689    time_t stop_time = 0;
1690
1691    /*
1692     * no args
1693     * Wait until no job is running
1694     */
1695    if (ua->argc == 1) {
1696       bmicrosleep(0, 200000);            /* let job actually start */
1697       for (bool running=true; running; ) {
1698          running = false;
1699          foreach_jcr(jcr) {
1700             if (jcr->JobId != 0) {
1701                running = true;
1702                break;
1703             }
1704          }
1705          endeach_jcr(jcr);
1706
1707          if (running) {
1708             bmicrosleep(1, 0);
1709          }
1710       }
1711       return 1;
1712    }
1713
1714    i = find_arg_with_value(ua, NT_("timeout")); 
1715    if (i > 0 && ua->argv[i]) {
1716       stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1717    }
1718
1719    /* we have jobid, jobname or ujobid argument */
1720
1721    uint32_t jobid = 0 ;
1722
1723    if (!open_client_db(ua)) {
1724       ua->error_msg(_("ERR: Can't open db\n")) ;
1725       return 1;
1726    }
1727
1728    for (int i=1; i<ua->argc; i++) {
1729       if (strcasecmp(ua->argk[i], "jobid") == 0) {
1730          if (!ua->argv[i]) {
1731             break;
1732          }
1733          jobid = str_to_int64(ua->argv[i]);
1734          break;
1735       } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1736                  strcasecmp(ua->argk[i], "job") == 0) {
1737          if (!ua->argv[i]) {
1738             break;
1739          }
1740          jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1741          if (jcr) {
1742             jobid = jcr->JobId ;
1743             free_jcr(jcr);
1744          }
1745          break;
1746       } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1747          if (!ua->argv[i]) {
1748             break;
1749          }
1750          jcr=get_jcr_by_full_name(ua->argv[i]) ;
1751          if (jcr) {
1752             jobid = jcr->JobId ;
1753             free_jcr(jcr);
1754          }
1755          break;
1756       /* Wait for a mount request */
1757       } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1758          for (bool waiting=false; !waiting; ) {
1759             foreach_jcr(jcr) {
1760                if (jcr->JobId != 0 && 
1761                    (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1762                   waiting = true;
1763                   break;
1764                }
1765             }
1766             endeach_jcr(jcr);
1767             if (waiting) {
1768                break;
1769             }
1770             if (stop_time && (time(NULL) >= stop_time)) {
1771                ua->warning_msg(_("Wait on mount timed out\n"));
1772                return 1;
1773             }
1774             bmicrosleep(1, 0);
1775          }
1776          return 1;
1777       }
1778    }
1779
1780    if (jobid == 0) {
1781       ua->error_msg(_("ERR: Job was not found\n"));
1782       return 1 ;
1783    }
1784
1785    /*
1786     * We wait the end of a specific job
1787     */
1788
1789    bmicrosleep(0, 200000);            /* let job actually start */
1790    for (bool running=true; running; ) {
1791       running = false;
1792
1793       jcr=get_jcr_by_id(jobid) ;
1794
1795       if (jcr) {
1796          running = true ;
1797          free_jcr(jcr);
1798       }
1799
1800       if (running) {
1801          bmicrosleep(1, 0);
1802       }
1803    }
1804
1805    /*
1806     * We have to get JobStatus
1807     */
1808
1809    int status ;
1810    char jobstatus = '?';        /* Unknown by default */
1811    char buf[256] ;
1812
1813    bsnprintf(buf, sizeof(buf),
1814              "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1815
1816
1817    db_sql_query(ua->db, buf,
1818                 status_handler, (void *)&jobstatus);
1819
1820    switch (jobstatus) {
1821    case JS_Error:
1822       status = 1 ;         /* Warning */
1823       break;
1824
1825    case JS_FatalError:
1826    case JS_ErrorTerminated:
1827    case JS_Canceled:
1828       status = 2 ;         /* Critical */
1829       break;
1830
1831    case JS_Warnings:
1832    case JS_Terminated:
1833       status = 0 ;         /* Ok */
1834       break;
1835
1836    default:
1837       status = 3 ;         /* Unknown */
1838       break;
1839    }
1840
1841    ua->send_msg("JobId=%i\n", jobid) ;
1842    ua->send_msg("JobStatus=%s (%c)\n", 
1843             job_status_to_str(jobstatus), 
1844             jobstatus) ;
1845
1846    if (ua->gui || ua->api) {
1847       ua->send_msg("ExitStatus=%i\n", status) ;
1848    }
1849
1850    return 1;
1851 }
1852
1853
1854 static int help_cmd(UAContext *ua, const char *cmd)
1855 {
1856    int i;
1857    ua->send_msg(_("  Command       Description\n  =======       ===========\n"));
1858    for (i=0; i<comsize; i++) {
1859       if (ua->argc == 2) {
1860          if (!strcasecmp(ua->argk[1], commands[i].key)) {
1861             ua->send_msg(_("  %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key, 
1862                          commands[i].help, commands[i].usage);
1863             break;
1864          }
1865       } else {
1866          ua->send_msg(_("  %-13s %s\n"), commands[i].key, commands[i].help);
1867       }
1868    }
1869    if (i == comsize && ua->argc == 2) {
1870       ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
1871    }
1872    ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1873    return 1;
1874 }
1875
1876 int qhelp_cmd(UAContext *ua, const char *cmd)
1877 {
1878    int i,j;
1879    /* Want to display only commands */
1880    j = find_arg(ua, NT_("all"));
1881    if (j >= 0) {
1882       for (i=0; i<comsize; i++) {
1883          ua->send_msg("%s\n", commands[i].key);
1884       }
1885       return 1;
1886    }
1887    /* Want to display a specific help section */
1888    j = find_arg_with_value(ua, NT_("item"));
1889    if (j >= 0 && ua->argk[j]) {
1890       for (i=0; i<comsize; i++) {
1891          if (bstrcmp(commands[i].key, ua->argv[j])) {
1892             ua->send_msg("%s\n", commands[i].usage);
1893             break;
1894          }
1895       }
1896       return 1;
1897    }
1898    /* Want to display everything */
1899    for (i=0; i<comsize; i++) {
1900       ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
1901    }
1902    return 1;
1903 }
1904
1905 #if 1 
1906 static int version_cmd(UAContext *ua, const char *cmd)
1907 {
1908    ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1909                 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1910    return 1;
1911 }
1912 #else
1913 /*
1914  *  Test code -- turned on only for debug testing 
1915  */
1916 static int version_cmd(UAContext *ua, const char *cmd)
1917 {
1918    dbid_list ids;
1919    POOL_MEM query(PM_MESSAGE);
1920    open_db(ua);
1921    Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1922    db_get_query_dbids(ua->jcr, ua->db, query, ids);
1923    ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1924    for (int i=0; i < ids.num_ids; i++) {
1925       ua->send_msg("id=%d\n", ids.DBId[i]);
1926    }
1927    close_db(ua);
1928    return 1;
1929 }
1930 #endif
1931
1932 /* 
1933  * This call uses open_client_db() and force a
1934  * new dedicated connection to the catalog
1935  */
1936 bool open_new_client_db(UAContext *ua)
1937 {   
1938    bool ret;
1939
1940    /* Force a new dedicated connection */
1941    close_db(ua);
1942    ua->force_mult_db_connections = true;
1943    ret = open_client_db(ua);
1944    ua->force_mult_db_connections = false;
1945    return ret;
1946 }
1947
1948 /* 
1949  * This call explicitly checks for a catalog=xxx and
1950  *  if given, opens that catalog.  It also checks for
1951  *  client=xxx and if found, opens the catalog 
1952  *  corresponding to that client. If we still don't 
1953  *  have a catalog, look for a Job keyword and get the
1954  *  catalog from its client record.
1955  */
1956 bool open_client_db(UAContext *ua)
1957 {
1958    int i;
1959    CAT *catalog;
1960    CLIENT *client;
1961    JOB *job;
1962
1963    /* Try for catalog keyword */
1964    i = find_arg_with_value(ua, NT_("catalog"));
1965    if (i >= 0) {
1966       if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1967          ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1968          return false;
1969       }
1970       catalog = GetCatalogResWithName(ua->argv[i]);
1971       if (catalog) {
1972          if (ua->catalog && ua->catalog != catalog) {
1973             close_db(ua);
1974          }
1975          ua->catalog = catalog;
1976          return open_db(ua);
1977       }
1978    }
1979
1980    /* Try for client keyword */
1981    i = find_arg_with_value(ua, NT_("client"));
1982    if (i >= 0) {
1983       if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1984          ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1985          return false;
1986       }
1987       client = GetClientResWithName(ua->argv[i]);
1988       if (client) {
1989          catalog = client->catalog;
1990          if (ua->catalog && ua->catalog != catalog) {
1991             close_db(ua);
1992          }
1993          if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1994             ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1995             return false;
1996          }
1997          ua->catalog = catalog;
1998          return open_db(ua);
1999       }
2000    }
2001
2002    /* Try for Job keyword */
2003    i = find_arg_with_value(ua, NT_("job"));
2004    if (i >= 0) {
2005       if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
2006          ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
2007          return false;
2008       }
2009       job = GetJobResWithName(ua->argv[i]);
2010       if (job) {
2011          catalog = job->client->catalog;
2012          if (ua->catalog && ua->catalog != catalog) {
2013             close_db(ua);
2014          }
2015          if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
2016             ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
2017             return false;
2018          }
2019          ua->catalog = catalog;
2020          return open_db(ua);
2021       }
2022    }
2023
2024    return open_db(ua);
2025 }
2026
2027
2028 /*
2029  * Open the catalog database.
2030  */
2031 bool open_db(UAContext *ua)
2032 {
2033    bool mult_db_conn;
2034
2035    if (ua->db) {
2036       return true;
2037    }
2038    if (!ua->catalog) {
2039       ua->catalog = get_catalog_resource(ua);
2040       if (!ua->catalog) {
2041          ua->error_msg( _("Could not find a Catalog resource\n"));
2042          return false;
2043       }
2044    }
2045
2046    /* Some modules like bvfs need their own catalog connection */
2047    mult_db_conn = ua->catalog->mult_db_connections;
2048    if (ua->force_mult_db_connections) {
2049       mult_db_conn = true;
2050    }
2051
2052    ua->jcr->catalog = ua->catalog;
2053
2054    Dmsg0(100, "UA Open database\n");
2055    ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name, 
2056                              ua->catalog->db_user,
2057                              ua->catalog->db_password, ua->catalog->db_address,
2058                              ua->catalog->db_port, ua->catalog->db_socket,
2059                              mult_db_conn);
2060    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2061       ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2062                  ua->catalog->db_name);
2063       if (ua->db) {
2064          ua->error_msg("%s", db_strerror(ua->db));
2065       }
2066       close_db(ua);
2067       return false;
2068    }
2069    ua->jcr->db = ua->db;
2070    if (!ua->api) {
2071       ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name()); 
2072    }
2073    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2074    return true;
2075 }
2076
2077 void close_db(UAContext *ua)
2078 {
2079    if (ua->db) {
2080       db_close_database(ua->jcr, ua->db);
2081       ua->db = NULL;
2082       if (ua->jcr) {
2083          ua->jcr->db = NULL;
2084       }
2085    }
2086 }