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