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)
755 Dmsg1(800, "JobType=%c\n", jcr->getJobType());
756 switch (jcr->getJobType()) {
758 char dt[MAX_TIME_LENGTH];
760 if (ua->api) ua->signal(BNET_RUN_CMD);
761 ua->send_msg(_("Run %s job\n"
770 jcr->fileset->name(),
771 NPRT(jcr->client->name()),
772 jcr->wstore?jcr->wstore->name():"*None*",
773 bstrutime(dt, sizeof(dt), jcr->sched_time),
775 jcr->set_JobLevel(L_FULL);
779 if (jcr->getJobType() == JT_BACKUP) {
780 if (ua->api) ua->signal(BNET_RUN_CMD);
781 ua->send_msg(_("Run %s job\n"
786 "Pool: %s (From %s)\n"
787 "Storage: %s (From %s)\n"
793 level_to_str(jcr->getJobLevel()),
795 jcr->fileset->name(),
796 NPRT(jcr->pool->name()), jcr->pool_source,
797 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
798 bstrutime(dt, sizeof(dt), jcr->sched_time),
800 jcr->plugin_options?"Plugin Options: ":"",
801 jcr->plugin_options?jcr->plugin_options:"",
802 jcr->plugin_options?"\n":"");
803 } else { /* JT_VERIFY */
805 if (jcr->verify_job) {
806 Name = jcr->verify_job->name();
811 verify_list = job->WriteVerifyList;
816 if (ua->api) ua->signal(BNET_RUN_CMD);
817 ua->send_msg(_("Run %s job\n"
822 "Pool: %s (From %s)\n"
823 "Storage: %s (From %s)\n"
830 level_to_str(jcr->getJobLevel()),
832 jcr->fileset->name(),
833 NPRT(jcr->pool->name()), jcr->pool_source,
834 jcr->rstore->name(), jcr->rstore_source,
837 bstrutime(dt, sizeof(dt), jcr->sched_time),
842 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
844 jcr->RestoreJobId = str_to_int64(jid);
846 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
849 jcr->RestoreJobId = ua->int64_val;
852 jcr->set_JobLevel(L_FULL); /* default level */
853 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
854 if (jcr->RestoreJobId == 0) {
855 if (ua->api) ua->signal(BNET_RUN_CMD);
856 /* RegexWhere is take before RestoreWhere */
857 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
858 ua->send_msg(_("Run Restore job\n"
864 "Backup Client: %s\n"
865 "Restore Client: %s\n"
870 "Plugin Options: %s\n"),
872 NPRT(jcr->RestoreBootstrap),
873 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere,
875 jcr->fileset->name(),
879 bstrutime(dt, sizeof(dt), jcr->sched_time),
880 jcr->catalog->name(),
882 NPRT(jcr->plugin_options));
885 ua->send_msg(_("Run Restore job\n"
891 "Backup Client: %s\n"
892 "Restore Client: %s\n"
897 "Plugin Options: %s\n"),
899 NPRT(jcr->RestoreBootstrap),
900 jcr->where?jcr->where:NPRT(job->RestoreWhere),
902 jcr->fileset->name(),
906 bstrutime(dt, sizeof(dt), jcr->sched_time),
907 jcr->catalog->name(),
909 NPRT(jcr->plugin_options));
913 if (ua->api) ua->signal(BNET_RUN_CMD);
914 ua->send_msg(_("Run Restore job\n"
918 NPRT(jcr->RestoreBootstrap));
920 /* RegexWhere is take before RestoreWhere */
921 if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) {
922 ua->send_msg(_("RegexWhere: %s\n"),
923 jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere);
925 ua->send_msg(_("Where: %s\n"),
926 jcr->where?jcr->where:NPRT(job->RestoreWhere));
929 ua->send_msg(_("Replace: %s\n"
936 "Plugin Options: %s\n"),
940 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
941 bstrutime(dt, sizeof(dt), jcr->sched_time),
942 jcr->catalog->name(),
944 NPRT(jcr->plugin_options));
950 if (jcr->getJobType() == JT_COPY) {
951 prt_type = _("Run Copy job\n");
953 prt_type = _("Run Migration job\n");
955 jcr->set_JobLevel(L_FULL); /* default level */
956 if (ua->api) ua->signal(BNET_RUN_CMD);
962 "Pool: %s (From %s)\n"
963 "Read Storage: %s (From %s)\n"
964 "Write Storage: %s (From %s)\n"
971 NPRT(jcr->RestoreBootstrap),
973 jcr->fileset->name(),
974 NPRT(jcr->pool->name()), jcr->pool_source,
975 jcr->rstore->name(), jcr->rstore_source,
976 jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
977 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
978 bstrutime(dt, sizeof(dt), jcr->sched_time),
979 jcr->catalog->name(),
983 ua->error_msg(_("Unknown Job Type=%d\n"), jcr->getJobType());
990 static bool scan_command_line_arguments(UAContext *ua, run_ctx &rc)
994 static const char *kw[] = { /* command line arguments */
995 "job", /* Used in a switch() */
1003 "regexwhere", /* 8 where string as a bregexp */
1005 "bootstrap", /* 10 */
1008 "priority", /* 13 */
1009 "yes", /* 14 -- if you change this change YES_POS too */
1010 "verifyjob", /* 15 */
1011 "files", /* 16 number of files to restore */
1012 "catalog", /* 17 override catalog */
1013 "since", /* 18 since */
1014 "cloned", /* 19 cloned */
1015 "verifylist", /* 20 verify output list */
1016 "migrationjob", /* 21 migration job name */
1018 "backupclient", /* 23 */
1019 "restoreclient", /* 24 */
1020 "pluginoptions", /* 25 */
1021 "spooldata", /* 26 */
1027 rc.catalog_name = NULL;
1029 rc.pool_name = NULL;
1030 rc.store_name = NULL;
1031 rc.client_name = NULL;
1032 rc.restore_client_name = NULL;
1033 rc.fileset_name = NULL;
1034 rc.verify_job_name = NULL;
1035 rc.previous_job_name = NULL;
1036 rc.spool_data_set = 0;
1039 for (i=1; i<ua->argc; i++) {
1040 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
1042 /* Keep looking until we find a good keyword */
1043 for (j=0; !kw_ok && kw[j]; j++) {
1044 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
1045 /* Note, yes and run have no value, so do not fail */
1046 if (!ua->argv[i] && j != YES_POS /*yes*/) {
1047 ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
1050 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
1054 ua->send_msg(_("Job name specified twice.\n"));
1057 rc.job_name = ua->argv[i];
1061 if (rc.jid && !rc.mod) {
1062 ua->send_msg(_("JobId specified twice.\n"));
1065 rc.jid = ua->argv[i];
1068 case 2: /* client */
1070 if (rc.client_name) {
1071 ua->send_msg(_("Client specified twice.\n"));
1074 rc.client_name = ua->argv[i];
1077 case 4: /* fileset */
1078 if (rc.fileset_name) {
1079 ua->send_msg(_("FileSet specified twice.\n"));
1082 rc.fileset_name = ua->argv[i];
1086 if (rc.level_name) {
1087 ua->send_msg(_("Level specified twice.\n"));
1090 rc.level_name = ua->argv[i];
1093 case 6: /* storage */
1095 if (rc.store_name) {
1096 ua->send_msg(_("Storage specified twice.\n"));
1099 rc.store_name = ua->argv[i];
1102 case 8: /* regexwhere */
1103 if ((rc.regexwhere || rc.where) && !rc.mod) {
1104 ua->send_msg(_("RegexWhere or Where specified twice.\n"));
1107 rc.regexwhere = ua->argv[i];
1108 if (!acl_access_ok(ua, Where_ACL, rc.regexwhere)) {
1109 ua->send_msg(_("No authorization for \"regexwhere\" specification.\n"));
1115 if ((rc.where || rc.regexwhere) && !rc.mod) {
1116 ua->send_msg(_("Where or RegexWhere specified twice.\n"));
1119 rc.where = ua->argv[i];
1120 if (!acl_access_ok(ua, Where_ACL, rc.where)) {
1121 ua->send_msg(_("No authoriztion for \"where\" specification.\n"));
1126 case 10: /* bootstrap */
1127 if (rc.bootstrap && !rc.mod) {
1128 ua->send_msg(_("Bootstrap specified twice.\n"));
1131 rc.bootstrap = ua->argv[i];
1134 case 11: /* replace */
1135 if (rc.replace && !rc.mod) {
1136 ua->send_msg(_("Replace specified twice.\n"));
1139 rc.replace = ua->argv[i];
1143 if (rc.when && !rc.mod) {
1144 ua->send_msg(_("When specified twice.\n"));
1147 rc.when = ua->argv[i];
1150 case 13: /* Priority */
1151 if (rc.Priority && !rc.mod) {
1152 ua->send_msg(_("Priority specified twice.\n"));
1155 rc.Priority = atoi(ua->argv[i]);
1156 if (rc.Priority <= 0) {
1157 ua->send_msg(_("Priority must be positive nonzero setting it to 10.\n"));
1165 case 15: /* Verify Job */
1166 if (rc.verify_job_name) {
1167 ua->send_msg(_("Verify Job specified twice.\n"));
1170 rc.verify_job_name = ua->argv[i];
1173 case 16: /* files */
1174 rc.files = atoi(ua->argv[i]);
1178 case 17: /* catalog */
1179 rc.catalog_name = ua->argv[i];
1183 case 18: /* since */
1184 rc.since = ua->argv[i];
1188 case 19: /* cloned */
1193 case 20: /* write verify list output */
1194 rc.verify_list = ua->argv[i];
1197 case 21: /* Migration Job */
1198 if (rc.previous_job_name) {
1199 ua->send_msg(_("Migration Job specified twice.\n"));
1202 rc.previous_job_name = ua->argv[i];
1207 ua->send_msg(_("Pool specified twice.\n"));
1210 rc.pool_name = ua->argv[i];
1213 case 23: /* backupclient */
1214 if (rc.client_name) {
1215 ua->send_msg(_("Client specified twice.\n"));
1218 rc.client_name = ua->argv[i];
1221 case 24: /* restoreclient */
1222 if (rc.restore_client_name && !rc.mod) {
1223 ua->send_msg(_("Restore Client specified twice.\n"));
1226 rc.restore_client_name = ua->argv[i];
1229 case 25: /* pluginoptions */
1230 ua->send_msg(_("Plugin Options not yet implemented.\n"));
1232 if (rc.plugin_options) {
1233 ua->send_msg(_("Plugin Options specified twice.\n"));
1236 rc.plugin_options = ua->argv[i];
1237 if (!acl_access_ok(ua, PluginOptions_ACL, rc.plugin_options)) {
1238 ua->send_msg(_("No authoriztion for \"PluginOptions\" specification.\n"));
1243 case 26: /* spooldata */
1244 if (rc.spool_data_set) {
1245 ua->send_msg(_("Spool flag specified twice.\n"));
1248 if (is_yesno(ua->argv[i], &rc.spool_data)) {
1249 rc.spool_data_set = 1;
1252 ua->send_msg(_("Invalid spooldata flag.\n"));
1255 case 27: /* comment */
1256 rc.comment = ua->argv[i];
1261 } /* end strcase compare */
1262 } /* end keyword loop */
1264 * End of keyword for loop -- if not found, we got a bogus keyword
1267 Dmsg1(800, "%s not found\n", ua->argk[i]);
1269 * Special case for Job Name, it can be the first
1270 * keyword that has no value.
1272 if (!rc.job_name && !ua->argv[i]) {
1273 rc.job_name = ua->argk[i]; /* use keyword as job name */
1274 Dmsg1(800, "Set jobname=%s\n", rc.job_name);
1276 ua->send_msg(_("Invalid keyword: %s\n"), ua->argk[i]);
1280 } /* end argc loop */
1282 Dmsg0(800, "Done scan.\n");
1284 if (!is_comment_legal(ua, rc.comment)) {
1288 if (rc.catalog_name) {
1289 rc.catalog = GetCatalogResWithName(rc.catalog_name);
1290 if (rc.catalog == NULL) {
1291 ua->error_msg(_("Catalog \"%s\" not found\n"), rc.catalog_name);
1294 if (!acl_access_ok(ua, Catalog_ACL, rc.catalog->name())) {
1295 ua->error_msg(_("No authorization. Catalog \"%s\".\n"), rc.catalog->name());
1299 Dmsg1(800, "Using catalog=%s\n", NPRT(rc.catalog_name));
1303 rc.job = GetJobResWithName(rc.job_name);
1305 if (*rc.job_name != 0) {
1306 ua->send_msg(_("Job \"%s\" not found\n"), rc.job_name);
1308 rc.job = select_job_resource(ua);
1310 Dmsg1(800, "Found job=%s\n", rc.job_name);
1312 } else if (!rc.job) {
1313 ua->send_msg(_("A job name must be specified.\n"));
1314 rc.job = select_job_resource(ua);
1318 } else if (!acl_access_ok(ua, Job_ACL, rc.job->name())) {
1319 ua->error_msg( _("No authorization. Job \"%s\".\n"), rc.job->name());
1324 rc.pool = GetPoolResWithName(rc.pool_name);
1326 if (*rc.pool_name != 0) {
1327 ua->warning_msg(_("Pool \"%s\" not found.\n"), rc.pool_name);
1329 rc.pool = select_pool_resource(ua);
1331 } else if (!rc.pool) {
1332 rc.pool = rc.job->pool; /* use default */
1336 } else if (!acl_access_ok(ua, Pool_ACL, rc.pool->name())) {
1337 ua->error_msg(_("No authorization. Pool \"%s\".\n"), rc.pool->name());
1340 Dmsg1(100, "Using pool %s\n", rc.pool->name());
1342 if (rc.spool_data_set) {
1343 rc.job->spool_data = rc.spool_data;
1345 Dmsg1(900, "Spooling data: %s\n", (rc.job->spool_data ? "Yes" : "No"));
1347 if (rc.store_name) {
1348 rc.store->store = GetStoreResWithName(rc.store_name);
1349 pm_strcpy(rc.store->store_source, _("command line"));
1350 if (!rc.store->store) {
1351 if (*rc.store_name != 0) {
1352 ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
1354 rc.store->store = select_storage_resource(ua);
1355 pm_strcpy(rc.store->store_source, _("user selection"));
1357 } else if (!rc.store->store) {
1358 get_job_storage(rc.store, rc.job, NULL); /* use default */
1360 if (!rc.store->store) {
1361 ua->error_msg(_("No storage specified.\n"));
1363 } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
1364 ua->error_msg(_("No authorization. Storage \"%s\".\n"),
1365 rc.store->store->name());
1368 Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
1370 if (rc.client_name) {
1371 rc.client = GetClientResWithName(rc.client_name);
1373 if (*rc.client_name != 0) {
1374 ua->warning_msg(_("Client \"%s\" not found.\n"), rc.client_name);
1376 rc.client = select_client_resource(ua);
1378 } else if (!rc.client) {
1379 rc.client = rc.job->client; /* use default */
1383 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1384 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1388 Dmsg1(800, "Using client=%s\n", rc.client->name());
1390 if (rc.restore_client_name) {
1391 rc.client = GetClientResWithName(rc.restore_client_name);
1393 if (*rc.restore_client_name != 0) {
1394 ua->warning_msg(_("Restore Client \"%s\" not found.\n"), rc.restore_client_name);
1396 rc.client = select_client_resource(ua);
1398 } else if (!rc.client) {
1399 rc.client = rc.job->client; /* use default */
1403 } else if (!acl_access_ok(ua, Client_ACL, rc.client->name())) {
1404 ua->error_msg(_("No authorization. Client \"%s\".\n"),
1408 Dmsg1(800, "Using restore client=%s\n", rc.client->name());
1411 if (rc.fileset_name) {
1412 rc.fileset = GetFileSetResWithName(rc.fileset_name);
1414 ua->send_msg(_("FileSet \"%s\" not found.\n"), rc.fileset_name);
1415 rc.fileset = select_fileset_resource(ua);
1417 } else if (!rc.fileset) {
1418 rc.fileset = rc.job->fileset; /* use default */
1422 } else if (!acl_access_ok(ua, FileSet_ACL, rc.fileset->name())) {
1423 ua->send_msg(_("No authorization. FileSet \"%s\".\n"),
1424 rc.fileset->name());
1428 if (rc.verify_job_name) {
1429 rc.verify_job = GetJobResWithName(rc.verify_job_name);
1430 if (!rc.verify_job) {
1431 ua->send_msg(_("Verify Job \"%s\" not found.\n"), rc.verify_job_name);
1432 rc.verify_job = select_job_resource(ua);
1434 } else if (!rc.verify_job) {
1435 rc.verify_job = rc.job->verify_job;
1438 if (rc.previous_job_name) {
1439 rc.previous_job = GetJobResWithName(rc.previous_job_name);
1440 if (!rc.previous_job) {
1441 ua->send_msg(_("Migration Job \"%s\" not found.\n"), rc.previous_job_name);
1442 rc.previous_job = select_job_resource(ua);
1445 rc.previous_job = rc.job->verify_job;