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 three of the GNU Affero 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 Affero 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
39 /* Imported variables */
40 extern struct s_jl joblevels[];
44 * Confirm a retention period
46 int confirm_retention(UAContext *ua, utime_t *ret, const char *msg)
51 int yes_in_arg = find_arg(ua, NT_("yes"));
54 ua->info_msg(_("The current %s retention period is: %s\n"),
55 msg, edit_utime(*ret, ed1, sizeof(ed1)));
56 if (yes_in_arg != -1) {
59 if (!get_cmd(ua, _("Continue? (yes/mod/no): "))) {
62 if (strcasecmp(ua->cmd, _("mod")) == 0) {
63 if (!get_cmd(ua, _("Enter new retention period: "))) {
66 if (!duration_to_utime(ua->cmd, ret)) {
67 ua->error_msg(_("Invalid period.\n"));
72 if (is_yesno(ua->cmd, &val)) {
73 return val; /* is 1 for yes, 0 for no */
80 * Given a list of keywords, find the first one
81 * that is in the argument list.
82 * Returns: -1 if not found
83 * index into list (base 0) on success
85 int find_arg_keyword(UAContext *ua, const char **list)
87 for (int i=1; i<ua->argc; i++) {
88 for(int j=0; list[j]; j++) {
89 if (strcasecmp(list[j], ua->argk[i]) == 0) {
98 * Given one keyword, find the first one that
99 * is in the argument list.
100 * Returns: argk index (always gt 0)
103 int find_arg(UAContext *ua, const char *keyword)
105 for (int i=1; i<ua->argc; i++) {
106 if (strcasecmp(keyword, ua->argk[i]) == 0) {
114 * Given a single keyword, find it in the argument list, but
115 * it must have a value
116 * Returns: -1 if not found or no value
117 * list index (base 0) on success
119 int find_arg_with_value(UAContext *ua, const char *keyword)
121 for (int i=1; i<ua->argc; i++) {
122 if (strcasecmp(keyword, ua->argk[i]) == 0) {
134 * Given a list of keywords, prompt the user
137 * Returns: -1 on failure
138 * index into list (base 0) on success
140 int do_keyword_prompt(UAContext *ua, const char *msg, const char **list)
143 start_prompt(ua, _("You have the following choices:\n"));
144 for (i=0; list[i]; i++) {
145 add_prompt(ua, list[i]);
147 return do_prompt(ua, "", msg, NULL, 0);
152 * Select a Storage resource from prompt list
154 STORE *select_storage_resource(UAContext *ua)
156 char name[MAX_NAME_LENGTH];
159 start_prompt(ua, _("The defined Storage resources are:\n"));
161 foreach_res(store, R_STORAGE) {
162 if (acl_access_ok(ua, Storage_ACL, store->name())) {
163 add_prompt(ua, store->name());
167 if (do_prompt(ua, _("Storage"), _("Select Storage resource"), name, sizeof(name)) < 0) {
170 store = (STORE *)GetResWithName(R_STORAGE, name);
175 * Select a FileSet resource from prompt list
177 FILESET *select_fileset_resource(UAContext *ua)
179 char name[MAX_NAME_LENGTH];
182 start_prompt(ua, _("The defined FileSet resources are:\n"));
184 foreach_res(fs, R_FILESET) {
185 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
186 add_prompt(ua, fs->name());
190 if (do_prompt(ua, _("FileSet"), _("Select FileSet resource"), name, sizeof(name)) < 0) {
193 fs = (FILESET *)GetResWithName(R_FILESET, name);
199 * Get a catalog resource from prompt list
201 CAT *get_catalog_resource(UAContext *ua)
203 char name[MAX_NAME_LENGTH];
207 for (i=1; i<ua->argc; i++) {
208 if (strcasecmp(ua->argk[i], NT_("catalog")) == 0 && ua->argv[i]) {
209 if (acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
210 catalog = (CAT *)GetResWithName(R_CATALOG, ua->argv[i]);
215 if (ua->gui && !catalog) {
217 catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
220 ua->error_msg(_("Could not find a Catalog resource\n"));
222 } else if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
223 ua->error_msg(_("You must specify a \"use <catalog-name>\" command before continuing.\n"));
229 start_prompt(ua, _("The defined Catalog resources are:\n"));
231 foreach_res(catalog, R_CATALOG) {
232 if (acl_access_ok(ua, Catalog_ACL, catalog->name())) {
233 add_prompt(ua, catalog->name());
237 if (do_prompt(ua, _("Catalog"), _("Select Catalog resource"), name, sizeof(name)) < 0) {
240 catalog = (CAT *)GetResWithName(R_CATALOG, name);
247 * Select a job to enable or disable
249 JOB *select_enable_disable_job_resource(UAContext *ua, bool enable)
251 char name[MAX_NAME_LENGTH];
255 start_prompt(ua, _("The defined Job resources are:\n"));
256 foreach_res(job, R_JOB) {
257 if (!acl_access_ok(ua, Job_ACL, job->name())) {
260 if (job->enabled == enable) { /* Already enabled/disabled? */
261 continue; /* yes, skip */
263 add_prompt(ua, job->name());
266 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
269 job = (JOB *)GetResWithName(R_JOB, name);
274 * Select a Job resource from prompt list
276 JOB *select_job_resource(UAContext *ua)
278 char name[MAX_NAME_LENGTH];
281 start_prompt(ua, _("The defined Job resources are:\n"));
283 foreach_res(job, R_JOB) {
284 if (acl_access_ok(ua, Job_ACL, job->name())) {
285 add_prompt(ua, job->name());
289 if (do_prompt(ua, _("Job"), _("Select Job resource"), name, sizeof(name)) < 0) {
292 job = (JOB *)GetResWithName(R_JOB, name);
297 * Select a Restore Job resource from prompt list
299 JOB *select_restore_job_resource(UAContext *ua)
301 char name[MAX_NAME_LENGTH];
304 start_prompt(ua, _("The defined Restore Job resources are:\n"));
306 foreach_res(job, R_JOB) {
307 if (job->JobType == JT_RESTORE && acl_access_ok(ua, Job_ACL, job->name())) {
308 add_prompt(ua, job->name());
312 if (do_prompt(ua, _("Job"), _("Select Restore Job"), name, sizeof(name)) < 0) {
315 job = (JOB *)GetResWithName(R_JOB, name);
322 * Select a client resource from prompt list
324 CLIENT *select_client_resource(UAContext *ua)
326 char name[MAX_NAME_LENGTH];
329 start_prompt(ua, _("The defined Client resources are:\n"));
331 foreach_res(client, R_CLIENT) {
332 if (acl_access_ok(ua, Client_ACL, client->name())) {
333 add_prompt(ua, client->name());
337 if (do_prompt(ua, _("Client"), _("Select Client (File daemon) resource"), name, sizeof(name)) < 0) {
340 client = (CLIENT *)GetResWithName(R_CLIENT, name);
345 * Get client resource, start by looking for
346 * client=<client-name>
347 * if we don't find the keyword, we prompt the user.
349 CLIENT *get_client_resource(UAContext *ua)
351 CLIENT *client = NULL;
354 for (i=1; i<ua->argc; i++) {
355 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
356 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
357 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
360 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
364 ua->error_msg(_("Error: Client resource %s does not exist.\n"), ua->argv[i]);
368 return select_client_resource(ua);
371 /* Scan what the user has entered looking for:
373 * client=<client-name>
375 * if error or not found, put up a list of client DBRs
378 * returns: 0 on error
379 * 1 on success and fills in CLIENT_DBR
381 bool get_client_dbr(UAContext *ua, CLIENT_DBR *cr)
385 if (cr->Name[0]) { /* If name already supplied */
386 if (db_get_client_record(ua->jcr, ua->db, cr)) {
389 ua->error_msg(_("Could not find Client %s: ERR=%s"), cr->Name, db_strerror(ua->db));
391 for (i=1; i<ua->argc; i++) {
392 if ((strcasecmp(ua->argk[i], NT_("client")) == 0 ||
393 strcasecmp(ua->argk[i], NT_("fd")) == 0) && ua->argv[i]) {
394 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
397 bstrncpy(cr->Name, ua->argv[i], sizeof(cr->Name));
398 if (!db_get_client_record(ua->jcr, ua->db, cr)) {
399 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), ua->argv[i],
400 db_strerror(ua->db));
407 if (!select_client_dbr(ua, cr)) { /* try once more by proposing a list */
414 * Select a Client record from the catalog
415 * Returns 1 on success
418 bool select_client_dbr(UAContext *ua, CLIENT_DBR *cr)
421 char name[MAX_NAME_LENGTH];
427 if (!db_get_client_ids(ua->jcr, ua->db, &num_clients, &ids)) {
428 ua->error_msg(_("Error obtaining client ids. ERR=%s\n"), db_strerror(ua->db));
431 if (num_clients <= 0) {
432 ua->error_msg(_("No clients defined. You must run a job before using this command.\n"));
436 start_prompt(ua, _("Defined Clients:\n"));
437 for (i=0; i < num_clients; i++) {
438 ocr.ClientId = ids[i];
439 if (!db_get_client_record(ua->jcr, ua->db, &ocr) ||
440 !acl_access_ok(ua, Client_ACL, ocr.Name)) {
443 add_prompt(ua, ocr.Name);
446 if (do_prompt(ua, _("Client"), _("Select the Client"), name, sizeof(name)) < 0) {
449 memset(&ocr, 0, sizeof(ocr));
450 bstrncpy(ocr.Name, name, sizeof(ocr.Name));
452 if (!db_get_client_record(ua->jcr, ua->db, &ocr)) {
453 ua->error_msg(_("Could not find Client \"%s\": ERR=%s"), name, db_strerror(ua->db));
456 memcpy(cr, &ocr, sizeof(ocr));
460 /* Scan what the user has entered looking for:
464 * where argk can be : pool, recyclepool, scratchpool, nextpool etc..
466 * if error or not found, put up a list of pool DBRs
469 * returns: false on error
470 * true on success and fills in POOL_DBR
472 bool get_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
474 if (pr->Name[0]) { /* If name already supplied */
475 if (db_get_pool_record(ua->jcr, ua->db, pr) &&
476 acl_access_ok(ua, Pool_ACL, pr->Name)) {
479 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), pr->Name, db_strerror(ua->db));
481 if (!select_pool_dbr(ua, pr, argk)) { /* try once more */
488 * Select a Pool record from catalog
489 * argk can be pool, recyclepool, scratchpool etc..
491 bool select_pool_dbr(UAContext *ua, POOL_DBR *pr, const char *argk)
494 char name[MAX_NAME_LENGTH];
498 for (i=1; i<ua->argc; i++) {
499 if (strcasecmp(ua->argk[i], argk) == 0 && ua->argv[i] &&
500 acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
501 bstrncpy(pr->Name, ua->argv[i], sizeof(pr->Name));
502 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
503 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), ua->argv[i],
504 db_strerror(ua->db));
513 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
514 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db));
517 if (num_pools <= 0) {
518 ua->error_msg(_("No pools defined. Use the \"create\" command to create one.\n"));
522 start_prompt(ua, _("Defined Pools:\n"));
523 if (bstrcmp(argk, NT_("recyclepool"))) {
524 add_prompt(ua, _("*None*"));
526 for (i=0; i < num_pools; i++) {
528 if (!db_get_pool_record(ua->jcr, ua->db, &opr) ||
529 !acl_access_ok(ua, Pool_ACL, opr.Name)) {
532 add_prompt(ua, opr.Name);
535 if (do_prompt(ua, _("Pool"), _("Select the Pool"), name, sizeof(name)) < 0) {
539 memset(&opr, 0, sizeof(opr));
540 /* *None* is only returned when selecting a recyclepool, and in that case
541 * the calling code is only interested in opr.Name, so then we can leave
544 if (!bstrcmp(name, _("*None*"))) {
545 bstrncpy(opr.Name, name, sizeof(opr.Name));
547 if (!db_get_pool_record(ua->jcr, ua->db, &opr)) {
548 ua->error_msg(_("Could not find Pool \"%s\": ERR=%s"), name, db_strerror(ua->db));
553 memcpy(pr, &opr, sizeof(opr));
558 * Select a Pool and a Media (Volume) record from the database
560 int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr)
563 if (!select_media_dbr(ua, mr)) {
566 memset(pr, 0, sizeof(POOL_DBR));
567 pr->PoolId = mr->PoolId;
568 if (!db_get_pool_record(ua->jcr, ua->db, pr)) {
569 ua->error_msg("%s", db_strerror(ua->db));
572 if (!acl_access_ok(ua, Pool_ACL, pr->Name)) {
573 ua->error_msg(_("No access to Pool \"%s\"\n"), pr->Name);
579 /* Select a Media (Volume) record from the database */
580 int select_media_dbr(UAContext *ua, MEDIA_DBR *mr)
584 memset(mr, 0, sizeof(MEDIA_DBR));
586 i = find_arg_with_value(ua, "volume");
588 bstrncpy(mr->VolumeName, ua->argv[i], sizeof(mr->VolumeName));
590 if (mr->VolumeName[0] == 0) {
592 memset(&pr, 0, sizeof(pr));
593 /* Get the pool from pool=<pool-name> */
594 if (!get_pool_dbr(ua, &pr)) {
597 mr->PoolId = pr.PoolId;
598 db_list_media_records(ua->jcr, ua->db, mr, prtit, ua, HORZ_LIST);
599 if (!get_cmd(ua, _("Enter *MediaId or Volume name: "))) {
602 if (ua->cmd[0] == '*' && is_a_number(ua->cmd+1)) {
603 mr->MediaId = str_to_int64(ua->cmd+1);
605 bstrncpy(mr->VolumeName, ua->cmd, sizeof(mr->VolumeName));
609 if (!db_get_media_record(ua->jcr, ua->db, mr)) {
610 ua->error_msg("%s", db_strerror(ua->db));
618 * Select a pool resource from prompt list
620 POOL *select_pool_resource(UAContext *ua)
622 char name[MAX_NAME_LENGTH];
625 start_prompt(ua, _("The defined Pool resources are:\n"));
627 foreach_res(pool, R_POOL) {
628 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
629 add_prompt(ua, pool->name());
633 if (do_prompt(ua, _("Pool"), _("Select Pool resource"), name, sizeof(name)) < 0) {
636 pool = (POOL *)GetResWithName(R_POOL, name);
642 * If you are thinking about using it, you
643 * probably want to use select_pool_dbr()
644 * or get_pool_dbr() above.
646 POOL *get_pool_resource(UAContext *ua)
651 i = find_arg_with_value(ua, "pool");
652 if (i >= 0 && acl_access_ok(ua, Pool_ACL, ua->argv[i])) {
653 pool = (POOL *)GetResWithName(R_POOL, ua->argv[i]);
657 ua->error_msg(_("Error: Pool resource \"%s\" does not exist.\n"), ua->argv[i]);
659 return select_pool_resource(ua);
663 * List all jobs and ask user to select one
665 int select_job_dbr(UAContext *ua, JOB_DBR *jr)
667 db_list_job_records(ua->jcr, ua->db, jr, prtit, ua, HORZ_LIST);
668 if (!get_pint(ua, _("Enter the JobId to select: "))) {
671 jr->JobId = ua->int64_val;
672 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
673 ua->error_msg("%s", db_strerror(ua->db));
681 /* Scan what the user has entered looking for:
685 * if error or not found, put up a list of Jobs
688 * returns: 0 on error
689 * JobId on success and fills in JOB_DBR
691 int get_job_dbr(UAContext *ua, JOB_DBR *jr)
695 for (i=1; i<ua->argc; i++) {
696 if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
698 bstrncpy(jr->Job, ua->argv[i], sizeof(jr->Job));
699 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0 && ua->argv[i]) {
700 jr->JobId = str_to_int64(ua->argv[i]);
705 if (!db_get_job_record(ua->jcr, ua->db, jr)) {
706 ua->error_msg(_("Could not find Job \"%s\": ERR=%s"), ua->argv[i],
707 db_strerror(ua->db));
717 for (i=1; i<ua->argc; i++) {
718 if ((strcasecmp(ua->argk[i], NT_("jobname")) == 0 ||
719 strcasecmp(ua->argk[i], NT_("job")) == 0) && ua->argv[i]) {
721 bstrncpy(jr->Name, ua->argv[i], sizeof(jr->Name));
725 if (!select_job_dbr(ua, jr)) { /* try once more */
732 * Implement unique set of prompts
734 void start_prompt(UAContext *ua, const char *msg)
736 if (ua->max_prompts == 0) {
737 ua->max_prompts = 10;
738 ua->prompt = (char **)bmalloc(sizeof(char *) * ua->max_prompts);
741 ua->prompt[0] = bstrdup(msg);
745 * Add to prompts -- keeping them unique
747 void add_prompt(UAContext *ua, const char *prompt)
750 if (ua->num_prompts == ua->max_prompts) {
751 ua->max_prompts *= 2;
752 ua->prompt = (char **)brealloc(ua->prompt, sizeof(char *) *
755 for (i=1; i < ua->num_prompts; i++) {
756 if (strcmp(ua->prompt[i], prompt) == 0) {
760 ua->prompt[ua->num_prompts++] = bstrdup(prompt);
764 * Display prompts and get user's choice
766 * Returns: -1 on error
767 * index base 0 on success, and choice
768 * is copied to prompt if not NULL
769 * prompt is set to the chosen prompt item string
771 int do_prompt(UAContext *ua, const char *automsg, const char *msg,
772 char *prompt, int max_prompt)
775 char pmsg[MAXSTRING];
776 BSOCK *user = ua->UA_sock;
781 if (ua->num_prompts == 2) {
784 bstrncpy(prompt, ua->prompt[1], max_prompt);
786 ua->send_msg(_("Automatically selected %s: %s\n"), automsg, ua->prompt[1]);
789 /* If running non-interactive, bail out */
791 /* First print the choices he wanted to make */
792 ua->send_msg(ua->prompt[0]);
793 for (i=1; i < ua->num_prompts; i++) {
794 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
796 /* Now print error message */
797 ua->send_msg(_("Your request has multiple choices for \"%s\". Selection is not possible in batch mode.\n"), automsg);
801 if (ua->api) user->signal(BNET_START_SELECT);
802 ua->send_msg(ua->prompt[0]);
803 for (i=1; i < ua->num_prompts; i++) {
805 ua->send_msg("%s", ua->prompt[i]);
807 ua->send_msg("%6d: %s\n", i, ua->prompt[i]);
810 if (ua->api) user->signal(BNET_END_SELECT);
813 /* First item is the prompt string, not the items */
814 if (ua->num_prompts == 1) {
815 ua->error_msg(_("Selection list for \"%s\" is empty!\n"), automsg);
816 item = -1; /* list is empty ! */
819 if (ua->num_prompts == 2) {
821 ua->send_msg(_("Automatically selected: %s\n"), ua->prompt[1]);
823 bstrncpy(prompt, ua->prompt[1], max_prompt);
827 sprintf(pmsg, "%s (1-%d): ", msg, ua->num_prompts-1);
829 /* Either a . or an @ will get you out of the loop */
830 if (ua->api) user->signal(BNET_SELECT_INPUT);
831 if (!get_pint(ua, pmsg)) {
832 item = -1; /* error */
833 ua->info_msg(_("Selection aborted, nothing done.\n"));
836 item = ua->pint32_val;
837 if (item < 1 || item >= ua->num_prompts) {
838 ua->warning_msg(_("Please enter a number between 1 and %d\n"), ua->num_prompts-1);
842 bstrncpy(prompt, ua->prompt[item], max_prompt);
848 for (i=0; i < ua->num_prompts; i++) {
852 return item>0 ? item-1 : item;
857 * We scan what the user has entered looking for
858 * storage=<storage-resource>
861 * ? (prompt him with storage list)
862 * <some-error> (prompt him with storage list)
864 * If use_default is set, we assume that any keyword without a value
865 * is the name of the Storage resource wanted.
867 STORE *get_storage_resource(UAContext *ua, bool use_default)
869 char *store_name = NULL;
876 for (i=1; i<ua->argc; i++) {
877 if (use_default && !ua->argv[i]) {
878 /* Ignore slots, scan and barcode(s) keywords */
879 if (strcasecmp("scan", ua->argk[i]) == 0 ||
880 strcasecmp("barcode", ua->argk[i]) == 0 ||
881 strcasecmp("barcodes", ua->argk[i]) == 0 ||
882 strcasecmp("slots", ua->argk[i]) == 0) {
885 /* Default argument is storage */
887 ua->error_msg(_("Storage name given twice.\n"));
890 store_name = ua->argk[i];
891 if (*store_name == '?') {
896 if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
897 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
898 store_name = ua->argv[i];
901 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
902 jobid = str_to_int64(ua->argv[i]);
904 ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
907 if (!(jcr=get_jcr_by_id(jobid))) {
908 ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
915 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0 ||
916 strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
918 ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
921 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
922 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
928 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
930 ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
933 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
934 ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
943 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
947 if (!store && store_name && store_name[0] != 0) {
948 store = (STORE *)GetResWithName(R_STORAGE, store_name);
950 ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
953 if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
956 /* No keywords found, so present a selection list */
958 store = select_storage_resource(ua);
963 /* Get drive that we are working with for this storage */
964 int get_storage_drive(UAContext *ua, STORE *store)
967 /* Get drive for autochanger if possible */
968 i = find_arg_with_value(ua, "drive");
970 drive = atoi(ua->argv[i]);
971 } else if (store && store->autochanger) {
972 /* If our structure is not set ask SD for # drives */
973 if (store->drives == 0) {
974 store->drives = get_num_drives_from_SD(ua);
976 /* If only one drive, default = 0 */
977 if (store->drives == 1) {
980 /* Ask user to enter drive number */
982 if (!get_cmd(ua, _("Enter autochanger drive[0]: "))) {
983 drive = -1; /* None */
985 drive = atoi(ua->cmd);
992 /* Get slot that we are working with for this storage */
993 int get_storage_slot(UAContext *ua, STORE *store)
996 /* Get slot for autochanger if possible */
997 i = find_arg_with_value(ua, "slot");
999 slot = atoi(ua->argv[i]);
1000 } else if (store && store->autochanger) {
1001 /* Ask user to enter slot number */
1003 if (!get_cmd(ua, _("Enter autochanger slot: "))) {
1004 slot = -1; /* None */
1006 slot = atoi(ua->cmd);
1015 * Scan looking for mediatype=
1017 * if not found or error, put up selection list
1019 * Returns: 0 on error
1020 * 1 on success, MediaType is set
1022 int get_media_type(UAContext *ua, char *MediaType, int max_media)
1027 i = find_arg_with_value(ua, "mediatype");
1029 bstrncpy(MediaType, ua->argv[i], max_media);
1033 start_prompt(ua, _("Media Types defined in conf file:\n"));
1035 foreach_res(store, R_STORAGE) {
1036 add_prompt(ua, store->media_type);
1039 return (do_prompt(ua, _("Media Type"), _("Select the Media Type"), MediaType, max_media) < 0) ? 0 : 1;
1042 bool get_level_from_name(JCR *jcr, const char *level_name)
1044 /* Look up level name and pull code */
1046 for (int i=0; joblevels[i].level_name; i++) {
1047 if (strcasecmp(level_name, joblevels[i].level_name) == 0) {
1048 jcr->set_JobLevel(joblevels[i].level);
1056 /* Get a running job
1057 * "reason" is used in user messages
1058 * can be: cancel, limit, ...
1059 * Returns: NULL on error
1060 * JCR on success (should be free_jcr() after)
1062 JCR *select_running_job(UAContext *ua, const char *reason)
1067 char JobName[MAX_NAME_LENGTH];
1070 for (i=1; i<ua->argc; i++) {
1071 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
1073 JobId = str_to_int64(ua->argv[i]);
1077 if (!(jcr=get_jcr_by_id(JobId))) {
1078 ua->error_msg(_("JobId %s is not running. Use Job name to %s inactive jobs.\n"), ua->argv[i], _(reason));
1082 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1086 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
1087 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1088 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1089 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1092 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
1096 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
1097 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
1098 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
1099 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
1106 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1107 ua->error_msg(_("Unauthorized command from this console.\n"));
1112 * If we still do not have a jcr,
1113 * throw up a list and ask the user to select one.
1116 int tjobs = 0; /* total # number jobs */
1117 /* Count Jobs running */
1119 if (jcr->JobId == 0) { /* this is us */
1122 tjobs++; /* count of all jobs */
1123 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1124 continue; /* skip not authorized */
1126 njobs++; /* count of authorized jobs */
1130 if (njobs == 0) { /* no authorized */
1132 ua->send_msg(_("No Jobs running.\n"));
1134 ua->send_msg(_("None of your jobs are running.\n"));
1139 start_prompt(ua, _("Select Job:\n"));
1142 if (jcr->JobId == 0) { /* this is us */
1145 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
1146 continue; /* skip not authorized */
1148 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
1149 add_prompt(ua, buf);
1152 bsnprintf(temp, sizeof(temp), _("Choose Job to %s"), _(reason));
1153 if (do_prompt(ua, _("Job"), temp, buf, sizeof(buf)) < 0) {
1156 if (!strcmp(reason, "cancel")) {
1157 if (ua->api && njobs == 1) {
1159 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
1160 _("Confirm cancel?"));
1161 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
1166 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
1172 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
1173 jcr = get_jcr_by_full_name(JobName);
1175 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);