]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
First cut AutoPrune
[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_fs_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 /* 
202  * Select a client resource from prompt list
203  */
204 CLIENT *select_client_resource(UAContext *ua)
205 {
206    char name[MAX_NAME_LENGTH];    
207    CLIENT *client = NULL;
208
209    start_prompt(ua, _("The defined Client resources are:\n"));
210    LockRes();
211    while ( (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)) ) {
212       add_prompt(ua, client->hdr.name);
213    }
214    UnlockRes();
215    do_prompt(ua, _("Select Client (File daemon) resource"), name);
216    client = (CLIENT *)GetResWithName(R_CLIENT, name);
217    return client;
218 }
219
220 /*
221  *  Get client resource, start by looking for
222  *   client=<client-name>
223  *  if we don't find the keyword, we prompt the user.
224  */
225 CLIENT *get_client_resource(UAContext *ua)
226 {
227    CLIENT *client = NULL;
228    int i;
229    
230    for (i=1; i<ua->argc; i++) {
231       if (strcasecmp(ua->argk[i], _("client")) == 0 && ua->argv[i]) {
232          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
233          if (client) {
234             return client;
235          }
236          bsendmsg(ua, _("Error: Client resource %s does not exist.\n"), ua->argv[i]);
237          break;
238       }
239    }
240    return select_client_resource(ua);
241 }
242
243 /* Scan what the user has entered looking for:
244  * 
245  *  pool=<pool-name>   
246  *
247  *  if error or not found, put up a list of pool DBRs
248  *  to choose from.
249  *
250  *   returns: 0 on error
251  *            poolid on success and fills in POOL_DBR
252  */
253 int get_pool_dbr(UAContext *ua, POOL_DBR *pr)
254 {
255    int i;
256
257    for (i=1; i<ua->argc; i++) {
258       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
259          strcpy(pr->Name, ua->argv[i]);
260          if (!db_get_pool_record(ua->db, pr)) {
261             bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), ua->argv[i],
262                      db_strerror(ua->db));
263             pr->PoolId = 0;
264             break;
265          }
266          return pr->PoolId;
267       }
268    }
269    if (!select_pool_dbr(ua, pr)) {  /* try once more */
270       return 0;
271    }
272    return pr->PoolId;
273 }
274
275 /*
276  * Select a Pool record from the catalog
277  */
278 int select_pool_dbr(UAContext *ua, POOL_DBR *pr)
279 {
280    POOL_DBR opr;
281    char name[MAX_NAME_LENGTH];
282    int num_pools, i;
283    uint32_t *ids; 
284
285
286    pr->PoolId = 0;
287    if (!db_get_pool_ids(ua->db, &num_pools, &ids)) {
288       bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
289       return 0;
290    }
291    if (num_pools <= 0) {
292       bsendmsg(ua, _("No pools defined. Use the \"create\" command to create one.\n"));
293       return 0;
294    }
295      
296    start_prompt(ua, _("Defined Pools:\n"));
297    for (i=0; i < num_pools; i++) {
298       opr.PoolId = ids[i];
299       if (!db_get_pool_record(ua->db, &opr)) {
300          continue;
301       }
302       add_prompt(ua, opr.Name);
303    }
304    free(ids);
305    if (do_prompt(ua, _("Select the Pool"), name) < 0) {
306       return 0;
307    }
308    memset(&opr, 0, sizeof(pr));
309    strcpy(opr.Name, name);
310
311    if (!db_get_pool_record(ua->db, &opr)) {
312       bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), name, db_strerror(ua->db));
313       return 0;
314    }
315    memcpy(pr, &opr, sizeof(opr));
316    return opr.PoolId;
317 }
318
319 /*
320  * Select a Pool and a Media (Volume) record from the database
321  */
322 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
323 {
324    int found = FALSE;
325    int i;
326
327    memset(pr, 0, sizeof(POOL_DBR));
328    memset(mr, 0, sizeof(MEDIA_DBR));
329
330    /* Get the pool, possibly from pool=<pool-name> */
331    if (!get_pool_dbr(ua, pr)) {
332       return 0;
333    }
334    mr->PoolId = pr->PoolId;
335
336    /* See if a volume name is specified as an argument */
337    for (i=1; i<ua->argc; i++) {
338       if (strcasecmp(ua->argk[i], _("volume")) == 0 && ua->argv[i]) {
339          found = TRUE;
340          break;
341       }
342    }
343    if (found) {
344       strcpy(mr->VolumeName, ua->argv[i]);
345    } else {
346       db_list_media_records(ua->db, mr, prtit, ua);
347       if (!get_cmd(ua, _("Enter the Volume name to delete: "))) {
348          return 01;
349       }
350       strcpy(mr->VolumeName, ua->cmd);
351    }
352    mr->MediaId = 0;
353    if (!db_get_media_record(ua->db, mr)) {
354       bsendmsg(ua, "%s", db_strerror(ua->db));
355       return 0;
356    }
357    return 1;
358 }
359
360
361 /*
362  *  This routine is ONLY used in the create command.
363  *  If you are thinking about using it, you
364  *  probably want to use select_pool_dbr() 
365  *  or get_pool_dbr() above.
366  */
367 POOL *get_pool_resource(UAContext *ua)
368 {
369    POOL *pool = NULL;
370    char name[MAX_NAME_LENGTH];
371    int i;
372    
373    for (i=1; i<ua->argc; i++) {
374       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
375          pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
376          if (pool) {
377             return pool;
378          }
379          bsendmsg(ua, _("Error: Pool resource %s does not exist.\n"), ua->argv[i]);
380          break;
381       }
382    }
383    start_prompt(ua, _("The defined Pool resources are:\n"));
384    LockRes();
385    while ((pool = (POOL *)GetNextRes(R_POOL, (RES *)pool))) {
386       add_prompt(ua, pool->hdr.name);
387    }
388    UnlockRes();
389    do_prompt(ua, _("Select Pool resource"), name);
390    pool = (POOL *)GetResWithName(R_POOL, name);
391    return pool;
392 }
393
394 /*
395  * List all jobs and ask user to select one
396  */
397 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
398 {
399    db_list_job_records(ua->db, jr, prtit, ua);
400    if (!get_cmd(ua, _("Enter the JobId to select: "))) {
401       return 0;
402    }
403    jr->JobId = atoi(ua->cmd);
404    if (!db_get_job_record(ua->db, jr)) {
405       bsendmsg(ua, "%s", db_strerror(ua->db));
406       return 0;
407    }
408    return jr->JobId;
409
410 }
411
412
413 /* Scan what the user has entered looking for:
414  * 
415  *  jobid=nn
416  *
417  *  if error or not found, put up a list of Jobs
418  *  to choose from.
419  *
420  *   returns: 0 on error
421  *            JobId on success and fills in JOB_DBR
422  */
423 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
424 {
425    int i;
426
427    for (i=1; i<ua->argc; i++) {
428       if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
429          jr->JobId = 0;
430          strcpy(jr->Job, ua->argv[i]);
431       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0 && ua->argv[i]) {
432          jr->JobId = atoi(ua->argv[i]);
433       } else {
434          continue;
435       }
436       if (!db_get_job_record(ua->db, jr)) {
437          bsendmsg(ua, _("Could not find Job %s: ERR=%s"), ua->argv[i],
438                   db_strerror(ua->db));
439          jr->JobId = 0;
440          break;
441       }
442       return jr->JobId;
443    }
444
445    if (!select_job_dbr(ua, jr)) {  /* try once more */
446       return 0;
447    }
448    return jr->JobId;
449 }
450
451
452
453
454 /*
455  * Implement unique set of prompts 
456  */
457 void start_prompt(UAContext *ua, char *msg)
458 {
459   if (ua->max_prompts == 0) {
460      ua->max_prompts = 10;
461      ua->prompt = (char **) bmalloc(sizeof(char *) * ua->max_prompts);
462   }
463   ua->num_prompts = 1;
464   ua->prompt[0] = bstrdup(msg);
465 }
466
467 /*
468  * Add to prompts -- keeping them unique 
469  */
470 void add_prompt(UAContext *ua, char *prompt)
471 {
472    int i;
473    if (ua->num_prompts == ua->max_prompts) {
474       ua->max_prompts *= 2;
475       ua->prompt = (char **) brealloc(ua->prompt, sizeof(char *) *
476          ua->max_prompts);
477     }
478     for (i=1; i < ua->num_prompts; i++) {
479        if (strcmp(ua->prompt[i], prompt) == 0) {
480           return;
481        }
482     }
483     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
484 }
485
486 /*
487  * Display prompts and get user's choice
488  *
489  *  Returns: -1 on error
490  *            index base 0 on success, and choice
491  *               is copied to prompt if not NULL
492  */
493 int do_prompt(UAContext *ua, char *msg, char *prompt)
494 {
495    int i, item;
496    char pmsg[MAXSTRING];
497
498    bsendmsg(ua, ua->prompt[0]);
499    for (i=1; i < ua->num_prompts; i++) {
500       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
501    }
502
503    if (prompt) {
504       *prompt = 0;
505    }
506
507    for ( ;; ) {
508       if (ua->num_prompts == 2) {
509          item = 1;
510          bsendmsg(ua, _("Item 1 selected automatically.\n"));
511          if (prompt) {
512             strcpy(prompt, ua->prompt[1]);
513          }
514          break;
515       } else {
516          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
517       }
518       /* Either a . or an @ will get you out of the loop */
519       if (!get_cmd(ua, pmsg) || *ua->cmd == '.' || *ua->cmd == '@') {
520          item = -1;                   /* error */
521          break;
522       }
523       item = atoi(ua->cmd);
524       if (item < 1 || item >= ua->num_prompts) {
525          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
526          continue;
527       }
528       if (prompt) {
529          strcpy(prompt, ua->prompt[item]);
530       }
531       break;
532    }
533                               
534    for (i=0; i < ua->num_prompts; i++) {
535       free(ua->prompt[i]);
536    }
537    ua->num_prompts = 0;
538    return item - 1;
539 }
540
541
542 /*
543  * We scan what the user has entered looking for
544  *    <storage-resource>
545  *    device=<device-name>      ???? does this work ????
546  *    storage=<storage-resource>
547  *    job=<job_name>
548  *    jobid=<jobid>
549  *    ?              (prompt him with storage list)
550  *    <some-error>   (prompt him with storage list)
551  */
552 STORE *get_storage_resource(UAContext *ua, char *cmd)
553 {
554    char *store_name, *device_name;
555    STORE *store;
556    int jobid;
557    JCR *jcr;
558    int i;
559       
560    if (ua->argc == 1) {
561       return select_storage_resource(ua);
562    }
563    
564    device_name = NULL;
565    store_name = NULL;
566
567    for (i=1; i<ua->argc; i++) {
568       if (!ua->argv[i]) {
569          /* Default argument is storage */
570          if (store_name) {
571             bsendmsg(ua, _("Storage name given twice.\n"));
572             return NULL;
573          }
574          store_name = ua->argk[i];
575          if (*store_name == '?') {
576             return select_storage_resource(ua);
577          }
578       } else {
579          if (strcasecmp(ua->argk[i], _("device")) == 0) {
580             device_name = ua->argv[i];
581
582          } else if (strcasecmp(ua->argk[i], _("storage")) == 0) {
583             store_name = ua->argv[i];
584
585          } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
586             jobid = atoi(ua->argv[i]);
587             if (jobid <= 0) {
588                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
589                return NULL;
590             }
591             if (!(jcr=get_jcr_by_id(jobid))) {
592                bsendmsg(ua, _("JobId %d is not running.\n"), jobid);
593                return NULL;
594             }
595             store = jcr->store;
596             free_jcr(jcr);
597             return store;
598
599          } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
600             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
601                bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
602                return NULL;
603             }
604             store = jcr->store;
605             free_jcr(jcr);
606             return store;
607
608          } else {
609             bsendmsg(ua, _("Unknown keyword: %s\n"), ua->argk[i]);
610             return NULL;
611          }
612       }
613    }
614
615    if (!store_name) {
616      bsendmsg(ua, _("A storage device name must be given.\n"));
617      store = NULL;
618    } else {
619       store = (STORE *)GetResWithName(R_STORAGE, store_name);
620       if (!store) {
621          bsendmsg(ua, "Storage resource %s: not found\n", store_name);
622       }
623    }
624    if (!store) {
625       store = select_storage_resource(ua);
626    }
627    return store;
628 }
629
630
631 /*
632  * Scan looking for mediatype= 
633  *
634  *  if not found or error, put up selection list
635  *
636  *  Returns: 0 on error
637  *           1 on success, MediaType is set
638  */
639 int get_media_type(UAContext *ua, char *MediaType)
640 {
641    STORE *store;
642    int i;
643    static char *keyword[] = {
644       "mediatype",
645       NULL};
646
647    i = find_arg_keyword(ua, keyword);
648    if (i >= 0 && ua->argv[i]) {
649       strcpy(MediaType, ua->argv[i]);
650       return 1;
651    }
652
653    start_prompt(ua, _("Media Types defined in conf file:\n"));
654    LockRes();
655    for (store = NULL; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); ) {
656       add_prompt(ua, store->media_type);
657    }
658    UnlockRes();
659    return (do_prompt(ua, _("Select the Media Type"), MediaType) < 0) ? 0 : 1;
660 }