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