]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_select.c
Check if volume name is valid in select_media_dbr()
[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 prompt list
298  */
299 JOB *select_restore_job_resource(UAContext *ua)
300 {
301    char name[MAX_NAME_LENGTH];
302    JOB *job;
303
304    start_prompt(ua, _("The defined Restore Job resources are:\n"));
305    LockRes();
306    foreach_res(job, R_JOB) {
307       if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
308          add_prompt(ua, job->name());
309       }
310    }
311    UnlockRes();
312    if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
313       return NULL;
314    }
315    job = (JOB *)GetResWithName(R_JOB, name);
316    return job;
317 }
318
319
320
321 /*
322  * Select a client resource from prompt list
323  */
324 CLIENT *select_client_resource(UAContext *ua)
325 {
326    char name[MAX_NAME_LENGTH];
327    CLIENT *client;
328
329    start_prompt(ua, _("The defined Client resources are:\n"));
330    LockRes();
331    foreach_res(client, R_CLIENT) {
332       if (acl_access_ok(ua, Client_ACL, client->name())) {
333          add_prompt(ua, client->name());
334       }
335    }
336    UnlockRes();
337    if (do_prompt(ua, _("Client"),  _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
338       return NULL;
339    }
340    client = (CLIENT *)GetResWithName(R_CLIENT, name);
341    return client;
342 }
343
344 /*
345  *  Get client resource, start by looking for
346  *   client=<client-name>
347  *  if we don't find the keyword, we prompt the user.
348  */
349 CLIENT *get_client_resource(UAContext *ua)
350 {
351    CLIENT *client = NULL;
352    int i;
353
354    for (i=1; i<ua->argc; i++) {
355       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
356            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
357          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
358             break;
359          }
360          client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
361          if (client) {
362             return client;
363          }
364          ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
365          break;
366       }
367    }
368    return select_client_resource(ua);
369 }
370
371 /* Scan what the user has entered looking for:
372  *
373  *  client=<client-name>
374  *
375  *  if error or not found, put up a list of client DBRs
376  *  to choose from.
377  *
378  *   returns: 0 on error
379  *            1 on success and fills in CLIENT_DBR
380  */
381 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
382 {
383    int i;
384
385    if (cr->Name[0]) {                 /* If name already supplied */
386       if (db_get_client_record(ua->jcr, ua->db, cr)) {
387          return 1;
388       }
389       ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
390    }
391    for (i=1; i<ua->argc; i++) {
392       if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
393            strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
394          if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
395             break;
396          }
397          bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
398          if (!db_get_client_record(ua->jcr, ua->db, cr)) {
399             ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
400                      db_strerror(ua->db));
401             cr->ClientId = 0;
402             break;
403          }
404          return 1;
405       }
406    }
407    if (!select_client_dbr(ua, cr)) {  /* try once more by proposing a list */
408       return 0;
409    }
410    return 1;
411 }
412
413 /*
414  * Select a Client record from the catalog
415  *  Returns 1 on success
416  *          0 on failure
417  */
418 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
419 {
420    CLIENT_DBR ocr;
421    char name[MAX_NAME_LENGTH];
422    int num_clients, i;
423    uint32_t *ids;
424
425
426    cr->ClientId = 0;
427    if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
428       ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
429       return 0;
430    }
431    if (num_clients <= 0) {
432       ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
433       return 0;
434    }
435
436    start_prompt(ua, _("Defined Clients:\n"));
437    for (i=0; i < num_clients; i++) {
438       ocr.ClientId = ids[i];
439       if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
440           !acl_access_ok(ua, Client_ACL, ocr.Name)) {
441          continue;
442       }
443       add_prompt(ua, ocr.Name);
444    }
445    free(ids);
446    if (do_prompt(ua, _("Client"),  _("Select the Client"), name, sizeof(name)) < 0) {
447       return 0;
448    }
449    memset(&ocr, 0, sizeof(ocr));
450    bstrncpy(ocr.Name, name, sizeof(ocr.Name));
451
452    if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
453       ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
454       return 0;
455    }
456    memcpy(cr, &ocr, sizeof(ocr));
457    return 1;
458 }
459
460 /* Scan what the user has entered looking for:
461  *
462  *  argk=<pool-name>
463  *
464  *  where argk can be : pool, recyclepool, scratchpool, nextpool etc..
465  *
466  *  if error or not found, put up a list of pool DBRs
467  *  to choose from.
468  *
469  *   returns: false on error
470  *            true  on success and fills in POOL_DBR
471  */
472 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
473 {
474    if (pr->Name[0]) {                 /* If name already supplied */
475       if (db_get_pool_record(ua->jcr, ua->db, pr) &&
476           acl_access_ok(ua, Pool_ACL, pr->Name)) {
477          return true;
478       }
479       ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
480    }
481    if (!select_pool_dbr(ua, pr, argk)) {  /* try once more */
482       return false;
483    }
484    return true;
485 }
486
487 /*
488  * Select a Pool record from catalog
489  * argk can be pool, recyclepool, scratchpool etc..
490  */
491 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
492 {
493    POOL_DBR opr;
494    char name[MAX_NAME_LENGTH];
495    int num_pools, i;
496    uint32_t *ids;
497
498    for (i=1; i<ua->argc; i++) {
499       if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
500           acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
501          bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
502          if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
503             ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
504                      db_strerror(ua->db));
505             pr->PoolId = 0;
506             break;
507          }
508          return true;
509       }
510    }
511
512    pr->PoolId = 0;
513    if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
514       ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
515       return 0;
516    }
517    if (num_pools <= 0) {
518       ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
519       return false;
520    }
521
522    start_prompt(ua, _("Defined Pools:\n"));
523    if (bstrcmp(argk, NT_("recyclepool"))) {
524       add_prompt(ua, _("*None*"));
525    }
526    for (i=0; i < num_pools; i++) {
527       opr.PoolId = ids[i];
528       if (!db_get_pool_record(ua->jcr, ua->db, &opr) ||
529           !acl_access_ok(ua, Pool_ACL, opr.Name)) {
530          continue;
531       }
532       add_prompt(ua, opr.Name);
533    }
534    free(ids);
535    if (do_prompt(ua, _("Pool"),  _("Select the Pool"), name, sizeof(name)) < 0) {
536       return false;
537    }
538
539    memset(&opr, 0, sizeof(opr));
540    /* *None* is only returned when selecting a recyclepool, and in that case
541     * the calling code is only interested in opr.Name, so then we can leave
542     * pr as all zero.
543     */
544    if (!bstrcmp(name, _("*None*"))) {
545      bstrncpy(opr.Name, name, sizeof(opr.Name));
546
547      if (!db_get_pool_record(ua->jcr, ua->db, &opr)) {
548         ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
549         return false;
550      }
551    }
552
553    memcpy(pr, &opr, sizeof(opr));
554    return true;
555 }
556
557 /*
558  * Select a Pool and a Media (Volume) record from the database
559  */
560 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
561 {
562
563    if (!select_media_dbr(ua, mr)) {
564       return 0;
565    }
566    memset(pr, 0, sizeof(POOL_DBR));
567    pr->PoolId = mr->PoolId;
568    if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
569       ua->error_msg("%s", db_strerror(ua->db));
570       return 0;
571    }
572    if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
573       ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
574       return 0;
575    }
576    return 1;
577 }
578
579 /* Select a Media (Volume) record from the database */
580 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
581 {
582    int i;
583
584    int ret = 0;
585    POOLMEM *err = get_pool_memory(PM_FNAME);
586    memset(mr, 0, sizeof(MEDIA_DBR));
587
588    i = find_arg_with_value(ua, "volume");
589    if (i >= 0) {
590       if (is_name_valid(ua->argv[i], &err)) {
591          bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
592       } else {
593          goto bail_out;
594       }
595    }
596    if (mr->VolumeName[0] == 0) {
597       POOL_DBR pr;
598       memset(&pr, 0, sizeof(pr));
599       /* Get the pool from pool=<pool-name> */
600       if (!get_pool_dbr(ua, &pr)) {
601          goto bail_out;
602       }
603       mr->PoolId = pr.PoolId;
604       db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
605       if (!get_cmd(ua, _("Enter *MediaId or Volume name: "))) {
606          goto bail_out;
607       }
608       if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
609          mr->MediaId = str_to_int64(ua->cmd+1);
610       } else if (is_name_valid(ua->cmd, &err)) {
611          bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
612       } else {
613          goto bail_out;
614       }
615    }
616
617    if (!db_get_media_record(ua->jcr, ua->db, mr)) {
618       pm_strcpy(err, db_strerror(ua->db));
619       goto bail_out;
620    }
621    ret = 1;
622
623 bail_out:
624    if (*err) {
625       ua->error_msg("%s", err);
626    }
627    free_pool_memory(err);
628    return ret;
629 }
630
631
632 /*
633  * Select a pool resource from prompt list
634  */
635 POOL *select_pool_resource(UAContext *ua)
636 {
637    char name[MAX_NAME_LENGTH];
638    POOL *pool;
639
640    start_prompt(ua, _("The defined Pool resources are:\n"));
641    LockRes();
642    foreach_res(pool, R_POOL) {
643       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
644          add_prompt(ua, pool->name());
645       }
646    }
647    UnlockRes();
648    if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
649       return NULL;
650    }
651    pool = (POOL *)GetResWithName(R_POOL, name);
652    return pool;
653 }
654
655
656 /*
657  *  If you are thinking about using it, you
658  *  probably want to use select_pool_dbr()
659  *  or get_pool_dbr() above.
660  */
661 POOL *get_pool_resource(UAContext *ua)
662 {
663    POOL *pool = NULL;
664    int i;
665
666    i = find_arg_with_value(ua, "pool");
667    if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
668       pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
669       if (pool) {
670          return pool;
671       }
672       ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
673    }
674    return select_pool_resource(ua);
675 }
676
677 /*
678  * List all jobs and ask user to select one
679  */
680 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
681 {
682    db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
683    if (!get_pint(ua, _("Enter the JobId to select: "))) {
684       return 0;
685    }
686    jr->JobId = ua->int64_val;
687    if (!db_get_job_record(ua->jcr, ua->db, jr)) {
688       ua->error_msg("%s", db_strerror(ua->db));
689       return 0;
690    }
691    return jr->JobId;
692
693 }
694
695
696 /* Scan what the user has entered looking for:
697  *
698  *  jobid=nn
699  *
700  *  if error or not found, put up a list of Jobs
701  *  to choose from.
702  *
703  *   returns: 0 on error
704  *            JobId on success and fills in JOB_DBR
705  */
706 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
707 {
708    int i;
709
710    for (i=1; i<ua->argc; i++) {
711       if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
712          jr->JobId = 0;
713          bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
714       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
715          jr->JobId = str_to_int64(ua->argv[i]);
716          jr->Job[0] = 0;
717       } else {
718          continue;
719       }
720       if (!db_get_job_record(ua->jcr, ua->db, jr)) {
721          ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
722                   db_strerror(ua->db));
723          jr->JobId = 0;
724          break;
725       }
726       return jr->JobId;
727    }
728
729    jr->JobId = 0;
730    jr->Job[0] = 0;
731
732    for (i=1; i<ua->argc; i++) {
733       if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
734            strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
735          jr->JobId = 0;
736          bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
737          break;
738       }
739    }
740    if (!select_job_dbr(ua, jr)) {  /* try once more */
741       return 0;
742    }
743    return jr->JobId;
744 }
745
746 /*
747  * Implement unique set of prompts
748  */
749 void start_prompt(UAContext *ua, const char *msg)
750 {
751   if (ua->max_prompts == 0) {
752      ua->max_prompts = 10;
753      ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
754   }
755   ua->num_prompts = 1;
756   ua->prompt[0] = bstrdup(msg);
757 }
758
759 /*
760  * Add to prompts -- keeping them unique
761  */
762 void add_prompt(UAContext *ua, const char *prompt)
763 {
764    int i;
765    if (ua->num_prompts == ua->max_prompts) {
766       ua->max_prompts *= 2;
767       ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
768          ua->max_prompts);
769     }
770     for (i=1; i < ua->num_prompts; i++) {
771        if (strcmp(ua->prompt[i], prompt) == 0) {
772           return;
773        }
774     }
775     ua->prompt[ua->num_prompts++] = bstrdup(prompt);
776 }
777
778 /*
779  * Display prompts and get user's choice
780  *
781  *  Returns: -1 on error
782  *            index base 0 on success, and choice
783  *               is copied to prompt if not NULL
784  *             prompt is set to the chosen prompt item string
785  */
786 int do_prompt(UAContext *ua, const char *automsg, const char *msg, 
787               char *prompt, int max_prompt)
788 {
789    int i, item;
790    char pmsg[MAXSTRING];
791    BSOCK *user = ua->UA_sock;
792
793    if (prompt) {
794       *prompt = 0;
795    }
796    if (ua->num_prompts == 2) {
797       item = 1;
798       if (prompt) {
799          bstrncpy(prompt, ua->prompt[1], max_prompt);
800       }
801       ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
802       goto done;
803    }
804    /* If running non-interactive, bail out */
805    if (ua->batch) {
806       /* First print the choices he wanted to make */
807       ua->send_msg(ua->prompt[0]);
808       for (i=1; i < ua->num_prompts; i++) {
809          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
810       }
811       /* Now print error message */
812       ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
813       item = -1;
814       goto done;
815    }
816    if (ua->api) user->signal(BNET_START_SELECT);
817    ua->send_msg(ua->prompt[0]);
818    for (i=1; i < ua->num_prompts; i++) {
819       if (ua->api) {
820          ua->send_msg("%s", ua->prompt[i]);
821       } else {
822          ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
823       }
824    }
825    if (ua->api) user->signal(BNET_END_SELECT);
826
827    for ( ;; ) {
828       /* First item is the prompt string, not the items */
829       if (ua->num_prompts == 1) {
830          ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
831          item = -1;                    /* list is empty ! */
832          break;
833       }
834       if (ua->num_prompts == 2) {
835          item = 1;
836          ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
837          if (prompt) {
838             bstrncpy(prompt, ua->prompt[1], max_prompt);
839          }
840          break;
841       } else {
842          sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
843       }
844       /* Either a . or an @ will get you out of the loop */
845       if (ua->api) user->signal(BNET_SELECT_INPUT);
846       if (!get_pint(ua, pmsg)) {
847          item = -1;                   /* error */
848          ua->info_msg(_("Selection aborted, nothing done.\n"));
849          break;
850       }
851       item = ua->pint32_val;
852       if (item < 1 || item >= ua->num_prompts) {
853          ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
854          continue;
855       }
856       if (prompt) {
857          bstrncpy(prompt, ua->prompt[item], max_prompt);
858       }
859       break;
860    }
861
862 done:
863    for (i=0; i < ua->num_prompts; i++) {
864       free(ua->prompt[i]);
865    }
866    ua->num_prompts = 0;
867    return item>0 ? item-1 : item;
868 }
869
870
871 /*
872  * We scan what the user has entered looking for
873  *    storage=<storage-resource>
874  *    job=<job_name>
875  *    jobid=<jobid>
876  *    ?              (prompt him with storage list)
877  *    <some-error>   (prompt him with storage list)
878  *
879  * If use_default is set, we assume that any keyword without a value
880  *   is the name of the Storage resource wanted.
881  */
882 STORE *get_storage_resource(UAContext *ua, bool use_default)
883 {
884    char *store_name = NULL;
885    STORE *store = NULL;
886    int jobid;
887    JCR *jcr;
888    int i;
889    char ed1[50];
890
891    for (i=1; i<ua->argc; i++) {
892       if (use_default && !ua->argv[i]) {
893          /* Ignore slots, scan and barcode(s) keywords */
894          if (strcasecmp("scan", ua->argk[i]) == 0 ||
895              strcasecmp("barcode", ua->argk[i]) == 0 ||
896              strcasecmp("barcodes", ua->argk[i]) == 0 ||
897              strcasecmp("slots", ua->argk[i]) == 0) {
898             continue;
899          }
900          /* Default argument is storage */
901          if (store_name) {
902             ua->error_msg(_("Storage name given twice.\n"));
903             return NULL;
904          }
905          store_name = ua->argk[i];
906          if (*store_name == '?') {
907             *store_name = 0;
908             break;
909          }
910       } else {
911          if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
912              strcasecmp(ua->argk[i], NT_("sd")) == 0) {
913             store_name = ua->argv[i];
914             break;
915
916          } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
917             jobid = str_to_int64(ua->argv[i]);
918             if (jobid <= 0) {
919                ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
920                return NULL;
921             }
922             if (!(jcr=get_jcr_by_id(jobid))) {
923                ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
924                return NULL;
925             }
926             store = jcr->wstore;
927             free_jcr(jcr);
928             break;
929
930          } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
931                     strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
932             if (!ua->argv[i]) {
933                ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
934                return NULL;
935             }
936             if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
937                ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
938                return NULL;
939             }
940             store = jcr->wstore;
941             free_jcr(jcr);
942             break;
943          } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
944             if (!ua->argv[i]) {
945                ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
946                return NULL;
947             }
948             if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
949                ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
950                return NULL;
951             }
952             store = jcr->wstore;
953             free_jcr(jcr);
954             break;
955         }
956       }
957    }
958    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
959       store = NULL;
960    }
961
962    if (!store && store_name && store_name[0] != 0) {
963       store = (STORE *)GetResWithName(R_STORAGE, store_name);
964       if (!store) {
965          ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
966       }
967    }
968    if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
969       store = NULL;
970    }
971    /* No keywords found, so present a selection list */
972    if (!store) {
973       store = select_storage_resource(ua);
974    }
975    return store;
976 }
977
978 /* Get drive that we are working with for this storage */
979 int get_storage_drive(UAContext *ua, STORE *store)
980 {
981    int i, drive = -1;
982    /* Get drive for autochanger if possible */
983    i = find_arg_with_value(ua, "drive");
984    if (i >=0) {
985       drive = atoi(ua->argv[i]);
986    } else if (store && store->autochanger) {
987       /* If our structure is not set ask SD for # drives */
988       if (store->drives == 0) {
989          store->drives = get_num_drives_from_SD(ua);
990       }
991       /* If only one drive, default = 0 */
992       if (store->drives == 1) {
993          drive = 0;
994       } else {
995          /* Ask user to enter drive number */
996          ua->cmd[0] = 0;
997          if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
998             drive = -1;  /* None */
999          } else {
1000             drive = atoi(ua->cmd);
1001          }
1002      }
1003    }
1004    return drive;
1005 }
1006
1007 /* Get slot that we are working with for this storage */
1008 int get_storage_slot(UAContext *ua, STORE *store)
1009 {
1010    int i, slot = -1;
1011    /* Get slot for autochanger if possible */
1012    i = find_arg_with_value(ua, "slot");
1013    if (i >=0) {
1014       slot = atoi(ua->argv[i]);
1015    } else if (store && store->autochanger) {
1016       /* Ask user to enter slot number */
1017       ua->cmd[0] = 0;
1018       if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1019          slot = -1;  /* None */
1020       } else {
1021          slot = atoi(ua->cmd);
1022       }
1023    }
1024    return slot;
1025 }
1026
1027
1028
1029 /*
1030  * Scan looking for mediatype=
1031  *
1032  *  if not found or error, put up selection list
1033  *
1034  *  Returns: 0 on error
1035  *           1 on success, MediaType is set
1036  */
1037 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1038 {
1039    STORE *store;
1040    int i;
1041
1042    i = find_arg_with_value(ua, "mediatype");
1043    if (i >= 0) {
1044       bstrncpy(MediaType, ua->argv[i], max_media);
1045       return 1;
1046    }
1047
1048    start_prompt(ua, _("Media Types defined in conf file:\n"));
1049    LockRes();
1050    foreach_res(store, R_STORAGE) {
1051       add_prompt(ua, store->media_type);
1052    }
1053    UnlockRes();
1054    return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1055 }
1056
1057 bool get_level_from_name(JCR *jcr, const char *level_name)
1058 {
1059    /* Look up level name and pull code */
1060    bool found = false;
1061    for (int i=0; joblevels[i].level_name; i++) {
1062       if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1063          jcr->set_JobLevel(joblevels[i].level);
1064          found = true;
1065          break;
1066       }
1067    }
1068    return found;
1069 }