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