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