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