]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
tweak help message
[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> level=<level> 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=<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       jcr->file_bsock->signal(BNET_TERMINATE);
1346       jcr->file_bsock->close();
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    db_list_ctx lst;
1533
1534    if (!select_media_dbr(ua, &mr)) {
1535       return 1;
1536    }
1537    ua->warning_msg(_("\nThis command will delete volume %s\n"
1538       "and all Jobs saved on that volume from the Catalog\n"),
1539       mr.VolumeName);
1540
1541    if (find_arg(ua, "yes") >= 0) {
1542       ua->pint32_val = 1; /* Have "yes" on command line already" */
1543    } else {
1544       bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1545          mr.VolumeName);
1546       if (!get_yesno(ua, buf)) {
1547          return 1;
1548       }
1549    }
1550    if (!ua->pint32_val) {
1551       return 1;
1552    }
1553
1554    /* If not purged, do it */
1555    if (strcmp(mr.VolStatus, "Purged") != 0) {
1556       if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
1557          ua->error_msg(_("Can't list jobs on this volume\n"));
1558          return 1;
1559       }
1560       if (lst.count) {
1561          purge_jobs_from_catalog(ua, lst.list);
1562       }
1563    }
1564
1565    db_delete_media_record(ua->jcr, ua->db, &mr);
1566    return 1;
1567 }
1568
1569 /*
1570  * Delete a pool record from the database -- dangerous
1571  */
1572 static int delete_pool(UAContext *ua)
1573 {
1574    POOL_DBR  pr;
1575    char buf[200];
1576
1577    memset(&pr, 0, sizeof(pr));
1578
1579    if (!get_pool_dbr(ua, &pr)) {
1580       return 1;
1581    }
1582    bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1583       pr.Name);
1584    if (!get_yesno(ua, buf)) {
1585       return 1;
1586    }
1587    if (ua->pint32_val) {
1588       db_delete_pool_record(ua->jcr, ua->db, &pr);
1589    }
1590    return 1;
1591 }
1592
1593 int memory_cmd(UAContext *ua, const char *cmd)
1594 {
1595    list_dir_status_header(ua);
1596    sm_dump(false, true);
1597    return 1;
1598 }
1599
1600 static void do_mount_cmd(UAContext *ua, const char *command)
1601 {
1602    USTORE store;
1603    BSOCK *sd;
1604    JCR *jcr = ua->jcr;
1605    char dev_name[MAX_NAME_LENGTH];
1606    int drive;
1607    int slot = -1;
1608
1609    if (!open_client_db(ua)) {
1610       return;
1611    }
1612    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1613
1614    store.store = get_storage_resource(ua, true/*arg is storage*/);
1615    if (!store.store) {
1616       return;
1617    }
1618    pm_strcpy(store.store_source, _("unknown source"));
1619    set_wstorage(jcr, &store);
1620    drive = get_storage_drive(ua, store.store);
1621    if (strcmp(command, "mount") == 0) {
1622       slot = get_storage_slot(ua, store.store);
1623    }
1624
1625    Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1626       store.store->media_type, store.store->dev_name(), drive);
1627
1628    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1629       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1630       return;
1631    }
1632    sd = jcr->store_bsock;
1633    bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1634    bash_spaces(dev_name);
1635    if (slot > 0) {
1636       bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1637    } else {
1638       bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1639    }
1640    while (bnet_recv(sd) >= 0) {
1641       ua->send_msg("%s", sd->msg);
1642    }
1643    bnet_sig(sd, BNET_TERMINATE);
1644    bnet_close(sd);
1645    jcr->store_bsock = NULL;
1646 }
1647
1648 /*
1649  * mount [storage=<name>] [drive=nn] [slot=mm]
1650  */
1651 static int mount_cmd(UAContext *ua, const char *cmd)
1652 {
1653    do_mount_cmd(ua, "mount");          /* mount */
1654    return 1;
1655 }
1656
1657
1658 /*
1659  * unmount [storage=<name>] [drive=nn]
1660  */
1661 static int unmount_cmd(UAContext *ua, const char *cmd)
1662 {
1663    do_mount_cmd(ua, "unmount");          /* unmount */
1664    return 1;
1665 }
1666
1667
1668 /*
1669  * release [storage=<name>] [drive=nn]
1670  */
1671 static int release_cmd(UAContext *ua, const char *cmd)
1672 {
1673    do_mount_cmd(ua, "release");          /* release */
1674    return 1;
1675 }
1676
1677
1678 /*
1679  * Switch databases
1680  *   use catalog=<name>
1681  */
1682 static int use_cmd(UAContext *ua, const char *cmd)
1683 {
1684    CAT *oldcatalog, *catalog;
1685
1686
1687    close_db(ua);                      /* close any previously open db */
1688    oldcatalog = ua->catalog;
1689
1690    if (!(catalog = get_catalog_resource(ua))) {
1691       ua->catalog = oldcatalog;
1692    } else {
1693       ua->catalog = catalog;
1694    }
1695    if (open_db(ua)) {
1696       ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1697          ua->catalog->name(), ua->catalog->db_name);
1698    }
1699    return 1;
1700 }
1701
1702 int quit_cmd(UAContext *ua, const char *cmd)
1703 {
1704    ua->quit = true;
1705    return 1;
1706 }
1707
1708 /* Handler to get job status */
1709 static int status_handler(void *ctx, int num_fields, char **row)
1710 {
1711    char *val = (char *)ctx;
1712
1713    if (row[0]) {
1714       *val = row[0][0];
1715    } else {
1716       *val = '?';               /* Unknown by default */
1717    }
1718
1719    return 0;
1720 }
1721
1722 /*
1723  * Wait until no job is running
1724  */
1725 int wait_cmd(UAContext *ua, const char *cmd)
1726 {
1727    JCR *jcr;
1728    int i;
1729    time_t stop_time = 0;
1730
1731    /*
1732     * no args
1733     * Wait until no job is running
1734     */
1735    if (ua->argc == 1) {
1736       bmicrosleep(0, 200000);            /* let job actually start */
1737       for (bool running=true; running; ) {
1738          running = false;
1739          foreach_jcr(jcr) {
1740             if (jcr->JobId != 0) {
1741                running = true;
1742                break;
1743             }
1744          }
1745          endeach_jcr(jcr);
1746
1747          if (running) {
1748             bmicrosleep(1, 0);
1749          }
1750       }
1751       return 1;
1752    }
1753
1754    i = find_arg_with_value(ua, NT_("timeout")); 
1755    if (i > 0 && ua->argv[i]) {
1756       stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1757    }
1758
1759    /* we have jobid, jobname or ujobid argument */
1760
1761    uint32_t jobid = 0 ;
1762
1763    if (!open_client_db(ua)) {
1764       ua->error_msg(_("ERR: Can't open db\n")) ;
1765       return 1;
1766    }
1767
1768    for (int i=1; i<ua->argc; i++) {
1769       if (strcasecmp(ua->argk[i], "jobid") == 0) {
1770          if (!ua->argv[i]) {
1771             break;
1772          }
1773          jobid = str_to_int64(ua->argv[i]);
1774          break;
1775       } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1776                  strcasecmp(ua->argk[i], "job") == 0) {
1777          if (!ua->argv[i]) {
1778             break;
1779          }
1780          jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1781          if (jcr) {
1782             jobid = jcr->JobId ;
1783             free_jcr(jcr);
1784          }
1785          break;
1786       } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1787          if (!ua->argv[i]) {
1788             break;
1789          }
1790          jcr=get_jcr_by_full_name(ua->argv[i]) ;
1791          if (jcr) {
1792             jobid = jcr->JobId ;
1793             free_jcr(jcr);
1794          }
1795          break;
1796       /* Wait for a mount request */
1797       } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1798          for (bool waiting=false; !waiting; ) {
1799             foreach_jcr(jcr) {
1800                if (jcr->JobId != 0 && 
1801                    (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1802                   waiting = true;
1803                   break;
1804                }
1805             }
1806             endeach_jcr(jcr);
1807             if (waiting) {
1808                break;
1809             }
1810             if (stop_time && (time(NULL) >= stop_time)) {
1811                ua->warning_msg(_("Wait on mount timed out\n"));
1812                return 1;
1813             }
1814             bmicrosleep(1, 0);
1815          }
1816          return 1;
1817       }
1818    }
1819
1820    if (jobid == 0) {
1821       ua->error_msg(_("ERR: Job was not found\n"));
1822       return 1 ;
1823    }
1824
1825    /*
1826     * We wait the end of a specific job
1827     */
1828
1829    bmicrosleep(0, 200000);            /* let job actually start */
1830    for (bool running=true; running; ) {
1831       running = false;
1832
1833       jcr=get_jcr_by_id(jobid) ;
1834
1835       if (jcr) {
1836          running = true ;
1837          free_jcr(jcr);
1838       }
1839
1840       if (running) {
1841          bmicrosleep(1, 0);
1842       }
1843    }
1844
1845    /*
1846     * We have to get JobStatus
1847     */
1848
1849    int status ;
1850    char jobstatus = '?';        /* Unknown by default */
1851    char buf[256] ;
1852
1853    bsnprintf(buf, sizeof(buf),
1854              "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1855
1856
1857    db_sql_query(ua->db, buf,
1858                 status_handler, (void *)&jobstatus);
1859
1860    switch (jobstatus) {
1861    case JS_Error:
1862       status = 1 ;         /* Warning */
1863       break;
1864
1865    case JS_FatalError:
1866    case JS_ErrorTerminated:
1867    case JS_Canceled:
1868       status = 2 ;         /* Critical */
1869       break;
1870
1871    case JS_Warnings:
1872    case JS_Terminated:
1873       status = 0 ;         /* Ok */
1874       break;
1875
1876    default:
1877       status = 3 ;         /* Unknown */
1878       break;
1879    }
1880
1881    ua->send_msg("JobId=%i\n", jobid) ;
1882    ua->send_msg("JobStatus=%s (%c)\n", 
1883             job_status_to_str(jobstatus), 
1884             jobstatus) ;
1885
1886    if (ua->gui || ua->api) {
1887       ua->send_msg("ExitStatus=%i\n", status) ;
1888    }
1889
1890    return 1;
1891 }
1892
1893
1894 static int help_cmd(UAContext *ua, const char *cmd)
1895 {
1896    int i;
1897    ua->send_msg(_("  Command       Description\n  =======       ===========\n"));
1898    for (i=0; i<comsize; i++) {
1899       if (ua->argc == 2) {
1900          if (!strcasecmp(ua->argk[1], commands[i].key)) {
1901             ua->send_msg(_("  %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key, 
1902                          commands[i].help, commands[i].usage);
1903             break;
1904          }
1905       } else {
1906          ua->send_msg(_("  %-13s %s\n"), commands[i].key, commands[i].help);
1907       }
1908    }
1909    if (i == comsize && ua->argc == 2) {
1910       ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
1911    }
1912    ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1913    return 1;
1914 }
1915
1916 int qhelp_cmd(UAContext *ua, const char *cmd)
1917 {
1918    int i,j;
1919    /* Want to display only commands */
1920    j = find_arg(ua, NT_("all"));
1921    if (j >= 0) {
1922       for (i=0; i<comsize; i++) {
1923          ua->send_msg("%s\n", commands[i].key);
1924       }
1925       return 1;
1926    }
1927    /* Want to display a specific help section */
1928    j = find_arg_with_value(ua, NT_("item"));
1929    if (j >= 0 && ua->argk[j]) {
1930       for (i=0; i<comsize; i++) {
1931          if (bstrcmp(commands[i].key, ua->argv[j])) {
1932             ua->send_msg("%s\n", commands[i].usage);
1933             break;
1934          }
1935       }
1936       return 1;
1937    }
1938    /* Want to display everything */
1939    for (i=0; i<comsize; i++) {
1940       ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
1941    }
1942    return 1;
1943 }
1944
1945 #if 1 
1946 static int version_cmd(UAContext *ua, const char *cmd)
1947 {
1948    ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1949                 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1950    return 1;
1951 }
1952 #else
1953 /*
1954  *  Test code -- turned on only for debug testing 
1955  */
1956 static int version_cmd(UAContext *ua, const char *cmd)
1957 {
1958    dbid_list ids;
1959    POOL_MEM query(PM_MESSAGE);
1960    open_db(ua);
1961    Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1962    db_get_query_dbids(ua->jcr, ua->db, query, ids);
1963    ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1964    for (int i=0; i < ids.num_ids; i++) {
1965       ua->send_msg("id=%d\n", ids.DBId[i]);
1966    }
1967    close_db(ua);
1968    return 1;
1969 }
1970 #endif
1971
1972 /* 
1973  * This call uses open_client_db() and force a
1974  * new dedicated connection to the catalog
1975  */
1976 bool open_new_client_db(UAContext *ua)
1977 {   
1978    bool ret;
1979
1980    /* Force a new dedicated connection */
1981    close_db(ua);
1982    ua->force_mult_db_connections = true;
1983    ret = open_client_db(ua);
1984    ua->force_mult_db_connections = false;
1985    return ret;
1986 }
1987
1988 /* 
1989  * This call explicitly checks for a catalog=xxx and
1990  *  if given, opens that catalog.  It also checks for
1991  *  client=xxx and if found, opens the catalog 
1992  *  corresponding to that client. If we still don't 
1993  *  have a catalog, look for a Job keyword and get the
1994  *  catalog from its client record.
1995  */
1996 bool open_client_db(UAContext *ua)
1997 {
1998    int i;
1999    CAT *catalog;
2000    CLIENT *client;
2001    JOB *job;
2002
2003    /* Try for catalog keyword */
2004    i = find_arg_with_value(ua, NT_("catalog"));
2005    if (i >= 0) {
2006       if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
2007          ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
2008          return false;
2009       }
2010       catalog = GetCatalogResWithName(ua->argv[i]);
2011       if (catalog) {
2012          if (ua->catalog && ua->catalog != catalog) {
2013             close_db(ua);
2014          }
2015          ua->catalog = catalog;
2016          return open_db(ua);
2017       }
2018    }
2019
2020    /* Try for client keyword */
2021    i = find_arg_with_value(ua, NT_("client"));
2022    if (i >= 0) {
2023       if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
2024          ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
2025          return false;
2026       }
2027       client = GetClientResWithName(ua->argv[i]);
2028       if (client) {
2029          catalog = client->catalog;
2030          if (ua->catalog && ua->catalog != catalog) {
2031             close_db(ua);
2032          }
2033          if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
2034             ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
2035             return false;
2036          }
2037          ua->catalog = catalog;
2038          return open_db(ua);
2039       }
2040    }
2041
2042    /* Try for Job keyword */
2043    i = find_arg_with_value(ua, NT_("job"));
2044    if (i >= 0) {
2045       if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
2046          ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
2047          return false;
2048       }
2049       job = GetJobResWithName(ua->argv[i]);
2050       if (job) {
2051          catalog = job->client->catalog;
2052          if (ua->catalog && ua->catalog != catalog) {
2053             close_db(ua);
2054          }
2055          if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
2056             ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
2057             return false;
2058          }
2059          ua->catalog = catalog;
2060          return open_db(ua);
2061       }
2062    }
2063
2064    return open_db(ua);
2065 }
2066
2067
2068 /*
2069  * Open the catalog database.
2070  */
2071 bool open_db(UAContext *ua)
2072 {
2073    bool mult_db_conn;
2074
2075    if (ua->db) {
2076       return true;
2077    }
2078    if (!ua->catalog) {
2079       ua->catalog = get_catalog_resource(ua);
2080       if (!ua->catalog) {
2081          ua->error_msg( _("Could not find a Catalog resource\n"));
2082          return false;
2083       }
2084    }
2085
2086    /* Some modules like bvfs need their own catalog connection */
2087    mult_db_conn = ua->catalog->mult_db_connections;
2088    if (ua->force_mult_db_connections) {
2089       mult_db_conn = true;
2090    }
2091
2092    ua->jcr->catalog = ua->catalog;
2093
2094    Dmsg0(100, "UA Open database\n");
2095    ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name, 
2096                              ua->catalog->db_user,
2097                              ua->catalog->db_password, ua->catalog->db_address,
2098                              ua->catalog->db_port, ua->catalog->db_socket,
2099                              mult_db_conn);
2100    if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2101       ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2102                  ua->catalog->db_name);
2103       if (ua->db) {
2104          ua->error_msg("%s", db_strerror(ua->db));
2105       }
2106       close_db(ua);
2107       return false;
2108    }
2109    ua->jcr->db = ua->db;
2110    if (!ua->api) {
2111       ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name()); 
2112    }
2113    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2114    return true;
2115 }
2116
2117 void close_db(UAContext *ua)
2118 {
2119    if (ua->db) {
2120       db_close_database(ua->jcr, ua->db);
2121       ua->db = NULL;
2122       if (ua->jcr) {
2123          ua->jcr->db = NULL;
2124       }
2125    }
2126 }