]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
Write MaxVolJobs and VolUseDuration to DB
[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    for (i=startnum; i < num+startnum; i++) { 
268       sprintf(mr.VolumeName, name, i);
269       mr.Slot = slot++;
270       Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
271       if (!db_create_media_record(ua->db, &mr)) {
272          bsendmsg(ua, db_strerror(ua->db));
273          return 1;
274       }
275       if (i == startnum) {
276          first_id = mr.PoolId;
277       }
278    }
279    pr.NumVols += num;
280    Dmsg0(200, "Update pool record.\n"); 
281    if (db_update_pool_record(ua->db, &pr) != 1) {
282       bsendmsg(ua, db_strerror(ua->db));
283       return 1;
284    }
285    bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
286
287    return 1;
288 }
289
290 /*
291  * Turn auto mount on/off  
292  * 
293  *  automount on 
294  *  automount off
295  */
296 int automountcmd(UAContext *ua, char *cmd)
297 {
298    char *onoff;
299
300    if (ua->argc != 2) {
301       if (!get_cmd(ua, _("Turn on or off? "))) {
302             return 1;
303       }
304       onoff = ua->cmd;
305    } else {
306       onoff = ua->argk[1];
307    }
308
309    ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
310    return 1; 
311 }
312
313
314 /*
315  * Cancel a job
316  */
317 static int cancelcmd(UAContext *ua, char *cmd)
318 {
319    int i;
320    int njobs = 0;
321    BSOCK *sd, *fd;
322    JCR *jcr = NULL;
323    char JobName[MAX_NAME_LENGTH];
324
325    if (!open_db(ua)) {
326       return 1;
327    }
328
329    for (i=1; i<ua->argc; i++) {
330       if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
331          if (!ua->argv[i]) {
332             break;
333          }
334          if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
335             bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
336             return 1;
337          }
338          break;
339       } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
340          if (!ua->argv[i]) {
341             break;
342          }
343          if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
344             bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
345             return 1;
346          }
347          break;
348       }
349    }
350    /* If we still do not have a jcr,
351     *   throw up a list and ask the user to select one.
352     */
353    if (!jcr) {
354       /* Count Jobs running */
355       lock_jcr_chain();
356       for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
357          if (jcr->JobId == 0) {      /* this is us */
358             free_locked_jcr(jcr);
359             njobs--;
360             continue;
361          }
362          free_locked_jcr(jcr);
363       }
364       unlock_jcr_chain();
365
366       if (njobs == 0) {
367          bsendmsg(ua, _("No Jobs running.\n"));
368          return 1;
369       }
370       start_prompt(ua, _("Select Job:\n"));
371       lock_jcr_chain();
372       for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
373          if (jcr->JobId == 0) {      /* this is us */
374             free_locked_jcr(jcr);
375             continue;
376          }
377          add_prompt(ua, jcr->Job);
378          free_locked_jcr(jcr);
379       }
380       unlock_jcr_chain();
381
382       if (do_prompt(ua, _("Choose Job to cancel"), JobName) < 0) {
383          return 1;
384       }
385       if (njobs == 1) {
386          if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
387             return 1;
388          }
389          if (strcasecmp(ua->cmd, _("yes")) != 0) {
390             return 1;
391          }
392       }
393       jcr = get_jcr_by_full_name(JobName);
394       if (!jcr) {
395          bsendmsg(ua, _("Job %s not found.\n"), JobName);
396          return 1;
397       }
398    }
399      
400    switch (jcr->JobStatus) {
401    case JS_Created:
402       jcr->JobStatus = JS_Cancelled;
403       bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
404               jcr->JobId, jcr->Job);
405       free_jcr(jcr);
406       return 1;
407          
408    default:
409
410       jcr->JobStatus = JS_Cancelled;
411       /* Cancel File daemon */
412       ua->jcr->client = jcr->client;
413       if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
414          bsendmsg(ua, _("Failed to connect to File daemon.\n"));
415          free_jcr(jcr);
416          return 1;
417       }
418       Dmsg0(200, "Connected to file daemon\n");
419       fd = ua->jcr->file_bsock;
420       bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
421       while (bnet_recv(fd) >= 0) {
422          bsendmsg(ua, "%s", fd->msg);
423       }
424       bnet_sig(fd, BNET_TERMINATE);
425       bnet_close(fd);
426       ua->jcr->file_bsock = NULL;
427
428       /* Cancel Storage daemon */
429       ua->jcr->store = jcr->store;
430       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
431          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
432          free_jcr(jcr);
433          return 1;
434       }
435       Dmsg0(200, "Connected to storage daemon\n");
436       sd = ua->jcr->store_bsock;
437       bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
438       while (bnet_recv(sd) >= 0) {
439          bsendmsg(ua, "%s", sd->msg);
440       }
441       bnet_sig(sd, BNET_TERMINATE);
442       bnet_close(sd);
443       ua->jcr->store_bsock = NULL;
444
445    }
446    free_jcr(jcr);
447
448    return 1; 
449 }
450
451 /*
452  * Create a pool record from a given Pool resource
453  *   Also called from backup.c
454  * Returns: -1  on error
455  *           0  record already exists
456  *           1  record created
457  */
458
459 int create_pool(B_DB *db, POOL *pool)
460 {
461    POOL_DBR  pr;
462
463    memset(&pr, 0, sizeof(POOL_DBR));
464
465    strcpy(pr.Name, pool->hdr.name);
466
467    if (db_get_pool_record(db, &pr)) {
468       return 0;                       /* exists */
469    }
470
471    strcpy(pr.PoolType, pool->pool_type);
472    pr.MaxVols = pool->max_volumes;
473    pr.NumVols = 0;
474    pr.UseOnce = pool->use_volume_once;
475    pr.UseCatalog = pool->use_catalog;
476    pr.AcceptAnyVolume = pool->accept_any_volume;
477    pr.Recycle = pool->Recycle;
478    pr.VolRetention = pool->VolRetention;
479    pr.VolUseDuration = pool->VolUseDuration;
480    pr.MaxVolJobs = pool->MaxVolJobs;
481    pr.AutoPrune = pool->AutoPrune;
482    if (pool->label_format) {
483       strcpy(pr.LabelFormat, pool->label_format);
484    } else {
485       strcpy(pr.LabelFormat, "*");    /* none */
486    }
487
488    if (!db_create_pool_record(db, &pr)) {
489       return -1;                      /* error */
490    }
491    return 1;
492 }
493
494
495
496 /*
497  * Create a Pool Record in the database.
498  *  It is always created from the Resource record.
499  */
500 static int createcmd(UAContext *ua, char *cmd) 
501 {
502    POOL *pool;
503
504    if (!open_db(ua)) {
505       return 1;
506    }
507
508    pool = get_pool_resource(ua);
509    if (!pool) {
510       return 1;
511    }
512
513    switch (create_pool(ua->db, pool)) {
514    case 0:
515       bsendmsg(ua, _("Error: Pool %s already exists.\n\
516 Use update to change it.\n"), pool->hdr.name);
517       break;
518
519    case -1:
520       bsendmsg(ua, db_strerror(ua->db));
521       break;
522
523    default:
524      break;
525    }
526    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
527    return 1;
528 }
529
530
531
532
533 /*
534  * Update a Pool Record in the database.
535  *  It is always updated from the Resource record.
536  *
537  *    update pool=<pool-name>
538  *         updates pool from Pool resource
539  *    update media pool=<pool-name> volume=<volume-name>
540  *         changes pool info for volume
541  */
542 static int updatecmd(UAContext *ua, char *cmd) 
543 {
544    static char *kw[] = {
545       N_("media"),
546       N_("volume"),
547       N_("pool"),
548       NULL};
549
550    if (!open_db(ua)) {
551       return 1;
552    }
553
554    switch (find_arg_keyword(ua, kw)) {
555       case 0:
556       case 1:
557          update_volume(ua);
558          return 1;
559       case 2:
560          update_pool(ua);
561          return 1;
562       default:
563          break;
564    }
565     
566    start_prompt(ua, _("Update choice:\n"));
567    add_prompt(ua, _("Volume parameters"));
568    add_prompt(ua, _("Pool from resource"));
569    switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
570       case 0:
571          update_volume(ua);
572          break;
573       case 1:
574          update_pool(ua);
575          break;
576       default:
577          break;
578    }
579    return 1;
580 }
581
582 /*
583  * Update a media record -- allows you to change the
584  *  Volume status. E.g. if you want Bacula to stop
585  *  writing on the volume, set it to anything other
586  *  than Append.
587  */              
588 static int update_volume(UAContext *ua)
589 {
590    POOL_DBR pr;
591    MEDIA_DBR mr;
592    POOLMEM *query;
593    char ed1[30];
594
595    if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
596       return 0;
597    }
598
599    for (int done=0; !done; ) {
600       if (!db_get_media_record(ua->db, &mr)) {
601          if (mr.MediaId != 0) {
602             bsendmsg(ua, _("Volume record for MediaId %d not found.\n"), mr.MediaId);
603          } else {
604             bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
605          }
606          return 0;
607       }
608       bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
609       start_prompt(ua, _("Parameters to modify:\n"));
610       add_prompt(ua, _("Volume Status"));
611       add_prompt(ua, _("Volume Retention Period"));
612       add_prompt(ua, _("Volume Use Duration"));
613       add_prompt(ua, _("Maximum Volume Jobs"));
614       add_prompt(ua, _("Recycle Flag"));
615       add_prompt(ua, _("Slot"));
616       add_prompt(ua, _("Done"));
617       switch (do_prompt(ua, _("Select parameter to modify"), NULL)) {
618       case 0:                         /* Volume Status */
619          /* Modify Volume Status */
620          bsendmsg(ua, _("Current value is: %s\n"), mr.VolStatus);
621          start_prompt(ua, _("Possible Values are:\n"));
622          add_prompt(ua, "Append");      /* Better not translate these as */
623          add_prompt(ua, "Archive");     /* They are known in the database code */
624          add_prompt(ua, "Disabled");
625          add_prompt(ua, "Full");
626          add_prompt(ua, "Used");
627          if (strcmp(mr.VolStatus, "Purged") == 0) {
628             add_prompt(ua, "Recycle");
629          }
630          add_prompt(ua, "Read-Only");
631          if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
632             return 1;
633          }
634          strcpy(mr.VolStatus, ua->cmd);
635          query = get_pool_memory(PM_MESSAGE);
636          Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u",
637             mr.VolStatus, mr.MediaId);
638          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
639             bsendmsg(ua, "%s", db_strerror(ua->db));
640          }       
641          free_pool_memory(query);
642          break;
643       case 1:                         /* Retention */
644          bsendmsg(ua, _("Current value is: %s\n"),
645             edit_utime(mr.VolRetention, ed1));
646          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
647             return 0;
648          }
649          if (!duration_to_utime(ua->cmd, &mr.VolRetention)) {
650             bsendmsg(ua, _("Invalid retention period specified.\n"));
651             break;
652          }
653          query = get_pool_memory(PM_MESSAGE);
654          Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u",
655             edit_uint64(mr.VolRetention, ed1), mr.MediaId);
656          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
657             bsendmsg(ua, "%s", db_strerror(ua->db));
658          }       
659          free_pool_memory(query);
660          break;
661
662       case 2:                         /* Use Duration */
663          bsendmsg(ua, _("Current value is: %s\n"),
664             edit_utime(mr.VolUseDuration, ed1));
665          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
666             return 0;
667          }
668          if (!duration_to_utime(ua->cmd, &mr.VolUseDuration)) {
669             bsendmsg(ua, _("Invalid use duration specified.\n"));
670             break;
671          }
672          query = get_pool_memory(PM_MESSAGE);
673          Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u",
674             edit_uint64(mr.VolUseDuration, ed1), mr.MediaId);
675          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
676             bsendmsg(ua, "%s", db_strerror(ua->db));
677          }       
678          free_pool_memory(query);
679          break;
680
681       case 3:                         /* Max Jobs */
682          int32_t maxjobs;
683          bsendmsg(ua, _("Current value is: %u\n"), mr.MaxVolJobs);
684          if (!get_cmd(ua, _("Enter new Maximum Jobs: "))) {
685             return 0;
686          }
687          maxjobs = atoi(ua->cmd);
688          if (maxjobs < 0) {
689             bsendmsg(ua, _("Invalid number, it must be 0 or greater\n"));
690             break;
691          } 
692          query = get_pool_memory(PM_MESSAGE);
693          Mmsg(&query, "UPDATE Media SET MaxVolJobs=%u WHERE MediaId=%u",
694             maxjobs, mr.MediaId);
695          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
696             bsendmsg(ua, "%s", db_strerror(ua->db));
697          } else {
698             bsendmsg(ua, "New value is: %u\n", maxjobs);
699          }
700          free_pool_memory(query);
701          break;
702
703
704       case 4:                         /* Recycle */
705          int recycle;
706          bsendmsg(ua, _("Current value is: %s\n"),
707             mr.Recycle==1?_("yes"):_("no"));
708          if (!get_cmd(ua, _("Enter new Recycle status: "))) {
709             return 0;
710          }
711          if (strcasecmp(ua->cmd, _("yes")) == 0) {
712             recycle = 1;
713          } else if (strcasecmp(ua->cmd, _("no")) == 0) {
714             recycle = 0;
715          } else {
716             bsendmsg(ua, _("Invalid recycle status specified.\n"));
717             break;
718          }
719          query = get_pool_memory(PM_MESSAGE);
720          Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u",
721             recycle, mr.MediaId);
722          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
723             bsendmsg(ua, "%s", db_strerror(ua->db));
724          }       
725          free_pool_memory(query);
726          break;
727
728       case 5:                         /* Slot */
729          int slot;
730          bsendmsg(ua, _("Current value is: %d\n"), mr.Slot);
731          if (!get_cmd(ua, _("Enter new Slot: "))) {
732             return 0;
733          }
734          slot = atoi(ua->cmd);
735          if (slot < 0) {
736             bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
737             break;
738          } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
739             bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
740                pr.MaxVols);
741             break;
742          }
743          query = get_pool_memory(PM_MESSAGE);
744          Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%u",
745             slot, mr.MediaId);
746          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
747             bsendmsg(ua, "%s", db_strerror(ua->db));
748          } else {
749             bsendmsg(ua, "New value is: %d\n", slot);
750          }
751          free_pool_memory(query);
752          break;
753
754       default:                        /* Done or error */
755          bsendmsg(ua, "Selection done.\n");
756          return 1;
757       }
758    }
759    return 1;
760 }
761
762 /* 
763  * Update pool record -- pull info from current POOL resource
764  */
765 static int update_pool(UAContext *ua)
766 {
767    POOL_DBR  pr;
768    int id;
769    POOL *pool;
770    
771    
772    pool = get_pool_resource(ua);
773    if (!pool) {
774       return 0;
775    }
776
777    memset(&pr, 0, sizeof(pr));
778    strcpy(pr.Name, pool->hdr.name);
779    if (!get_pool_dbr(ua, &pr)) {
780       return 0;
781    }
782    strcpy(pr.PoolType, pool->pool_type);
783    if (pr.MaxVols != pool->max_volumes) {
784       pr.MaxVols = pool->max_volumes;
785    }
786    if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
787       pr.MaxVols = pr.NumVols;
788    }
789    pr.UseOnce = pool->use_volume_once;
790    pr.UseCatalog = pool->use_catalog;
791    pr.AcceptAnyVolume = pool->accept_any_volume;
792    pr.VolRetention = pool->VolRetention;
793    pr.VolUseDuration = pool->VolUseDuration;
794    pr.MaxVolJobs = pool->MaxVolJobs;
795    if (pool->label_format) {
796       strcpy(pr.LabelFormat, pool->label_format);
797    } else {
798       strcpy(pr.LabelFormat, "*");    /* none */
799    }
800    id = db_update_pool_record(ua->db, &pr);
801    if (id <= 0) {
802       bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
803          id, db_strerror(ua->db));
804    }
805    bsendmsg(ua, _("Pool DB record updated from resource.\n"));
806    return 1;
807 }
808
809
810 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
811 {
812    BSOCK *sd;
813
814    ua->jcr->store = store;
815    /* Try connecting for up to 15 seconds */
816    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
817       store->hdr.name, store->address, store->SDport);
818    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
819       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
820       return;
821    }
822    Dmsg0(120, _("Connected to storage daemon\n"));
823    sd = ua->jcr->store_bsock;
824    bnet_fsend(sd, "setdebug=%d\n", level);
825    if (bnet_recv(sd) >= 0) {
826       bsendmsg(ua, "%s", sd->msg);
827    }
828    bnet_sig(sd, BNET_TERMINATE);
829    bnet_close(sd);
830    ua->jcr->store_bsock = NULL;
831    return;  
832 }
833    
834 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
835 {
836    BSOCK *fd;
837
838    /* Connect to File daemon */
839
840    ua->jcr->client = client;
841    /* Try to connect for 15 seconds */
842    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
843       client->hdr.name, client->address, client->FDport);
844    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
845       bsendmsg(ua, _("Failed to connect to Client.\n"));
846       return;
847    }
848    Dmsg0(120, "Connected to file daemon\n");
849    fd = ua->jcr->file_bsock;
850    bnet_fsend(fd, "setdebug=%d\n", level);
851    if (bnet_recv(fd) >= 0) {
852       bsendmsg(ua, "%s", fd->msg);
853    }
854    bnet_sig(fd, BNET_TERMINATE);
855    bnet_close(fd);
856    ua->jcr->file_bsock = NULL;
857
858    return;  
859 }
860
861
862 static void do_all_setdebug(UAContext *ua, int level)
863 {
864    STORE *store, **unique_store;
865    CLIENT *client, **unique_client;
866    int i, j, found;
867
868    /* Director */
869    debug_level = level;
870
871    /* Count Storage items */
872    LockRes();
873    store = NULL;
874    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
875       { }
876    unique_store = (STORE **) malloc(i * sizeof(STORE));
877    /* Find Unique Storage address/port */         
878    store = (STORE *)GetNextRes(R_STORAGE, NULL);
879    i = 0;
880    unique_store[i++] = store;
881    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
882       found = 0;
883       for (j=0; j<i; j++) {
884          if (strcmp(unique_store[j]->address, store->address) == 0 &&
885              unique_store[j]->SDport == store->SDport) {
886             found = 1;
887             break;
888          }
889       }
890       if (!found) {
891          unique_store[i++] = store;
892          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
893       }
894    }
895    UnlockRes();
896
897    /* Call each unique Storage daemon */
898    for (j=0; j<i; j++) {
899       do_storage_setdebug(ua, unique_store[j], level);
900    }
901    free(unique_store);
902
903    /* Count Client items */
904    LockRes();
905    client = NULL;
906    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
907       { }
908    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
909    /* Find Unique Client address/port */         
910    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
911    i = 0;
912    unique_client[i++] = client;
913    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
914       found = 0;
915       for (j=0; j<i; j++) {
916          if (strcmp(unique_client[j]->address, client->address) == 0 &&
917              unique_client[j]->FDport == client->FDport) {
918             found = 1;
919             break;
920          }
921       }
922       if (!found) {
923          unique_client[i++] = client;
924          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
925       }
926    }
927    UnlockRes();
928
929    /* Call each unique File daemon */
930    for (j=0; j<i; j++) {
931       do_client_setdebug(ua, unique_client[j], level);
932    }
933    free(unique_client);
934 }
935
936 /*
937  * setdebug level=nn all
938  */
939 static int setdebugcmd(UAContext *ua, char *cmd)
940 {
941    STORE *store;
942    CLIENT *client;
943    int level;
944    int i;
945
946    if (!open_db(ua)) {
947       return 1;
948    }
949    Dmsg1(120, "setdebug:%s:\n", cmd);
950
951    level = -1;
952    for (i=1; i<ua->argc; i++) {
953       if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
954          level = atoi(ua->argv[i]);
955          break;
956       }
957    }
958    if (level < 0) {
959       if (!get_cmd(ua, _("Enter new debug level: "))) {
960          return 1;
961       }
962       level = atoi(ua->cmd);
963    }
964    if (level < 0) {
965       bsendmsg(ua, _("level cannot be negative.\n"));
966       return 1;
967    }
968
969    /* General debug? */
970    for (i=1; i<ua->argc; i++) {
971       if (strcasecmp(ua->argk[i], _("all")) == 0) {
972          do_all_setdebug(ua, level);
973          return 1;
974       }
975       if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
976           strcasecmp(ua->argk[i], _("director")) == 0) {
977          debug_level = level;
978          return 1;
979       }
980       if (strcasecmp(ua->argk[i], _("client")) == 0) {
981          client = NULL;
982          if (ua->argv[i]) {
983             client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
984             if (client) {
985                do_client_setdebug(ua, client, level);
986                return 1;
987             }
988          }
989          client = select_client_resource(ua);   
990          if (client) {
991             do_client_setdebug(ua, client, level);
992             return 1;
993          }
994
995          store = get_storage_resource(ua, cmd);
996          if (store) {
997             do_storage_setdebug(ua, store, level);
998             return 1;
999          }
1000       }
1001    } 
1002    /*
1003     * We didn't find an appropriate keyword above, so
1004     * prompt the user.
1005     */
1006    start_prompt(ua, _("Available daemons are: \n"));
1007    add_prompt(ua, _("Director"));
1008    add_prompt(ua, _("Storage"));
1009    add_prompt(ua, _("Client"));
1010    add_prompt(ua, _("All"));
1011    switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
1012       case 0:                         /* Director */
1013          debug_level = level;
1014          break;
1015       case 1:
1016          store = get_storage_resource(ua, cmd);
1017          if (store) {
1018             do_storage_setdebug(ua, store, level);
1019          }
1020          break;
1021       case 2:
1022          client = select_client_resource(ua);
1023          if (client) {
1024             do_client_setdebug(ua, client, level);
1025          }
1026          break;
1027       case 3:
1028          do_all_setdebug(ua, level);
1029          break;
1030       default:
1031          break;
1032    }
1033    return 1;
1034 }
1035
1036
1037
1038 /*
1039  * Delete Pool records (should purge Media with it).
1040  *
1041  *  delete pool=<pool-name>
1042  *  delete media pool=<pool-name> volume=<name>
1043  */
1044 static int deletecmd(UAContext *ua, char *cmd)
1045 {
1046    static char *keywords[] = {
1047       N_("volume"),
1048       N_("pool"),
1049       NULL};
1050
1051    if (!open_db(ua)) {
1052       return 1;
1053    }
1054
1055    bsendmsg(ua, _(
1056 "In general it is not a good idea to delete either a\n"
1057 "Pool or a Volume since they may contain data.\n\n"));
1058      
1059    switch (find_arg_keyword(ua, keywords)) {
1060       case 0:
1061          delete_volume(ua);     
1062          return 1;
1063       case 1:
1064          delete_pool(ua);
1065          return 1;
1066       default:
1067          break;
1068    }
1069    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1070       case 0:
1071          delete_volume(ua);
1072          break;
1073       case 1:
1074          delete_pool(ua);
1075          break;
1076       default:
1077          bsendmsg(ua, _("Nothing done.\n"));
1078          break;
1079    }
1080    return 1;
1081 }
1082
1083 /*
1084  * Delete media records from database -- dangerous 
1085  */
1086 static int delete_volume(UAContext *ua)
1087 {
1088    POOL_DBR pr;
1089    MEDIA_DBR mr;
1090
1091    if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
1092       return 1;
1093    }
1094    bsendmsg(ua, _("\nThis command will delete volume %s\n"
1095       "and all Jobs saved on that volume from the Catalog\n"),
1096       mr.VolumeName);
1097
1098    if (!get_cmd(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1099       return 1;
1100    }
1101    if (strcasecmp(ua->cmd, _("yes")) == 0) {
1102       db_delete_media_record(ua->db, &mr);
1103    }
1104    return 1;
1105 }
1106
1107 /*
1108  * Delete a pool record from the database -- dangerous   
1109  */
1110 static int delete_pool(UAContext *ua)
1111 {
1112    POOL_DBR  pr;
1113    
1114    memset(&pr, 0, sizeof(pr));
1115
1116    if (!get_pool_dbr(ua, &pr)) {
1117       return 1;
1118    }
1119    if (!get_cmd(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1120       return 1;
1121    }
1122    if (strcasecmp(ua->cmd, _("yes")) == 0) {
1123       db_delete_pool_record(ua->db, &pr);
1124    }
1125    return 1;
1126 }
1127
1128
1129 /*
1130  * Label a tape 
1131  *  
1132  *   label storage=xxx volume=vvv
1133  */
1134 static int labelcmd(UAContext *ua, char *cmd)
1135 {
1136    STORE *store;
1137    BSOCK *sd;
1138    char dev_name[MAX_NAME_LENGTH];
1139    MEDIA_DBR mr;
1140    POOL_DBR pr;
1141    int ok = FALSE;
1142    int mounted = FALSE;
1143    int i;
1144    int slot = 0;
1145    static char *keyword[] = {
1146       "volume",
1147       NULL};
1148
1149    if (!open_db(ua)) {
1150       return 1;
1151    }
1152    store = get_storage_resource(ua, cmd);
1153    if (!store) {
1154       return 1;
1155    }
1156
1157    i = find_arg_keyword(ua, keyword);
1158    if (i >=0 && ua->argv[i]) {
1159       strcpy(ua->cmd, ua->argv[i]);
1160       goto gotVol;
1161    }
1162
1163 getVol:
1164    if (!get_cmd(ua, _("Enter new Volume name: "))) {
1165       return 1;
1166    }
1167 gotVol:
1168    if (strchr(ua->cmd, '|')) {
1169       bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1170       goto getVol;
1171    }
1172    if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1173       bsendmsg(ua, _("Volume name too long.\n"));
1174       goto getVol;
1175    }
1176    if (strlen(ua->cmd) == 0) {
1177       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
1178       goto getVol;
1179    }
1180
1181
1182    memset(&mr, 0, sizeof(mr));
1183    strcpy(mr.VolumeName, ua->cmd);
1184    if (db_get_media_record(ua->db, &mr)) {
1185        bsendmsg(ua, _("Media record for Volume %s already exists.\n"), 
1186           mr.VolumeName);
1187        return 1;
1188    }
1189
1190    /* Do some more checking on slot ****FIXME**** */
1191    if (store->autochanger) {
1192       if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
1193          return 1;
1194       }
1195       slot = atoi(ua->cmd);
1196    }
1197    strcpy(mr.MediaType, store->media_type);
1198    mr.Slot = slot;
1199
1200    memset(&pr, 0, sizeof(pr));
1201    if (!select_pool_dbr(ua, &pr)) {
1202       return 1;
1203    }
1204    mr.PoolId = pr.PoolId;
1205    strcpy(mr.VolStatus, "Append");
1206    mr.Recycle = pr.Recycle;
1207    mr.VolRetention = pr.VolRetention;
1208
1209    ua->jcr->store = store;
1210    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
1211       store->hdr.name, store->address, store->SDport);
1212    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1213       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1214       return 1;   
1215    }
1216    sd = ua->jcr->store_bsock;
1217    strcpy(dev_name, store->dev_name);
1218    bash_spaces(dev_name);
1219    bash_spaces(mr.VolumeName);
1220    bash_spaces(mr.MediaType);
1221    bash_spaces(pr.Name);
1222    bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
1223       dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
1224    bsendmsg(ua, "Sending label command ...\n");
1225    while (bget_msg(sd, 0) >= 0) {
1226       bsendmsg(ua, "%s", sd->msg);
1227       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1228          ok = TRUE;
1229       }
1230    }
1231    ua->jcr->store_bsock = NULL;
1232    unbash_spaces(dev_name);
1233    unbash_spaces(mr.VolumeName);
1234    unbash_spaces(mr.MediaType);
1235    unbash_spaces(pr.Name);
1236    if (ok) {
1237       if (db_create_media_record(ua->db, &mr)) {
1238          bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1239             mr.VolumeName);
1240          if (ua->automount) {
1241             bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1242             bash_spaces(dev_name);
1243             bnet_fsend(sd, "mount %s", dev_name);
1244             unbash_spaces(dev_name);
1245             while (bnet_recv(sd) >= 0) {
1246                bsendmsg(ua, "%s", sd->msg);
1247                /* Here we can get
1248                 *  3001 OK mount. Device=xxx      or
1249                 *  3001 Mounted Volume vvvv
1250                 */
1251                if (strncmp(sd->msg, "3001 ", 5) == 0) {
1252                   mounted = TRUE;
1253                   /***** ****FIXME***** find job waiting for  
1254                    ***** mount, and change to waiting for SD  
1255                    */
1256                }
1257             }
1258          }
1259       } else {
1260          bsendmsg(ua, "%s", db_strerror(ua->db));
1261       }
1262    }
1263    if (!mounted) {
1264       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1265    }
1266    bnet_sig(sd, BNET_TERMINATE);
1267    bnet_close(sd);
1268    return 1;
1269 }
1270
1271 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
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    Dmsg1(120, "mount: %s\n", ua->UA_sock->msg);
1282
1283    store = get_storage_resource(ua, cmd);
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    if (mount) {
1300       bnet_fsend(sd, "mount %s", dev_name);
1301    } else {
1302       bnet_fsend(sd, "unmount %s", dev_name);
1303    }
1304    while (bnet_recv(sd) >= 0) {
1305       bsendmsg(ua, "%s", sd->msg);
1306       if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1307           /***** ****FIXME**** fix JobStatus */
1308       }
1309    }
1310    bnet_sig(sd, BNET_TERMINATE);
1311    bnet_close(sd);
1312    ua->jcr->store_bsock = NULL;
1313 }
1314
1315 /*
1316  * mount [storage | device] <name>
1317  */
1318 static int mountcmd(UAContext *ua, char *cmd)
1319 {
1320    do_mount_cmd(1, ua, cmd);          /* mount */
1321    return 1;
1322 }
1323
1324
1325 /*
1326  * unmount [storage | device] <name>
1327  */
1328 static int unmountcmd(UAContext *ua, char *cmd)
1329 {
1330    do_mount_cmd(0, ua, cmd);          /* unmount */
1331    return 1;
1332 }
1333
1334
1335 /*
1336  * Switch databases
1337  *   use catalog=<name>
1338  */
1339 static int usecmd(UAContext *ua, char *cmd)
1340 {
1341    CAT *oldcatalog, *catalog;
1342
1343
1344    close_db(ua);                      /* close any previously open db */
1345    oldcatalog = ua->catalog;
1346
1347    if (!(catalog = get_catalog_resource(ua))) {
1348       ua->catalog = oldcatalog;
1349    } else {
1350       ua->catalog = catalog;
1351    }
1352    if (open_db(ua)) {
1353       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1354          ua->catalog->hdr.name, ua->catalog->db_name);
1355    }
1356    return 1;
1357 }
1358
1359 int quitcmd(UAContext *ua, char *cmd) 
1360 {
1361    ua->quit = TRUE;
1362    return 1;
1363 }
1364
1365 static int helpcmd(UAContext *ua, char *cmd)
1366 {
1367    unsigned int i;
1368
1369 /* usage(); */
1370    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1371    for (i=0; i<comsize; i++) {
1372       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1373    }
1374    bsendmsg(ua, "\n");
1375    return 1;
1376 }
1377
1378 static int versioncmd(UAContext *ua, char *cmd)
1379 {
1380    bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
1381    return 1;
1382 }
1383
1384
1385 /* A bit brain damaged in that if the user has not done
1386  * a "use catalog xxx" command, we simply find the first
1387  * catalog resource and open it.
1388  */
1389 int open_db(UAContext *ua)
1390 {
1391    if (ua->db) {
1392       return 1;
1393    }
1394    if (!ua->catalog) {
1395       LockRes();
1396       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1397       UnlockRes();
1398       if (!ua->catalog) {    
1399          bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
1400          return 0;
1401       } else {
1402          bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"), 
1403             ua->catalog->hdr.name, ua->catalog->db_name);
1404       }
1405    }
1406
1407    Dmsg0(150, "Open database\n");
1408    ua->db = db_init_database(NULL, ua->catalog->db_name, ua->catalog->db_user,
1409                              ua->catalog->db_password);
1410    if (!db_open_database(ua->db)) {
1411       bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"), 
1412          ua->catalog->db_name, db_strerror(ua->db));
1413       close_db(ua);
1414       return 0;
1415    }
1416    ua->jcr->db = ua->db;
1417    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1418    return 1;
1419 }
1420
1421 void close_db(UAContext *ua)
1422 {
1423    if (ua->db) {
1424       db_close_database(ua->db);
1425    }
1426    ua->db = NULL;
1427    ua->jcr->db = NULL;
1428 }