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