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