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