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