]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
More debug info when aborting
[bacula/bacula] / bacula / src / dird / ua_select.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 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    char name[MAX_NAME_LENGTH];
174    STORE *store;
175
176    /* Does user want a full selection? */
177    if (unique && find_arg(ua, NT_("select")) > 0) {
178       unique = false;
179    }
180    start_prompt(ua, _("The defined Storage resources are:\n"));
181    LockRes();
182    foreach_res(store, R_STORAGE) {
183       if (acl_access_ok(ua, Storage_ACL, store->name())) {
184          if (unique) {
185             add_prompt(ua, store->name(), store->address);
186          } else {
187             add_prompt(ua, store->name());
188          }
189       }
190    }
191    UnlockRes();
192    if (do_prompt(ua, _("Storage"),  _("Select Storage resource"), name, sizeof(name)) < 0) {
193       return NULL;
194    }
195    store = (STORE *)GetResWithName(R_STORAGE, name);
196    return store;
197 }
198
199 /*
200  * Select a FileSet resource from prompt list
201  */
202 FILESET *select_fileset_resource(UAContext *ua)
203 {
204    char name[MAX_NAME_LENGTH];
205    FILESET *fs;
206
207    start_prompt(ua, _("The defined FileSet resources are:\n"));
208    LockRes();
209    foreach_res(fs, R_FILESET) {
210       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
211          add_prompt(ua, fs->name());
212       }
213    }
214    UnlockRes();
215    if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
216       return NULL;
217    }
218    fs = (FILESET *)GetResWithName(R_FILESET, name);
219    return fs;
220 }
221
222
223 /*
224  * Get a catalog resource from prompt list
225  */
226 CAT *get_catalog_resource(UAContext *ua)
227 {
228    char name[MAX_NAME_LENGTH];
229    CAT *catalog = NULL;
230    CLIENT *client = NULL;
231    int i;
232
233    for (i=1; i<ua->argc; i++) {
234       if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
235          if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
236             catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
237             break;
238          }
239       }
240       if (strcasecmp(ua->argk[i], NT_("client")) == 0 && ua->argv[i]) {
241          if (acl_access_ok(ua, Client_ACL, ua->argv[i])) {
242             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
243             break;
244          }
245       }
246    }
247    if (!catalog && client) {    /* Try to take the catalog from the client */
248       catalog = client->catalog;
249    }
250    if (ua->gui && !catalog) {
251       LockRes();
252       catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
253       UnlockRes();
254       if (!catalog) {
255          ua->error_msg(_("Could not find a Catalog resource\n"));
256          return NULL;
257       } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
258          ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
259          return NULL;
260       }
261       return catalog;
262    }
263    if (!catalog) {
264       start_prompt(ua, _("The defined Catalog resources are:\n"));
265       LockRes();
266       foreach_res(catalog, R_CATALOG) {
267          if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
268             add_prompt(ua, catalog->name());
269          }
270       }
271       UnlockRes();
272       if (do_prompt(ua, _("Catalog"),  _("Select Catalog resource"), name, sizeof(name)) < 0) {
273          return NULL;
274       }
275       catalog = (CAT *)GetResWithName(R_CATALOG, name);
276    }
277    return catalog;
278 }
279
280
281 /*
282  * Select a job to enable or disable
283  */
284 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
285 {
286    char name[MAX_NAME_LENGTH];
287    JOB *job;
288
289    LockRes();
290    if (enable) {
291       start_prompt(ua, _("The disabled Job resources are:\n"));
292    } else {
293       start_prompt(ua, _("The enabled Job resources are:\n"));
294    }
295    foreach_res(job, R_JOB) {
296       if (!acl_access_ok(ua, Job_ACL, job->name())) {
297          continue;
298       }
299       if (job->enabled == enable) {   /* Already enabled/disabled? */
300          continue;                    /* yes, skip */
301       }
302       add_prompt(ua, job->name());
303    }
304    UnlockRes();
305    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
306       return NULL;
307    }
308    job = (JOB *)GetResWithName(R_JOB, name);
309    return job;
310 }
311
312 /*
313  * Select a Job resource from prompt list
314  */
315 JOB *select_job_resource(UAContext *ua)
316 {
317    char name[MAX_NAME_LENGTH];
318    JOB *job;
319
320    start_prompt(ua, _("The defined Job resources are:\n"));
321    LockRes();
322    foreach_res(job, R_JOB) {
323       if (acl_access_ok(ua, Job_ACL, job->name())) {
324          add_prompt(ua, job->name());
325       }
326    }
327    UnlockRes();
328    if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
329       return NULL;
330    }
331    job = (JOB *)GetResWithName(R_JOB, name);
332    return job;
333 }
334
335 /*
336  * Select a Restore Job resource from argument or prompt
337  */
338 JOB *get_restore_job(UAContext *ua)
339 {
340    JOB *job;
341    int i = find_arg_with_value(ua, "restorejob");
342    if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
343       job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
344       if (job && job->JobType == JT_RESTORE) {
345          return job;
346       }
347       ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
348                     ua->argv[i]);
349    }
350    return select_restore_job_resource(ua);
351 }
352
353 /*
354  * Select a Restore Job resource from prompt list
355  */
356 JOB *select_restore_job_resource(UAContext *ua)
357 {
358    char name[MAX_NAME_LENGTH];
359    JOB *job;
360
361    start_prompt(ua, _("The defined Restore Job resources are:\n"));
362    LockRes();
363    foreach_res(job, R_JOB) {
364       if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
365          add_prompt(ua, job->name());
366       }
367    }
368    UnlockRes();
369    if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
370       return NULL;
371    }
372    job = (JOB *)GetResWithName(R_JOB, name);
373    return job;
374 }
375
376 /*
377  * Select a client to enable or disable
378  */
379 CLIENT *select_enable_disable_client_resource(UAContext *ua, bool enable)
380 {
381    char name[MAX_NAME_LENGTH];
382    CLIENT *client;
383
384    LockRes();
385    start_prompt(ua, _("The defined Client resources are:\n"));
386    foreach_res(client, R_CLIENT) {
387       if (!acl_access_ok(ua, Client_ACL, client->name())) {
388          continue;
389       }
390       if (client->enabled == enable) {   /* Already enabled/disabled? */
391          continue;                       /* yes, skip */
392       }
393       add_prompt(ua, client->name());
394    }
395    UnlockRes();
396    if (do_prompt(ua, _("Client"), _("Select Client resource"), name, sizeof(name)) < 0) {
397       return NULL;
398    }
399    client = (CLIENT *)GetResWithName(R_CLIENT, name);
400    return client;
401 }
402
403
404 /*
405  * Select a client resource from prompt list
406  */
407 CLIENT *select_client_resource(UAContext *ua)
408 {
409    char name[MAX_NAME_LENGTH];
410    CLIENT *client;
411
412    start_prompt(ua, _("The defined Client resources are:\n"));
413    LockRes();
414    foreach_res(client, R_CLIENT) {
415       if (acl_access_ok(ua, Client_ACL, client->name())) {
416          add_prompt(ua, client->name());
417       }
418    }
419    UnlockRes();
420    if (do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
421       return NULL;
422    }
423    client = (CLIENT *)GetResWithName(R_CLIENT, name);
424    return client;
425 }
426
427 /*
428  *  Get client resource, start by looking for
429  *   client=<client-name>
430  *  if we don't find the keyword, we prompt the user.
431  */
432 CLIENT *get_client_resource(UAContext *ua)
433 {
434    CLIENT *client = NULL;
435    int i;
436
437    for (i=1; i<ua->argc; i++) {
438       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
439            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
440          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
441             break;
442          }
443          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
444          if (client) {
445             return client;
446          }
447          ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
448          break;
449       }
450    }
451    return select_client_resource(ua);
452 }
453
454 /*
455  * Select a schedule to enable or disable
456  */
457 SCHED *select_enable_disable_schedule_resource(UAContext *ua, bool enable)
458 {
459    char name[MAX_NAME_LENGTH];
460    SCHED *sched;
461
462    LockRes();
463    start_prompt(ua, _("The defined Schedule resources are:\n"));
464    foreach_res(sched, R_SCHEDULE) {
465       if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
466          continue;
467       }
468       if (sched->enabled == enable) {   /* Already enabled/disabled? */
469          continue;                      /* yes, skip */
470       }
471       add_prompt(ua, sched->name());
472    }
473    UnlockRes();
474    if (do_prompt(ua, _("Schedule"), _("Select Schedule resource"), name, sizeof(name)) < 0) {
475       return NULL;
476    }
477    sched = (SCHED *)GetResWithName(R_SCHEDULE, name);
478    return sched;
479 }
480
481
482 /* Scan what the user has entered looking for:
483  *
484  *  client=<client-name>
485  *
486  *  if error or not found, put up a list of client DBRs
487  *  to choose from.
488  *
489  *   returns: 0 on error
490  *            1 on success and fills in CLIENT_DBR
491  */
492 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
493 {
494    int i;
495
496    if (cr->Name[0]) {                 /* If name already supplied */
497       if (db_get_client_record(ua->jcr, ua->db, cr)) {
498          return 1;
499       }
500       ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
501    }
502    for (i=1; i<ua->argc; i++) {
503       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
504            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
505          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
506             break;
507          }
508          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
509          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
510             ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
511                      db_strerror(ua->db));
512             cr->ClientId = 0;
513             break;
514          }
515          return 1;
516       }
517    }
518    if (!select_client_dbr(ua, cr)) {  /* try once more by proposing a list */
519       return 0;
520    }
521    return 1;
522 }
523
524 /*
525  * Select a Client record from the catalog
526  *  Returns 1 on success
527  *          0 on failure
528  */
529 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
530 {
531    CLIENT_DBR ocr;
532    char name[MAX_NAME_LENGTH];
533    int num_clients, i;
534    uint32_t *ids;
535
536
537    cr->ClientId = 0;
538    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
539       ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
540       return 0;
541    }
542    if (num_clients <= 0) {
543       ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
544       return 0;
545    }
546
547    start_prompt(ua, _("Defined Clients:\n"));
548    for (i=0; i < num_clients; i++) {
549       ocr.ClientId = ids[i];
550       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
551           !acl_access_ok(ua, Client_ACL, ocr.Name)) {
552          continue;
553       }
554       add_prompt(ua, ocr.Name);
555    }
556    free(ids);
557    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
558       return 0;
559    }
560    memset(&ocr, 0, sizeof(ocr));
561    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
562
563    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
564       ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
565       return 0;
566    }
567    memcpy(cr, &ocr, sizeof(ocr));
568    return 1;
569 }
570
571 /* Scan what the user has entered looking for:
572  *
573  *  argk=<pool-name>
574  *
575  *  where argk can be : pool, recyclepool, scratchpool, nextpool etc..
576  *
577  *  if error or not found, put up a list of pool DBRs
578  *  to choose from.
579  *
580  *   returns: false on error
581  *            true  on success and fills in POOL_DBR
582  */
583 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
584 {
585    if (pr->Name[0]) {                 /* If name already supplied */
586       if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
587           acl_access_ok(ua, Pool_ACL, pr->Name)) {
588          return true;
589       }
590       ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
591    }
592    if (!select_pool_dbr(ua, pr, argk)) {  /* try once more */
593       return false;
594    }
595    return true;
596 }
597
598 /*
599  * Select a Pool record from catalog
600  * argk can be pool, recyclepool, scratchpool etc..
601  */
602 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
603 {
604    POOL_DBR opr;
605    char name[MAX_NAME_LENGTH];
606    int num_pools, i;
607    uint32_t *ids;
608
609    for (i=1; i<ua->argc; i++) {
610       if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
611           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
612          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
613          if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
614             ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
615                      db_strerror(ua->db));
616             pr->PoolId = 0;
617             break;
618          }
619          return true;
620       }
621    }
622
623    pr->PoolId = 0;
624    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
625       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
626       return 0;
627    }
628    if (num_pools <= 0) {
629       ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
630       return false;
631    }
632
633    start_prompt(ua, _("Defined Pools:\n"));
634    if (bstrcmp(argk, NT_("recyclepool"))) {
635       add_prompt(ua, _("*None*"));
636    }
637    for (i=0; i < num_pools; i++) {
638       opr.PoolId = ids[i];
639       if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
640           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
641          continue;
642       }
643       add_prompt(ua, opr.Name);
644    }
645    free(ids);
646    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
647       return false;
648    }
649
650    memset(&opr, 0, sizeof(opr));
651    /* *None* is only returned when selecting a recyclepool, and in that case
652     * the calling code is only interested in opr.Name, so then we can leave
653     * pr as all zero.
654     */
655    if (!bstrcmp(name, _("*None*"))) {
656      bstrncpy(opr.Name, name, sizeof(opr.Name));
657
658      if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
659         ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
660         return false;
661      }
662    }
663
664    memcpy(pr, &opr, sizeof(opr));
665    return true;
666 }
667
668 /*
669  * Select a Pool and a Media (Volume) record from the database
670  */
671 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
672 {
673
674    if (!select_media_dbr(ua, mr)) {
675       return 0;
676    }
677    memset(pr, 0, sizeof(POOL_DBR));
678    pr->PoolId = mr->PoolId;
679    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
680       ua->error_msg("%s", db_strerror(ua->db));
681       return 0;
682    }
683    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
684       ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
685       return 0;
686    }
687    return 1;
688 }
689
690 /* Select a Media (Volume) record from the database */
691 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
692 {
693    int i;
694    int ret = 0;
695    POOLMEM *err = get_pool_memory(PM_FNAME);
696    *err=0;
697
698    mr->clear();
699    i = find_arg_with_value(ua, "volume");
700    if (i >= 0) {
701       if (is_name_valid(ua->argv[i], &err)) {
702          bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
703       } else {
704          goto bail_out;
705       }
706    }
707    if (mr->VolumeName[0] == 0) {
708       POOL_DBR pr;
709       memset(&pr, 0, sizeof(pr));
710       /* Get the pool from pool=<pool-name> */
711       if (!get_pool_dbr(ua, &pr)) {
712          goto bail_out;
713       }
714       mr->PoolId = pr.PoolId;
715       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
716       if (!get_cmd(ua, _("Enter a Volume name or *MediaId: "))) {
717          goto bail_out;
718       }
719       if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
720          mr->MediaId = str_to_int64(ua->cmd+1);
721       } else if (is_name_valid(ua->cmd, &err)) {
722          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
723       } else {
724          goto bail_out;
725       }
726    }
727
728    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
729       pm_strcpy(err, db_strerror(ua->db));
730       goto bail_out;
731    }
732    ret = 1;
733
734 bail_out:
735    if (!ret && *err) {
736       ua->error_msg("%s", err);
737    }
738    free_pool_memory(err);
739    return ret;
740 }
741
742
743 /*
744  * Select a pool resource from prompt list
745  */
746 POOL *select_pool_resource(UAContext *ua)
747 {
748    char name[MAX_NAME_LENGTH];
749    POOL *pool;
750
751    start_prompt(ua, _("The defined Pool resources are:\n"));
752    LockRes();
753    foreach_res(pool, R_POOL) {
754       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
755          add_prompt(ua, pool->name());
756       }
757    }
758    UnlockRes();
759    if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
760       return NULL;
761    }
762    pool = (POOL *)GetResWithName(R_POOL, name);
763    return pool;
764 }
765
766
767 /*
768  *  If you are thinking about using it, you
769  *  probably want to use select_pool_dbr()
770  *  or get_pool_dbr() above.
771  */
772 POOL *get_pool_resource(UAContext *ua)
773 {
774    POOL *pool = NULL;
775    int i;
776
777    i = find_arg_with_value(ua, "pool");
778    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
779       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
780       if (pool) {
781          return pool;
782       }
783       ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
784    }
785    return select_pool_resource(ua);
786 }
787
788 /*
789  * List all jobs and ask user to select one
790  */
791 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
792 {
793    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
794    if (!get_pint(ua, _("Enter the JobId to select: "))) {
795       return 0;
796    }
797    jr->JobId = ua->int64_val;
798    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
799       ua->error_msg("%s", db_strerror(ua->db));
800       return 0;
801    }
802    return jr->JobId;
803
804 }
805
806
807 /* Scan what the user has entered looking for:
808  *
809  *  jobid=nn
810  *
811  *  if error or not found, put up a list of Jobs
812  *  to choose from.
813  *
814  *   returns: 0 on error
815  *            JobId on success and fills in JOB_DBR
816  */
817 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
818 {
819    int i;
820
821    for (i=1; i<ua->argc; i++) {
822       if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
823          jr->JobId = 0;
824          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
825       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
826          jr->JobId = str_to_int64(ua->argv[i]);
827          jr->Job[0] = 0;
828       } else {
829          continue;
830       }
831       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
832          ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
833                   db_strerror(ua->db));
834          jr->JobId = 0;
835          break;
836       }
837       return jr->JobId;
838    }
839
840    jr->JobId = 0;
841    jr->Job[0] = 0;
842
843    for (i=1; i<ua->argc; i++) {
844       if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
845            strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
846          jr->JobId = 0;
847          bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
848          break;
849       }
850    }
851    if (!select_job_dbr(ua, jr)) {  /* try once more */
852       return 0;
853    }
854    return jr->JobId;
855 }
856
857 /*
858  * Implement unique set of prompts
859  */
860 void start_prompt(UAContext *ua, const char *msg)
861 {
862   if (ua->max_prompts == 0) {
863      ua->max_prompts = 10;
864      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
865      ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
866   }
867   ua->num_prompts = 1;
868   ua->prompt[0] = bstrdup(msg);
869   ua->unique[0] = NULL;
870 }
871
872 /*
873  * Add to prompts -- keeping them unique by name
874  */
875 void add_prompt(UAContext *ua, const char *prompt, char *unique)
876 {
877    int i;
878    if (ua->num_prompts == ua->max_prompts) {
879       ua->max_prompts *= 2;
880       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
881          ua->max_prompts);
882       ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
883          ua->max_prompts);
884     }
885     for (i=1; i < ua->num_prompts; i++) {
886        if (strcmp(ua->prompt[i], prompt) == 0) {
887           return;
888        } else if (unique && strcmp(ua->unique[i], unique) == 0) {
889           return;
890        }
891     }
892     ua->prompt[ua->num_prompts] = bstrdup(prompt);
893     if (unique) {
894        ua->unique[ua->num_prompts++] = bstrdup(unique);
895     } else {
896        ua->unique[ua->num_prompts++] = NULL;
897     }
898 }
899
900 /*
901  * Display prompts and get user's choice
902  *
903  *  Returns: -1 on error
904  *            index base 0 on success, and choice
905  *               is copied to prompt if not NULL
906  *             prompt is set to the chosen prompt item string
907  */
908 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
909               char *prompt, int max_prompt)
910 {
911    int i, item;
912    char pmsg[MAXSTRING];
913    BSOCK *user = ua->UA_sock;
914
915    if (prompt) {
916       *prompt = 0;
917    }
918    if (ua->num_prompts == 2) {
919       item = 1;
920       if (prompt) {
921          bstrncpy(prompt, ua->prompt[1], max_prompt);
922       }
923       ua->send_msg(_("Automatically selected %s: %s\n"), NPRTB(automsg), ua->prompt[1]);
924       goto done;
925    }
926    /* If running non-interactive, bail out */
927    if (ua->batch) {
928       /* First print the choices he wanted to make */
929       ua->send_msg(ua->prompt[0]);
930       for (i=1; i < ua->num_prompts; i++) {
931          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
932       }
933       /* Now print error message */
934       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
935       item = -1;
936       goto done;
937    }
938    if (ua->api) user->signal(BNET_START_SELECT);
939    ua->send_msg(ua->prompt[0]);
940    for (i=1; i < ua->num_prompts; i++) {
941       if (ua->api) {
942          ua->send_msg("%s", ua->prompt[i]);
943       } else {
944          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
945       }
946    }
947    if (ua->api) user->signal(BNET_END_SELECT);
948
949    for ( ;; ) {
950       /* First item is the prompt string, not the items */
951       if (ua->num_prompts == 1) {
952          ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
953          item = -1;                    /* list is empty ! */
954          break;
955       }
956       if (ua->num_prompts == 2) {
957          item = 1;
958          ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
959          if (prompt) {
960             bstrncpy(prompt, ua->prompt[1], max_prompt);
961          }
962          break;
963       } else {
964          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
965       }
966       /* Either a . or an @ will get you out of the loop */
967       if (ua->api) user->signal(BNET_SELECT_INPUT);
968       if (!get_pint(ua, pmsg)) {
969          item = -1;                   /* error */
970          ua->info_msg(_("Selection aborted, nothing done.\n"));
971          break;
972       }
973       item = ua->pint32_val;
974       if (item < 1 || item >= ua->num_prompts) {
975          ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
976          continue;
977       }
978       if (prompt) {
979          bstrncpy(prompt, ua->prompt[item], max_prompt);
980       }
981       break;
982    }
983
984 done:
985    for (i=0; i < ua->num_prompts; i++) {
986       free(ua->prompt[i]);
987       if (ua->unique[i]) free(ua->unique[i]);
988    }
989    ua->num_prompts = 0;
990    return item>0 ? item-1 : item;
991 }
992
993 /*
994  * Display prompts and get user's choice
995  *
996  *  Returns: -1 on error
997  *            number of items selected and the choices are
998  *               copied to selected if not NULL
999  *            selected is an alist of the prompts chosen
1000  *              Note! selected must already be initialized.
1001  */
1002 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
1003               alist *selected)
1004 {
1005    int i, item;
1006    char pmsg[MAXSTRING];
1007    BSOCK *user = ua->UA_sock;
1008    sellist sl;
1009
1010    /* First item is the prompt string, not the items */
1011    if (ua->num_prompts == 1) {
1012       ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
1013       item = -1;                    /* list is empty ! */
1014       goto done;
1015    }
1016    if (ua->num_prompts == 2) {
1017       item = 1;
1018       selected->append(bstrdup(ua->prompt[1]));
1019       ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
1020       goto done;
1021    }
1022    /* If running non-interactive, bail out */
1023    if (ua->batch) {
1024       /* First print the choices he wanted to make */
1025       ua->send_msg(ua->prompt[0]);
1026       for (i=1; i < ua->num_prompts; i++) {
1027          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1028       }
1029       /* Now print error message */
1030       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
1031       item = -1;
1032       goto done;
1033    }
1034    if (ua->api) user->signal(BNET_START_SELECT);
1035    ua->send_msg(ua->prompt[0]);
1036    for (i=1; i < ua->num_prompts; i++) {
1037       if (ua->api) {
1038          ua->send_msg("%s", ua->prompt[i]);
1039       } else {
1040          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1041       }
1042    }
1043    if (ua->api) user->signal(BNET_END_SELECT);
1044
1045    sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
1046
1047    for ( ;; ) {
1048       bool ok = true;
1049       /* Either a . or an @ will get you out of the loop */
1050       if (ua->api) user->signal(BNET_SELECT_INPUT);
1051
1052       if (!get_selection_list(ua, sl, pmsg, false)) {
1053          item = -1;
1054          break;
1055       }
1056
1057       if (sl.is_all()) {
1058          for (i=1; i < ua->num_prompts; i++) {
1059             selected->append(bstrdup(ua->prompt[i]));
1060          }
1061       } else {
1062          while ( (item = sl.next()) > 0) {
1063             if (item < 1 || item >= ua->num_prompts) {
1064                ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
1065                ok = false;
1066                break;
1067             }
1068             selected->append(bstrdup(ua->prompt[item]));
1069          }
1070       }
1071       if (ok) {
1072          item = selected->size();
1073          break;
1074       }
1075    }
1076
1077 done:
1078    for (i=0; i < ua->num_prompts; i++) {
1079       free(ua->prompt[i]);
1080       if (ua->unique[i]) free(ua->unique[i]);
1081    }
1082    ua->num_prompts = 0;
1083    return item;
1084 }
1085
1086
1087 /*
1088  * We scan what the user has entered looking for
1089  *    storage=<storage-resource>
1090  *    job=<job_name>
1091  *    jobid=<jobid>
1092  *    ?              (prompt him with storage list)
1093  *    <some-error>   (prompt him with storage list)
1094  *
1095  * If use_default is set, we assume that any keyword without a value
1096  *   is the name of the Storage resource wanted.
1097  */
1098 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1099 {
1100    char *store_name = NULL;
1101    STORE *store = NULL;
1102    int jobid;
1103    JCR *jcr;
1104    int i;
1105    char ed1[50];
1106
1107    for (i=1; i<ua->argc; i++) {
1108       if (use_default && !ua->argv[i]) {
1109          /* Ignore slots, scan and barcode(s) keywords */
1110          if (strcasecmp("scan", ua->argk[i]) == 0 ||
1111              strcasecmp("barcode", ua->argk[i]) == 0 ||
1112              strcasecmp("barcodes", ua->argk[i]) == 0 ||
1113              strcasecmp("slots", ua->argk[i]) == 0) {
1114             continue;
1115          }
1116          /* Default argument is storage */
1117          if (store_name) {
1118             ua->error_msg(_("Storage name given twice.\n"));
1119             return NULL;
1120          }
1121          store_name = ua->argk[i];
1122          if (*store_name == '?') {
1123             *store_name = 0;
1124             break;
1125          }
1126       } else {
1127          if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1128              strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1129             store_name = ua->argv[i];
1130             break;
1131
1132          } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1133             jobid = str_to_int64(ua->argv[i]);
1134             if (jobid <= 0) {
1135                ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1136                return NULL;
1137             }
1138             if (!(jcr=get_jcr_by_id(jobid))) {
1139                ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1140                return NULL;
1141             }
1142             store = jcr->wstore;
1143             free_jcr(jcr);
1144             break;
1145
1146          } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1147                     strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1148             if (!ua->argv[i]) {
1149                ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1150                return NULL;
1151             }
1152             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1153                ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1154                return NULL;
1155             }
1156             store = jcr->wstore;
1157             free_jcr(jcr);
1158             break;
1159          } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1160             if (!ua->argv[i]) {
1161                ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1162                return NULL;
1163             }
1164             if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1165                store = jcr->wstore;
1166                free_jcr(jcr);
1167                /* The job might not be running, so we try to see other keywords */
1168                if (store) {
1169                   break;
1170                }
1171             }
1172          }
1173       }
1174    }
1175    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1176       store = NULL;
1177    }
1178
1179    if (!store && store_name && store_name[0] != 0) {
1180       store = (STORE *)GetResWithName(R_STORAGE, store_name);
1181       if (!store) {
1182          ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1183       }
1184    }
1185    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1186       store = NULL;
1187    }
1188    /* No keywords found, so present a selection list */
1189    if (!store) {
1190       store = select_storage_resource(ua, unique);
1191    }
1192    return store;
1193 }
1194
1195 /* Get drive that we are working with for this storage */
1196 int get_storage_drive(UAContext *ua, STORE *store)
1197 {
1198    int i, drive = -1;
1199    /* Get drive for autochanger if possible */
1200    i = find_arg_with_value(ua, "drive");
1201    if (i >=0) {
1202       drive = atoi(ua->argv[i]);
1203    } else if (store && store->autochanger) {
1204       /* If our structure is not set ask SD for # drives */
1205       if (store->drives == 0) {
1206          store->drives = get_num_drives_from_SD(ua);
1207       }
1208       /* If only one drive, default = 0 */
1209       if (store->drives == 1) {
1210          drive = 0;
1211       } else {
1212          /* Ask user to enter drive number */
1213          ua->cmd[0] = 0;
1214          if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1215             drive = -1;  /* None */
1216          } else {
1217             drive = atoi(ua->cmd);
1218          }
1219      }
1220    }
1221    return drive;
1222 }
1223
1224 /* Get slot that we are working with for this storage */
1225 int get_storage_slot(UAContext *ua, STORE *store)
1226 {
1227    int i, slot = -1;
1228    /* Get slot for autochanger if possible */
1229    i = find_arg_with_value(ua, "slot");
1230    if (i >=0) {
1231       slot = atoi(ua->argv[i]);
1232    } else if (store && store->autochanger) {
1233       /* Ask user to enter slot number */
1234       ua->cmd[0] = 0;
1235       if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1236          slot = -1;  /* None */
1237       } else {
1238          slot = atoi(ua->cmd);
1239       }
1240    }
1241    return slot;
1242 }
1243
1244
1245
1246 /*
1247  * Scan looking for mediatype=
1248  *
1249  *  if not found or error, put up selection list
1250  *
1251  *  Returns: 0 on error
1252  *           1 on success, MediaType is set
1253  */
1254 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1255 {
1256    STORE *store;
1257    int i;
1258
1259    i = find_arg_with_value(ua, "mediatype");
1260    if (i >= 0) {
1261       bstrncpy(MediaType, ua->argv[i], max_media);
1262       return 1;
1263    }
1264
1265    start_prompt(ua, _("Media Types defined in conf file:\n"));
1266    LockRes();
1267    foreach_res(store, R_STORAGE) {
1268       add_prompt(ua, store->media_type);
1269    }
1270    UnlockRes();
1271    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1272 }
1273
1274
1275 bool get_level_from_name(JCR *jcr, const char *level_name)
1276 {
1277    /* Look up level name and pull code */
1278    bool found = false;
1279    for (int i=0; joblevels[i].level_name; i++) {
1280       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1281          jcr->setJobLevel(joblevels[i].level);
1282          found = true;
1283          break;
1284       }
1285    }
1286    return found;
1287 }
1288
1289 static int count_running_jobs(UAContext *ua)
1290 {
1291    int tjobs = 0;                  /* total # number jobs */
1292    int njobs = 0;
1293    JCR *jcr;
1294    /* Count Jobs running */
1295    foreach_jcr(jcr) {
1296       if (jcr->JobId == 0) {      /* this is us */
1297          continue;
1298       }
1299       tjobs++;                    /* count of all jobs */
1300       if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1301          continue;               /* skip not authorized */
1302       }
1303       njobs++;                   /* count of authorized jobs */
1304    }
1305    endeach_jcr(jcr);
1306
1307    if (njobs == 0) {            /* no authorized */
1308       if (tjobs == 0) {
1309          ua->send_msg(_("No Jobs running.\n"));
1310       } else {
1311          ua->send_msg(_("None of your jobs are running.\n"));
1312       }
1313    }
1314    return njobs;
1315 }
1316
1317
1318 /* Get a list of running jobs
1319  * "reason" is used in user messages
1320  * can be: cancel, limit, ...
1321  *  Returns: -1 on error
1322  *           nb of JCR on success (should be free_jcr() after)
1323  */
1324 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1325 {
1326    int i;
1327    JCR *jcr = NULL;
1328    int njobs = 0;
1329    char JobName[MAX_NAME_LENGTH];
1330    char temp[256];
1331    alist *selected = NULL;
1332
1333    for (i=1; i<ua->argc; i++) {
1334       if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1335          sellist sl;
1336          int32_t JobId;
1337
1338          if (!ua->argv[i]) {
1339             ua->error_msg(_("No value given for \"jobid\".\n"));
1340             goto bail_out;
1341          }
1342          if (!sl.set_string(ua->argv[i], true)) {
1343             ua->send_msg("%s", sl.get_errmsg());
1344             goto bail_out;
1345          }
1346          foreach_sellist(JobId, &sl) {
1347             jcr = get_jcr_by_id(JobId);
1348             if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1349                jcrs->append(jcr);
1350             } else if (jcr) {
1351                ua->error_msg(_("Unauthorized command from this console "
1352                                "for JobId=%d.\n"), JobId);
1353                free_jcr(jcr);
1354             } else {
1355                ua->warning_msg(_("Warning Job JobId=%d is not running.\n"), JobId);
1356             }
1357          }
1358          if (jcrs->size() == 0) {
1359             goto bail_out;               /* If we did not find specified jobid, get out */
1360          }
1361          break;
1362
1363       /* TODO: might want to implement filters (client, status, etc...) */
1364       } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1365          foreach_jcr(jcr) {
1366             if (jcr->JobId == 0) {      /* Do not cancel consoles */
1367                continue;
1368             }
1369             if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1370                continue;               /* skip not authorized */
1371             }
1372             jcr->inc_use_count();
1373             jcrs->append(jcr);
1374          }
1375          endeach_jcr(jcr);
1376
1377          /* If we have something and no "yes" on command line, get confirmation */
1378          if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1379             char nbuf[1000];
1380             bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1381                       reason, jcrs->size(), jcrs->size()>1?"s":"");
1382             if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1383                goto bail_out;
1384             }
1385          }
1386          if (jcrs->size() == 0) {
1387             goto bail_out;               /* If we did not find specified jobid, get out */
1388          }
1389          break;
1390
1391       } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1392          if (!ua->argv[i]) {
1393             ua->error_msg(_("No value given for \"job\".\n"));
1394             goto bail_out;
1395          }
1396          jcr = get_jcr_by_partial_name(ua->argv[i]);
1397
1398          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1399             jcrs->append(jcr);
1400
1401          } else if (jcr) {
1402             if (jcr->job) {
1403                ua->error_msg(_("Unauthorized command from this console "
1404                                "for job=%s.\n"), ua->argv[i]);
1405             }
1406             free_jcr(jcr);
1407
1408          } else {
1409             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1410          }
1411          if (jcrs->size() == 0) {
1412             goto bail_out;               /* If we did not find specified jobid, get out */
1413          }
1414          break;
1415
1416       } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1417          if (!ua->argv[i]) {
1418             ua->error_msg(_("No value given for \"ujobid\".\n"));
1419             goto bail_out;
1420          }
1421          jcr = get_jcr_by_full_name(ua->argv[i]);
1422
1423          if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1424             jcrs->append(jcr);
1425
1426          } else if (jcr) {
1427             if (jcr->job) {
1428                ua->error_msg(_("Unauthorized command from this console "
1429                                "for ujobid=%s.\n"), ua->argv[i]);
1430             }
1431             free_jcr(jcr);
1432
1433          } else {
1434             ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1435          }
1436          if (jcrs->size() == 0) {
1437             goto bail_out;               /* If we did not find specified jobid, get out */
1438          }
1439          break;
1440       }
1441    }
1442
1443    if (jcrs->size() == 0) {
1444       /*
1445        * If we still do not have a jcr,
1446        *   throw up a list and ask the user to select one.
1447        */
1448       char *item;
1449       char buf[1000];
1450       njobs = count_running_jobs(ua);
1451       if (njobs == 0) {
1452          goto bail_out;
1453       }
1454       start_prompt(ua, _("Select Job(s):\n"));
1455       foreach_jcr(jcr) {
1456          char ed1[50];
1457          if (jcr->JobId == 0) {      /* this is us */
1458             continue;
1459          }
1460          bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1461          add_prompt(ua, buf);
1462       }
1463       endeach_jcr(jcr);
1464       bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1465       selected = New(alist(5, owned_by_alist));
1466       if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1467          goto bail_out;
1468       }
1469       /* Possibly ask for confirmation */
1470       if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1471          char nbuf[1000];
1472          foreach_alist(item, selected) {
1473             ua->send_msg("%s\n", item);
1474          }
1475          bsnprintf(nbuf, sizeof(nbuf),  _("Confirm %s of %d Job%s (yes/no): "),
1476                    reason, selected->size(), selected->size()>1?"s":"");
1477          if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1478             goto bail_out;
1479          }
1480       }
1481
1482       foreach_alist(item, selected) {
1483          if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1484             ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1485             continue;
1486          }
1487          jcr = get_jcr_by_full_name(JobName);
1488          if (jcr) {
1489             jcrs->append(jcr);
1490          } else {
1491             ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1492          }
1493       }
1494    }
1495 bail_out:
1496    if (selected) delete selected;
1497    return jcrs->size();
1498 }