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