2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2012 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 int ignoreduplicatecheck;
67 bool ignoreduplicatecheck_set;
70 run_ctx() { memset(this, 0, sizeof(run_ctx));
71 store = new USTORE; };
72 ~run_ctx() { delete store; };
75 /* Forward referenced subroutines */
76 static void select_job_level(UAContext *ua, JCR *jcr);
77 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
78 const char *verify_list, char *jid, const char *replace,
80 static void select_where_regexp(UAContext *ua, JCR *jcr);
81 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
82 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
83 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
85 /* Imported variables */
86 extern struct s_kw ReplaceOptions[];
89 * For Backup and Verify Jobs
90 * run [job=]<job-name> level=<level-name>
99 int run_cmd(UAContext *ua, const char *cmd)
105 if (!open_client_db(ua)) {
109 if (!scan_command_line_arguments(ua, rc)) {
113 if (find_arg(ua, NT_("fdcalled")) > 0) {
114 jcr->file_bsock = dup_bsock(ua->UA_sock);
119 * Create JCR to run job. NOTE!!! after this point, free_jcr()
123 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
124 set_jcr_defaults(jcr, rc.job);
125 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
126 ua->jcr->unlink_bsr = false;
128 /* Transfer JobIds to new restore Job */
129 if (ua->jcr->JobIds) {
130 jcr->JobIds = ua->jcr->JobIds;
131 ua->jcr->JobIds = NULL;
135 if (!reset_restore_context(ua, jcr, rc)) {
140 /* Run without prompting? */
141 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
146 * Prompt User to see if all run job parameters are correct, and
147 * allow him to modify them.
149 if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
154 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
158 if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
159 (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
162 if (!scan_command_line_arguments(ua, rc)) {
168 /* Allow the user to modify the settings */
169 status = modify_job_parameters(ua, jcr, rc);
180 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
182 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
185 Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId,
186 jcr->pool->name(), jcr->JobPriority);
187 Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
188 JobId = run_job(jcr);
189 Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId,
190 JobId, jcr->pool->name(), jcr->JobPriority);
191 free_jcr(jcr); /* release jcr */
193 ua->error_msg(_("Job failed.\n"));
196 ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
200 if (strncasecmp(ua->cmd, _("no"), strlen(ua->cmd)) == 0) {
203 ua->send_msg(_("\nBad response: %s. You must answer yes, mod, or no.\n\n"), ua->cmd);
207 ua->send_msg(_("Job not run.\n"));
209 return 0; /* do not run */
212 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
217 * At user request modify parameters of job to be run.
219 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
222 start_prompt(ua, _("Parameters to modify:\n"));
223 add_prompt(ua, _("Level")); /* 0 */
224 add_prompt(ua, _("Storage")); /* 1 */
225 add_prompt(ua, _("Job")); /* 2 */
226 add_prompt(ua, _("FileSet")); /* 3 */
227 if (jcr->getJobType() == JT_RESTORE) {
228 add_prompt(ua, _("Restore Client")); /* 4 */
230 add_prompt(ua, _("Client")); /* 4 */
232 add_prompt(ua, _("When")); /* 5 */
233 add_prompt(ua, _("Priority")); /* 6 */
234 if (jcr->getJobType() == JT_BACKUP ||
235 jcr->getJobType() == JT_COPY ||
236 jcr->getJobType() == JT_MIGRATE ||
237 jcr->getJobType() == JT_VERIFY) {
238 add_prompt(ua, _("Pool")); /* 7 */
239 if (jcr->getJobType() == JT_VERIFY) {
240 add_prompt(ua, _("Verify Job")); /* 8 */
242 } else if (jcr->getJobType() == JT_RESTORE) {
243 add_prompt(ua, _("Bootstrap")); /* 7 */
244 add_prompt(ua, _("Where")); /* 8 */
245 add_prompt(ua, _("File Relocation"));/* 9 */
246 add_prompt(ua, _("Replace")); /* 10 */
247 add_prompt(ua, _("JobId")); /* 11 */
249 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
250 add_prompt(ua, _("Plugin Options")); /* 12 */
252 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
255 select_job_level(ua, jcr);
259 rc.store->store = select_storage_resource(ua);
260 if (rc.store->store) {
261 pm_strcpy(rc.store->store_source, _("user selection"));
262 set_rwstorage(jcr, rc.store);
268 rc.job = select_job_resource(ua);
271 set_jcr_defaults(jcr, rc.job);
277 rc.fileset = select_fileset_resource(ua);
279 jcr->fileset = rc.fileset;
285 rc.client = select_client_resource(ua);
287 jcr->client = rc.client;
293 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
296 if (ua->cmd[0] == 0) {
297 jcr->sched_time = time(NULL);
299 jcr->sched_time = str_to_utime(ua->cmd);
300 if (jcr->sched_time == 0) {
301 ua->send_msg(_("Invalid time, using current time.\n"));
302 jcr->sched_time = time(NULL);
308 if (!get_pint(ua, _("Enter new Priority: "))) {
311 if (ua->pint32_val == 0) {
312 ua->send_msg(_("Priority must be a positive integer.\n"));
314 jcr->JobPriority = ua->pint32_val;
318 /* Pool or Bootstrap depending on JobType */
319 if (jcr->getJobType() == JT_BACKUP ||
320 jcr->getJobType() == JT_COPY ||
321 jcr->getJobType() == JT_MIGRATE ||
322 jcr->getJobType() == JT_VERIFY) { /* Pool */
323 rc.pool = select_pool_resource(ua);
326 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
333 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
336 if (jcr->RestoreBootstrap) {
337 free(jcr->RestoreBootstrap);
338 jcr->RestoreBootstrap = NULL;
340 if (ua->cmd[0] != 0) {
341 jcr->RestoreBootstrap = bstrdup(ua->cmd);
342 fd = fopen(jcr->RestoreBootstrap, "rb");
345 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
346 jcr->RestoreBootstrap, be.bstrerror());
347 free(jcr->RestoreBootstrap);
348 jcr->RestoreBootstrap = NULL;
356 if (jcr->getJobType() == JT_VERIFY) {
357 rc.verify_job = select_job_resource(ua);
359 jcr->verify_job = rc.verify_job;
364 if (!get_cmd(ua, _("Please enter the full path prefix for restore (/ for none): "))) {
367 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
368 free(jcr->RegexWhere);
369 jcr->RegexWhere = NULL;
375 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
378 jcr->where = bstrdup(ua->cmd);
381 /* File relocation */
382 select_where_regexp(ua, jcr);
386 start_prompt(ua, _("Replace:\n"));
387 for (i=0; ReplaceOptions[i].name; i++) {
388 add_prompt(ua, ReplaceOptions[i].name);
390 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
392 rc.replace = ReplaceOptions[opt].name;
393 jcr->replace = ReplaceOptions[opt].token;
398 rc.jid = NULL; /* force reprompt */
399 jcr->RestoreJobId = 0;
400 if (jcr->RestoreBootstrap) {
401 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
406 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
409 if (jcr->plugin_options) {
410 free(jcr->plugin_options);
411 jcr->plugin_options = NULL;
413 jcr->plugin_options = bstrdup(ua->cmd);
415 case -1: /* error or cancel */
432 * Reset the restore context.
433 * This subroutine can be called multiple times, so it
434 * must keep any prior settings.
436 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
440 jcr->verify_job = rc.verify_job;
441 jcr->previous_job = rc.previous_job;
443 if (jcr->pool != jcr->job->pool) {
444 pm_strcpy(jcr->pool_source, _("User input"));
446 set_rwstorage(jcr, rc.store);
447 jcr->client = rc.client;
448 pm_strcpy(jcr->client_name, rc.client->name());
449 jcr->fileset = rc.fileset;
450 jcr->ExpectedFiles = rc.files;
452 jcr->catalog = rc.catalog;
453 pm_strcpy(jcr->catalog_source, _("User input"));
456 pm_strcpy(jcr->comment, rc.comment);
462 jcr->where = bstrdup(rc.where);
467 if (jcr->RegexWhere) {
468 free(jcr->RegexWhere);
470 jcr->RegexWhere = bstrdup(rc.regexwhere);
471 rc.regexwhere = NULL;
475 jcr->sched_time = str_to_utime(rc.when);
476 if (jcr->sched_time == 0) {
477 ua->send_msg(_("Invalid time, using current time.\n"));
478 jcr->sched_time = time(NULL);
484 if (jcr->RestoreBootstrap) {
485 free(jcr->RestoreBootstrap);
487 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
491 if (rc.plugin_options) {
492 if (jcr->plugin_options) {
493 free(jcr->plugin_options);
495 jcr->plugin_options = bstrdup(rc.plugin_options);
496 rc.plugin_options = NULL;
501 for (i=0; ReplaceOptions[i].name; i++) {
502 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
503 jcr->replace = ReplaceOptions[i].token;
507 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
510 } else if (rc.job->replace) {
511 jcr->replace = rc.job->replace;
513 jcr->replace = REPLACE_ALWAYS;
518 jcr->JobPriority = rc.Priority;
524 jcr->stime = get_pool_memory(PM_MESSAGE);
526 pm_strcpy(jcr->stime, rc.since);
531 jcr->cloned = rc.cloned;
535 /* If pool changed, update migration write storage */
536 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
537 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
538 if (!set_migration_wstorage(jcr, rc.pool)) {
542 rc.replace = ReplaceOptions[0].name;
543 for (i=0; ReplaceOptions[i].name; i++) {
544 if (ReplaceOptions[i].token == jcr->replace) {
545 rc.replace = ReplaceOptions[i].name;
549 if (!get_level_from_name(jcr, rc.level_name)) {
550 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
553 rc.level_name = NULL;
556 /* Note, this is also MigrateJobId and a VerifyJobId */
557 jcr->RestoreJobId = str_to_int64(rc.jid);
561 /* Some options are not available through the menu
562 * TODO: Add an advanced menu?
564 if (rc.spool_data_set) {
565 jcr->spool_data = rc.spool_data;
568 if (rc.accurate_set) {
569 jcr->accurate = rc.accurate;
572 /* Used by migration jobs that can have the same name,
573 * but can run at the same time
575 if (rc.ignoreduplicatecheck_set) {
576 jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
582 static void select_where_regexp(UAContext *ua, JCR *jcr)
585 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
586 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
589 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
590 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
592 start_prompt(ua, _("This will replace your current Where value\n"));
593 add_prompt(ua, _("Strip prefix")); /* 0 */
594 add_prompt(ua, _("Add prefix")); /* 1 */
595 add_prompt(ua, _("Add file suffix")); /* 2 */
596 add_prompt(ua, _("Enter a regexp")); /* 3 */
597 add_prompt(ua, _("Test filename manipulation")); /* 4 */
598 add_prompt(ua, _("Use this ?")); /* 5 */
600 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
603 if (get_cmd(ua, _("Please enter the path prefix to strip: "))) {
604 if (strip_prefix) bfree(strip_prefix);
605 strip_prefix = bstrdup(ua->cmd);
611 if (get_cmd(ua, _("Please enter the path prefix to add (/ for none): "))) {
612 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
616 if (add_prefix) bfree(add_prefix);
617 add_prefix = bstrdup(ua->cmd);
622 if (get_cmd(ua, _("Please enter the file suffix to add: "))) {
623 if (add_suffix) bfree(add_suffix);
624 add_suffix = bstrdup(ua->cmd);
629 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
630 if (rwhere) bfree(rwhere);
631 rwhere = bstrdup(ua->cmd);
640 if (rwhere && rwhere[0] != '\0') {
641 regs = get_bregexps(rwhere);
642 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
644 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
645 regexp = (char *) bmalloc (len * sizeof(char));
646 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
647 regs = get_bregexps(regexp);
648 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
649 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
655 ua->send_msg(_("Cannot use your regexp\n"));
658 ua->send_msg(_("Enter a period (.) to stop this test\n"));
659 while (get_cmd(ua, _("Please enter filename to test: "))) {
660 apply_bregexps(ua->cmd, regs, &result);
661 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
670 case -1: /* error or cancel */
676 /* replace the existing where */
682 /* replace the existing regexwhere */
683 if (jcr->RegexWhere) {
684 bfree(jcr->RegexWhere);
685 jcr->RegexWhere = NULL;
689 jcr->RegexWhere = bstrdup(rwhere);
690 } else if (strip_prefix || add_prefix || add_suffix) {
691 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
692 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
693 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
696 regs = get_bregexps(jcr->RegexWhere);
701 if (jcr->RegexWhere) {
702 bfree(jcr->RegexWhere);
703 jcr->RegexWhere = NULL;
705 ua->send_msg(_("Cannot use your regexp.\n"));
709 if (strip_prefix) bfree(strip_prefix);
710 if (add_prefix) bfree(add_prefix);
711 if (add_suffix) bfree(add_suffix);
712 if (rwhere) bfree(rwhere);
715 static void select_job_level(UAContext *ua, JCR *jcr)
717 if (jcr->getJobType() == JT_BACKUP) {
718 start_prompt(ua, _("Levels:\n"));
719 // add_prompt(ua, _("Base"));
720 add_prompt(ua, _("Full"));
721 add_prompt(ua, _("Incremental"));
722 add_prompt(ua, _("Differential"));
723 add_prompt(ua, _("Since"));
724 add_prompt(ua, _("VirtualFull"));
725 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
727 // jcr->JobLevel = L_BASE;
730 jcr->setJobLevel(L_FULL);
733 jcr->setJobLevel(L_INCREMENTAL);
736 jcr->setJobLevel(L_DIFFERENTIAL);
739 jcr->setJobLevel(L_SINCE);
742 jcr->setJobLevel(L_VIRTUAL_FULL);
747 } else if (jcr->getJobType() == JT_VERIFY) {
748 start_prompt(ua, _("Levels:\n"));
749 add_prompt(ua, _("Initialize Catalog"));
750 add_prompt(ua, _("Verify Catalog"));
751 add_prompt(ua, _("Verify Volume to Catalog"));
752 add_prompt(ua, _("Verify Disk to Catalog"));
753 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
754 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
756 jcr->setJobLevel(L_VERIFY_INIT);
759 jcr->setJobLevel(L_VERIFY_CATALOG);
762 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
765 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
768 jcr->setJobLevel(L_VERIFY_DATA);
774 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
779 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
780 char *jid, const char *replace, char *client_name)
783 char dt[MAX_TIME_LENGTH];
785 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
786 switch (jcr->getJobType()) {
789 ua->signal(BNET_RUN_CMD);
790 ua->send_msg("Type: Admin\n"
791 "Title: Run Admin Job\n"
799 jcr->fileset->name(),
800 NPRT(jcr->client->name()),
801 jcr->wstore?jcr->wstore->name():"*None*",
802 bstrutime(dt, sizeof(dt), jcr->sched_time),
805 ua->send_msg(_("Run Admin Job\n"
813 jcr->fileset->name(),
814 NPRT(jcr->client->name()),
815 jcr->wstore?jcr->wstore->name():"*None*",
816 bstrutime(dt, sizeof(dt), jcr->sched_time),
819 jcr->setJobLevel(L_FULL);
823 if (jcr->getJobType() == JT_BACKUP) {
825 ua->signal(BNET_RUN_CMD);
826 ua->send_msg("Type: Backup\n"
827 "Title: Run Backup Job\n"
838 level_to_str(jcr->getJobLevel()),
840 jcr->fileset->name(),
841 NPRT(jcr->pool->name()),
842 jcr->wstore?jcr->wstore->name():"*None*",
843 bstrutime(dt, sizeof(dt), jcr->sched_time),
845 jcr->plugin_options?"Plugin Options: ":"",
846 jcr->plugin_options?jcr->plugin_options:"",
847 jcr->plugin_options?"\n":"");
849 ua->send_msg(_("Run Backup job\n"
854 "Pool: %s (From %s)\n"
855 "Storage: %s (From %s)\n"
860 level_to_str(jcr->getJobLevel()),
862 jcr->fileset->name(),
863 NPRT(jcr->pool->name()), jcr->pool_source,
864 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
865 bstrutime(dt, sizeof(dt), jcr->sched_time),
867 jcr->plugin_options?"Plugin Options: ":"",
868 jcr->plugin_options?jcr->plugin_options:"",
869 jcr->plugin_options?"\n":"");
871 } else { /* JT_VERIFY */
874 if (jcr->verify_job) {
875 Name = jcr->verify_job->name();
876 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
877 memset(&jr, 0, sizeof(jr));
878 jr.JobId = jcr->RestoreJobId;
879 if (!db_get_job_record(jcr, ua->db, &jr)) {
880 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
881 db_strerror(ua->db));
889 verify_list = job->WriteVerifyList;
895 ua->signal(BNET_RUN_CMD);
896 ua->send_msg("Type: Verify\n"
897 "Title: Run Verify Job\n"
902 "Pool: %s (From %s)\n"
903 "Storage: %s (From %s)\n"
909 level_to_str(jcr->getJobLevel()),
911 jcr->fileset->name(),
912 NPRT(jcr->pool->name()), jcr->pool_source,
913 jcr->rstore->name(), jcr->rstore_source,
916 bstrutime(dt, sizeof(dt), jcr->sched_time),
919 ua->send_msg(_("Run Verify Job\n"
924 "Pool: %s (From %s)\n"
925 "Storage: %s (From %s)\n"
931 level_to_str(jcr->getJobLevel()),
933 jcr->fileset->name(),
934 NPRT(jcr->pool->name()), jcr->pool_source,
935 jcr->rstore->name(), jcr->rstore_source,
938 bstrutime(dt, sizeof(dt), jcr->sched_time),
944 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
946 jcr->RestoreJobId = str_to_int64(jid);
948 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
951 jcr->RestoreJobId = ua->int64_val;
954 jcr->setJobLevel(L_FULL); /* default level */
955 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
956 if (jcr->RestoreJobId == 0) {
957 /* RegexWhere is take before RestoreWhere */
958 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
960 ua->signal(BNET_RUN_CMD);
961 ua->send_msg("Type: Restore\n"
962 "Title: Run Restore Job\n"
968 "Backup Client: %s\n"
969 "Restore Client: %s\n"
974 "Plugin Options: %s\n",
976 NPRT(jcr->RestoreBootstrap),
977 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
979 jcr->fileset->name(),
983 bstrutime(dt, sizeof(dt), jcr->sched_time),
984 jcr->catalog->name(),
986 NPRT(jcr->plugin_options));
988 ua->send_msg(_("Run Restore job\n"
994 "Backup Client: %s\n"
995 "Restore Client: %s\n"
1000 "Plugin Options: %s\n"),
1002 NPRT(jcr->RestoreBootstrap),
1003 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1005 jcr->fileset->name(),
1007 jcr->client->name(),
1008 jcr->rstore->name(),
1009 bstrutime(dt, sizeof(dt), jcr->sched_time),
1010 jcr->catalog->name(),
1012 NPRT(jcr->plugin_options));
1016 ua->signal(BNET_RUN_CMD);
1017 ua->send_msg("Type: Restore\n"
1018 "Title: Run Restore job\n"
1024 "Backup Client: %s\n"
1025 "Restore Client: %s\n"
1030 "Plugin Options: %s\n",
1032 NPRT(jcr->RestoreBootstrap),
1033 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1035 jcr->fileset->name(),
1037 jcr->client->name(),
1038 jcr->rstore->name(),
1039 bstrutime(dt, sizeof(dt), jcr->sched_time),
1040 jcr->catalog->name(),
1042 NPRT(jcr->plugin_options));
1044 ua->send_msg(_("Run Restore job\n"
1050 "Backup Client: %s\n"
1051 "Restore Client: %s\n"
1056 "Plugin Options: %s\n"),
1058 NPRT(jcr->RestoreBootstrap),
1059 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1061 jcr->fileset->name(),
1063 jcr->client->name(),
1064 jcr->rstore->name(),
1065 bstrutime(dt, sizeof(dt), jcr->sched_time),
1066 jcr->catalog->name(),
1068 NPRT(jcr->plugin_options));
1073 /* ***FIXME*** This needs to be fixed for bat */
1074 if (ua->api) ua->signal(BNET_RUN_CMD);
1075 ua->send_msg(_("Run Restore job\n"
1079 NPRT(jcr->RestoreBootstrap));
1081 /* RegexWhere is take before RestoreWhere */
1082 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1083 ua->send_msg(_("RegexWhere: %s\n"),
1084 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1086 ua->send_msg(_("Where: %s\n"),
1087 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1090 ua->send_msg(_("Replace: %s\n"
1097 "Plugin Options: %s\n"),
1099 jcr->client->name(),
1100 jcr->rstore->name(),
1101 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1102 bstrutime(dt, sizeof(dt), jcr->sched_time),
1103 jcr->catalog->name(),
1105 NPRT(jcr->plugin_options));
1111 jcr->setJobLevel(L_FULL); /* default level */
1113 ua->signal(BNET_RUN_CMD);
1114 if (jcr->getJobType() == JT_COPY) {
1115 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1117 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1125 "Read Storage: %s\n"
1126 "Write Storage: %s\n"
1133 NPRT(jcr->RestoreBootstrap),
1134 jcr->client->name(),
1135 jcr->fileset->name(),
1136 NPRT(jcr->pool->name()),
1137 jcr->rstore->name(),
1138 jcr->wstore?jcr->wstore->name():"*None*",
1139 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1140 bstrutime(dt, sizeof(dt), jcr->sched_time),
1141 jcr->catalog->name(),
1144 if (jcr->getJobType() == JT_COPY) {
1145 prt_type = _("Run Copy job\n");
1147 prt_type = _("Run Migration job\n");
1154 "Pool: %s (From %s)\n"
1155 "Read Storage: %s (From %s)\n"
1156 "Write Storage: %s (From %s)\n"
1163 NPRT(jcr->RestoreBootstrap),
1164 jcr->client->name(),
1165 jcr->fileset->name(),
1166 NPRT(jcr->pool->name()), jcr->pool_source,
1167 jcr->rstore->name(), jcr->rstore_source,
1168 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1169 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1170 bstrutime(dt, sizeof(dt), jcr->sched_time),
1171 jcr->catalog->name(),
1176 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1183 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1187 static const char *kw[] = { /* command line arguments */
1188 "job", /* Used in a switch() */
1196 "regexwhere", /* 8 where string as a bregexp */
1198 "bootstrap", /* 10 */
1201 "priority", /* 13 */
1202 "yes", /* 14 -- if you change this change YES_POS too */
1203 "verifyjob", /* 15 */
1204 "files", /* 16 number of files to restore */
1205 "catalog", /* 17 override catalog */
1206 "since", /* 18 since */
1207 "cloned", /* 19 cloned */
1208 "verifylist", /* 20 verify output list */
1209 "migrationjob", /* 21 migration job name */
1211 "backupclient", /* 23 */
1212 "restoreclient", /* 24 */
1213 "pluginoptions", /* 25 */
1214 "spooldata", /* 26 */
1216 "ignoreduplicatecheck", /* 28 */
1217 "accurate", /* 29 */
1223 rc.catalog_name = NULL;
1225 rc.pool_name = NULL;
1226 rc.store_name = NULL;
1227 rc.client_name = NULL;
1228 rc.restore_client_name = NULL;
1229 rc.fileset_name = NULL;
1230 rc.verify_job_name = NULL;
1231 rc.previous_job_name = NULL;
1232 rc.accurate_set = false;
1233 rc.spool_data_set = false;
1234 rc.ignoreduplicatecheck = false;
1237 for (i=1; i<ua->argc; i++) {
1238 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1240 /* Keep looking until we find a good keyword */
1241 for (j=0; !kw_ok && kw[j]; j++) {
1242 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1243 /* Note, yes and run have no value, so do not fail */
1244 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1245 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1248 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1252 ua->send_msg(_("Job name specified twice.\n"));
1255 rc.job_name = ua->argv[i];
1259 if (rc.jid && !rc.mod) {
1260 ua->send_msg(_("JobId specified twice.\n"));
1263 rc.jid = ua->argv[i];
1266 case 2: /* client */
1268 if (rc.client_name) {
1269 ua->send_msg(_("Client specified twice.\n"));
1272 rc.client_name = ua->argv[i];
1275 case 4: /* fileset */
1276 if (rc.fileset_name) {
1277 ua->send_msg(_("FileSet specified twice.\n"));
1280 rc.fileset_name = ua->argv[i];
1284 if (rc.level_name) {
1285 ua->send_msg(_("Level specified twice.\n"));
1288 rc.level_name = ua->argv[i];
1291 case 6: /* storage */
1293 if (rc.store_name) {
1294 ua->send_msg(_("Storage specified twice.\n"));
1297 rc.store_name = ua->argv[i];
1300 case 8: /* regexwhere */
1301 if ((rc.regexwhere || rc.where) && !rc.mod) {
1302 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1305 rc.regexwhere = ua->argv[i];
1306 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1307 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1313 if ((rc.where || rc.regexwhere) && !rc.mod) {
1314 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1317 rc.where = ua->argv[i];
1318 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1319 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1324 case 10: /* bootstrap */
1325 if (rc.bootstrap && !rc.mod) {
1326 ua->send_msg(_("Bootstrap specified twice.\n"));
1329 rc.bootstrap = ua->argv[i];
1332 case 11: /* replace */
1333 if (rc.replace && !rc.mod) {
1334 ua->send_msg(_("Replace specified twice.\n"));
1337 rc.replace = ua->argv[i];
1341 if (rc.when && !rc.mod) {
1342 ua->send_msg(_("When specified twice.\n"));
1345 rc.when = ua->argv[i];
1348 case 13: /* Priority */
1349 if (rc.Priority && !rc.mod) {
1350 ua->send_msg(_("Priority specified twice.\n"));
1353 rc.Priority = atoi(ua->argv[i]);
1354 if (rc.Priority <= 0) {
1355 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1363 case 15: /* Verify Job */
1364 if (rc.verify_job_name) {
1365 ua->send_msg(_("Verify Job specified twice.\n"));
1368 rc.verify_job_name = ua->argv[i];
1371 case 16: /* files */
1372 rc.files = atoi(ua->argv[i]);
1375 case 17: /* catalog */
1376 rc.catalog_name = ua->argv[i];
1379 case 18: /* since */
1380 rc.since = ua->argv[i];
1383 case 19: /* cloned */
1387 case 20: /* write verify list output */
1388 rc.verify_list = ua->argv[i];
1391 case 21: /* Migration Job */
1392 if (rc.previous_job_name) {
1393 ua->send_msg(_("Migration Job specified twice.\n"));
1396 rc.previous_job_name = ua->argv[i];
1401 ua->send_msg(_("Pool specified twice.\n"));
1404 rc.pool_name = ua->argv[i];
1407 case 23: /* backupclient */
1408 if (rc.client_name) {
1409 ua->send_msg(_("Client specified twice.\n"));
1412 rc.client_name = ua->argv[i];
1415 case 24: /* restoreclient */
1416 if (rc.restore_client_name && !rc.mod) {
1417 ua->send_msg(_("Restore Client specified twice.\n"));
1420 rc.restore_client_name = ua->argv[i];
1423 case 25: /* pluginoptions */
1424 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1426 if (rc.plugin_options) {
1427 ua->send_msg(_("Plugin Options specified twice.\n"));
1430 rc.plugin_options = ua->argv[i];
1431 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1432 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1437 case 26: /* spooldata */
1438 if (rc.spool_data_set) {
1439 ua->send_msg(_("Spool flag specified twice.\n"));
1442 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1443 rc.spool_data_set = true;
1446 ua->send_msg(_("Invalid spooldata flag.\n"));
1449 case 27: /* comment */
1450 rc.comment = ua->argv[i];
1453 case 28: /* ignoreduplicatecheck */
1454 if (rc.ignoreduplicatecheck_set) {
1455 ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1458 if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1459 rc.ignoreduplicatecheck_set = true;
1462 ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1465 case 29: /* accurate */
1466 if (rc.accurate_set) {
1467 ua->send_msg(_("Accurate flag specified twice.\n"));
1470 if (is_yesno(ua->argv[i], &rc.accurate)) {
1471 rc.accurate_set = true;
1474 ua->send_msg(_("Invalid accurate flag.\n"));
1480 } /* end strcase compare */
1481 } /* end keyword loop */
1483 * End of keyword for loop -- if not found, we got a bogus keyword
1486 Dmsg1(800, "%s not found\n", ua->argk[i]);
1488 * Special case for Job Name, it can be the first
1489 * keyword that has no value.
1491 if (!rc.job_name && !ua->argv[i]) {
1492 rc.job_name = ua->argk[i]; /* use keyword as job name */
1493 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1495 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1499 } /* end argc loop */
1501 Dmsg0(800, "Done scan.\n");
1503 if (!is_comment_legal(ua, rc.comment)) {
1507 if (rc.catalog_name) {
1508 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1509 if (rc.catalog == NULL) {
1510 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1513 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1514 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1518 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1522 rc.job = GetJobResWithName(rc.job_name);
1524 if (*rc.job_name != 0) {
1525 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1527 rc.job = select_job_resource(ua);
1529 Dmsg1(800, "Found job=%s\n", rc.job_name);
1531 } else if (!rc.job) {
1532 ua->send_msg(_("A job name must be specified.\n"));
1533 rc.job = select_job_resource(ua);
1537 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1538 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1543 rc.pool = GetPoolResWithName(rc.pool_name);
1545 if (*rc.pool_name != 0) {
1546 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1548 rc.pool = select_pool_resource(ua);
1550 } else if (!rc.pool) {
1551 rc.pool = rc.job->pool; /* use default */
1555 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1556 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1559 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1561 if (rc.store_name) {
1562 rc.store->store = GetStoreResWithName(rc.store_name);
1563 pm_strcpy(rc.store->store_source, _("command line"));
1564 if (!rc.store->store) {
1565 if (*rc.store_name != 0) {
1566 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1568 rc.store->store = select_storage_resource(ua);
1569 pm_strcpy(rc.store->store_source, _("user selection"));
1571 } else if (!rc.store->store) {
1572 get_job_storage(rc.store, rc.job, NULL); /* use default */
1574 if (!rc.store->store) {
1575 ua->error_msg(_("No storage specified.\n"));
1577 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1578 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1579 rc.store->store->name());
1582 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1584 if (rc.client_name) {
1585 rc.client = GetClientResWithName(rc.client_name);
1587 if (*rc.client_name != 0) {
1588 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1590 rc.client = select_client_resource(ua);
1592 } else if (!rc.client) {
1593 rc.client = rc.job->client; /* use default */
1597 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1598 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1602 Dmsg1(800, "Using client=%s\n", rc.client->name());
1604 if (rc.restore_client_name) {
1605 rc.client = GetClientResWithName(rc.restore_client_name);
1607 if (*rc.restore_client_name != 0) {
1608 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1610 rc.client = select_client_resource(ua);
1612 } else if (!rc.client) {
1613 rc.client = rc.job->client; /* use default */
1617 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1618 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1622 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1624 if (rc.fileset_name) {
1625 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1627 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1628 rc.fileset = select_fileset_resource(ua);
1630 } else if (!rc.fileset) {
1631 rc.fileset = rc.job->fileset; /* use default */
1635 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1636 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1637 rc.fileset->name());
1641 if (rc.verify_job_name) {
1642 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1643 if (!rc.verify_job) {
1644 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1645 rc.verify_job = select_job_resource(ua);
1647 } else if (!rc.verify_job) {
1648 rc.verify_job = rc.job->verify_job;
1651 if (rc.previous_job_name) {
1652 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1653 if (!rc.previous_job) {
1654 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1655 rc.previous_job = select_job_resource(ua);
1658 rc.previous_job = rc.job->verify_job;