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