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