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