2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
18 * Bacula Director -- User Agent Prompt and Selection code
20 * Kern Sibbald, October MMI
27 /* Imported variables */
28 extern struct s_jl joblevels[];
32 * Confirm a retention period
34 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
39 int yes_in_arg = find_arg(ua, NT_("yes"));
42 ua->info_msg(_("The current %s retention period is: %s\n"),
43 msg, edit_utime(*ret, ed1, sizeof(ed1)));
44 if (yes_in_arg != -1) {
47 if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
50 if (strcasecmp(ua->cmd, _("mod")) == 0) {
51 if (!get_cmd(ua, _("Enter new retention period: "))) {
54 if (!duration_to_utime(ua->cmd, ret)) {
55 ua->error_msg(_("Invalid period.\n"));
60 if (is_yesno(ua->cmd, &val)) {
61 return val; /* is 1 for yes, 0 for no */
68 * Given a list of keywords, find the first one
69 * that is in the argument list.
70 * Returns: -1 if not found
71 * index into list (base 0) on success
73 int find_arg_keyword(UAContext *ua, const char **list)
75 for (int i=1; i<ua->argc; i++) {
76 for(int j=0; list[j]; j++) {
77 if (strcasecmp(list[j], ua->argk[i]) == 0) {
86 * Given one keyword, find the first one that
87 * is in the argument list.
88 * Returns: argk index (always gt 0)
91 int find_arg(UAContext *ua, const char *keyword)
93 for (int i=1; i<ua->argc; i++) {
94 if (strcasecmp(keyword, ua->argk[i]) == 0) {
102 * Given a single keyword, find it in the argument list, but
103 * it must have a value
104 * Returns: -1 if not found or no value
105 * list index (base 0) on success
107 int find_arg_with_value(UAContext *ua, const char *keyword)
109 for (int i=1; i<ua->argc; i++) {
110 if (strcasecmp(keyword, ua->argk[i]) == 0) {
122 * Given a list of keywords, prompt the user
125 * Returns: -1 on failure
126 * index into list (base 0) on success
128 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
131 start_prompt(ua, _("You have the following choices:\n"));
132 for (i=0; list[i]; i++) {
133 add_prompt(ua, list[i]);
135 return do_prompt(ua, "", msg, NULL, 0);
140 * Select a Storage resource from prompt list
141 * If unique is set storage resources that have the main address are
142 * combined into one (i.e. they are all part of the same)
143 * storage. Note, not all commands want this.
145 STORE *select_storage_resource(UAContext *ua, bool unique)
147 char name[MAX_NAME_LENGTH];
150 /* Does user want a full selection? */
151 if (unique && find_arg(ua, NT_("select")) > 0) {
154 start_prompt(ua, _("The defined Storage resources are:\n"));
156 foreach_res(store, R_STORAGE) {
157 if (acl_access_ok(ua, Storage_ACL, store->name())) {
159 add_prompt(ua, store->name(), store->address);
161 add_prompt(ua, store->name());
166 if (do_prompt(ua, _("Storage"), _("Select Storage resource"), name, sizeof(name)) < 0) {
169 store = (STORE *)GetResWithName(R_STORAGE, name);
174 * Select a FileSet resource from prompt list
176 FILESET *select_fileset_resource(UAContext *ua)
178 char name[MAX_NAME_LENGTH];
181 start_prompt(ua, _("The defined FileSet resources are:\n"));
183 foreach_res(fs, R_FILESET) {
184 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
185 add_prompt(ua, fs->name());
189 if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
192 fs = (FILESET *)GetResWithName(R_FILESET, name);
198 * Get a catalog resource from prompt list
200 CAT *get_catalog_resource(UAContext *ua)
202 char name[MAX_NAME_LENGTH];
206 for (i=1; i<ua->argc; i++) {
207 if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
208 if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
209 catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
214 if (ua->gui && !catalog) {
216 catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
219 ua->error_msg(_("Could not find a Catalog resource\n"));
221 } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
222 ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
228 start_prompt(ua, _("The defined Catalog resources are:\n"));
230 foreach_res(catalog, R_CATALOG) {
231 if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
232 add_prompt(ua, catalog->name());
236 if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) {
239 catalog = (CAT *)GetResWithName(R_CATALOG, name);
246 * Select a job to enable or disable
248 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
250 char name[MAX_NAME_LENGTH];
254 start_prompt(ua, _("The defined Job resources are:\n"));
255 foreach_res(job, R_JOB) {
256 if (!acl_access_ok(ua, Job_ACL, job->name())) {
259 if (job->enabled == enable) { /* Already enabled/disabled? */
260 continue; /* yes, skip */
262 add_prompt(ua, job->name());
265 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
268 job = (JOB *)GetResWithName(R_JOB, name);
273 * Select a Job resource from prompt list
275 JOB *select_job_resource(UAContext *ua)
277 char name[MAX_NAME_LENGTH];
280 start_prompt(ua, _("The defined Job resources are:\n"));
282 foreach_res(job, R_JOB) {
283 if (acl_access_ok(ua, Job_ACL, job->name())) {
284 add_prompt(ua, job->name());
288 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
291 job = (JOB *)GetResWithName(R_JOB, name);
296 * Select a Restore Job resource from argument or prompt
298 JOB *get_restore_job(UAContext *ua)
301 int i = find_arg_with_value(ua, "restorejob");
302 if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
303 job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
304 if (job && job->JobType == JT_RESTORE) {
307 ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
310 return select_restore_job_resource(ua);
314 * Select a Restore Job resource from prompt list
316 JOB *select_restore_job_resource(UAContext *ua)
318 char name[MAX_NAME_LENGTH];
321 start_prompt(ua, _("The defined Restore Job resources are:\n"));
323 foreach_res(job, R_JOB) {
324 if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
325 add_prompt(ua, job->name());
329 if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
332 job = (JOB *)GetResWithName(R_JOB, name);
339 * Select a client resource from prompt list
341 CLIENT *select_client_resource(UAContext *ua)
343 char name[MAX_NAME_LENGTH];
346 start_prompt(ua, _("The defined Client resources are:\n"));
348 foreach_res(client, R_CLIENT) {
349 if (acl_access_ok(ua, Client_ACL, client->name())) {
350 add_prompt(ua, client->name());
354 if (do_prompt(ua, _("Client"), _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
357 client = (CLIENT *)GetResWithName(R_CLIENT, name);
362 * Get client resource, start by looking for
363 * client=<client-name>
364 * if we don't find the keyword, we prompt the user.
366 CLIENT *get_client_resource(UAContext *ua)
368 CLIENT *client = NULL;
371 for (i=1; i<ua->argc; i++) {
372 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
373 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
374 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
377 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
381 ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
385 return select_client_resource(ua);
388 /* Scan what the user has entered looking for:
390 * client=<client-name>
392 * if error or not found, put up a list of client DBRs
395 * returns: 0 on error
396 * 1 on success and fills in CLIENT_DBR
398 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
402 if (cr->Name[0]) { /* If name already supplied */
403 if (db_get_client_record(ua->jcr, ua->db, cr)) {
406 ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
408 for (i=1; i<ua->argc; i++) {
409 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
410 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
411 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
414 bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
415 if (!db_get_client_record(ua->jcr, ua->db, cr)) {
416 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
417 db_strerror(ua->db));
424 if (!select_client_dbr(ua, cr)) { /* try once more by proposing a list */
431 * Select a Client record from the catalog
432 * Returns 1 on success
435 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
438 char name[MAX_NAME_LENGTH];
444 if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
445 ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
448 if (num_clients <= 0) {
449 ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
453 start_prompt(ua, _("Defined Clients:\n"));
454 for (i=0; i < num_clients; i++) {
455 ocr.ClientId = ids[i];
456 if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
457 !acl_access_ok(ua, Client_ACL, ocr.Name)) {
460 add_prompt(ua, ocr.Name);
463 if (do_prompt(ua, _("Client"), _("Select the Client"), name, sizeof(name)) < 0) {
466 memset(&ocr, 0, sizeof(ocr));
467 bstrncpy(ocr.Name, name, sizeof(ocr.Name));
469 if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
470 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
473 memcpy(cr, &ocr, sizeof(ocr));
477 /* Scan what the user has entered looking for:
481 * where argk can be : pool, recyclepool, scratchpool, nextpool etc..
483 * if error or not found, put up a list of pool DBRs
486 * returns: false on error
487 * true on success and fills in POOL_DBR
489 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
491 if (pr->Name[0]) { /* If name already supplied */
492 if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
493 acl_access_ok(ua, Pool_ACL, pr->Name)) {
496 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
498 if (!select_pool_dbr(ua, pr, argk)) { /* try once more */
505 * Select a Pool record from catalog
506 * argk can be pool, recyclepool, scratchpool etc..
508 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
511 char name[MAX_NAME_LENGTH];
515 for (i=1; i<ua->argc; i++) {
516 if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
517 acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
518 bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
519 if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
520 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
521 db_strerror(ua->db));
530 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
531 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
534 if (num_pools <= 0) {
535 ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
539 start_prompt(ua, _("Defined Pools:\n"));
540 if (bstrcmp(argk, NT_("recyclepool"))) {
541 add_prompt(ua, _("*None*"));
543 for (i=0; i < num_pools; i++) {
545 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
546 !acl_access_ok(ua, Pool_ACL, opr.Name)) {
549 add_prompt(ua, opr.Name);
552 if (do_prompt(ua, _("Pool"), _("Select the Pool"), name, sizeof(name)) < 0) {
556 memset(&opr, 0, sizeof(opr));
557 /* *None* is only returned when selecting a recyclepool, and in that case
558 * the calling code is only interested in opr.Name, so then we can leave
561 if (!bstrcmp(name, _("*None*"))) {
562 bstrncpy(opr.Name, name, sizeof(opr.Name));
564 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
565 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
570 memcpy(pr, &opr, sizeof(opr));
575 * Select a Pool and a Media (Volume) record from the database
577 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
580 if (!select_media_dbr(ua, mr)) {
583 memset(pr, 0, sizeof(POOL_DBR));
584 pr->PoolId = mr->PoolId;
585 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
586 ua->error_msg("%s", db_strerror(ua->db));
589 if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
590 ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
596 /* Select a Media (Volume) record from the database */
597 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
601 POOLMEM *err = get_pool_memory(PM_FNAME);
605 i = find_arg_with_value(ua, "volume");
607 if (is_name_valid(ua->argv[i], &err)) {
608 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
613 if (mr->VolumeName[0] == 0) {
615 memset(&pr, 0, sizeof(pr));
616 /* Get the pool from pool=<pool-name> */
617 if (!get_pool_dbr(ua, &pr)) {
620 mr->PoolId = pr.PoolId;
621 db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
622 if (!get_cmd(ua, _("Enter *MediaId or Volume name: "))) {
625 if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
626 mr->MediaId = str_to_int64(ua->cmd+1);
627 } else if (is_name_valid(ua->cmd, &err)) {
628 bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
634 if (!db_get_media_record(ua->jcr, ua->db, mr)) {
635 pm_strcpy(err, db_strerror(ua->db));
642 ua->error_msg("%s", err);
644 free_pool_memory(err);
650 * Select a pool resource from prompt list
652 POOL *select_pool_resource(UAContext *ua)
654 char name[MAX_NAME_LENGTH];
657 start_prompt(ua, _("The defined Pool resources are:\n"));
659 foreach_res(pool, R_POOL) {
660 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
661 add_prompt(ua, pool->name());
665 if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
668 pool = (POOL *)GetResWithName(R_POOL, name);
674 * If you are thinking about using it, you
675 * probably want to use select_pool_dbr()
676 * or get_pool_dbr() above.
678 POOL *get_pool_resource(UAContext *ua)
683 i = find_arg_with_value(ua, "pool");
684 if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
685 pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
689 ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
691 return select_pool_resource(ua);
695 * List all jobs and ask user to select one
697 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
699 db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
700 if (!get_pint(ua, _("Enter the JobId to select: "))) {
703 jr->JobId = ua->int64_val;
704 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
705 ua->error_msg("%s", db_strerror(ua->db));
713 /* Scan what the user has entered looking for:
717 * if error or not found, put up a list of Jobs
720 * returns: 0 on error
721 * JobId on success and fills in JOB_DBR
723 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
727 for (i=1; i<ua->argc; i++) {
728 if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
730 bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
731 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
732 jr->JobId = str_to_int64(ua->argv[i]);
737 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
738 ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
739 db_strerror(ua->db));
749 for (i=1; i<ua->argc; i++) {
750 if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
751 strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
753 bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
757 if (!select_job_dbr(ua, jr)) { /* try once more */
764 * Implement unique set of prompts
766 void start_prompt(UAContext *ua, const char *msg)
768 if (ua->max_prompts == 0) {
769 ua->max_prompts = 10;
770 ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
771 ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
774 ua->prompt[0] = bstrdup(msg);
775 ua->unique[0] = NULL;
779 * Add to prompts -- keeping them unique by name
781 void add_prompt(UAContext *ua, const char *prompt, char *unique)
784 if (ua->num_prompts == ua->max_prompts) {
785 ua->max_prompts *= 2;
786 ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
788 ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
791 for (i=1; i < ua->num_prompts; i++) {
792 if (strcmp(ua->prompt[i], prompt) == 0) {
794 } else if (unique && strcmp(ua->unique[i], unique) == 0) {
798 ua->prompt[ua->num_prompts] = bstrdup(prompt);
800 ua->unique[ua->num_prompts++] = bstrdup(unique);
802 ua->unique[ua->num_prompts++] = NULL;
807 * Display prompts and get user's choice
809 * Returns: -1 on error
810 * index base 0 on success, and choice
811 * is copied to prompt if not NULL
812 * prompt is set to the chosen prompt item string
814 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
815 char *prompt, int max_prompt)
818 char pmsg[MAXSTRING];
819 BSOCK *user = ua->UA_sock;
824 if (ua->num_prompts == 2) {
827 bstrncpy(prompt, ua->prompt[1], max_prompt);
829 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
832 /* If running non-interactive, bail out */
834 /* First print the choices he wanted to make */
835 ua->send_msg(ua->prompt[0]);
836 for (i=1; i < ua->num_prompts; i++) {
837 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
839 /* Now print error message */
840 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
844 if (ua->api) user->signal(BNET_START_SELECT);
845 ua->send_msg(ua->prompt[0]);
846 for (i=1; i < ua->num_prompts; i++) {
848 ua->send_msg("%s", ua->prompt[i]);
850 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
853 if (ua->api) user->signal(BNET_END_SELECT);
856 /* First item is the prompt string, not the items */
857 if (ua->num_prompts == 1) {
858 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
859 item = -1; /* list is empty ! */
862 if (ua->num_prompts == 2) {
864 ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
866 bstrncpy(prompt, ua->prompt[1], max_prompt);
870 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
872 /* Either a . or an @ will get you out of the loop */
873 if (ua->api) user->signal(BNET_SELECT_INPUT);
874 if (!get_pint(ua, pmsg)) {
875 item = -1; /* error */
876 ua->info_msg(_("Selection aborted, nothing done.\n"));
879 item = ua->pint32_val;
880 if (item < 1 || item >= ua->num_prompts) {
881 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
885 bstrncpy(prompt, ua->prompt[item], max_prompt);
891 for (i=0; i < ua->num_prompts; i++) {
893 if (ua->unique[i]) free(ua->unique[i]);
896 return item>0 ? item-1 : item;
900 * Display prompts and get user's choice
902 * Returns: -1 on error
903 * number of items selected and the choices are
904 * copied to selected if not NULL
905 * selected is an alist of the prompts chosen
906 * Note! selected must already be initialized.
908 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
912 char pmsg[MAXSTRING];
913 BSOCK *user = ua->UA_sock;
916 /* First item is the prompt string, not the items */
917 if (ua->num_prompts == 1) {
918 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
919 item = -1; /* list is empty ! */
922 if (ua->num_prompts == 2) {
924 selected->append(bstrdup(ua->prompt[1]));
925 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
928 /* If running non-interactive, bail out */
930 /* First print the choices he wanted to make */
931 ua->send_msg(ua->prompt[0]);
932 for (i=1; i < ua->num_prompts; i++) {
933 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
935 /* Now print error message */
936 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
940 if (ua->api) user->signal(BNET_START_SELECT);
941 ua->send_msg(ua->prompt[0]);
942 for (i=1; i < ua->num_prompts; i++) {
944 ua->send_msg("%s", ua->prompt[i]);
946 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
949 if (ua->api) user->signal(BNET_END_SELECT);
951 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
955 /* Either a . or an @ will get you out of the loop */
956 if (ua->api) user->signal(BNET_SELECT_INPUT);
958 if (!get_selection_list(ua, sl, pmsg, false)) {
964 for (i=1; i < ua->num_prompts; i++) {
965 selected->append(bstrdup(ua->prompt[i]));
968 while ( (item = sl.next()) > 0) {
969 if (item < 1 || item >= ua->num_prompts) {
970 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
974 selected->append(bstrdup(ua->prompt[item]));
978 item = selected->size();
984 for (i=0; i < ua->num_prompts; i++) {
986 if (ua->unique[i]) free(ua->unique[i]);
994 * We scan what the user has entered looking for
995 * storage=<storage-resource>
998 * ? (prompt him with storage list)
999 * <some-error> (prompt him with storage list)
1001 * If use_default is set, we assume that any keyword without a value
1002 * is the name of the Storage resource wanted.
1004 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1006 char *store_name = NULL;
1007 STORE *store = NULL;
1013 for (i=1; i<ua->argc; i++) {
1014 if (use_default && !ua->argv[i]) {
1015 /* Ignore slots, scan and barcode(s) keywords */
1016 if (strcasecmp("scan", ua->argk[i]) == 0 ||
1017 strcasecmp("barcode", ua->argk[i]) == 0 ||
1018 strcasecmp("barcodes", ua->argk[i]) == 0 ||
1019 strcasecmp("slots", ua->argk[i]) == 0) {
1022 /* Default argument is storage */
1024 ua->error_msg(_("Storage name given twice.\n"));
1027 store_name = ua->argk[i];
1028 if (*store_name == '?') {
1033 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1034 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1035 store_name = ua->argv[i];
1038 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1039 jobid = str_to_int64(ua->argv[i]);
1041 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1044 if (!(jcr=get_jcr_by_id(jobid))) {
1045 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1048 store = jcr->wstore;
1052 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1053 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1055 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1058 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1059 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1062 store = jcr->wstore;
1065 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1067 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1070 if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1071 store = jcr->wstore;
1073 /* The job might not be running, so we try to see other keywords */
1081 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1085 if (!store && store_name && store_name[0] != 0) {
1086 store = (STORE *)GetResWithName(R_STORAGE, store_name);
1088 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1091 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1094 /* No keywords found, so present a selection list */
1096 store = select_storage_resource(ua, unique);
1101 /* Get drive that we are working with for this storage */
1102 int get_storage_drive(UAContext *ua, STORE *store)
1105 /* Get drive for autochanger if possible */
1106 i = find_arg_with_value(ua, "drive");
1108 drive = atoi(ua->argv[i]);
1109 } else if (store && store->autochanger) {
1110 /* If our structure is not set ask SD for # drives */
1111 if (store->drives == 0) {
1112 store->drives = get_num_drives_from_SD(ua);
1114 /* If only one drive, default = 0 */
1115 if (store->drives == 1) {
1118 /* Ask user to enter drive number */
1120 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1121 drive = -1; /* None */
1123 drive = atoi(ua->cmd);
1130 /* Get slot that we are working with for this storage */
1131 int get_storage_slot(UAContext *ua, STORE *store)
1134 /* Get slot for autochanger if possible */
1135 i = find_arg_with_value(ua, "slot");
1137 slot = atoi(ua->argv[i]);
1138 } else if (store && store->autochanger) {
1139 /* Ask user to enter slot number */
1141 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1142 slot = -1; /* None */
1144 slot = atoi(ua->cmd);
1153 * Scan looking for mediatype=
1155 * if not found or error, put up selection list
1157 * Returns: 0 on error
1158 * 1 on success, MediaType is set
1160 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1165 i = find_arg_with_value(ua, "mediatype");
1167 bstrncpy(MediaType, ua->argv[i], max_media);
1171 start_prompt(ua, _("Media Types defined in conf file:\n"));
1173 foreach_res(store, R_STORAGE) {
1174 add_prompt(ua, store->media_type);
1177 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1181 bool get_level_from_name(JCR *jcr, const char *level_name)
1183 /* Look up level name and pull code */
1185 for (int i=0; joblevels[i].level_name; i++) {
1186 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1187 jcr->setJobLevel(joblevels[i].level);
1195 static int count_running_jobs(UAContext *ua)
1197 int tjobs = 0; /* total # number jobs */
1200 /* Count Jobs running */
1202 if (jcr->JobId == 0) { /* this is us */
1205 tjobs++; /* count of all jobs */
1206 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1207 continue; /* skip not authorized */
1209 njobs++; /* count of authorized jobs */
1213 if (njobs == 0) { /* no authorized */
1215 ua->send_msg(_("No Jobs running.\n"));
1217 ua->send_msg(_("None of your jobs are running.\n"));
1224 /* Get a list of running jobs
1225 * "reason" is used in user messages
1226 * can be: cancel, limit, ...
1227 * Returns: -1 on error
1228 * nb of JCR on success (should be free_jcr() after)
1230 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1235 char JobName[MAX_NAME_LENGTH];
1237 alist *selected = NULL;
1239 for (i=1; i<ua->argc; i++) {
1240 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1244 if (!sl.set_string(ua->argv[i], true)) {
1245 ua->send_msg("%s", sl.get_errmsg());
1249 foreach_sellist(JobId, &sl) {
1250 jcr = get_jcr_by_id(JobId);
1251 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1255 ua->error_msg(_("Unauthorized command from this console "
1256 "for JobId=%d.\n"), JobId);
1260 if (debug_level > 5) {
1261 ua->warning_msg(_("Warning Job JobId=%d is not running. "
1262 "Continuing anyway...\n"), JobId);
1268 /* TODO: might want to implement filters (client, status, etc...) */
1269 } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1271 if (jcr->JobId == 0) { /* this is us */
1274 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1275 continue; /* skip not authorized */
1277 jcr->inc_use_count();
1282 if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1284 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1285 reason, jcrs->size(), jcrs->size()>1?"s":"");
1286 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1292 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1296 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1297 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1298 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1299 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1301 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1306 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1310 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
1311 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1312 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1313 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1315 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1322 if (jcrs->size() == 0) {
1324 * If we still do not have a jcr,
1325 * throw up a list and ask the user to select one.
1329 njobs = count_running_jobs(ua);
1333 start_prompt(ua, _("Select Job(s):\n"));
1336 if (jcr->JobId == 0) { /* this is us */
1339 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1340 add_prompt(ua, buf);
1343 bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1344 selected = New(alist(5, owned_by_alist));
1345 if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1348 /* Possibly ask for confirmation */
1349 if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1351 foreach_alist(item, selected) {
1352 ua->send_msg("%s\n", item);
1354 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1355 reason, selected->size(), selected->size()>1?"s":"");
1356 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1361 foreach_alist(item, selected) {
1362 if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1363 ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1366 jcr = get_jcr_by_full_name(JobName);
1370 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1375 if (selected) delete selected;
1376 return jcrs->size();