2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * Bacula Director -- Run Command
24 * Kern Sibbald, December MMI
31 const char *get_command(int index);
35 char *job_name, *level_name, *jid, *store_name, *pool_name;
36 char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
37 char *restore_client_name, *comment, *media_type, *next_pool_name;
39 char *when, *verify_job_name, *catalog_name;
40 char *previous_job_name;
43 const char *verify_list;
67 int ignoreduplicatecheck;
68 bool ignoreduplicatecheck_set;
70 run_ctx() { memset(this, 0, sizeof(run_ctx));
71 store = new USTORE; };
80 /* Forward referenced subroutines */
81 static void select_job_level(UAContext *ua, JCR *jcr);
82 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
83 const char *verify_list, char *jid, const char *replace,
85 static void select_where_regexp(UAContext *ua, JCR *jcr);
86 static bool scan_run_command_line_arguments(UAContext *ua, run_ctx &rc);
87 static bool set_run_context_in_jcr(UAContext *ua, JCR *jcr, run_ctx &rc);
88 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
89 static JobId_t start_job(UAContext *ua, JCR *jcr, run_ctx &rc);
91 /* Imported variables */
92 extern struct s_kw ReplaceOptions[];
95 * For Backup and Verify Jobs
96 * run [job=]<job-name> level=<level-name>
101 * Returns: 0 on error
105 int run_cmd(UAContext *ua, const char *cmd)
111 if (!open_client_db(ua)) {
115 if (!scan_run_command_line_arguments(ua, rc)) {
119 if (find_arg(ua, NT_("fdcalled")) > 0) {
120 jcr->file_bsock = dup_bsock(ua->UA_sock);
126 * Create JCR to run job. NOTE!!! after this point, free_jcr()
130 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
131 set_jcr_defaults(jcr, rc.job);
132 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
133 ua->jcr->unlink_bsr = false;
135 /* Transfer JobIds to new restore Job */
136 if (ua->jcr->JobIds) {
137 jcr->JobIds = ua->jcr->JobIds;
138 ua->jcr->JobIds = NULL;
140 /* Transfer VSS component info */
141 if (ua->jcr->component_fname) {
142 jcr->component_fname = ua->jcr->component_fname;
143 ua->jcr->component_fname = NULL;
144 jcr->component_fd = ua->jcr->component_fd;
145 ua->jcr->component_fd = NULL;
148 if (!set_run_context_in_jcr(ua, jcr, rc)) {
149 break; /* error get out of while loop */
152 /* Run without prompting? */
153 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
154 return start_job(ua, jcr, rc);
158 * Prompt User to see if all run job parameters are correct, and
159 * allow him to modify them.
161 if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
163 break; /* error get out of while loop */
166 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
167 break; /* error get out of while loop */
170 if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
171 (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
174 if (!scan_run_command_line_arguments(ua, rc)) {
175 break; /* error get out of while loop */
177 continue; /* another round with while loop */
180 /* Allow the user to modify the settings */
181 status = modify_job_parameters(ua, jcr, rc);
183 continue; /* another round with while loop */
185 if (status == -1) { /* error */
186 break; /* error get out of while loop */
189 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
190 return start_job(ua, jcr, rc);
192 if (strncasecmp(ua->cmd, _("no"), strlen(ua->cmd)) == 0) {
193 break; /* get out of while loop */
195 ua->send_msg(_("\nBad response: %s. You must answer yes, mod, or no.\n\n"), ua->cmd);
199 ua->send_msg(_("Job not run.\n"));
200 if (ua->jcr->component_fd) {
201 fclose(ua->jcr->component_fd);
202 ua->jcr->component_fd = NULL;
204 if (ua->jcr->component_fname) {
205 unlink(ua->jcr->component_fname);
206 free_and_null_pool_memory(ua->jcr->component_fname);
209 if (jcr->component_fd) {
210 fclose(jcr->component_fd);
211 jcr->component_fd = NULL;
213 if (jcr->component_fname) {
214 unlink(jcr->component_fname);
215 free_and_null_pool_memory(jcr->component_fname);
219 return 0; /* do not run */
222 static JobId_t start_job(UAContext *ua, JCR *jcr, run_ctx &rc)
226 if (rc.jr.JobStatus == JS_Incomplete) {
227 Dmsg1(100, "Ressuming JobId=%d\n", rc.jr.JobId);
228 JobId = resume_job(jcr, &rc.jr);
230 Dmsg1(100, "Starting JobId=%d\n", rc.jr.JobId);
231 JobId = run_job(jcr);
233 Dmsg4(100, "JobId=%u NewJobId=%d pool=%s priority=%d\n", (int)jcr->JobId,
234 JobId, jcr->pool->name(), jcr->JobPriority);
235 free_jcr(jcr); /* release jcr */
237 ua->error_msg(_("Job failed.\n"));
240 ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
246 * If no job_name defined in the run context, ask
248 * Then put the job resource in the run context and
249 * check the access rights.
251 static bool get_job(UAContext *ua, run_ctx &rc)
255 rc.job = GetJobResWithName(rc.job_name);
257 if (*rc.job_name != 0) {
258 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
260 rc.job = select_job_resource(ua);
262 Dmsg1(100, "Found job=%s\n", rc.job_name);
264 } else if (!rc.job) {
265 ua->send_msg(_("A job name must be specified.\n"));
266 rc.job = select_job_resource(ua);
270 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
271 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
278 * If no pool_name defined in the run context, ask
280 * Then put the pool resource in the run context and
281 * check the access rights.
283 static bool get_pool(UAContext *ua, run_ctx &rc)
286 rc.pool = GetPoolResWithName(rc.pool_name);
288 if (*rc.pool_name != 0) {
289 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
291 rc.pool = select_pool_resource(ua);
293 } else if (!rc.pool) {
294 rc.pool = rc.job->pool; /* use default */
298 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
299 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
302 Dmsg1(100, "Using Pool=%s\n", rc.pool->name());
306 static bool get_next_pool(UAContext *ua, run_ctx &rc)
308 if (rc.next_pool_name) {
309 Dmsg1(100, "Have next pool=%s\n", rc.next_pool_name);
310 rc.next_pool = GetPoolResWithName(rc.next_pool_name);
312 if (*rc.next_pool_name != 0) {
313 ua->warning_msg(_("NextPool \"%s\" not found.\n"), rc.next_pool_name);
315 rc.next_pool = select_pool_resource(ua);
318 /* NextPool can come from Job resource NextPool or Pool resource NextPool */
320 if (rc.job->next_pool) {
321 rc.next_pool = rc.job->next_pool;
323 rc.next_pool = rc.pool->NextPool; /* use default */
326 if (rc.next_pool && !acl_access_ok(ua, Pool_ACL, rc.next_pool->name())) {
327 ua->error_msg(_("No authorization. NextPool \"%s\".\n"), rc.next_pool->name());
331 Dmsg1(100, "Using NextPool=%s\n", NPRT(rc.next_pool->name()));
338 * Fill in client data according to what is setup
339 * in the run context, and make sure the user
340 * has authorized access to it.
342 static bool get_client(UAContext *ua, run_ctx &rc)
344 if (rc.client_name) {
345 rc.client = GetClientResWithName(rc.client_name);
347 if (*rc.client_name != 0) {
348 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
350 rc.client = select_client_resource(ua);
352 } else if (!rc.client) {
353 rc.client = rc.job->client; /* use default */
357 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
358 ua->error_msg(_("No authorization. Client \"%s\".\n"),
362 Dmsg1(800, "Using client=%s\n", rc.client->name());
364 if (rc.restore_client_name) {
365 rc.client = GetClientResWithName(rc.restore_client_name);
367 if (*rc.restore_client_name != 0) {
368 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
370 rc.client = select_client_resource(ua);
372 } else if (!rc.client) {
373 rc.client = rc.job->client; /* use default */
377 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
378 ua->error_msg(_("No authorization. Client \"%s\".\n"),
382 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
388 * Fill in fileset data according to what is setup
389 * in the run context, and make sure the user
390 * has authorized access to it.
392 static bool get_fileset(UAContext *ua, run_ctx &rc)
394 if (rc.fileset_name) {
395 rc.fileset = GetFileSetResWithName(rc.fileset_name);
397 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
398 rc.fileset = select_fileset_resource(ua);
400 } else if (!rc.fileset) {
401 rc.fileset = rc.job->fileset; /* use default */
405 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
406 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
414 * Fill in storage data according to what is setup
415 * in the run context, and make sure the user
416 * has authorized access to it.
418 static bool get_storage(UAContext *ua, run_ctx &rc)
421 rc.store->store = GetStoreResWithName(rc.store_name);
422 pm_strcpy(rc.store->store_source, _("command line"));
423 if (!rc.store->store) {
424 if (*rc.store_name != 0) {
425 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
427 rc.store->store = select_storage_resource(ua);
428 pm_strcpy(rc.store->store_source, _("user selection"));
430 } else if (!rc.store->store) {
431 get_job_storage(rc.store, rc.job, NULL); /* use default */
433 if (!rc.store->store) {
434 ua->error_msg(_("No storage specified.\n"));
436 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
437 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
438 rc.store->store->name());
441 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
446 * Get and pass back a list of Jobids in rc.jid
448 static bool get_jobid_list(UAContext *ua, sellist &sl, run_ctx &rc)
455 memset(&jr, 0, sizeof(jr));
457 /* See if any JobId is specified */
458 if ((i=find_arg(ua, "jobid")) >= 0) {
459 rc.jid = ua->argv[i];
461 ua->send_msg(_("No JobId specified.\n"));
464 if (!sl.set_string(ua->argv[i], true)) {
465 ua->send_msg("%s", sl.get_errmsg());
471 /* No JobId list give, so see if he specified a Job */
472 if ((i=find_arg(ua, "job")) >= 0) {
473 rc.job_name = ua->argv[i];
474 if (!get_job(ua, rc)) {
475 ua->send_msg(_("Invalid or no Job name specified.\n"));
479 jr.limit = 100; /* max 100 records */
481 bstrncpy(jr.Name, rc.job_name, sizeof(jr.Name));
485 jr.JobStatus = rc.jr.JobStatus;
486 Dmsg2(100, "JobStatus=%d JobName=%s\n", jr.JobStatus, jr.Name);
487 /* rc.JobIds is alist of all records found and printed */
488 rc.JobIds = db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, INCOMPLETE_JOBS);
489 if (!rc.JobIds || rc.JobIds->size()==0 ||
490 !get_selection_list(ua, sl, _("Enter the JobId list to select: "), false)) {
493 Dmsg1(100, "list=%s\n", sl.get_list());
495 * Make sure each item entered is in the JobIds list
497 while ( (JobId = sl.next()) > 0) {
498 foreach_alist(pJobId, rc.JobIds) {
499 if (JobId == str_to_int64(pJobId)) {
506 ua->error_msg(_("JobId=%d entered is not in the list.\n"), JobId);
510 sl.begin(); /* reset to walk list again */
515 static bool get_jobid_from_list(UAContext *ua, sellist &sl, run_ctx &rc)
522 if ((JobId = sl.next()) < 0) {
523 Dmsg1(100, "sl.next()=%d\n", JobId);
527 rc.jr.JobId = rc.JobId = JobId;
528 Dmsg1(100, "Next JobId=%d\n", rc.JobId);
529 if (!db_get_job_record(ua->jcr, ua->db, &rc.jr)) {
530 ua->error_msg(_("Could not get job record for selected JobId=%d. ERR=%s"),
531 rc.JobId, db_strerror(ua->db));
534 Dmsg3(100, "Job=%s JobId=%d JobStatus=%c\n", rc.jr.Name, rc.jr.JobId,
536 rc.job_name = rc.jr.Name;
537 if (!get_job(ua, rc)) {
540 if (!get_pool(ua, rc)) {
543 get_job_storage(rc.store, rc.job, NULL);
544 rc.client_name = rc.job->client->hdr.name;
545 if (!get_client(ua, rc)) {
548 if (!get_fileset(ua, rc)) {
551 if (!get_storage(ua, rc)) {
558 * Restart Canceled, Failed, or Incomplete Jobs
560 * Returns: 0 on error
564 int restart_cmd(UAContext *ua, const char *cmd)
572 const char *status_name;
576 {"Incomplete", JS_Incomplete},
577 {"Canceled", JS_Canceled},
578 {"Failed", JS_FatalError},
583 if (!open_client_db(ua)) {
588 for (i=1; i<ua->argc; i++) {
589 for (j=0; kw[j].status_name; j++) {
590 if (strcasecmp(ua->argk[i], kw[j].status_name) == 0) {
591 rc.jr.JobStatus = kw[j].job_status;
597 if (!got_kw) { /* Must prompt user */
598 start_prompt(ua, _("You have the following choices:\n"));
599 for (i=0; kw[i].status_name; i++) {
600 add_prompt(ua, kw[i].status_name);
602 i = do_prompt(ua, NULL, _("Select termination code: "), NULL, 0);
606 rc.jr.JobStatus = kw[i].job_status;
609 /* type now has what job termination code we want to look at */
610 Dmsg1(100, "Termination code=%c\n", rc.jr.JobStatus);
612 /* Get a list of JobIds to restore */
613 if (!get_jobid_list(ua, sl, rc)) {
615 rc.JobIds->destroy();
619 Dmsg1(100, "list=%s\n", sl.get_list());
621 while (get_jobid_from_list(ua, sl, rc)) {
623 * Create JCR to run job. NOTE!!! after this point, free_jcr()
627 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
628 set_jcr_defaults(jcr, rc.job);
629 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
630 ua->jcr->unlink_bsr = false;
633 if (!set_run_context_in_jcr(ua, jcr, rc)) {
636 start_job(ua, jcr, rc);
644 rc.JobIds->destroy();
646 return 0; /* do not run */
649 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
654 * At user request modify parameters of job to be run.
656 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0){
659 start_prompt(ua, _("Parameters to modify:\n"));
660 add_prompt(ua, _("Level")); /* 0 */
661 add_prompt(ua, _("Storage")); /* 1 */
662 add_prompt(ua, _("Job")); /* 2 */
663 add_prompt(ua, _("FileSet")); /* 3 */
664 if (jcr->getJobType() == JT_RESTORE) {
665 add_prompt(ua, _("Restore Client")); /* 4 */
667 add_prompt(ua, _("Client")); /* 4 */
669 add_prompt(ua, _("When")); /* 5 */
670 add_prompt(ua, _("Priority")); /* 6 */
671 if (jcr->getJobType() == JT_BACKUP ||
672 jcr->getJobType() == JT_COPY ||
673 jcr->getJobType() == JT_MIGRATE ||
674 jcr->getJobType() == JT_VERIFY) {
675 add_prompt(ua, _("Pool")); /* 7 */
676 if ((jcr->getJobType() == JT_BACKUP && /* Virtual full */
677 jcr->is_JobLevel(L_VIRTUAL_FULL)) ||
678 jcr->getJobType() == JT_COPY ||
679 jcr->getJobType() == JT_MIGRATE) {
680 add_prompt(ua, _("NextPool")); /* 8 */
681 } else if (jcr->getJobType() == JT_VERIFY) {
682 add_prompt(ua, _("Verify Job")); /* 8 */
684 } else if (jcr->getJobType() == JT_RESTORE) {
685 add_prompt(ua, _("Bootstrap")); /* 7 */
686 add_prompt(ua, _("Where")); /* 8 */
687 add_prompt(ua, _("File Relocation"));/* 9 */
688 add_prompt(ua, _("Replace")); /* 10 */
689 add_prompt(ua, _("JobId")); /* 11 */
691 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
692 add_prompt(ua, _("Plugin Options")); /* 12 */
694 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
697 select_job_level(ua, jcr);
701 rc.store->store = select_storage_resource(ua);
702 if (rc.store->store) {
703 pm_strcpy(rc.store->store_source, _("user selection"));
704 set_rwstorage(jcr, rc.store);
710 rc.job = select_job_resource(ua);
713 set_jcr_defaults(jcr, rc.job);
719 rc.fileset = select_fileset_resource(ua);
721 jcr->fileset = rc.fileset;
727 rc.client = select_client_resource(ua);
729 jcr->client = rc.client;
735 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
738 if (ua->cmd[0] == 0) {
739 jcr->sched_time = time(NULL);
741 jcr->sched_time = str_to_utime(ua->cmd);
742 if (jcr->sched_time == 0) {
743 ua->send_msg(_("Invalid time, using current time.\n"));
744 jcr->sched_time = time(NULL);
750 if (!get_pint(ua, _("Enter new Priority: "))) {
753 if (ua->pint32_val == 0) {
754 ua->send_msg(_("Priority must be a positive integer.\n"));
756 jcr->JobPriority = ua->pint32_val;
760 /* Pool or Bootstrap depending on JobType */
761 if (jcr->getJobType() == JT_BACKUP ||
762 jcr->getJobType() == JT_COPY ||
763 jcr->getJobType() == JT_MIGRATE ||
764 jcr->getJobType() == JT_VERIFY) { /* Pool */
765 rc.pool = select_pool_resource(ua);
768 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
775 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
778 if (jcr->RestoreBootstrap) {
779 free(jcr->RestoreBootstrap);
780 jcr->RestoreBootstrap = NULL;
782 if (ua->cmd[0] != 0) {
783 jcr->RestoreBootstrap = bstrdup(ua->cmd);
784 fd = fopen(jcr->RestoreBootstrap, "rb");
787 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
788 jcr->RestoreBootstrap, be.bstrerror());
789 free(jcr->RestoreBootstrap);
790 jcr->RestoreBootstrap = NULL;
797 /* Specify Next Pool */
798 if ((jcr->getJobType() == JT_BACKUP && /* Virtual full */
799 jcr->is_JobLevel(L_VIRTUAL_FULL)) ||
800 jcr->getJobType() == JT_COPY ||
801 jcr->getJobType() == JT_MIGRATE) {
802 rc.next_pool = select_pool_resource(ua);
804 jcr->next_pool = rc.next_pool;
809 if (jcr->getJobType() == JT_VERIFY) {
810 rc.verify_job = select_job_resource(ua);
812 jcr->verify_job = rc.verify_job;
817 if (!get_cmd(ua, _("Please enter the full path prefix for restore (/ for none): "))) {
820 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
821 free(jcr->RegexWhere);
822 jcr->RegexWhere = NULL;
828 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
831 jcr->where = bstrdup(ua->cmd);
834 /* File relocation */
835 select_where_regexp(ua, jcr);
839 start_prompt(ua, _("Replace:\n"));
840 for (i=0; ReplaceOptions[i].name; i++) {
841 add_prompt(ua, ReplaceOptions[i].name);
843 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
845 rc.replace = ReplaceOptions[opt].name;
846 jcr->replace = ReplaceOptions[opt].token;
851 rc.jid = NULL; /* force reprompt */
852 jcr->RestoreJobId = 0;
853 if (jcr->RestoreBootstrap) {
854 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
859 //generate_plugin_event(jcr, bEventJobConfig, &rc);
860 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
863 if (jcr->plugin_options) {
864 free(jcr->plugin_options);
865 jcr->plugin_options = NULL;
867 jcr->plugin_options = bstrdup(ua->cmd);
869 case -1: /* error or cancel */
885 * Put the run context that we have at this point into the JCR.
886 * That allows us to re-ask for the run context.
887 * This subroutine can be called multiple times, so it
888 * must keep any prior settings.
890 static bool set_run_context_in_jcr(UAContext *ua, JCR *jcr, run_ctx &rc)
894 jcr->verify_job = rc.verify_job;
895 jcr->previous_job = rc.previous_job;
897 jcr->next_pool = rc.next_pool;
899 jcr->cmdline_next_pool_override = true;
902 pm_strcpy(jcr->pool_source, _("Command input"));
903 } else if (jcr->pool != jcr->job->pool) {
904 pm_strcpy(jcr->pool_source, _("User input"));
906 if (rc.next_pool_name) {
907 pm_strcpy(jcr->next_pool_source, _("Command input"));
908 } else if (jcr->next_pool == jcr->job->next_pool) {
909 pm_strcpy(jcr->next_pool_source, _("Job resource"));
910 } else if (jcr->next_pool != jcr->pool->NextPool) {
911 pm_strcpy(jcr->next_pool_source, _("User input"));
914 set_rwstorage(jcr, rc.store);
915 jcr->client = rc.client;
917 pm_strcpy(jcr->client_name, rc.client->name());
919 pm_strcpy(jcr->client_name, "**Dummy**");
922 if (!jcr->media_type) {
923 jcr->media_type = get_pool_memory(PM_NAME);
925 pm_strcpy(jcr->media_type, rc.media_type);
927 jcr->fileset = rc.fileset;
928 jcr->ExpectedFiles = rc.files;
930 jcr->catalog = rc.catalog;
931 pm_strcpy(jcr->catalog_source, _("User input"));
934 pm_strcpy(jcr->comment, rc.comment);
940 jcr->where = bstrdup(rc.where);
945 if (jcr->RegexWhere) {
946 free(jcr->RegexWhere);
948 jcr->RegexWhere = bstrdup(rc.regexwhere);
949 rc.regexwhere = NULL;
953 jcr->sched_time = str_to_utime(rc.when);
954 if (jcr->sched_time == 0) {
955 ua->send_msg(_("Invalid time, using current time.\n"));
956 jcr->sched_time = time(NULL);
962 if (jcr->RestoreBootstrap) {
963 free(jcr->RestoreBootstrap);
965 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
969 if (rc.plugin_options) {
970 if (jcr->plugin_options) {
971 free(jcr->plugin_options);
973 jcr->plugin_options = bstrdup(rc.plugin_options);
974 rc.plugin_options = NULL;
979 for (i=0; ReplaceOptions[i].name; i++) {
980 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
981 jcr->replace = ReplaceOptions[i].token;
985 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
988 } else if (rc.job->replace) {
989 jcr->replace = rc.job->replace;
991 jcr->replace = REPLACE_ALWAYS;
995 /* Set Snapshot Retention (Job <- Client) */
997 jcr->snapshot_retention = jcr->client->SnapRetention;
999 if (jcr->job && jcr->job->SnapRetention > 0) {
1000 jcr->snapshot_retention = jcr->job->SnapRetention;
1004 jcr->JobPriority = rc.Priority;
1010 jcr->stime = get_pool_memory(PM_MESSAGE);
1012 pm_strcpy(jcr->stime, rc.since);
1017 jcr->cloned = rc.cloned;
1021 /* If pool changed, update migration write storage */
1022 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
1023 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
1024 if (!set_mac_wstorage(ua, jcr, rc.pool, rc.next_pool,
1025 jcr->next_pool_source)) {
1029 rc.replace = ReplaceOptions[0].name;
1030 for (i=0; ReplaceOptions[i].name; i++) {
1031 if ((int)ReplaceOptions[i].token == jcr->replace) {
1032 rc.replace = ReplaceOptions[i].name;
1035 if (rc.level_name) {
1036 if (!get_level_from_name(jcr, rc.level_name)) {
1037 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
1040 rc.level_name = NULL;
1043 /* Note, this is also MigrateJobId and a VerifyJobId */
1044 jcr->RestoreJobId = str_to_int64(rc.jid);
1046 /* Copy also this parameter for VirtualFull in jcr->JobIds */
1048 jcr->JobIds = get_pool_memory(PM_FNAME);
1050 pm_strcpy(jcr->JobIds, rc.jid);
1051 jcr->use_all_JobIds = rc.alljobid; /* if we found the "alljobid=" kw */
1052 rc.alljobid = false;
1056 /* Some options are not available through the menu
1057 * TODO: Add an advanced menu?
1059 if (rc.spool_data_set) {
1060 jcr->spool_data = rc.spool_data;
1063 if (rc.accurate_set) {
1064 jcr->accurate = rc.accurate;
1067 /* Used by migration jobs that can have the same name,
1068 * but can run at the same time
1070 if (rc.ignoreduplicatecheck_set) {
1071 jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
1074 /* Not a good idea to start a job with the Scratch pool */
1075 if (rc.pool && strcmp(rc.pool->name(), NT_("Scratch")) == 0) {
1076 ua->send_msg(_("Pool \"Scratch\" not valid.\n"));
1082 static void select_where_regexp(UAContext *ua, JCR *jcr)
1085 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
1086 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
1089 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
1090 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
1092 start_prompt(ua, _("This will replace your current Where value\n"));
1093 add_prompt(ua, _("Strip prefix")); /* 0 */
1094 add_prompt(ua, _("Add prefix")); /* 1 */
1095 add_prompt(ua, _("Add file suffix")); /* 2 */
1096 add_prompt(ua, _("Enter a regexp")); /* 3 */
1097 add_prompt(ua, _("Test filename manipulation")); /* 4 */
1098 add_prompt(ua, _("Use this ?")); /* 5 */
1100 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
1103 if (get_cmd(ua, _("Please enter the path prefix to strip: "))) {
1104 if (strip_prefix) bfree(strip_prefix);
1105 strip_prefix = bstrdup(ua->cmd);
1111 if (get_cmd(ua, _("Please enter the path prefix to add (/ for none): "))) {
1112 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
1116 if (add_prefix) bfree(add_prefix);
1117 add_prefix = bstrdup(ua->cmd);
1122 if (get_cmd(ua, _("Please enter the file suffix to add: "))) {
1123 if (add_suffix) bfree(add_suffix);
1124 add_suffix = bstrdup(ua->cmd);
1129 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
1130 if (rwhere) bfree(rwhere);
1131 rwhere = bstrdup(ua->cmd);
1140 if (rwhere && rwhere[0] != '\0') {
1141 regs = get_bregexps(rwhere);
1142 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
1144 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
1145 regexp = (char *) bmalloc (len * sizeof(char));
1146 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
1147 regs = get_bregexps(regexp);
1148 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
1149 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
1155 ua->send_msg(_("Cannot use your regexp\n"));
1158 ua->send_msg(_("Enter a period (.) to stop this test\n"));
1159 while (get_cmd(ua, _("Please enter filename to test: "))) {
1160 apply_bregexps(ua->cmd, regs, &result);
1161 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
1163 free_bregexps(regs);
1170 case -1: /* error or cancel */
1176 /* replace the existing where */
1182 /* replace the existing regexwhere */
1183 if (jcr->RegexWhere) {
1184 bfree(jcr->RegexWhere);
1185 jcr->RegexWhere = NULL;
1189 jcr->RegexWhere = bstrdup(rwhere);
1190 } else if (strip_prefix || add_prefix || add_suffix) {
1191 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
1192 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
1193 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
1196 regs = get_bregexps(jcr->RegexWhere);
1198 free_bregexps(regs);
1201 if (jcr->RegexWhere) {
1202 bfree(jcr->RegexWhere);
1203 jcr->RegexWhere = NULL;
1205 ua->send_msg(_("Cannot use your regexp.\n"));
1209 if (strip_prefix) bfree(strip_prefix);
1210 if (add_prefix) bfree(add_prefix);
1211 if (add_suffix) bfree(add_suffix);
1212 if (rwhere) bfree(rwhere);
1215 static void select_job_level(UAContext *ua, JCR *jcr)
1217 if (jcr->getJobType() == JT_BACKUP) {
1218 start_prompt(ua, _("Levels:\n"));
1219 // add_prompt(ua, _("Base"));
1220 add_prompt(ua, _("Full"));
1221 add_prompt(ua, _("Incremental"));
1222 add_prompt(ua, _("Differential"));
1223 add_prompt(ua, _("Since"));
1224 add_prompt(ua, _("VirtualFull"));
1225 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
1227 // jcr->JobLevel = L_BASE;
1230 jcr->setJobLevel(L_FULL);
1233 jcr->setJobLevel(L_INCREMENTAL);
1236 jcr->setJobLevel(L_DIFFERENTIAL);
1239 jcr->setJobLevel(L_SINCE);
1242 jcr->setJobLevel(L_VIRTUAL_FULL);
1247 } else if (jcr->getJobType() == JT_VERIFY) {
1248 start_prompt(ua, _("Levels:\n"));
1249 add_prompt(ua, _("Initialize Catalog"));
1250 add_prompt(ua, _("Verify Catalog"));
1251 add_prompt(ua, _("Verify Volume to Catalog"));
1252 add_prompt(ua, _("Verify Disk to Catalog"));
1253 add_prompt(ua, _("Verify Volume Data"));
1254 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
1256 jcr->setJobLevel(L_VERIFY_INIT);
1259 jcr->setJobLevel(L_VERIFY_CATALOG);
1262 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
1265 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
1268 jcr->setJobLevel(L_VERIFY_DATA);
1274 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
1279 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
1280 char *jid, const char *replace, char *client_name)
1283 char dt[MAX_TIME_LENGTH];
1285 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
1286 switch (jcr->getJobType()) {
1289 ua->signal(BNET_RUN_CMD);
1290 ua->send_msg("Type: Admin\n"
1291 "Title: Run Admin Job\n"
1299 jcr->fileset->name(),
1300 NPRT(jcr->client->name()),
1301 jcr->wstore?jcr->wstore->name():"*None*",
1302 bstrutime(dt, sizeof(dt), jcr->sched_time),
1305 ua->send_msg(_("Run Admin Job\n"
1313 jcr->fileset->name(),
1314 NPRT(jcr->client->name()),
1315 jcr->wstore?jcr->wstore->name():"*None*",
1316 bstrutime(dt, sizeof(dt), jcr->sched_time),
1319 jcr->setJobLevel(L_FULL);
1323 char next_pool[MAX_NAME_LENGTH + 50];
1325 if (jcr->getJobType() == JT_BACKUP) {
1327 ua->signal(BNET_RUN_CMD);
1328 if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
1329 bsnprintf(next_pool, sizeof(next_pool), "NextPool: %s\n",
1330 jcr->next_pool ? jcr->next_pool->name() : "*None*");
1332 ua->send_msg("Type: Backup\n"
1333 "Title: Run Backup Job\n"
1345 level_to_str(jcr->getJobLevel()),
1346 jcr->client->name(),
1347 jcr->fileset->name(),
1348 NPRT(jcr->pool->name()),
1350 jcr->wstore?jcr->wstore->name():"*None*",
1351 bstrutime(dt, sizeof(dt), jcr->sched_time),
1353 jcr->plugin_options?"Plugin Options: ":"",
1354 jcr->plugin_options?jcr->plugin_options:"",
1355 jcr->plugin_options?"\n":"");
1357 if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
1358 bsnprintf(next_pool, sizeof(next_pool),
1359 "NextPool: %s (From %s)\n",
1360 jcr->next_pool ? jcr->next_pool->name() : "*None*",
1361 jcr->next_pool_source);
1363 ua->send_msg(_("Run Backup job\n"
1368 "Pool: %s (From %s)\n"
1370 "Storage: %s (From %s)\n"
1375 level_to_str(jcr->getJobLevel()),
1376 jcr->client->name(),
1377 jcr->fileset->name(),
1378 NPRT(jcr->pool->name()), jcr->pool_source,
1380 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1381 bstrutime(dt, sizeof(dt), jcr->sched_time),
1383 jcr->plugin_options?"Plugin Options: ":"",
1384 jcr->plugin_options?jcr->plugin_options:"",
1385 jcr->plugin_options?"\n":"");
1387 } else { /* JT_VERIFY */
1390 if (jcr->verify_job) {
1391 Name = jcr->verify_job->name();
1392 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
1393 memset(&jr, 0, sizeof(jr));
1394 jr.JobId = jcr->RestoreJobId;
1395 if (!db_get_job_record(jcr, ua->db, &jr)) {
1396 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
1397 db_strerror(ua->db));
1405 verify_list = job->WriteVerifyList;
1411 ua->signal(BNET_RUN_CMD);
1412 ua->send_msg("Type: Verify\n"
1413 "Title: Run Verify Job\n"
1418 "Pool: %s (From %s)\n"
1419 "Storage: %s (From %s)\n"
1425 level_to_str(jcr->getJobLevel()),
1426 jcr->client->name(),
1427 jcr->fileset->name(),
1428 NPRT(jcr->pool->name()), jcr->pool_source,
1429 jcr->rstore->name(), jcr->rstore_source,
1432 bstrutime(dt, sizeof(dt), jcr->sched_time),
1435 ua->send_msg(_("Run Verify Job\n"
1440 "Pool: %s (From %s)\n"
1441 "Storage: %s (From %s)\n"
1447 level_to_str(jcr->getJobLevel()),
1448 jcr->client->name(),
1449 jcr->fileset->name(),
1450 NPRT(jcr->pool->name()), jcr->pool_source,
1451 jcr->rstore->name(), jcr->rstore_source,
1454 bstrutime(dt, sizeof(dt), jcr->sched_time),
1460 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
1462 jcr->RestoreJobId = str_to_int64(jid);
1464 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
1467 jcr->RestoreJobId = ua->int64_val;
1470 jcr->setJobLevel(L_FULL); /* default level */
1471 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
1472 if (jcr->RestoreJobId == 0) {
1473 /* RegexWhere is take before RestoreWhere */
1474 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1476 ua->signal(BNET_RUN_CMD);
1477 ua->send_msg("Type: Restore\n"
1478 "Title: Run Restore Job\n"
1484 "Backup Client: %s\n"
1485 "Restore Client: %s\n"
1490 "Plugin Options: %s\n",
1492 NPRT(jcr->RestoreBootstrap),
1493 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1495 jcr->fileset->name(),
1497 jcr->client->name(),
1498 jcr->rstore->name(),
1499 bstrutime(dt, sizeof(dt), jcr->sched_time),
1500 jcr->catalog->name(),
1502 NPRTB(jcr->plugin_options));
1505 ua->send_msg(_("Run Restore job\n"
1511 "Backup Client: %s\n"
1512 "Restore Client: %s\n"
1517 "Plugin Options: %s\n"),
1519 NPRT(jcr->RestoreBootstrap),
1520 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1522 jcr->fileset->name(),
1524 jcr->client->name(),
1525 jcr->rstore->name(),
1526 bstrutime(dt, sizeof(dt), jcr->sched_time),
1527 jcr->catalog->name(),
1529 NPRTB(jcr->plugin_options));
1533 ua->signal(BNET_RUN_CMD);
1534 ua->send_msg("Type: Restore\n"
1535 "Title: Run Restore job\n"
1541 "Backup Client: %s\n"
1542 "Restore Client: %s\n"
1547 "Plugin Options: %s\n",
1549 NPRT(jcr->RestoreBootstrap),
1550 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1552 jcr->fileset->name(),
1554 jcr->client->name(),
1555 jcr->rstore->name(),
1556 bstrutime(dt, sizeof(dt), jcr->sched_time),
1557 jcr->catalog->name(),
1559 NPRTB(jcr->plugin_options));
1562 ua->send_msg(_("Run Restore job\n"
1568 "Backup Client: %s\n"
1569 "Restore Client: %s\n"
1574 "Plugin Options: %s\n"),
1576 NPRT(jcr->RestoreBootstrap),
1577 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1579 jcr->fileset->name(),
1581 jcr->client->name(),
1582 jcr->rstore->name(),
1583 bstrutime(dt, sizeof(dt), jcr->sched_time),
1584 jcr->catalog->name(),
1586 NPRTB(jcr->plugin_options));
1591 /* ***FIXME*** This needs to be fixed for bat */
1592 if (ua->api) ua->signal(BNET_RUN_CMD);
1593 ua->send_msg(_("Run Restore job\n"
1597 NPRT(jcr->RestoreBootstrap));
1599 /* RegexWhere is take before RestoreWhere */
1600 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1601 ua->send_msg(_("RegexWhere: %s\n"),
1602 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1604 ua->send_msg(_("Where: %s\n"),
1605 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1608 ua->send_msg(_("Replace: %s\n"
1615 "Plugin Options: %s\n"),
1617 jcr->client->name(),
1618 jcr->rstore->name(),
1619 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1620 bstrutime(dt, sizeof(dt), jcr->sched_time),
1621 jcr->catalog->name(),
1623 NPRTB(jcr->plugin_options));
1629 jcr->setJobLevel(L_FULL); /* default level */
1631 ua->signal(BNET_RUN_CMD);
1632 if (jcr->getJobType() == JT_COPY) {
1633 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1635 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1644 "Read Storage: %s\n"
1645 "Write Storage: %s\n"
1652 NPRT(jcr->RestoreBootstrap),
1653 jcr->client->name(),
1654 jcr->fileset->name(),
1655 NPRT(jcr->pool->name()),
1656 jcr->next_pool?jcr->next_pool->name():"*None*",
1657 jcr->rstore->name(),
1658 jcr->wstore?jcr->wstore->name():"*None*",
1659 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1660 bstrutime(dt, sizeof(dt), jcr->sched_time),
1661 jcr->catalog->name(),
1664 if (jcr->getJobType() == JT_COPY) {
1665 prt_type = _("Run Copy job\n");
1667 prt_type = _("Run Migration job\n");
1674 "Pool: %s (From %s)\n"
1675 "NextPool: %s (From %s)\n"
1676 "Read Storage: %s (From %s)\n"
1677 "Write Storage: %s (From %s)\n"
1684 NPRT(jcr->RestoreBootstrap),
1685 jcr->client->name(),
1686 jcr->fileset->name(),
1687 NPRT(jcr->pool->name()), jcr->pool_source,
1688 jcr->next_pool?jcr->next_pool->name():"*None*",
1689 NPRT(jcr->next_pool_source),
1690 jcr->rstore->name(), jcr->rstore_source,
1691 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1692 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1693 bstrutime(dt, sizeof(dt), jcr->sched_time),
1694 jcr->catalog->name(),
1699 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1706 static bool scan_run_command_line_arguments(UAContext *ua, run_ctx &rc)
1710 static const char *kw[] = { /* command line arguments */
1711 "alljobid", /* 0 Used in a switch() */
1719 "regexwhere", /* 8 where string as a bregexp */
1721 "bootstrap", /* 10 */
1724 "priority", /* 13 */
1725 "yes", /* 14 -- if you change this change YES_POS too */
1726 "verifyjob", /* 15 */
1727 "files", /* 16 number of files to restore */
1728 "catalog", /* 17 override catalog */
1729 "since", /* 18 since */
1730 "cloned", /* 19 cloned */
1731 "verifylist", /* 20 verify output list */
1732 "migrationjob", /* 21 migration job name */
1734 "backupclient", /* 23 */
1735 "restoreclient", /* 24 */
1736 "pluginoptions", /* 25 */
1737 "spooldata", /* 26 */
1739 "ignoreduplicatecheck", /* 28 */
1740 "accurate", /* 29 */
1742 "mediatype", /* 31 */
1743 "nextpool", /* 32 override next pool name */
1748 rc.catalog_name = NULL;
1750 rc.pool_name = NULL;
1751 rc.next_pool_name = NULL;
1752 rc.store_name = NULL;
1753 rc.client_name = NULL;
1754 rc.media_type = NULL;
1755 rc.restore_client_name = NULL;
1756 rc.fileset_name = NULL;
1757 rc.verify_job_name = NULL;
1758 rc.previous_job_name = NULL;
1759 rc.accurate_set = false;
1760 rc.spool_data_set = false;
1761 rc.ignoreduplicatecheck = false;
1763 rc.plugin_options = NULL;
1765 for (i=1; i<ua->argc; i++) {
1766 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1768 /* Keep looking until we find a good keyword */
1769 for (j=0; !kw_ok && kw[j]; j++) {
1770 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1771 /* Note, yes and run have no value, so do not fail */
1772 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1773 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1776 Dmsg2(800, "Got j=%d keyword=%s\n", j, NPRT(kw[j]));
1778 case 0: /* alljobid */
1780 /* Fall through wanted */
1782 if (rc.jid && !rc.mod) {
1783 ua->send_msg(_("JobId specified twice.\n"));
1786 rc.jid = ua->argv[i];
1789 case 2: /* client */
1791 if (rc.client_name) {
1792 ua->send_msg(_("Client specified twice.\n"));
1795 rc.client_name = ua->argv[i];
1798 case 4: /* fileset */
1799 if (rc.fileset_name) {
1800 ua->send_msg(_("FileSet specified twice.\n"));
1803 rc.fileset_name = ua->argv[i];
1807 if (rc.level_name) {
1808 ua->send_msg(_("Level specified twice.\n"));
1811 rc.level_name = ua->argv[i];
1814 case 6: /* storage */
1816 if (rc.store_name) {
1817 ua->send_msg(_("Storage specified twice.\n"));
1820 rc.store_name = ua->argv[i];
1823 case 8: /* regexwhere */
1824 if ((rc.regexwhere || rc.where) && !rc.mod) {
1825 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1828 rc.regexwhere = ua->argv[i];
1829 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1830 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1836 if ((rc.where || rc.regexwhere) && !rc.mod) {
1837 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1840 rc.where = ua->argv[i];
1841 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1842 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1847 case 10: /* bootstrap */
1848 if (rc.bootstrap && !rc.mod) {
1849 ua->send_msg(_("Bootstrap specified twice.\n"));
1852 rc.bootstrap = ua->argv[i];
1855 case 11: /* replace */
1856 if (rc.replace && !rc.mod) {
1857 ua->send_msg(_("Replace specified twice.\n"));
1860 rc.replace = ua->argv[i];
1864 if (rc.when && !rc.mod) {
1865 ua->send_msg(_("When specified twice.\n"));
1868 rc.when = ua->argv[i];
1871 case 13: /* Priority */
1872 if (rc.Priority && !rc.mod) {
1873 ua->send_msg(_("Priority specified twice.\n"));
1876 rc.Priority = atoi(ua->argv[i]);
1877 if (rc.Priority <= 0) {
1878 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1886 case 15: /* Verify Job */
1887 if (rc.verify_job_name) {
1888 ua->send_msg(_("Verify Job specified twice.\n"));
1891 rc.verify_job_name = ua->argv[i];
1894 case 16: /* files */
1895 rc.files = atoi(ua->argv[i]);
1898 case 17: /* catalog */
1899 rc.catalog_name = ua->argv[i];
1902 case 18: /* since */
1903 rc.since = ua->argv[i];
1906 case 19: /* cloned */
1910 case 20: /* write verify list output */
1911 rc.verify_list = ua->argv[i];
1914 case 21: /* Migration Job */
1915 if (rc.previous_job_name) {
1916 ua->send_msg(_("Migration Job specified twice.\n"));
1919 rc.previous_job_name = ua->argv[i];
1924 ua->send_msg(_("Pool specified twice.\n"));
1927 rc.pool_name = ua->argv[i];
1930 case 23: /* backupclient */
1931 if (rc.client_name) {
1932 ua->send_msg(_("Client specified twice.\n"));
1935 rc.client_name = ua->argv[i];
1938 case 24: /* restoreclient */
1939 if (rc.restore_client_name && !rc.mod) {
1940 ua->send_msg(_("Restore Client specified twice.\n"));
1943 rc.restore_client_name = ua->argv[i];
1946 case 25: /* pluginoptions */
1947 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1949 if (rc.plugin_options) {
1950 ua->send_msg(_("Plugin Options specified twice.\n"));
1953 rc.plugin_options = ua->argv[i];
1954 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1955 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1960 case 26: /* spooldata */
1961 if (rc.spool_data_set) {
1962 ua->send_msg(_("Spool flag specified twice.\n"));
1965 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1966 rc.spool_data_set = true;
1969 ua->send_msg(_("Invalid spooldata flag.\n"));
1972 case 27: /* comment */
1973 rc.comment = ua->argv[i];
1976 case 28: /* ignoreduplicatecheck */
1977 if (rc.ignoreduplicatecheck_set) {
1978 ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1981 if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1982 rc.ignoreduplicatecheck_set = true;
1985 ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1988 case 29: /* accurate */
1989 if (rc.accurate_set) {
1990 ua->send_msg(_("Accurate flag specified twice.\n"));
1993 if (is_yesno(ua->argv[i], &rc.accurate)) {
1994 rc.accurate_set = true;
1997 ua->send_msg(_("Invalid accurate flag.\n"));
2002 ua->send_msg(_("Job name specified twice.\n"));
2005 rc.job_name = ua->argv[i];
2008 case 31: /* mediatype */
2009 if (rc.media_type) {
2010 ua->send_msg(_("Media Type specified twice.\n"));
2013 rc.media_type = ua->argv[i];
2016 case 32: /* Next Pool */
2017 if (rc.next_pool_name) {
2018 ua->send_msg(_("NextPool specified twice.\n"));
2021 rc.next_pool_name = ua->argv[i];
2027 } /* end strcase compare */
2028 } /* end keyword loop */
2031 * End of keyword for loop -- if not found, we got a bogus keyword
2034 Dmsg1(800, "%s not found\n", ua->argk[i]);
2036 * Special case for Job Name, it can be the first
2037 * keyword that has no value.
2039 if (!rc.job_name && !ua->argv[i]) {
2040 rc.job_name = ua->argk[i]; /* use keyword as job name */
2041 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
2043 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
2047 } /* end argc loop */
2049 Dmsg0(800, "Done scan.\n");
2051 if (!is_comment_legal(ua, rc.comment)) {
2055 if (rc.catalog_name) {
2056 rc.catalog = GetCatalogResWithName(rc.catalog_name);
2057 if (rc.catalog == NULL) {
2058 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
2061 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
2062 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
2066 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
2068 if (!get_job(ua, rc)) {
2072 if (!get_pool(ua, rc)) {
2076 if (!get_next_pool(ua, rc)) {
2080 if (!get_storage(ua, rc)) {
2085 if (!get_client(ua, rc)) {
2089 if (!get_fileset(ua, rc)) {
2093 if (rc.verify_job_name) {
2094 rc.verify_job = GetJobResWithName(rc.verify_job_name);
2095 if (!rc.verify_job) {
2096 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
2097 rc.verify_job = select_job_resource(ua);
2099 } else if (!rc.verify_job) {
2100 rc.verify_job = rc.job->verify_job;
2103 if (rc.previous_job_name) {
2104 rc.previous_job = GetJobResWithName(rc.previous_job_name);
2105 if (!rc.previous_job) {
2106 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
2107 rc.previous_job = select_job_resource(ua);
2110 rc.previous_job = rc.job->verify_job;