]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
Initial revision
[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
212
213
214 /* Scan what the user has entered looking for:
215  * 
216  *  pool=<pool-name>   
217  *
218  *  if error or not found, put up a list of pool DBRs
219  *  to choose from.
220  *
221  *   returns: 0 on error
222  *            poolid on success and fills in POOL_DBR
223  */
224 int get_pool_dbr(UAContext *ua, POOL_DBR *pr)
225 {
226    int i;
227
228    for (i=1; i<ua->argc; i++) {
229       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
230          strcpy(pr->Name, ua->argv[i]);
231          if (!db_get_pool_record(ua->db, pr)) {
232             bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), ua->argv[i],
233                      db_strerror(ua->db));
234             pr->PoolId = 0;
235             break;
236          }
237          return pr->PoolId;
238       }
239    }
240    if (!select_pool_dbr(ua, pr)) {  /* try once more */
241       return 0;
242    }
243    return pr->PoolId;
244 }
245
246 /*
247  * Select a Pool record from the catalog
248  */
249 int select_pool_dbr(UAContext *ua, POOL_DBR *pr)
250 {
251    POOL_DBR opr;
252    char name[MAX_NAME_LENGTH];
253    int num_pools, i;
254    uint32_t *ids; 
255
256
257    pr->PoolId = 0;
258    if (!db_get_pool_ids(ua->db, &num_pools, &ids)) {
259       bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
260       return 0;
261    }
262    if (num_pools <= 0) {
263       bsendmsg(ua, _("No pools defined.\n"));
264       return 0;
265    }
266      
267    start_prompt(ua, _("Defined Pools:\n"));
268    for (i=0; i < num_pools; i++) {
269       opr.PoolId = ids[i];
270       if (!db_get_pool_record(ua->db, &opr)) {
271          continue;
272       }
273       add_prompt(ua, opr.Name);
274    }
275    free(ids);
276    if (do_prompt(ua, _("Select the Pool"), name) < 0) {
277       return 0;
278    }
279    memset(&opr, 0, sizeof(pr));
280    strcpy(opr.Name, name);
281
282    if (!db_get_pool_record(ua->db, &opr)) {
283       bsendmsg(ua, _("Could not find Pool %s: ERR=%s"), name, db_strerror(ua->db));
284       return 0;
285    }
286    memcpy(pr, &opr, sizeof(opr));
287    return opr.PoolId;
288 }
289
290
291 /*
292  *  This routine is ONLY used in the create command.
293  *  If you are thinking about using it, you
294  *  probably want to use select_pool_dbr() 
295  *  or get_pool_dbr() above.
296  */
297 POOL *get_pool_resource(UAContext *ua)
298 {
299    POOL *pool = NULL;
300    char name[MAX_NAME_LENGTH];
301    int i;
302    
303    for (i=1; i<ua->argc; i++) {
304       if (strcasecmp(ua->argk[i], _("pool")) == 0 && ua->argv[i]) {
305          pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
306          if (pool) {
307             return pool;
308          }
309          bsendmsg(ua, _("Error: Pool resource %s does not exist.\n"), ua->argv[i]);
310          break;
311       }
312    }
313    start_prompt(ua, _("The defined Pool resources are:\n"));
314    LockRes();
315    while ((pool = (POOL *)GetNextRes(R_POOL, (RES *)pool))) {
316       add_prompt(ua, pool->hdr.name);
317    }
318    UnlockRes();
319    do_prompt(ua, _("Select Pool resource"), name);
320    pool = (POOL *)GetResWithName(R_POOL, name);
321    return pool;
322 }
323
324
325
326
327 /*
328  * Implement unique set of prompts 
329  */
330 void start_prompt(UAContext *ua, char *msg)
331 {
332   if (ua->max_prompts == 0) {
333      ua->max_prompts = 10;
334      ua->prompt = (char **) bmalloc(sizeof(char *) * ua->max_prompts);
335   }
336   ua->num_prompts = 1;
337   ua->prompt[0] = bstrdup(msg);
338 }
339
340 /*
341  * Add to prompts -- keeping them unique 
342  */
343 void add_prompt(UAContext *ua, char *prompt)
344 {
345    int i;
346    if (ua->num_prompts == ua->max_prompts) {
347       ua->max_prompts *= 2;
348       ua->prompt = (char **) brealloc(ua->prompt, sizeof(char *) *
349          ua->max_prompts);
350     }
351     for (i=1; i < ua->num_prompts; i++) {
352        if (strcmp(ua->prompt[i], prompt) == 0) {
353           return;
354        }
355     }
356     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
357 }
358
359 /*
360  * Display prompts and get user's choice
361  *
362  *  Returns: -1 on error
363  *            index base 0 on success, and choice
364  *               is copied to prompt if not NULL
365  */
366 int do_prompt(UAContext *ua, char *msg, char *prompt)
367 {
368    int i, item;
369    char pmsg[MAXSTRING];
370
371    bsendmsg(ua, ua->prompt[0]);
372    for (i=1; i < ua->num_prompts; i++) {
373       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
374    }
375
376    if (prompt) {
377       *prompt = 0;
378    }
379
380    for ( ;; ) {
381       if (ua->num_prompts == 2) {
382          item = 1;
383          bsendmsg(ua, _("Item 1 selected automatically.\n"));
384          if (prompt) {
385             strcpy(prompt, ua->prompt[1]);
386          }
387          break;
388       } else {
389          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
390       }
391       if (!get_cmd(ua, pmsg) || *ua->cmd == '.') {
392          item = -1;                   /* error */
393          break;
394       }
395       item = atoi(ua->cmd);
396       if (item < 1 || item >= ua->num_prompts) {
397          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
398          continue;
399       }
400       if (prompt) {
401          strcpy(prompt, ua->prompt[item]);
402       }
403       break;
404    }
405                               
406    for (i=0; i < ua->num_prompts; i++) {
407       free(ua->prompt[i]);
408    }
409    ua->num_prompts = 0;
410    return item - 1;
411 }
412
413
414 /*
415  * We scan what the user has entered looking for
416  *    <storage-resource>
417  *    device=<device-name>      ???? does this work ????
418  *    storage=<storage-resource>
419  *    job=<job_name>
420  *    jobid=<jobid>
421  *    ?              (prompt him with storage list)
422  *    <some-error>   (prompt him with storage list)
423  */
424 STORE *get_storage_resource(UAContext *ua, char *cmd)
425 {
426    char *store_name, *device_name;
427    STORE *store;
428    int jobid;
429    JCR *jcr;
430    int i;
431       
432    if (ua->argc == 1) {
433       return select_storage_resource(ua);
434    }
435    
436    device_name = NULL;
437    store_name = NULL;
438
439    for (i=1; i<ua->argc; i++) {
440       if (!ua->argv[i]) {
441          /* Default argument is storage */
442          if (store_name) {
443             bsendmsg(ua, _("Storage name given twice.\n"));
444             return NULL;
445          }
446          store_name = ua->argk[i];
447          if (*store_name == '?') {
448             return select_storage_resource(ua);
449          }
450       } else {
451          if (strcasecmp(ua->argk[i], _("device")) == 0) {
452             device_name = ua->argv[i];
453
454          } else if (strcasecmp(ua->argk[i], _("storage")) == 0) {
455             store_name = ua->argv[i];
456
457          } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
458             jobid = atoi(ua->argv[i]);
459             if (jobid <= 0) {
460                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
461                return NULL;
462             }
463             if (!(jcr=get_jcr_by_id(jobid))) {
464                bsendmsg(ua, _("JobId %d is not running.\n"), jobid);
465                return NULL;
466             }
467             store = jcr->store;
468             free_jcr(jcr);
469             return store;
470
471          } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
472             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
473                bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
474                return NULL;
475             }
476             store = jcr->store;
477             free_jcr(jcr);
478             return store;
479
480          } else {
481             bsendmsg(ua, _("Unknown keyword: %s\n"), ua->argk[i]);
482             return NULL;
483          }
484       }
485    }
486
487    if (!store_name) {
488      bsendmsg(ua, _("A storage device name must be given.\n"));
489      store = NULL;
490    } else {
491       store = (STORE *)GetResWithName(R_STORAGE, store_name);
492       if (!store) {
493          bsendmsg(ua, "Storage resource %s: not found\n", store_name);
494       }
495    }
496    if (!store) {
497       store = select_storage_resource(ua);
498    }
499    return store;
500 }
501
502
503 /*
504  * Scan looking for mediatype= 
505  *
506  *  if not found or error, put up selection list
507  *
508  *  Returns: 0 on error
509  *           1 on success, MediaType is set
510  */
511 int get_media_type(UAContext *ua, char *MediaType)
512 {
513    STORE *store;
514    int i;
515    static char *keyword[] = {
516       "mediatype",
517       NULL};
518
519    i = find_arg_keyword(ua, keyword);
520    if (i >= 0 && ua->argv[i]) {
521       strcpy(MediaType, ua->argv[i]);
522       return 1;
523    }
524
525    start_prompt(ua, _("Media Types defined in conf file:\n"));
526    LockRes();
527    for (store = NULL; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); ) {
528       add_prompt(ua, store->media_type);
529    }
530    UnlockRes();
531    return (do_prompt(ua, _("Select the Media Type"), MediaType) < 0) ? 0 : 1;
532 }