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