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);
954 /* Either a . or an @ will get you out of the loop */
955 if (ua->api) user->signal(BNET_SELECT_INPUT);
957 if (!get_selection_list(ua, sl, pmsg, false)) {
963 for (i=1; i < ua->num_prompts; i++) {
964 selected->append(bstrdup(ua->prompt[i]));
967 while ( (item = sl.next()) > 0) {
968 if (item < 1 || item >= ua->num_prompts) {
969 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
972 selected->append(bstrdup(ua->prompt[item]));
975 item = selected->size();
980 for (i=0; i < ua->num_prompts; i++) {
982 if (ua->unique[i]) free(ua->unique[i]);
990 * We scan what the user has entered looking for
991 * storage=<storage-resource>
994 * ? (prompt him with storage list)
995 * <some-error> (prompt him with storage list)
997 * If use_default is set, we assume that any keyword without a value
998 * is the name of the Storage resource wanted.
1000 STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
1002 char *store_name = NULL;
1003 STORE *store = NULL;
1009 for (i=1; i<ua->argc; i++) {
1010 if (use_default && !ua->argv[i]) {
1011 /* Ignore slots, scan and barcode(s) keywords */
1012 if (strcasecmp("scan", ua->argk[i]) == 0 ||
1013 strcasecmp("barcode", ua->argk[i]) == 0 ||
1014 strcasecmp("barcodes", ua->argk[i]) == 0 ||
1015 strcasecmp("slots", ua->argk[i]) == 0) {
1018 /* Default argument is storage */
1020 ua->error_msg(_("Storage name given twice.\n"));
1023 store_name = ua->argk[i];
1024 if (*store_name == '?') {
1029 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1030 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1031 store_name = ua->argv[i];
1034 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1035 jobid = str_to_int64(ua->argv[i]);
1037 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
1040 if (!(jcr=get_jcr_by_id(jobid))) {
1041 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
1044 store = jcr->wstore;
1048 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
1049 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
1051 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
1054 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1055 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
1058 store = jcr->wstore;
1061 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1063 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
1066 if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
1067 store = jcr->wstore;
1069 /* The job might not be running, so we try to see other keywords */
1077 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1081 if (!store && store_name && store_name[0] != 0) {
1082 store = (STORE *)GetResWithName(R_STORAGE, store_name);
1084 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
1087 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
1090 /* No keywords found, so present a selection list */
1092 store = select_storage_resource(ua, unique);
1097 /* Get drive that we are working with for this storage */
1098 int get_storage_drive(UAContext *ua, STORE *store)
1101 /* Get drive for autochanger if possible */
1102 i = find_arg_with_value(ua, "drive");
1104 drive = atoi(ua->argv[i]);
1105 } else if (store && store->autochanger) {
1106 /* If our structure is not set ask SD for # drives */
1107 if (store->drives == 0) {
1108 store->drives = get_num_drives_from_SD(ua);
1110 /* If only one drive, default = 0 */
1111 if (store->drives == 1) {
1114 /* Ask user to enter drive number */
1116 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
1117 drive = -1; /* None */
1119 drive = atoi(ua->cmd);
1126 /* Get slot that we are working with for this storage */
1127 int get_storage_slot(UAContext *ua, STORE *store)
1130 /* Get slot for autochanger if possible */
1131 i = find_arg_with_value(ua, "slot");
1133 slot = atoi(ua->argv[i]);
1134 } else if (store && store->autochanger) {
1135 /* Ask user to enter slot number */
1137 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1138 slot = -1; /* None */
1140 slot = atoi(ua->cmd);
1149 * Scan looking for mediatype=
1151 * if not found or error, put up selection list
1153 * Returns: 0 on error
1154 * 1 on success, MediaType is set
1156 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1161 i = find_arg_with_value(ua, "mediatype");
1163 bstrncpy(MediaType, ua->argv[i], max_media);
1167 start_prompt(ua, _("Media Types defined in conf file:\n"));
1169 foreach_res(store, R_STORAGE) {
1170 add_prompt(ua, store->media_type);
1173 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1177 bool get_level_from_name(JCR *jcr, const char *level_name)
1179 /* Look up level name and pull code */
1181 for (int i=0; joblevels[i].level_name; i++) {
1182 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1183 jcr->setJobLevel(joblevels[i].level);
1191 static int count_running_jobs(UAContext *ua)
1193 int tjobs = 0; /* total # number jobs */
1196 /* Count Jobs running */
1198 if (jcr->JobId == 0) { /* this is us */
1201 tjobs++; /* count of all jobs */
1202 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1203 continue; /* skip not authorized */
1205 njobs++; /* count of authorized jobs */
1209 if (njobs == 0) { /* no authorized */
1211 ua->send_msg(_("No Jobs running.\n"));
1213 ua->send_msg(_("None of your jobs are running.\n"));
1220 /* Get a list of running jobs
1221 * "reason" is used in user messages
1222 * can be: cancel, limit, ...
1223 * Returns: -1 on error
1224 * nb of JCR on success (should be free_jcr() after)
1226 int select_running_jobs(UAContext *ua, alist *jcrs, const char *reason)
1231 char JobName[MAX_NAME_LENGTH];
1233 alist *selected = NULL;
1235 for (i=1; i<ua->argc; i++) {
1236 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1240 if (sl.set_string(ua->argv[i], true) < 0 && sl.get_errmsg()) {
1241 ua->send_msg("%s", sl.get_errmsg());
1245 foreach_sellist(JobId, &sl) {
1246 jcr = get_jcr_by_id(JobId);
1247 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1251 ua->error_msg(_("Unauthorized command from this console "
1252 "for JobId=%d.\n"), JobId);
1256 if (debug_level > 5) {
1257 ua->warning_msg(_("Warning Job JobId=%d is not running. "
1258 "Continuing anyway...\n"), JobId);
1264 /* TODO: might want to implement filters (client, status, etc...) */
1265 } else if (strcasecmp(ua->argk[i], NT_("all")) == 0) {
1267 if (jcr->JobId == 0) { /* this is us */
1270 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1271 continue; /* skip not authorized */
1273 jcr->inc_use_count();
1278 if (jcrs->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1280 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1281 reason, jcrs->size(), jcrs->size()>1?"s":"");
1282 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1288 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1292 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1293 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1294 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1295 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1297 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1302 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1306 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
1307 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1308 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1309 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1311 if (jcr && jcr->job && acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1318 if (jcrs->size() == 0) {
1320 * If we still do not have a jcr,
1321 * throw up a list and ask the user to select one.
1325 njobs = count_running_jobs(ua);
1329 start_prompt(ua, _("Select Job(s):\n"));
1332 if (jcr->JobId == 0) { /* this is us */
1335 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1336 add_prompt(ua, buf);
1339 bsnprintf(temp, sizeof(temp), _("Choose Job list to %s"), _(reason));
1340 selected = New(alist(5, owned_by_alist));
1341 if (do_alist_prompt(ua, _("Job"), temp, selected) < 0) {
1344 /* Possibly ask for confirmation */
1345 if (selected->size() > 0 && find_arg(ua, NT_("yes")) < 0) {
1347 foreach_alist(item, selected) {
1348 ua->send_msg("%s\n", item);
1350 bsnprintf(nbuf, sizeof(nbuf), _("Confirm %s of %d Job%s (yes/no): "),
1351 reason, selected->size(), selected->size()>1?"s":"");
1352 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1357 foreach_alist(item, selected) {
1358 if (sscanf(item, "JobId=%d Job=%127s", &njobs, JobName) != 2) {
1359 ua->warning_msg(_("Job \"%s\" not found.\n"), item);
1362 jcr = get_jcr_by_full_name(JobName);
1366 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
1371 if (selected) delete selected;
1372 return jcrs->size();