2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2009 Free Software Foundation Europe e.V.
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
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.
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
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.
30 * Bacula Director -- User Agent Prompt and Selection code
32 * Kern Sibbald, October MMI
40 /* Imported variables */
41 extern struct s_jl joblevels[];
45 * Confirm a retention period
47 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
52 int yes_in_arg = find_arg(ua, NT_("yes"));
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) {
60 if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
63 if (strcasecmp(ua->cmd, _("mod")) == 0) {
64 if (!get_cmd(ua, _("Enter new retention period: "))) {
67 if (!duration_to_utime(ua->cmd, ret)) {
68 ua->error_msg(_("Invalid period.\n"));
73 if (is_yesno(ua->cmd, &val)) {
74 return val; /* is 1 for yes, 0 for no */
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
86 int find_arg_keyword(UAContext *ua, const char **list)
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) {
99 * Given one keyword, find the first one that
100 * is in the argument list.
101 * Returns: argk index (always gt 0)
104 int find_arg(UAContext *ua, const char *keyword)
106 for (int i=1; i<ua->argc; i++) {
107 if (strcasecmp(keyword, ua->argk[i]) == 0) {
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
120 int find_arg_with_value(UAContext *ua, const char *keyword)
122 for (int i=1; i<ua->argc; i++) {
123 if (strcasecmp(keyword, ua->argk[i]) == 0) {
135 * Given a list of keywords, prompt the user
138 * Returns: -1 on failure
139 * index into list (base 0) on success
141 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
144 start_prompt(ua, _("You have the following choices:\n"));
145 for (i=0; list[i]; i++) {
146 add_prompt(ua, list[i]);
148 return do_prompt(ua, "", msg, NULL, 0);
153 * Select a Storage resource from prompt list
155 STORE *select_storage_resource(UAContext *ua)
157 char name[MAX_NAME_LENGTH];
160 start_prompt(ua, _("The defined Storage resources are:\n"));
162 foreach_res(store, R_STORAGE) {
163 if (acl_access_ok(ua, Storage_ACL, store->name())) {
164 add_prompt(ua, store->name());
168 if (do_prompt(ua, _("Storage"), _("Select Storage resource"), name, sizeof(name)) < 0) {
171 store = (STORE *)GetResWithName(R_STORAGE, name);
176 * Select a FileSet resource from prompt list
178 FILESET *select_fileset_resource(UAContext *ua)
180 char name[MAX_NAME_LENGTH];
183 start_prompt(ua, _("The defined FileSet resources are:\n"));
185 foreach_res(fs, R_FILESET) {
186 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
187 add_prompt(ua, fs->name());
191 if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
194 fs = (FILESET *)GetResWithName(R_FILESET, name);
200 * Get a catalog resource from prompt list
202 CAT *get_catalog_resource(UAContext *ua)
204 char name[MAX_NAME_LENGTH];
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]);
216 if (ua->gui && !catalog) {
218 catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
221 ua->error_msg(_("Could not find a Catalog resource\n"));
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"));
230 start_prompt(ua, _("The defined Catalog resources are:\n"));
232 foreach_res(catalog, R_CATALOG) {
233 if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
234 add_prompt(ua, catalog->name());
238 if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) {
241 catalog = (CAT *)GetResWithName(R_CATALOG, name);
248 * Select a Job resource from prompt list
250 JOB *select_job_resource(UAContext *ua)
252 char name[MAX_NAME_LENGTH];
255 start_prompt(ua, _("The defined Job resources are:\n"));
257 foreach_res(job, R_JOB) {
258 if (acl_access_ok(ua, Job_ACL, job->name())) {
259 add_prompt(ua, job->name());
263 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
266 job = (JOB *)GetResWithName(R_JOB, name);
271 * Select a Restore Job resource from prompt list
273 JOB *select_restore_job_resource(UAContext *ua)
275 char name[MAX_NAME_LENGTH];
278 start_prompt(ua, _("The defined Restore Job resources are:\n"));
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());
286 if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
289 job = (JOB *)GetResWithName(R_JOB, name);
296 * Select a client resource from prompt list
298 CLIENT *select_client_resource(UAContext *ua)
300 char name[MAX_NAME_LENGTH];
303 start_prompt(ua, _("The defined Client resources are:\n"));
305 foreach_res(client, R_CLIENT) {
306 if (acl_access_ok(ua, Client_ACL, client->name())) {
307 add_prompt(ua, client->name());
311 if (do_prompt(ua, _("Client"), _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
314 client = (CLIENT *)GetResWithName(R_CLIENT, name);
319 * Get client resource, start by looking for
320 * client=<client-name>
321 * if we don't find the keyword, we prompt the user.
323 CLIENT *get_client_resource(UAContext *ua)
325 CLIENT *client = NULL;
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])) {
334 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
338 ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
342 return select_client_resource(ua);
345 /* Scan what the user has entered looking for:
347 * client=<client-name>
349 * if error or not found, put up a list of client DBRs
352 * returns: 0 on error
353 * 1 on success and fills in CLIENT_DBR
355 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
359 if (cr->Name[0]) { /* If name already supplied */
360 if (db_get_client_record(ua->jcr, ua->db, cr)) {
363 ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
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])) {
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));
381 if (!select_client_dbr(ua, cr)) { /* try once more by proposing a list */
388 * Select a Client record from the catalog
389 * Returns 1 on success
392 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
395 char name[MAX_NAME_LENGTH];
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));
405 if (num_clients <= 0) {
406 ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
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)) {
417 add_prompt(ua, ocr.Name);
420 if (do_prompt(ua, _("Client"), _("Select the Client"), name, sizeof(name)) < 0) {
423 memset(&ocr, 0, sizeof(ocr));
424 bstrncpy(ocr.Name, name, sizeof(ocr.Name));
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));
430 memcpy(cr, &ocr, sizeof(ocr));
434 /* Scan what the user has entered looking for:
438 * where argk can be : pool, recyclepool, scratchpool, nextpool etc..
440 * if error or not found, put up a list of pool DBRs
443 * returns: false on error
444 * true on success and fills in POOL_DBR
446 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
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)) {
453 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
455 if (!select_pool_dbr(ua, pr, argk)) { /* try once more */
462 * Select a Pool record from catalog
463 * argk can be pool, recyclepool, scratchpool etc..
465 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
468 char name[MAX_NAME_LENGTH];
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));
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));
491 if (num_pools <= 0) {
492 ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
496 start_prompt(ua, _("Defined Pools:\n"));
497 if (bstrcmp(argk, NT_("recyclepool"))) {
498 add_prompt(ua, _("*None*"));
500 for (i=0; i < num_pools; i++) {
502 if (!db_get_pool_record(ua->jcr, ua->db, &opr) ||
503 !acl_access_ok(ua, Pool_ACL, opr.Name)) {
506 add_prompt(ua, opr.Name);
509 if (do_prompt(ua, _("Pool"), _("Select the Pool"), name, sizeof(name)) < 0) {
513 memset(&opr, 0, sizeof(opr));
514 /* *None* is only returned when selecting a recyclepool, and in that case
515 * the calling code is only interested in opr.Name, so then we can leave
518 if (!bstrcmp(name, _("*None*"))) {
519 bstrncpy(opr.Name, name, sizeof(opr.Name));
521 if (!db_get_pool_record(ua->jcr, ua->db, &opr)) {
522 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
527 memcpy(pr, &opr, sizeof(opr));
532 * Select a Pool and a Media (Volume) record from the database
534 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
537 if (!select_media_dbr(ua, mr)) {
540 memset(pr, 0, sizeof(POOL_DBR));
541 pr->PoolId = mr->PoolId;
542 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
543 ua->error_msg("%s", db_strerror(ua->db));
546 if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
547 ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
553 /* Select a Media (Volume) record from the database */
554 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
558 memset(mr, 0, sizeof(MEDIA_DBR));
560 i = find_arg_with_value(ua, "volume");
562 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
564 if (mr->VolumeName[0] == 0) {
566 memset(&pr, 0, sizeof(pr));
567 /* Get the pool from pool=<pool-name> */
568 if (!get_pool_dbr(ua, &pr)) {
571 mr->PoolId = pr.PoolId;
572 db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
573 if (!get_cmd(ua, _("Enter *MediaId or Volume name: "))) {
576 if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
577 mr->MediaId = str_to_int64(ua->cmd+1);
579 bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
583 if (!db_get_media_record(ua->jcr, ua->db, mr)) {
584 ua->error_msg("%s", db_strerror(ua->db));
592 * Select a pool resource from prompt list
594 POOL *select_pool_resource(UAContext *ua)
596 char name[MAX_NAME_LENGTH];
599 start_prompt(ua, _("The defined Pool resources are:\n"));
601 foreach_res(pool, R_POOL) {
602 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
603 add_prompt(ua, pool->name());
607 if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
610 pool = (POOL *)GetResWithName(R_POOL, name);
616 * If you are thinking about using it, you
617 * probably want to use select_pool_dbr()
618 * or get_pool_dbr() above.
620 POOL *get_pool_resource(UAContext *ua)
625 i = find_arg_with_value(ua, "pool");
626 if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
627 pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
631 ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
633 return select_pool_resource(ua);
637 * List all jobs and ask user to select one
639 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
641 db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
642 if (!get_pint(ua, _("Enter the JobId to select: "))) {
645 jr->JobId = ua->int64_val;
646 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
647 ua->error_msg("%s", db_strerror(ua->db));
655 /* Scan what the user has entered looking for:
659 * if error or not found, put up a list of Jobs
662 * returns: 0 on error
663 * JobId on success and fills in JOB_DBR
665 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
669 for (i=1; i<ua->argc; i++) {
670 if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
672 bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
673 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
674 jr->JobId = str_to_int64(ua->argv[i]);
679 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
680 ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
681 db_strerror(ua->db));
691 for (i=1; i<ua->argc; i++) {
692 if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
693 strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
695 bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
699 if (!select_job_dbr(ua, jr)) { /* try once more */
706 * Implement unique set of prompts
708 void start_prompt(UAContext *ua, const char *msg)
710 if (ua->max_prompts == 0) {
711 ua->max_prompts = 10;
712 ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
715 ua->prompt[0] = bstrdup(msg);
719 * Add to prompts -- keeping them unique
721 void add_prompt(UAContext *ua, const char *prompt)
724 if (ua->num_prompts == ua->max_prompts) {
725 ua->max_prompts *= 2;
726 ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
729 for (i=1; i < ua->num_prompts; i++) {
730 if (strcmp(ua->prompt[i], prompt) == 0) {
734 ua->prompt[ua->num_prompts++] = bstrdup(prompt);
738 * Display prompts and get user's choice
740 * Returns: -1 on error
741 * index base 0 on success, and choice
742 * is copied to prompt if not NULL
743 * prompt is set to the chosen prompt item string
745 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
746 char *prompt, int max_prompt)
749 char pmsg[MAXSTRING];
750 BSOCK *user = ua->UA_sock;
755 if (ua->num_prompts == 2) {
758 bstrncpy(prompt, ua->prompt[1], max_prompt);
760 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
763 /* If running non-interactive, bail out */
765 /* First print the choices he wanted to make */
766 ua->send_msg(ua->prompt[0]);
767 for (i=1; i < ua->num_prompts; i++) {
768 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
770 /* Now print error message */
771 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
775 if (ua->api) user->signal(BNET_START_SELECT);
776 ua->send_msg(ua->prompt[0]);
777 for (i=1; i < ua->num_prompts; i++) {
779 ua->send_msg("%s", ua->prompt[i]);
781 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
784 if (ua->api) user->signal(BNET_END_SELECT);
787 /* First item is the prompt string, not the items */
788 if (ua->num_prompts == 1) {
789 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
790 item = -1; /* list is empty ! */
793 if (ua->num_prompts == 2) {
795 ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
797 bstrncpy(prompt, ua->prompt[1], max_prompt);
801 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
803 /* Either a . or an @ will get you out of the loop */
804 if (ua->api) user->signal(BNET_SELECT_INPUT);
805 if (!get_pint(ua, pmsg)) {
806 item = -1; /* error */
807 ua->info_msg(_("Selection aborted, nothing done.\n"));
810 item = ua->pint32_val;
811 if (item < 1 || item >= ua->num_prompts) {
812 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
816 bstrncpy(prompt, ua->prompt[item], max_prompt);
822 for (i=0; i < ua->num_prompts; i++) {
826 return item>0 ? item-1 : item;
831 * We scan what the user has entered looking for
832 * storage=<storage-resource>
835 * ? (prompt him with storage list)
836 * <some-error> (prompt him with storage list)
838 * If use_default is set, we assume that any keyword without a value
839 * is the name of the Storage resource wanted.
841 STORE *get_storage_resource(UAContext *ua, bool use_default)
843 char *store_name = NULL;
850 for (i=1; i<ua->argc; i++) {
851 if (use_default && !ua->argv[i]) {
852 /* Ignore slots, scan and barcode(s) keywords */
853 if (strcasecmp("scan", ua->argk[i]) == 0 ||
854 strcasecmp("barcode", ua->argk[i]) == 0 ||
855 strcasecmp("barcodes", ua->argk[i]) == 0 ||
856 strcasecmp("slots", ua->argk[i]) == 0) {
859 /* Default argument is storage */
861 ua->error_msg(_("Storage name given twice.\n"));
864 store_name = ua->argk[i];
865 if (*store_name == '?') {
870 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
871 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
872 store_name = ua->argv[i];
875 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
876 jobid = str_to_int64(ua->argv[i]);
878 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
881 if (!(jcr=get_jcr_by_id(jobid))) {
882 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
889 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
890 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
892 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
895 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
896 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
902 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
904 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
907 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
908 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
917 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
921 if (!store && store_name && store_name[0] != 0) {
922 store = (STORE *)GetResWithName(R_STORAGE, store_name);
924 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
927 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
930 /* No keywords found, so present a selection list */
932 store = select_storage_resource(ua);
937 /* Get drive that we are working with for this storage */
938 int get_storage_drive(UAContext *ua, STORE *store)
941 /* Get drive for autochanger if possible */
942 i = find_arg_with_value(ua, "drive");
944 drive = atoi(ua->argv[i]);
945 } else if (store && store->autochanger) {
946 /* If our structure is not set ask SD for # drives */
947 if (store->drives == 0) {
948 store->drives = get_num_drives_from_SD(ua);
950 /* If only one drive, default = 0 */
951 if (store->drives == 1) {
954 /* Ask user to enter drive number */
956 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
957 drive = -1; /* None */
959 drive = atoi(ua->cmd);
966 /* Get slot that we are working with for this storage */
967 int get_storage_slot(UAContext *ua, STORE *store)
970 /* Get slot for autochanger if possible */
971 i = find_arg_with_value(ua, "slot");
973 slot = atoi(ua->argv[i]);
974 } else if (store && store->autochanger) {
975 /* Ask user to enter slot number */
977 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
978 slot = -1; /* None */
980 slot = atoi(ua->cmd);
989 * Scan looking for mediatype=
991 * if not found or error, put up selection list
993 * Returns: 0 on error
994 * 1 on success, MediaType is set
996 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1001 i = find_arg_with_value(ua, "mediatype");
1003 bstrncpy(MediaType, ua->argv[i], max_media);
1007 start_prompt(ua, _("Media Types defined in conf file:\n"));
1009 foreach_res(store, R_STORAGE) {
1010 add_prompt(ua, store->media_type);
1013 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1016 bool get_level_from_name(JCR *jcr, const char *level_name)
1018 /* Look up level name and pull code */
1020 for (int i=0; joblevels[i].level_name; i++) {
1021 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1022 jcr->set_JobLevel(joblevels[i].level);