]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
Make out of freespace non-fatal for removable devices -- i.e. behaves like tape
[bacula/bacula] / bacula / src / dird / ua_select.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- User Agent Prompt and Selection code
22  *
23  *     Kern Sibbald, October MMI
24  *
25  */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 /* Imported variables */
31 extern struct s_jl joblevels[];
32
33 int confirm_retention_yesno(UAContext *ua, utime_t ret, const char *msg)
34 {
35    char ed1[100];
36    int val;
37
38    /* Look for "yes" in command line */
39    if (find_arg(ua, NT_("yes")) != -1) {
40       return 1;
41    }
42
43    for ( ;; ) {
44        ua->info_msg(_("The current %s retention period is: %s\n"),
45           msg, edit_utime(ret, ed1, sizeof(ed1)));
46        if (!get_cmd(ua, _("Continue? (yes/no): "))) {
47           return 0;
48        }
49        if (is_yesno(ua->cmd, &val)) {
50           return val;           /* is 1 for yes, 0 for no */
51        }
52     }
53     return 1;
54 }
55
56 /*
57  * Confirm a retention period
58  */
59 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
60 {
61    char ed1[100];
62    int val;
63
64    /* Look for "yes" in command line */
65    if (find_arg(ua, NT_("yes")) != -1) {
66       return 1;
67    }
68
69    for ( ;; ) {
70        ua->info_msg(_("The current %s retention period is: %s\n"),
71           msg, edit_utime(*ret, ed1, sizeof(ed1)));
72
73        if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
74           return 0;
75        }
76        if (strcasecmp(ua->cmd, _("mod")) == 0) {
77           if (!get_cmd(ua, _("Enter new retention period: "))) {
78              return 0;
79           }
80           if (!duration_to_utime(ua->cmd, ret)) {
81              ua->error_msg(_("Invalid period.\n"));
82              continue;
83           }
84           continue;
85        }
86        if (is_yesno(ua->cmd, &val)) {
87           return val;           /* is 1 for yes, 0 for no */
88        }
89     }
90     return 1;
91 }
92
93 /*
94  * Given a list of keywords, find the first one
95  *  that is in the argument list.
96  * Returns: -1 if not found
97  *          index into list (base 0) on success
98  */
99 int find_arg_keyword(UAContext *ua, const char **list)
100 {
101    for (int i=1; i<ua->argc; i++) {
102       for(int j=0; list[j]; j++) {
103          if (strcasecmp(list[j], ua->argk[i]) == 0) {
104             return j;
105          }
106       }
107    }
108    return -1;
109 }
110
111 /*
112  * Given one keyword, find the first one that
113  *   is in the argument list.
114  * Returns: argk index (always gt 0)
115  *          -1 if not found
116  */
117 int find_arg(UAContext *ua, const char *keyword)
118 {
119    for (int i=1; i<ua->argc; i++) {
120       if (strcasecmp(keyword, ua->argk[i]) == 0) {
121          return i;
122       }
123    }
124    return -1;
125 }
126
127 /*
128  * Given a single keyword, find it in the argument list, but
129  *   it must have a value
130  * Returns: -1 if not found or no value
131  *           list index (base 0) on success
132  */
133 int find_arg_with_value(UAContext *ua, const char *keyword)
134 {
135    for (int i=1; i<ua->argc; i++) {
136       if (strcasecmp(keyword, ua->argk[i]) == 0) {
137          if (ua->argv[i]) {
138             return i;
139          } else {
140             return -1;
141          }
142       }
143    }
144    return -1;
145 }
146
147 /*
148  * Given a list of keywords, prompt the user
149  * to choose one.
150  *
151  * Returns: -1 on failure
152  *          index into list (base 0) on success
153  */
154 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
155 {
156    int i;
157    start_prompt(ua, _("You have the following choices:\n"));
158    for (i=0; list[i]; i++) {
159       add_prompt(ua, list[i]);
160    }
161    return do_prompt(ua, "", msg, NULL, 0);
162 }
163
164
165 /*
166  * Select a Storage resource from prompt list
167  *  If unique is set storage resources that have the main address are
168  *   combined into one (i.e. they are all part of the same)
169  *   storage.  Note, not all commands want this.
170  */
171 STORE *select_storage_resource(UAContext *ua, bool unique)
172 {
173    POOL_MEM tmp;
174    char name[MAX_NAME_LENGTH];
175    STORE *store;
176
177    /* Does user want a full selection? */
178    if (unique && find_arg(ua, NT_("select")) > 0) {
179       unique = false;
180    }
181    start_prompt(ua, _("The defined Storage resources are:\n"));
182    LockRes();
183    foreach_res(store, R_STORAGE) {
184       if (store->is_enabled() && acl_access_ok(ua, Storage_ACL, store->name())) {
185          if (unique) {
186             Mmsg(tmp, "%s:%d", store->address, store->SDport);
187             add_prompt(ua, store->name(), tmp.c_str());
188          } else {
189             add_prompt(ua, store->name());
190          }
191       }
192    }
193    UnlockRes();
194    if (do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name)) < 0) {
195       return NULL;
196    }
197    store = (STORE *)GetResWithName(R_STORAGE, name);
198    return store;
199 }
200
201 /*
202  * Select a FileSet resource from prompt list
203  */
204 FILESET *select_fileset_resource(UAContext *ua)
205 {
206    char name[MAX_NAME_LENGTH];
207    FILESET *fs;
208
209    start_prompt(ua, _("The defined FileSet resources are:\n"));
210    LockRes();
211    foreach_res(fs, R_FILESET) {
212       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
213          add_prompt(ua, fs->name());
214       }
215    }
216    UnlockRes();
217    if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
218       return NULL;
219    }
220    fs = (FILESET *)GetResWithName(R_FILESET, name);
221    return fs;
222 }
223
224
225 /*
226  * Get a catalog resource from prompt list
227  */
228 CAT *get_catalog_resource(UAContext *ua)
229 {
230    char name[MAX_NAME_LENGTH];
231    CAT *catalog = NULL;
232    CLIENT *client = NULL;
233    int i;
234
235    for (i=1; i<ua->argc; i++) {
236       if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
237          if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
238             catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
239             break;
240          }
241       }
242       if (strcasecmp(ua->argk[i], NT_("client")) == 0 && ua->argv[i]) {
243          if (acl_access_client_ok(ua, ua->argv[i], JT_BACKUP_RESTORE)) {
244             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
245             break;
246          }
247       }
248    }
249    if (!catalog && client) {    /* Try to take the catalog from the client */
250       catalog = client->catalog;
251    }
252    if (ua->gui && !catalog) {
253       LockRes();
254       catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
255       UnlockRes();
256       if (!catalog) {
257          ua->error_msg(_("Could not find a Catalog resource\n"));
258          return NULL;
259       } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
260          ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
261          return NULL;
262       }
263       return catalog;
264    }
265    if (!catalog) {
266       start_prompt(ua, _("The defined Catalog resources are:\n"));
267       LockRes();
268       foreach_res(catalog, R_CATALOG) {
269          if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
270             add_prompt(ua, catalog->name());
271          }
272       }
273       UnlockRes();
274       if (do_prompt(ua, _("Catalog"),  _("Select Catalog resource"), name, sizeof(name)) < 0) {
275          return NULL;
276       }
277       catalog = (CAT *)GetResWithName(R_CATALOG, name);
278    }
279    return catalog;
280 }
281
282
283 /*
284  * Select a job to enable or disable
285  */
286 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
287 {
288    char name[MAX_NAME_LENGTH];
289    JOB *job;
290
291    LockRes();
292    if (enable) {
293       start_prompt(ua, _("The disabled Job resources are:\n"));
294    } else {
295       start_prompt(ua, _("The enabled Job resources are:\n"));
296    }
297    foreach_res(job, R_JOB) {
298       if (!acl_access_ok(ua, Job_ACL, job->name())) {
299          continue;
300       }
301       if (job->is_enabled() == enable) {   /* Already enabled/disabled? */
302          continue;                    /* yes, skip */
303       }
304       add_prompt(ua, job->name());
305    }
306    UnlockRes();
307    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
308       return NULL;
309    }
310    job = (JOB *)GetResWithName(R_JOB, name);
311    return job;
312 }
313
314 /*
315  * Select a Job resource from prompt list
316  */
317 JOB *select_job_resource(UAContext *ua)
318 {
319    char name[MAX_NAME_LENGTH];
320    JOB *job;
321
322    start_prompt(ua, _("The defined Job resources are:\n"));
323    LockRes();
324    foreach_res(job, R_JOB) {
325       if (job->is_enabled() && acl_access_ok(ua, Job_ACL, job->name())) {
326          add_prompt(ua, job->name());
327       }
328    }
329    UnlockRes();
330    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
331       return NULL;
332    }
333    job = (JOB *)GetResWithName(R_JOB, name);
334    return job;
335 }
336
337 /*
338  * Select a Restore Job resource from argument or prompt
339  */
340 JOB *get_restore_job(UAContext *ua)
341 {
342    JOB *job;
343    int i = find_arg_with_value(ua, "restorejob");
344    if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
345       job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
346       if (job && job->JobType == JT_RESTORE) {
347          return job;
348       }
349       ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
350                     ua->argv[i]);
351    }
352    return select_restore_job_resource(ua);
353 }
354
355 /*
356  * Select a Restore Job resource from prompt list
357  */
358 JOB *select_restore_job_resource(UAContext *ua)
359 {
360    char name[MAX_NAME_LENGTH];
361    JOB *job;
362
363    start_prompt(ua, _("The defined Restore Job resources are:\n"));
364    LockRes();
365    foreach_res(job, R_JOB) {
366       if (job->JobType == JT_RESTORE && job->is_enabled() &&
367           acl_access_ok(ua, Job_ACL, job->name())) {
368          add_prompt(ua, job->name());
369       }
370    }
371    UnlockRes();
372    if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
373       return NULL;
374    }
375    job = (JOB *)GetResWithName(R_JOB, name);
376    return job;
377 }
378
379 /*
380  * Select a client to enable or disable
381  */
382 CLIENT *select_enable_disable_client_resource(UAContext *ua, bool enable)
383 {
384    char name[MAX_NAME_LENGTH];
385    CLIENT *client;
386
387    LockRes();
388    start_prompt(ua, _("The defined Client resources are:\n"));
389    foreach_res(client, R_CLIENT) {
390       if (!acl_access_client_ok(ua, client->name(), JT_BACKUP_RESTORE)) {
391          continue;
392       }
393       if (client->is_enabled() == enable) {   /* Already enabled/disabled? */
394          continue;                       /* yes, skip */
395       }
396       add_prompt(ua, client->name());
397    }
398    UnlockRes();
399    if (do_prompt(ua, _("Client"), _("Select Client resource"), name, sizeof(name)) < 0) {
400       return NULL;
401    }
402    client = (CLIENT *)GetResWithName(R_CLIENT, name);
403    return client;
404 }
405
406
407 /*
408  * Select a client resource from prompt list
409  */
410 CLIENT *select_client_resource(UAContext *ua, int32_t jobtype)
411 {
412    char name[MAX_NAME_LENGTH];
413    CLIENT *client;
414
415    start_prompt(ua, _("The defined Client resources are:\n"));
416    LockRes();
417    foreach_res(client, R_CLIENT) {
418       if (client->is_enabled() && acl_access_client_ok(ua, client->name(), jobtype)) {
419          add_prompt(ua, client->name());
420       }
421    }
422    UnlockRes();
423    if (do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
424       return NULL;
425    }
426    client = (CLIENT *)GetResWithName(R_CLIENT, name);
427    return client;
428 }
429
430 /*
431  *  Get client resource, start by looking for
432  *   client=<client-name>
433  *  if we don't find the keyword, we prompt the user.
434  */
435 CLIENT *get_client_resource(UAContext *ua, int32_t jobtype)
436 {
437    CLIENT *client = NULL;
438    int i;
439
440    for (i=1; i<ua->argc; i++) {
441       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
442            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
443          if (!acl_access_client_ok(ua, ua->argv[i], jobtype)) {
444             break;
445          }
446          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
447          if (client) {
448             return client;
449          }
450          ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
451          break;
452       }
453    }
454    return select_client_resource(ua, jobtype);
455 }
456
457 /*
458  * Select a schedule to enable or disable
459  */
460 SCHED *select_enable_disable_schedule_resource(UAContext *ua, bool enable)
461 {
462    char name[MAX_NAME_LENGTH];
463    SCHED *sched;
464
465    LockRes();
466    start_prompt(ua, _("The defined Schedule resources are:\n"));
467    foreach_res(sched, R_SCHEDULE) {
468       if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
469          continue;
470       }
471       if (sched->is_enabled() == enable) {   /* Already enabled/disabled? */
472          continue;                      /* yes, skip */
473       }
474       add_prompt(ua, sched->name());
475    }
476    UnlockRes();
477    if (do_prompt(ua, _("Schedule"), _("Select Schedule resource"), name, sizeof(name)) < 0) {
478       return NULL;
479    }
480    sched = (SCHED *)GetResWithName(R_SCHEDULE, name);
481    return sched;
482 }
483
484
485 /* Scan what the user has entered looking for:
486  *
487  *  client=<client-name>
488  *
489  *  if error or not found, put up a list of client DBRs
490  *  to choose from.
491  *
492  *   returns: 0 on error
493  *            1 on success and fills in CLIENT_DBR
494  */
495 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr, int32_t jobtype)
496 {
497    int i;
498
499    if (cr->Name[0]) {                 /* If name already supplied */
500       if (db_get_client_record(ua->jcr, ua->db, cr)) {
501          return 1;
502       }
503       ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
504    }
505    for (i=1; i<ua->argc; i++) {
506       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
507            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
508          if (!acl_access_client_ok(ua, ua->argv[i], jobtype)) {
509             break;
510          }
511          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
512          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
513             ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
514                      db_strerror(ua->db));
515             cr->ClientId = 0;
516             break;
517          }
518          return 1;
519       }
520    }
521    if (!select_client_dbr(ua, cr, jobtype)) {  /* try once more by proposing a list */
522       return 0;
523    }
524    return 1;
525 }
526
527 /*
528  * Select a Client record from the catalog
529  *  Returns 1 on success
530  *          0 on failure
531  */
532 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr, int32_t jobtype)
533 {
534    CLIENT_DBR ocr;
535    char name[MAX_NAME_LENGTH];
536    int num_clients, i;
537    uint32_t *ids;
538
539
540    cr->ClientId = 0;
541    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
542       ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
543       return 0;
544    }
545    if (num_clients <= 0) {
546       ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
547       return 0;
548    }
549
550    start_prompt(ua, _("Defined Clients:\n"));
551    for (i=0; i < num_clients; i++) {
552       ocr.ClientId = ids[i];
553       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
554           !acl_access_client_ok(ua, ocr.Name, jobtype)) {
555          continue;
556       }
557       add_prompt(ua, ocr.Name);
558    }
559    free(ids);
560    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
561       return 0;
562    }
563    memset(&ocr, 0, sizeof(ocr));
564    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
565
566    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
567       ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
568       return 0;
569    }
570    memcpy(cr, &ocr, sizeof(ocr));
571    return 1;
572 }
573
574 /* Scan what the user has entered looking for:
575  *
576  *  argk=<pool-name>
577  *
578  *  where argk can be : pool, recyclepool, scratchpool, nextpool etc..
579  *
580  *  if error or not found, put up a list of pool DBRs
581  *  to choose from.
582  *
583  *   returns: false on error
584  *            true  on success and fills in POOL_DBR
585  */
586 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
587 {
588    if (pr->Name[0]) {                 /* If name already supplied */
589       if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
590           acl_access_ok(ua, Pool_ACL, pr->Name)) {
591          return true;
592       }
593       ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
594    }
595    if (!select_pool_dbr(ua, pr, argk)) {  /* try once more */
596       return false;
597    }
598    return true;
599 }
600
601 /*
602  * Select a Pool record from catalog
603  * argk can be pool, recyclepool, scratchpool etc..
604  */
605 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
606 {
607    POOL_DBR opr;
608    char name[MAX_NAME_LENGTH];
609    int num_pools, i;
610    uint32_t *ids;
611
612    for (i=1; i<ua->argc; i++) {
613       if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
614           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
615          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
616          if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
617             ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
618                      db_strerror(ua->db));
619             pr->PoolId = 0;
620             break;
621          }
622          return true;
623       }
624    }
625
626    pr->PoolId = 0;
627    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
628       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
629       return 0;
630    }
631    if (num_pools <= 0) {
632       ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
633       return false;
634    }
635
636    start_prompt(ua, _("Defined Pools:\n"));
637    if (bstrcmp(argk, NT_("recyclepool"))) {
638       add_prompt(ua, _("*None*"));
639    }
640    for (i=0; i < num_pools; i++) {
641       opr.PoolId = ids[i];
642       if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
643           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
644          continue;
645       }
646       add_prompt(ua, opr.Name);
647    }
648    free(ids);
649    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
650       return false;
651    }
652
653    memset(&opr, 0, sizeof(opr));
654    /* *None* is only returned when selecting a recyclepool, and in that case
655     * the calling code is only interested in opr.Name, so then we can leave
656     * pr as all zero.
657     */
658    if (!bstrcmp(name, _("*None*"))) {
659      bstrncpy(opr.Name, name, sizeof(opr.Name));
660
661      if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
662         ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
663         return false;
664      }
665    }
666
667    memcpy(pr, &opr, sizeof(opr));
668    return true;
669 }
670
671 /*
672  * Select a Pool and a Media (Volume) record from the database
673  */
674 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
675 {
676
677    if (!select_media_dbr(ua, mr)) {
678       return 0;
679    }
680    memset(pr, 0, sizeof(POOL_DBR));
681    pr->PoolId = mr->PoolId;
682    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
683       ua->error_msg("%s", db_strerror(ua->db));
684       return 0;
685    }
686    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
687       ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
688       return 0;
689    }
690    return 1;
691 }
692
693 /* Select a Media (Volume) record from the database */
694 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
695 {
696    int i;
697    int ret = 0;
698    POOLMEM *err = get_pool_memory(PM_FNAME);
699    *err=0;
700
701    mr->clear();
702    i = find_arg_with_value(ua, "volume");
703    if (i >= 0) {
704       if (is_name_valid(ua->argv[i], &err)) {
705          bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
706       } else {
707          goto bail_out;
708       }
709    }
710    if (mr->VolumeName[0] == 0) {
711       POOL_DBR pr;
712       memset(&pr, 0, sizeof(pr));
713       /* Get the pool from pool=<pool-name> */
714       if (!get_pool_dbr(ua, &pr)) {
715          goto bail_out;
716       }
717       mr->PoolId = pr.PoolId;
718       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
719       if (!get_cmd(ua, _("Enter a Volume name or *MediaId: "))) {
720          goto bail_out;
721       }
722       if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
723          mr->MediaId = str_to_int64(ua->cmd+1);
724       } else if (is_name_valid(ua->cmd, &err)) {
725          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
726       } else {
727          goto bail_out;
728       }
729    }
730
731    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
732       pm_strcpy(err, db_strerror(ua->db));
733       goto bail_out;
734    }
735    ret = 1;
736
737 bail_out:
738    if (!ret && *err) {
739       ua->error_msg("%s", err);
740    }
741    free_pool_memory(err);
742    return ret;
743 }
744
745
746 /*
747  * Select a pool resource from prompt list
748  */
749 POOL *select_pool_resource(UAContext *ua)
750 {
751    char name[MAX_NAME_LENGTH];
752    POOL *pool;
753
754    start_prompt(ua, _("The defined Pool resources are:\n"));
755    LockRes();
756    foreach_res(pool, R_POOL) {
757       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
758          add_prompt(ua, pool->name());
759       }
760    }
761    UnlockRes();
762    if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
763       return NULL;
764    }
765    pool = (POOL *)GetResWithName(R_POOL, name);
766    return pool;
767 }
768
769
770 /*
771  *  If you are thinking about using it, you
772  *  probably want to use select_pool_dbr()
773  *  or get_pool_dbr() above.
774  */
775 POOL *get_pool_resource(UAContext *ua)
776 {
777    POOL *pool = NULL;
778    int i;
779
780    i = find_arg_with_value(ua, "pool");
781    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
782       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
783       if (pool) {
784          return pool;
785       }
786       ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
787    }
788    return select_pool_resource(ua);
789 }
790
791 /*
792  * List all jobs and ask user to select one
793  */
794 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
795 {
796    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
797    if (!get_pint(ua, _("Enter the JobId to select: "))) {
798       return 0;
799    }
800    jr->JobId = ua->int64_val;
801    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
802       ua->error_msg("%s", db_strerror(ua->db));
803       return 0;
804    }
805    return jr->JobId;
806
807 }
808
809
810 /* Scan what the user has entered looking for:
811  *
812  *  jobid=nn
813  *
814  *  if error or not found, put up a list of Jobs
815  *  to choose from.
816  *
817  *   returns: 0 on error
818  *            JobId on success and fills in JOB_DBR
819  */
820 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
821 {
822    int i;
823
824    for (i=1; i<ua->argc; i++) {
825       if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
826          jr->JobId = 0;
827          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
828       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
829          jr->JobId = str_to_int64(ua->argv[i]);
830          jr->Job[0] = 0;
831       } else {
832          continue;
833       }
834       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
835          ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
836                   db_strerror(ua->db));
837          jr->JobId = 0;
838          break;
839       }
840       return jr->JobId;
841    }
842
843    jr->JobId = 0;
844    jr->Job[0] = 0;
845
846    for (i=1; i<ua->argc; i++) {
847       if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
848            strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
849          jr->JobId = 0;
850          bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
851          break;
852       }
853    }
854    if (!select_job_dbr(ua, jr)) {  /* try once more */
855       return 0;
856    }
857    return jr->JobId;
858 }
859
860 /*
861  * Implement unique set of prompts
862  */
863 void start_prompt(UAContext *ua, const char *msg)
864 {
865   if (ua->max_prompts == 0) {
866      ua->max_prompts = 10;
867      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
868      ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
869   }
870   ua->num_prompts = 1;
871   ua->prompt[0] = bstrdup(msg);
872   ua->unique[0] = NULL;
873 }
874
875 /*
876  * Add to prompts -- keeping them unique by name
877  */
878 void add_prompt(UAContext *ua, const char *prompt, char *unique)
879 {
880    int i;
881    if (ua->num_prompts == ua->max_prompts) {
882       ua->max_prompts *= 2;
883       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
884          ua->max_prompts);
885       ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
886          ua->max_prompts);
887     }
888     for (i=1; i < ua->num_prompts; i++) {
889        if (strcmp(ua->prompt[i], prompt) == 0) {
890           return;
891        } else if (unique && strcmp(ua->unique[i], unique) == 0) {
892           return;
893        }
894     }
895     ua->prompt[ua->num_prompts] = bstrdup(prompt);
896     if (unique) {
897        ua->unique[ua->num_prompts++] = bstrdup(unique);
898     } else {
899        ua->unique[ua->num_prompts++] = NULL;
900     }
901 }
902
903 /*
904  * Display prompts and get user's choice
905  *
906  *  Returns: -1 on error
907  *            index base 0 on success, and choice
908  *               is copied to prompt if not NULL
909  *             prompt is set to the chosen prompt item string
910  */
911 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
912               char *prompt, int max_prompt)
913 {
914    int i, item;
915    char pmsg[MAXSTRING];
916    BSOCK *user = ua->UA_sock;
917
918    if (prompt) {
919       *prompt = 0;
920    }
921    if (ua->num_prompts == 2) {
922       item = 1;
923       if (prompt) {
924          bstrncpy(prompt, ua->prompt[1], max_prompt);
925       }
926       ua->send_msg(_("Automatically selected %s: %s\n"), NPRTB(automsg), ua->prompt[1]);
927       goto done;
928    }
929    /* If running non-interactive, bail out */
930    if (ua->batch) {
931       /* First print the choices he wanted to make */
932       ua->send_msg(ua->prompt[0]);
933       for (i=1; i < ua->num_prompts; i++) {
934          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
935       }
936       /* Now print error message */
937       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
938       item = -1;
939       goto done;
940    }
941    if (ua->api) user->signal(BNET_START_SELECT);
942    ua->send_msg(ua->prompt[0]);
943    for (i=1; i < ua->num_prompts; i++) {
944       if (ua->api) {
945          ua->send_msg("%s", ua->prompt[i]);
946       } else {
947          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
948       }
949    }
950    if (ua->api) user->signal(BNET_END_SELECT);
951
952    for ( ;; ) {
953       /* First item is the prompt string, not the items */
954       if (ua->num_prompts == 1) {
955          ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
956          item = -1;                    /* list is empty ! */
957          break;
958       }
959       if (ua->num_prompts == 2) {
960          item = 1;
961          ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
962          if (prompt) {
963             bstrncpy(prompt, ua->prompt[1], max_prompt);
964          }
965          break;
966       } else {
967          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
968       }
969       /* Either a . or an @ will get you out of the loop */
970       if (ua->api) user->signal(BNET_SELECT_INPUT);
971       if (!get_pint(ua, pmsg)) {
972          item = -1;                   /* error */
973          ua->info_msg(_("Selection aborted, nothing done.\n"));
974          break;
975       }
976       item = ua->pint32_val;
977       if (item < 1 || item >= ua->num_prompts) {
978          ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
979          continue;
980       }
981       if (prompt) {
982          bstrncpy(prompt, ua->prompt[item], max_prompt);
983       }
984       break;
985    }
986
987 done:
988    for (i=0; i < ua->num_prompts; i++) {
989       free(ua->prompt[i]);
990       if (ua->unique[i]) free(ua->unique[i]);
991    }
992    ua->num_prompts = 0;
993    return item>0 ? item-1 : item;
994 }
995
996 /*
997  * Display prompts and get user's choice
998  *
999  *  Returns: -1 on error
1000  *            number of items selected and the choices are
1001  *               copied to selected if not NULL
1002  *            selected is an alist of the prompts chosen
1003  *              Note! selected must already be initialized.
1004  */
1005 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
1006               alist *selected)
1007 {
1008    int i, item;
1009    char pmsg[MAXSTRING];
1010    BSOCK *user = ua->UA_sock;
1011    sellist sl;
1012
1013    /* First item is the prompt string, not the items */
1014    if (ua->num_prompts == 1) {
1015       ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
1016       item = -1;                    /* list is empty ! */
1017       goto done;
1018    }
1019    if (ua->num_prompts == 2) {
1020       item = 1;
1021       selected->append(bstrdup(ua->prompt[1]));
1022       ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
1023       goto done;
1024    }
1025    /* If running non-interactive, bail out */
1026    if (ua->batch) {
1027       /* First print the choices he wanted to make */
1028       ua->send_msg(ua->prompt[0]);
1029       for (i=1; i < ua->num_prompts; i++) {
1030          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1031       }
1032       /* Now print error message */
1033       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
1034       item = -1;
1035       goto done;
1036    }
1037    if (ua->api) user->signal(BNET_START_SELECT);
1038    ua->send_msg(ua->prompt[0]);
1039    for (i=1; i < ua->num_prompts; i++) {
1040       if (ua->api) {
1041          ua->send_msg("%s", ua->prompt[i]);
1042       } else {
1043          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1044       }
1045    }
1046    if (ua->api) user->signal(BNET_END_SELECT);
1047
1048    sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
1049
1050    for ( ;; ) {
1051       bool ok = true;
1052       /* Either a . or an @ will get you out of the loop */
1053       if (ua->api) user->signal(BNET_SELECT_INPUT);
1054
1055       if (!get_selection_list(ua, sl, pmsg, false)) {
1056          item = -1;
1057          break;
1058       }
1059
1060       if (sl.is_all()) {
1061          for (i=1; i < ua->num_prompts; i++) {
1062             selected->append(bstrdup(ua->prompt[i]));
1063          }
1064       } else {
1065          while ( (item = sl.next()) > 0) {
1066             if (item < 1 || item >= ua->num_prompts) {
1067                ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
1068                ok = false;
1069                break;
1070             }
1071             selected->append(bstrdup(ua->prompt[item]));
1072          }
1073       }
1074       if (ok) {
1075          item = selected->size();
1076          break;
1077       }
1078    }
1079
1080 done:
1081    for (i=0; i < ua->num_prompts; i++) {
1082       free(ua->prompt[i]);
1083       if (ua->unique[i]) free(ua->unique[i]);
1084    }
1085    ua->num_prompts = 0;
1086    return item;
1087 }
1088
1089
1090 /*
1091  * We scan what the user has entered looking for
1092  *    storage=<storage-resource>
1093  *    job=<job_name>
1094  *    jobid=<jobid>
1095  *    ?              (prompt him with storage list)
1096  *    <some-error>   (prompt him with storage list)
1097  *
1098  * If use_default is set, we assume that any keyword without a value
1099  *   is the name of the Storage resource wanted.
1100  */
1101 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1102 {
1103    char store_name[MAX_NAME_LENGTH];
1104    STORE *store = NULL;
1105    int jobid;
1106    JCR *jcr;
1107    int i;
1108    char ed1[50];
1109    *store_name = 0;
1110
1111    for (i=1; i<ua->argc; i++) {
1112       if (use_default && !ua->argv[i]) {
1113          /* Ignore slots, scan and barcode(s) keywords */
1114          if (strcasecmp("scan", ua->argk[i]) == 0 ||
1115              strcasecmp("barcode", ua->argk[i]) == 0 ||
1116              strcasecmp("barcodes", ua->argk[i]) == 0 ||
1117              strcasecmp("slots", ua->argk[i]) == 0) {
1118             continue;
1119          }
1120          /* Default argument is storage (except in enable/disable command) */
1121          if (store_name[0]) {
1122             ua->error_msg(_("Storage name given twice.\n"));
1123             return NULL;
1124          }
1125          bstrncpy(store_name, ua->argk[i], sizeof(store_name));
1126          if (store_name[0] == '?') {
1127             *store_name = 0;
1128             break;
1129          }
1130       } else {
1131          if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1132              strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1133             bstrncpy(store_name, NPRTB(ua->argv[i]), sizeof(store_name));
1134
1135          } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1136             jobid = str_to_int64(ua->argv[i]);
1137             if (jobid <= 0) {
1138                ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1139                return NULL;
1140             }
1141             if (!(jcr=get_jcr_by_id(jobid))) {
1142                ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1143                return NULL;
1144             }
1145             if (jcr->wstore) {
1146                bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1147             }
1148             free_jcr(jcr);
1149
1150          } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1151                     strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1152             if (!ua->argv[i]) {
1153                ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1154                return NULL;
1155             }
1156             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1157                ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1158                return NULL;
1159             }
1160             if (jcr->wstore) {
1161                bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1162             }
1163             free_jcr(jcr);
1164
1165          } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1166             if (!ua->argv[i]) {
1167                ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1168                return NULL;
1169             }
1170             if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1171                if (jcr->wstore) {
1172                   bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
1173                }
1174                free_jcr(jcr);
1175             }
1176          }
1177          if (store_name[0]) {
1178             break;              /* We can stop the loop if we have something */
1179          }
1180       }
1181    }
1182
1183    if (store_name[0] != 0) {
1184       store = (STORE *)GetResWithName(R_STORAGE, store_name);
1185       if (!store && strcmp(store_name, "storage") != 0) {
1186          /* Looks that the first keyword of the line was not a storage name, make
1187           * sure that it's not "storage=" before we print the following message
1188           */
1189          ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1190       }
1191    }
1192    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1193       store = NULL;
1194    }
1195    /* No keywords found, so present a selection list */
1196    if (!store) {
1197       store = select_storage_resource(ua, unique);
1198    }
1199    return store;
1200 }
1201
1202 /* Get drive that we are working with for this storage */
1203 int get_storage_drive(UAContext *ua, STORE *store)
1204 {
1205    int i, drive = -1;
1206    /* Get drive for autochanger if possible */
1207    i = find_arg_with_value(ua, "drive");
1208    if (i >=0) {
1209       drive = atoi(ua->argv[i]);
1210    } else if (store && store->autochanger) {
1211       /* If our structure is not set ask SD for # drives */
1212       if (store->drives == 0) {
1213          store->drives = get_num_drives_from_SD(ua);
1214       }
1215       /* If only one drive, default = 0 */
1216       if (store->drives == 1) {
1217          drive = 0;
1218       } else {
1219          /* Ask user to enter drive number */
1220          ua->cmd[0] = 0;
1221          if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1222             drive = -1;  /* None */
1223          } else {
1224             drive = atoi(ua->cmd);
1225          }
1226      }
1227    }
1228    return drive;
1229 }
1230
1231 /* Get slot that we are working with for this storage */
1232 int get_storage_slot(UAContext *ua, STORE *store)
1233 {
1234    int i, slot = -1;
1235    /* Get slot for autochanger if possible */
1236    i = find_arg_with_value(ua, "slot");
1237    if (i >=0) {
1238       slot = atoi(ua->argv[i]);
1239    } else if (store && store->autochanger) {
1240       /* Ask user to enter slot number */
1241       ua->cmd[0] = 0;
1242       if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1243          slot = -1;  /* None */
1244       } else {
1245          slot = atoi(ua->cmd);
1246       }
1247    }
1248    return slot;
1249 }
1250
1251
1252
1253 /*
1254  * Scan looking for mediatype=
1255  *
1256  *  if not found or error, put up selection list
1257  *
1258  *  Returns: 0 on error
1259  *           1 on success, MediaType is set
1260  */
1261 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1262 {
1263    STORE *store;
1264    int i;
1265
1266    i = find_arg_with_value(ua, "mediatype");
1267    if (i >= 0) {
1268       bstrncpy(MediaType, ua->argv[i], max_media);
1269       return 1;
1270    }
1271
1272    start_prompt(ua, _("Media Types defined in conf file:\n"));
1273    LockRes();
1274    foreach_res(store, R_STORAGE) {
1275       if (store->is_enabled()) {
1276          add_prompt(ua, store->media_type);
1277       }
1278    }
1279    UnlockRes();
1280    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1281 }
1282
1283 int get_level_code_from_name(const char *level_name)
1284 {
1285    int ret = 0;
1286    if (!level_name) {
1287       return ret;
1288    }
1289    for (int i=0; joblevels[i].level_name; i++) {
1290       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1291          ret = joblevels[i].level;
1292          break;
1293       }
1294    }
1295    return ret;
1296 }
1297
1298 bool get_level_from_name(JCR *jcr, const char *level_name)
1299 {
1300    int level = get_level_code_from_name(level_name);
1301    if (level > 0) {
1302       jcr->setJobLevel(level);
1303       return true;
1304    }
1305    return false;
1306 }
1307
1308 static int count_running_jobs(UAContext *ua)
1309 {
1310    int tjobs = 0;                  /* total # number jobs */
1311    int njobs = 0;
1312    JCR *jcr;
1313    /* Count Jobs running */
1314    foreach_jcr(jcr) {
1315       if (jcr->is_internal_job()) {      /* this is us */
1316          continue;
1317       }
1318       tjobs++;                    /* count of all jobs */
1319       if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1320          continue;               /* skip not authorized */
1321       }
1322       njobs++;                   /* count of authorized jobs */
1323    }
1324    endeach_jcr(jcr);
1325
1326    if (njobs == 0) {            /* no authorized */
1327       if (tjobs == 0) {
1328          ua->send_msg(_("No Jobs running.\n"));
1329       } else {
1330          ua->send_msg(_("None of your jobs are running.\n"));
1331       }
1332    }
1333    return njobs;
1334 }
1335
1336
1337 /* Get a list of running jobs
1338  * "reason" is used in user messages
1339  * can be: cancel, limit, ...
1340  *  Returns: -1 on error
1341  *           nb of JCR on success (should be free_jcr() after)
1342  */
1343 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1344 {
1345    int i;
1346    JCR *jcr = NULL;
1347    int njobs = 0;
1348    char JobName[MAX_NAME_LENGTH];
1349    char temp[256];
1350    alist *selected = NULL;
1351
1352    for (i=1; i<ua->argc; i++) {
1353       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1354          sellist sl;
1355          int32_t JobId;
1356
1357          if (!ua->argv[i]) {
1358             ua->error_msg(_("No value given for \"jobid\".\n"));
1359             goto bail_out;
1360          }
1361          if (!sl.set_string(ua->argv[i], true)) {
1362             ua->send_msg("%s", sl.get_errmsg());
1363             goto bail_out;
1364          }
1365          foreach_sellist(JobId, &sl) {
1366             jcr = get_jcr_by_id(JobId);
1367             if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1368                jcrs->append(jcr);
1369             } else if (jcr) {
1370                ua->error_msg(_("Unauthorized command from this console "
1371                                "for JobId=%d.\n"), JobId);
1372                free_jcr(jcr);
1373             } else {
1374                ua->warning_msg(_("Warning Job JobId=%d is not running.\n"), JobId);
1375             }
1376          }
1377          if (jcrs->size() == 0) {
1378             goto bail_out;               /* If we did not find specified jobid, get out */
1379          }
1380          break;
1381
1382       /* TODO: might want to implement filters (client, status, etc...) */
1383       } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1384          foreach_jcr(jcr) {
1385             if (jcr->is_internal_job()) { /* Do not cancel consoles */
1386                continue;
1387             }
1388             if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1389                continue;               /* skip not authorized */
1390             }
1391             jcr->inc_use_count();
1392             jcrs->append(jcr);
1393          }
1394          endeach_jcr(jcr);
1395
1396          /* If we have something and no "yes" on command line, get confirmation */
1397          if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1398             char nbuf[1000];
1399             bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1400                       reason, jcrs->size(), jcrs->size()>1?"s":"");
1401             if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1402                goto bail_out;
1403             }
1404          }
1405          if (jcrs->size() == 0) {
1406             goto bail_out;               /* If we did not find specified jobid, get out */
1407          }
1408          break;
1409
1410       } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1411          if (!ua->argv[i]) {
1412             ua->error_msg(_("No value given for \"job\".\n"));
1413             goto bail_out;
1414          }
1415          jcr = get_jcr_by_partial_name(ua->argv[i]);
1416
1417          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1418             jcrs->append(jcr);
1419
1420          } else if (jcr) {
1421             if (jcr->job) {
1422                ua->error_msg(_("Unauthorized command from this console "
1423                                "for job=%s.\n"), ua->argv[i]);
1424             }
1425             free_jcr(jcr);
1426
1427          } else {
1428             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1429          }
1430          if (jcrs->size() == 0) {
1431             goto bail_out;               /* If we did not find specified jobid, get out */
1432          }
1433          break;
1434
1435       } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1436          if (!ua->argv[i]) {
1437             ua->error_msg(_("No value given for \"ujobid\".\n"));
1438             goto bail_out;
1439          }
1440          jcr = get_jcr_by_full_name(ua->argv[i]);
1441
1442          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1443             jcrs->append(jcr);
1444
1445          } else if (jcr) {
1446             if (jcr->job) {
1447                ua->error_msg(_("Unauthorized command from this console "
1448                                "for ujobid=%s.\n"), ua->argv[i]);
1449             }
1450             free_jcr(jcr);
1451
1452          } else {
1453             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1454          }
1455          if (jcrs->size() == 0) {
1456             goto bail_out;               /* If we did not find specified jobid, get out */
1457          }
1458          break;
1459       }
1460    }
1461
1462    if (jcrs->size() == 0) {
1463       /*
1464        * If we still do not have a jcr,
1465        *   throw up a list and ask the user to select one.
1466        */
1467       char *item;
1468       char buf[1000];
1469       njobs = count_running_jobs(ua);
1470       if (njobs == 0) {
1471          goto bail_out;
1472       }
1473       start_prompt(ua, _("Select Job(s):\n"));
1474       foreach_jcr(jcr) {
1475          char ed1[50];
1476          if (jcr->is_internal_job()) {      /* this is us */
1477             continue;
1478          }
1479          bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1480          add_prompt(ua, buf);
1481       }
1482       endeach_jcr(jcr);
1483       bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1484       selected = New(alist(5, owned_by_alist));
1485       if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1486          goto bail_out;
1487       }
1488       /* Possibly ask for confirmation */
1489       if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1490          char nbuf[1000];
1491          foreach_alist(item, selected) {
1492             ua->send_msg("%s\n", item);
1493          }
1494          bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1495                    reason, selected->size(), selected->size()>1?"s":"");
1496          if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1497             goto bail_out;
1498          }
1499       }
1500
1501       foreach_alist(item, selected) {
1502          if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1503             ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1504             continue;
1505          }
1506          jcr = get_jcr_by_full_name(JobName);
1507          if (jcr) {
1508             jcrs->append(jcr);
1509          } else {
1510             ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1511          }
1512       }
1513    }
1514 bail_out:
1515    if (selected) delete selected;
1516    return jcrs->size();
1517 }
1518
1519 /* Small helper to scan storage daemon commands and search for volumes */
1520 int scan_storage_cmd(UAContext *ua, const char *cmd,
1521                      bool allfrompool,    /* Choose to select a specific volume or not */
1522                      int *drive,          /* Drive number */
1523                      MEDIA_DBR *mr,       /* Media Record, can have options already filled */
1524                      POOL_DBR  *pr,       /* Pool Record */
1525                      const char **action, /* action= argument, can be NULL if not relevant */
1526                      char *storage,       /* Storage name, must be MAX_NAME_LENGTH long */
1527                      int  *nb,            /* Number of media found */
1528                      uint32_t **results)  /* List of MediaId */
1529 {
1530    bool allpools=false, has_vol = false;;
1531    STORE *store;
1532
1533    *nb      = 0;
1534    *drive   = 0;
1535    *results = NULL;
1536    *storage = 0;
1537
1538    /* Look at arguments */
1539    for (int i=1; i<ua->argc; i++) {
1540       if (strcasecmp(ua->argk[i], NT_("allpools")) == 0) {
1541          allpools = true;
1542
1543       } else if (strcasecmp(ua->argk[i], NT_("allfrompool")) == 0) {
1544          allfrompool = true;
1545
1546       } else if (strcasecmp(ua->argk[i], NT_("volume")) == 0
1547                  && is_name_valid(ua->argv[i], NULL)) {
1548          bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
1549          has_vol = true;
1550
1551       } else if (strcasecmp(ua->argk[i], NT_("mediatype")) == 0
1552                  && ua->argv[i]) {
1553          bstrncpy(mr->MediaType, ua->argv[i], sizeof(mr->MediaType));
1554
1555       } else if (strcasecmp(ua->argk[i], NT_("drive")) == 0 && ua->argv[i]) {
1556          *drive = atoi(ua->argv[i]);
1557
1558       } else if (strcasecmp(ua->argk[i], NT_("action")) == 0
1559                  && is_name_valid(ua->argv[i], NULL)) {
1560
1561          if (action) {
1562             *action = ua->argv[i];
1563          } else {
1564             ua->warning_msg(_("Invalid argument \"action\".\n"));
1565          }
1566       }
1567    }
1568
1569    /* Choose storage */
1570    ua->jcr->wstore = store =  get_storage_resource(ua, false);
1571    if (!store) {
1572       goto bail_out;
1573    }
1574    bstrncpy(storage, store->dev_name(), MAX_NAME_LENGTH);
1575
1576    if (!open_db(ua)) {
1577       Dmsg0(100, "Can't open db\n");
1578       goto bail_out;
1579    }
1580
1581    /*
1582     * Look for all volumes that are enabled 
1583     */
1584    mr->Enabled = 1;
1585    set_storageid_in_mr(store, mr);
1586
1587    if (allfrompool && !has_vol) { /* We need a list of volumes */
1588
1589       /* We don't take all pools and we don't have a volume in argument,
1590        * so we need to choose a pool 
1591        */
1592       if (!allpools) {
1593          /* force pool selection */
1594          POOL *pool = get_pool_resource(ua);
1595
1596          if (!pool) {
1597             Dmsg0(100, "Can't get pool resource\n");
1598             goto bail_out;
1599          }
1600          bstrncpy(pr->Name, pool->name(), sizeof(pr->Name));
1601          if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
1602             Dmsg0(100, "Can't get pool record\n");
1603             goto bail_out;
1604          }
1605          mr->PoolId = pr->PoolId;
1606       }
1607
1608       if (!db_get_media_ids(ua->jcr, ua->db, mr, nb, results)) {
1609          Dmsg0(100, "No results from db_get_media_ids\n");
1610          goto bail_out;
1611       }
1612
1613    } else {                     /* We want a single volume */
1614       MEDIA_DBR mr2;
1615       if (!select_media_dbr(ua, &mr2)) {
1616          goto bail_out;
1617       }
1618       /* The select_media_dbr() doesn't filter on the CacheRetention */
1619       if (mr->CacheRetention) {
1620          if ((mr2.CacheRetention + mr2.LastWritten) > time(NULL)) {
1621             /* The volume cache retention is not exipred */
1622             goto bail_out;
1623          }
1624       }
1625       *nb = 1;
1626       *results = (uint32_t *) malloc(1 * sizeof(uint32_t));
1627       *results[0] = mr2.MediaId;
1628    }
1629
1630    if (*nb == 0) {
1631       goto bail_out;
1632    }
1633    return 1;
1634
1635 bail_out:
1636    if (!*nb) {
1637       ua->send_msg(_("No Volumes found to perform the command.\n"));
1638    }
1639
1640    close_db(ua);
1641    ua->jcr->wstore = NULL;
1642    if (*results) {
1643       free(*results);
1644       *results = NULL;
1645    }
1646    *nb = 0;
1647    return 0;
1648 }