]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
4aa0c21ae487b5b6b2588ad6c9047e2384164cc9
[bacula/bacula] / bacula / src / dird / ua_select.c
1 /*
2  *
3  *   Bacula Director -- User Agent Prompt and Selection code
4  *
5  *     Kern Sibbald, October MMI
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
35 /* Imported variables */
36
37
38 /* Exported functions */
39
40 int do_prompt(UAContext *ua, char *msg, char *prompt);
41 void add_prompt(UAContext *ua, char *prompt);
42 void start_prompt(UAContext *ua, char *msg);
43 STORE *select_storage_resource(UAContext *ua);
44 JOB *select_job_resource(UAContext *ua);
45
46 /*
47  * Confirm a retention period
48  */
49 int confirm_retention(UAContext *ua, btime_t *ret, char *msg)
50 {
51    char ed1[30];
52
53    for ( ;; ) {
54        bsendmsg(ua, _("The current %s retention period is: %s\n"), 
55           msg, edit_btime(*ret, ed1));
56        if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
57           return 0;
58        }
59        if (strcasecmp(ua->cmd, _("mod")) == 0) {
60           if (!get_cmd(ua, _("Enter new retention period: "))) {
61              return 0;
62           }
63           if (!string_to_btime(ua->cmd, ret)) {
64              bsendmsg(ua, _("Invalid period.\n"));
65              continue;
66           }
67           continue;
68        }
69        if (strcasecmp(ua->cmd, _("yes")) == 0) {
70           break;
71        }
72     }
73     return 1;
74 }
75
76 /* 
77  * Given a list of keywords, find the first one
78  *  that is in the argument list.
79  * Returns: -1 if not found
80  *          index into list (base 0) on success
81  */
82 int find_arg_keyword(UAContext *ua, char **list)
83 {
84    int i, j;
85    for (i=1; i<ua->argc; i++) {
86       for(j=0; list[j]; j++) {
87          if (strcasecmp(_(list[j]), ua->argk[i]) == 0) {
88             return j;
89          }
90       }
91    }
92    return -1;
93 }
94
95 /* 
96  * Given a list of keywords, prompt the user 
97  * to choose one.
98  *
99  * Returns: -1 on failure
100  *          index into list (base 0) on success
101  */
102 int do_keyword_prompt(UAContext *ua, char *msg, char **list)
103 {
104    int i;
105    start_prompt(ua, _("You have the following choices:\n"));
106    for (i=0; list[i]; i++) {
107       add_prompt(ua, list[i]);
108    }
109    return do_prompt(ua, msg, NULL);
110 }
111
112
113 /* 
114  * Select a Storage resource from prompt list
115  */
116 STORE *select_storage_resource(UAContext *ua)
117 {
118    char name[MAX_NAME_LENGTH];    
119    STORE *store = NULL;
120
121    start_prompt(ua, _("The defined Storage resources are:\n"));
122    LockRes();
123    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
124       add_prompt(ua, store->hdr.name);
125    }
126    UnlockRes();
127    do_prompt(ua, _("Select Storage resource"), name);
128    store = (STORE *)GetResWithName(R_STORAGE, name);
129    return store;
130 }
131
132 /* 
133  * Select a FileSet resource from prompt list
134  */
135 FILESET *select_fileset_resource(UAContext *ua)
136 {
137    char name[MAX_NAME_LENGTH];    
138    FILESET *fs = NULL;
139
140    start_prompt(ua, _("The defined FileSet resources are:\n"));
141    LockRes();
142    while ((fs = (FILESET *)GetNextRes(R_FILESET, (RES *)fs))) {
143       add_prompt(ua, fs->hdr.name);
144    }
145    UnlockRes();
146    do_prompt(ua, _("Select FileSet resource"), name);
147    fs = (FILESET *)GetResWithName(R_FILESET, name);
148    return fs;
149 }
150
151
152 /* 
153  * Get a catalog resource from prompt list
154  */
155 CAT *get_catalog_resource(UAContext *ua)
156 {
157    char name[MAX_NAME_LENGTH];    
158    CAT *catalog = NULL;
159    int i;
160
161    for (i=1; i<ua->argc; i++) {
162       if (strcasecmp(ua->argk[i], _("catalog")) == 0 && ua->argv[i]) {
163          catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
164          break;
165       }
166    }
167    if (!catalog) {
168       start_prompt(ua, _("The defined Catalog resources are:\n"));
169       LockRes();
170       while ((catalog = (CAT *)GetNextRes(R_CATALOG, (RES *)catalog))) {
171          add_prompt(ua, catalog->hdr.name);
172       }
173       UnlockRes();
174       do_prompt(ua, _("Select Catalog resource"), name);
175       catalog = (CAT *)GetResWithName(R_CATALOG, name);
176    }
177    return catalog;
178 }
179
180
181 /* 
182  * Select a Job resource from prompt list
183  */
184 JOB *select_job_resource(UAContext *ua)
185 {
186    char name[MAX_NAME_LENGTH];    
187    JOB *job = NULL;
188
189    start_prompt(ua, _("The defined Job resources are:\n"));
190    LockRes();
191    while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) {
192       add_prompt(ua, job->hdr.name);
193    }
194    UnlockRes();
195    do_prompt(ua, _("Select Job resource"), name);
196    job = (JOB *)GetResWithName(R_JOB, name);
197    return job;
198 }
199
200 /* 
201  * Select a Restore Job resource from prompt list
202  */
203 JOB *select_restore_job_resource(UAContext *ua)
204 {
205    char name[MAX_NAME_LENGTH];    
206    JOB *job = NULL;
207
208    start_prompt(ua, _("The defined Restore Job resources are:\n"));
209    LockRes();
210    while ( (job = (JOB *)GetNextRes(R_JOB, (RES *)job)) ) {
211       if (job->JobType == JT_RESTORE) {
212          add_prompt(ua, job->hdr.name);
213       }
214    }
215    UnlockRes();
216    do_prompt(ua, _("Select Restore Job"), name);
217    job = (JOB *)GetResWithName(R_JOB, name);
218    return job;
219 }
220
221
222
223 /* 
224  * Select a client resource from prompt list
225  */
226 CLIENT *select_client_resource(UAContext *ua)
227 {
228    char name[MAX_NAME_LENGTH];    
229    CLIENT *client = NULL;
230
231    start_prompt(ua, _("The defined Client resources are:\n"));
232    LockRes();
233    while ( (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)) ) {
234       add_prompt(ua, client->hdr.name);
235    }
236    UnlockRes();
237    do_prompt(ua, _("Select Client (File daemon) resource"), name);
238    client = (CLIENT *)GetResWithName(R_CLIENT, name);
239    return client;
240 }
241
242 /*
243  *  Get client resource, start by looking for
244  *   client=<client-name>
245  *  if we don't find the keyword, we prompt the user.
246  */
247 CLIENT *get_client_resource(UAContext *ua)
248 {
249    CLIENT *client = NULL;
250    int i;
251    
252    for (i=1; i<ua->argc; i++) {
253       if (strcasecmp(ua->argk[i], _("client")) == 0 && ua->argv[i]) {
254          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
255          if (client) {
256             return client;
257          }
258          bsendmsg(ua, _("Error: Client resource %s does not exist.\n"), ua->argv[i]);
259          break;
260       }
261    }
262    return select_client_resource(ua);
263 }
264
265 /* Scan what the user has entered looking for:
266  * 
267  *  pool=<pool-name>   
268  *
269  *  if error or not found, put up a list of pool DBRs
270  *  to choose from.
271  *
272  *   returns: 0 on error
273  *            poolid on success and fills in POOL_DBR
274  */
275 int get_pool_dbr(UAContext *ua, POOL_DBR *pr)
276 {
277    int i;
278
279    if (pr->Name[0]) {                 /* If name already supplied */
280       if (db_get_pool_record(ua->db, pr)) {
281          return pr->PoolId;
282       }
283       bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), pr->Name, db_strerror(ua->db));
284    }
285    for (i=1; i<ua->argc; i++) {
286       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
287          strcpy(pr->Name, ua->argv[i]);
288          if (!db_get_pool_record(ua->db, pr)) {
289             bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), ua->argv[i],
290                      db_strerror(ua->db));
291             pr->PoolId = 0;
292             break;
293          }
294          return pr->PoolId;
295       }
296    }
297    if (!select_pool_dbr(ua, pr)) {  /* try once more */
298       return 0;
299    }
300    return pr->PoolId;
301 }
302
303 /*
304  * Select a Pool record from the catalog
305  */
306 int select_pool_dbr(UAContext *ua, POOL_DBR *pr)
307 {
308    POOL_DBR opr;
309    char name[MAX_NAME_LENGTH];
310    int num_pools, i;
311    uint32_t *ids; 
312
313
314    pr->PoolId = 0;
315    if (!db_get_pool_ids(ua->db, &num_pools, &ids)) {
316       bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
317       return 0;
318    }
319    if (num_pools <= 0) {
320       bsendmsg(ua, _("No pools defined. Use the \"create\" command to create one.\n"));
321       return 0;
322    }
323      
324    start_prompt(ua, _("Defined Pools:\n"));
325    for (i=0; i < num_pools; i++) {
326       opr.PoolId = ids[i];
327       if (!db_get_pool_record(ua->db, &opr)) {
328          continue;
329       }
330       add_prompt(ua, opr.Name);
331    }
332    free(ids);
333    if (do_prompt(ua, _("Select the Pool"), name) < 0) {
334       return 0;
335    }
336    memset(&opr, 0, sizeof(pr));
337    strcpy(opr.Name, name);
338
339    if (!db_get_pool_record(ua->db, &opr)) {
340       bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), name, db_strerror(ua->db));
341       return 0;
342    }
343    memcpy(pr, &opr, sizeof(opr));
344    return opr.PoolId;
345 }
346
347 /*
348  * Select a Pool and a Media (Volume) record from the database
349  */
350 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
351 {
352    int i;
353    static char *kw[] = {
354       N_("volume"),
355       NULL};
356
357    memset(pr, 0, sizeof(POOL_DBR));
358    memset(mr, 0, sizeof(MEDIA_DBR));
359
360    /* Get the pool, possibly from pool=<pool-name> */
361    if (!get_pool_dbr(ua, pr)) {
362       return 0;
363    }
364    mr->PoolId = pr->PoolId;
365
366    i = find_arg_keyword(ua, kw);
367    if (i == 0 && ua->argv[i]) {
368       strcpy(mr->VolumeName, ua->argv[i]);
369    }
370    if (mr->VolumeName[0] == 0) {
371       db_list_media_records(ua->db, mr, prtit, ua);
372       if (!get_cmd(ua, _("Enter MediaId or Volume name: "))) {
373          return 0;
374       }
375       if (is_a_number(ua->cmd)) {
376          mr->MediaId = atoi(ua->cmd);
377       } else {
378          strcpy(mr->VolumeName, ua->cmd);
379       }
380    }
381
382    if (!db_get_media_record(ua->db, mr)) {
383       bsendmsg(ua, "%s", db_strerror(ua->db));
384       return 0;
385    }
386    return 1;
387 }
388
389
390 /*
391  *  This routine is ONLY used in the create command.
392  *  If you are thinking about using it, you
393  *  probably want to use select_pool_dbr() 
394  *  or get_pool_dbr() above.
395  */
396 POOL *get_pool_resource(UAContext *ua)
397 {
398    POOL *pool = NULL;
399    char name[MAX_NAME_LENGTH];
400    int i;
401    
402    for (i=1; i<ua->argc; i++) {
403       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
404          pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
405          if (pool) {
406             return pool;
407          }
408          bsendmsg(ua, _("Error: Pool resource %s does not exist.\n"), ua->argv[i]);
409          break;
410       }
411    }
412    start_prompt(ua, _("The defined Pool resources are:\n"));
413    LockRes();
414    while ((pool = (POOL *)GetNextRes(R_POOL, (RES *)pool))) {
415       add_prompt(ua, pool->hdr.name);
416    }
417    UnlockRes();
418    do_prompt(ua, _("Select Pool resource"), name);
419    pool = (POOL *)GetResWithName(R_POOL, name);
420    return pool;
421 }
422
423 /*
424  * List all jobs and ask user to select one
425  */
426 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
427 {
428    db_list_job_records(ua->db, jr, prtit, ua);
429    if (!get_cmd(ua, _("Enter the JobId to select: "))) {
430       return 0;
431    }
432    jr->JobId = atoi(ua->cmd);
433    if (!db_get_job_record(ua->db, jr)) {
434       bsendmsg(ua, "%s", db_strerror(ua->db));
435       return 0;
436    }
437    return jr->JobId;
438
439 }
440
441
442 /* Scan what the user has entered looking for:
443  * 
444  *  jobid=nn
445  *
446  *  if error or not found, put up a list of Jobs
447  *  to choose from.
448  *
449  *   returns: 0 on error
450  *            JobId on success and fills in JOB_DBR
451  */
452 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
453 {
454    int i;
455
456    for (i=1; i<ua->argc; i++) {
457       if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
458          jr->JobId = 0;
459          strcpy(jr->Job, ua->argv[i]);
460       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0 && ua->argv[i]) {
461          jr->JobId = atoi(ua->argv[i]);
462       } else {
463          continue;
464       }
465       if (!db_get_job_record(ua->db, jr)) {
466          bsendmsg(ua, _("Could not find Job %s: ERR=%s"), ua->argv[i],
467                   db_strerror(ua->db));
468          jr->JobId = 0;
469          break;
470       }
471       return jr->JobId;
472    }
473
474    if (!select_job_dbr(ua, jr)) {  /* try once more */
475       return 0;
476    }
477    return jr->JobId;
478 }
479
480
481
482
483 /*
484  * Implement unique set of prompts 
485  */
486 void start_prompt(UAContext *ua, char *msg)
487 {
488   if (ua->max_prompts == 0) {
489      ua->max_prompts = 10;
490      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
491   }
492   ua->num_prompts = 1;
493   ua->prompt[0] = bstrdup(msg);
494 }
495
496 /*
497  * Add to prompts -- keeping them unique 
498  */
499 void add_prompt(UAContext *ua, char *prompt)
500 {
501    int i;
502    if (ua->num_prompts == ua->max_prompts) {
503       ua->max_prompts *= 2;
504       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
505          ua->max_prompts);
506     }
507     for (i=1; i < ua->num_prompts; i++) {
508        if (strcmp(ua->prompt[i], prompt) == 0) {
509           return;
510        }
511     }
512     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
513 }
514
515 /*
516  * Display prompts and get user's choice
517  *
518  *  Returns: -1 on error
519  *            index base 0 on success, and choice
520  *               is copied to prompt if not NULL
521  */
522 int do_prompt(UAContext *ua, char *msg, char *prompt)
523 {
524    int i, item;
525    char pmsg[MAXSTRING];
526
527    bsendmsg(ua, ua->prompt[0]);
528    for (i=1; i < ua->num_prompts; i++) {
529       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
530    }
531
532    if (prompt) {
533       *prompt = 0;
534    }
535
536    for ( ;; ) {
537       /* First item is the prompt string, not the items */
538       if (ua->num_prompts == 1) { 
539          item = 0;                    /* list is empty ! */
540          break;
541       }
542       if (ua->num_prompts == 2) {
543          item = 1;
544          bsendmsg(ua, _("Item 1 selected automatically.\n"));
545          if (prompt) {
546             strcpy(prompt, ua->prompt[1]);
547          }
548          break;
549       } else {
550          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
551       }
552       /* Either a . or an @ will get you out of the loop */
553       if (!get_cmd(ua, pmsg) || *ua->cmd == '.' || *ua->cmd == '@') {
554          item = -1;                   /* error */
555          bsendmsg(ua, _("Selection aborted, nothing done.\n"));
556          break;
557       }
558       item = atoi(ua->cmd);
559       if (item < 1 || item >= ua->num_prompts) {
560          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
561          continue;
562       }
563       if (prompt) {
564          strcpy(prompt, ua->prompt[item]);
565       }
566       break;
567    }
568                               
569    for (i=0; i < ua->num_prompts; i++) {
570       free(ua->prompt[i]);
571    }
572    ua->num_prompts = 0;
573    return item - 1;
574 }
575
576
577 /*
578  * We scan what the user has entered looking for
579  *    <storage-resource>
580  *    device=<device-name>      ???? does this work ????
581  *    storage=<storage-resource>
582  *    job=<job_name>
583  *    jobid=<jobid>
584  *    ?              (prompt him with storage list)
585  *    <some-error>   (prompt him with storage list)
586  */
587 STORE *get_storage_resource(UAContext *ua, char *cmd)
588 {
589    char *store_name, *device_name;
590    STORE *store;
591    int jobid;
592    JCR *jcr;
593    int i;
594       
595    if (ua->argc == 1) {
596       return select_storage_resource(ua);
597    }
598    
599    device_name = NULL;
600    store_name = NULL;
601
602    for (i=1; i<ua->argc; i++) {
603       if (!ua->argv[i]) {
604          /* Default argument is storage */
605          if (store_name) {
606             bsendmsg(ua, _("Storage name given twice.\n"));
607             return NULL;
608          }
609          store_name = ua->argk[i];
610          if (*store_name == '?') {
611             return select_storage_resource(ua);
612          }
613       } else {
614          if (strcasecmp(ua->argk[i], _("device")) == 0) {
615             device_name = ua->argv[i];
616
617          } else if (strcasecmp(ua->argk[i], _("storage")) == 0) {
618             store_name = ua->argv[i];
619
620          } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
621             jobid = atoi(ua->argv[i]);
622             if (jobid <= 0) {
623                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
624                return NULL;
625             }
626             if (!(jcr=get_jcr_by_id(jobid))) {
627                bsendmsg(ua, _("JobId %d is not running.\n"), jobid);
628                return NULL;
629             }
630             store = jcr->store;
631             free_jcr(jcr);
632             return store;
633
634          } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
635             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
636                bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
637                return NULL;
638             }
639             store = jcr->store;
640             free_jcr(jcr);
641             return store;
642
643          } else {
644             bsendmsg(ua, _("Unknown keyword: %s\n"), ua->argk[i]);
645             return NULL;
646          }
647       }
648    }
649
650    if (!store_name) {
651      bsendmsg(ua, _("A storage device name must be given.\n"));
652      store = NULL;
653    } else {
654       store = (STORE *)GetResWithName(R_STORAGE, store_name);
655       if (!store) {
656          bsendmsg(ua, "Storage resource %s: not found\n", store_name);
657       }
658    }
659    if (!store) {
660       store = select_storage_resource(ua);
661    }
662    return store;
663 }
664
665
666 /*
667  * Scan looking for mediatype= 
668  *
669  *  if not found or error, put up selection list
670  *
671  *  Returns: 0 on error
672  *           1 on success, MediaType is set
673  */
674 int get_media_type(UAContext *ua, char *MediaType)
675 {
676    STORE *store;
677    int i;
678    static char *keyword[] = {
679       "mediatype",
680       NULL};
681
682    i = find_arg_keyword(ua, keyword);
683    if (i >= 0 && ua->argv[i]) {
684       strcpy(MediaType, ua->argv[i]);
685       return 1;
686    }
687
688    start_prompt(ua, _("Media Types defined in conf file:\n"));
689    LockRes();
690    for (store = NULL; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); ) {
691       add_prompt(ua, store->media_type);
692    }
693    UnlockRes();
694    return (do_prompt(ua, _("Select the Media Type"), MediaType) < 0) ? 0 : 1;
695 }