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