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