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 *)GetResWithName(R_STORAGE, store_name);
350 if (*store_name != 0) {
351 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
353 store = select_storage_resource(ua);
355 } else if (job->storage) {
356 store = (STORE *)job->storage->first(); /* use default */
360 } else if (!acl_access_ok(ua, Storage_ACL, store->name())) {
361 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
365 Dmsg1(800, "Using storage=%s\n", store->name());
368 pool = (POOL *)GetResWithName(R_POOL, pool_name);
370 if (*pool_name != 0) {
371 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
373 pool = select_pool_resource(ua);
376 pool = job->pool; /* use default */
380 } else if (!acl_access_ok(ua, Pool_ACL, pool->name())) {
381 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
385 Dmsg1(800, "Using pool\n", pool->name());
388 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
390 if (*client_name != 0) {
391 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
393 client = select_client_resource(ua);
396 client = job->client; /* use default */
400 } else if (!acl_access_ok(ua, Client_ACL, client->name())) {
401 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
405 Dmsg1(800, "Using client=%s\n", client->name());
408 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
410 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
411 fileset = select_fileset_resource(ua);
414 fileset = job->fileset; /* use default */
418 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
419 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
424 if (verify_job_name) {
425 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
427 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
428 verify_job = select_job_resource(ua);
431 verify_job = job->verify_job;
434 if (previous_job_name) {
435 previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
437 bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
438 previous_job = select_job_resource(ua);
441 previous_job = job->verify_job;
446 * Create JCR to run job. NOTE!!! after this point, free_jcr()
449 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
450 set_jcr_defaults(jcr, job);
452 jcr->verify_job = verify_job;
453 jcr->previous_job = previous_job;
454 set_rwstorage(jcr, store);
455 jcr->client = client;
456 jcr->fileset = fileset;
458 jcr->ExpectedFiles = files;
459 if (catalog != NULL) {
460 jcr->catalog = catalog;
466 jcr->where = bstrdup(where);
470 jcr->sched_time = str_to_utime(when);
471 if (jcr->sched_time == 0) {
472 bsendmsg(ua, _("Invalid time, using current time.\n"));
473 jcr->sched_time = time(NULL);
478 if (jcr->RestoreBootstrap) {
479 free(jcr->RestoreBootstrap);
481 jcr->RestoreBootstrap = bstrdup(bootstrap);
486 for (i=0; ReplaceOptions[i].name; i++) {
487 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
488 jcr->replace = ReplaceOptions[i].token;
492 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
495 } else if (job->replace) {
496 jcr->replace = job->replace;
498 jcr->replace = REPLACE_ALWAYS;
502 jcr->JobPriority = Priority;
507 jcr->stime = get_pool_memory(PM_MESSAGE);
509 pm_strcpy(jcr->stime, since);
512 jcr->cloned = cloned;
514 if (find_arg(ua, NT_("fdcalled")) > 0) {
515 jcr->file_bsock = dup_bsock(ua->UA_sock);
520 replace = ReplaceOptions[0].name;
521 for (i=0; ReplaceOptions[i].name; i++) {
522 if (ReplaceOptions[i].token == jcr->replace) {
523 replace = ReplaceOptions[i].name;
527 if (!get_level_from_name(jcr, level_name)) {
528 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
533 /* Note, this is also MigrateJobId */
534 jcr->RestoreJobId = str_to_int64(jid);
537 /* Run without prompting? */
538 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
543 * Prompt User to see if all run job parameters are correct, and
544 * allow him to modify them.
546 Dmsg1(800, "JobType=%c\n", jcr->JobType);
547 switch (jcr->JobType) {
549 char dt[MAX_TIME_LENGTH];
551 bsendmsg(ua, _("Run %s job\n"
560 jcr->fileset->name(),
561 NPRT(jcr->client->name()),
562 NPRT(jcr->wstore->name()),
563 bstrutime(dt, sizeof(dt), jcr->sched_time),
565 jcr->JobLevel = L_FULL;
569 if (jcr->JobType == JT_BACKUP) {
570 bsendmsg(ua, _("Run %s job\n"
581 jcr->fileset->name(),
582 level_to_str(jcr->JobLevel),
585 NPRT(jcr->pool->name()),
586 bstrutime(dt, sizeof(dt), jcr->sched_time),
588 } else { /* JT_VERIFY */
590 if (jcr->verify_job) {
591 Name = jcr->verify_job->name();
596 verify_list = job->WriteVerifyList;
601 bsendmsg(ua, _("Run %s job\n"
614 jcr->fileset->name(),
615 level_to_str(jcr->JobLevel),
618 NPRT(jcr->pool->name()),
621 bstrutime(dt, sizeof(dt), jcr->sched_time),
626 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
628 jcr->RestoreJobId = str_to_int64(jid);
630 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
633 jcr->RestoreJobId = ua->int64_val;
636 jcr->JobLevel = L_FULL; /* default level */
637 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
638 if (jcr->RestoreJobId == 0) {
639 bsendmsg(ua, _("Run Restore job\n"
651 NPRT(jcr->RestoreBootstrap),
652 jcr->where?jcr->where:NPRT(job->RestoreWhere),
654 jcr->fileset->name(),
657 bstrutime(dt, sizeof(dt), jcr->sched_time),
658 jcr->catalog->name(),
661 bsendmsg(ua, _("Run Restore job\n"
673 NPRT(jcr->RestoreBootstrap),
674 jcr->where?jcr->where:NPRT(job->RestoreWhere),
678 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
679 bstrutime(dt, sizeof(dt), jcr->sched_time),
680 jcr->catalog->name(),
685 jcr->JobLevel = L_FULL; /* default level */
686 bsendmsg(ua, _("Run Migration job\n"
697 NPRT(jcr->RestoreBootstrap),
698 jcr->fileset->name(),
701 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
702 bstrutime(dt, sizeof(dt), jcr->sched_time),
703 jcr->catalog->name(),
707 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
711 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
715 * At user request modify parameters of job to be run.
717 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
720 start_prompt(ua, _("Parameters to modify:\n"));
721 add_prompt(ua, _("Level")); /* 0 */
722 add_prompt(ua, _("Storage")); /* 1 */
723 add_prompt(ua, _("Job")); /* 2 */
724 add_prompt(ua, _("FileSet")); /* 3 */
725 add_prompt(ua, _("Client")); /* 4 */
726 add_prompt(ua, _("When")); /* 5 */
727 add_prompt(ua, _("Priority")); /* 6 */
728 if (jcr->JobType == JT_BACKUP ||
729 jcr->JobType == JT_VERIFY) {
730 add_prompt(ua, _("Pool")); /* 7 */
731 if (jcr->JobType == JT_VERIFY) {
732 add_prompt(ua, _("Verify Job")); /* 8 */
734 } else if (jcr->JobType == JT_RESTORE) {
735 add_prompt(ua, _("Bootstrap")); /* 7 */
736 add_prompt(ua, _("Where")); /* 8 */
737 add_prompt(ua, _("Replace")); /* 9 */
738 add_prompt(ua, _("JobId")); /* 10 */
740 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
743 if (jcr->JobType == JT_BACKUP) {
744 start_prompt(ua, _("Levels:\n"));
745 add_prompt(ua, _("Base"));
746 add_prompt(ua, _("Full"));
747 add_prompt(ua, _("Incremental"));
748 add_prompt(ua, _("Differential"));
749 add_prompt(ua, _("Since"));
750 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
752 jcr->JobLevel = L_BASE;
755 jcr->JobLevel = L_FULL;
758 jcr->JobLevel = L_INCREMENTAL;
761 jcr->JobLevel = L_DIFFERENTIAL;
764 jcr->JobLevel = L_SINCE;
770 } else if (jcr->JobType == JT_VERIFY) {
771 start_prompt(ua, _("Levels:\n"));
772 add_prompt(ua, _("Initialize Catalog"));
773 add_prompt(ua, _("Verify Catalog"));
774 add_prompt(ua, _("Verify Volume to Catalog"));
775 add_prompt(ua, _("Verify Disk to Catalog"));
776 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
777 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
779 jcr->JobLevel = L_VERIFY_INIT;
782 jcr->JobLevel = L_VERIFY_CATALOG;
785 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
788 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
791 jcr->JobLevel = L_VERIFY_DATA;
798 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
803 store = select_storage_resource(ua);
805 set_rwstorage(jcr, store);
811 job = select_job_resource(ua);
814 set_jcr_defaults(jcr, job);
820 fileset = select_fileset_resource(ua);
822 jcr->fileset = fileset;
828 client = select_client_resource(ua);
830 jcr->client = client;
836 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
839 if (ua->cmd[0] == 0) {
840 jcr->sched_time = time(NULL);
842 jcr->sched_time = str_to_utime(ua->cmd);
843 if (jcr->sched_time == 0) {
844 bsendmsg(ua, _("Invalid time, using current time.\n"));
845 jcr->sched_time = time(NULL);
851 if (!get_pint(ua, _("Enter new Priority: "))) {
854 if (ua->pint32_val == 0) {
855 bsendmsg(ua, _("Priority must be a positive integer.\n"));
857 jcr->JobPriority = ua->pint32_val;
861 /* Pool or Bootstrap depending on JobType */
862 if (jcr->JobType == JT_BACKUP ||
863 jcr->JobType == JT_VERIFY) { /* Pool */
864 pool = select_pool_resource(ua);
873 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
876 if (jcr->RestoreBootstrap) {
877 free(jcr->RestoreBootstrap);
878 jcr->RestoreBootstrap = NULL;
880 if (ua->cmd[0] != 0) {
881 jcr->RestoreBootstrap = bstrdup(ua->cmd);
882 fd = fopen(jcr->RestoreBootstrap, "rb");
884 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
885 jcr->RestoreBootstrap, strerror(errno));
886 free(jcr->RestoreBootstrap);
887 jcr->RestoreBootstrap = NULL;
895 if (jcr->JobType == JT_VERIFY) {
896 verify_job = select_job_resource(ua);
898 jcr->verify_job = verify_job;
903 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
910 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
913 jcr->where = bstrdup(ua->cmd);
917 start_prompt(ua, _("Replace:\n"));
918 for (i=0; ReplaceOptions[i].name; i++) {
919 add_prompt(ua, ReplaceOptions[i].name);
921 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
923 jcr->replace = ReplaceOptions[opt].token;
928 jid = NULL; /* force reprompt */
929 jcr->RestoreJobId = 0;
930 if (jcr->RestoreBootstrap) {
931 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
934 case -1: /* error or cancel */
942 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
944 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
946 JobId = run_job(jcr);
948 bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
949 "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
950 time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
951 jcr->Job, jcr->JobLevel, jcr->JobPriority);
953 free_jcr(jcr); /* release jcr */
955 bsendmsg(ua, _("Job failed.\n"));
958 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
964 bsendmsg(ua, _("Job not run.\n"));
966 return 0; /* do not run */