2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many 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 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Director -- User Agent Prompt and Selection code
23 * Kern Sibbald, October MMI
30 /* Imported variables */
31 extern struct s_jl joblevels[];
33 int confirm_retention_yesno(UAContext *ua, utime_t ret, const char *msg)
38 /* Look for "yes" in command line */
39 if (find_arg(ua, NT_("yes")) != -1) {
44 ua->info_msg(_("The current %s retention period is: %s\n"),
45 msg, edit_utime(ret, ed1, sizeof(ed1)));
46 if (!get_cmd(ua, _("Continue? (yes/no): "))) {
49 if (is_yesno(ua->cmd, &val)) {
50 return val; /* is 1 for yes, 0 for no */
57 * Confirm a retention period
59 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
64 /* Look for "yes" in command line */
65 if (find_arg(ua, NT_("yes")) != -1) {
70 ua->info_msg(_("The current %s retention period is: %s\n"),
71 msg, edit_utime(*ret, ed1, sizeof(ed1)));
73 if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
76 if (strcasecmp(ua->cmd, _("mod")) == 0) {
77 if (!get_cmd(ua, _("Enter new retention period: "))) {
80 if (!duration_to_utime(ua->cmd, ret)) {
81 ua->error_msg(_("Invalid period.\n"));
86 if (is_yesno(ua->cmd, &val)) {
87 return val; /* is 1 for yes, 0 for no */
94 * Given a list of keywords, find the first one
95 * that is in the argument list.
96 * Returns: -1 if not found
97 * index into list (base 0) on success
99 int find_arg_keyword(UAContext *ua, const char **list)
101 for (int i=1; i<ua->argc; i++) {
102 for(int j=0; list[j]; j++) {
103 if (strcasecmp(list[j], ua->argk[i]) == 0) {
112 * Given one keyword, find the first one that
113 * is in the argument list.
114 * Returns: argk index (always gt 0)
117 int find_arg(UAContext *ua, const char *keyword)
119 for (int i=1; i<ua->argc; i++) {
120 if (strcasecmp(keyword, ua->argk[i]) == 0) {
128 * Given a single keyword, find it in the argument list, but
129 * it must have a value
130 * Returns: -1 if not found or no value
131 * list index (base 0) on success
133 int find_arg_with_value(UAContext *ua, const char *keyword)
135 for (int i=1; i<ua->argc; i++) {
136 if (strcasecmp(keyword, ua->argk[i]) == 0) {
148 * Given a list of keywords, prompt the user
151 * Returns: -1 on failure
152 * index into list (base 0) on success
154 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
157 start_prompt(ua, _("You have the following choices:\n"));
158 for (i=0; list[i]; i++) {
159 add_prompt(ua, list[i]);
161 return do_prompt(ua, "", msg, NULL, 0);
166 * Select a Storage resource from prompt list
167 * If unique is set storage resources that have the main address are
168 * combined into one (i.e. they are all part of the same)
169 * storage. Note, not all commands want this.
171 STORE *select_storage_resource(UAContext *ua, bool unique)
173 char name[MAX_NAME_LENGTH];
176 /* Does user want a full selection? */
177 if (unique && find_arg(ua, NT_("select")) > 0) {
180 start_prompt(ua, _("The defined Storage resources are:\n"));
182 foreach_res(store, R_STORAGE) {
183 if (acl_access_ok(ua, Storage_ACL, store->name())) {
185 add_prompt(ua, store->name(), store->address);
187 add_prompt(ua, store->name());
192 if (do_prompt(ua, _("Storage"), _("Select Storage resource"), name, sizeof(name)) < 0) {
195 store = (STORE *)GetResWithName(R_STORAGE, name);
200 * Select a FileSet resource from prompt list
202 FILESET *select_fileset_resource(UAContext *ua)
204 char name[MAX_NAME_LENGTH];
207 start_prompt(ua, _("The defined FileSet resources are:\n"));
209 foreach_res(fs, R_FILESET) {
210 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
211 add_prompt(ua, fs->name());
215 if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
218 fs = (FILESET *)GetResWithName(R_FILESET, name);
224 * Get a catalog resource from prompt list
226 CAT *get_catalog_resource(UAContext *ua)
228 char name[MAX_NAME_LENGTH];
232 for (i=1; i<ua->argc; i++) {
233 if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
234 if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
235 catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
240 if (ua->gui && !catalog) {
242 catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
245 ua->error_msg(_("Could not find a Catalog resource\n"));
247 } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
248 ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
254 start_prompt(ua, _("The defined Catalog resources are:\n"));
256 foreach_res(catalog, R_CATALOG) {
257 if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
258 add_prompt(ua, catalog->name());
262 if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) {
265 catalog = (CAT *)GetResWithName(R_CATALOG, name);
272 * Select a job to enable or disable
274 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
276 char name[MAX_NAME_LENGTH];
281 start_prompt(ua, _("The disabled Job resources are:\n"));
283 start_prompt(ua, _("The enabled Job resources are:\n"));
285 foreach_res(job, R_JOB) {
286 if (!acl_access_ok(ua, Job_ACL, job->name())) {
289 if (job->enabled == enable) { /* Already enabled/disabled? */
290 continue; /* yes, skip */
292 add_prompt(ua, job->name());
295 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
298 job = (JOB *)GetResWithName(R_JOB, name);
303 * Select a Job resource from prompt list
305 JOB *select_job_resource(UAContext *ua)
307 char name[MAX_NAME_LENGTH];
310 start_prompt(ua, _("The defined Job resources are:\n"));
312 foreach_res(job, R_JOB) {
313 if (acl_access_ok(ua, Job_ACL, job->name())) {
314 add_prompt(ua, job->name());
318 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
321 job = (JOB *)GetResWithName(R_JOB, name);
326 * Select a Restore Job resource from argument or prompt
328 JOB *get_restore_job(UAContext *ua)
331 int i = find_arg_with_value(ua, "restorejob");
332 if (i >= 0 && acl_access_ok(ua, Job_ACL, ua->argv[i])) {
333 job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
334 if (job && job->JobType == JT_RESTORE) {
337 ua->error_msg(_("Error: Restore Job resource \"%s\" does not exist.\n"),
340 return select_restore_job_resource(ua);
344 * Select a Restore Job resource from prompt list
346 JOB *select_restore_job_resource(UAContext *ua)
348 char name[MAX_NAME_LENGTH];
351 start_prompt(ua, _("The defined Restore Job resources are:\n"));
353 foreach_res(job, R_JOB) {
354 if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
355 add_prompt(ua, job->name());
359 if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
362 job = (JOB *)GetResWithName(R_JOB, name);
367 * Select a client to enable or disable
369 CLIENT *select_enable_disable_client_resource(UAContext *ua, bool enable)
371 char name[MAX_NAME_LENGTH];
375 start_prompt(ua, _("The defined Client resources are:\n"));
376 foreach_res(client, R_CLIENT) {
377 if (!acl_access_ok(ua, Client_ACL, client->name())) {
380 if (client->enabled == enable) { /* Already enabled/disabled? */
381 continue; /* yes, skip */
383 add_prompt(ua, client->name());
386 if (do_prompt(ua, _("Client"), _("Select Client resource"), name, sizeof(name)) < 0) {
389 client = (CLIENT *)GetResWithName(R_CLIENT, name);
395 * Select a client resource from prompt list
397 CLIENT *select_client_resource(UAContext *ua)
399 char name[MAX_NAME_LENGTH];
402 start_prompt(ua, _("The defined Client resources are:\n"));
404 foreach_res(client, R_CLIENT) {
405 if (acl_access_ok(ua, Client_ACL, client->name())) {
406 add_prompt(ua, client->name());
410 if (do_prompt(ua, _("Client"), _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
413 client = (CLIENT *)GetResWithName(R_CLIENT, name);
418 * Get client resource, start by looking for
419 * client=<client-name>
420 * if we don't find the keyword, we prompt the user.
422 CLIENT *get_client_resource(UAContext *ua)
424 CLIENT *client = NULL;
427 for (i=1; i<ua->argc; i++) {
428 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
429 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
430 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
433 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
437 ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
441 return select_client_resource(ua);
445 * Select a schedule to enable or disable
447 SCHED *select_enable_disable_schedule_resource(UAContext *ua, bool enable)
449 char name[MAX_NAME_LENGTH];
453 start_prompt(ua, _("The defined Schedule resources are:\n"));
454 foreach_res(sched, R_SCHEDULE) {
455 if (!acl_access_ok(ua, Schedule_ACL, sched->name())) {
458 if (sched->enabled == enable) { /* Already enabled/disabled? */
459 continue; /* yes, skip */
461 add_prompt(ua, sched->name());
464 if (do_prompt(ua, _("Schedule"), _("Select Schedule resource"), name, sizeof(name)) < 0) {
467 sched = (SCHED *)GetResWithName(R_SCHEDULE, name);
472 /* Scan what the user has entered looking for:
474 * client=<client-name>
476 * if error or not found, put up a list of client DBRs
479 * returns: 0 on error
480 * 1 on success and fills in CLIENT_DBR
482 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
486 if (cr->Name[0]) { /* If name already supplied */
487 if (db_get_client_record(ua->jcr, ua->db, cr)) {
490 ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
492 for (i=1; i<ua->argc; i++) {
493 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
494 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
495 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
498 bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
499 if (!db_get_client_record(ua->jcr, ua->db, cr)) {
500 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
501 db_strerror(ua->db));
508 if (!select_client_dbr(ua, cr)) { /* try once more by proposing a list */
515 * Select a Client record from the catalog
516 * Returns 1 on success
519 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
522 char name[MAX_NAME_LENGTH];
528 if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
529 ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
532 if (num_clients <= 0) {
533 ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
537 start_prompt(ua, _("Defined Clients:\n"));
538 for (i=0; i < num_clients; i++) {
539 ocr.ClientId = ids[i];
540 if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
541 !acl_access_ok(ua, Client_ACL, ocr.Name)) {
544 add_prompt(ua, ocr.Name);
547 if (do_prompt(ua, _("Client"), _("Select the Client"), name, sizeof(name)) < 0) {
550 memset(&ocr, 0, sizeof(ocr));
551 bstrncpy(ocr.Name, name, sizeof(ocr.Name));
553 if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
554 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
557 memcpy(cr, &ocr, sizeof(ocr));
561 /* Scan what the user has entered looking for:
565 * where argk can be : pool, recyclepool, scratchpool, nextpool etc..
567 * if error or not found, put up a list of pool DBRs
570 * returns: false on error
571 * true on success and fills in POOL_DBR
573 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
575 if (pr->Name[0]) { /* If name already supplied */
576 if (db_get_pool_numvols(ua->jcr, ua->db, pr) &&
577 acl_access_ok(ua, Pool_ACL, pr->Name)) {
580 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
582 if (!select_pool_dbr(ua, pr, argk)) { /* try once more */
589 * Select a Pool record from catalog
590 * argk can be pool, recyclepool, scratchpool etc..
592 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
595 char name[MAX_NAME_LENGTH];
599 for (i=1; i<ua->argc; i++) {
600 if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
601 acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
602 bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
603 if (!db_get_pool_numvols(ua->jcr, ua->db, pr)) {
604 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
605 db_strerror(ua->db));
614 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
615 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
618 if (num_pools <= 0) {
619 ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
623 start_prompt(ua, _("Defined Pools:\n"));
624 if (bstrcmp(argk, NT_("recyclepool"))) {
625 add_prompt(ua, _("*None*"));
627 for (i=0; i < num_pools; i++) {
629 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr) ||
630 !acl_access_ok(ua, Pool_ACL, opr.Name)) {
633 add_prompt(ua, opr.Name);
636 if (do_prompt(ua, _("Pool"), _("Select the Pool"), name, sizeof(name)) < 0) {
640 memset(&opr, 0, sizeof(opr));
641 /* *None* is only returned when selecting a recyclepool, and in that case
642 * the calling code is only interested in opr.Name, so then we can leave
645 if (!bstrcmp(name, _("*None*"))) {
646 bstrncpy(opr.Name, name, sizeof(opr.Name));
648 if (!db_get_pool_numvols(ua->jcr, ua->db, &opr)) {
649 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
654 memcpy(pr, &opr, sizeof(opr));
659 * Select a Pool and a Media (Volume) record from the database
661 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
664 if (!select_media_dbr(ua, mr)) {
667 memset(pr, 0, sizeof(POOL_DBR));
668 pr->PoolId = mr->PoolId;
669 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
670 ua->error_msg("%s", db_strerror(ua->db));
673 if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
674 ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
680 /* Select a Media (Volume) record from the database */
681 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
685 POOLMEM *err = get_pool_memory(PM_FNAME);
689 i = find_arg_with_value(ua, "volume");
691 if (is_name_valid(ua->argv[i], &err)) {
692 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
697 if (mr->VolumeName[0] == 0) {
699 memset(&pr, 0, sizeof(pr));
700 /* Get the pool from pool=<pool-name> */
701 if (!get_pool_dbr(ua, &pr)) {
704 mr->PoolId = pr.PoolId;
705 db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
706 if (!get_cmd(ua, _("Enter a Volume name or *MediaId: "))) {
709 if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
710 mr->MediaId = str_to_int64(ua->cmd+1);
711 } else if (is_name_valid(ua->cmd, &err)) {
712 bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
718 if (!db_get_media_record(ua->jcr, ua->db, mr)) {
719 pm_strcpy(err, db_strerror(ua->db));
726 ua->error_msg("%s", err);
728 free_pool_memory(err);
734 * Select a pool resource from prompt list
736 POOL *select_pool_resource(UAContext *ua)
738 char name[MAX_NAME_LENGTH];
741 start_prompt(ua, _("The defined Pool resources are:\n"));
743 foreach_res(pool, R_POOL) {
744 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
745 add_prompt(ua, pool->name());
749 if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
752 pool = (POOL *)GetResWithName(R_POOL, name);
758 * If you are thinking about using it, you
759 * probably want to use select_pool_dbr()
760 * or get_pool_dbr() above.
762 POOL *get_pool_resource(UAContext *ua)
767 i = find_arg_with_value(ua, "pool");
768 if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
769 pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
773 ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
775 return select_pool_resource(ua);
779 * List all jobs and ask user to select one
781 static int select_job_dbr(UAContext *ua, JOB_DBR *jr)
783 db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
784 if (!get_pint(ua, _("Enter the JobId to select: "))) {
787 jr->JobId = ua->int64_val;
788 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
789 ua->error_msg("%s", db_strerror(ua->db));
797 /* Scan what the user has entered looking for:
801 * if error or not found, put up a list of Jobs
804 * returns: 0 on error
805 * JobId on success and fills in JOB_DBR
807 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
811 for (i=1; i<ua->argc; i++) {
812 if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
814 bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
815 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
816 jr->JobId = str_to_int64(ua->argv[i]);
821 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
822 ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
823 db_strerror(ua->db));
833 for (i=1; i<ua->argc; i++) {
834 if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
835 strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
837 bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
841 if (!select_job_dbr(ua, jr)) { /* try once more */
848 * Implement unique set of prompts
850 void start_prompt(UAContext *ua, const char *msg)
852 if (ua->max_prompts == 0) {
853 ua->max_prompts = 10;
854 ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
855 ua->unique = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
858 ua->prompt[0] = bstrdup(msg);
859 ua->unique[0] = NULL;
863 * Add to prompts -- keeping them unique by name
865 void add_prompt(UAContext *ua, const char *prompt, char *unique)
868 if (ua->num_prompts == ua->max_prompts) {
869 ua->max_prompts *= 2;
870 ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
872 ua->unique = (char **)brealloc(ua->unique, sizeof(char *) *
875 for (i=1; i < ua->num_prompts; i++) {
876 if (strcmp(ua->prompt[i], prompt) == 0) {
878 } else if (unique && strcmp(ua->unique[i], unique) == 0) {
882 ua->prompt[ua->num_prompts] = bstrdup(prompt);
884 ua->unique[ua->num_prompts++] = bstrdup(unique);
886 ua->unique[ua->num_prompts++] = NULL;
891 * Display prompts and get user's choice
893 * Returns: -1 on error
894 * index base 0 on success, and choice
895 * is copied to prompt if not NULL
896 * prompt is set to the chosen prompt item string
898 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
899 char *prompt, int max_prompt)
902 char pmsg[MAXSTRING];
903 BSOCK *user = ua->UA_sock;
908 if (ua->num_prompts == 2) {
911 bstrncpy(prompt, ua->prompt[1], max_prompt);
913 ua->send_msg(_("Automatically selected %s: %s\n"), NPRTB(automsg), ua->prompt[1]);
916 /* If running non-interactive, bail out */
918 /* First print the choices he wanted to make */
919 ua->send_msg(ua->prompt[0]);
920 for (i=1; i < ua->num_prompts; i++) {
921 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
923 /* Now print error message */
924 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
928 if (ua->api) user->signal(BNET_START_SELECT);
929 ua->send_msg(ua->prompt[0]);
930 for (i=1; i < ua->num_prompts; i++) {
932 ua->send_msg("%s", ua->prompt[i]);
934 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
937 if (ua->api) user->signal(BNET_END_SELECT);
940 /* First item is the prompt string, not the items */
941 if (ua->num_prompts == 1) {
942 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
943 item = -1; /* list is empty ! */
946 if (ua->num_prompts == 2) {
948 ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
950 bstrncpy(prompt, ua->prompt[1], max_prompt);
954 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
956 /* Either a . or an @ will get you out of the loop */
957 if (ua->api) user->signal(BNET_SELECT_INPUT);
958 if (!get_pint(ua, pmsg)) {
959 item = -1; /* error */
960 ua->info_msg(_("Selection aborted, nothing done.\n"));
963 item = ua->pint32_val;
964 if (item < 1 || item >= ua->num_prompts) {
965 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
969 bstrncpy(prompt, ua->prompt[item], max_prompt);
975 for (i=0; i < ua->num_prompts; i++) {
977 if (ua->unique[i]) free(ua->unique[i]);
980 return item>0 ? item-1 : item;
984 * Display prompts and get user's choice
986 * Returns: -1 on error
987 * number of items selected and the choices are
988 * copied to selected if not NULL
989 * selected is an alist of the prompts chosen
990 * Note! selected must already be initialized.
992 int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
996 char pmsg[MAXSTRING];
997 BSOCK *user = ua->UA_sock;
1000 /* First item is the prompt string, not the items */
1001 if (ua->num_prompts == 1) {
1002 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
1003 item = -1; /* list is empty ! */
1006 if (ua->num_prompts == 2) {
1008 selected->append(bstrdup(ua->prompt[1]));
1009 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
1012 /* If running non-interactive, bail out */
1014 /* First print the choices he wanted to make */
1015 ua->send_msg(ua->prompt[0]);
1016 for (i=1; i < ua->num_prompts; i++) {
1017 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1019 /* Now print error message */
1020 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
1024 if (ua->api) user->signal(BNET_START_SELECT);
1025 ua->send_msg(ua->prompt[0]);
1026 for (i=1; i < ua->num_prompts; i++) {
1028 ua->send_msg("%s", ua->prompt[i]);
1030 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
1033 if (ua->api) user->signal(BNET_END_SELECT);
1035 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
1039 /* Either a . or an @ will get you out of the loop */
1040 if (ua->api) user->signal(BNET_SELECT_INPUT);
1042 if (!get_selection_list(ua, sl, pmsg, false)) {
1048 for (i=1; i < ua->num_prompts; i++) {
1049 selected->append(bstrdup(ua->prompt[i]));
1052 while ( (item = sl.next()) > 0) {
1053 if (item < 1 || item >= ua->num_prompts) {
1054 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
1058 selected->append(bstrdup(ua->prompt[item]));
1062 item = selected->size();
1068 for (i=0; i < ua->num_prompts; i++) {
1069 free(ua->prompt[i]);
1070 if (ua->unique[i]) free(ua->unique[i]);
1072 ua->num_prompts = 0;
1078 * We scan what the user has entered looking for
1079 * storage=<storage-resource>
1082 * ? (prompt him with storage list)
1083 * <some-error> (prompt him with storage list)
1085 * If use_default is set, we assume that any keyword without a value
1086 * is the name of the Storage resource wanted.
1088 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1090 char *store_name = NULL;
1091 STORE *store = NULL;
1097 for (i=1; i<ua->argc; i++) {
1098 if (use_default && !ua->argv[i]) {
1099 /* Ignore slots, scan and barcode(s) keywords */
1100 if (strcasecmp("scan", ua->argk[i]) == 0 ||
1101 strcasecmp("barcode", ua->argk[i]) == 0 ||
1102 strcasecmp("barcodes", ua->argk[i]) == 0 ||
1103 strcasecmp("slots", ua->argk[i]) == 0) {
1106 /* Default argument is storage */
1108 ua->error_msg(_("Storage name given twice.\n"));
1111 store_name = ua->argk[i];
1112 if (*store_name == '?') {
1117 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1118 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1119 store_name = ua->argv[i];
1122 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1123 jobid = str_to_int64(ua->argv[i]);
1125 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1128 if (!(jcr=get_jcr_by_id(jobid))) {
1129 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1132 store = jcr->wstore;
1136 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1137 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1139 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1142 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1143 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1146 store = jcr->wstore;
1149 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1151 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1154 if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1155 store = jcr->wstore;
1157 /* The job might not be running, so we try to see other keywords */
1165 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1169 if (!store && store_name && store_name[0] != 0) {
1170 store = (STORE *)GetResWithName(R_STORAGE, store_name);
1172 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1175 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1178 /* No keywords found, so present a selection list */
1180 store = select_storage_resource(ua, unique);
1185 /* Get drive that we are working with for this storage */
1186 int get_storage_drive(UAContext *ua, STORE *store)
1189 /* Get drive for autochanger if possible */
1190 i = find_arg_with_value(ua, "drive");
1192 drive = atoi(ua->argv[i]);
1193 } else if (store && store->autochanger) {
1194 /* If our structure is not set ask SD for # drives */
1195 if (store->drives == 0) {
1196 store->drives = get_num_drives_from_SD(ua);
1198 /* If only one drive, default = 0 */
1199 if (store->drives == 1) {
1202 /* Ask user to enter drive number */
1204 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1205 drive = -1; /* None */
1207 drive = atoi(ua->cmd);
1214 /* Get slot that we are working with for this storage */
1215 int get_storage_slot(UAContext *ua, STORE *store)
1218 /* Get slot for autochanger if possible */
1219 i = find_arg_with_value(ua, "slot");
1221 slot = atoi(ua->argv[i]);
1222 } else if (store && store->autochanger) {
1223 /* Ask user to enter slot number */
1225 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1226 slot = -1; /* None */
1228 slot = atoi(ua->cmd);
1237 * Scan looking for mediatype=
1239 * if not found or error, put up selection list
1241 * Returns: 0 on error
1242 * 1 on success, MediaType is set
1244 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1249 i = find_arg_with_value(ua, "mediatype");
1251 bstrncpy(MediaType, ua->argv[i], max_media);
1255 start_prompt(ua, _("Media Types defined in conf file:\n"));
1257 foreach_res(store, R_STORAGE) {
1258 add_prompt(ua, store->media_type);
1261 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1265 bool get_level_from_name(JCR *jcr, const char *level_name)
1267 /* Look up level name and pull code */
1269 for (int i=0; joblevels[i].level_name; i++) {
1270 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1271 jcr->setJobLevel(joblevels[i].level);
1279 static int count_running_jobs(UAContext *ua)
1281 int tjobs = 0; /* total # number jobs */
1284 /* Count Jobs running */
1286 if (jcr->JobId == 0) { /* this is us */
1289 tjobs++; /* count of all jobs */
1290 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1291 continue; /* skip not authorized */
1293 njobs++; /* count of authorized jobs */
1297 if (njobs == 0) { /* no authorized */
1299 ua->send_msg(_("No Jobs running.\n"));
1301 ua->send_msg(_("None of your jobs are running.\n"));
1308 /* Get a list of running jobs
1309 * "reason" is used in user messages
1310 * can be: cancel, limit, ...
1311 * Returns: -1 on error
1312 * nb of JCR on success (should be free_jcr() after)
1314 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1319 char JobName[MAX_NAME_LENGTH];
1321 alist *selected = NULL;
1323 for (i=1; i<ua->argc; i++) {
1324 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1329 ua->error_msg(_("No value given for \"jobid\".\n"));
1332 if (!sl.set_string(ua->argv[i], true)) {
1333 ua->send_msg("%s", sl.get_errmsg());
1336 foreach_sellist(JobId, &sl) {
1337 jcr = get_jcr_by_id(JobId);
1338 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1341 ua->error_msg(_("Unauthorized command from this console "
1342 "for JobId=%d.\n"), JobId);
1345 ua->warning_msg(_("Warning Job JobId=%d is not running.\n"), JobId);
1348 if (jcrs->size() == 0) {
1349 goto bail_out; /* If we did not find specified jobid, get out */
1353 /* TODO: might want to implement filters (client, status, etc...) */
1354 } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1356 if (jcr->JobId == 0) { /* Do not cancel consoles */
1359 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1360 continue; /* skip not authorized */
1362 jcr->inc_use_count();
1367 /* If we have something and no "yes" on command line, get confirmation */
1368 if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1370 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1371 reason, jcrs->size(), jcrs->size()>1?"s":"");
1372 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1376 if (jcrs->size() == 0) {
1377 goto bail_out; /* If we did not find specified jobid, get out */
1381 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1383 ua->error_msg(_("No value given for \"job\".\n"));
1386 jcr = get_jcr_by_partial_name(ua->argv[i]);
1388 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1393 ua->error_msg(_("Unauthorized command from this console "
1394 "for job=%s.\n"), ua->argv[i]);
1399 ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1401 if (jcrs->size() == 0) {
1402 goto bail_out; /* If we did not find specified jobid, get out */
1406 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1408 ua->error_msg(_("No value given for \"ujobid\".\n"));
1411 jcr = get_jcr_by_full_name(ua->argv[i]);
1413 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1418 ua->error_msg(_("Unauthorized command from this console "
1419 "for ujobid=%s.\n"), ua->argv[i]);
1424 ua->warning_msg(_("Warning Job %s is not running.\n"), ua->argv[i]);
1426 if (jcrs->size() == 0) {
1427 goto bail_out; /* If we did not find specified jobid, get out */
1433 if (jcrs->size() == 0) {
1435 * If we still do not have a jcr,
1436 * throw up a list and ask the user to select one.
1440 njobs = count_running_jobs(ua);
1444 start_prompt(ua, _("Select Job(s):\n"));
1447 if (jcr->JobId == 0) { /* this is us */
1450 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1451 add_prompt(ua, buf);
1454 bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1455 selected = New(alist(5, owned_by_alist));
1456 if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1459 /* Possibly ask for confirmation */
1460 if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1462 foreach_alist(item, selected) {
1463 ua->send_msg("%s\n", item);
1465 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1466 reason, selected->size(), selected->size()>1?"s":"");
1467 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1472 foreach_alist(item, selected) {
1473 if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1474 ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1477 jcr = get_jcr_by_full_name(JobName);
1481 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1486 if (selected) delete selected;
1487 return jcrs->size();