2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2010 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 -- Run Command
32 * Kern Sibbald, December MMI
41 char *job_name, *level_name, *jid, *store_name, *pool_name;
42 char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
43 char *restore_client_name, *comment;
45 char *when, *verify_job_name, *catalog_name;
46 char *previous_job_name;
49 const char *verify_list;
66 run_ctx() { memset(this, 0, sizeof(run_ctx));
67 store = new USTORE; };
68 ~run_ctx() { delete store; };
71 /* Forward referenced subroutines */
72 static void select_job_level(UAContext *ua, JCR *jcr);
73 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
74 const char *verify_list, char *jid, const char *replace,
76 static void select_where_regexp(UAContext *ua, JCR *jcr);
77 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
78 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
79 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
81 /* Imported variables */
82 extern struct s_kw ReplaceOptions[];
85 * For Backup and Verify Jobs
86 * run [job=]<job-name> level=<level-name>
95 int run_cmd(UAContext *ua, const char *cmd)
101 if (!open_client_db(ua)) {
105 if (!scan_command_line_arguments(ua, rc)) {
109 if (find_arg(ua, NT_("fdcalled")) > 0) {
110 jcr->file_bsock = dup_bsock(ua->UA_sock);
115 * Create JCR to run job. NOTE!!! after this point, free_jcr()
119 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
120 set_jcr_defaults(jcr, rc.job);
121 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
122 ua->jcr->unlink_bsr = false;
124 /* Transfer JobIds to new restore Job */
125 if (ua->jcr->JobIds) {
126 jcr->JobIds = ua->jcr->JobIds;
127 ua->jcr->JobIds = NULL;
131 if (!reset_restore_context(ua, jcr, rc)) {
136 /* Run without prompting? */
137 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
142 * Prompt User to see if all run job parameters are correct, and
143 * allow him to modify them.
145 if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
150 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
154 if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
155 (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
158 if (!scan_command_line_arguments(ua, rc)) {
164 /* Allow the user to modify the settings */
165 status = modify_job_parameters(ua, jcr, rc);
176 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
178 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
181 Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId,
182 jcr->pool->name(), jcr->JobPriority);
183 Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
184 JobId = run_job(jcr);
185 Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId,
186 JobId, jcr->pool->name(), jcr->JobPriority);
187 free_jcr(jcr); /* release jcr */
189 ua->error_msg(_("Job failed.\n"));
192 ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
198 ua->send_msg(_("Job not run.\n"));
200 return 0; /* do not run */
203 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
207 * At user request modify parameters of job to be run.
209 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
212 start_prompt(ua, _("Parameters to modify:\n"));
213 add_prompt(ua, _("Level")); /* 0 */
214 add_prompt(ua, _("Storage")); /* 1 */
215 add_prompt(ua, _("Job")); /* 2 */
216 add_prompt(ua, _("FileSet")); /* 3 */
217 if (jcr->getJobType() == JT_RESTORE) {
218 add_prompt(ua, _("Restore Client")); /* 4 */
220 add_prompt(ua, _("Client")); /* 4 */
222 add_prompt(ua, _("When")); /* 5 */
223 add_prompt(ua, _("Priority")); /* 6 */
224 if (jcr->getJobType() == JT_BACKUP ||
225 jcr->getJobType() == JT_COPY ||
226 jcr->getJobType() == JT_MIGRATE ||
227 jcr->getJobType() == JT_VERIFY) {
228 add_prompt(ua, _("Pool")); /* 7 */
229 if (jcr->getJobType() == JT_VERIFY) {
230 add_prompt(ua, _("Verify Job")); /* 8 */
232 } else if (jcr->getJobType() == JT_RESTORE) {
233 add_prompt(ua, _("Bootstrap")); /* 7 */
234 add_prompt(ua, _("Where")); /* 8 */
235 add_prompt(ua, _("File Relocation"));/* 9 */
236 add_prompt(ua, _("Replace")); /* 10 */
237 add_prompt(ua, _("JobId")); /* 11 */
239 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
240 add_prompt(ua, _("Plugin Options")); /* 12 */
242 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
245 select_job_level(ua, jcr);
249 rc.store->store = select_storage_resource(ua);
250 if (rc.store->store) {
251 pm_strcpy(rc.store->store_source, _("user selection"));
252 set_rwstorage(jcr, rc.store);
258 rc.job = select_job_resource(ua);
261 set_jcr_defaults(jcr, rc.job);
267 rc.fileset = select_fileset_resource(ua);
269 jcr->fileset = rc.fileset;
275 rc.client = select_client_resource(ua);
277 jcr->client = rc.client;
283 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
286 if (ua->cmd[0] == 0) {
287 jcr->sched_time = time(NULL);
289 jcr->sched_time = str_to_utime(ua->cmd);
290 if (jcr->sched_time == 0) {
291 ua->send_msg(_("Invalid time, using current time.\n"));
292 jcr->sched_time = time(NULL);
298 if (!get_pint(ua, _("Enter new Priority: "))) {
301 if (ua->pint32_val == 0) {
302 ua->send_msg(_("Priority must be a positive integer.\n"));
304 jcr->JobPriority = ua->pint32_val;
308 /* Pool or Bootstrap depending on JobType */
309 if (jcr->getJobType() == JT_BACKUP ||
310 jcr->getJobType() == JT_COPY ||
311 jcr->getJobType() == JT_MIGRATE ||
312 jcr->getJobType() == JT_VERIFY) { /* Pool */
313 rc.pool = select_pool_resource(ua);
316 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
323 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
326 if (jcr->RestoreBootstrap) {
327 free(jcr->RestoreBootstrap);
328 jcr->RestoreBootstrap = NULL;
330 if (ua->cmd[0] != 0) {
331 jcr->RestoreBootstrap = bstrdup(ua->cmd);
332 fd = fopen(jcr->RestoreBootstrap, "rb");
335 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
336 jcr->RestoreBootstrap, be.bstrerror());
337 free(jcr->RestoreBootstrap);
338 jcr->RestoreBootstrap = NULL;
346 if (jcr->getJobType() == JT_VERIFY) {
347 rc.verify_job = select_job_resource(ua);
349 jcr->verify_job = rc.verify_job;
354 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
357 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
358 free(jcr->RegexWhere);
359 jcr->RegexWhere = NULL;
365 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
368 jcr->where = bstrdup(ua->cmd);
371 /* File relocation */
372 select_where_regexp(ua, jcr);
376 start_prompt(ua, _("Replace:\n"));
377 for (i=0; ReplaceOptions[i].name; i++) {
378 add_prompt(ua, ReplaceOptions[i].name);
380 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
382 rc.replace = ReplaceOptions[opt].name;
383 jcr->replace = ReplaceOptions[opt].token;
388 rc.jid = NULL; /* force reprompt */
389 jcr->RestoreJobId = 0;
390 if (jcr->RestoreBootstrap) {
391 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
396 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
399 if (jcr->plugin_options) {
400 free(jcr->plugin_options);
401 jcr->plugin_options = NULL;
403 jcr->plugin_options = bstrdup(ua->cmd);
405 case -1: /* error or cancel */
422 * Reset the restore context.
423 * This subroutine can be called multiple times, so it
424 * must keep any prior settings.
426 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
430 jcr->verify_job = rc.verify_job;
431 jcr->previous_job = rc.previous_job;
433 if (jcr->pool != jcr->job->pool) {
434 pm_strcpy(jcr->pool_source, _("User input"));
436 set_rwstorage(jcr, rc.store);
437 jcr->client = rc.client;
438 pm_strcpy(jcr->client_name, rc.client->name());
439 jcr->fileset = rc.fileset;
440 jcr->ExpectedFiles = rc.files;
442 jcr->catalog = rc.catalog;
443 pm_strcpy(jcr->catalog_source, _("User input"));
446 pm_strcpy(jcr->comment, rc.comment);
452 jcr->where = bstrdup(rc.where);
457 if (jcr->RegexWhere) {
458 free(jcr->RegexWhere);
460 jcr->RegexWhere = bstrdup(rc.regexwhere);
461 rc.regexwhere = NULL;
465 jcr->sched_time = str_to_utime(rc.when);
466 if (jcr->sched_time == 0) {
467 ua->send_msg(_("Invalid time, using current time.\n"));
468 jcr->sched_time = time(NULL);
474 if (jcr->RestoreBootstrap) {
475 free(jcr->RestoreBootstrap);
477 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
481 if (rc.plugin_options) {
482 if (jcr->plugin_options) {
483 free(jcr->plugin_options);
485 jcr->plugin_options = bstrdup(rc.plugin_options);
486 rc.plugin_options = NULL;
492 for (i=0; ReplaceOptions[i].name; i++) {
493 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
494 jcr->replace = ReplaceOptions[i].token;
498 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
501 } else if (rc.job->replace) {
502 jcr->replace = rc.job->replace;
504 jcr->replace = REPLACE_ALWAYS;
509 jcr->JobPriority = rc.Priority;
515 jcr->stime = get_pool_memory(PM_MESSAGE);
517 pm_strcpy(jcr->stime, rc.since);
522 jcr->cloned = rc.cloned;
527 /* If pool changed, update migration write storage */
528 if (jcr->getJobType() == JT_MIGRATE || jcr->getJobType() == JT_COPY ||
529 (jcr->getJobType() == JT_BACKUP && jcr->getJobLevel() == L_VIRTUAL_FULL)) {
530 if (!set_migration_wstorage(jcr, rc.pool)) {
534 rc.replace = ReplaceOptions[0].name;
535 for (i=0; ReplaceOptions[i].name; i++) {
536 if (ReplaceOptions[i].token == jcr->replace) {
537 rc.replace = ReplaceOptions[i].name;
541 if (!get_level_from_name(jcr, rc.level_name)) {
542 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
545 rc.level_name = NULL;
548 /* Note, this is also MigrateJobId and a VerifyJobId */
549 jcr->RestoreJobId = str_to_int64(rc.jid);
555 static void select_where_regexp(UAContext *ua, JCR *jcr)
558 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
559 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
562 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
563 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
565 start_prompt(ua, _("This will replace your current Where value\n"));
566 add_prompt(ua, _("Strip prefix")); /* 0 */
567 add_prompt(ua, _("Add prefix")); /* 1 */
568 add_prompt(ua, _("Add file suffix")); /* 2 */
569 add_prompt(ua, _("Enter a regexp")); /* 3 */
570 add_prompt(ua, _("Test filename manipulation")); /* 4 */
571 add_prompt(ua, _("Use this ?")); /* 5 */
573 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
576 if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
577 if (strip_prefix) bfree(strip_prefix);
578 strip_prefix = bstrdup(ua->cmd);
584 if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
585 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
589 if (add_prefix) bfree(add_prefix);
590 add_prefix = bstrdup(ua->cmd);
595 if (get_cmd(ua, _("Please enter file suffix to add: "))) {
596 if (add_suffix) bfree(add_suffix);
597 add_suffix = bstrdup(ua->cmd);
602 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
603 if (rwhere) bfree(rwhere);
604 rwhere = bstrdup(ua->cmd);
613 if (rwhere && rwhere[0] != '\0') {
614 regs = get_bregexps(rwhere);
615 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
617 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
618 regexp = (char *) bmalloc (len * sizeof(char));
619 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
620 regs = get_bregexps(regexp);
621 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
622 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
628 ua->send_msg(_("Cannot use your regexp\n"));
631 ua->send_msg(_("Enter a period (.) to stop this test\n"));
632 while (get_cmd(ua, _("Please enter filename to test: "))) {
633 apply_bregexps(ua->cmd, regs, &result);
634 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
643 case -1: /* error or cancel */
649 /* replace the existing where */
655 /* replace the existing regexwhere */
656 if (jcr->RegexWhere) {
657 bfree(jcr->RegexWhere);
658 jcr->RegexWhere = NULL;
662 jcr->RegexWhere = bstrdup(rwhere);
663 } else if (strip_prefix || add_prefix || add_suffix) {
664 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
665 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
666 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
669 regs = get_bregexps(jcr->RegexWhere);
674 if (jcr->RegexWhere) {
675 bfree(jcr->RegexWhere);
676 jcr->RegexWhere = NULL;
678 ua->send_msg(_("Cannot use your regexp.\n"));
682 if (strip_prefix) bfree(strip_prefix);
683 if (add_prefix) bfree(add_prefix);
684 if (add_suffix) bfree(add_suffix);
685 if (rwhere) bfree(rwhere);
688 static void select_job_level(UAContext *ua, JCR *jcr)
690 if (jcr->getJobType() == JT_BACKUP) {
691 start_prompt(ua, _("Levels:\n"));
692 // add_prompt(ua, _("Base"));
693 add_prompt(ua, _("Full"));
694 add_prompt(ua, _("Incremental"));
695 add_prompt(ua, _("Differential"));
696 add_prompt(ua, _("Since"));
697 add_prompt(ua, _("VirtualFull"));
698 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
700 // jcr->JobLevel = L_BASE;
703 jcr->set_JobLevel(L_FULL);
706 jcr->set_JobLevel(L_INCREMENTAL);
709 jcr->set_JobLevel(L_DIFFERENTIAL);
712 jcr->set_JobLevel(L_SINCE);
715 jcr->set_JobLevel(L_VIRTUAL_FULL);
720 } else if (jcr->getJobType() == JT_VERIFY) {
721 start_prompt(ua, _("Levels:\n"));
722 add_prompt(ua, _("Initialize Catalog"));
723 add_prompt(ua, _("Verify Catalog"));
724 add_prompt(ua, _("Verify Volume to Catalog"));
725 add_prompt(ua, _("Verify Disk to Catalog"));
726 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
727 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
729 jcr->set_JobLevel(L_VERIFY_INIT);
732 jcr->set_JobLevel(L_VERIFY_CATALOG);
735 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
738 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
741 jcr->set_JobLevel(L_VERIFY_DATA);
747 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
752 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
753 char *jid, const char *replace, char *client_name)
756 char dt[MAX_TIME_LENGTH];
758 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
759 switch (jcr->getJobType()) {
761 if (ua->api) ua->signal(BNET_RUN_CMD);
762 ua->send_msg(_("Run %s job\n"
771 jcr->fileset->name(),
772 NPRT(jcr->client->name()),
773 jcr->wstore?jcr->wstore->name():"*None*",
774 bstrutime(dt, sizeof(dt), jcr->sched_time),
776 jcr->set_JobLevel(L_FULL);
780 if (jcr->getJobType() == JT_BACKUP) {
781 if (ua->api) ua->signal(BNET_RUN_CMD);
782 ua->send_msg(_("Run %s job\n"
787 "Pool: %s (From %s)\n"
788 "Storage: %s (From %s)\n"
794 level_to_str(jcr->getJobLevel()),
796 jcr->fileset->name(),
797 NPRT(jcr->pool->name()), jcr->pool_source,
798 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
799 bstrutime(dt, sizeof(dt), jcr->sched_time),
801 jcr->plugin_options?"Plugin Options: ":"",
802 jcr->plugin_options?jcr->plugin_options:"",
803 jcr->plugin_options?"\n":"");
804 } else { /* JT_VERIFY */
807 if (jcr->verify_job) {
808 Name = jcr->verify_job->name();
809 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
810 memset(&jr, 0, sizeof(jr));
811 jr.JobId = jcr->RestoreJobId;
812 if (!db_get_job_record(jcr, ua->db, &jr)) {
813 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
814 db_strerror(ua->db));
822 verify_list = job->WriteVerifyList;
827 if (ua->api) ua->signal(BNET_RUN_CMD);
828 ua->send_msg(_("Run %s job\n"
833 "Pool: %s (From %s)\n"
834 "Storage: %s (From %s)\n"
841 level_to_str(jcr->getJobLevel()),
843 jcr->fileset->name(),
844 NPRT(jcr->pool->name()), jcr->pool_source,
845 jcr->rstore->name(), jcr->rstore_source,
848 bstrutime(dt, sizeof(dt), jcr->sched_time),
853 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
855 jcr->RestoreJobId = str_to_int64(jid);
857 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
860 jcr->RestoreJobId = ua->int64_val;
863 jcr->set_JobLevel(L_FULL); /* default level */
864 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
865 if (jcr->RestoreJobId == 0) {
866 if (ua->api) ua->signal(BNET_RUN_CMD);
867 /* RegexWhere is take before RestoreWhere */
868 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
869 ua->send_msg(_("Run Restore job\n"
875 "Backup Client: %s\n"
876 "Restore Client: %s\n"
881 "Plugin Options: %s\n"),
883 NPRT(jcr->RestoreBootstrap),
884 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
886 jcr->fileset->name(),
890 bstrutime(dt, sizeof(dt), jcr->sched_time),
891 jcr->catalog->name(),
893 NPRT(jcr->plugin_options));
896 ua->send_msg(_("Run Restore job\n"
902 "Backup Client: %s\n"
903 "Restore Client: %s\n"
908 "Plugin Options: %s\n"),
910 NPRT(jcr->RestoreBootstrap),
911 jcr->where?jcr->where:NPRT(job->RestoreWhere),
913 jcr->fileset->name(),
917 bstrutime(dt, sizeof(dt), jcr->sched_time),
918 jcr->catalog->name(),
920 NPRT(jcr->plugin_options));
924 if (ua->api) ua->signal(BNET_RUN_CMD);
925 ua->send_msg(_("Run Restore job\n"
929 NPRT(jcr->RestoreBootstrap));
931 /* RegexWhere is take before RestoreWhere */
932 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
933 ua->send_msg(_("RegexWhere: %s\n"),
934 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
936 ua->send_msg(_("Where: %s\n"),
937 jcr->where?jcr->where:NPRT(job->RestoreWhere));
940 ua->send_msg(_("Replace: %s\n"
947 "Plugin Options: %s\n"),
951 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
952 bstrutime(dt, sizeof(dt), jcr->sched_time),
953 jcr->catalog->name(),
955 NPRT(jcr->plugin_options));
961 if (jcr->getJobType() == JT_COPY) {
962 prt_type = _("Run Copy job\n");
964 prt_type = _("Run Migration job\n");
966 jcr->set_JobLevel(L_FULL); /* default level */
967 if (ua->api) ua->signal(BNET_RUN_CMD);
973 "Pool: %s (From %s)\n"
974 "Read Storage: %s (From %s)\n"
975 "Write Storage: %s (From %s)\n"
982 NPRT(jcr->RestoreBootstrap),
984 jcr->fileset->name(),
985 NPRT(jcr->pool->name()), jcr->pool_source,
986 jcr->rstore->name(), jcr->rstore_source,
987 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
988 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
989 bstrutime(dt, sizeof(dt), jcr->sched_time),
990 jcr->catalog->name(),
994 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1001 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1005 static const char *kw[] = { /* command line arguments */
1006 "job", /* Used in a switch() */
1014 "regexwhere", /* 8 where string as a bregexp */
1016 "bootstrap", /* 10 */
1019 "priority", /* 13 */
1020 "yes", /* 14 -- if you change this change YES_POS too */
1021 "verifyjob", /* 15 */
1022 "files", /* 16 number of files to restore */
1023 "catalog", /* 17 override catalog */
1024 "since", /* 18 since */
1025 "cloned", /* 19 cloned */
1026 "verifylist", /* 20 verify output list */
1027 "migrationjob", /* 21 migration job name */
1029 "backupclient", /* 23 */
1030 "restoreclient", /* 24 */
1031 "pluginoptions", /* 25 */
1032 "spooldata", /* 26 */
1038 rc.catalog_name = NULL;
1040 rc.pool_name = NULL;
1041 rc.store_name = NULL;
1042 rc.client_name = NULL;
1043 rc.restore_client_name = NULL;
1044 rc.fileset_name = NULL;
1045 rc.verify_job_name = NULL;
1046 rc.previous_job_name = NULL;
1047 rc.spool_data_set = 0;
1050 for (i=1; i<ua->argc; i++) {
1051 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1053 /* Keep looking until we find a good keyword */
1054 for (j=0; !kw_ok && kw[j]; j++) {
1055 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1056 /* Note, yes and run have no value, so do not fail */
1057 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1058 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1061 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1065 ua->send_msg(_("Job name specified twice.\n"));
1068 rc.job_name = ua->argv[i];
1072 if (rc.jid && !rc.mod) {
1073 ua->send_msg(_("JobId specified twice.\n"));
1076 rc.jid = ua->argv[i];
1079 case 2: /* client */
1081 if (rc.client_name) {
1082 ua->send_msg(_("Client specified twice.\n"));
1085 rc.client_name = ua->argv[i];
1088 case 4: /* fileset */
1089 if (rc.fileset_name) {
1090 ua->send_msg(_("FileSet specified twice.\n"));
1093 rc.fileset_name = ua->argv[i];
1097 if (rc.level_name) {
1098 ua->send_msg(_("Level specified twice.\n"));
1101 rc.level_name = ua->argv[i];
1104 case 6: /* storage */
1106 if (rc.store_name) {
1107 ua->send_msg(_("Storage specified twice.\n"));
1110 rc.store_name = ua->argv[i];
1113 case 8: /* regexwhere */
1114 if ((rc.regexwhere || rc.where) && !rc.mod) {
1115 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1118 rc.regexwhere = ua->argv[i];
1119 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1120 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1126 if ((rc.where || rc.regexwhere) && !rc.mod) {
1127 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1130 rc.where = ua->argv[i];
1131 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1132 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1137 case 10: /* bootstrap */
1138 if (rc.bootstrap && !rc.mod) {
1139 ua->send_msg(_("Bootstrap specified twice.\n"));
1142 rc.bootstrap = ua->argv[i];
1145 case 11: /* replace */
1146 if (rc.replace && !rc.mod) {
1147 ua->send_msg(_("Replace specified twice.\n"));
1150 rc.replace = ua->argv[i];
1154 if (rc.when && !rc.mod) {
1155 ua->send_msg(_("When specified twice.\n"));
1158 rc.when = ua->argv[i];
1161 case 13: /* Priority */
1162 if (rc.Priority && !rc.mod) {
1163 ua->send_msg(_("Priority specified twice.\n"));
1166 rc.Priority = atoi(ua->argv[i]);
1167 if (rc.Priority <= 0) {
1168 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1176 case 15: /* Verify Job */
1177 if (rc.verify_job_name) {
1178 ua->send_msg(_("Verify Job specified twice.\n"));
1181 rc.verify_job_name = ua->argv[i];
1184 case 16: /* files */
1185 rc.files = atoi(ua->argv[i]);
1189 case 17: /* catalog */
1190 rc.catalog_name = ua->argv[i];
1194 case 18: /* since */
1195 rc.since = ua->argv[i];
1199 case 19: /* cloned */
1204 case 20: /* write verify list output */
1205 rc.verify_list = ua->argv[i];
1208 case 21: /* Migration Job */
1209 if (rc.previous_job_name) {
1210 ua->send_msg(_("Migration Job specified twice.\n"));
1213 rc.previous_job_name = ua->argv[i];
1218 ua->send_msg(_("Pool specified twice.\n"));
1221 rc.pool_name = ua->argv[i];
1224 case 23: /* backupclient */
1225 if (rc.client_name) {
1226 ua->send_msg(_("Client specified twice.\n"));
1229 rc.client_name = ua->argv[i];
1232 case 24: /* restoreclient */
1233 if (rc.restore_client_name && !rc.mod) {
1234 ua->send_msg(_("Restore Client specified twice.\n"));
1237 rc.restore_client_name = ua->argv[i];
1240 case 25: /* pluginoptions */
1241 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1243 if (rc.plugin_options) {
1244 ua->send_msg(_("Plugin Options specified twice.\n"));
1247 rc.plugin_options = ua->argv[i];
1248 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1249 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1254 case 26: /* spooldata */
1255 if (rc.spool_data_set) {
1256 ua->send_msg(_("Spool flag specified twice.\n"));
1259 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1260 rc.spool_data_set = 1;
1263 ua->send_msg(_("Invalid spooldata flag.\n"));
1266 case 27: /* comment */
1267 rc.comment = ua->argv[i];
1272 } /* end strcase compare */
1273 } /* end keyword loop */
1275 * End of keyword for loop -- if not found, we got a bogus keyword
1278 Dmsg1(800, "%s not found\n", ua->argk[i]);
1280 * Special case for Job Name, it can be the first
1281 * keyword that has no value.
1283 if (!rc.job_name && !ua->argv[i]) {
1284 rc.job_name = ua->argk[i]; /* use keyword as job name */
1285 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1287 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1291 } /* end argc loop */
1293 Dmsg0(800, "Done scan.\n");
1295 if (!is_comment_legal(ua, rc.comment)) {
1299 if (rc.catalog_name) {
1300 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1301 if (rc.catalog == NULL) {
1302 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1305 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1306 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1310 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1314 rc.job = GetJobResWithName(rc.job_name);
1316 if (*rc.job_name != 0) {
1317 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1319 rc.job = select_job_resource(ua);
1321 Dmsg1(800, "Found job=%s\n", rc.job_name);
1323 } else if (!rc.job) {
1324 ua->send_msg(_("A job name must be specified.\n"));
1325 rc.job = select_job_resource(ua);
1329 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1330 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1335 rc.pool = GetPoolResWithName(rc.pool_name);
1337 if (*rc.pool_name != 0) {
1338 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1340 rc.pool = select_pool_resource(ua);
1342 } else if (!rc.pool) {
1343 rc.pool = rc.job->pool; /* use default */
1347 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1348 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1351 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1353 if (rc.spool_data_set) {
1354 rc.job->spool_data = rc.spool_data;
1356 Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1358 if (rc.store_name) {
1359 rc.store->store = GetStoreResWithName(rc.store_name);
1360 pm_strcpy(rc.store->store_source, _("command line"));
1361 if (!rc.store->store) {
1362 if (*rc.store_name != 0) {
1363 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1365 rc.store->store = select_storage_resource(ua);
1366 pm_strcpy(rc.store->store_source, _("user selection"));
1368 } else if (!rc.store->store) {
1369 get_job_storage(rc.store, rc.job, NULL); /* use default */
1371 if (!rc.store->store) {
1372 ua->error_msg(_("No storage specified.\n"));
1374 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1375 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1376 rc.store->store->name());
1379 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1381 if (rc.client_name) {
1382 rc.client = GetClientResWithName(rc.client_name);
1384 if (*rc.client_name != 0) {
1385 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1387 rc.client = select_client_resource(ua);
1389 } else if (!rc.client) {
1390 rc.client = rc.job->client; /* use default */
1394 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1395 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1399 Dmsg1(800, "Using client=%s\n", rc.client->name());
1401 if (rc.restore_client_name) {
1402 rc.client = GetClientResWithName(rc.restore_client_name);
1404 if (*rc.restore_client_name != 0) {
1405 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1407 rc.client = select_client_resource(ua);
1409 } else if (!rc.client) {
1410 rc.client = rc.job->client; /* use default */
1414 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1415 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1419 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1422 if (rc.fileset_name) {
1423 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1425 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1426 rc.fileset = select_fileset_resource(ua);
1428 } else if (!rc.fileset) {
1429 rc.fileset = rc.job->fileset; /* use default */
1433 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1434 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1435 rc.fileset->name());
1439 if (rc.verify_job_name) {
1440 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1441 if (!rc.verify_job) {
1442 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1443 rc.verify_job = select_job_resource(ua);
1445 } else if (!rc.verify_job) {
1446 rc.verify_job = rc.job->verify_job;
1449 if (rc.previous_job_name) {
1450 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1451 if (!rc.previous_job) {
1452 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1453 rc.previous_job = select_job_resource(ua);
1456 rc.previous_job = rc.job->verify_job;