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