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)
212 * At user request modify parameters of job to be run.
214 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
217 start_prompt(ua, _("Parameters to modify:\n"));
218 add_prompt(ua, _("Level")); /* 0 */
219 add_prompt(ua, _("Storage")); /* 1 */
220 add_prompt(ua, _("Job")); /* 2 */
221 add_prompt(ua, _("FileSet")); /* 3 */
222 if (jcr->getJobType() == JT_RESTORE) {
223 add_prompt(ua, _("Restore Client")); /* 4 */
225 add_prompt(ua, _("Client")); /* 4 */
227 add_prompt(ua, _("When")); /* 5 */
228 add_prompt(ua, _("Priority")); /* 6 */
229 if (jcr->getJobType() == JT_BACKUP ||
230 jcr->getJobType() == JT_COPY ||
231 jcr->getJobType() == JT_MIGRATE ||
232 jcr->getJobType() == JT_VERIFY) {
233 add_prompt(ua, _("Pool")); /* 7 */
234 if (jcr->getJobType() == JT_VERIFY) {
235 add_prompt(ua, _("Verify Job")); /* 8 */
237 } else if (jcr->getJobType() == JT_RESTORE) {
238 add_prompt(ua, _("Bootstrap")); /* 7 */
239 add_prompt(ua, _("Where")); /* 8 */
240 add_prompt(ua, _("File Relocation"));/* 9 */
241 add_prompt(ua, _("Replace")); /* 10 */
242 add_prompt(ua, _("JobId")); /* 11 */
244 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
245 add_prompt(ua, _("Plugin Options")); /* 12 */
247 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
250 select_job_level(ua, jcr);
254 rc.store->store = select_storage_resource(ua);
255 if (rc.store->store) {
256 pm_strcpy(rc.store->store_source, _("user selection"));
257 set_rwstorage(jcr, rc.store);
263 rc.job = select_job_resource(ua);
266 set_jcr_defaults(jcr, rc.job);
272 rc.fileset = select_fileset_resource(ua);
274 jcr->fileset = rc.fileset;
280 rc.client = select_client_resource(ua);
282 jcr->client = rc.client;
288 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
291 if (ua->cmd[0] == 0) {
292 jcr->sched_time = time(NULL);
294 jcr->sched_time = str_to_utime(ua->cmd);
295 if (jcr->sched_time == 0) {
296 ua->send_msg(_("Invalid time, using current time.\n"));
297 jcr->sched_time = time(NULL);
303 if (!get_pint(ua, _("Enter new Priority: "))) {
306 if (ua->pint32_val == 0) {
307 ua->send_msg(_("Priority must be a positive integer.\n"));
309 jcr->JobPriority = ua->pint32_val;
313 /* Pool or Bootstrap depending on JobType */
314 if (jcr->getJobType() == JT_BACKUP ||
315 jcr->getJobType() == JT_COPY ||
316 jcr->getJobType() == JT_MIGRATE ||
317 jcr->getJobType() == JT_VERIFY) { /* Pool */
318 rc.pool = select_pool_resource(ua);
321 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
328 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
331 if (jcr->RestoreBootstrap) {
332 free(jcr->RestoreBootstrap);
333 jcr->RestoreBootstrap = NULL;
335 if (ua->cmd[0] != 0) {
336 jcr->RestoreBootstrap = bstrdup(ua->cmd);
337 fd = fopen(jcr->RestoreBootstrap, "rb");
340 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
341 jcr->RestoreBootstrap, be.bstrerror());
342 free(jcr->RestoreBootstrap);
343 jcr->RestoreBootstrap = NULL;
351 if (jcr->getJobType() == JT_VERIFY) {
352 rc.verify_job = select_job_resource(ua);
354 jcr->verify_job = rc.verify_job;
359 if (!get_cmd(ua, _("Please enter the full path prefix for restore (/ for none): "))) {
362 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
363 free(jcr->RegexWhere);
364 jcr->RegexWhere = NULL;
370 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
373 jcr->where = bstrdup(ua->cmd);
376 /* File relocation */
377 select_where_regexp(ua, jcr);
381 start_prompt(ua, _("Replace:\n"));
382 for (i=0; ReplaceOptions[i].name; i++) {
383 add_prompt(ua, ReplaceOptions[i].name);
385 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
387 rc.replace = ReplaceOptions[opt].name;
388 jcr->replace = ReplaceOptions[opt].token;
393 rc.jid = NULL; /* force reprompt */
394 jcr->RestoreJobId = 0;
395 if (jcr->RestoreBootstrap) {
396 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
401 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
404 if (jcr->plugin_options) {
405 free(jcr->plugin_options);
406 jcr->plugin_options = NULL;
408 jcr->plugin_options = bstrdup(ua->cmd);
410 case -1: /* error or cancel */
427 * Reset the restore context.
428 * This subroutine can be called multiple times, so it
429 * must keep any prior settings.
431 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
435 jcr->verify_job = rc.verify_job;
436 jcr->previous_job = rc.previous_job;
438 if (jcr->pool != jcr->job->pool) {
439 pm_strcpy(jcr->pool_source, _("User input"));
441 set_rwstorage(jcr, rc.store);
442 jcr->client = rc.client;
443 pm_strcpy(jcr->client_name, rc.client->name());
444 jcr->fileset = rc.fileset;
445 jcr->ExpectedFiles = rc.files;
447 jcr->catalog = rc.catalog;
448 pm_strcpy(jcr->catalog_source, _("User input"));
451 pm_strcpy(jcr->comment, rc.comment);
457 jcr->where = bstrdup(rc.where);
462 if (jcr->RegexWhere) {
463 free(jcr->RegexWhere);
465 jcr->RegexWhere = bstrdup(rc.regexwhere);
466 rc.regexwhere = NULL;
470 jcr->sched_time = str_to_utime(rc.when);
471 if (jcr->sched_time == 0) {
472 ua->send_msg(_("Invalid time, using current time.\n"));
473 jcr->sched_time = time(NULL);
479 if (jcr->RestoreBootstrap) {
480 free(jcr->RestoreBootstrap);
482 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
486 if (rc.plugin_options) {
487 if (jcr->plugin_options) {
488 free(jcr->plugin_options);
490 jcr->plugin_options = bstrdup(rc.plugin_options);
491 rc.plugin_options = NULL;
496 for (i=0; ReplaceOptions[i].name; i++) {
497 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
498 jcr->replace = ReplaceOptions[i].token;
502 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
505 } else if (rc.job->replace) {
506 jcr->replace = rc.job->replace;
508 jcr->replace = REPLACE_ALWAYS;
513 jcr->JobPriority = rc.Priority;
519 jcr->stime = get_pool_memory(PM_MESSAGE);
521 pm_strcpy(jcr->stime, rc.since);
526 jcr->cloned = rc.cloned;
530 /* If pool changed, update migration write storage */
531 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
532 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
533 if (!set_migration_wstorage(jcr, rc.pool)) {
537 rc.replace = ReplaceOptions[0].name;
538 for (i=0; ReplaceOptions[i].name; i++) {
539 if (ReplaceOptions[i].token == jcr->replace) {
540 rc.replace = ReplaceOptions[i].name;
544 if (!get_level_from_name(jcr, rc.level_name)) {
545 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
548 rc.level_name = NULL;
551 /* Note, this is also MigrateJobId and a VerifyJobId */
552 jcr->RestoreJobId = str_to_int64(rc.jid);
556 /* Some options are not available through the menu
557 * TODO: Add an advanced menu?
559 if (rc.spool_data_set) {
560 jcr->spool_data = rc.spool_data;
563 if (rc.accurate_set) {
564 jcr->accurate = rc.accurate;
567 /* Used by migration jobs that can have the same name,
568 * but can run at the same time
570 if (rc.ignoreduplicatecheck_set) {
571 jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
577 static void select_where_regexp(UAContext *ua, JCR *jcr)
580 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
581 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
584 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
585 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
587 start_prompt(ua, _("This will replace your current Where value\n"));
588 add_prompt(ua, _("Strip prefix")); /* 0 */
589 add_prompt(ua, _("Add prefix")); /* 1 */
590 add_prompt(ua, _("Add file suffix")); /* 2 */
591 add_prompt(ua, _("Enter a regexp")); /* 3 */
592 add_prompt(ua, _("Test filename manipulation")); /* 4 */
593 add_prompt(ua, _("Use this ?")); /* 5 */
595 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
598 if (get_cmd(ua, _("Please enter the path prefix to strip: "))) {
599 if (strip_prefix) bfree(strip_prefix);
600 strip_prefix = bstrdup(ua->cmd);
606 if (get_cmd(ua, _("Please enter the path prefix to add (/ for none): "))) {
607 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
611 if (add_prefix) bfree(add_prefix);
612 add_prefix = bstrdup(ua->cmd);
617 if (get_cmd(ua, _("Please enter the file suffix to add: "))) {
618 if (add_suffix) bfree(add_suffix);
619 add_suffix = bstrdup(ua->cmd);
624 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
625 if (rwhere) bfree(rwhere);
626 rwhere = bstrdup(ua->cmd);
635 if (rwhere && rwhere[0] != '\0') {
636 regs = get_bregexps(rwhere);
637 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
639 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
640 regexp = (char *) bmalloc (len * sizeof(char));
641 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
642 regs = get_bregexps(regexp);
643 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
644 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
650 ua->send_msg(_("Cannot use your regexp\n"));
653 ua->send_msg(_("Enter a period (.) to stop this test\n"));
654 while (get_cmd(ua, _("Please enter filename to test: "))) {
655 apply_bregexps(ua->cmd, regs, &result);
656 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
665 case -1: /* error or cancel */
671 /* replace the existing where */
677 /* replace the existing regexwhere */
678 if (jcr->RegexWhere) {
679 bfree(jcr->RegexWhere);
680 jcr->RegexWhere = NULL;
684 jcr->RegexWhere = bstrdup(rwhere);
685 } else if (strip_prefix || add_prefix || add_suffix) {
686 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
687 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
688 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
691 regs = get_bregexps(jcr->RegexWhere);
696 if (jcr->RegexWhere) {
697 bfree(jcr->RegexWhere);
698 jcr->RegexWhere = NULL;
700 ua->send_msg(_("Cannot use your regexp.\n"));
704 if (strip_prefix) bfree(strip_prefix);
705 if (add_prefix) bfree(add_prefix);
706 if (add_suffix) bfree(add_suffix);
707 if (rwhere) bfree(rwhere);
710 static void select_job_level(UAContext *ua, JCR *jcr)
712 if (jcr->getJobType() == JT_BACKUP) {
713 start_prompt(ua, _("Levels:\n"));
714 // add_prompt(ua, _("Base"));
715 add_prompt(ua, _("Full"));
716 add_prompt(ua, _("Incremental"));
717 add_prompt(ua, _("Differential"));
718 add_prompt(ua, _("Since"));
719 add_prompt(ua, _("VirtualFull"));
720 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
722 // jcr->JobLevel = L_BASE;
725 jcr->setJobLevel(L_FULL);
728 jcr->setJobLevel(L_INCREMENTAL);
731 jcr->setJobLevel(L_DIFFERENTIAL);
734 jcr->setJobLevel(L_SINCE);
737 jcr->setJobLevel(L_VIRTUAL_FULL);
742 } else if (jcr->getJobType() == JT_VERIFY) {
743 start_prompt(ua, _("Levels:\n"));
744 add_prompt(ua, _("Initialize Catalog"));
745 add_prompt(ua, _("Verify Catalog"));
746 add_prompt(ua, _("Verify Volume to Catalog"));
747 add_prompt(ua, _("Verify Disk to Catalog"));
748 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
749 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
751 jcr->setJobLevel(L_VERIFY_INIT);
754 jcr->setJobLevel(L_VERIFY_CATALOG);
757 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
760 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
763 jcr->setJobLevel(L_VERIFY_DATA);
769 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
774 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
775 char *jid, const char *replace, char *client_name)
778 char dt[MAX_TIME_LENGTH];
780 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
781 switch (jcr->getJobType()) {
784 ua->signal(BNET_RUN_CMD);
785 ua->send_msg("Type: Admin\n"
786 "Title: Run Admin Job\n"
794 jcr->fileset->name(),
795 NPRT(jcr->client->name()),
796 jcr->wstore?jcr->wstore->name():"*None*",
797 bstrutime(dt, sizeof(dt), jcr->sched_time),
800 ua->send_msg(_("Run Admin Job\n"
808 jcr->fileset->name(),
809 NPRT(jcr->client->name()),
810 jcr->wstore?jcr->wstore->name():"*None*",
811 bstrutime(dt, sizeof(dt), jcr->sched_time),
814 jcr->setJobLevel(L_FULL);
818 if (jcr->getJobType() == JT_BACKUP) {
820 ua->signal(BNET_RUN_CMD);
821 ua->send_msg("Type: Backup\n"
822 "Title: Run Backup Job\n"
833 level_to_str(jcr->getJobLevel()),
835 jcr->fileset->name(),
836 NPRT(jcr->pool->name()),
837 jcr->wstore?jcr->wstore->name():"*None*",
838 bstrutime(dt, sizeof(dt), jcr->sched_time),
840 jcr->plugin_options?"Plugin Options: ":"",
841 jcr->plugin_options?jcr->plugin_options:"",
842 jcr->plugin_options?"\n":"");
844 ua->send_msg(_("Run Backup job\n"
849 "Pool: %s (From %s)\n"
850 "Storage: %s (From %s)\n"
855 level_to_str(jcr->getJobLevel()),
857 jcr->fileset->name(),
858 NPRT(jcr->pool->name()), jcr->pool_source,
859 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
860 bstrutime(dt, sizeof(dt), jcr->sched_time),
862 jcr->plugin_options?"Plugin Options: ":"",
863 jcr->plugin_options?jcr->plugin_options:"",
864 jcr->plugin_options?"\n":"");
866 } else { /* JT_VERIFY */
869 if (jcr->verify_job) {
870 Name = jcr->verify_job->name();
871 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
872 memset(&jr, 0, sizeof(jr));
873 jr.JobId = jcr->RestoreJobId;
874 if (!db_get_job_record(jcr, ua->db, &jr)) {
875 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
876 db_strerror(ua->db));
884 verify_list = job->WriteVerifyList;
890 ua->signal(BNET_RUN_CMD);
891 ua->send_msg("Type: Verify\n"
892 "Title: Run Verify Job\n"
897 "Pool: %s (From %s)\n"
898 "Storage: %s (From %s)\n"
904 level_to_str(jcr->getJobLevel()),
906 jcr->fileset->name(),
907 NPRT(jcr->pool->name()), jcr->pool_source,
908 jcr->rstore->name(), jcr->rstore_source,
911 bstrutime(dt, sizeof(dt), jcr->sched_time),
914 ua->send_msg(_("Run Verify Job\n"
919 "Pool: %s (From %s)\n"
920 "Storage: %s (From %s)\n"
926 level_to_str(jcr->getJobLevel()),
928 jcr->fileset->name(),
929 NPRT(jcr->pool->name()), jcr->pool_source,
930 jcr->rstore->name(), jcr->rstore_source,
933 bstrutime(dt, sizeof(dt), jcr->sched_time),
939 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
941 jcr->RestoreJobId = str_to_int64(jid);
943 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
946 jcr->RestoreJobId = ua->int64_val;
949 jcr->setJobLevel(L_FULL); /* default level */
950 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
951 if (jcr->RestoreJobId == 0) {
952 /* RegexWhere is take before RestoreWhere */
953 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
955 ua->signal(BNET_RUN_CMD);
956 ua->send_msg("Type: Restore\n"
957 "Title: Run Restore Job\n"
963 "Backup Client: %s\n"
964 "Restore Client: %s\n"
969 "Plugin Options: %s\n",
971 NPRT(jcr->RestoreBootstrap),
972 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
974 jcr->fileset->name(),
978 bstrutime(dt, sizeof(dt), jcr->sched_time),
979 jcr->catalog->name(),
981 NPRT(jcr->plugin_options));
983 ua->send_msg(_("Run Restore job\n"
989 "Backup Client: %s\n"
990 "Restore Client: %s\n"
995 "Plugin Options: %s\n"),
997 NPRT(jcr->RestoreBootstrap),
998 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
1000 jcr->fileset->name(),
1002 jcr->client->name(),
1003 jcr->rstore->name(),
1004 bstrutime(dt, sizeof(dt), jcr->sched_time),
1005 jcr->catalog->name(),
1007 NPRT(jcr->plugin_options));
1011 ua->signal(BNET_RUN_CMD);
1012 ua->send_msg("Type: Restore\n"
1013 "Title: Run Restore job\n"
1019 "Backup Client: %s\n"
1020 "Restore Client: %s\n"
1025 "Plugin Options: %s\n",
1027 NPRT(jcr->RestoreBootstrap),
1028 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1030 jcr->fileset->name(),
1032 jcr->client->name(),
1033 jcr->rstore->name(),
1034 bstrutime(dt, sizeof(dt), jcr->sched_time),
1035 jcr->catalog->name(),
1037 NPRT(jcr->plugin_options));
1039 ua->send_msg(_("Run Restore job\n"
1045 "Backup Client: %s\n"
1046 "Restore Client: %s\n"
1051 "Plugin Options: %s\n"),
1053 NPRT(jcr->RestoreBootstrap),
1054 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1056 jcr->fileset->name(),
1058 jcr->client->name(),
1059 jcr->rstore->name(),
1060 bstrutime(dt, sizeof(dt), jcr->sched_time),
1061 jcr->catalog->name(),
1063 NPRT(jcr->plugin_options));
1068 /* ***FIXME*** This needs to be fixed for bat */
1069 if (ua->api) ua->signal(BNET_RUN_CMD);
1070 ua->send_msg(_("Run Restore job\n"
1074 NPRT(jcr->RestoreBootstrap));
1076 /* RegexWhere is take before RestoreWhere */
1077 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1078 ua->send_msg(_("RegexWhere: %s\n"),
1079 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1081 ua->send_msg(_("Where: %s\n"),
1082 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1085 ua->send_msg(_("Replace: %s\n"
1092 "Plugin Options: %s\n"),
1094 jcr->client->name(),
1095 jcr->rstore->name(),
1096 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1097 bstrutime(dt, sizeof(dt), jcr->sched_time),
1098 jcr->catalog->name(),
1100 NPRT(jcr->plugin_options));
1106 jcr->setJobLevel(L_FULL); /* default level */
1108 ua->signal(BNET_RUN_CMD);
1109 if (jcr->getJobType() == JT_COPY) {
1110 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1112 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1120 "Read Storage: %s\n"
1121 "Write Storage: %s\n"
1128 NPRT(jcr->RestoreBootstrap),
1129 jcr->client->name(),
1130 jcr->fileset->name(),
1131 NPRT(jcr->pool->name()),
1132 jcr->rstore->name(),
1133 jcr->wstore?jcr->wstore->name():"*None*",
1134 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1135 bstrutime(dt, sizeof(dt), jcr->sched_time),
1136 jcr->catalog->name(),
1139 if (jcr->getJobType() == JT_COPY) {
1140 prt_type = _("Run Copy job\n");
1142 prt_type = _("Run Migration job\n");
1149 "Pool: %s (From %s)\n"
1150 "Read Storage: %s (From %s)\n"
1151 "Write Storage: %s (From %s)\n"
1158 NPRT(jcr->RestoreBootstrap),
1159 jcr->client->name(),
1160 jcr->fileset->name(),
1161 NPRT(jcr->pool->name()), jcr->pool_source,
1162 jcr->rstore->name(), jcr->rstore_source,
1163 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1164 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1165 bstrutime(dt, sizeof(dt), jcr->sched_time),
1166 jcr->catalog->name(),
1171 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1178 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1182 static const char *kw[] = { /* command line arguments */
1183 "job", /* Used in a switch() */
1191 "regexwhere", /* 8 where string as a bregexp */
1193 "bootstrap", /* 10 */
1196 "priority", /* 13 */
1197 "yes", /* 14 -- if you change this change YES_POS too */
1198 "verifyjob", /* 15 */
1199 "files", /* 16 number of files to restore */
1200 "catalog", /* 17 override catalog */
1201 "since", /* 18 since */
1202 "cloned", /* 19 cloned */
1203 "verifylist", /* 20 verify output list */
1204 "migrationjob", /* 21 migration job name */
1206 "backupclient", /* 23 */
1207 "restoreclient", /* 24 */
1208 "pluginoptions", /* 25 */
1209 "spooldata", /* 26 */
1211 "ignoreduplicatecheck", /* 28 */
1212 "accurate", /* 29 */
1218 rc.catalog_name = NULL;
1220 rc.pool_name = NULL;
1221 rc.store_name = NULL;
1222 rc.client_name = NULL;
1223 rc.restore_client_name = NULL;
1224 rc.fileset_name = NULL;
1225 rc.verify_job_name = NULL;
1226 rc.previous_job_name = NULL;
1227 rc.accurate_set = false;
1228 rc.spool_data_set = false;
1229 rc.ignoreduplicatecheck = false;
1232 for (i=1; i<ua->argc; i++) {
1233 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1235 /* Keep looking until we find a good keyword */
1236 for (j=0; !kw_ok && kw[j]; j++) {
1237 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1238 /* Note, yes and run have no value, so do not fail */
1239 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1240 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1243 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1247 ua->send_msg(_("Job name specified twice.\n"));
1250 rc.job_name = ua->argv[i];
1254 if (rc.jid && !rc.mod) {
1255 ua->send_msg(_("JobId specified twice.\n"));
1258 rc.jid = ua->argv[i];
1261 case 2: /* client */
1263 if (rc.client_name) {
1264 ua->send_msg(_("Client specified twice.\n"));
1267 rc.client_name = ua->argv[i];
1270 case 4: /* fileset */
1271 if (rc.fileset_name) {
1272 ua->send_msg(_("FileSet specified twice.\n"));
1275 rc.fileset_name = ua->argv[i];
1279 if (rc.level_name) {
1280 ua->send_msg(_("Level specified twice.\n"));
1283 rc.level_name = ua->argv[i];
1286 case 6: /* storage */
1288 if (rc.store_name) {
1289 ua->send_msg(_("Storage specified twice.\n"));
1292 rc.store_name = ua->argv[i];
1295 case 8: /* regexwhere */
1296 if ((rc.regexwhere || rc.where) && !rc.mod) {
1297 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1300 rc.regexwhere = ua->argv[i];
1301 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1302 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1308 if ((rc.where || rc.regexwhere) && !rc.mod) {
1309 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1312 rc.where = ua->argv[i];
1313 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1314 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1319 case 10: /* bootstrap */
1320 if (rc.bootstrap && !rc.mod) {
1321 ua->send_msg(_("Bootstrap specified twice.\n"));
1324 rc.bootstrap = ua->argv[i];
1327 case 11: /* replace */
1328 if (rc.replace && !rc.mod) {
1329 ua->send_msg(_("Replace specified twice.\n"));
1332 rc.replace = ua->argv[i];
1336 if (rc.when && !rc.mod) {
1337 ua->send_msg(_("When specified twice.\n"));
1340 rc.when = ua->argv[i];
1343 case 13: /* Priority */
1344 if (rc.Priority && !rc.mod) {
1345 ua->send_msg(_("Priority specified twice.\n"));
1348 rc.Priority = atoi(ua->argv[i]);
1349 if (rc.Priority <= 0) {
1350 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1358 case 15: /* Verify Job */
1359 if (rc.verify_job_name) {
1360 ua->send_msg(_("Verify Job specified twice.\n"));
1363 rc.verify_job_name = ua->argv[i];
1366 case 16: /* files */
1367 rc.files = atoi(ua->argv[i]);
1370 case 17: /* catalog */
1371 rc.catalog_name = ua->argv[i];
1374 case 18: /* since */
1375 rc.since = ua->argv[i];
1378 case 19: /* cloned */
1382 case 20: /* write verify list output */
1383 rc.verify_list = ua->argv[i];
1386 case 21: /* Migration Job */
1387 if (rc.previous_job_name) {
1388 ua->send_msg(_("Migration Job specified twice.\n"));
1391 rc.previous_job_name = ua->argv[i];
1396 ua->send_msg(_("Pool specified twice.\n"));
1399 rc.pool_name = ua->argv[i];
1402 case 23: /* backupclient */
1403 if (rc.client_name) {
1404 ua->send_msg(_("Client specified twice.\n"));
1407 rc.client_name = ua->argv[i];
1410 case 24: /* restoreclient */
1411 if (rc.restore_client_name && !rc.mod) {
1412 ua->send_msg(_("Restore Client specified twice.\n"));
1415 rc.restore_client_name = ua->argv[i];
1418 case 25: /* pluginoptions */
1419 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1421 if (rc.plugin_options) {
1422 ua->send_msg(_("Plugin Options specified twice.\n"));
1425 rc.plugin_options = ua->argv[i];
1426 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1427 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1432 case 26: /* spooldata */
1433 if (rc.spool_data_set) {
1434 ua->send_msg(_("Spool flag specified twice.\n"));
1437 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1438 rc.spool_data_set = true;
1441 ua->send_msg(_("Invalid spooldata flag.\n"));
1444 case 27: /* comment */
1445 rc.comment = ua->argv[i];
1448 case 28: /* ignoreduplicatecheck */
1449 if (rc.ignoreduplicatecheck_set) {
1450 ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1453 if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1454 rc.ignoreduplicatecheck_set = true;
1457 ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1460 case 29: /* accurate */
1461 if (rc.accurate_set) {
1462 ua->send_msg(_("Accurate flag specified twice.\n"));
1465 if (is_yesno(ua->argv[i], &rc.accurate)) {
1466 rc.accurate_set = true;
1469 ua->send_msg(_("Invalid accurate flag.\n"));
1475 } /* end strcase compare */
1476 } /* end keyword loop */
1478 * End of keyword for loop -- if not found, we got a bogus keyword
1481 Dmsg1(800, "%s not found\n", ua->argk[i]);
1483 * Special case for Job Name, it can be the first
1484 * keyword that has no value.
1486 if (!rc.job_name && !ua->argv[i]) {
1487 rc.job_name = ua->argk[i]; /* use keyword as job name */
1488 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1490 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1494 } /* end argc loop */
1496 Dmsg0(800, "Done scan.\n");
1498 if (!is_comment_legal(ua, rc.comment)) {
1502 if (rc.catalog_name) {
1503 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1504 if (rc.catalog == NULL) {
1505 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1508 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1509 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1513 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1517 rc.job = GetJobResWithName(rc.job_name);
1519 if (*rc.job_name != 0) {
1520 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1522 rc.job = select_job_resource(ua);
1524 Dmsg1(800, "Found job=%s\n", rc.job_name);
1526 } else if (!rc.job) {
1527 ua->send_msg(_("A job name must be specified.\n"));
1528 rc.job = select_job_resource(ua);
1532 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1533 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1538 rc.pool = GetPoolResWithName(rc.pool_name);
1540 if (*rc.pool_name != 0) {
1541 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1543 rc.pool = select_pool_resource(ua);
1545 } else if (!rc.pool) {
1546 rc.pool = rc.job->pool; /* use default */
1550 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1551 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1554 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1556 if (rc.store_name) {
1557 rc.store->store = GetStoreResWithName(rc.store_name);
1558 pm_strcpy(rc.store->store_source, _("command line"));
1559 if (!rc.store->store) {
1560 if (*rc.store_name != 0) {
1561 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1563 rc.store->store = select_storage_resource(ua);
1564 pm_strcpy(rc.store->store_source, _("user selection"));
1566 } else if (!rc.store->store) {
1567 get_job_storage(rc.store, rc.job, NULL); /* use default */
1569 if (!rc.store->store) {
1570 ua->error_msg(_("No storage specified.\n"));
1572 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1573 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1574 rc.store->store->name());
1577 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1579 if (rc.client_name) {
1580 rc.client = GetClientResWithName(rc.client_name);
1582 if (*rc.client_name != 0) {
1583 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1585 rc.client = select_client_resource(ua);
1587 } else if (!rc.client) {
1588 rc.client = rc.job->client; /* use default */
1592 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1593 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1597 Dmsg1(800, "Using client=%s\n", rc.client->name());
1599 if (rc.restore_client_name) {
1600 rc.client = GetClientResWithName(rc.restore_client_name);
1602 if (*rc.restore_client_name != 0) {
1603 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1605 rc.client = select_client_resource(ua);
1607 } else if (!rc.client) {
1608 rc.client = rc.job->client; /* use default */
1612 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1613 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1617 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1619 if (rc.fileset_name) {
1620 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1622 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1623 rc.fileset = select_fileset_resource(ua);
1625 } else if (!rc.fileset) {
1626 rc.fileset = rc.job->fileset; /* use default */
1630 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1631 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1632 rc.fileset->name());
1636 if (rc.verify_job_name) {
1637 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1638 if (!rc.verify_job) {
1639 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1640 rc.verify_job = select_job_resource(ua);
1642 } else if (!rc.verify_job) {
1643 rc.verify_job = rc.job->verify_job;
1646 if (rc.previous_job_name) {
1647 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1648 if (!rc.previous_job) {
1649 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1650 rc.previous_job = select_job_resource(ua);
1653 rc.previous_job = rc.job->verify_job;