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