]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
- Implement search for exact Volume in reservation before
[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    Copyright (C) 2001-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 #include "bacula.h"
25 #include "dird.h"
26
27 /* Imported variables */
28 extern struct s_jl joblevels[];
29
30
31 /*
32  * Confirm a retention period
33  */
34 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
35 {
36    char ed1[100];
37
38    for ( ;; ) {
39        bsendmsg(ua, _("The current %s retention period is: %s\n"),
40           msg, edit_utime(*ret, ed1, sizeof(ed1)));
41        if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
42           return 0;
43        }
44        if (strcasecmp(ua->cmd, _("mod")) == 0) {
45           if (!get_cmd(ua, _("Enter new retention period: "))) {
46              return 0;
47           }
48           if (!duration_to_utime(ua->cmd, ret)) {
49              bsendmsg(ua, _("Invalid period.\n"));
50              continue;
51           }
52           continue;
53        }
54        if (strcasecmp(ua->cmd, _("yes")) == 0) {
55           return 1;
56        }
57        if (strcasecmp(ua->cmd, _("no")) == 0) {
58           return 0;
59        }
60     }
61     return 1;
62 }
63
64 /*
65  * Given a list of keywords, find the first one
66  *  that is in the argument list.
67  * Returns: -1 if not found
68  *          index into list (base 0) on success
69  */
70 int find_arg_keyword(UAContext *ua, const char **list)
71 {
72    for (int i=1; i<ua->argc; i++) {
73       for(int j=0; list[j]; j++) {
74          if (strcasecmp(_(list[j]), ua->argk[i]) == 0) {
75             return j;
76          }
77       }
78    }
79    return -1;
80 }
81
82 /*
83  * Given one keyword, find the first one that
84  *   is in the argument list.
85  * Returns: argk index (always gt 0)
86  *          -1 if not found
87  */
88 int find_arg(UAContext *ua, const char *keyword)
89 {
90    for (int i=1; i<ua->argc; i++) {
91       if (strcasecmp(keyword, ua->argk[i]) == 0) {
92          return i;
93       }
94    }
95    return -1;
96 }
97
98 /*
99  * Given a single keyword, find it in the argument list, but
100  *   it must have a value
101  * Returns: -1 if not found or no value
102  *           list index (base 0) on success
103  */
104 int find_arg_with_value(UAContext *ua, const char *keyword)
105 {
106    for (int i=1; i<ua->argc; i++) {
107       if (strcasecmp(keyword, ua->argk[i]) == 0) {
108          if (ua->argv[i]) {
109             return i;
110          } else {
111             return -1;
112          }
113       }
114    }
115    return -1;
116 }
117
118 /*
119  * Given a list of keywords, prompt the user
120  * to choose one.
121  *
122  * Returns: -1 on failure
123  *          index into list (base 0) on success
124  */
125 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
126 {
127    int i;
128    start_prompt(ua, _("You have the following choices:\n"));
129    for (i=0; list[i]; i++) {
130       add_prompt(ua, list[i]);
131    }
132    return do_prompt(ua, "", msg, NULL, 0);
133 }
134
135
136 /*
137  * Select a Storage resource from prompt list
138  */
139 STORE *select_storage_resource(UAContext *ua)
140 {
141    char name[MAX_NAME_LENGTH];
142    STORE *store;
143
144    start_prompt(ua, _("The defined Storage resources are:\n"));
145    LockRes();
146    foreach_res(store, R_STORAGE) {
147       if (acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
148          add_prompt(ua, store->hdr.name);
149       }
150    }
151    UnlockRes();
152    do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name));
153    store = (STORE *)GetResWithName(R_STORAGE, name);
154    return store;
155 }
156
157 /*
158  * Select a FileSet resource from prompt list
159  */
160 FILESET *select_fileset_resource(UAContext *ua)
161 {
162    char name[MAX_NAME_LENGTH];
163    FILESET *fs;
164
165    start_prompt(ua, _("The defined FileSet resources are:\n"));
166    LockRes();
167    foreach_res(fs, R_FILESET) {
168       if (acl_access_ok(ua, FileSet_ACL, fs->hdr.name)) {
169          add_prompt(ua, fs->hdr.name);
170       }
171    }
172    UnlockRes();
173    do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name));
174    fs = (FILESET *)GetResWithName(R_FILESET, name);
175    return fs;
176 }
177
178
179 /*
180  * Get a catalog resource from prompt list
181  */
182 CAT *get_catalog_resource(UAContext *ua)
183 {
184    char name[MAX_NAME_LENGTH];
185    CAT *catalog = NULL;
186    int i;
187
188    for (i=1; i<ua->argc; i++) {
189       if (strcasecmp(ua->argk[i], _("catalog")) == 0 && ua->argv[i]) {
190          if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
191             catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
192             break;
193          }
194       }
195    }
196    if (!catalog) {
197       start_prompt(ua, _("The defined Catalog resources are:\n"));
198       LockRes();
199       foreach_res(catalog, R_CATALOG) {
200          if (acl_access_ok(ua, Catalog_ACL, catalog->hdr.name)) {
201             add_prompt(ua, catalog->hdr.name);
202          }
203       }
204       UnlockRes();
205       do_prompt(ua, _("Catalog"),  _("Select Catalog resource"), name, sizeof(name));
206       catalog = (CAT *)GetResWithName(R_CATALOG, name);
207    }
208    return catalog;
209 }
210
211
212 /*
213  * Select a Job resource from prompt list
214  */
215 JOB *select_job_resource(UAContext *ua)
216 {
217    char name[MAX_NAME_LENGTH];
218    JOB *job;
219
220    start_prompt(ua, _("The defined Job resources are:\n"));
221    LockRes();
222    foreach_res(job, R_JOB) {
223       if (acl_access_ok(ua, Job_ACL, job->hdr.name)) {
224          add_prompt(ua, job->hdr.name);
225       }
226    }
227    UnlockRes();
228    do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name));
229    job = (JOB *)GetResWithName(R_JOB, name);
230    return job;
231 }
232
233 /*
234  * Select a Restore Job resource from prompt list
235  */
236 JOB *select_restore_job_resource(UAContext *ua)
237 {
238    char name[MAX_NAME_LENGTH];
239    JOB *job;
240
241    start_prompt(ua, _("The defined Restore Job resources are:\n"));
242    LockRes();
243    foreach_res(job, R_JOB) {
244       if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->hdr.name)) {
245          add_prompt(ua, job->hdr.name);
246       }
247    }
248    UnlockRes();
249    do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name));
250    job = (JOB *)GetResWithName(R_JOB, name);
251    return job;
252 }
253
254
255
256 /*
257  * Select a client resource from prompt list
258  */
259 CLIENT *select_client_resource(UAContext *ua)
260 {
261    char name[MAX_NAME_LENGTH];
262    CLIENT *client;
263
264    start_prompt(ua, _("The defined Client resources are:\n"));
265    LockRes();
266    foreach_res(client, R_CLIENT) {
267       if (acl_access_ok(ua, Client_ACL, client->hdr.name)) {
268          add_prompt(ua, client->hdr.name);
269       }
270    }
271    UnlockRes();
272    do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name));
273    client = (CLIENT *)GetResWithName(R_CLIENT, name);
274    return client;
275 }
276
277 /*
278  *  Get client resource, start by looking for
279  *   client=<client-name>
280  *  if we don't find the keyword, we prompt the user.
281  */
282 CLIENT *get_client_resource(UAContext *ua)
283 {
284    CLIENT *client = NULL;
285    int i;
286
287    for (i=1; i<ua->argc; i++) {
288       if ((strcasecmp(ua->argk[i], N_("client")) == 0 ||
289            strcasecmp(ua->argk[i], N_("fd")) == 0) && ua->argv[i]) {
290          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
291             break;
292          }
293          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
294          if (client) {
295             return client;
296          }
297          bsendmsg(ua, _("Error: Client resource %s does not exist.\n"), ua->argv[i]);
298          break;
299       }
300    }
301    return select_client_resource(ua);
302 }
303
304 /* Scan what the user has entered looking for:
305  *
306  *  client=<client-name>
307  *
308  *  if error or not found, put up a list of client DBRs
309  *  to choose from.
310  *
311  *   returns: 0 on error
312  *            1 on success and fills in CLIENT_DBR
313  */
314 int get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
315 {
316    int i;
317
318    if (cr->Name[0]) {                 /* If name already supplied */
319       if (db_get_client_record(ua->jcr, ua->db, cr)) {
320          return 1;
321       }
322       bsendmsg(ua, _("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
323    }
324    for (i=1; i<ua->argc; i++) {
325       if ((strcasecmp(ua->argk[i], _("client")) == 0 ||
326            strcasecmp(ua->argk[i], _("fd")) == 0) && ua->argv[i]) {
327          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
328             break;
329          }
330          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
331          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
332             bsendmsg(ua, _("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
333                      db_strerror(ua->db));
334             cr->ClientId = 0;
335             break;
336          }
337          return 1;
338       }
339    }
340    if (!select_client_dbr(ua, cr)) {  /* try once more by proposing a list */
341       return 0;
342    }
343    return 1;
344 }
345
346 /*
347  * Select a Client record from the catalog
348  *  Returns 1 on success
349  *          0 on failure
350  */
351 int select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
352 {
353    CLIENT_DBR ocr;
354    char name[MAX_NAME_LENGTH];
355    int num_clients, i;
356    uint32_t *ids;
357
358
359    cr->ClientId = 0;
360    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
361       bsendmsg(ua, _("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
362       return 0;
363    }
364    if (num_clients <= 0) {
365       bsendmsg(ua, _("No clients defined. You must run a job before using this command.\n"));
366       return 0;
367    }
368
369    start_prompt(ua, _("Defined Clients:\n"));
370    for (i=0; i < num_clients; i++) {
371       ocr.ClientId = ids[i];
372       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
373           !acl_access_ok(ua, Client_ACL, ocr.Name)) {
374          continue;
375       }
376       add_prompt(ua, ocr.Name);
377    }
378    free(ids);
379    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
380       return 0;
381    }
382    memset(&ocr, 0, sizeof(ocr));
383    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
384
385    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
386       bsendmsg(ua, _("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
387       return 0;
388    }
389    memcpy(cr, &ocr, sizeof(ocr));
390    return 1;
391 }
392
393
394
395 /* Scan what the user has entered looking for:
396  *
397  *  pool=<pool-name>
398  *
399  *  if error or not found, put up a list of pool DBRs
400  *  to choose from.
401  *
402  *   returns: false on error
403  *            true  on success and fills in POOL_DBR
404  */
405 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr)
406 {
407    if (pr->Name[0]) {                 /* If name already supplied */
408       if (db_get_pool_record(ua->jcr, ua->db, pr) &&
409           acl_access_ok(ua, Pool_ACL, pr->Name)) {
410          return true;
411       }
412       bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
413    }
414    if (!select_pool_dbr(ua, pr)) {  /* try once more */
415       return false;
416    }
417    return true;
418 }
419
420 /*
421  * Select a Pool record from the catalog
422  */
423 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr)
424 {
425    POOL_DBR opr;
426    char name[MAX_NAME_LENGTH];
427    int num_pools, i;
428    uint32_t *ids;
429
430    for (i=1; i<ua->argc; i++) {
431       if (strcasecmp(ua->argk[i], N_("pool")) == 0 && ua->argv[i] &&
432           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
433          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
434          if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
435             bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
436                      db_strerror(ua->db));
437             pr->PoolId = 0;
438             break;
439          }
440          return true;
441       }
442    }
443
444    pr->PoolId = 0;
445    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
446       bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
447       return 0;
448    }
449    if (num_pools <= 0) {
450       bsendmsg(ua, _("No pools defined. Use the \"create\" command to create one.\n"));
451       return false;
452    }
453
454    start_prompt(ua, _("Defined Pools:\n"));
455    for (i=0; i < num_pools; i++) {
456       opr.PoolId = ids[i];
457       if (!db_get_pool_record(ua->jcr, ua->db, &opr) ||
458           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
459          continue;
460       }
461       add_prompt(ua, opr.Name);
462    }
463    free(ids);
464    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
465       return false;
466    }
467    memset(&opr, 0, sizeof(opr));
468    bstrncpy(opr.Name, name, sizeof(opr.Name));
469
470    if (!db_get_pool_record(ua->jcr, ua->db, &opr)) {
471       bsendmsg(ua, _("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
472       return false;
473    }
474    memcpy(pr, &opr, sizeof(opr));
475    return true;
476 }
477
478 /*
479  * Select a Pool and a Media (Volume) record from the database
480  */
481 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
482 {
483
484    if (!select_media_dbr(ua, mr)) {
485       return 0;
486    }
487    memset(pr, 0, sizeof(POOL_DBR));
488    pr->PoolId = mr->PoolId;
489    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
490       bsendmsg(ua, "%s", db_strerror(ua->db));
491       return 0;
492    }
493    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
494       bsendmsg(ua, _("No access to Pool \"%s\"\n"), pr->Name);
495       return 0;
496    }
497    return 1;
498 }
499
500 /* Select a Media (Volume) record from the database */
501 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
502 {
503    int i;
504
505    memset(mr, 0, sizeof(MEDIA_DBR));
506
507    i = find_arg_with_value(ua, "volume");
508    if (i >= 0) {
509       bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
510    }
511    if (mr->VolumeName[0] == 0) {
512       POOL_DBR pr;
513       memset(&pr, 0, sizeof(pr));
514       /* Get the pool from pool=<pool-name> */
515       if (!get_pool_dbr(ua, &pr)) {
516          return 0;
517       }
518       mr->PoolId = pr.PoolId;
519       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
520       if (!get_cmd(ua, _("Enter MediaId or Volume name: "))) {
521          return 0;
522       }
523       if (is_a_number(ua->cmd)) {
524          mr->MediaId = str_to_int64(ua->cmd);
525       } else {
526          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
527       }
528    }
529
530    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
531       bsendmsg(ua, "%s", db_strerror(ua->db));
532       return 0;
533    }
534    return 1;
535 }
536
537
538 /*
539  * Select a pool resource from prompt list
540  */
541 POOL *select_pool_resource(UAContext *ua)
542 {
543    char name[MAX_NAME_LENGTH];
544    POOL *pool;
545
546    start_prompt(ua, _("The defined Pool resources are:\n"));
547    LockRes();
548    foreach_res(pool, R_POOL) {
549       if (acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
550          add_prompt(ua, pool->hdr.name);
551       }
552    }
553    UnlockRes();
554    do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name));
555    pool = (POOL *)GetResWithName(R_POOL, name);
556    return pool;
557 }
558
559
560 /*
561  *  If you are thinking about using it, you
562  *  probably want to use select_pool_dbr()
563  *  or get_pool_dbr() above.
564  */
565 POOL *get_pool_resource(UAContext *ua)
566 {
567    POOL *pool = NULL;
568    int i;
569
570    i = find_arg_with_value(ua, "pool");
571    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
572       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
573       if (pool) {
574          return pool;
575       }
576       bsendmsg(ua, _("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
577    }
578    return select_pool_resource(ua);
579 }
580
581 /*
582  * List all jobs and ask user to select one
583  */
584 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
585 {
586    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
587    if (!get_pint(ua, _("Enter the JobId to select: "))) {
588       return 0;
589    }
590    jr->JobId = ua->int64_val;
591    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
592       bsendmsg(ua, "%s", db_strerror(ua->db));
593       return 0;
594    }
595    return jr->JobId;
596
597 }
598
599
600 /* Scan what the user has entered looking for:
601  *
602  *  jobid=nn
603  *
604  *  if error or not found, put up a list of Jobs
605  *  to choose from.
606  *
607  *   returns: 0 on error
608  *            JobId on success and fills in JOB_DBR
609  */
610 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
611 {
612    int i;
613
614    for (i=1; i<ua->argc; i++) {
615       if (strcasecmp(ua->argk[i], N_("job")) == 0 && ua->argv[i]) {
616          jr->JobId = 0;
617          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
618       } else if (strcasecmp(ua->argk[i], N_("jobid")) == 0 && ua->argv[i]) {
619          jr->JobId = str_to_int64(ua->argv[i]);
620       } else {
621          continue;
622       }
623       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
624          bsendmsg(ua, _("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
625                   db_strerror(ua->db));
626          jr->JobId = 0;
627          break;
628       }
629       return jr->JobId;
630    }
631
632    if (!select_job_dbr(ua, jr)) {  /* try once more */
633       return 0;
634    }
635    return jr->JobId;
636 }
637
638 /*
639  * Implement unique set of prompts
640  */
641 void start_prompt(UAContext *ua, const char *msg)
642 {
643   if (ua->max_prompts == 0) {
644      ua->max_prompts = 10;
645      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
646   }
647   ua->num_prompts = 1;
648   ua->prompt[0] = bstrdup(msg);
649 }
650
651 /*
652  * Add to prompts -- keeping them unique
653  */
654 void add_prompt(UAContext *ua, const char *prompt)
655 {
656    int i;
657    if (ua->num_prompts == ua->max_prompts) {
658       ua->max_prompts *= 2;
659       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
660          ua->max_prompts);
661     }
662     for (i=1; i < ua->num_prompts; i++) {
663        if (strcmp(ua->prompt[i], prompt) == 0) {
664           return;
665        }
666     }
667     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
668 }
669
670 /*
671  * Display prompts and get user's choice
672  *
673  *  Returns: -1 on error
674  *            index base 0 on success, and choice
675  *               is copied to prompt if not NULL
676  */
677 int do_prompt(UAContext *ua, const char *automsg, const char *msg, char *prompt, int max_prompt)
678 {
679    int i, item;
680    char pmsg[MAXSTRING];
681
682    if (ua->num_prompts == 2) {
683       item = 1;
684       if (prompt) {
685          bstrncpy(prompt, ua->prompt[1], max_prompt);
686       }
687       bsendmsg(ua, _("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
688       goto done;
689    }
690    /* If running non-interactive, bail out */
691    if (ua->batch) {
692       bsendmsg(ua, _("Cannot select %s in batch mode.\n"), automsg);
693       item = -1;
694       goto done;
695    }
696    bsendmsg(ua, ua->prompt[0]);
697    for (i=1; i < ua->num_prompts; i++) {
698       bsendmsg(ua, "%6d: %s\n", i, ua->prompt[i]);
699    }
700
701    if (prompt) {
702       *prompt = 0;
703    }
704
705    for ( ;; ) {
706       /* First item is the prompt string, not the items */
707       if (ua->num_prompts == 1) {
708          bsendmsg(ua, _("Selection is empty!\n"));
709          item = 0;                    /* list is empty ! */
710          break;
711       }
712       if (ua->num_prompts == 2) {
713          item = 1;
714          bsendmsg(ua, _("Item 1 selected automatically.\n"));
715          if (prompt) {
716             bstrncpy(prompt, ua->prompt[1], max_prompt);
717          }
718          break;
719       } else {
720          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
721       }
722       /* Either a . or an @ will get you out of the loop */
723       if (!get_pint(ua, pmsg)) {
724          item = -1;                   /* error */
725          bsendmsg(ua, _("Selection aborted, nothing done.\n"));
726          break;
727       }
728       item = ua->pint32_val;
729       if (item < 1 || item >= ua->num_prompts) {
730          bsendmsg(ua, _("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
731          continue;
732       }
733       if (prompt) {
734          bstrncpy(prompt, ua->prompt[item], max_prompt);
735       }
736       break;
737    }
738
739 done:
740    for (i=0; i < ua->num_prompts; i++) {
741       free(ua->prompt[i]);
742    }
743    ua->num_prompts = 0;
744    return item - 1;
745 }
746
747
748 /*
749  * We scan what the user has entered looking for
750  *    storage=<storage-resource>
751  *    job=<job_name>
752  *    jobid=<jobid>
753  *    ?              (prompt him with storage list)
754  *    <some-error>   (prompt him with storage list)
755  *
756  * If use_default is set, we assume that any keyword without a value
757  *   is the name of the Storage resource wanted.
758  */
759 STORE *get_storage_resource(UAContext *ua, bool use_default)
760 {
761    char *store_name = NULL;
762    STORE *store = NULL;
763    int jobid;
764    JCR *jcr;
765    int i;
766    char ed1[50];
767
768    for (i=1; i<ua->argc; i++) {
769       if (use_default && !ua->argv[i]) {
770          /* Ignore slots, scan and barcode(s) keywords */
771          if (strcasecmp("scan", ua->argk[i]) == 0 ||
772              strcasecmp("barcode", ua->argk[i]) == 0 ||
773              strcasecmp("slots", ua->argk[i]) == 0) {
774             continue;
775          }
776          /* Default argument is storage */
777          if (store_name) {
778             bsendmsg(ua, _("Storage name given twice.\n"));
779             return NULL;
780          }
781          store_name = ua->argk[i];
782          if (*store_name == '?') {
783             *store_name = 0;
784             break;
785          }
786       } else {
787          if (strcasecmp(ua->argk[i], N_("storage")) == 0 ||
788              strcasecmp(ua->argk[i], N_("sd")) == 0) {
789             store_name = ua->argv[i];
790             break;
791
792          } else if (strcasecmp(ua->argk[i], N_("jobid")) == 0) {
793             jobid = str_to_int64(ua->argv[i]);
794             if (jobid <= 0) {
795                bsendmsg(ua, _("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
796                return NULL;
797             }
798             if (!(jcr=get_jcr_by_id(jobid))) {
799                bsendmsg(ua, _("JobId %s is not running.\n"), edit_int64(jobid, ed1));
800                return NULL;
801             }
802             store = jcr->store;
803             free_jcr(jcr);
804             break;
805
806          } else if (strcasecmp(ua->argk[i], N_("job")) == 0) {
807             if (!ua->argv[i]) {
808                bsendmsg(ua, _("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
809                return NULL;
810             }
811             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
812                bsendmsg(ua, _("Job \"%s\" is not running.\n"), ua->argv[i]);
813                return NULL;
814             }
815             store = jcr->store;
816             free_jcr(jcr);
817             break;
818         }
819       }
820    }
821    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
822       store = NULL;
823    }
824
825    if (!store && store_name) {
826       store = (STORE *)GetResWithName(R_STORAGE, store_name);
827       if (!store) {
828          bsendmsg(ua, _("Storage resource \"%s\": not found\n"), store_name);
829       }
830    }
831    if (store && !acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
832       store = NULL;
833    }
834    /* No keywords found, so present a selection list */
835    if (!store) {
836       store = select_storage_resource(ua);
837    }
838    return store;
839 }
840
841 int get_storage_drive(UAContext *ua, STORE *store)
842 {
843    int i, drive;
844    /* Get drive for autochanger if possible */
845    i = find_arg_with_value(ua, "drive");
846    if (i >=0) {
847       drive = atoi(ua->argv[i]);
848    } else if (store && store->autochanger) {
849       ua->cmd[0] = 0;
850       if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
851          drive = -1;  /* None */
852       } else {
853          drive = atoi(ua->cmd);
854       }
855    }
856    return drive;
857 }
858
859
860 /*
861  * Scan looking for mediatype=
862  *
863  *  if not found or error, put up selection list
864  *
865  *  Returns: 0 on error
866  *           1 on success, MediaType is set
867  */
868 int get_media_type(UAContext *ua, char *MediaType, int max_media)
869 {
870    STORE *store;
871    int i;
872
873    i = find_arg_with_value(ua, "mediatype");
874    if (i >= 0) {
875       bstrncpy(MediaType, ua->argv[i], max_media);
876       return 1;
877    }
878
879    start_prompt(ua, _("Media Types defined in conf file:\n"));
880    LockRes();
881    foreach_res(store, R_STORAGE) {
882       add_prompt(ua, store->media_type);
883    }
884    UnlockRes();
885    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
886 }
887
888 bool get_level_from_name(JCR *jcr, const char *level_name)
889 {
890    /* Look up level name and pull code */
891    bool found = false;
892    for (int i=0; joblevels[i].level_name; i++) {
893       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
894          jcr->JobLevel = joblevels[i].level;
895          found = true;
896          break;
897       }
898    }
899    return found;
900 }