3 * Bacula Director -- Run Command
5 * Kern Sibbald, December MMI
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 /* Imported subroutines */
42 /* Imported variables */
43 extern struct s_kw ReplaceOptions[];
46 * For Backup and Verify Jobs
47 * run [job=]<job-name> level=<level-name>
56 int run_cmd(UAContext *ua, const char *cmd)
59 char *job_name, *level_name, *jid, *store_name, *pool_name;
60 char *where, *fileset_name, *client_name, *bootstrap;
62 char *when, *verify_job_name, *catalog_name;
63 char *previous_job_name;
68 int i, j, opt, files = 0;
71 JOB *verify_job = NULL;
72 JOB *previous_job = NULL;
74 CLIENT *client = NULL;
75 FILESET *fileset = NULL;
77 static const char *kw[] = { /* command line arguments */
78 "job", /* Used in a switch() */
92 "yes", /* 14 -- if you change this change YES_POS too */
94 "files", /* 16 number of files to restore */
95 "catalog", /* 17 override catalog */
96 "since", /* 18 since */
97 "cloned", /* 19 cloned */
98 "verifylist", /* 20 verify output list */
99 "migrationjob", /* 21 migration job name */
119 verify_job_name = NULL;
120 previous_job_name = NULL;
124 for (i=1; i<ua->argc; i++) {
125 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
127 /* Keep looking until we find a good keyword */
128 for (j=0; !kw_ok && kw[j]; j++) {
129 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
130 /* Note, yes and run have no value, so do not fail */
131 if (!ua->argv[i] && j != YES_POS /*yes*/) {
132 bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
135 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
139 bsendmsg(ua, _("Job name specified twice.\n"));
142 job_name = ua->argv[i];
147 bsendmsg(ua, _("JobId specified twice.\n"));
156 bsendmsg(ua, _("Client specified twice.\n"));
159 client_name = ua->argv[i];
162 case 4: /* fileset */
164 bsendmsg(ua, _("FileSet specified twice.\n"));
167 fileset_name = ua->argv[i];
172 bsendmsg(ua, _("Level specified twice.\n"));
175 level_name = ua->argv[i];
178 case 6: /* storage */
181 bsendmsg(ua, _("Storage specified twice.\n"));
184 store_name = ua->argv[i];
189 bsendmsg(ua, _("Pool specified twice.\n"));
192 pool_name = ua->argv[i];
197 bsendmsg(ua, _("Where specified twice.\n"));
201 if (!acl_access_ok(ua, Where_ACL, where)) {
202 bsendmsg(ua, _("Forbidden \"where\" specified.\n"));
207 case 10: /* bootstrap */
209 bsendmsg(ua, _("Bootstrap specified twice.\n"));
212 bootstrap = ua->argv[i];
215 case 11: /* replace */
217 bsendmsg(ua, _("Replace specified twice.\n"));
220 replace = ua->argv[i];
225 bsendmsg(ua, _("When specified twice.\n"));
231 case 13: /* Priority */
233 bsendmsg(ua, _("Priority specified twice.\n"));
236 Priority = atoi(ua->argv[i]);
238 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
246 case 15: /* Verify Job */
247 if (verify_job_name) {
248 bsendmsg(ua, _("Verify Job specified twice.\n"));
251 verify_job_name = ua->argv[i];
255 files = atoi(ua->argv[i]);
259 case 17: /* catalog */
260 catalog_name = ua->argv[i];
269 case 19: /* cloned */
274 case 20: /* write verify list output */
275 verify_list = ua->argv[i];
278 case 21: /* Migration Job */
279 if (previous_job_name) {
280 bsendmsg(ua, _("Migration Job specified twice.\n"));
283 previous_job_name = ua->argv[i];
291 } /* end strcase compare */
292 } /* end keyword loop */
294 * End of keyword for loop -- if not found, we got a bogus keyword
297 Dmsg1(800, "%s not found\n", ua->argk[i]);
299 * Special case for Job Name, it can be the first
300 * keyword that has no value.
302 if (!job_name && !ua->argv[i]) {
303 job_name = ua->argk[i]; /* use keyword as job name */
304 Dmsg1(800, "Set jobname=%s\n", job_name);
306 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
310 } /* end argc loop */
312 Dmsg0(800, "Done scan.\n");
315 if (catalog_name != NULL) {
316 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
317 if (catalog == NULL) {
318 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
322 Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
326 job = (JOB *)GetResWithName(R_JOB, job_name);
328 if (*job_name != 0) {
329 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
331 job = select_job_resource(ua);
333 Dmsg1(800, "Found job=%s\n", job_name);
336 bsendmsg(ua, _("A job name must be specified.\n"));
337 job = select_job_resource(ua);
341 } else if (!acl_access_ok(ua, Job_ACL, job->name())) {
342 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
348 store.store = (STORE *)GetResWithName(R_STORAGE, store_name);
349 pm_strcpy(store.store_source, _("command line"));
351 if (*store_name != 0) {
352 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
354 store.store = select_storage_resource(ua);
355 pm_strcpy(store.store_source, _("user selection"));
358 get_job_storage(&store, job, NULL); /* use default */
362 } else if (!acl_access_ok(ua, Storage_ACL, store.store->name())) {
363 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
364 store.store->name());
367 Dmsg1(800, "Using storage=%s\n", store.store->name());
370 pool = (POOL *)GetResWithName(R_POOL, pool_name);
372 if (*pool_name != 0) {
373 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
375 pool = select_pool_resource(ua);
378 pool = job->pool; /* use default */
382 } else if (!acl_access_ok(ua, Pool_ACL, pool->name())) {
383 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
387 Dmsg1(800, "Using pool\n", pool->name());
390 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
392 if (*client_name != 0) {
393 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
395 client = select_client_resource(ua);
398 client = job->client; /* use default */
402 } else if (!acl_access_ok(ua, Client_ACL, client->name())) {
403 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
407 Dmsg1(800, "Using client=%s\n", client->name());
410 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
412 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
413 fileset = select_fileset_resource(ua);
416 fileset = job->fileset; /* use default */
420 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
421 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
426 if (verify_job_name) {
427 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
429 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
430 verify_job = select_job_resource(ua);
433 verify_job = job->verify_job;
436 if (previous_job_name) {
437 previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
439 bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
440 previous_job = select_job_resource(ua);
443 previous_job = job->verify_job;
448 * Create JCR to run job. NOTE!!! after this point, free_jcr()
451 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
452 set_jcr_defaults(jcr, job);
454 jcr->verify_job = verify_job;
455 jcr->previous_job = previous_job;
456 set_rwstorage(jcr, &store);
457 jcr->client = client;
458 jcr->fileset = fileset;
460 jcr->ExpectedFiles = files;
461 if (catalog != NULL) {
462 jcr->catalog = catalog;
468 jcr->where = bstrdup(where);
472 jcr->sched_time = str_to_utime(when);
473 if (jcr->sched_time == 0) {
474 bsendmsg(ua, _("Invalid time, using current time.\n"));
475 jcr->sched_time = time(NULL);
480 if (jcr->RestoreBootstrap) {
481 free(jcr->RestoreBootstrap);
483 jcr->RestoreBootstrap = bstrdup(bootstrap);
488 for (i=0; ReplaceOptions[i].name; i++) {
489 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
490 jcr->replace = ReplaceOptions[i].token;
494 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
497 } else if (job->replace) {
498 jcr->replace = job->replace;
500 jcr->replace = REPLACE_ALWAYS;
504 jcr->JobPriority = Priority;
509 jcr->stime = get_pool_memory(PM_MESSAGE);
511 pm_strcpy(jcr->stime, since);
514 jcr->cloned = cloned;
516 if (find_arg(ua, NT_("fdcalled")) > 0) {
517 jcr->file_bsock = dup_bsock(ua->UA_sock);
522 replace = ReplaceOptions[0].name;
523 for (i=0; ReplaceOptions[i].name; i++) {
524 if (ReplaceOptions[i].token == jcr->replace) {
525 replace = ReplaceOptions[i].name;
529 if (!get_level_from_name(jcr, level_name)) {
530 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
535 /* Note, this is also MigrateJobId */
536 jcr->RestoreJobId = str_to_int64(jid);
539 /* Run without prompting? */
540 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
545 * Prompt User to see if all run job parameters are correct, and
546 * allow him to modify them.
548 Dmsg1(800, "JobType=%c\n", jcr->JobType);
549 switch (jcr->JobType) {
551 char dt[MAX_TIME_LENGTH];
553 bsendmsg(ua, _("Run %s job\n"
562 jcr->fileset->name(),
563 NPRT(jcr->client->name()),
564 NPRT(jcr->wstore->name()),
565 bstrutime(dt, sizeof(dt), jcr->sched_time),
567 jcr->JobLevel = L_FULL;
571 if (jcr->JobType == JT_BACKUP) {
572 bsendmsg(ua, _("Run %s job\n"
583 jcr->fileset->name(),
584 level_to_str(jcr->JobLevel),
587 NPRT(jcr->pool->name()),
588 bstrutime(dt, sizeof(dt), jcr->sched_time),
590 } else { /* JT_VERIFY */
592 if (jcr->verify_job) {
593 Name = jcr->verify_job->name();
598 verify_list = job->WriteVerifyList;
603 bsendmsg(ua, _("Run %s job\n"
616 jcr->fileset->name(),
617 level_to_str(jcr->JobLevel),
620 NPRT(jcr->pool->name()),
623 bstrutime(dt, sizeof(dt), jcr->sched_time),
628 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
630 jcr->RestoreJobId = str_to_int64(jid);
632 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
635 jcr->RestoreJobId = ua->int64_val;
638 jcr->JobLevel = L_FULL; /* default level */
639 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
640 if (jcr->RestoreJobId == 0) {
641 bsendmsg(ua, _("Run Restore job\n"
653 NPRT(jcr->RestoreBootstrap),
654 jcr->where?jcr->where:NPRT(job->RestoreWhere),
656 jcr->fileset->name(),
659 bstrutime(dt, sizeof(dt), jcr->sched_time),
660 jcr->catalog->name(),
663 bsendmsg(ua, _("Run Restore job\n"
675 NPRT(jcr->RestoreBootstrap),
676 jcr->where?jcr->where:NPRT(job->RestoreWhere),
680 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
681 bstrutime(dt, sizeof(dt), jcr->sched_time),
682 jcr->catalog->name(),
687 jcr->JobLevel = L_FULL; /* default level */
688 bsendmsg(ua, _("Run Migration job\n"
699 NPRT(jcr->RestoreBootstrap),
700 jcr->fileset->name(),
703 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
704 bstrutime(dt, sizeof(dt), jcr->sched_time),
705 jcr->catalog->name(),
709 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
713 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
717 * At user request modify parameters of job to be run.
719 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
722 start_prompt(ua, _("Parameters to modify:\n"));
723 add_prompt(ua, _("Level")); /* 0 */
724 add_prompt(ua, _("Storage")); /* 1 */
725 add_prompt(ua, _("Job")); /* 2 */
726 add_prompt(ua, _("FileSet")); /* 3 */
727 add_prompt(ua, _("Client")); /* 4 */
728 add_prompt(ua, _("When")); /* 5 */
729 add_prompt(ua, _("Priority")); /* 6 */
730 if (jcr->JobType == JT_BACKUP ||
731 jcr->JobType == JT_VERIFY) {
732 add_prompt(ua, _("Pool")); /* 7 */
733 if (jcr->JobType == JT_VERIFY) {
734 add_prompt(ua, _("Verify Job")); /* 8 */
736 } else if (jcr->JobType == JT_RESTORE) {
737 add_prompt(ua, _("Bootstrap")); /* 7 */
738 add_prompt(ua, _("Where")); /* 8 */
739 add_prompt(ua, _("Replace")); /* 9 */
740 add_prompt(ua, _("JobId")); /* 10 */
742 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
745 if (jcr->JobType == JT_BACKUP) {
746 start_prompt(ua, _("Levels:\n"));
747 add_prompt(ua, _("Base"));
748 add_prompt(ua, _("Full"));
749 add_prompt(ua, _("Incremental"));
750 add_prompt(ua, _("Differential"));
751 add_prompt(ua, _("Since"));
752 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
754 jcr->JobLevel = L_BASE;
757 jcr->JobLevel = L_FULL;
760 jcr->JobLevel = L_INCREMENTAL;
763 jcr->JobLevel = L_DIFFERENTIAL;
766 jcr->JobLevel = L_SINCE;
772 } else if (jcr->JobType == JT_VERIFY) {
773 start_prompt(ua, _("Levels:\n"));
774 add_prompt(ua, _("Initialize Catalog"));
775 add_prompt(ua, _("Verify Catalog"));
776 add_prompt(ua, _("Verify Volume to Catalog"));
777 add_prompt(ua, _("Verify Disk to Catalog"));
778 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
779 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
781 jcr->JobLevel = L_VERIFY_INIT;
784 jcr->JobLevel = L_VERIFY_CATALOG;
787 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
790 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
793 jcr->JobLevel = L_VERIFY_DATA;
800 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
805 store.store = select_storage_resource(ua);
807 pm_strcpy(store.store_source, _("user selection"));
808 set_rwstorage(jcr, &store);
814 job = select_job_resource(ua);
817 set_jcr_defaults(jcr, job);
823 fileset = select_fileset_resource(ua);
825 jcr->fileset = fileset;
831 client = select_client_resource(ua);
833 jcr->client = client;
839 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
842 if (ua->cmd[0] == 0) {
843 jcr->sched_time = time(NULL);
845 jcr->sched_time = str_to_utime(ua->cmd);
846 if (jcr->sched_time == 0) {
847 bsendmsg(ua, _("Invalid time, using current time.\n"));
848 jcr->sched_time = time(NULL);
854 if (!get_pint(ua, _("Enter new Priority: "))) {
857 if (ua->pint32_val == 0) {
858 bsendmsg(ua, _("Priority must be a positive integer.\n"));
860 jcr->JobPriority = ua->pint32_val;
864 /* Pool or Bootstrap depending on JobType */
865 if (jcr->JobType == JT_BACKUP ||
866 jcr->JobType == JT_VERIFY) { /* Pool */
867 pool = select_pool_resource(ua);
876 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
879 if (jcr->RestoreBootstrap) {
880 free(jcr->RestoreBootstrap);
881 jcr->RestoreBootstrap = NULL;
883 if (ua->cmd[0] != 0) {
884 jcr->RestoreBootstrap = bstrdup(ua->cmd);
885 fd = fopen(jcr->RestoreBootstrap, "rb");
887 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
888 jcr->RestoreBootstrap, strerror(errno));
889 free(jcr->RestoreBootstrap);
890 jcr->RestoreBootstrap = NULL;
898 if (jcr->JobType == JT_VERIFY) {
899 verify_job = select_job_resource(ua);
901 jcr->verify_job = verify_job;
906 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
913 if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') {
916 jcr->where = bstrdup(ua->cmd);
920 start_prompt(ua, _("Replace:\n"));
921 for (i=0; ReplaceOptions[i].name; i++) {
922 add_prompt(ua, ReplaceOptions[i].name);
924 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
926 jcr->replace = ReplaceOptions[opt].token;
931 jid = NULL; /* force reprompt */
932 jcr->RestoreJobId = 0;
933 if (jcr->RestoreBootstrap) {
934 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
937 case -1: /* error or cancel */
945 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
947 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
949 JobId = run_job(jcr);
951 bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
952 "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
953 time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
954 jcr->Job, jcr->JobLevel, jcr->JobPriority);
956 free_jcr(jcr); /* release jcr */
958 bsendmsg(ua, _("Job failed.\n"));
961 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
967 bsendmsg(ua, _("Job not run.\n"));
969 return 0; /* do not run */