]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_cmds.c
Important protocol change -- see kes29Oct02
[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.AutoPrune = pool->AutoPrune;
480    if (pool->label_format) {
481       strcpy(pr.LabelFormat, pool->label_format);
482    } else {
483       strcpy(pr.LabelFormat, "*");    /* none */
484    }
485
486    if (!db_create_pool_record(db, &pr)) {
487       return -1;                      /* error */
488    }
489    return 1;
490 }
491
492
493
494 /*
495  * Create a Pool Record in the database.
496  *  It is always created from the Resource record.
497  */
498 static int createcmd(UAContext *ua, char *cmd) 
499 {
500    POOL *pool;
501
502    if (!open_db(ua)) {
503       return 1;
504    }
505
506    pool = get_pool_resource(ua);
507    if (!pool) {
508       return 1;
509    }
510
511    switch (create_pool(ua->db, pool)) {
512    case 0:
513       bsendmsg(ua, _("Error: Pool %s already exists.\n\
514 Use update to change it.\n"), pool->hdr.name);
515       break;
516
517    case -1:
518       bsendmsg(ua, db_strerror(ua->db));
519       break;
520
521    default:
522      break;
523    }
524    bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
525    return 1;
526 }
527
528
529
530
531 /*
532  * Update a Pool Record in the database.
533  *  It is always updated from the Resource record.
534  *
535  *    update pool=<pool-name>
536  *         updates pool from Pool resource
537  *    update media pool=<pool-name> volume=<volume-name>
538  *         changes pool info for volume
539  */
540 static int updatecmd(UAContext *ua, char *cmd) 
541 {
542    static char *kw[] = {
543       N_("media"),
544       N_("volume"),
545       N_("pool"),
546       NULL};
547
548    if (!open_db(ua)) {
549       return 1;
550    }
551
552    switch (find_arg_keyword(ua, kw)) {
553       case 0:
554       case 1:
555          update_volume(ua);
556          return 1;
557       case 2:
558          update_pool(ua);
559          return 1;
560       default:
561          break;
562    }
563     
564    start_prompt(ua, _("Update choice:\n"));
565    add_prompt(ua, _("Volume parameters"));
566    add_prompt(ua, _("Pool from resource"));
567    switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
568       case 0:
569          update_volume(ua);
570          break;
571       case 1:
572          update_pool(ua);
573          break;
574       default:
575          break;
576    }
577    return 1;
578 }
579
580 /*
581  * Update a media record -- allows you to change the
582  *  Volume status. E.g. if you want Bacula to stop
583  *  writing on the volume, set it to anything other
584  *  than Append.
585  */              
586 static int update_volume(UAContext *ua)
587 {
588    POOL_DBR pr;
589    MEDIA_DBR mr;
590    POOLMEM *query;
591    char ed1[30];
592
593    if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
594       return 0;
595    }
596
597    for (int done=0; !done; ) {
598       if (!db_get_media_record(ua->db, &mr)) {
599          if (mr.MediaId != 0) {
600             bsendmsg(ua, _("Volume record for MediaId %d not found.\n"), mr.MediaId);
601          } else {
602             bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
603          }
604          return 0;
605       }
606       bsendmsg(ua, _("Updating Volume %s\n"), mr.VolumeName);
607       start_prompt(ua, _("Parameters to modify:\n"));
608       add_prompt(ua, _("Volume Status"));
609       add_prompt(ua, _("Volume Retention Period"));
610       add_prompt(ua, _("Recycle Flag"));
611       add_prompt(ua, _("Slot"));
612       add_prompt(ua, _("Done"));
613       switch (do_prompt(ua, _("Select parameter to modify"), NULL)) {
614       case 0:                         /* Volume Status */
615          /* Modify Volume Status */
616          bsendmsg(ua, _("Current value is: %s\n"), mr.VolStatus);
617          start_prompt(ua, _("Possible Values are:\n"));
618          add_prompt(ua, "Append");
619          add_prompt(ua, "Archive");
620          add_prompt(ua, "Disabled");
621          add_prompt(ua, "Full");
622          if (strcmp(mr.VolStatus, "Purged") == 0) {
623             add_prompt(ua, "Recycle");
624          }
625          add_prompt(ua, "Read-Only");
626          if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
627             return 1;
628          }
629          strcpy(mr.VolStatus, ua->cmd);
630          query = get_pool_memory(PM_MESSAGE);
631          Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%d",
632             mr.VolStatus, mr.MediaId);
633          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
634             bsendmsg(ua, "%s", db_strerror(ua->db));
635          }       
636          free_pool_memory(query);
637          break;
638       case 1:                         /* Retention */
639          bsendmsg(ua, _("Current value is: %s\n"),
640             edit_btime(mr.VolRetention, ed1));
641          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
642             return 0;
643          }
644          if (!string_to_btime(ua->cmd, &mr.VolRetention)) {
645             bsendmsg(ua, _("Invalid retention period specified.\n"));
646             break;
647          }
648          query = get_pool_memory(PM_MESSAGE);
649          Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%d",
650             edit_uint64(mr.VolRetention, ed1), mr.MediaId);
651          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
652             bsendmsg(ua, "%s", db_strerror(ua->db));
653          }       
654          free_pool_memory(query);
655          break;
656       case 2:                         /* Recycle */
657          int recycle;
658          bsendmsg(ua, _("Current value is: %s\n"),
659             mr.Recycle==1?_("yes"):_("no"));
660          if (!get_cmd(ua, _("Enter new Recycle status: "))) {
661             return 0;
662          }
663          if (strcasecmp(ua->cmd, _("yes")) == 0) {
664             recycle = 1;
665          } else if (strcasecmp(ua->cmd, _("no")) == 0) {
666             recycle = 0;
667          } else {
668             bsendmsg(ua, _("Invalid recycle status specified.\n"));
669             break;
670          }
671          query = get_pool_memory(PM_MESSAGE);
672          Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%d",
673             recycle, mr.MediaId);
674          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
675             bsendmsg(ua, "%s", db_strerror(ua->db));
676          }       
677          free_pool_memory(query);
678          break;
679
680       case 3:                         /* Slot */
681          int slot;
682          bsendmsg(ua, _("Current value is: %d\n"), mr.Slot);
683          if (!get_cmd(ua, _("Enter new Slot: "))) {
684             return 0;
685          }
686          slot = atoi(ua->cmd);
687          if (slot < 0) {
688             bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
689             break;
690          } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
691             bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
692                pr.MaxVols);
693             break;
694          }
695          query = get_pool_memory(PM_MESSAGE);
696          Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%d",
697             slot, mr.MediaId);
698          if (!db_sql_query(ua->db, query, NULL, NULL)) {  
699             bsendmsg(ua, "%s", db_strerror(ua->db));
700          } else {
701             bsendmsg(ua, "New value is: %d\n", slot);
702          }
703          free_pool_memory(query);
704          break;
705
706          
707       default:                        /* Done or error */
708          bsendmsg(ua, "Selection done.\n");
709          return 1;
710       }
711    }
712    return 1;
713 }
714
715 /* 
716  * Update pool record -- pull info from current POOL resource
717  */
718 static int update_pool(UAContext *ua)
719 {
720    POOL_DBR  pr;
721    int id;
722    POOL *pool;
723    
724    
725    pool = get_pool_resource(ua);
726    if (!pool) {
727       return 0;
728    }
729
730    memset(&pr, 0, sizeof(pr));
731    strcpy(pr.Name, pool->hdr.name);
732    if (!get_pool_dbr(ua, &pr)) {
733       return 0;
734    }
735    strcpy(pr.PoolType, pool->pool_type);
736    if (pr.MaxVols != (uint32_t) (pool->max_volumes)) {
737       pr.MaxVols = pool->max_volumes;
738    }
739    if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
740       pr.MaxVols = pr.NumVols;
741    }
742    pr.UseOnce = pool->use_volume_once;
743    pr.UseCatalog = pool->use_catalog;
744    pr.AcceptAnyVolume = pool->accept_any_volume;
745    if (pool->label_format) {
746       strcpy(pr.LabelFormat, pool->label_format);
747    } else {
748       strcpy(pr.LabelFormat, "*");    /* none */
749    }
750    id = db_update_pool_record(ua->db, &pr);
751    if (id <= 0) {
752       bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
753          id, db_strerror(ua->db));
754    }
755    bsendmsg(ua, _("Pool DB record updated from resource.\n"));
756    return 1;
757 }
758
759
760 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
761 {
762    BSOCK *sd;
763
764    ua->jcr->store = store;
765    /* Try connecting for up to 15 seconds */
766    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
767       store->hdr.name, store->address, store->SDport);
768    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
769       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
770       return;
771    }
772    Dmsg0(120, _("Connected to storage daemon\n"));
773    sd = ua->jcr->store_bsock;
774    bnet_fsend(sd, "setdebug=%d\n", level);
775    if (bnet_recv(sd) >= 0) {
776       bsendmsg(ua, "%s", sd->msg);
777    }
778    bnet_sig(sd, BNET_TERMINATE);
779    bnet_close(sd);
780    ua->jcr->store_bsock = NULL;
781    return;  
782 }
783    
784 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
785 {
786    BSOCK *fd;
787
788    /* Connect to File daemon */
789
790    ua->jcr->client = client;
791    /* Try to connect for 15 seconds */
792    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
793       client->hdr.name, client->address, client->FDport);
794    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
795       bsendmsg(ua, _("Failed to connect to Client.\n"));
796       return;
797    }
798    Dmsg0(120, "Connected to file daemon\n");
799    fd = ua->jcr->file_bsock;
800    bnet_fsend(fd, "setdebug=%d\n", level);
801    if (bnet_recv(fd) >= 0) {
802       bsendmsg(ua, "%s", fd->msg);
803    }
804    bnet_sig(fd, BNET_TERMINATE);
805    bnet_close(fd);
806    ua->jcr->file_bsock = NULL;
807
808    return;  
809 }
810
811
812 static void do_all_setdebug(UAContext *ua, int level)
813 {
814    STORE *store, **unique_store;
815    CLIENT *client, **unique_client;
816    int i, j, found;
817
818    /* Director */
819    debug_level = level;
820
821    /* Count Storage items */
822    LockRes();
823    store = NULL;
824    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
825       { }
826    unique_store = (STORE **) malloc(i * sizeof(STORE));
827    /* Find Unique Storage address/port */         
828    store = (STORE *)GetNextRes(R_STORAGE, NULL);
829    i = 0;
830    unique_store[i++] = store;
831    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
832       found = 0;
833       for (j=0; j<i; j++) {
834          if (strcmp(unique_store[j]->address, store->address) == 0 &&
835              unique_store[j]->SDport == store->SDport) {
836             found = 1;
837             break;
838          }
839       }
840       if (!found) {
841          unique_store[i++] = store;
842          Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
843       }
844    }
845    UnlockRes();
846
847    /* Call each unique Storage daemon */
848    for (j=0; j<i; j++) {
849       do_storage_setdebug(ua, unique_store[j], level);
850    }
851    free(unique_store);
852
853    /* Count Client items */
854    LockRes();
855    client = NULL;
856    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
857       { }
858    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
859    /* Find Unique Client address/port */         
860    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
861    i = 0;
862    unique_client[i++] = client;
863    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
864       found = 0;
865       for (j=0; j<i; j++) {
866          if (strcmp(unique_client[j]->address, client->address) == 0 &&
867              unique_client[j]->FDport == client->FDport) {
868             found = 1;
869             break;
870          }
871       }
872       if (!found) {
873          unique_client[i++] = client;
874          Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
875       }
876    }
877    UnlockRes();
878
879    /* Call each unique File daemon */
880    for (j=0; j<i; j++) {
881       do_client_setdebug(ua, unique_client[j], level);
882    }
883    free(unique_client);
884 }
885
886 /*
887  * setdebug level=nn all
888  */
889 static int setdebugcmd(UAContext *ua, char *cmd)
890 {
891    STORE *store;
892    CLIENT *client;
893    int level;
894    int i;
895
896    if (!open_db(ua)) {
897       return 1;
898    }
899    Dmsg1(120, "setdebug:%s:\n", cmd);
900
901    level = -1;
902    for (i=1; i<ua->argc; i++) {
903       if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
904          level = atoi(ua->argv[i]);
905          break;
906       }
907    }
908    if (level < 0) {
909       if (!get_cmd(ua, _("Enter new debug level: "))) {
910          return 1;
911       }
912       level = atoi(ua->cmd);
913    }
914    if (level < 0) {
915       bsendmsg(ua, _("level cannot be negative.\n"));
916       return 1;
917    }
918
919    /* General debug? */
920    for (i=1; i<ua->argc; i++) {
921       if (strcasecmp(ua->argk[i], _("all")) == 0) {
922          do_all_setdebug(ua, level);
923          return 1;
924       }
925       if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
926           strcasecmp(ua->argk[i], _("director")) == 0) {
927          debug_level = level;
928          return 1;
929       }
930       if (strcasecmp(ua->argk[i], _("client")) == 0) {
931          client = NULL;
932          if (ua->argv[i]) {
933             client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
934             if (client) {
935                do_client_setdebug(ua, client, level);
936                return 1;
937             }
938          }
939          client = select_client_resource(ua);   
940          if (client) {
941             do_client_setdebug(ua, client, level);
942             return 1;
943          }
944
945          store = get_storage_resource(ua, cmd);
946          if (store) {
947             do_storage_setdebug(ua, store, level);
948             return 1;
949          }
950       }
951    } 
952    /*
953     * We didn't find an appropriate keyword above, so
954     * prompt the user.
955     */
956    start_prompt(ua, _("Available daemons are: \n"));
957    add_prompt(ua, _("Director"));
958    add_prompt(ua, _("Storage"));
959    add_prompt(ua, _("Client"));
960    add_prompt(ua, _("All"));
961    switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
962       case 0:                         /* Director */
963          debug_level = level;
964          break;
965       case 1:
966          store = get_storage_resource(ua, cmd);
967          if (store) {
968             do_storage_setdebug(ua, store, level);
969          }
970          break;
971       case 2:
972          client = select_client_resource(ua);
973          if (client) {
974             do_client_setdebug(ua, client, level);
975          }
976          break;
977       case 3:
978          do_all_setdebug(ua, level);
979          break;
980       default:
981          break;
982    }
983    return 1;
984 }
985
986
987
988 /*
989  * Delete Pool records (should purge Media with it).
990  *
991  *  delete pool=<pool-name>
992  *  delete media pool=<pool-name> volume=<name>
993  */
994 static int deletecmd(UAContext *ua, char *cmd)
995 {
996    static char *keywords[] = {
997       N_("volume"),
998       N_("pool"),
999       NULL};
1000
1001    if (!open_db(ua)) {
1002       return 1;
1003    }
1004
1005    bsendmsg(ua, _(
1006 "In general it is not a good idea to delete either a\n"
1007 "Pool or a Volume since they may contain data.\n\n"));
1008      
1009    switch (find_arg_keyword(ua, keywords)) {
1010       case 0:
1011          delete_volume(ua);     
1012          return 1;
1013       case 1:
1014          delete_pool(ua);
1015          return 1;
1016       default:
1017          break;
1018    }
1019    switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1020       case 0:
1021          delete_volume(ua);
1022          break;
1023       case 1:
1024          delete_pool(ua);
1025          break;
1026       default:
1027          bsendmsg(ua, _("Nothing done.\n"));
1028          break;
1029    }
1030    return 1;
1031 }
1032
1033 /*
1034  * Delete media records from database -- dangerous 
1035  */
1036 static int delete_volume(UAContext *ua)
1037 {
1038    POOL_DBR pr;
1039    MEDIA_DBR mr;
1040
1041    if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
1042       return 1;
1043    }
1044    bsendmsg(ua, _("\nThis command will delete volume %s\n"
1045       "and all Jobs saved on that volume from the Catalog\n"),
1046       mr.VolumeName);
1047
1048    if (!get_cmd(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1049       return 1;
1050    }
1051    if (strcasecmp(ua->cmd, _("yes")) == 0) {
1052       db_delete_media_record(ua->db, &mr);
1053    }
1054    return 1;
1055 }
1056
1057 /*
1058  * Delete a pool record from the database -- dangerous   
1059  */
1060 static int delete_pool(UAContext *ua)
1061 {
1062    POOL_DBR  pr;
1063    
1064    memset(&pr, 0, sizeof(pr));
1065
1066    if (!get_pool_dbr(ua, &pr)) {
1067       return 1;
1068    }
1069    if (!get_cmd(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1070       return 1;
1071    }
1072    if (strcasecmp(ua->cmd, _("yes")) == 0) {
1073       db_delete_pool_record(ua->db, &pr);
1074    }
1075    return 1;
1076 }
1077
1078
1079 /*
1080  * Label a tape 
1081  *  
1082  *   label storage=xxx volume=vvv
1083  */
1084 static int labelcmd(UAContext *ua, char *cmd)
1085 {
1086    STORE *store;
1087    BSOCK *sd;
1088    char dev_name[MAX_NAME_LENGTH];
1089    MEDIA_DBR mr;
1090    POOL_DBR pr;
1091    int ok = FALSE;
1092    int mounted = FALSE;
1093    int i;
1094    int slot = 0;
1095    static char *keyword[] = {
1096       "volume",
1097       NULL};
1098
1099    if (!open_db(ua)) {
1100       return 1;
1101    }
1102    store = get_storage_resource(ua, cmd);
1103    if (!store) {
1104       return 1;
1105    }
1106
1107    i = find_arg_keyword(ua, keyword);
1108    if (i >=0 && ua->argv[i]) {
1109       strcpy(ua->cmd, ua->argv[i]);
1110       goto gotVol;
1111    }
1112
1113 getVol:
1114    if (!get_cmd(ua, _("Enter new Volume name: "))) {
1115       return 1;
1116    }
1117 gotVol:
1118    if (strchr(ua->cmd, '|')) {
1119       bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1120       goto getVol;
1121    }
1122    if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1123       bsendmsg(ua, _("Volume name too long.\n"));
1124       goto getVol;
1125    }
1126    if (strlen(ua->cmd) == 0) {
1127       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
1128       goto getVol;
1129    }
1130
1131
1132    memset(&mr, 0, sizeof(mr));
1133    strcpy(mr.VolumeName, ua->cmd);
1134    if (db_get_media_record(ua->db, &mr)) {
1135        bsendmsg(ua, _("Media record for Volume %s already exists.\n"), 
1136           mr.VolumeName);
1137        return 1;
1138    }
1139
1140    /* Do some more checking on slot ****FIXME**** */
1141    if (store->autochanger) {
1142       if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
1143          return 1;
1144       }
1145       slot = atoi(ua->cmd);
1146    }
1147    strcpy(mr.MediaType, store->media_type);
1148    mr.Slot = slot;
1149
1150    memset(&pr, 0, sizeof(pr));
1151    if (!select_pool_dbr(ua, &pr)) {
1152       return 1;
1153    }
1154    mr.PoolId = pr.PoolId;
1155    strcpy(mr.VolStatus, "Append");
1156    mr.Recycle = pr.Recycle;
1157    mr.VolRetention = pr.VolRetention;
1158
1159    ua->jcr->store = store;
1160    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
1161       store->hdr.name, store->address, store->SDport);
1162    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1163       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1164       return 1;   
1165    }
1166    sd = ua->jcr->store_bsock;
1167    strcpy(dev_name, store->dev_name);
1168    bash_spaces(dev_name);
1169    bash_spaces(mr.VolumeName);
1170    bash_spaces(mr.MediaType);
1171    bash_spaces(pr.Name);
1172    bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
1173       dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
1174    bsendmsg(ua, "Sending label command ...\n");
1175    while (bget_msg(sd, 0) >= 0) {
1176       bsendmsg(ua, "%s", sd->msg);
1177       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1178          ok = TRUE;
1179       }
1180    }
1181    ua->jcr->store_bsock = NULL;
1182    unbash_spaces(dev_name);
1183    unbash_spaces(mr.VolumeName);
1184    unbash_spaces(mr.MediaType);
1185    unbash_spaces(pr.Name);
1186    if (ok) {
1187       if (db_create_media_record(ua->db, &mr)) {
1188          bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1189             mr.VolumeName);
1190          if (ua->automount) {
1191             bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1192             bash_spaces(dev_name);
1193             bnet_fsend(sd, "mount %s", dev_name);
1194             unbash_spaces(dev_name);
1195             while (bnet_recv(sd) >= 0) {
1196                bsendmsg(ua, "%s", sd->msg);
1197                /* Here we can get
1198                 *  3001 OK mount. Device=xxx      or
1199                 *  3001 Mounted Volume vvvv
1200                 */
1201                if (strncmp(sd->msg, "3001 ", 5) == 0) {
1202                   mounted = TRUE;
1203                   /***** ****FIXME***** find job waiting for  
1204                    ***** mount, and change to waiting for SD  
1205                    */
1206                }
1207             }
1208          }
1209       } else {
1210          bsendmsg(ua, "%s", db_strerror(ua->db));
1211       }
1212    }
1213    if (!mounted) {
1214       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1215    }
1216    bnet_sig(sd, BNET_TERMINATE);
1217    bnet_close(sd);
1218    return 1;
1219 }
1220
1221 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
1222 {
1223    STORE *store;
1224    BSOCK *sd;
1225    char dev_name[MAX_NAME_LENGTH];
1226
1227
1228    if (!open_db(ua)) {
1229       return;
1230    }
1231    Dmsg1(120, "mount: %s\n", ua->UA_sock->msg);
1232
1233    store = get_storage_resource(ua, cmd);
1234    if (!store) {
1235       return;
1236    }
1237
1238    Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1239       store->media_type, store->dev_name);
1240
1241    ua->jcr->store = store;
1242    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1243       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1244       return;
1245    }
1246    sd = ua->jcr->store_bsock;
1247    strcpy(dev_name, store->dev_name);
1248    bash_spaces(dev_name);
1249    if (mount) {
1250       bnet_fsend(sd, "mount %s", dev_name);
1251    } else {
1252       bnet_fsend(sd, "unmount %s", dev_name);
1253    }
1254    while (bnet_recv(sd) >= 0) {
1255       bsendmsg(ua, "%s", sd->msg);
1256       if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1257           /***** ****FIXME**** fix JobStatus */
1258       }
1259    }
1260    bnet_sig(sd, BNET_TERMINATE);
1261    bnet_close(sd);
1262    ua->jcr->store_bsock = NULL;
1263 }
1264
1265 /*
1266  * mount [storage | device] <name>
1267  */
1268 static int mountcmd(UAContext *ua, char *cmd)
1269 {
1270    do_mount_cmd(1, ua, cmd);          /* mount */
1271    return 1;
1272 }
1273
1274
1275 /*
1276  * unmount [storage | device] <name>
1277  */
1278 static int unmountcmd(UAContext *ua, char *cmd)
1279 {
1280    do_mount_cmd(0, ua, cmd);          /* unmount */
1281    return 1;
1282 }
1283
1284
1285 /*
1286  * Switch databases
1287  *   use catalog=<name>
1288  */
1289 static int usecmd(UAContext *ua, char *cmd)
1290 {
1291    CAT *oldcatalog, *catalog;
1292
1293
1294    close_db(ua);                      /* close any previously open db */
1295    oldcatalog = ua->catalog;
1296
1297    if (!(catalog = get_catalog_resource(ua))) {
1298       ua->catalog = oldcatalog;
1299    } else {
1300       ua->catalog = catalog;
1301    }
1302    if (open_db(ua)) {
1303       bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1304          ua->catalog->hdr.name, ua->catalog->db_name);
1305    }
1306    return 1;
1307 }
1308
1309 int quitcmd(UAContext *ua, char *cmd) 
1310 {
1311    ua->quit = TRUE;
1312    return 1;
1313 }
1314
1315 static int helpcmd(UAContext *ua, char *cmd)
1316 {
1317    unsigned int i;
1318
1319 /* usage(); */
1320    bsendmsg(ua, _("  Command    Description\n  =======    ===========\n"));
1321    for (i=0; i<comsize; i++) {
1322       bsendmsg(ua, _("  %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1323    }
1324    bsendmsg(ua, "\n");
1325    return 1;
1326 }
1327
1328 static int versioncmd(UAContext *ua, char *cmd)
1329 {
1330    bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
1331    return 1;
1332 }
1333
1334
1335 /* A bit brain damaged in that if the user has not done
1336  * a "use catalog xxx" command, we simply find the first
1337  * catalog resource and open it.
1338  */
1339 int open_db(UAContext *ua)
1340 {
1341    if (ua->db) {
1342       return 1;
1343    }
1344    if (!ua->catalog) {
1345       LockRes();
1346       ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1347       UnlockRes();
1348       if (!ua->catalog) {    
1349          bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
1350          return 0;
1351       } else {
1352          bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"), 
1353             ua->catalog->hdr.name, ua->catalog->db_name);
1354       }
1355    }
1356
1357    Dmsg0(150, "Open database\n");
1358    ua->db = db_init_database(NULL, ua->catalog->db_name, ua->catalog->db_user,
1359                              ua->catalog->db_password);
1360    if (!db_open_database(ua->db)) {
1361       bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"), 
1362          ua->catalog->db_name, db_strerror(ua->db));
1363       close_db(ua);
1364       return 0;
1365    }
1366    ua->jcr->db = ua->db;
1367    Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1368    return 1;
1369 }
1370
1371 void close_db(UAContext *ua)
1372 {
1373    if (ua->db) {
1374       db_close_database(ua->db);
1375    }
1376    ua->db = NULL;
1377    ua->jcr->db = NULL;
1378 }