]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
Fix scheduled times + add Priority to run start prompt
[bacula/bacula] / bacula / src / dird / ua_cmds.c
1 /*
2  *
3  *   Bacula Director -- User Agent Commands
4  *
5  *     Kern Sibbald, September MM
6  *
7  *   Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Imported subroutines */
34
35 /* Imported variables */
36 extern int r_first;
37 extern int r_last;
38 extern struct s_res resources[];
39 extern char my_name[];
40 #ifndef USE_SEMAPHORE 
41 #ifdef JOB_QUEUE
42 extern jobq_t job_queue;              /* job queue */
43 #else
44 extern workq_t job_wq;                /* work queue */
45 #endif
46 #endif
47
48 extern char *list_pool;
49
50 /* Imported functions */
51 extern int statuscmd(UAContext *ua, char *cmd);
52 extern int listcmd(UAContext *ua, char *cmd);
53 extern int llistcmd(UAContext *ua, char *cmd);
54 extern int show_cmd(UAContext *ua, char *cmd);
55 extern int messagescmd(UAContext *ua, char *cmd);
56 extern int autodisplaycmd(UAContext *ua, char *cmd);
57 extern int sqlquerycmd(UAContext *ua, char *cmd);
58 extern int querycmd(UAContext *ua, char *cmd);
59 extern int runcmd(UAContext *ua, char *cmd);
60 extern int retentioncmd(UAContext *ua, char *cmd);
61 extern int prunecmd(UAContext *ua, char *cmd);
62 extern int purgecmd(UAContext *ua, char *cmd);
63 extern int restorecmd(UAContext *ua, char *cmd);
64 extern int label_cmd(UAContext *ua, char *cmd);
65 extern int relabel_cmd(UAContext *ua, char *cmd);
66 extern int update_slots(UAContext *ua);  /* ua_label.c */
67
68 /* Forward referenced functions */
69 static int add_cmd(UAContext *ua, char *cmd),  createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
70 static int setdebug_cmd(UAContext *ua, char *cmd);
71 static int var_cmd(UAContext *ua, char *cmd);
72 static int estimate_cmd(UAContext *ua, char *cmd);
73 static int help_cmd(UAContext *ua, char *cmd);
74 static int delete_cmd(UAContext *ua, char *cmd);
75 static int use_cmd(UAContext *ua, char *cmd),  unmount_cmd(UAContext *ua, char *cmd);
76 static int version_cmd(UAContext *ua, char *cmd), automount_cmd(UAContext *ua, char *cmd);
77 static int time_cmd(UAContext *ua, char *cmd);
78 static int update_volume(UAContext *ua);
79 static int update_pool(UAContext *ua);
80 static int delete_volume(UAContext *ua);
81 static int delete_pool(UAContext *ua);
82 static int mount_cmd(UAContext *ua, char *cmd);
83 static int release_cmd(UAContext *ua, char *cmd);
84 static int update_cmd(UAContext *ua, char *cmd);
85 static int wait_cmd(UAContext *ua, char *cmd);
86
87 int quit_cmd(UAContext *ua, char *cmd);
88
89
90 struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; }; 
91 static struct cmdstruct commands[] = {
92  { N_("add"),        add_cmd,       _("add media to a pool")},
93  { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")},
94  { N_("automount"),   automount_cmd,   _("automount [on/off] -- after label")},
95  { N_("cancel"),     cancelcmd,     _("cancel job=nnn -- cancel a job")},
96  { N_("create"),     createcmd,     _("create DB Pool from resource")},  
97  { N_("delete"),     delete_cmd,    _("delete [pool=<pool-name> | media volume=<volume-name>]")},    
98  { N_("estimate"),   estimate_cmd,  _("performs FileSet estimate debug=1 give full listing")},
99  { N_("exit"),       quit_cmd,      _("exit = quit")},
100  { N_("help"),       help_cmd,      _("print this command")},
101  { N_("label"),      label_cmd,     _("label a tape")},
102  { N_("list"),       listcmd,       _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
103  { N_("llist"),      llistcmd,      _("full or long list like list command")},
104  { N_("messages"),   messagescmd,   _("messages")},
105  { N_("mount"),      mount_cmd,     _("mount <storage-name>")},
106  { N_("prune"),      prunecmd,      _("prune expired records from catalog")},
107  { N_("purge"),      purgecmd,      _("purge records from catalog")},
108  { N_("query"),      querycmd,      _("query catalog")},
109  { N_("quit"),       quit_cmd,      _("quit")},
110  { N_("relabel"),    relabel_cmd,   _("relabel a tape")},
111  { N_("release"),    release_cmd,   _("release <storage-name>")},
112  { N_("restore"),    restorecmd,    _("restore files")},
113  { N_("run"),        runcmd,        _("run <job-name>")},
114  { N_("setdebug"),   setdebug_cmd,  _("sets debug level")},
115  { N_("show"),       show_cmd,      _("show (resource records) [jobs | pools | ... | all]")},
116  { N_("sqlquery"),   sqlquerycmd,   _("use SQL to query catalog")}, 
117  { N_("status"),     statuscmd,     _("status [storage | client]=<name>")},
118  { N_("time"),       time_cmd,      _("print current time")},
119  { N_("unmount"),    unmount_cmd,   _("unmount <storage-name>")},
120  { N_("update"),     update_cmd,    _("update Volume or Pool")},
121  { N_("use"),        use_cmd,       _("use catalog xxx")},
122  { N_("var"),        var_cmd,       _("does variable expansion")},
123  { N_("version"),    version_cmd,   _("print Director version")},
124  { N_("wait"),       wait_cmd,      _("wait until no jobs are running")},
125              };
126 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
127
128 /*
129  * Execute a command from the UA
130  */
131 int do_a_command(UAContext *ua, char *cmd)
132 {
133    unsigned int i;
134    int len, stat;
135    int found;
136
137    found = 0;
138    stat = 1;
139
140    Dmsg1(120, "Command: %s\n", ua->UA_sock->msg);
141    if (ua->argc == 0) {
142       return 1;
143    }
144
145    len = strlen(ua->argk[0]);
146    for (i=0; i<comsize; i++) {     /* search for command */
147       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
148          stat = (*commands[i].func)(ua, cmd);   /* go execute command */
149          found = 1;
150          break;
151       }
152    }
153    if (!found) {
154       pm_strcat(&ua->UA_sock->msg, _(": is an illegal command\n"));
155       ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
156       bnet_send(ua->UA_sock);
157    }
158    return stat;
159 }
160
161 /*
162  * This is a common routine used to stuff the Pool DB record defaults
163  *   into the Media DB record just before creating a media (Volume) 
164  *   record.
165  */
166 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
167 {
168    mr->PoolId = pr->PoolId;
169    strcpy(mr->VolStatus, "Append");
170    mr->Recycle = pr->Recycle;
171    mr->VolRetention = pr->VolRetention;
172    mr->VolUseDuration = pr->VolUseDuration;
173    mr->MaxVolJobs = pr->MaxVolJobs;
174    mr->MaxVolFiles = pr->MaxVolFiles;
175    mr->MaxVolBytes = pr->MaxVolBytes;
176 }
177
178
179 /*
180  *  Add Volumes to an existing Pool
181  */
182 static int add_cmd(UAContext *ua, char *cmd) 
183 {
184    POOL_DBR pr;
185    MEDIA_DBR mr;
186    int num, i, max, startnum;
187    int first_id = 0;
188    char name[MAX_NAME_LENGTH];
189    STORE *store;
190    int slot = 0;
191
192    bsendmsg(ua, _(
193 "You probably don't want to be using this command since it\n"
194 "creates database records without labeling the Volumes.\n"
195 "You probably want to use the \"label\" command.\n\n"));
196
197    if (!open_db(ua)) {
198       return 1;
199    }
200
201    memset(&pr, 0, sizeof(pr));
202    memset(&mr, 0, sizeof(mr));
203
204    if (!get_pool_dbr(ua, &pr)) {
205       return 1;
206    }
207
208    Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
209       pr.MaxVols, pr.PoolType);
210
211    while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
212       bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
213       for (;;) {
214          if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
215             return 1;
216          }
217          pr.MaxVols = ua->pint32_val;
218       }
219    }
220
221    /* Get media type */
222    if ((store = get_storage_resource(ua, 0)) != NULL) {
223       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
224    } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
225       return 1;
226    }
227       
228    if (pr.MaxVols == 0) {
229       max = 1000;
230    } else {
231       max = pr.MaxVols - pr.NumVols;
232    }
233    for (;;) {
234       char buf[100]; 
235       bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
236       if (!get_pint(ua, buf)) {
237          return 1;
238       }
239       num = ua->pint32_val;
240       if (num < 0 || num > max) {
241          bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
242          continue;
243       }
244       break;
245    }
246 getVolName:
247    if (num == 0) {
248       if (!get_cmd(ua, _("Enter Volume name: "))) {
249          return 1;
250       }
251    } else {
252       if (!get_cmd(ua, _("Enter base volume name: "))) {
253          return 1;
254       }
255    }
256    /* Don't allow | in Volume name because it is the volume separator character */
257    if (!is_volume_name_legal(ua, ua->cmd)) {
258       goto getVolName;
259    }
260    if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
261       bsendmsg(ua, _("Volume name too long.\n"));
262       goto getVolName;
263    }
264    if (strlen(ua->cmd) == 0) {
265       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
266       goto getVolName;
267    }
268
269    bstrncpy(name, ua->cmd, sizeof(name));
270    if (num > 0) {
271       strcat(name, "%04d");
272
273       for (;;) {
274          if (!get_pint(ua, _("Enter the starting number: "))) {
275             return 1;
276          }
277          startnum = ua->pint32_val;
278          if (startnum < 1) {
279             bsendmsg(ua, _("Start number must be greater than zero.\n"));
280             continue;
281          }
282          break;
283       }
284    } else {
285       startnum = 1;
286       num = 1;
287    }
288
289    if (store && store->autochanger) {
290       if (!get_pint(ua, _("Enter slot (0 for none): "))) {
291          return 1;
292       }
293       slot = ua->pint32_val;
294    }
295            
296    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
297    for (i=startnum; i < num+startnum; i++) { 
298       bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
299       mr.Slot = slot++;
300       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
301       if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
302          bsendmsg(ua, db_strerror(ua->db));
303          return 1;
304       }
305       if (i == startnum) {
306          first_id = mr.PoolId;
307       }
308    }
309    pr.NumVols += num;
310    Dmsg0(200, "Update pool record.\n"); 
311    if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
312       bsendmsg(ua, db_strerror(ua->db));
313       return 1;
314    }
315    bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
316
317    return 1;
318 }
319
320 /*
321  * Turn auto mount on/off  
322  * 
323  *  automount on 
324  *  automount off
325  */
326 int automount_cmd(UAContext *ua, char *cmd)
327 {
328    char *onoff;
329
330    if (ua->argc != 2) {
331       if (!get_cmd(ua, _("Turn on or off? "))) {
332             return 1;
333       }
334       onoff = ua->cmd;
335    } else {
336       onoff = ua->argk[1];
337    }
338
339    ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
340    return 1; 
341 }
342
343
344 /*
345  * Cancel a job
346  */
347 static int cancelcmd(UAContext *ua, char *cmd)
348 {
349    int i;
350    int njobs = 0;
351    BSOCK *sd, *fd;
352    JCR *jcr = NULL;
353    char JobName[MAX_NAME_LENGTH];
354
355    if (!open_db(ua)) {
356       return 1;
357    }
358
359    for (i=1; i<ua->argc; i++) {
360       if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
361          if (!ua->argv[i]) {
362             break;
363          }
364          if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
365             bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
366             return 1;
367          }
368          break;
369       } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
370          if (!ua->argv[i]) {
371             break;
372          }
373          if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
374             bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
375             return 1;
376          }
377          break;
378       }
379    }
380    /* If we still do not have a jcr,
381     *   throw up a list and ask the user to select one.
382     */
383    if (!jcr) {
384       /* Count Jobs running */
385       lock_jcr_chain();
386       for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
387          if (jcr->JobId == 0) {      /* this is us */
388             free_locked_jcr(jcr);
389             njobs--;
390             continue;
391          }
392          free_locked_jcr(jcr);
393       }
394       unlock_jcr_chain();
395
396       if (njobs == 0) {
397          bsendmsg(ua, _("No Jobs running.\n"));
398          return 1;
399       }
400       start_prompt(ua, _("Select Job:\n"));
401       lock_jcr_chain();
402       for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
403          if (jcr->JobId == 0) {      /* this is us */
404             free_locked_jcr(jcr);
405             continue;
406          }
407          add_prompt(ua, jcr->Job);
408          free_locked_jcr(jcr);
409       }
410       unlock_jcr_chain();
411
412       if (do_prompt(ua, _("Job"),  _("Choose Job to cancel"), JobName, sizeof(JobName)) < 0) {
413          return 1;
414       }
415       if (njobs == 1) {
416          if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
417             return 1;
418          }
419       }
420       jcr = get_jcr_by_full_name(JobName);
421       if (!jcr) {
422          bsendmsg(ua, _("Job %s not found.\n"), JobName);
423          return 1;
424       }
425    }
426      
427    switch (jcr->JobStatus) {
428    case JS_Created:
429    case JS_WaitJobRes:
430    case JS_WaitClientRes:
431    case JS_WaitStoreRes:
432    case JS_WaitPriority:
433    case JS_WaitMaxJobs:
434    case JS_WaitStartTime:
435       set_jcr_job_status(jcr, JS_Canceled);
436       bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
437               jcr->JobId, jcr->Job);
438 #ifndef USE_SEMAPHORE
439 #ifdef JOB_QUEUE
440       jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
441 #else
442       workq_remove(&job_wq, jcr->work_item); /* attempt to remove it from queue */
443 #endif
444 #endif
445       free_jcr(jcr);
446       return 1;
447          
448    default:
449       set_jcr_job_status(jcr, JS_Canceled);
450
451       /* Cancel File daemon */
452       if (jcr->file_bsock) {
453          ua->jcr->client = jcr->client;
454          if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
455             bsendmsg(ua, _("Failed to connect to File daemon.\n"));
456             free_jcr(jcr);
457             return 1;
458          }
459          Dmsg0(200, "Connected to file daemon\n");
460          fd = ua->jcr->file_bsock;
461          bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
462          while (bnet_recv(fd) >= 0) {
463             bsendmsg(ua, "%s", fd->msg);
464          }
465          bnet_sig(fd, BNET_TERMINATE);
466          bnet_close(fd);
467          ua->jcr->file_bsock = NULL;
468       }
469
470       /* Cancel Storage daemon */
471       if (jcr->store_bsock) {
472          ua->jcr->store = jcr->store;
473          if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
474             bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
475             free_jcr(jcr);
476             return 1;
477          }
478          Dmsg0(200, "Connected to storage daemon\n");
479          sd = ua->jcr->store_bsock;
480          bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
481          while (bnet_recv(sd) >= 0) {
482             bsendmsg(ua, "%s", sd->msg);
483          }
484          bnet_sig(sd, BNET_TERMINATE);
485          bnet_close(sd);
486          ua->jcr->store_bsock = NULL;
487       }
488    }
489    free_jcr(jcr);
490
491    return 1; 
492 }
493
494 /*
495  * This is a common routine to create or update a
496  *   Pool DB base record from a Pool Resource. We handle
497  *   the setting of MaxVols and NumVols slightly differently
498  *   depending on if we are creating the Pool or we are
499  *   simply bringing it into agreement with the resource (updage).
500  */
501 static void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
502 {
503    strcpy(pr->PoolType, pool->pool_type);
504    if (op == POOL_OP_CREATE) {
505       pr->MaxVols = pool->max_volumes;
506       pr->NumVols = 0;
507    } else {          /* update pool */
508       if (pr->MaxVols != pool->max_volumes) {
509          pr->MaxVols = pool->max_volumes;
510       }
511       if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
512          pr->MaxVols = pr->NumVols;
513       }
514    }
515    pr->UseOnce = pool->use_volume_once;
516    pr->UseCatalog = pool->use_catalog;
517    pr->AcceptAnyVolume = pool->accept_any_volume;
518    pr->Recycle = pool->Recycle;
519    pr->VolRetention = pool->VolRetention;
520    pr->VolUseDuration = pool->VolUseDuration;
521    pr->MaxVolJobs = pool->MaxVolJobs;
522    pr->MaxVolFiles = pool->MaxVolFiles;
523    pr->MaxVolBytes = pool->MaxVolBytes;
524    pr->AutoPrune = pool->AutoPrune;
525    pr->Recycle = pool->Recycle;
526    if (pool->label_format) {
527       strcpy(pr->LabelFormat, pool->label_format);
528    } else {
529       strcpy(pr->LabelFormat, "*");    /* none */
530    }
531 }
532
533
534 /*
535  * Create a pool record from a given Pool resource
536  *   Also called from backup.c
537  * Returns: -1  on error
538  *           0  record already exists
539  *           1  record created
540  */
541
542 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
543 {
544    POOL_DBR  pr;
545
546    memset(&pr, 0, sizeof(POOL_DBR));
547
548    strcpy(pr.Name, pool->hdr.name);
549
550    if (db_get_pool_record(jcr, db, &pr)) {
551       /* Pool Exists */
552       if (op == POOL_OP_UPDATE) {  /* update request */
553          set_pooldbr_from_poolres(&pr, pool, op);
554          db_update_pool_record(jcr, db, &pr);
555       }
556       return 0;                       /* exists */
557    }
558
559    set_pooldbr_from_poolres(&pr, pool, op);
560
561    if (!db_create_pool_record(jcr, db, &pr)) {
562       return -1;                      /* error */
563    }
564    return 1;
565 }
566
567
568
569 /*
570  * Create a Pool Record in the database.
571  *  It is always created from the Resource record.
572  */
573 static int createcmd(UAContext *ua, char *cmd) 
574 {
575    POOL *pool;
576
577    if (!open_db(ua)) {
578       return 1;
579    }
580
581    pool = get_pool_resource(ua);
582    if (!pool) {
583       return 1;
584    }
585
586    switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
587    case 0:
588       bsendmsg(ua, _("Error: Pool %s already exists.\n\
589 Use update to change it.\n"), pool->hdr.name);
590       break;
591
592    case -1:
593       bsendmsg(ua, db_strerror(ua->db));
594       break;
595
596    default:
597      break;
598    }
599    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
600    return 1;
601 }
602
603
604
605
606 /*
607  * Update a Pool Record in the database.
608  *  It is always updated from the Resource record.
609  *
610  *    update pool=<pool-name>
611  *         updates pool from Pool resource
612  *    update media pool=<pool-name> volume=<volume-name>
613  *         changes pool info for volume
614  */
615 static int update_cmd(UAContext *ua, char *cmd) 
616 {
617    static char *kw[] = {
618       N_("media"),  /* 0 */
619       N_("volume"), /* 1 */
620       N_("pool"),   /* 2 */
621       N_("slots"),  /* 3 */
622       NULL};
623
624    if (!open_db(ua)) {
625       return 1;
626    }
627
628    switch (find_arg_keyword(ua, kw)) {
629    case 0:
630    case 1:
631       update_volume(ua);
632       return 1;
633    case 2:
634       update_pool(ua);
635       return 1;
636    case 3:
637       update_slots(ua);
638       return 1;
639    default:
640       break;
641    }
642     
643    start_prompt(ua, _("Update choice:\n"));
644    add_prompt(ua, _("Volume parameters"));
645    add_prompt(ua, _("Pool from resource"));
646    add_prompt(ua, _("Slots from autochanger"));
647    switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
648    case 0:
649       update_volume(ua);
650       break;
651    case 1:
652       update_pool(ua);
653       break;
654    case 2:
655       update_slots(ua);
656       break;
657    default:
658       break;
659    }
660    return 1;
661 }
662
663 static void update_volstatus(UAContext *ua, char *val, MEDIA_DBR *mr)
664 {
665    POOLMEM *query = get_pool_memory(PM_MESSAGE);
666    char *kw[] = {
667       "Append",
668       "Archive",
669       "Disabled",
670       "Full",
671       "Used", 
672       "Cleaning", 
673       "Read-Only",
674       NULL};
675    bool found = false;
676    int i;
677
678    for (i=0; kw[i]; i++) {
679       if (strcasecmp(val, kw[i]) == 0) {
680          found = true;
681          break;
682       }
683    }
684    if (!found) {
685       bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
686    } else {
687       bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
688       Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u",
689          mr->VolStatus, mr->MediaId);
690       if (!db_sql_query(ua->db, query, NULL, NULL)) {  
691          bsendmsg(ua, "%s", db_strerror(ua->db));
692       } else {
693          bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
694       }
695    }
696    free_pool_memory(query);
697 }
698
699 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
700 {
701    char ed1[50];
702    POOLMEM *query;
703    if (!duration_to_utime(val, &mr->VolRetention)) {
704       bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
705       return;
706    }
707    query = get_pool_memory(PM_MESSAGE);
708    Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u",
709       edit_uint64(mr->VolRetention, ed1), mr->MediaId);
710    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
711       bsendmsg(ua, "%s", db_strerror(ua->db));
712    } else {
713       bsendmsg(ua, _("New retention seconds is: %s\n"),
714          edit_utime(mr->VolRetention, ed1));
715    }
716    free_pool_memory(query);
717 }
718
719 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
720 {
721    char ed1[50];
722    POOLMEM *query;
723
724    if (!duration_to_utime(val, &mr->VolUseDuration)) {
725       bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
726       return;
727    }
728    query = get_pool_memory(PM_MESSAGE);
729    Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u",
730       edit_uint64(mr->VolUseDuration, ed1), mr->MediaId);
731    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
732       bsendmsg(ua, "%s", db_strerror(ua->db));
733    } else {
734       bsendmsg(ua, _("New use duration is: %s\n"),
735          edit_utime(mr->VolUseDuration, ed1));
736    }
737    free_pool_memory(query);
738 }
739
740 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
741 {
742    POOLMEM *query = get_pool_memory(PM_MESSAGE);
743    Mmsg(&query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%u",
744       val, mr->MediaId);
745    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
746       bsendmsg(ua, "%s", db_strerror(ua->db));
747    } else {
748       bsendmsg(ua, _("New max jobs is: %s\n"), val);
749    }
750    free_pool_memory(query);
751 }
752
753 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
754 {
755    POOLMEM *query = get_pool_memory(PM_MESSAGE);
756    Mmsg(&query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%u",
757       val, mr->MediaId);
758    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
759       bsendmsg(ua, "%s", db_strerror(ua->db));
760    } else {
761       bsendmsg(ua, _("New max files is: %s\n"), val);
762    }
763    free_pool_memory(query);
764 }
765
766 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
767 {
768    uint64_t maxbytes;
769    char ed1[50];
770    POOLMEM *query;
771
772    if (!size_to_uint64(val, strlen(val), &maxbytes)) {
773       bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
774       return;
775    } 
776    query = get_pool_memory(PM_MESSAGE);
777    Mmsg(&query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%u",
778       edit_uint64(maxbytes, ed1), mr->MediaId);
779    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
780       bsendmsg(ua, "%s", db_strerror(ua->db));
781    } else {
782       bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
783    }
784    free_pool_memory(query);
785 }
786
787 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
788 {
789    int recycle;
790    POOLMEM *query;
791    if (strcasecmp(val, _("yes")) == 0) {
792       recycle = 1;
793    } else if (strcasecmp(val, _("no")) == 0) {
794       recycle = 0;
795    } else {
796       bsendmsg(ua, _("Invalid value. It must by yes or no.\n"));
797       return;
798    }
799    query = get_pool_memory(PM_MESSAGE);
800    Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u",
801       recycle, mr->MediaId);
802    if (!db_sql_query(ua->db, query, NULL, NULL)) {  
803       bsendmsg(ua, "%s", db_strerror(ua->db));
804    } else {       
805       bsendmsg(ua, _("New recycle flag is: %s\n"),
806          mr->Recycle==1?_("yes"):_("no"));
807    }
808    free_pool_memory(query);
809 }
810
811 /*
812  * Update a media record -- allows you to change the
813  *  Volume status. E.g. if you want Bacula to stop
814  *  writing on the volume, set it to anything other
815  *  than Append.
816  */              
817 static int update_volume(UAContext *ua)
818 {
819    MEDIA_DBR mr;
820    POOLMEM *query;
821    char ed1[30];
822    bool done = false;
823    char *kw[] = {
824       N_("VolStatus"),                /* 0 */
825       N_("VolRetention"),             /* 1 */
826       N_("VolUse"),                   /* 2 */
827       N_("MaxVolJobs"),               /* 3 */
828       N_("MaxVolFiles"),              /* 4 */
829       N_("MaxVolBytes"),              /* 5 */
830       N_("Recycle"),                  /* 6 */
831       NULL };
832
833    if (!select_media_dbr(ua, &mr)) {
834       return 0;
835    }
836    for (int i=0; kw[i]; i++) {
837       int j;
838       if ((j=find_arg_with_value(ua, kw[i])) > 0) {
839          switch (i) {
840          case 0:
841             update_volstatus(ua, ua->argv[j], &mr);
842             break;
843          case 1:
844             update_volretention(ua, ua->argv[j], &mr);
845             break;
846          case 2:
847             update_voluseduration(ua, ua->argv[j], &mr);
848             break;
849          case 3:
850             update_volmaxjobs(ua, ua->argv[j], &mr);
851             break;
852          case 4:
853             update_volmaxfiles(ua, ua->argv[j], &mr);
854             break;
855          case 5:
856             update_volmaxbytes(ua, ua->argv[j], &mr);
857             break;
858          case 6:
859             update_volrecycle(ua, ua->argv[j], &mr);
860             break;
861          }
862          done = true;
863       }
864    }
865
866    for ( ; !done; ) {
867       if (!select_media_dbr(ua, &mr)) {
868          return 0;
869       }
870       bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
871       start_prompt(ua, _("Parameters to modify:\n"));
872       add_prompt(ua, _("Volume Status"));
873       add_prompt(ua, _("Volume Retention Period"));
874       add_prompt(ua, _("Volume Use Duration"));
875       add_prompt(ua, _("Maximum Volume Jobs"));
876       add_prompt(ua, _("Maximum Volume Files"));
877       add_prompt(ua, _("Maximum Volume Bytes"));
878       add_prompt(ua, _("Recycle Flag"));
879       add_prompt(ua, _("Slot"));
880       add_prompt(ua, _("Volume Files"));
881       add_prompt(ua, _("Done"));
882       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
883       case 0:                         /* Volume Status */
884          /* Modify Volume Status */
885          bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
886          start_prompt(ua, _("Possible Values are:\n"));
887          add_prompt(ua, "Append");      /* Better not translate these as */
888          add_prompt(ua, "Archive");     /* They are known in the database code */
889          add_prompt(ua, "Disabled");
890          add_prompt(ua, "Full");
891          add_prompt(ua, "Used");
892          add_prompt(ua, "Cleaning");
893          if (strcmp(mr.VolStatus, "Purged") == 0) {
894             add_prompt(ua, "Recycle");
895          }
896          add_prompt(ua, "Read-Only");
897          if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
898             return 1;
899          }
900          update_volstatus(ua, ua->cmd, &mr);
901          break;
902       case 1:                         /* Retention */
903          bsendmsg(ua, _("Current retention seconds is: %s\n"),
904             edit_utime(mr.VolRetention, ed1));
905          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
906             return 0;
907          }
908          update_volretention(ua, ua->cmd, &mr);
909          break;
910
911       case 2:                         /* Use Duration */
912          bsendmsg(ua, _("Current use duration is: %s\n"),
913             edit_utime(mr.VolUseDuration, ed1));
914          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
915             return 0;
916          }
917          update_voluseduration(ua, ua->cmd, &mr);
918          break;
919
920       case 3:                         /* Max Jobs */
921          bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
922          if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
923             return 0;
924          }
925          update_volmaxjobs(ua, ua->cmd, &mr);
926          break;
927
928       case 4:                         /* Max Files */
929          bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
930          if (!get_pint(ua, _("Enter new Maximum Files: "))) {
931             return 0;
932          }
933          update_volmaxfiles(ua, ua->cmd, &mr);
934          break;
935
936       case 5:                         /* Max Bytes */
937          bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
938          if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
939             return 0;
940          }
941          update_volmaxbytes(ua, ua->cmd, &mr);
942          break;
943
944
945       case 6:                         /* Recycle */
946          bsendmsg(ua, _("Current recycle flag is: %s\n"),
947             mr.Recycle==1?_("yes"):_("no"));
948          if (!get_yesno(ua, _("Enter new Recycle status: "))) {
949             return 0;
950          }
951          update_volrecycle(ua, ua->cmd, &mr);
952          break;
953
954       case 7:                         /* Slot */
955          int slot;
956          POOL_DBR pr;
957
958          memset(&pr, 0, sizeof(POOL_DBR));
959          pr.PoolId = mr.PoolId;
960          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
961             bsendmsg(ua, "%s", db_strerror(ua->db));
962             return 0;
963          }
964          bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
965          if (!get_pint(ua, _("Enter new Slot: "))) {
966             return 0;
967          }
968          slot = ua->pint32_val;
969          if (pr.MaxVols > 0 && slot > (int)pr.MaxVols) {
970             bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
971                pr.MaxVols);
972             break;
973          }
974          query = get_pool_memory(PM_MESSAGE);
975          Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%u",
976             slot, mr.MediaId);
977          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
978             bsendmsg(ua, "%s", db_strerror(ua->db));
979          } else {
980             bsendmsg(ua, "New Slot is: %d\n", slot);
981          }
982          free_pool_memory(query);
983          break;
984
985       case 8:                         /* Volume Files */
986          int32_t VolFiles;
987          bsendmsg(ua, _("Warning changing Volume Files can result\n"
988                         "in loss of data on your Volume\n\n"));
989          bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
990          if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
991             return 0;
992          }
993          VolFiles = ua->pint32_val;
994          if (VolFiles != (int)(mr.VolFiles + 1)) {
995             bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
996             if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
997                break;
998             }
999          }
1000          query = get_pool_memory(PM_MESSAGE);
1001          Mmsg(&query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%u",
1002             VolFiles, mr.MediaId);
1003          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
1004             bsendmsg(ua, "%s", db_strerror(ua->db));
1005          } else {
1006             bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
1007          }
1008          free_pool_memory(query);
1009          break;
1010
1011       default:                        /* Done or error */
1012          bsendmsg(ua, "Selection done.\n");
1013          return 1;
1014       }
1015    }
1016    return 1;
1017 }
1018
1019 /* 
1020  * Update pool record -- pull info from current POOL resource
1021  */
1022 static int update_pool(UAContext *ua)
1023 {
1024    POOL_DBR  pr;
1025    int id;
1026    POOL *pool;
1027    POOLMEM *query;       
1028    
1029    pool = get_pool_resource(ua);
1030    if (!pool) {
1031       return 0;
1032    }
1033
1034    memset(&pr, 0, sizeof(pr));
1035    strcpy(pr.Name, pool->hdr.name);
1036    if (!get_pool_dbr(ua, &pr)) {
1037       return 0;
1038    }
1039
1040    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
1041
1042    id = db_update_pool_record(ua->jcr, ua->db, &pr);
1043    if (id <= 0) {
1044       bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
1045          id, db_strerror(ua->db));
1046    }
1047    query = get_pool_memory(PM_MESSAGE);
1048    Mmsg(&query, list_pool, pr.PoolId);
1049    db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
1050    free_pool_memory(query);
1051    bsendmsg(ua, _("Pool DB record updated from resource.\n"));
1052    return 1;
1053 }
1054
1055
1056 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
1057 {
1058    BSOCK *sd;
1059
1060    ua->jcr->store = store;
1061    /* Try connecting for up to 15 seconds */
1062    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
1063       store->hdr.name, store->address, store->SDport);
1064    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
1065       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1066       return;
1067    }
1068    Dmsg0(120, _("Connected to storage daemon\n"));
1069    sd = ua->jcr->store_bsock;
1070    bnet_fsend(sd, "setdebug=%d\n", level);
1071    if (bnet_recv(sd) >= 0) {
1072       bsendmsg(ua, "%s", sd->msg);
1073    }
1074    bnet_sig(sd, BNET_TERMINATE);
1075    bnet_close(sd);
1076    ua->jcr->store_bsock = NULL;
1077    return;  
1078 }
1079    
1080 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
1081 {
1082    BSOCK *fd;
1083
1084    /* Connect to File daemon */
1085
1086    ua->jcr->client = client;
1087    /* Try to connect for 15 seconds */
1088    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
1089       client->hdr.name, client->address, client->FDport);
1090    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
1091       bsendmsg(ua, _("Failed to connect to Client.\n"));
1092       return;
1093    }
1094    Dmsg0(120, "Connected to file daemon\n");
1095    fd = ua->jcr->file_bsock;
1096    bnet_fsend(fd, "setdebug=%d\n", level);
1097    if (bnet_recv(fd) >= 0) {
1098       bsendmsg(ua, "%s", fd->msg);
1099    }
1100    bnet_sig(fd, BNET_TERMINATE);
1101    bnet_close(fd);
1102    ua->jcr->file_bsock = NULL;
1103    return;  
1104 }
1105
1106
1107 static void do_all_setdebug(UAContext *ua, int level)
1108 {
1109    STORE *store, **unique_store;
1110    CLIENT *client, **unique_client;
1111    int i, j, found;
1112
1113    /* Director */
1114    debug_level = level;
1115
1116    /* Count Storage items */
1117    LockRes();
1118    store = NULL;
1119    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
1120       { }
1121    unique_store = (STORE **) malloc(i * sizeof(STORE));
1122    /* Find Unique Storage address/port */         
1123    store = (STORE *)GetNextRes(R_STORAGE, NULL);
1124    i = 0;
1125    unique_store[i++] = store;
1126    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
1127       found = 0;
1128       for (j=0; j<i; j++) {
1129          if (strcmp(unique_store[j]->address, store->address) == 0 &&
1130              unique_store[j]->SDport == store->SDport) {
1131             found = 1;
1132             break;
1133          }
1134       }
1135       if (!found) {
1136          unique_store[i++] = store;
1137          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
1138       }
1139    }
1140    UnlockRes();
1141
1142    /* Call each unique Storage daemon */
1143    for (j=0; j<i; j++) {
1144       do_storage_setdebug(ua, unique_store[j], level);
1145    }
1146    free(unique_store);
1147
1148    /* Count Client items */
1149    LockRes();
1150    client = NULL;
1151    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
1152       { }
1153    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
1154    /* Find Unique Client address/port */         
1155    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
1156    i = 0;
1157    unique_client[i++] = client;
1158    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
1159       found = 0;
1160       for (j=0; j<i; j++) {
1161          if (strcmp(unique_client[j]->address, client->address) == 0 &&
1162              unique_client[j]->FDport == client->FDport) {
1163             found = 1;
1164             break;
1165          }
1166       }
1167       if (!found) {
1168          unique_client[i++] = client;
1169          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
1170       }
1171    }
1172    UnlockRes();
1173
1174    /* Call each unique File daemon */
1175    for (j=0; j<i; j++) {
1176       do_client_setdebug(ua, unique_client[j], level);
1177    }
1178    free(unique_client);
1179 }
1180
1181 /*
1182  * setdebug level=nn all
1183  */
1184 static int setdebug_cmd(UAContext *ua, char *cmd)
1185 {
1186    STORE *store;
1187    CLIENT *client;
1188    int level;
1189    int i;
1190
1191    if (!open_db(ua)) {
1192       return 1;
1193    }
1194    Dmsg1(120, "setdebug:%s:\n", cmd);
1195
1196    level = -1;
1197    i = find_arg_with_value(ua, _("level"));
1198    if (i >= 0) {
1199       level = atoi(ua->argv[i]);
1200    }
1201    if (level < 0) {
1202       if (!get_pint(ua, _("Enter new debug level: "))) {
1203          return 1;
1204       }
1205       level = ua->pint32_val;
1206    }
1207
1208    /* General debug? */
1209    for (i=1; i<ua->argc; i++) {
1210       if (strcasecmp(ua->argk[i], _("all")) == 0) {
1211          do_all_setdebug(ua, level);
1212          return 1;
1213       }
1214       if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
1215           strcasecmp(ua->argk[i], _("director")) == 0) {
1216          debug_level = level;
1217          return 1;
1218       }
1219       if (strcasecmp(ua->argk[i], _("client")) == 0) {
1220          client = NULL;
1221          if (ua->argv[i]) {
1222             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
1223             if (client) {
1224                do_client_setdebug(ua, client, level);
1225                return 1;
1226             }
1227          }
1228          client = select_client_resource(ua);   
1229          if (client) {
1230             do_client_setdebug(ua, client, level);
1231             return 1;
1232          }
1233       }
1234
1235       if (strcasecmp(ua->argk[i], _("store")) == 0 ||
1236           strcasecmp(ua->argk[i], _("storage")) == 0) {
1237          store = NULL;
1238          if (ua->argv[i]) {
1239             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
1240             if (store) {
1241                do_storage_setdebug(ua, store, level);
1242                return 1;
1243             }
1244          }
1245          store = get_storage_resource(ua, 0);
1246          if (store) {
1247             do_storage_setdebug(ua, store, level);
1248             return 1;
1249          }
1250       }
1251    } 
1252    /*
1253     * We didn't find an appropriate keyword above, so
1254     * prompt the user.
1255     */
1256    start_prompt(ua, _("Available daemons are: \n"));
1257    add_prompt(ua, _("Director"));
1258    add_prompt(ua, _("Storage"));
1259    add_prompt(ua, _("Client"));
1260    add_prompt(ua, _("All"));
1261    switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1262    case 0:                         /* Director */
1263       debug_level = level;
1264       break;
1265    case 1:
1266       store = get_storage_resource(ua, 0);
1267       if (store) {
1268          do_storage_setdebug(ua, store, level);
1269       }
1270       break;
1271    case 2:
1272       client = select_client_resource(ua);
1273       if (client) {
1274          do_client_setdebug(ua, client, level);
1275       }
1276       break;
1277    case 3:
1278       do_all_setdebug(ua, level);
1279       break;
1280    default:
1281       break;
1282    }
1283    return 1;
1284 }
1285
1286 static int var_cmd(UAContext *ua, char *cmd)
1287 {
1288    POOLMEM *var = get_pool_memory(PM_FNAME);
1289    for (int i=1; i<ua->argc; i++) {
1290       if (ua->argk[i] && variable_expansion(ua->jcr, ua->argk[i], &var)) {
1291          bsendmsg(ua, "%s\n", var);
1292       }
1293    }
1294    free_pool_memory(var);
1295    return 1;
1296 }
1297
1298 static int estimate_cmd(UAContext *ua, char *cmd)
1299 {
1300    JOB *job = NULL;
1301    CLIENT *client = NULL;
1302    FILESET *fileset = NULL;
1303    int listing = 0;
1304    BSOCK *fd;
1305    char since[MAXSTRING];
1306
1307    for (int i=1; i<ua->argc; i++) {
1308       if (strcasecmp(ua->argk[i], _("client")) == 0) {
1309          if (ua->argv[i]) {
1310             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
1311             continue;
1312          }
1313       }
1314       if (strcasecmp(ua->argk[i], _("job")) == 0) {
1315          if (ua->argv[i]) {
1316             job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
1317             continue;
1318          }
1319       }
1320       if (strcasecmp(ua->argk[i], _("fileset")) == 0) {
1321          if (ua->argv[i]) {
1322             fileset = (FILESET *)GetResWithName(R_FILESET, ua->argv[i]);
1323             continue;
1324          }
1325       }
1326       if (strcasecmp(ua->argk[i], _("listing")) == 0) {
1327          listing = 1;
1328       }
1329    } 
1330    if (!job && !(client && fileset)) {
1331       if (!(job = select_job_resource(ua))) {
1332          return 1;
1333       }
1334    }
1335    if (!job) {
1336       job = (JOB *)GetResWithName(R_JOB, ua->argk[1]);
1337    }
1338    if (!client) {
1339       client = job->client;
1340    }
1341    if (!fileset) {
1342       fileset = job->fileset;
1343    }
1344    ua->jcr->client = client;
1345    ua->jcr->fileset = fileset;
1346    close_db(ua);
1347    ua->catalog = client->catalog;
1348
1349    if (!open_db(ua)) {
1350       return 1;
1351    }
1352
1353    get_level_since_time(ua->jcr, since, sizeof(since));
1354
1355    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
1356       job->client->hdr.name, job->client->address, job->client->FDport);
1357    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
1358       bsendmsg(ua, _("Failed to connect to Client.\n"));
1359       return 1;
1360    }
1361    fd = ua->jcr->file_bsock;
1362
1363    if (!send_include_list(ua->jcr)) {
1364       bsendmsg(ua, _("Error sending include list.\n"));
1365       return 1;
1366    }
1367
1368    if (!send_exclude_list(ua->jcr)) {
1369       bsendmsg(ua, _("Error sending exclude list.\n"));
1370       return 1;
1371    }
1372
1373    if (!send_level_command(ua->jcr)) {
1374       return 1;
1375    }
1376
1377    bnet_fsend(fd, "estimate listing=%d\n", listing);
1378    while (bnet_recv(fd) >= 0) {
1379       bsendmsg(ua, "%s", fd->msg);
1380    }
1381
1382    bnet_sig(fd, BNET_TERMINATE);
1383    bnet_close(fd);
1384    ua->jcr->file_bsock = NULL;
1385
1386    return 1;
1387 }
1388
1389
1390 /*
1391  * print time
1392  */
1393 static int time_cmd(UAContext *ua, char *cmd)
1394 {
1395    char sdt[50];
1396    time_t ttime = time(NULL);
1397    struct tm tm;
1398    localtime_r(&ttime, &tm);
1399    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1400    bsendmsg(ua, "%s\n", sdt);
1401    return 1;
1402 }
1403
1404
1405
1406 /*
1407  * Delete Pool records (should purge Media with it).
1408  *
1409  *  delete pool=<pool-name>
1410  *  delete media pool=<pool-name> volume=<name>
1411  */
1412 static int delete_cmd(UAContext *ua, char *cmd)
1413 {
1414    static char *keywords[] = {
1415       N_("volume"),
1416       N_("pool"),
1417       NULL};
1418
1419    if (!open_db(ua)) {
1420       return 1;
1421    }
1422
1423    bsendmsg(ua, _(
1424 "In general it is not a good idea to delete either a\n"
1425 "Pool or a Volume since they may contain data.\n\n"));
1426      
1427    switch (find_arg_keyword(ua, keywords)) {
1428    case 0:
1429       delete_volume(ua);     
1430       return 1;
1431    case 1:
1432       delete_pool(ua);
1433       return 1;
1434    default:
1435       break;
1436    }
1437    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1438    case 0:
1439       delete_volume(ua);
1440       break;
1441    case 1:
1442       delete_pool(ua);
1443       break;
1444    default:
1445       bsendmsg(ua, _("Nothing done.\n"));
1446       break;
1447    }
1448    return 1;
1449 }
1450
1451 /*
1452  * Delete media records from database -- dangerous 
1453  */
1454 static int delete_volume(UAContext *ua)
1455 {
1456    MEDIA_DBR mr;
1457
1458    if (!select_media_dbr(ua, &mr)) {
1459       return 1;
1460    }
1461    bsendmsg(ua, _("\nThis command will delete volume %s\n"
1462       "and all Jobs saved on that volume from the Catalog\n"),
1463       mr.VolumeName);
1464
1465    if (!get_yesno(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1466       return 1;
1467    }
1468    if (ua->pint32_val) {
1469       db_delete_media_record(ua->jcr, ua->db, &mr);
1470    }
1471    return 1;
1472 }
1473
1474 /*
1475  * Delete a pool record from the database -- dangerous   
1476  */
1477 static int delete_pool(UAContext *ua)
1478 {
1479    POOL_DBR  pr;
1480    
1481    memset(&pr, 0, sizeof(pr));
1482
1483    if (!get_pool_dbr(ua, &pr)) {
1484       return 1;
1485    }
1486    if (!get_yesno(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1487       return 1;
1488    }
1489    if (ua->pint32_val) {
1490       db_delete_pool_record(ua->jcr, ua->db, &pr);
1491    }
1492    return 1;
1493 }
1494
1495
1496 static void do_mount_cmd(UAContext *ua, char *command)
1497 {
1498    STORE *store;
1499    BSOCK *sd;
1500    char dev_name[MAX_NAME_LENGTH];
1501
1502
1503    if (!open_db(ua)) {
1504       return;
1505    }
1506    Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1507
1508    store = get_storage_resource(ua, 1);
1509    if (!store) {
1510       return;
1511    }
1512
1513    Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1514       store->media_type, store->dev_name);
1515
1516    ua->jcr->store = store;
1517    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1518       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1519       return;
1520    }
1521    sd = ua->jcr->store_bsock;
1522    strcpy(dev_name, store->dev_name);
1523    bash_spaces(dev_name);
1524    bnet_fsend(sd, "%s %s", command, dev_name);
1525    while (bnet_recv(sd) >= 0) {
1526       bsendmsg(ua, "%s", sd->msg);
1527    }
1528    bnet_sig(sd, BNET_TERMINATE);
1529    bnet_close(sd);
1530    ua->jcr->store_bsock = NULL;
1531 }
1532
1533 /*
1534  * mount [storage | device] <name>
1535  */
1536 static int mount_cmd(UAContext *ua, char *cmd)
1537 {
1538    do_mount_cmd(ua, "mount");          /* mount */
1539    return 1;
1540 }
1541
1542
1543 /*
1544  * unmount [storage | device] <name>
1545  */
1546 static int unmount_cmd(UAContext *ua, char *cmd)
1547 {
1548    do_mount_cmd(ua, "unmount");          /* unmount */
1549    return 1;
1550 }
1551
1552
1553 /*
1554  * release [storage | device] <name>
1555  */
1556 static int release_cmd(UAContext *ua, char *cmd)
1557 {
1558    do_mount_cmd(ua, "release");          /* release */
1559    return 1;
1560 }
1561
1562
1563 /*
1564  * Switch databases
1565  *   use catalog=<name>
1566  */
1567 static int use_cmd(UAContext *ua, char *cmd)
1568 {
1569    CAT *oldcatalog, *catalog;
1570
1571
1572    close_db(ua);                      /* close any previously open db */
1573    oldcatalog = ua->catalog;
1574
1575    if (!(catalog = get_catalog_resource(ua))) {
1576       ua->catalog = oldcatalog;
1577    } else {
1578       ua->catalog = catalog;
1579    }
1580    if (open_db(ua)) {
1581       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1582          ua->catalog->hdr.name, ua->catalog->db_name);
1583    }
1584    return 1;
1585 }
1586
1587 int quit_cmd(UAContext *ua, char *cmd) 
1588 {
1589    ua->quit = TRUE;
1590    return 1;
1591 }
1592
1593 /*
1594  * Wait until no job is running 
1595  */
1596 int wait_cmd(UAContext *ua, char *cmd) 
1597 {
1598    bmicrosleep(0, 200000);            /* let job actually start */
1599    for (int running=1; running; ) {
1600       running = 0;
1601       lock_jcr_chain();
1602       for (JCR *jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
1603          if (jcr->JobId != 0) {
1604             running = 1;
1605             free_locked_jcr(jcr);
1606             break;
1607          }
1608          free_locked_jcr(jcr);
1609       }
1610       unlock_jcr_chain();
1611       if (running) {
1612          bmicrosleep(1, 0);
1613       }
1614    }
1615    return 1;
1616 }
1617
1618
1619 static int help_cmd(UAContext *ua, char *cmd)
1620 {
1621    unsigned int i;
1622
1623 /* usage(); */
1624    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1625    for (i=0; i<comsize; i++) {
1626       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1627    }
1628    bsendmsg(ua, "\n");
1629    return 1;
1630 }
1631
1632 static int version_cmd(UAContext *ua, char *cmd)
1633 {
1634    bsendmsg(ua, "%s Version: " VERSION " (" BDATE ")\n", my_name);
1635    return 1;
1636 }
1637
1638
1639 /* A bit brain damaged in that if the user has not done
1640  * a "use catalog xxx" command, we simply find the first
1641  * catalog resource and open it.
1642  */
1643 int open_db(UAContext *ua)
1644 {
1645    if (ua->db) {
1646       return 1;
1647    }
1648    if (!ua->catalog) {
1649       LockRes();
1650       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1651       UnlockRes();
1652       if (!ua->catalog) {    
1653          bsendmsg(ua, _("Could not find a Catalog resource\n"));
1654          return 0;
1655       } else {
1656          bsendmsg(ua, _("Using default Catalog name=%s DB=%s\n"), 
1657             ua->catalog->hdr.name, ua->catalog->db_name);
1658       }
1659    }
1660
1661    ua->jcr->catalog = ua->catalog;
1662
1663    Dmsg0(150, "Open database\n");
1664    ua->db = db_init_database(ua->jcr, ua->catalog->db_name, ua->catalog->db_user,
1665                              ua->catalog->db_password, ua->catalog->db_address,
1666                              ua->catalog->db_port, ua->catalog->db_socket);
1667    if (!db_open_database(ua->jcr, ua->db)) {
1668       bsendmsg(ua, _("Could not open DB %s: ERR=%s"), 
1669          ua->catalog->db_name, db_strerror(ua->db));
1670       close_db(ua);
1671       return 0;
1672    }
1673    ua->jcr->db = ua->db;
1674    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1675    return 1;
1676 }
1677
1678 void close_db(UAContext *ua)
1679 {
1680    if (ua->db) {
1681       db_close_database(ua->jcr, ua->db);
1682    }
1683    ua->db = NULL;
1684 }