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 %s job\n"
787 jcr->fileset->name(),
788 NPRT(jcr->client->name()),
789 jcr->wstore?jcr->wstore->name():"*None*",
790 bstrutime(dt, sizeof(dt), jcr->sched_time),
793 jcr->set_JobLevel(L_FULL);
797 if (jcr->getJobType() == JT_BACKUP) {
799 ua->signal(BNET_RUN_CMD);
800 ua->send_msg("Type: Backup\n"
801 "Title: Run Backup Job\n"
812 level_to_str(jcr->getJobLevel()),
814 jcr->fileset->name(),
815 NPRT(jcr->pool->name()),
816 jcr->wstore?jcr->wstore->name():"*None*",
817 bstrutime(dt, sizeof(dt), jcr->sched_time),
819 jcr->plugin_options?"Plugin Options: ":"",
820 jcr->plugin_options?jcr->plugin_options:"",
821 jcr->plugin_options?"\n":"");
823 ua->send_msg(_("Run %s job\n"
828 "Pool: %s (From %s)\n"
829 "Storage: %s (From %s)\n"
834 level_to_str(jcr->getJobLevel()),
836 jcr->fileset->name(),
837 NPRT(jcr->pool->name()), jcr->pool_source,
838 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
839 bstrutime(dt, sizeof(dt), jcr->sched_time),
841 jcr->plugin_options?"Plugin Options: ":"",
842 jcr->plugin_options?jcr->plugin_options:"",
843 jcr->plugin_options?"\n":"");
845 } else { /* JT_VERIFY */
848 if (jcr->verify_job) {
849 Name = jcr->verify_job->name();
850 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
851 memset(&jr, 0, sizeof(jr));
852 jr.JobId = jcr->RestoreJobId;
853 if (!db_get_job_record(jcr, ua->db, &jr)) {
854 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
855 db_strerror(ua->db));
863 verify_list = job->WriteVerifyList;
869 ua->signal(BNET_RUN_CMD);
870 ua->send_msg("Type: Verify\n"
871 "Title: Run Verify Job\n"
876 "Pool: %s (From %s)\n"
877 "Storage: %s (From %s)\n"
883 level_to_str(jcr->getJobLevel()),
885 jcr->fileset->name(),
886 NPRT(jcr->pool->name()), jcr->pool_source,
887 jcr->rstore->name(), jcr->rstore_source,
890 bstrutime(dt, sizeof(dt), jcr->sched_time),
893 ua->send_msg(_("Run %s job\n"
898 "Pool: %s (From %s)\n"
899 "Storage: %s (From %s)\n"
906 level_to_str(jcr->getJobLevel()),
908 jcr->fileset->name(),
909 NPRT(jcr->pool->name()), jcr->pool_source,
910 jcr->rstore->name(), jcr->rstore_source,
913 bstrutime(dt, sizeof(dt), jcr->sched_time),
919 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
921 jcr->RestoreJobId = str_to_int64(jid);
923 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
926 jcr->RestoreJobId = ua->int64_val;
929 jcr->set_JobLevel(L_FULL); /* default level */
930 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
931 if (jcr->RestoreJobId == 0) {
932 /* RegexWhere is take before RestoreWhere */
933 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
935 ua->signal(BNET_RUN_CMD);
936 ua->send_msg("Type: Restore\n"
937 "Title: Run Restore Job\n"
943 "Backup Client: %s\n"
944 "Restore Client: %s\n"
949 "Plugin Options: %s\n",
951 NPRT(jcr->RestoreBootstrap),
952 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
954 jcr->fileset->name(),
958 bstrutime(dt, sizeof(dt), jcr->sched_time),
959 jcr->catalog->name(),
961 NPRT(jcr->plugin_options));
963 ua->send_msg(_("Run Restore job\n"
969 "Backup Client: %s\n"
970 "Restore Client: %s\n"
975 "Plugin Options: %s\n"),
977 NPRT(jcr->RestoreBootstrap),
978 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
980 jcr->fileset->name(),
984 bstrutime(dt, sizeof(dt), jcr->sched_time),
985 jcr->catalog->name(),
987 NPRT(jcr->plugin_options));
991 ua->signal(BNET_RUN_CMD);
992 ua->send_msg("Type: Restore\n"
993 "Title: Run Restore job\n"
999 "Backup Client: %s\n"
1000 "Restore Client: %s\n"
1005 "Plugin Options: %s\n",
1007 NPRT(jcr->RestoreBootstrap),
1008 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1010 jcr->fileset->name(),
1012 jcr->client->name(),
1013 jcr->rstore->name(),
1014 bstrutime(dt, sizeof(dt), jcr->sched_time),
1015 jcr->catalog->name(),
1017 NPRT(jcr->plugin_options));
1019 ua->send_msg(_("Run Restore job\n"
1025 "Backup Client: %s\n"
1026 "Restore Client: %s\n"
1031 "Plugin Options: %s\n"),
1033 NPRT(jcr->RestoreBootstrap),
1034 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1036 jcr->fileset->name(),
1038 jcr->client->name(),
1039 jcr->rstore->name(),
1040 bstrutime(dt, sizeof(dt), jcr->sched_time),
1041 jcr->catalog->name(),
1043 NPRT(jcr->plugin_options));
1048 /* ***FIXME*** This needs to be fixed for bat */
1049 if (ua->api) ua->signal(BNET_RUN_CMD);
1050 ua->send_msg(_("Run Restore job\n"
1054 NPRT(jcr->RestoreBootstrap));
1056 /* RegexWhere is take before RestoreWhere */
1057 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1058 ua->send_msg(_("RegexWhere: %s\n"),
1059 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1061 ua->send_msg(_("Where: %s\n"),
1062 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1065 ua->send_msg(_("Replace: %s\n"
1072 "Plugin Options: %s\n"),
1074 jcr->client->name(),
1075 jcr->rstore->name(),
1076 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1077 bstrutime(dt, sizeof(dt), jcr->sched_time),
1078 jcr->catalog->name(),
1080 NPRT(jcr->plugin_options));
1086 jcr->set_JobLevel(L_FULL); /* default level */
1088 ua->signal(BNET_RUN_CMD);
1089 if (jcr->getJobType() == JT_COPY) {
1090 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1092 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1100 "Read Storage: %s\n"
1101 "Write Storage: %s\n"
1108 NPRT(jcr->RestoreBootstrap),
1109 jcr->client->name(),
1110 jcr->fileset->name(),
1111 NPRT(jcr->pool->name()),
1112 jcr->rstore->name(),
1113 jcr->wstore?jcr->wstore->name():"*None*",
1114 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1115 bstrutime(dt, sizeof(dt), jcr->sched_time),
1116 jcr->catalog->name(),
1119 if (jcr->getJobType() == JT_COPY) {
1120 prt_type = _("Run Copy job\n");
1122 prt_type = _("Run Migration job\n");
1129 "Pool: %s (From %s)\n"
1130 "Read Storage: %s (From %s)\n"
1131 "Write Storage: %s (From %s)\n"
1138 NPRT(jcr->RestoreBootstrap),
1139 jcr->client->name(),
1140 jcr->fileset->name(),
1141 NPRT(jcr->pool->name()), jcr->pool_source,
1142 jcr->rstore->name(), jcr->rstore_source,
1143 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1144 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1145 bstrutime(dt, sizeof(dt), jcr->sched_time),
1146 jcr->catalog->name(),
1151 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1158 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1162 static const char *kw[] = { /* command line arguments */
1163 "job", /* Used in a switch() */
1171 "regexwhere", /* 8 where string as a bregexp */
1173 "bootstrap", /* 10 */
1176 "priority", /* 13 */
1177 "yes", /* 14 -- if you change this change YES_POS too */
1178 "verifyjob", /* 15 */
1179 "files", /* 16 number of files to restore */
1180 "catalog", /* 17 override catalog */
1181 "since", /* 18 since */
1182 "cloned", /* 19 cloned */
1183 "verifylist", /* 20 verify output list */
1184 "migrationjob", /* 21 migration job name */
1186 "backupclient", /* 23 */
1187 "restoreclient", /* 24 */
1188 "pluginoptions", /* 25 */
1189 "spooldata", /* 26 */
1195 rc.catalog_name = NULL;
1197 rc.pool_name = NULL;
1198 rc.store_name = NULL;
1199 rc.client_name = NULL;
1200 rc.restore_client_name = NULL;
1201 rc.fileset_name = NULL;
1202 rc.verify_job_name = NULL;
1203 rc.previous_job_name = NULL;
1204 rc.spool_data_set = 0;
1207 for (i=1; i<ua->argc; i++) {
1208 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1210 /* Keep looking until we find a good keyword */
1211 for (j=0; !kw_ok && kw[j]; j++) {
1212 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1213 /* Note, yes and run have no value, so do not fail */
1214 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1215 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1218 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1222 ua->send_msg(_("Job name specified twice.\n"));
1225 rc.job_name = ua->argv[i];
1229 if (rc.jid && !rc.mod) {
1230 ua->send_msg(_("JobId specified twice.\n"));
1233 rc.jid = ua->argv[i];
1236 case 2: /* client */
1238 if (rc.client_name) {
1239 ua->send_msg(_("Client specified twice.\n"));
1242 rc.client_name = ua->argv[i];
1245 case 4: /* fileset */
1246 if (rc.fileset_name) {
1247 ua->send_msg(_("FileSet specified twice.\n"));
1250 rc.fileset_name = ua->argv[i];
1254 if (rc.level_name) {
1255 ua->send_msg(_("Level specified twice.\n"));
1258 rc.level_name = ua->argv[i];
1261 case 6: /* storage */
1263 if (rc.store_name) {
1264 ua->send_msg(_("Storage specified twice.\n"));
1267 rc.store_name = ua->argv[i];
1270 case 8: /* regexwhere */
1271 if ((rc.regexwhere || rc.where) && !rc.mod) {
1272 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1275 rc.regexwhere = ua->argv[i];
1276 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1277 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1283 if ((rc.where || rc.regexwhere) && !rc.mod) {
1284 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1287 rc.where = ua->argv[i];
1288 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1289 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1294 case 10: /* bootstrap */
1295 if (rc.bootstrap && !rc.mod) {
1296 ua->send_msg(_("Bootstrap specified twice.\n"));
1299 rc.bootstrap = ua->argv[i];
1302 case 11: /* replace */
1303 if (rc.replace && !rc.mod) {
1304 ua->send_msg(_("Replace specified twice.\n"));
1307 rc.replace = ua->argv[i];
1311 if (rc.when && !rc.mod) {
1312 ua->send_msg(_("When specified twice.\n"));
1315 rc.when = ua->argv[i];
1318 case 13: /* Priority */
1319 if (rc.Priority && !rc.mod) {
1320 ua->send_msg(_("Priority specified twice.\n"));
1323 rc.Priority = atoi(ua->argv[i]);
1324 if (rc.Priority <= 0) {
1325 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1333 case 15: /* Verify Job */
1334 if (rc.verify_job_name) {
1335 ua->send_msg(_("Verify Job specified twice.\n"));
1338 rc.verify_job_name = ua->argv[i];
1341 case 16: /* files */
1342 rc.files = atoi(ua->argv[i]);
1346 case 17: /* catalog */
1347 rc.catalog_name = ua->argv[i];
1351 case 18: /* since */
1352 rc.since = ua->argv[i];
1356 case 19: /* cloned */
1361 case 20: /* write verify list output */
1362 rc.verify_list = ua->argv[i];
1365 case 21: /* Migration Job */
1366 if (rc.previous_job_name) {
1367 ua->send_msg(_("Migration Job specified twice.\n"));
1370 rc.previous_job_name = ua->argv[i];
1375 ua->send_msg(_("Pool specified twice.\n"));
1378 rc.pool_name = ua->argv[i];
1381 case 23: /* backupclient */
1382 if (rc.client_name) {
1383 ua->send_msg(_("Client specified twice.\n"));
1386 rc.client_name = ua->argv[i];
1389 case 24: /* restoreclient */
1390 if (rc.restore_client_name && !rc.mod) {
1391 ua->send_msg(_("Restore Client specified twice.\n"));
1394 rc.restore_client_name = ua->argv[i];
1397 case 25: /* pluginoptions */
1398 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1400 if (rc.plugin_options) {
1401 ua->send_msg(_("Plugin Options specified twice.\n"));
1404 rc.plugin_options = ua->argv[i];
1405 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1406 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1411 case 26: /* spooldata */
1412 if (rc.spool_data_set) {
1413 ua->send_msg(_("Spool flag specified twice.\n"));
1416 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1417 rc.spool_data_set = 1;
1420 ua->send_msg(_("Invalid spooldata flag.\n"));
1423 case 27: /* comment */
1424 rc.comment = ua->argv[i];
1429 } /* end strcase compare */
1430 } /* end keyword loop */
1432 * End of keyword for loop -- if not found, we got a bogus keyword
1435 Dmsg1(800, "%s not found\n", ua->argk[i]);
1437 * Special case for Job Name, it can be the first
1438 * keyword that has no value.
1440 if (!rc.job_name && !ua->argv[i]) {
1441 rc.job_name = ua->argk[i]; /* use keyword as job name */
1442 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1444 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1448 } /* end argc loop */
1450 Dmsg0(800, "Done scan.\n");
1452 if (!is_comment_legal(ua, rc.comment)) {
1456 if (rc.catalog_name) {
1457 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1458 if (rc.catalog == NULL) {
1459 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1462 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1463 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1467 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1471 rc.job = GetJobResWithName(rc.job_name);
1473 if (*rc.job_name != 0) {
1474 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1476 rc.job = select_job_resource(ua);
1478 Dmsg1(800, "Found job=%s\n", rc.job_name);
1480 } else if (!rc.job) {
1481 ua->send_msg(_("A job name must be specified.\n"));
1482 rc.job = select_job_resource(ua);
1486 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1487 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1492 rc.pool = GetPoolResWithName(rc.pool_name);
1494 if (*rc.pool_name != 0) {
1495 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1497 rc.pool = select_pool_resource(ua);
1499 } else if (!rc.pool) {
1500 rc.pool = rc.job->pool; /* use default */
1504 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1505 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1508 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1510 if (rc.spool_data_set) {
1511 rc.job->spool_data = rc.spool_data;
1513 Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1515 if (rc.store_name) {
1516 rc.store->store = GetStoreResWithName(rc.store_name);
1517 pm_strcpy(rc.store->store_source, _("command line"));
1518 if (!rc.store->store) {
1519 if (*rc.store_name != 0) {
1520 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1522 rc.store->store = select_storage_resource(ua);
1523 pm_strcpy(rc.store->store_source, _("user selection"));
1525 } else if (!rc.store->store) {
1526 get_job_storage(rc.store, rc.job, NULL); /* use default */
1528 if (!rc.store->store) {
1529 ua->error_msg(_("No storage specified.\n"));
1531 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1532 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1533 rc.store->store->name());
1536 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1538 if (rc.client_name) {
1539 rc.client = GetClientResWithName(rc.client_name);
1541 if (*rc.client_name != 0) {
1542 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1544 rc.client = select_client_resource(ua);
1546 } else if (!rc.client) {
1547 rc.client = rc.job->client; /* use default */
1551 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1552 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1556 Dmsg1(800, "Using client=%s\n", rc.client->name());
1558 if (rc.restore_client_name) {
1559 rc.client = GetClientResWithName(rc.restore_client_name);
1561 if (*rc.restore_client_name != 0) {
1562 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1564 rc.client = select_client_resource(ua);
1566 } else if (!rc.client) {
1567 rc.client = rc.job->client; /* use default */
1571 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1572 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1576 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1579 if (rc.fileset_name) {
1580 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1582 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1583 rc.fileset = select_fileset_resource(ua);
1585 } else if (!rc.fileset) {
1586 rc.fileset = rc.job->fileset; /* use default */
1590 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1591 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1592 rc.fileset->name());
1596 if (rc.verify_job_name) {
1597 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1598 if (!rc.verify_job) {
1599 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1600 rc.verify_job = select_job_resource(ua);
1602 } else if (!rc.verify_job) {
1603 rc.verify_job = rc.job->verify_job;
1606 if (rc.previous_job_name) {
1607 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1608 if (!rc.previous_job) {
1609 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1610 rc.previous_job = select_job_resource(ua);
1613 rc.previous_job = rc.job->verify_job;