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