2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- Run Command
32 * Kern Sibbald, December MMI
41 char *job_name, *level_name, *jid, *store_name, *pool_name;
42 char *where, *fileset_name, *client_name, *bootstrap, *regexwhere;
43 char *restore_client_name, *comment;
45 char *when, *verify_job_name, *catalog_name;
46 char *previous_job_name;
49 const char *verify_list;
66 run_ctx() { memset(this, 0, sizeof(run_ctx));
67 store = new USTORE; };
68 ~run_ctx() { delete store; };
71 /* Forward referenced subroutines */
72 static void select_job_level(UAContext *ua, JCR *jcr);
73 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
74 const char *verify_list, char *jid, const char *replace,
76 static void select_where_regexp(UAContext *ua, JCR *jcr);
77 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
78 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
79 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
81 /* Imported variables */
82 extern struct s_kw ReplaceOptions[];
85 * For Backup and Verify Jobs
86 * run [job=]<job-name> level=<level-name>
95 int run_cmd(UAContext *ua, const char *cmd)
101 if (!open_client_db(ua)) {
105 if (!scan_command_line_arguments(ua, rc)) {
109 if (find_arg(ua, NT_("fdcalled")) > 0) {
110 jcr->file_bsock = dup_bsock(ua->UA_sock);
115 * Create JCR to run job. NOTE!!! after this point, free_jcr()
119 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
120 set_jcr_defaults(jcr, rc.job);
121 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
122 ua->jcr->unlink_bsr = false;
124 /* Transfer JobIds to new restore Job */
125 if (ua->jcr->JobIds) {
126 jcr->JobIds = ua->jcr->JobIds;
127 ua->jcr->JobIds = NULL;
131 if (!reset_restore_context(ua, jcr, rc)) {
136 /* Run without prompting? */
137 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
142 * Prompt User to see if all run job parameters are correct, and
143 * allow him to modify them.
145 if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
150 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
154 if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
155 (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
158 if (!scan_command_line_arguments(ua, rc)) {
164 /* Allow the user to modify the settings */
165 status = modify_job_parameters(ua, jcr, rc);
176 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
178 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
181 Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId,
182 jcr->pool->name(), jcr->JobPriority);
183 Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
184 JobId = run_job(jcr);
185 Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId,
186 JobId, jcr->pool->name(), jcr->JobPriority);
187 free_jcr(jcr); /* release jcr */
189 ua->error_msg(_("Job failed.\n"));
192 ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
198 ua->send_msg(_("Job not run.\n"));
200 return 0; /* do not run */
203 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
207 * At user request modify parameters of job to be run.
209 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
212 start_prompt(ua, _("Parameters to modify:\n"));
213 add_prompt(ua, _("Level")); /* 0 */
214 add_prompt(ua, _("Storage")); /* 1 */
215 add_prompt(ua, _("Job")); /* 2 */
216 add_prompt(ua, _("FileSet")); /* 3 */
217 if (jcr->getJobType() == JT_RESTORE) {
218 add_prompt(ua, _("Restore Client")); /* 4 */
220 add_prompt(ua, _("Client")); /* 4 */
222 add_prompt(ua, _("When")); /* 5 */
223 add_prompt(ua, _("Priority")); /* 6 */
224 if (jcr->getJobType() == JT_BACKUP ||
225 jcr->getJobType() == JT_COPY ||
226 jcr->getJobType() == JT_MIGRATE ||
227 jcr->getJobType() == JT_VERIFY) {
228 add_prompt(ua, _("Pool")); /* 7 */
229 if (jcr->getJobType() == JT_VERIFY) {
230 add_prompt(ua, _("Verify Job")); /* 8 */
232 } else if (jcr->getJobType() == JT_RESTORE) {
233 add_prompt(ua, _("Bootstrap")); /* 7 */
234 add_prompt(ua, _("Where")); /* 8 */
235 add_prompt(ua, _("File Relocation"));/* 9 */
236 add_prompt(ua, _("Replace")); /* 10 */
237 add_prompt(ua, _("JobId")); /* 11 */
239 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
240 add_prompt(ua, _("Plugin Options")); /* 12 */
242 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
245 select_job_level(ua, jcr);
249 rc.store->store = select_storage_resource(ua);
250 if (rc.store->store) {
251 pm_strcpy(rc.store->store_source, _("user selection"));
252 set_rwstorage(jcr, rc.store);
258 rc.job = select_job_resource(ua);
261 set_jcr_defaults(jcr, rc.job);
267 rc.fileset = select_fileset_resource(ua);
269 jcr->fileset = rc.fileset;
275 rc.client = select_client_resource(ua);
277 jcr->client = rc.client;
283 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
286 if (ua->cmd[0] == 0) {
287 jcr->sched_time = time(NULL);
289 jcr->sched_time = str_to_utime(ua->cmd);
290 if (jcr->sched_time == 0) {
291 ua->send_msg(_("Invalid time, using current time.\n"));
292 jcr->sched_time = time(NULL);
298 if (!get_pint(ua, _("Enter new Priority: "))) {
301 if (ua->pint32_val == 0) {
302 ua->send_msg(_("Priority must be a positive integer.\n"));
304 jcr->JobPriority = ua->pint32_val;
308 /* Pool or Bootstrap depending on JobType */
309 if (jcr->getJobType() == JT_BACKUP ||
310 jcr->getJobType() == JT_COPY ||
311 jcr->getJobType() == JT_MIGRATE ||
312 jcr->getJobType() == JT_VERIFY) { /* Pool */
313 rc.pool = select_pool_resource(ua);
316 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
323 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
326 if (jcr->RestoreBootstrap) {
327 free(jcr->RestoreBootstrap);
328 jcr->RestoreBootstrap = NULL;
330 if (ua->cmd[0] != 0) {
331 jcr->RestoreBootstrap = bstrdup(ua->cmd);
332 fd = fopen(jcr->RestoreBootstrap, "rb");
335 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
336 jcr->RestoreBootstrap, be.bstrerror());
337 free(jcr->RestoreBootstrap);
338 jcr->RestoreBootstrap = NULL;
346 if (jcr->getJobType() == JT_VERIFY) {
347 rc.verify_job = select_job_resource(ua);
349 jcr->verify_job = rc.verify_job;
354 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
357 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
358 free(jcr->RegexWhere);
359 jcr->RegexWhere = NULL;
365 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
368 jcr->where = bstrdup(ua->cmd);
371 /* File relocation */
372 select_where_regexp(ua, jcr);
376 start_prompt(ua, _("Replace:\n"));
377 for (i=0; ReplaceOptions[i].name; i++) {
378 add_prompt(ua, ReplaceOptions[i].name);
380 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
382 rc.replace = ReplaceOptions[opt].name;
383 jcr->replace = ReplaceOptions[opt].token;
388 rc.jid = NULL; /* force reprompt */
389 jcr->RestoreJobId = 0;
390 if (jcr->RestoreBootstrap) {
391 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
396 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
399 if (jcr->plugin_options) {
400 free(jcr->plugin_options);
401 jcr->plugin_options = NULL;
403 jcr->plugin_options = bstrdup(ua->cmd);
405 case -1: /* error or cancel */
422 * Reset the restore context.
423 * This subroutine can be called multiple times, so it
424 * must keep any prior settings.
426 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
430 jcr->verify_job = rc.verify_job;
431 jcr->previous_job = rc.previous_job;
433 if (jcr->pool != jcr->job->pool) {
434 pm_strcpy(jcr->pool_source, _("User input"));
436 set_rwstorage(jcr, rc.store);
437 jcr->client = rc.client;
438 pm_strcpy(jcr->client_name, rc.client->name());
439 jcr->fileset = rc.fileset;
440 jcr->ExpectedFiles = rc.files;
442 jcr->catalog = rc.catalog;
443 pm_strcpy(jcr->catalog_source, _("User input"));
446 pm_strcpy(jcr->comment, rc.comment);
452 jcr->where = bstrdup(rc.where);
457 if (jcr->RegexWhere) {
458 free(jcr->RegexWhere);
460 jcr->RegexWhere = bstrdup(rc.regexwhere);
461 rc.regexwhere = NULL;
465 jcr->sched_time = str_to_utime(rc.when);
466 if (jcr->sched_time == 0) {
467 ua->send_msg(_("Invalid time, using current time.\n"));
468 jcr->sched_time = time(NULL);
474 if (jcr->RestoreBootstrap) {
475 free(jcr->RestoreBootstrap);
477 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
481 if (rc.plugin_options) {
482 if (jcr->plugin_options) {
483 free(jcr->plugin_options);
485 jcr->plugin_options = bstrdup(rc.plugin_options);
486 rc.plugin_options = NULL;
492 for (i=0; ReplaceOptions[i].name; i++) {
493 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
494 jcr->replace = ReplaceOptions[i].token;
498 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
501 } else if (rc.job->replace) {
502 jcr->replace = rc.job->replace;
504 jcr->replace = REPLACE_ALWAYS;
509 jcr->JobPriority = rc.Priority;
515 jcr->stime = get_pool_memory(PM_MESSAGE);
517 pm_strcpy(jcr->stime, rc.since);
522 jcr->cloned = rc.cloned;
527 /* If pool changed, update migration write storage */
528 if (jcr->getJobType() == JT_MIGRATE || jcr->getJobType() == JT_COPY ||
529 (jcr->getJobType() == JT_BACKUP && jcr->getJobLevel() == L_VIRTUAL_FULL)) {
530 if (!set_migration_wstorage(jcr, rc.pool)) {
534 rc.replace = ReplaceOptions[0].name;
535 for (i=0; ReplaceOptions[i].name; i++) {
536 if (ReplaceOptions[i].token == jcr->replace) {
537 rc.replace = ReplaceOptions[i].name;
541 if (!get_level_from_name(jcr, rc.level_name)) {
542 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
545 rc.level_name = NULL;
548 /* Note, this is also MigrateJobId and a VerifyJobId */
549 jcr->RestoreJobId = str_to_int64(rc.jid);
555 static void select_where_regexp(UAContext *ua, JCR *jcr)
558 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
559 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
562 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
563 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
565 start_prompt(ua, _("This will replace your current Where value\n"));
566 add_prompt(ua, _("Strip prefix")); /* 0 */
567 add_prompt(ua, _("Add prefix")); /* 1 */
568 add_prompt(ua, _("Add file suffix")); /* 2 */
569 add_prompt(ua, _("Enter a regexp")); /* 3 */
570 add_prompt(ua, _("Test filename manipulation")); /* 4 */
571 add_prompt(ua, _("Use this ?")); /* 5 */
573 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
576 if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
577 if (strip_prefix) bfree(strip_prefix);
578 strip_prefix = bstrdup(ua->cmd);
584 if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
585 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
589 if (add_prefix) bfree(add_prefix);
590 add_prefix = bstrdup(ua->cmd);
595 if (get_cmd(ua, _("Please enter file suffix to add: "))) {
596 if (add_suffix) bfree(add_suffix);
597 add_suffix = bstrdup(ua->cmd);
602 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
603 if (rwhere) bfree(rwhere);
604 rwhere = bstrdup(ua->cmd);
613 if (rwhere && rwhere[0] != '\0') {
614 regs = get_bregexps(rwhere);
615 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
617 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
618 regexp = (char *) bmalloc (len * sizeof(char));
619 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
620 regs = get_bregexps(regexp);
621 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
622 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
628 ua->send_msg(_("Cannot use your regexp\n"));
631 ua->send_msg(_("Enter a period (.) to stop this test\n"));
632 while (get_cmd(ua, _("Please enter filename to test: "))) {
633 apply_bregexps(ua->cmd, regs, &result);
634 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
643 case -1: /* error or cancel */
649 /* replace the existing where */
655 /* replace the existing regexwhere */
656 if (jcr->RegexWhere) {
657 bfree(jcr->RegexWhere);
658 jcr->RegexWhere = NULL;
662 jcr->RegexWhere = bstrdup(rwhere);
663 } else if (strip_prefix || add_prefix || add_suffix) {
664 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
665 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
666 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
669 regs = get_bregexps(jcr->RegexWhere);
674 if (jcr->RegexWhere) {
675 bfree(jcr->RegexWhere);
676 jcr->RegexWhere = NULL;
678 ua->send_msg(_("Cannot use your regexp.\n"));
682 if (strip_prefix) bfree(strip_prefix);
683 if (add_prefix) bfree(add_prefix);
684 if (add_suffix) bfree(add_suffix);
685 if (rwhere) bfree(rwhere);
688 static void select_job_level(UAContext *ua, JCR *jcr)
690 if (jcr->getJobType() == JT_BACKUP) {
691 start_prompt(ua, _("Levels:\n"));
692 // add_prompt(ua, _("Base"));
693 add_prompt(ua, _("Full"));
694 add_prompt(ua, _("Incremental"));
695 add_prompt(ua, _("Differential"));
696 add_prompt(ua, _("Since"));
697 add_prompt(ua, _("VirtualFull"));
698 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
700 // jcr->JobLevel = L_BASE;
703 jcr->set_JobLevel(L_FULL);
706 jcr->set_JobLevel(L_INCREMENTAL);
709 jcr->set_JobLevel(L_DIFFERENTIAL);
712 jcr->set_JobLevel(L_SINCE);
715 jcr->set_JobLevel(L_VIRTUAL_FULL);
720 } else if (jcr->getJobType() == JT_VERIFY) {
721 start_prompt(ua, _("Levels:\n"));
722 add_prompt(ua, _("Initialize Catalog"));
723 add_prompt(ua, _("Verify Catalog"));
724 add_prompt(ua, _("Verify Volume to Catalog"));
725 add_prompt(ua, _("Verify Disk to Catalog"));
726 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
727 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
729 jcr->set_JobLevel(L_VERIFY_INIT);
732 jcr->set_JobLevel(L_VERIFY_CATALOG);
735 jcr->set_JobLevel(L_VERIFY_VOLUME_TO_CATALOG);
738 jcr->set_JobLevel(L_VERIFY_DISK_TO_CATALOG);
741 jcr->set_JobLevel(L_VERIFY_DATA);
747 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
752 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
753 char *jid, const char *replace, char *client_name)
756 char dt[MAX_TIME_LENGTH];
758 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
759 switch (jcr->getJobType()) {
762 ua->signal(BNET_RUN_CMD);
763 ua->send_msg("Type: Admin\n"
764 "Title: Run Admin Job\n"
772 jcr->fileset->name(),
773 NPRT(jcr->client->name()),
774 jcr->wstore?jcr->wstore->name():"*None*",
775 bstrutime(dt, sizeof(dt), jcr->sched_time),
778 ua->send_msg(_("Run Admin Job\n"
786 jcr->fileset->name(),
787 NPRT(jcr->client->name()),
788 jcr->wstore?jcr->wstore->name():"*None*",
789 bstrutime(dt, sizeof(dt), jcr->sched_time),
792 jcr->set_JobLevel(L_FULL);
796 if (jcr->getJobType() == JT_BACKUP) {
798 ua->signal(BNET_RUN_CMD);
799 ua->send_msg("Type: Backup\n"
800 "Title: Run Backup Job\n"
811 level_to_str(jcr->getJobLevel()),
813 jcr->fileset->name(),
814 NPRT(jcr->pool->name()),
815 jcr->wstore?jcr->wstore->name():"*None*",
816 bstrutime(dt, sizeof(dt), jcr->sched_time),
818 jcr->plugin_options?"Plugin Options: ":"",
819 jcr->plugin_options?jcr->plugin_options:"",
820 jcr->plugin_options?"\n":"");
822 ua->send_msg(_("Run Backup job\n"
827 "Pool: %s (From %s)\n"
828 "Storage: %s (From %s)\n"
833 level_to_str(jcr->getJobLevel()),
835 jcr->fileset->name(),
836 NPRT(jcr->pool->name()), jcr->pool_source,
837 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
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 } else { /* JT_VERIFY */
847 if (jcr->verify_job) {
848 Name = jcr->verify_job->name();
849 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
850 memset(&jr, 0, sizeof(jr));
851 jr.JobId = jcr->RestoreJobId;
852 if (!db_get_job_record(jcr, ua->db, &jr)) {
853 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
854 db_strerror(ua->db));
862 verify_list = job->WriteVerifyList;
868 ua->signal(BNET_RUN_CMD);
869 ua->send_msg("Type: Verify\n"
870 "Title: Run Verify Job\n"
875 "Pool: %s (From %s)\n"
876 "Storage: %s (From %s)\n"
882 level_to_str(jcr->getJobLevel()),
884 jcr->fileset->name(),
885 NPRT(jcr->pool->name()), jcr->pool_source,
886 jcr->rstore->name(), jcr->rstore_source,
889 bstrutime(dt, sizeof(dt), jcr->sched_time),
892 ua->send_msg(_("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),
917 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
919 jcr->RestoreJobId = str_to_int64(jid);
921 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
924 jcr->RestoreJobId = ua->int64_val;
927 jcr->set_JobLevel(L_FULL); /* default level */
928 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
929 if (jcr->RestoreJobId == 0) {
930 /* RegexWhere is take before RestoreWhere */
931 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
933 ua->signal(BNET_RUN_CMD);
934 ua->send_msg("Type: Restore\n"
935 "Title: Run Restore Job\n"
941 "Backup Client: %s\n"
942 "Restore Client: %s\n"
947 "Plugin Options: %s\n",
949 NPRT(jcr->RestoreBootstrap),
950 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
952 jcr->fileset->name(),
956 bstrutime(dt, sizeof(dt), jcr->sched_time),
957 jcr->catalog->name(),
959 NPRT(jcr->plugin_options));
961 ua->send_msg(_("Run Restore job\n"
967 "Backup Client: %s\n"
968 "Restore Client: %s\n"
973 "Plugin Options: %s\n"),
975 NPRT(jcr->RestoreBootstrap),
976 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
978 jcr->fileset->name(),
982 bstrutime(dt, sizeof(dt), jcr->sched_time),
983 jcr->catalog->name(),
985 NPRT(jcr->plugin_options));
989 ua->signal(BNET_RUN_CMD);
990 ua->send_msg("Type: Restore\n"
991 "Title: Run Restore job\n"
997 "Backup Client: %s\n"
998 "Restore Client: %s\n"
1003 "Plugin Options: %s\n",
1005 NPRT(jcr->RestoreBootstrap),
1006 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1008 jcr->fileset->name(),
1010 jcr->client->name(),
1011 jcr->rstore->name(),
1012 bstrutime(dt, sizeof(dt), jcr->sched_time),
1013 jcr->catalog->name(),
1015 NPRT(jcr->plugin_options));
1017 ua->send_msg(_("Run Restore job\n"
1023 "Backup Client: %s\n"
1024 "Restore Client: %s\n"
1029 "Plugin Options: %s\n"),
1031 NPRT(jcr->RestoreBootstrap),
1032 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1034 jcr->fileset->name(),
1036 jcr->client->name(),
1037 jcr->rstore->name(),
1038 bstrutime(dt, sizeof(dt), jcr->sched_time),
1039 jcr->catalog->name(),
1041 NPRT(jcr->plugin_options));
1046 /* ***FIXME*** This needs to be fixed for bat */
1047 if (ua->api) ua->signal(BNET_RUN_CMD);
1048 ua->send_msg(_("Run Restore job\n"
1052 NPRT(jcr->RestoreBootstrap));
1054 /* RegexWhere is take before RestoreWhere */
1055 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1056 ua->send_msg(_("RegexWhere: %s\n"),
1057 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1059 ua->send_msg(_("Where: %s\n"),
1060 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1063 ua->send_msg(_("Replace: %s\n"
1070 "Plugin Options: %s\n"),
1072 jcr->client->name(),
1073 jcr->rstore->name(),
1074 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1075 bstrutime(dt, sizeof(dt), jcr->sched_time),
1076 jcr->catalog->name(),
1078 NPRT(jcr->plugin_options));
1084 jcr->set_JobLevel(L_FULL); /* default level */
1086 ua->signal(BNET_RUN_CMD);
1087 if (jcr->getJobType() == JT_COPY) {
1088 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1090 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1098 "Read Storage: %s\n"
1099 "Write Storage: %s\n"
1106 NPRT(jcr->RestoreBootstrap),
1107 jcr->client->name(),
1108 jcr->fileset->name(),
1109 NPRT(jcr->pool->name()),
1110 jcr->rstore->name(),
1111 jcr->wstore?jcr->wstore->name():"*None*",
1112 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1113 bstrutime(dt, sizeof(dt), jcr->sched_time),
1114 jcr->catalog->name(),
1117 if (jcr->getJobType() == JT_COPY) {
1118 prt_type = _("Run Copy job\n");
1120 prt_type = _("Run Migration job\n");
1127 "Pool: %s (From %s)\n"
1128 "Read Storage: %s (From %s)\n"
1129 "Write Storage: %s (From %s)\n"
1136 NPRT(jcr->RestoreBootstrap),
1137 jcr->client->name(),
1138 jcr->fileset->name(),
1139 NPRT(jcr->pool->name()), jcr->pool_source,
1140 jcr->rstore->name(), jcr->rstore_source,
1141 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1142 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1143 bstrutime(dt, sizeof(dt), jcr->sched_time),
1144 jcr->catalog->name(),
1149 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1156 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1160 static const char *kw[] = { /* command line arguments */
1161 "job", /* Used in a switch() */
1169 "regexwhere", /* 8 where string as a bregexp */
1171 "bootstrap", /* 10 */
1174 "priority", /* 13 */
1175 "yes", /* 14 -- if you change this change YES_POS too */
1176 "verifyjob", /* 15 */
1177 "files", /* 16 number of files to restore */
1178 "catalog", /* 17 override catalog */
1179 "since", /* 18 since */
1180 "cloned", /* 19 cloned */
1181 "verifylist", /* 20 verify output list */
1182 "migrationjob", /* 21 migration job name */
1184 "backupclient", /* 23 */
1185 "restoreclient", /* 24 */
1186 "pluginoptions", /* 25 */
1187 "spooldata", /* 26 */
1193 rc.catalog_name = NULL;
1195 rc.pool_name = NULL;
1196 rc.store_name = NULL;
1197 rc.client_name = NULL;
1198 rc.restore_client_name = NULL;
1199 rc.fileset_name = NULL;
1200 rc.verify_job_name = NULL;
1201 rc.previous_job_name = NULL;
1202 rc.spool_data_set = 0;
1205 for (i=1; i<ua->argc; i++) {
1206 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1208 /* Keep looking until we find a good keyword */
1209 for (j=0; !kw_ok && kw[j]; j++) {
1210 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1211 /* Note, yes and run have no value, so do not fail */
1212 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1213 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1216 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1220 ua->send_msg(_("Job name specified twice.\n"));
1223 rc.job_name = ua->argv[i];
1227 if (rc.jid && !rc.mod) {
1228 ua->send_msg(_("JobId specified twice.\n"));
1231 rc.jid = ua->argv[i];
1234 case 2: /* client */
1236 if (rc.client_name) {
1237 ua->send_msg(_("Client specified twice.\n"));
1240 rc.client_name = ua->argv[i];
1243 case 4: /* fileset */
1244 if (rc.fileset_name) {
1245 ua->send_msg(_("FileSet specified twice.\n"));
1248 rc.fileset_name = ua->argv[i];
1252 if (rc.level_name) {
1253 ua->send_msg(_("Level specified twice.\n"));
1256 rc.level_name = ua->argv[i];
1259 case 6: /* storage */
1261 if (rc.store_name) {
1262 ua->send_msg(_("Storage specified twice.\n"));
1265 rc.store_name = ua->argv[i];
1268 case 8: /* regexwhere */
1269 if ((rc.regexwhere || rc.where) && !rc.mod) {
1270 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1273 rc.regexwhere = ua->argv[i];
1274 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1275 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1281 if ((rc.where || rc.regexwhere) && !rc.mod) {
1282 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1285 rc.where = ua->argv[i];
1286 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1287 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1292 case 10: /* bootstrap */
1293 if (rc.bootstrap && !rc.mod) {
1294 ua->send_msg(_("Bootstrap specified twice.\n"));
1297 rc.bootstrap = ua->argv[i];
1300 case 11: /* replace */
1301 if (rc.replace && !rc.mod) {
1302 ua->send_msg(_("Replace specified twice.\n"));
1305 rc.replace = ua->argv[i];
1309 if (rc.when && !rc.mod) {
1310 ua->send_msg(_("When specified twice.\n"));
1313 rc.when = ua->argv[i];
1316 case 13: /* Priority */
1317 if (rc.Priority && !rc.mod) {
1318 ua->send_msg(_("Priority specified twice.\n"));
1321 rc.Priority = atoi(ua->argv[i]);
1322 if (rc.Priority <= 0) {
1323 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1331 case 15: /* Verify Job */
1332 if (rc.verify_job_name) {
1333 ua->send_msg(_("Verify Job specified twice.\n"));
1336 rc.verify_job_name = ua->argv[i];
1339 case 16: /* files */
1340 rc.files = atoi(ua->argv[i]);
1344 case 17: /* catalog */
1345 rc.catalog_name = ua->argv[i];
1349 case 18: /* since */
1350 rc.since = ua->argv[i];
1354 case 19: /* cloned */
1359 case 20: /* write verify list output */
1360 rc.verify_list = ua->argv[i];
1363 case 21: /* Migration Job */
1364 if (rc.previous_job_name) {
1365 ua->send_msg(_("Migration Job specified twice.\n"));
1368 rc.previous_job_name = ua->argv[i];
1373 ua->send_msg(_("Pool specified twice.\n"));
1376 rc.pool_name = ua->argv[i];
1379 case 23: /* backupclient */
1380 if (rc.client_name) {
1381 ua->send_msg(_("Client specified twice.\n"));
1384 rc.client_name = ua->argv[i];
1387 case 24: /* restoreclient */
1388 if (rc.restore_client_name && !rc.mod) {
1389 ua->send_msg(_("Restore Client specified twice.\n"));
1392 rc.restore_client_name = ua->argv[i];
1395 case 25: /* pluginoptions */
1396 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1398 if (rc.plugin_options) {
1399 ua->send_msg(_("Plugin Options specified twice.\n"));
1402 rc.plugin_options = ua->argv[i];
1403 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1404 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1409 case 26: /* spooldata */
1410 if (rc.spool_data_set) {
1411 ua->send_msg(_("Spool flag specified twice.\n"));
1414 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1415 rc.spool_data_set = 1;
1418 ua->send_msg(_("Invalid spooldata flag.\n"));
1421 case 27: /* comment */
1422 rc.comment = ua->argv[i];
1427 } /* end strcase compare */
1428 } /* end keyword loop */
1430 * End of keyword for loop -- if not found, we got a bogus keyword
1433 Dmsg1(800, "%s not found\n", ua->argk[i]);
1435 * Special case for Job Name, it can be the first
1436 * keyword that has no value.
1438 if (!rc.job_name && !ua->argv[i]) {
1439 rc.job_name = ua->argk[i]; /* use keyword as job name */
1440 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1442 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1446 } /* end argc loop */
1448 Dmsg0(800, "Done scan.\n");
1450 if (!is_comment_legal(ua, rc.comment)) {
1454 if (rc.catalog_name) {
1455 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1456 if (rc.catalog == NULL) {
1457 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1460 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1461 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1465 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1469 rc.job = GetJobResWithName(rc.job_name);
1471 if (*rc.job_name != 0) {
1472 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1474 rc.job = select_job_resource(ua);
1476 Dmsg1(800, "Found job=%s\n", rc.job_name);
1478 } else if (!rc.job) {
1479 ua->send_msg(_("A job name must be specified.\n"));
1480 rc.job = select_job_resource(ua);
1484 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1485 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1490 rc.pool = GetPoolResWithName(rc.pool_name);
1492 if (*rc.pool_name != 0) {
1493 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1495 rc.pool = select_pool_resource(ua);
1497 } else if (!rc.pool) {
1498 rc.pool = rc.job->pool; /* use default */
1502 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1503 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1506 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1508 if (rc.spool_data_set) {
1509 rc.job->spool_data = rc.spool_data;
1511 Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1513 if (rc.store_name) {
1514 rc.store->store = GetStoreResWithName(rc.store_name);
1515 pm_strcpy(rc.store->store_source, _("command line"));
1516 if (!rc.store->store) {
1517 if (*rc.store_name != 0) {
1518 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1520 rc.store->store = select_storage_resource(ua);
1521 pm_strcpy(rc.store->store_source, _("user selection"));
1523 } else if (!rc.store->store) {
1524 get_job_storage(rc.store, rc.job, NULL); /* use default */
1526 if (!rc.store->store) {
1527 ua->error_msg(_("No storage specified.\n"));
1529 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1530 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1531 rc.store->store->name());
1534 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1536 if (rc.client_name) {
1537 rc.client = GetClientResWithName(rc.client_name);
1539 if (*rc.client_name != 0) {
1540 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1542 rc.client = select_client_resource(ua);
1544 } else if (!rc.client) {
1545 rc.client = rc.job->client; /* use default */
1549 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1550 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1554 Dmsg1(800, "Using client=%s\n", rc.client->name());
1556 if (rc.restore_client_name) {
1557 rc.client = GetClientResWithName(rc.restore_client_name);
1559 if (*rc.restore_client_name != 0) {
1560 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1562 rc.client = select_client_resource(ua);
1564 } else if (!rc.client) {
1565 rc.client = rc.job->client; /* use default */
1569 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1570 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1574 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1577 if (rc.fileset_name) {
1578 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1580 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1581 rc.fileset = select_fileset_resource(ua);
1583 } else if (!rc.fileset) {
1584 rc.fileset = rc.job->fileset; /* use default */
1588 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1589 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1590 rc.fileset->name());
1594 if (rc.verify_job_name) {
1595 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1596 if (!rc.verify_job) {
1597 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1598 rc.verify_job = select_job_resource(ua);
1600 } else if (!rc.verify_job) {
1601 rc.verify_job = rc.job->verify_job;
1604 if (rc.previous_job_name) {
1605 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1606 if (!rc.previous_job) {
1607 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1608 rc.previous_job = select_job_resource(ua);
1611 rc.previous_job = rc.job->verify_job;