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;
64 int ignoreduplicatecheck;
65 bool ignoreduplicatecheck_set;
68 run_ctx() { memset(this, 0, sizeof(run_ctx));
69 store = new USTORE; };
70 ~run_ctx() { delete store; };
73 /* Forward referenced subroutines */
74 static void select_job_level(UAContext *ua, JCR *jcr);
75 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job,
76 const char *verify_list, char *jid, const char *replace,
78 static void select_where_regexp(UAContext *ua, JCR *jcr);
79 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc);
80 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc);
81 static int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc);
83 /* Imported variables */
84 extern struct s_kw ReplaceOptions[];
87 * For Backup and Verify Jobs
88 * run [job=]<job-name> level=<level-name>
97 int run_cmd(UAContext *ua, const char *cmd)
103 if (!open_client_db(ua)) {
107 if (!scan_command_line_arguments(ua, rc)) {
111 if (find_arg(ua, NT_("fdcalled")) > 0) {
112 jcr->file_bsock = dup_bsock(ua->UA_sock);
117 * Create JCR to run job. NOTE!!! after this point, free_jcr()
121 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
122 set_jcr_defaults(jcr, rc.job);
123 jcr->unlink_bsr = ua->jcr->unlink_bsr; /* copy unlink flag from caller */
124 ua->jcr->unlink_bsr = false;
126 /* Transfer JobIds to new restore Job */
127 if (ua->jcr->JobIds) {
128 jcr->JobIds = ua->jcr->JobIds;
129 ua->jcr->JobIds = NULL;
133 if (!reset_restore_context(ua, jcr, rc)) {
138 /* Run without prompting? */
139 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
144 * Prompt User to see if all run job parameters are correct, and
145 * allow him to modify them.
147 if (!display_job_parameters(ua, jcr, rc.job, rc.verify_list, rc.jid, rc.replace,
152 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
156 if (strncasecmp(ua->cmd, ".mod ", 5) == 0 ||
157 (strncasecmp(ua->cmd, "mod ", 4) == 0 && strlen(ua->cmd) > 6)) {
160 if (!scan_command_line_arguments(ua, rc)) {
166 /* Allow the user to modify the settings */
167 status = modify_job_parameters(ua, jcr, rc);
178 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
180 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
183 Dmsg3(100, "JobId=%u using pool %s priority=%d\n", (int)jcr->JobId,
184 jcr->pool->name(), jcr->JobPriority);
185 Dmsg1(900, "Running a job; its spool_data = %d\n", jcr->spool_data);
186 JobId = run_job(jcr);
187 Dmsg4(100, "JobId=%u NewJobId=%d using pool %s priority=%d\n", (int)jcr->JobId,
188 JobId, jcr->pool->name(), jcr->JobPriority);
189 free_jcr(jcr); /* release jcr */
191 ua->error_msg(_("Job failed.\n"));
194 ua->send_msg(_("Job queued. JobId=%s\n"), edit_int64(JobId, ed1));
200 ua->send_msg(_("Job not run.\n"));
202 return 0; /* do not run */
205 int modify_job_parameters(UAContext *ua, JCR *jcr, run_ctx &rc)
209 /* Some options are not available through the menu
210 * TODO: Add an advanced menu?
212 if (rc.spool_data_set) {
213 jcr->spool_data = rc.spool_data;
216 /* Used by migration jobs that can have the same name,
217 * but can run at the same time
219 if (rc.ignoreduplicatecheck_set) {
220 jcr->IgnoreDuplicateJobChecking = rc.ignoreduplicatecheck;
224 * At user request modify parameters of job to be run.
226 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
229 start_prompt(ua, _("Parameters to modify:\n"));
230 add_prompt(ua, _("Level")); /* 0 */
231 add_prompt(ua, _("Storage")); /* 1 */
232 add_prompt(ua, _("Job")); /* 2 */
233 add_prompt(ua, _("FileSet")); /* 3 */
234 if (jcr->getJobType() == JT_RESTORE) {
235 add_prompt(ua, _("Restore Client")); /* 4 */
237 add_prompt(ua, _("Client")); /* 4 */
239 add_prompt(ua, _("When")); /* 5 */
240 add_prompt(ua, _("Priority")); /* 6 */
241 if (jcr->getJobType() == JT_BACKUP ||
242 jcr->getJobType() == JT_COPY ||
243 jcr->getJobType() == JT_MIGRATE ||
244 jcr->getJobType() == JT_VERIFY) {
245 add_prompt(ua, _("Pool")); /* 7 */
246 if (jcr->getJobType() == JT_VERIFY) {
247 add_prompt(ua, _("Verify Job")); /* 8 */
249 } else if (jcr->getJobType() == JT_RESTORE) {
250 add_prompt(ua, _("Bootstrap")); /* 7 */
251 add_prompt(ua, _("Where")); /* 8 */
252 add_prompt(ua, _("File Relocation"));/* 9 */
253 add_prompt(ua, _("Replace")); /* 10 */
254 add_prompt(ua, _("JobId")); /* 11 */
256 if (jcr->getJobType() == JT_BACKUP || jcr->getJobType() == JT_RESTORE) {
257 add_prompt(ua, _("Plugin Options")); /* 12 */
259 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
262 select_job_level(ua, jcr);
266 rc.store->store = select_storage_resource(ua);
267 if (rc.store->store) {
268 pm_strcpy(rc.store->store_source, _("user selection"));
269 set_rwstorage(jcr, rc.store);
275 rc.job = select_job_resource(ua);
278 set_jcr_defaults(jcr, rc.job);
284 rc.fileset = select_fileset_resource(ua);
286 jcr->fileset = rc.fileset;
292 rc.client = select_client_resource(ua);
294 jcr->client = rc.client;
300 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
303 if (ua->cmd[0] == 0) {
304 jcr->sched_time = time(NULL);
306 jcr->sched_time = str_to_utime(ua->cmd);
307 if (jcr->sched_time == 0) {
308 ua->send_msg(_("Invalid time, using current time.\n"));
309 jcr->sched_time = time(NULL);
315 if (!get_pint(ua, _("Enter new Priority: "))) {
318 if (ua->pint32_val == 0) {
319 ua->send_msg(_("Priority must be a positive integer.\n"));
321 jcr->JobPriority = ua->pint32_val;
325 /* Pool or Bootstrap depending on JobType */
326 if (jcr->getJobType() == JT_BACKUP ||
327 jcr->getJobType() == JT_COPY ||
328 jcr->getJobType() == JT_MIGRATE ||
329 jcr->getJobType() == JT_VERIFY) { /* Pool */
330 rc.pool = select_pool_resource(ua);
333 Dmsg1(100, "Set new pool=%s\n", jcr->pool->name());
340 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
343 if (jcr->RestoreBootstrap) {
344 free(jcr->RestoreBootstrap);
345 jcr->RestoreBootstrap = NULL;
347 if (ua->cmd[0] != 0) {
348 jcr->RestoreBootstrap = bstrdup(ua->cmd);
349 fd = fopen(jcr->RestoreBootstrap, "rb");
352 ua->send_msg(_("Warning cannot open %s: ERR=%s\n"),
353 jcr->RestoreBootstrap, be.bstrerror());
354 free(jcr->RestoreBootstrap);
355 jcr->RestoreBootstrap = NULL;
363 if (jcr->getJobType() == JT_VERIFY) {
364 rc.verify_job = select_job_resource(ua);
366 jcr->verify_job = rc.verify_job;
371 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
374 if (jcr->RegexWhere) { /* cannot use regexwhere and where */
375 free(jcr->RegexWhere);
376 jcr->RegexWhere = NULL;
382 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
385 jcr->where = bstrdup(ua->cmd);
388 /* File relocation */
389 select_where_regexp(ua, jcr);
393 start_prompt(ua, _("Replace:\n"));
394 for (i=0; ReplaceOptions[i].name; i++) {
395 add_prompt(ua, ReplaceOptions[i].name);
397 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
399 rc.replace = ReplaceOptions[opt].name;
400 jcr->replace = ReplaceOptions[opt].token;
405 rc.jid = NULL; /* force reprompt */
406 jcr->RestoreJobId = 0;
407 if (jcr->RestoreBootstrap) {
408 ua->send_msg(_("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
413 if (!get_cmd(ua, _("Please Plugin Options string: "))) {
416 if (jcr->plugin_options) {
417 free(jcr->plugin_options);
418 jcr->plugin_options = NULL;
420 jcr->plugin_options = bstrdup(ua->cmd);
422 case -1: /* error or cancel */
439 * Reset the restore context.
440 * This subroutine can be called multiple times, so it
441 * must keep any prior settings.
443 static bool reset_restore_context(UAContext *ua, JCR *jcr, run_ctx &rc)
447 jcr->verify_job = rc.verify_job;
448 jcr->previous_job = rc.previous_job;
450 if (jcr->pool != jcr->job->pool) {
451 pm_strcpy(jcr->pool_source, _("User input"));
453 set_rwstorage(jcr, rc.store);
454 jcr->client = rc.client;
455 pm_strcpy(jcr->client_name, rc.client->name());
456 jcr->fileset = rc.fileset;
457 jcr->ExpectedFiles = rc.files;
459 jcr->catalog = rc.catalog;
460 pm_strcpy(jcr->catalog_source, _("User input"));
463 pm_strcpy(jcr->comment, rc.comment);
469 jcr->where = bstrdup(rc.where);
474 if (jcr->RegexWhere) {
475 free(jcr->RegexWhere);
477 jcr->RegexWhere = bstrdup(rc.regexwhere);
478 rc.regexwhere = NULL;
482 jcr->sched_time = str_to_utime(rc.when);
483 if (jcr->sched_time == 0) {
484 ua->send_msg(_("Invalid time, using current time.\n"));
485 jcr->sched_time = time(NULL);
491 if (jcr->RestoreBootstrap) {
492 free(jcr->RestoreBootstrap);
494 jcr->RestoreBootstrap = bstrdup(rc.bootstrap);
498 if (rc.plugin_options) {
499 if (jcr->plugin_options) {
500 free(jcr->plugin_options);
502 jcr->plugin_options = bstrdup(rc.plugin_options);
503 rc.plugin_options = NULL;
508 for (i=0; ReplaceOptions[i].name; i++) {
509 if (strcasecmp(rc.replace, ReplaceOptions[i].name) == 0) {
510 jcr->replace = ReplaceOptions[i].token;
514 ua->send_msg(_("Invalid replace option: %s\n"), rc.replace);
517 } else if (rc.job->replace) {
518 jcr->replace = rc.job->replace;
520 jcr->replace = REPLACE_ALWAYS;
525 jcr->JobPriority = rc.Priority;
531 jcr->stime = get_pool_memory(PM_MESSAGE);
533 pm_strcpy(jcr->stime, rc.since);
538 jcr->cloned = rc.cloned;
542 /* If pool changed, update migration write storage */
543 if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
544 (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
545 if (!set_migration_wstorage(jcr, rc.pool)) {
549 rc.replace = ReplaceOptions[0].name;
550 for (i=0; ReplaceOptions[i].name; i++) {
551 if (ReplaceOptions[i].token == jcr->replace) {
552 rc.replace = ReplaceOptions[i].name;
556 if (!get_level_from_name(jcr, rc.level_name)) {
557 ua->send_msg(_("Level \"%s\" not valid.\n"), rc.level_name);
560 rc.level_name = NULL;
563 /* Note, this is also MigrateJobId and a VerifyJobId */
564 jcr->RestoreJobId = str_to_int64(rc.jid);
570 static void select_where_regexp(UAContext *ua, JCR *jcr)
573 char *strip_prefix, *add_prefix, *add_suffix, *rwhere;
574 strip_prefix = add_suffix = rwhere = add_prefix = NULL;
577 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"),
578 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix));
580 start_prompt(ua, _("This will replace your current Where value\n"));
581 add_prompt(ua, _("Strip prefix")); /* 0 */
582 add_prompt(ua, _("Add prefix")); /* 1 */
583 add_prompt(ua, _("Add file suffix")); /* 2 */
584 add_prompt(ua, _("Enter a regexp")); /* 3 */
585 add_prompt(ua, _("Test filename manipulation")); /* 4 */
586 add_prompt(ua, _("Use this ?")); /* 5 */
588 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
591 if (get_cmd(ua, _("Please enter path prefix to strip: "))) {
592 if (strip_prefix) bfree(strip_prefix);
593 strip_prefix = bstrdup(ua->cmd);
599 if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) {
600 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
604 if (add_prefix) bfree(add_prefix);
605 add_prefix = bstrdup(ua->cmd);
610 if (get_cmd(ua, _("Please enter file suffix to add: "))) {
611 if (add_suffix) bfree(add_suffix);
612 add_suffix = bstrdup(ua->cmd);
617 if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) {
618 if (rwhere) bfree(rwhere);
619 rwhere = bstrdup(ua->cmd);
628 if (rwhere && rwhere[0] != '\0') {
629 regs = get_bregexps(rwhere);
630 ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere));
632 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
633 regexp = (char *) bmalloc (len * sizeof(char));
634 bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix);
635 regs = get_bregexps(regexp);
636 ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"),
637 NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp));
643 ua->send_msg(_("Cannot use your regexp\n"));
646 ua->send_msg(_("Enter a period (.) to stop this test\n"));
647 while (get_cmd(ua, _("Please enter filename to test: "))) {
648 apply_bregexps(ua->cmd, regs, &result);
649 ua->send_msg(_("%s -> %s\n"), ua->cmd, result);
658 case -1: /* error or cancel */
664 /* replace the existing where */
670 /* replace the existing regexwhere */
671 if (jcr->RegexWhere) {
672 bfree(jcr->RegexWhere);
673 jcr->RegexWhere = NULL;
677 jcr->RegexWhere = bstrdup(rwhere);
678 } else if (strip_prefix || add_prefix || add_suffix) {
679 int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix);
680 jcr->RegexWhere = (char *) bmalloc(len*sizeof(char));
681 bregexp_build_where(jcr->RegexWhere, len, strip_prefix, add_prefix, add_suffix);
684 regs = get_bregexps(jcr->RegexWhere);
689 if (jcr->RegexWhere) {
690 bfree(jcr->RegexWhere);
691 jcr->RegexWhere = NULL;
693 ua->send_msg(_("Cannot use your regexp.\n"));
697 if (strip_prefix) bfree(strip_prefix);
698 if (add_prefix) bfree(add_prefix);
699 if (add_suffix) bfree(add_suffix);
700 if (rwhere) bfree(rwhere);
703 static void select_job_level(UAContext *ua, JCR *jcr)
705 if (jcr->getJobType() == JT_BACKUP) {
706 start_prompt(ua, _("Levels:\n"));
707 // add_prompt(ua, _("Base"));
708 add_prompt(ua, _("Full"));
709 add_prompt(ua, _("Incremental"));
710 add_prompt(ua, _("Differential"));
711 add_prompt(ua, _("Since"));
712 add_prompt(ua, _("VirtualFull"));
713 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
715 // jcr->JobLevel = L_BASE;
718 jcr->setJobLevel(L_FULL);
721 jcr->setJobLevel(L_INCREMENTAL);
724 jcr->setJobLevel(L_DIFFERENTIAL);
727 jcr->setJobLevel(L_SINCE);
730 jcr->setJobLevel(L_VIRTUAL_FULL);
735 } else if (jcr->getJobType() == JT_VERIFY) {
736 start_prompt(ua, _("Levels:\n"));
737 add_prompt(ua, _("Initialize Catalog"));
738 add_prompt(ua, _("Verify Catalog"));
739 add_prompt(ua, _("Verify Volume to Catalog"));
740 add_prompt(ua, _("Verify Disk to Catalog"));
741 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
742 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
744 jcr->setJobLevel(L_VERIFY_INIT);
747 jcr->setJobLevel(L_VERIFY_CATALOG);
750 jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
753 jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
756 jcr->setJobLevel(L_VERIFY_DATA);
762 ua->warning_msg(_("Level not appropriate for this Job. Cannot be changed.\n"));
767 static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, const char *verify_list,
768 char *jid, const char *replace, char *client_name)
771 char dt[MAX_TIME_LENGTH];
773 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
774 switch (jcr->getJobType()) {
777 ua->signal(BNET_RUN_CMD);
778 ua->send_msg("Type: Admin\n"
779 "Title: Run Admin 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 ua->send_msg(_("Run Admin Job\n"
801 jcr->fileset->name(),
802 NPRT(jcr->client->name()),
803 jcr->wstore?jcr->wstore->name():"*None*",
804 bstrutime(dt, sizeof(dt), jcr->sched_time),
807 jcr->setJobLevel(L_FULL);
811 if (jcr->getJobType() == JT_BACKUP) {
813 ua->signal(BNET_RUN_CMD);
814 ua->send_msg("Type: Backup\n"
815 "Title: Run Backup Job\n"
826 level_to_str(jcr->getJobLevel()),
828 jcr->fileset->name(),
829 NPRT(jcr->pool->name()),
830 jcr->wstore?jcr->wstore->name():"*None*",
831 bstrutime(dt, sizeof(dt), jcr->sched_time),
833 jcr->plugin_options?"Plugin Options: ":"",
834 jcr->plugin_options?jcr->plugin_options:"",
835 jcr->plugin_options?"\n":"");
837 ua->send_msg(_("Run Backup job\n"
842 "Pool: %s (From %s)\n"
843 "Storage: %s (From %s)\n"
848 level_to_str(jcr->getJobLevel()),
850 jcr->fileset->name(),
851 NPRT(jcr->pool->name()), jcr->pool_source,
852 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
853 bstrutime(dt, sizeof(dt), jcr->sched_time),
855 jcr->plugin_options?"Plugin Options: ":"",
856 jcr->plugin_options?jcr->plugin_options:"",
857 jcr->plugin_options?"\n":"");
859 } else { /* JT_VERIFY */
862 if (jcr->verify_job) {
863 Name = jcr->verify_job->name();
864 } else if (jcr->RestoreJobId) { /* Display job name if jobid requested */
865 memset(&jr, 0, sizeof(jr));
866 jr.JobId = jcr->RestoreJobId;
867 if (!db_get_job_record(jcr, ua->db, &jr)) {
868 ua->error_msg(_("Could not get job record for selected JobId. ERR=%s"),
869 db_strerror(ua->db));
877 verify_list = job->WriteVerifyList;
883 ua->signal(BNET_RUN_CMD);
884 ua->send_msg("Type: Verify\n"
885 "Title: Run Verify Job\n"
890 "Pool: %s (From %s)\n"
891 "Storage: %s (From %s)\n"
897 level_to_str(jcr->getJobLevel()),
899 jcr->fileset->name(),
900 NPRT(jcr->pool->name()), jcr->pool_source,
901 jcr->rstore->name(), jcr->rstore_source,
904 bstrutime(dt, sizeof(dt), jcr->sched_time),
907 ua->send_msg(_("Run Verify Job\n"
912 "Pool: %s (From %s)\n"
913 "Storage: %s (From %s)\n"
919 level_to_str(jcr->getJobLevel()),
921 jcr->fileset->name(),
922 NPRT(jcr->pool->name()), jcr->pool_source,
923 jcr->rstore->name(), jcr->rstore_source,
926 bstrutime(dt, sizeof(dt), jcr->sched_time),
932 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
934 jcr->RestoreJobId = str_to_int64(jid);
936 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
939 jcr->RestoreJobId = ua->int64_val;
942 jcr->setJobLevel(L_FULL); /* default level */
943 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
944 if (jcr->RestoreJobId == 0) {
945 /* RegexWhere is take before RestoreWhere */
946 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
948 ua->signal(BNET_RUN_CMD);
949 ua->send_msg("Type: Restore\n"
950 "Title: Run Restore Job\n"
956 "Backup Client: %s\n"
957 "Restore Client: %s\n"
962 "Plugin Options: %s\n",
964 NPRT(jcr->RestoreBootstrap),
965 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
967 jcr->fileset->name(),
971 bstrutime(dt, sizeof(dt), jcr->sched_time),
972 jcr->catalog->name(),
974 NPRT(jcr->plugin_options));
976 ua->send_msg(_("Run Restore job\n"
982 "Backup Client: %s\n"
983 "Restore Client: %s\n"
988 "Plugin Options: %s\n"),
990 NPRT(jcr->RestoreBootstrap),
991 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
993 jcr->fileset->name(),
997 bstrutime(dt, sizeof(dt), jcr->sched_time),
998 jcr->catalog->name(),
1000 NPRT(jcr->plugin_options));
1004 ua->signal(BNET_RUN_CMD);
1005 ua->send_msg("Type: Restore\n"
1006 "Title: Run Restore job\n"
1012 "Backup Client: %s\n"
1013 "Restore Client: %s\n"
1018 "Plugin Options: %s\n",
1020 NPRT(jcr->RestoreBootstrap),
1021 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1023 jcr->fileset->name(),
1025 jcr->client->name(),
1026 jcr->rstore->name(),
1027 bstrutime(dt, sizeof(dt), jcr->sched_time),
1028 jcr->catalog->name(),
1030 NPRT(jcr->plugin_options));
1032 ua->send_msg(_("Run Restore job\n"
1038 "Backup Client: %s\n"
1039 "Restore Client: %s\n"
1044 "Plugin Options: %s\n"),
1046 NPRT(jcr->RestoreBootstrap),
1047 jcr->where?jcr->where:NPRT(job->RestoreWhere),
1049 jcr->fileset->name(),
1051 jcr->client->name(),
1052 jcr->rstore->name(),
1053 bstrutime(dt, sizeof(dt), jcr->sched_time),
1054 jcr->catalog->name(),
1056 NPRT(jcr->plugin_options));
1061 /* ***FIXME*** This needs to be fixed for bat */
1062 if (ua->api) ua->signal(BNET_RUN_CMD);
1063 ua->send_msg(_("Run Restore job\n"
1067 NPRT(jcr->RestoreBootstrap));
1069 /* RegexWhere is take before RestoreWhere */
1070 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
1071 ua->send_msg(_("RegexWhere: %s\n"),
1072 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
1074 ua->send_msg(_("Where: %s\n"),
1075 jcr->where?jcr->where:NPRT(job->RestoreWhere));
1078 ua->send_msg(_("Replace: %s\n"
1085 "Plugin Options: %s\n"),
1087 jcr->client->name(),
1088 jcr->rstore->name(),
1089 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
1090 bstrutime(dt, sizeof(dt), jcr->sched_time),
1091 jcr->catalog->name(),
1093 NPRT(jcr->plugin_options));
1099 jcr->setJobLevel(L_FULL); /* default level */
1101 ua->signal(BNET_RUN_CMD);
1102 if (jcr->getJobType() == JT_COPY) {
1103 prt_type = (char *)"Type: Copy\nTitle: Run Copy Job\n";
1105 prt_type = (char *)"Type: Migration\nTitle: Run Migration Job\n";
1113 "Read Storage: %s\n"
1114 "Write Storage: %s\n"
1121 NPRT(jcr->RestoreBootstrap),
1122 jcr->client->name(),
1123 jcr->fileset->name(),
1124 NPRT(jcr->pool->name()),
1125 jcr->rstore->name(),
1126 jcr->wstore?jcr->wstore->name():"*None*",
1127 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1128 bstrutime(dt, sizeof(dt), jcr->sched_time),
1129 jcr->catalog->name(),
1132 if (jcr->getJobType() == JT_COPY) {
1133 prt_type = _("Run Copy job\n");
1135 prt_type = _("Run Migration job\n");
1142 "Pool: %s (From %s)\n"
1143 "Read Storage: %s (From %s)\n"
1144 "Write Storage: %s (From %s)\n"
1151 NPRT(jcr->RestoreBootstrap),
1152 jcr->client->name(),
1153 jcr->fileset->name(),
1154 NPRT(jcr->pool->name()), jcr->pool_source,
1155 jcr->rstore->name(), jcr->rstore_source,
1156 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
1157 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
1158 bstrutime(dt, sizeof(dt), jcr->sched_time),
1159 jcr->catalog->name(),
1164 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
1171 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
1175 static const char *kw[] = { /* command line arguments */
1176 "job", /* Used in a switch() */
1184 "regexwhere", /* 8 where string as a bregexp */
1186 "bootstrap", /* 10 */
1189 "priority", /* 13 */
1190 "yes", /* 14 -- if you change this change YES_POS too */
1191 "verifyjob", /* 15 */
1192 "files", /* 16 number of files to restore */
1193 "catalog", /* 17 override catalog */
1194 "since", /* 18 since */
1195 "cloned", /* 19 cloned */
1196 "verifylist", /* 20 verify output list */
1197 "migrationjob", /* 21 migration job name */
1199 "backupclient", /* 23 */
1200 "restoreclient", /* 24 */
1201 "pluginoptions", /* 25 */
1202 "spooldata", /* 26 */
1204 "ignoreduplicatecheck", /* 28 */
1210 rc.catalog_name = NULL;
1212 rc.pool_name = NULL;
1213 rc.store_name = NULL;
1214 rc.client_name = NULL;
1215 rc.restore_client_name = NULL;
1216 rc.fileset_name = NULL;
1217 rc.verify_job_name = NULL;
1218 rc.previous_job_name = NULL;
1219 rc.spool_data_set = false;
1220 rc.ignoreduplicatecheck = false;
1223 for (i=1; i<ua->argc; i++) {
1224 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1226 /* Keep looking until we find a good keyword */
1227 for (j=0; !kw_ok && kw[j]; j++) {
1228 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1229 /* Note, yes and run have no value, so do not fail */
1230 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1231 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1234 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1238 ua->send_msg(_("Job name specified twice.\n"));
1241 rc.job_name = ua->argv[i];
1245 if (rc.jid && !rc.mod) {
1246 ua->send_msg(_("JobId specified twice.\n"));
1249 rc.jid = ua->argv[i];
1252 case 2: /* client */
1254 if (rc.client_name) {
1255 ua->send_msg(_("Client specified twice.\n"));
1258 rc.client_name = ua->argv[i];
1261 case 4: /* fileset */
1262 if (rc.fileset_name) {
1263 ua->send_msg(_("FileSet specified twice.\n"));
1266 rc.fileset_name = ua->argv[i];
1270 if (rc.level_name) {
1271 ua->send_msg(_("Level specified twice.\n"));
1274 rc.level_name = ua->argv[i];
1277 case 6: /* storage */
1279 if (rc.store_name) {
1280 ua->send_msg(_("Storage specified twice.\n"));
1283 rc.store_name = ua->argv[i];
1286 case 8: /* regexwhere */
1287 if ((rc.regexwhere || rc.where) && !rc.mod) {
1288 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1291 rc.regexwhere = ua->argv[i];
1292 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1293 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1299 if ((rc.where || rc.regexwhere) && !rc.mod) {
1300 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1303 rc.where = ua->argv[i];
1304 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1305 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1310 case 10: /* bootstrap */
1311 if (rc.bootstrap && !rc.mod) {
1312 ua->send_msg(_("Bootstrap specified twice.\n"));
1315 rc.bootstrap = ua->argv[i];
1318 case 11: /* replace */
1319 if (rc.replace && !rc.mod) {
1320 ua->send_msg(_("Replace specified twice.\n"));
1323 rc.replace = ua->argv[i];
1327 if (rc.when && !rc.mod) {
1328 ua->send_msg(_("When specified twice.\n"));
1331 rc.when = ua->argv[i];
1334 case 13: /* Priority */
1335 if (rc.Priority && !rc.mod) {
1336 ua->send_msg(_("Priority specified twice.\n"));
1339 rc.Priority = atoi(ua->argv[i]);
1340 if (rc.Priority <= 0) {
1341 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1349 case 15: /* Verify Job */
1350 if (rc.verify_job_name) {
1351 ua->send_msg(_("Verify Job specified twice.\n"));
1354 rc.verify_job_name = ua->argv[i];
1357 case 16: /* files */
1358 rc.files = atoi(ua->argv[i]);
1361 case 17: /* catalog */
1362 rc.catalog_name = ua->argv[i];
1365 case 18: /* since */
1366 rc.since = ua->argv[i];
1369 case 19: /* cloned */
1373 case 20: /* write verify list output */
1374 rc.verify_list = ua->argv[i];
1377 case 21: /* Migration Job */
1378 if (rc.previous_job_name) {
1379 ua->send_msg(_("Migration Job specified twice.\n"));
1382 rc.previous_job_name = ua->argv[i];
1387 ua->send_msg(_("Pool specified twice.\n"));
1390 rc.pool_name = ua->argv[i];
1393 case 23: /* backupclient */
1394 if (rc.client_name) {
1395 ua->send_msg(_("Client specified twice.\n"));
1398 rc.client_name = ua->argv[i];
1401 case 24: /* restoreclient */
1402 if (rc.restore_client_name && !rc.mod) {
1403 ua->send_msg(_("Restore Client specified twice.\n"));
1406 rc.restore_client_name = ua->argv[i];
1409 case 25: /* pluginoptions */
1410 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1412 if (rc.plugin_options) {
1413 ua->send_msg(_("Plugin Options specified twice.\n"));
1416 rc.plugin_options = ua->argv[i];
1417 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1418 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1423 case 26: /* spooldata */
1424 if (rc.spool_data_set) {
1425 ua->send_msg(_("Spool flag specified twice.\n"));
1428 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1429 rc.spool_data_set = true;
1432 ua->send_msg(_("Invalid spooldata flag.\n"));
1435 case 27: /* comment */
1436 rc.comment = ua->argv[i];
1439 case 28: /* ignoreduplicatecheck */
1440 if (rc.ignoreduplicatecheck_set) {
1441 ua->send_msg(_("IgnoreDuplicateCheck flag specified twice.\n"));
1444 if (is_yesno(ua->argv[i], &rc.ignoreduplicatecheck)) {
1445 rc.ignoreduplicatecheck_set = true;
1448 ua->send_msg(_("Invalid ignoreduplicatecheck flag.\n"));
1454 } /* end strcase compare */
1455 } /* end keyword loop */
1457 * End of keyword for loop -- if not found, we got a bogus keyword
1460 Dmsg1(800, "%s not found\n", ua->argk[i]);
1462 * Special case for Job Name, it can be the first
1463 * keyword that has no value.
1465 if (!rc.job_name && !ua->argv[i]) {
1466 rc.job_name = ua->argk[i]; /* use keyword as job name */
1467 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1469 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1473 } /* end argc loop */
1475 Dmsg0(800, "Done scan.\n");
1477 if (!is_comment_legal(ua, rc.comment)) {
1481 if (rc.catalog_name) {
1482 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1483 if (rc.catalog == NULL) {
1484 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1487 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1488 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1492 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1496 rc.job = GetJobResWithName(rc.job_name);
1498 if (*rc.job_name != 0) {
1499 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1501 rc.job = select_job_resource(ua);
1503 Dmsg1(800, "Found job=%s\n", rc.job_name);
1505 } else if (!rc.job) {
1506 ua->send_msg(_("A job name must be specified.\n"));
1507 rc.job = select_job_resource(ua);
1511 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1512 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1517 rc.pool = GetPoolResWithName(rc.pool_name);
1519 if (*rc.pool_name != 0) {
1520 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1522 rc.pool = select_pool_resource(ua);
1524 } else if (!rc.pool) {
1525 rc.pool = rc.job->pool; /* use default */
1529 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1530 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1533 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1535 if (rc.store_name) {
1536 rc.store->store = GetStoreResWithName(rc.store_name);
1537 pm_strcpy(rc.store->store_source, _("command line"));
1538 if (!rc.store->store) {
1539 if (*rc.store_name != 0) {
1540 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1542 rc.store->store = select_storage_resource(ua);
1543 pm_strcpy(rc.store->store_source, _("user selection"));
1545 } else if (!rc.store->store) {
1546 get_job_storage(rc.store, rc.job, NULL); /* use default */
1548 if (!rc.store->store) {
1549 ua->error_msg(_("No storage specified.\n"));
1551 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1552 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1553 rc.store->store->name());
1556 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1558 if (rc.client_name) {
1559 rc.client = GetClientResWithName(rc.client_name);
1561 if (*rc.client_name != 0) {
1562 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.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 client=%s\n", rc.client->name());
1578 if (rc.restore_client_name) {
1579 rc.client = GetClientResWithName(rc.restore_client_name);
1581 if (*rc.restore_client_name != 0) {
1582 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1584 rc.client = select_client_resource(ua);
1586 } else if (!rc.client) {
1587 rc.client = rc.job->client; /* use default */
1591 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1592 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1596 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1598 if (rc.fileset_name) {
1599 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1601 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1602 rc.fileset = select_fileset_resource(ua);
1604 } else if (!rc.fileset) {
1605 rc.fileset = rc.job->fileset; /* use default */
1609 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1610 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1611 rc.fileset->name());
1615 if (rc.verify_job_name) {
1616 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1617 if (!rc.verify_job) {
1618 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1619 rc.verify_job = select_job_resource(ua);
1621 } else if (!rc.verify_job) {
1622 rc.verify_job = rc.job->verify_job;
1625 if (rc.previous_job_name) {
1626 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1627 if (!rc.previous_job) {
1628 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1629 rc.previous_job = select_job_resource(ua);
1632 rc.previous_job = rc.job->verify_job;