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