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));
202 ua->send_msg(_("Job not run.\n"));
204 return 0; /* do not run */
207 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
211 /* Some options are not available through the menu
212 * TODO: Add an advanced menu?
214 if (rc.spool_data_set) {
215 jcr->spool_data = rc.spool_data;
218 if (rc.accurate_set) {
219 jcr->accurate = rc.accurate;
222 /* Used by migration jobs that can have the same name,
223 * but can run at the same time
225 if (rc.ignoreduplicatecheck_set) {
226 jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
230 * At user request modify parameters of job to be run.
232 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
235 start_prompt(ua, _("Parameters to modify:\n"));
236 add_prompt(ua, _("Level")); /* 0 */
237 add_prompt(ua, _("Storage")); /* 1 */
238 add_prompt(ua, _("Job")); /* 2 */
239 add_prompt(ua, _("FileSet")); /* 3 */
240 if (jcr->getJobType() == JT_RESTORE) {
241 add_prompt(ua, _("Restore Client")); /* 4 */
243 add_prompt(ua, _("Client")); /* 4 */
245 add_prompt(ua, _("When")); /* 5 */
246 add_prompt(ua, _("Priority")); /* 6 */
247 if (jcr->getJobType() == JT_BACKUP ||
248 jcr->getJobType() == JT_COPY ||
249 jcr->getJobType() == JT_MIGRATE ||
250 jcr->getJobType() == JT_VERIFY) {
251 add_prompt(ua, _("Pool")); /* 7 */
252 if (jcr->getJobType() == JT_VERIFY) {
253 add_prompt(ua, _("Verify Job")); /* 8 */
255 } else if (jcr->getJobType() == JT_RESTORE) {
256 add_prompt(ua, _("Bootstrap")); /* 7 */
257 add_prompt(ua, _("Where")); /* 8 */
258 add_prompt(ua, _("File Relocation"));/* 9 */
259 add_prompt(ua, _("Replace")); /* 10 */
260 add_prompt(ua, _("JobId")); /* 11 */
262 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
263 add_prompt(ua, _("Plugin Options")); /* 12 */
265 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
268 select_job_level(ua, jcr);
272 rc.store->store = select_storage_resource(ua);
273 if (rc.store->store) {
274 pm_strcpy(rc.store->store_source, _("user selection"));
275 set_rwstorage(jcr, rc.store);
281 rc.job = select_job_resource(ua);
284 set_jcr_defaults(jcr, rc.job);
290 rc.fileset = select_fileset_resource(ua);
292 jcr->fileset = rc.fileset;
298 rc.client = select_client_resource(ua);
300 jcr->client = rc.client;
306 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
309 if (ua->cmd[0] == 0) {
310 jcr->sched_time = time(NULL);
312 jcr->sched_time = str_to_utime(ua->cmd);
313 if (jcr->sched_time == 0) {
314 ua->send_msg(_("Invalid time, using current time.\n"));
315 jcr->sched_time = time(NULL);
321 if (!get_pint(ua, _("Enter new Priority: "))) {
324 if (ua->pint32_val == 0) {
325 ua->send_msg(_("Priority must be a positive integer.\n"));
327 jcr->JobPriority = ua->pint32_val;
331 /* Pool or Bootstrap depending on JobType */
332 if (jcr->getJobType() == JT_BACKUP ||
333 jcr->getJobType() == JT_COPY ||
334 jcr->getJobType() == JT_MIGRATE ||
335 jcr->getJobType() == JT_VERIFY) { /* Pool */
336 rc.pool = select_pool_resource(ua);
339 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
346 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
349 if (jcr->RestoreBootstrap) {
350 free(jcr->RestoreBootstrap);
351 jcr->RestoreBootstrap = NULL;
353 if (ua->cmd[0] != 0) {
354 jcr->RestoreBootstrap = bstrdup(ua->cmd);
355 fd = fopen(jcr->RestoreBootstrap, "rb");
358 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
359 jcr->RestoreBootstrap, be.bstrerror());
360 free(jcr->RestoreBootstrap);
361 jcr->RestoreBootstrap = NULL;
369 if (jcr->getJobType() == JT_VERIFY) {
370 rc.verify_job = select_job_resource(ua);
372 jcr->verify_job = rc.verify_job;
377 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
380 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
381 free(jcr->RegexWhere);
382 jcr->RegexWhere = NULL;
388 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
391 jcr->where = bstrdup(ua->cmd);
394 /* File relocation */
395 select_where_regexp(ua, jcr);
399 start_prompt(ua, _("Replace:\n"));
400 for (i=0; ReplaceOptions[i].name; i++) {
401 add_prompt(ua, ReplaceOptions[i].name);
403 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
405 rc.replace = ReplaceOptions[opt].name;
406 jcr->replace = ReplaceOptions[opt].token;
411 rc.jid = NULL; /* force reprompt */
412 jcr->RestoreJobId = 0;
413 if (jcr->RestoreBootstrap) {
414 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
419 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
422 if (jcr->plugin_options) {
423 free(jcr->plugin_options);
424 jcr->plugin_options = NULL;
426 jcr->plugin_options = bstrdup(ua->cmd);
428 case -1: /* error or cancel */
445 * Reset the restore context.
446 * This subroutine can be called multiple times, so it
447 * must keep any prior settings.
449 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
453 jcr->verify_job = rc.verify_job;
454 jcr->previous_job = rc.previous_job;
456 if (jcr->pool != jcr->job->pool) {
457 pm_strcpy(jcr->pool_source, _("User input"));
459 set_rwstorage(jcr, rc.store);
460 jcr->client = rc.client;
461 pm_strcpy(jcr->client_name, rc.client->name());
462 jcr->fileset = rc.fileset;
463 jcr->ExpectedFiles = rc.files;
465 jcr->catalog = rc.catalog;
466 pm_strcpy(jcr->catalog_source, _("User input"));
469 pm_strcpy(jcr->comment, rc.comment);
475 jcr->where = bstrdup(rc.where);
480 if (jcr->RegexWhere) {
481 free(jcr->RegexWhere);
483 jcr->RegexWhere = bstrdup(rc.regexwhere);
484 rc.regexwhere = NULL;
488 jcr->sched_time = str_to_utime(rc.when);
489 if (jcr->sched_time == 0) {
490 ua->send_msg(_("Invalid time, using current time.\n"));
491 jcr->sched_time = time(NULL);
497 if (jcr->RestoreBootstrap) {
498 free(jcr->RestoreBootstrap);
500 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
504 if (rc.plugin_options) {
505 if (jcr->plugin_options) {
506 free(jcr->plugin_options);
508 jcr->plugin_options = bstrdup(rc.plugin_options);
509 rc.plugin_options = NULL;
514 for (i=0; ReplaceOptions[i].name; i++) {
515 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
516 jcr->replace = ReplaceOptions[i].token;
520 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
523 } else if (rc.job->replace) {
524 jcr->replace = rc.job->replace;
526 jcr->replace = REPLACE_ALWAYS;
531 jcr->JobPriority = rc.Priority;
537 jcr->stime = get_pool_memory(PM_MESSAGE);
539 pm_strcpy(jcr->stime, rc.since);
544 jcr->cloned = rc.cloned;
548 /* If pool changed, update migration write storage */
549 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
550 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
551 if (!set_migration_wstorage(jcr, rc.pool)) {
555 rc.replace = ReplaceOptions[0].name;
556 for (i=0; ReplaceOptions[i].name; i++) {
557 if (ReplaceOptions[i].token == jcr->replace) {
558 rc.replace = ReplaceOptions[i].name;
562 if (!get_level_from_name(jcr, rc.level_name)) {
563 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
566 rc.level_name = NULL;
569 /* Note, this is also MigrateJobId and a VerifyJobId */
570 jcr->RestoreJobId = str_to_int64(rc.jid);
576 static void select_where_regexp(UAContext *ua, JCR *jcr)
579 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
580 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
583 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
584 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
586 start_prompt(ua, _("This will replace your current Where value\n"));
587 add_prompt(ua, _("Strip prefix")); /* 0 */
588 add_prompt(ua, _("Add prefix")); /* 1 */
589 add_prompt(ua, _("Add file suffix")); /* 2 */
590 add_prompt(ua, _("Enter a regexp")); /* 3 */
591 add_prompt(ua, _("Test filename manipulation")); /* 4 */
592 add_prompt(ua, _("Use this ?")); /* 5 */
594 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
597 if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
598 if (strip_prefix) bfree(strip_prefix);
599 strip_prefix = bstrdup(ua->cmd);
605 if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
606 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
610 if (add_prefix) bfree(add_prefix);
611 add_prefix = bstrdup(ua->cmd);
616 if (get_cmd(ua, _("Please enter file suffix to add: "))) {
617 if (add_suffix) bfree(add_suffix);
618 add_suffix = bstrdup(ua->cmd);
623 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
624 if (rwhere) bfree(rwhere);
625 rwhere = bstrdup(ua->cmd);
634 if (rwhere && rwhere[0] != '\0') {
635 regs = get_bregexps(rwhere);
636 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
638 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
639 regexp = (char *) bmalloc (len * sizeof(char));
640 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
641 regs = get_bregexps(regexp);
642 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
643 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
649 ua->send_msg(_("Cannot use your regexp\n"));
652 ua->send_msg(_("Enter a period (.) to stop this test\n"));
653 while (get_cmd(ua, _("Please enter filename to test: "))) {
654 apply_bregexps(ua->cmd, regs, &result);
655 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
664 case -1: /* error or cancel */
670 /* replace the existing where */
676 /* replace the existing regexwhere */
677 if (jcr->RegexWhere) {
678 bfree(jcr->RegexWhere);
679 jcr->RegexWhere = NULL;
683 jcr->RegexWhere = bstrdup(rwhere);
684 } else if (strip_prefix || add_prefix || add_suffix) {
685 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
686 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
687 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
690 regs = get_bregexps(jcr->RegexWhere);
695 if (jcr->RegexWhere) {
696 bfree(jcr->RegexWhere);
697 jcr->RegexWhere = NULL;
699 ua->send_msg(_("Cannot use your regexp.\n"));
703 if (strip_prefix) bfree(strip_prefix);
704 if (add_prefix) bfree(add_prefix);
705 if (add_suffix) bfree(add_suffix);
706 if (rwhere) bfree(rwhere);
709 static void select_job_level(UAContext *ua, JCR *jcr)
711 if (jcr->getJobType() == JT_BACKUP) {
712 start_prompt(ua, _("Levels:\n"));
713 // add_prompt(ua, _("Base"));
714 add_prompt(ua, _("Full"));
715 add_prompt(ua, _("Incremental"));
716 add_prompt(ua, _("Differential"));
717 add_prompt(ua, _("Since"));
718 add_prompt(ua, _("VirtualFull"));
719 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
721 // jcr->JobLevel = L_BASE;
724 jcr->setJobLevel(L_FULL);
727 jcr->setJobLevel(L_INCREMENTAL);
730 jcr->setJobLevel(L_DIFFERENTIAL);
733 jcr->setJobLevel(L_SINCE);
736 jcr->setJobLevel(L_VIRTUAL_FULL);
741 } else if (jcr->getJobType() == JT_VERIFY) {
742 start_prompt(ua, _("Levels:\n"));
743 add_prompt(ua, _("Initialize Catalog"));
744 add_prompt(ua, _("Verify Catalog"));
745 add_prompt(ua, _("Verify Volume to Catalog"));
746 add_prompt(ua, _("Verify Disk to Catalog"));
747 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
748 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
750 jcr->setJobLevel(L_VERIFY_INIT);
753 jcr->setJobLevel(L_VERIFY_CATALOG);
756 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
759 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
762 jcr->setJobLevel(L_VERIFY_DATA);
768 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
773 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
774 char *jid, const char *replace, char *client_name)
777 char dt[MAX_TIME_LENGTH];
779 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
780 switch (jcr->getJobType()) {
783 ua->signal(BNET_RUN_CMD);
784 ua->send_msg("Type: Admin\n"
785 "Title: Run Admin Job\n"
793 jcr->fileset->name(),
794 NPRT(jcr->client->name()),
795 jcr->wstore?jcr->wstore->name():"*None*",
796 bstrutime(dt, sizeof(dt), jcr->sched_time),
799 ua->send_msg(_("Run Admin Job\n"
807 jcr->fileset->name(),
808 NPRT(jcr->client->name()),
809 jcr->wstore?jcr->wstore->name():"*None*",
810 bstrutime(dt, sizeof(dt), jcr->sched_time),
813 jcr->setJobLevel(L_FULL);
817 if (jcr->getJobType() == JT_BACKUP) {
819 ua->signal(BNET_RUN_CMD);
820 ua->send_msg("Type: Backup\n"
821 "Title: Run Backup Job\n"
832 level_to_str(jcr->getJobLevel()),
834 jcr->fileset->name(),
835 NPRT(jcr->pool->name()),
836 jcr->wstore?jcr->wstore->name():"*None*",
837 bstrutime(dt, sizeof(dt), jcr->sched_time),
839 jcr->plugin_options?"Plugin Options: ":"",
840 jcr->plugin_options?jcr->plugin_options:"",
841 jcr->plugin_options?"\n":"");
843 ua->send_msg(_("Run Backup job\n"
848 "Pool: %s (From %s)\n"
849 "Storage: %s (From %s)\n"
854 level_to_str(jcr->getJobLevel()),
856 jcr->fileset->name(),
857 NPRT(jcr->pool->name()), jcr->pool_source,
858 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
859 bstrutime(dt, sizeof(dt), jcr->sched_time),
861 jcr->plugin_options?"Plugin Options: ":"",
862 jcr->plugin_options?jcr->plugin_options:"",
863 jcr->plugin_options?"\n":"");
865 } else { /* JT_VERIFY */
868 if (jcr->verify_job) {
869 Name = jcr->verify_job->name();
870 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
871 memset(&jr, 0, sizeof(jr));
872 jr.JobId = jcr->RestoreJobId;
873 if (!db_get_job_record(jcr, ua->db, &jr)) {
874 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
875 db_strerror(ua->db));
883 verify_list = job->WriteVerifyList;
889 ua->signal(BNET_RUN_CMD);
890 ua->send_msg("Type: Verify\n"
891 "Title: Run Verify Job\n"
896 "Pool: %s (From %s)\n"
897 "Storage: %s (From %s)\n"
903 level_to_str(jcr->getJobLevel()),
905 jcr->fileset->name(),
906 NPRT(jcr->pool->name()), jcr->pool_source,
907 jcr->rstore->name(), jcr->rstore_source,
910 bstrutime(dt, sizeof(dt), jcr->sched_time),
913 ua->send_msg(_("Run Verify Job\n"
918 "Pool: %s (From %s)\n"
919 "Storage: %s (From %s)\n"
925 level_to_str(jcr->getJobLevel()),
927 jcr->fileset->name(),
928 NPRT(jcr->pool->name()), jcr->pool_source,
929 jcr->rstore->name(), jcr->rstore_source,
932 bstrutime(dt, sizeof(dt), jcr->sched_time),
938 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
940 jcr->RestoreJobId = str_to_int64(jid);
942 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
945 jcr->RestoreJobId = ua->int64_val;
948 jcr->setJobLevel(L_FULL); /* default level */
949 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
950 if (jcr->RestoreJobId == 0) {
951 /* RegexWhere is take before RestoreWhere */
952 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
954 ua->signal(BNET_RUN_CMD);
955 ua->send_msg("Type: Restore\n"
956 "Title: Run Restore Job\n"
962 "Backup Client: %s\n"
963 "Restore Client: %s\n"
968 "Plugin Options: %s\n",
970 NPRT(jcr->RestoreBootstrap),
971 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
973 jcr->fileset->name(),
977 bstrutime(dt, sizeof(dt), jcr->sched_time),
978 jcr->catalog->name(),
980 NPRT(jcr->plugin_options));
982 ua->send_msg(_("Run Restore job\n"
988 "Backup Client: %s\n"
989 "Restore Client: %s\n"
994 "Plugin Options: %s\n"),
996 NPRT(jcr->RestoreBootstrap),
997 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
999 jcr->fileset->name(),
1001 jcr->client->name(),
1002 jcr->rstore->name(),
1003 bstrutime(dt, sizeof(dt), jcr->sched_time),
1004 jcr->catalog->name(),
1006 NPRT(jcr->plugin_options));
1010 ua->signal(BNET_RUN_CMD);
1011 ua->send_msg("Type: Restore\n"
1012 "Title: Run Restore job\n"
1018 "Backup Client: %s\n"
1019 "Restore Client: %s\n"
1024 "Plugin Options: %s\n",
1026 NPRT(jcr->RestoreBootstrap),
1027 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1029 jcr->fileset->name(),
1031 jcr->client->name(),
1032 jcr->rstore->name(),
1033 bstrutime(dt, sizeof(dt), jcr->sched_time),
1034 jcr->catalog->name(),
1036 NPRT(jcr->plugin_options));
1038 ua->send_msg(_("Run Restore job\n"
1044 "Backup Client: %s\n"
1045 "Restore Client: %s\n"
1050 "Plugin Options: %s\n"),
1052 NPRT(jcr->RestoreBootstrap),
1053 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1055 jcr->fileset->name(),
1057 jcr->client->name(),
1058 jcr->rstore->name(),
1059 bstrutime(dt, sizeof(dt), jcr->sched_time),
1060 jcr->catalog->name(),
1062 NPRT(jcr->plugin_options));
1067 /* ***FIXME*** This needs to be fixed for bat */
1068 if (ua->api) ua->signal(BNET_RUN_CMD);
1069 ua->send_msg(_("Run Restore job\n"
1073 NPRT(jcr->RestoreBootstrap));
1075 /* RegexWhere is take before RestoreWhere */
1076 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1077 ua->send_msg(_("RegexWhere: %s\n"),
1078 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1080 ua->send_msg(_("Where: %s\n"),
1081 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1084 ua->send_msg(_("Replace: %s\n"
1091 "Plugin Options: %s\n"),
1093 jcr->client->name(),
1094 jcr->rstore->name(),
1095 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1096 bstrutime(dt, sizeof(dt), jcr->sched_time),
1097 jcr->catalog->name(),
1099 NPRT(jcr->plugin_options));
1105 jcr->setJobLevel(L_FULL); /* default level */
1107 ua->signal(BNET_RUN_CMD);
1108 if (jcr->getJobType() == JT_COPY) {
1109 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1111 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1119 "Read Storage: %s\n"
1120 "Write Storage: %s\n"
1127 NPRT(jcr->RestoreBootstrap),
1128 jcr->client->name(),
1129 jcr->fileset->name(),
1130 NPRT(jcr->pool->name()),
1131 jcr->rstore->name(),
1132 jcr->wstore?jcr->wstore->name():"*None*",
1133 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1134 bstrutime(dt, sizeof(dt), jcr->sched_time),
1135 jcr->catalog->name(),
1138 if (jcr->getJobType() == JT_COPY) {
1139 prt_type = _("Run Copy job\n");
1141 prt_type = _("Run Migration job\n");
1148 "Pool: %s (From %s)\n"
1149 "Read Storage: %s (From %s)\n"
1150 "Write Storage: %s (From %s)\n"
1157 NPRT(jcr->RestoreBootstrap),
1158 jcr->client->name(),
1159 jcr->fileset->name(),
1160 NPRT(jcr->pool->name()), jcr->pool_source,
1161 jcr->rstore->name(), jcr->rstore_source,
1162 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1163 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1164 bstrutime(dt, sizeof(dt), jcr->sched_time),
1165 jcr->catalog->name(),
1170 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1177 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1181 static const char *kw[] = { /* command line arguments */
1182 "job", /* Used in a switch() */
1190 "regexwhere", /* 8 where string as a bregexp */
1192 "bootstrap", /* 10 */
1195 "priority", /* 13 */
1196 "yes", /* 14 -- if you change this change YES_POS too */
1197 "verifyjob", /* 15 */
1198 "files", /* 16 number of files to restore */
1199 "catalog", /* 17 override catalog */
1200 "since", /* 18 since */
1201 "cloned", /* 19 cloned */
1202 "verifylist", /* 20 verify output list */
1203 "migrationjob", /* 21 migration job name */
1205 "backupclient", /* 23 */
1206 "restoreclient", /* 24 */
1207 "pluginoptions", /* 25 */
1208 "spooldata", /* 26 */
1210 "ignoreduplicatecheck", /* 28 */
1211 "accurate", /* 29 */
1217 rc.catalog_name = NULL;
1219 rc.pool_name = NULL;
1220 rc.store_name = NULL;
1221 rc.client_name = NULL;
1222 rc.restore_client_name = NULL;
1223 rc.fileset_name = NULL;
1224 rc.verify_job_name = NULL;
1225 rc.previous_job_name = NULL;
1226 rc.accurate_set = false;
1227 rc.spool_data_set = false;
1228 rc.ignoreduplicatecheck = false;
1231 for (i=1; i<ua->argc; i++) {
1232 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1234 /* Keep looking until we find a good keyword */
1235 for (j=0; !kw_ok && kw[j]; j++) {
1236 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1237 /* Note, yes and run have no value, so do not fail */
1238 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1239 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1242 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1246 ua->send_msg(_("Job name specified twice.\n"));
1249 rc.job_name = ua->argv[i];
1253 if (rc.jid && !rc.mod) {
1254 ua->send_msg(_("JobId specified twice.\n"));
1257 rc.jid = ua->argv[i];
1260 case 2: /* client */
1262 if (rc.client_name) {
1263 ua->send_msg(_("Client specified twice.\n"));
1266 rc.client_name = ua->argv[i];
1269 case 4: /* fileset */
1270 if (rc.fileset_name) {
1271 ua->send_msg(_("FileSet specified twice.\n"));
1274 rc.fileset_name = ua->argv[i];
1278 if (rc.level_name) {
1279 ua->send_msg(_("Level specified twice.\n"));
1282 rc.level_name = ua->argv[i];
1285 case 6: /* storage */
1287 if (rc.store_name) {
1288 ua->send_msg(_("Storage specified twice.\n"));
1291 rc.store_name = ua->argv[i];
1294 case 8: /* regexwhere */
1295 if ((rc.regexwhere || rc.where) && !rc.mod) {
1296 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1299 rc.regexwhere = ua->argv[i];
1300 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1301 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1307 if ((rc.where || rc.regexwhere) && !rc.mod) {
1308 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1311 rc.where = ua->argv[i];
1312 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1313 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1318 case 10: /* bootstrap */
1319 if (rc.bootstrap && !rc.mod) {
1320 ua->send_msg(_("Bootstrap specified twice.\n"));
1323 rc.bootstrap = ua->argv[i];
1326 case 11: /* replace */
1327 if (rc.replace && !rc.mod) {
1328 ua->send_msg(_("Replace specified twice.\n"));
1331 rc.replace = ua->argv[i];
1335 if (rc.when && !rc.mod) {
1336 ua->send_msg(_("When specified twice.\n"));
1339 rc.when = ua->argv[i];
1342 case 13: /* Priority */
1343 if (rc.Priority && !rc.mod) {
1344 ua->send_msg(_("Priority specified twice.\n"));
1347 rc.Priority = atoi(ua->argv[i]);
1348 if (rc.Priority <= 0) {
1349 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1357 case 15: /* Verify Job */
1358 if (rc.verify_job_name) {
1359 ua->send_msg(_("Verify Job specified twice.\n"));
1362 rc.verify_job_name = ua->argv[i];
1365 case 16: /* files */
1366 rc.files = atoi(ua->argv[i]);
1369 case 17: /* catalog */
1370 rc.catalog_name = ua->argv[i];
1373 case 18: /* since */
1374 rc.since = ua->argv[i];
1377 case 19: /* cloned */
1381 case 20: /* write verify list output */
1382 rc.verify_list = ua->argv[i];
1385 case 21: /* Migration Job */
1386 if (rc.previous_job_name) {
1387 ua->send_msg(_("Migration Job specified twice.\n"));
1390 rc.previous_job_name = ua->argv[i];
1395 ua->send_msg(_("Pool specified twice.\n"));
1398 rc.pool_name = ua->argv[i];
1401 case 23: /* backupclient */
1402 if (rc.client_name) {
1403 ua->send_msg(_("Client specified twice.\n"));
1406 rc.client_name = ua->argv[i];
1409 case 24: /* restoreclient */
1410 if (rc.restore_client_name && !rc.mod) {
1411 ua->send_msg(_("Restore Client specified twice.\n"));
1414 rc.restore_client_name = ua->argv[i];
1417 case 25: /* pluginoptions */
1418 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1420 if (rc.plugin_options) {
1421 ua->send_msg(_("Plugin Options specified twice.\n"));
1424 rc.plugin_options = ua->argv[i];
1425 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1426 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1431 case 26: /* spooldata */
1432 if (rc.spool_data_set) {
1433 ua->send_msg(_("Spool flag specified twice.\n"));
1436 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1437 rc.spool_data_set = true;
1440 ua->send_msg(_("Invalid spooldata flag.\n"));
1443 case 27: /* comment */
1444 rc.comment = ua->argv[i];
1447 case 28: /* ignoreduplicatecheck */
1448 if (rc.ignoreduplicatecheck_set) {
1449 ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1452 if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1453 rc.ignoreduplicatecheck_set = true;
1456 ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1459 case 29: /* accurate */
1460 if (rc.accurate_set) {
1461 ua->send_msg(_("Accurate flag specified twice.\n"));
1464 if (is_yesno(ua->argv[i], &rc.accurate)) {
1465 rc.accurate_set = true;
1468 ua->send_msg(_("Invalid accurate flag.\n"));
1474 } /* end strcase compare */
1475 } /* end keyword loop */
1477 * End of keyword for loop -- if not found, we got a bogus keyword
1480 Dmsg1(800, "%s not found\n", ua->argk[i]);
1482 * Special case for Job Name, it can be the first
1483 * keyword that has no value.
1485 if (!rc.job_name && !ua->argv[i]) {
1486 rc.job_name = ua->argk[i]; /* use keyword as job name */
1487 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1489 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1493 } /* end argc loop */
1495 Dmsg0(800, "Done scan.\n");
1497 if (!is_comment_legal(ua, rc.comment)) {
1501 if (rc.catalog_name) {
1502 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1503 if (rc.catalog == NULL) {
1504 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1507 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1508 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1512 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1516 rc.job = GetJobResWithName(rc.job_name);
1518 if (*rc.job_name != 0) {
1519 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1521 rc.job = select_job_resource(ua);
1523 Dmsg1(800, "Found job=%s\n", rc.job_name);
1525 } else if (!rc.job) {
1526 ua->send_msg(_("A job name must be specified.\n"));
1527 rc.job = select_job_resource(ua);
1531 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1532 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1537 rc.pool = GetPoolResWithName(rc.pool_name);
1539 if (*rc.pool_name != 0) {
1540 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1542 rc.pool = select_pool_resource(ua);
1544 } else if (!rc.pool) {
1545 rc.pool = rc.job->pool; /* use default */
1549 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1550 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1553 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1555 if (rc.store_name) {
1556 rc.store->store = GetStoreResWithName(rc.store_name);
1557 pm_strcpy(rc.store->store_source, _("command line"));
1558 if (!rc.store->store) {
1559 if (*rc.store_name != 0) {
1560 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1562 rc.store->store = select_storage_resource(ua);
1563 pm_strcpy(rc.store->store_source, _("user selection"));
1565 } else if (!rc.store->store) {
1566 get_job_storage(rc.store, rc.job, NULL); /* use default */
1568 if (!rc.store->store) {
1569 ua->error_msg(_("No storage specified.\n"));
1571 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1572 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1573 rc.store->store->name());
1576 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1578 if (rc.client_name) {
1579 rc.client = GetClientResWithName(rc.client_name);
1581 if (*rc.client_name != 0) {
1582 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1584 rc.client = select_client_resource(ua);
1586 } else if (!rc.client) {
1587 rc.client = rc.job->client; /* use default */
1591 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1592 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1596 Dmsg1(800, "Using client=%s\n", rc.client->name());
1598 if (rc.restore_client_name) {
1599 rc.client = GetClientResWithName(rc.restore_client_name);
1601 if (*rc.restore_client_name != 0) {
1602 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1604 rc.client = select_client_resource(ua);
1606 } else if (!rc.client) {
1607 rc.client = rc.job->client; /* use default */
1611 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1612 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1616 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1618 if (rc.fileset_name) {
1619 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1621 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1622 rc.fileset = select_fileset_resource(ua);
1624 } else if (!rc.fileset) {
1625 rc.fileset = rc.job->fileset; /* use default */
1629 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1630 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1631 rc.fileset->name());
1635 if (rc.verify_job_name) {
1636 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1637 if (!rc.verify_job) {
1638 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1639 rc.verify_job = select_job_resource(ua);
1641 } else if (!rc.verify_job) {
1642 rc.verify_job = rc.job->verify_job;
1645 if (rc.previous_job_name) {
1646 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1647 if (!rc.previous_job) {
1648 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1649 rc.previous_job = select_job_resource(ua);
1652 rc.previous_job = rc.job->verify_job;