3 * Bacula Director -- Run Command
5 * Kern Sibbald, December MMI
10 Copyright (C) 2001-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
27 /* Imported subroutines */
29 /* Imported variables */
30 extern struct s_kw ReplaceOptions[];
33 * For Backup and Verify Jobs
34 * run [job=]<job-name> level=<level-name>
43 int run_cmd(UAContext *ua, const char *cmd)
46 char *job_name, *level_name, *jid, *store_name, *pool_name;
47 char *where, *fileset_name, *client_name, *bootstrap;
49 char *when, *verify_job_name, *catalog_name;
50 char *previous_job_name;
55 int i, j, opt, files = 0;
58 JOB *verify_job = NULL;
59 JOB *previous_job = NULL;
61 CLIENT *client = NULL;
62 FILESET *fileset = NULL;
64 static const char *kw[] = { /* command line arguments */
65 "job", /* Used in a switch() */
79 "yes", /* 14 -- if you change this change YES_POS too */
81 "files", /* 16 number of files to restore */
82 "catalog", /* 17 override catalog */
83 "since", /* 18 since */
84 "cloned", /* 19 cloned */
85 "verifylist", /* 20 verify output list */
86 "migrationjob", /* 21 migration job name */
106 verify_job_name = NULL;
107 previous_job_name = NULL;
111 for (i=1; i<ua->argc; i++) {
112 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
114 /* Keep looking until we find a good keyword */
115 for (j=0; !kw_ok && kw[j]; j++) {
116 if (strcasecmp(ua->argk[i], kw[j]) == 0) {
117 /* Note, yes and run have no value, so do not fail */
118 if (!ua->argv[i] && j != YES_POS /*yes*/) {
119 bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
122 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
126 bsendmsg(ua, _("Job name specified twice.\n"));
129 job_name = ua->argv[i];
134 bsendmsg(ua, _("JobId specified twice.\n"));
143 bsendmsg(ua, _("Client specified twice.\n"));
146 client_name = ua->argv[i];
149 case 4: /* fileset */
151 bsendmsg(ua, _("FileSet specified twice.\n"));
154 fileset_name = ua->argv[i];
159 bsendmsg(ua, _("Level specified twice.\n"));
162 level_name = ua->argv[i];
165 case 6: /* storage */
168 bsendmsg(ua, _("Storage specified twice.\n"));
171 store_name = ua->argv[i];
176 bsendmsg(ua, _("Pool specified twice.\n"));
179 pool_name = ua->argv[i];
184 bsendmsg(ua, _("Where specified twice.\n"));
190 case 10: /* bootstrap */
192 bsendmsg(ua, _("Bootstrap specified twice.\n"));
195 bootstrap = ua->argv[i];
198 case 11: /* replace */
200 bsendmsg(ua, _("Replace specified twice.\n"));
203 replace = ua->argv[i];
208 bsendmsg(ua, _("When specified twice.\n"));
214 case 13: /* Priority */
216 bsendmsg(ua, _("Priority specified twice.\n"));
219 Priority = atoi(ua->argv[i]);
221 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
229 case 15: /* Verify Job */
230 if (verify_job_name) {
231 bsendmsg(ua, _("Verify Job specified twice.\n"));
234 verify_job_name = ua->argv[i];
238 files = atoi(ua->argv[i]);
242 case 17: /* catalog */
243 catalog_name = ua->argv[i];
252 case 19: /* cloned */
257 case 20: /* write verify list output */
258 verify_list = ua->argv[i];
261 case 21: /* Migration Job */
262 if (previous_job_name) {
263 bsendmsg(ua, _("Migration Job specified twice.\n"));
266 previous_job_name = ua->argv[i];
274 } /* end strcase compare */
275 } /* end keyword loop */
277 * End of keyword for loop -- if not found, we got a bogus keyword
280 Dmsg1(800, "%s not found\n", ua->argk[i]);
282 * Special case for Job Name, it can be the first
283 * keyword that has no value.
285 if (!job_name && !ua->argv[i]) {
286 job_name = ua->argk[i]; /* use keyword as job name */
287 Dmsg1(800, "Set jobname=%s\n", job_name);
289 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
293 } /* end argc loop */
295 Dmsg0(800, "Done scan.\n");
298 if (catalog_name != NULL) {
299 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
300 if (catalog == NULL) {
301 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
305 Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
309 job = (JOB *)GetResWithName(R_JOB, job_name);
311 if (*job_name != 0) {
312 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
314 job = select_job_resource(ua);
316 Dmsg1(800, "Found job=%s\n", job_name);
319 bsendmsg(ua, _("A job name must be specified.\n"));
320 job = select_job_resource(ua);
324 } else if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
325 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
331 store = (STORE *)GetResWithName(R_STORAGE, store_name);
333 if (*store_name != 0) {
334 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
336 store = select_storage_resource(ua);
339 store = (STORE *)job->storage->first(); /* use default */
343 } else if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
344 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
348 Dmsg1(800, "Using storage=%s\n", store->hdr.name);
351 pool = (POOL *)GetResWithName(R_POOL, pool_name);
353 if (*pool_name != 0) {
354 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
356 pool = select_pool_resource(ua);
359 pool = job->pool; /* use default */
363 } else if (!acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
364 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
368 Dmsg1(800, "Using pool\n", pool->hdr.name);
371 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
373 if (*client_name != 0) {
374 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
376 client = select_client_resource(ua);
379 client = job->client; /* use default */
383 } else if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) {
384 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
388 Dmsg1(800, "Using client=%s\n", client->hdr.name);
391 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
393 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
394 fileset = select_fileset_resource(ua);
397 fileset = job->fileset; /* use default */
401 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->hdr.name)) {
402 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
407 if (verify_job_name) {
408 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
410 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
411 verify_job = select_job_resource(ua);
414 verify_job = job->verify_job;
417 if (previous_job_name) {
418 previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
420 bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
421 previous_job = select_job_resource(ua);
424 previous_job = job->verify_job;
429 * Create JCR to run job. NOTE!!! after this point, free_jcr()
432 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
433 set_jcr_defaults(jcr, job);
435 jcr->verify_job = verify_job;
436 jcr->previous_job = previous_job;
437 set_storage(jcr, store);
438 jcr->client = client;
439 jcr->fileset = fileset;
441 jcr->ExpectedFiles = files;
442 if (catalog != NULL) {
443 jcr->catalog = catalog;
449 jcr->where = bstrdup(where);
453 jcr->sched_time = str_to_utime(when);
454 if (jcr->sched_time == 0) {
455 bsendmsg(ua, _("Invalid time, using current time.\n"));
456 jcr->sched_time = time(NULL);
461 if (jcr->RestoreBootstrap) {
462 free(jcr->RestoreBootstrap);
464 jcr->RestoreBootstrap = bstrdup(bootstrap);
469 for (i=0; ReplaceOptions[i].name; i++) {
470 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
471 jcr->replace = ReplaceOptions[i].token;
475 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
478 } else if (job->replace) {
479 jcr->replace = job->replace;
481 jcr->replace = REPLACE_ALWAYS;
485 jcr->JobPriority = Priority;
490 jcr->stime = get_pool_memory(PM_MESSAGE);
492 pm_strcpy(jcr->stime, since);
495 jcr->cloned = cloned;
497 if (find_arg(ua, NT_("fdcalled")) > 0) {
498 jcr->file_bsock = dup_bsock(ua->UA_sock);
503 replace = ReplaceOptions[0].name;
504 for (i=0; ReplaceOptions[i].name; i++) {
505 if (ReplaceOptions[i].token == jcr->replace) {
506 replace = ReplaceOptions[i].name;
510 if (!get_level_from_name(jcr, level_name)) {
511 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
516 /* Note, this is also MigrateJobId */
517 jcr->RestoreJobId = str_to_int64(jid);
520 /* Run without prompting? */
521 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
526 * Prompt User to see if all run job parameters are correct, and
527 * allow him to modify them.
529 Dmsg1(800, "JobType=%c\n", jcr->JobType);
530 switch (jcr->JobType) {
532 char dt[MAX_TIME_LENGTH];
534 bsendmsg(ua, _("Run %s job\n"
543 jcr->fileset->hdr.name,
544 NPRT(jcr->client->hdr.name),
545 NPRT(jcr->store->hdr.name),
546 bstrutime(dt, sizeof(dt), jcr->sched_time),
548 jcr->JobLevel = L_FULL;
552 if (jcr->JobType == JT_BACKUP) {
553 bsendmsg(ua, _("Run %s job\n"
564 jcr->fileset->hdr.name,
565 level_to_str(jcr->JobLevel),
566 jcr->client->hdr.name,
567 jcr->store->hdr.name,
568 NPRT(jcr->pool->hdr.name),
569 bstrutime(dt, sizeof(dt), jcr->sched_time),
571 } else { /* JT_VERIFY */
573 if (jcr->verify_job) {
574 Name = jcr->verify_job->hdr.name;
579 verify_list = job->WriteVerifyList;
584 bsendmsg(ua, _("Run %s job\n"
597 jcr->fileset->hdr.name,
598 level_to_str(jcr->JobLevel),
599 jcr->client->hdr.name,
600 jcr->store->hdr.name,
601 NPRT(jcr->pool->hdr.name),
604 bstrutime(dt, sizeof(dt), jcr->sched_time),
609 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
611 jcr->RestoreJobId = str_to_int64(jid);
613 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
616 jcr->RestoreJobId = ua->int64_val;
619 jcr->JobLevel = L_FULL; /* default level */
620 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
621 if (jcr->RestoreJobId == 0) {
622 bsendmsg(ua, _("Run Restore job\n"
634 NPRT(jcr->RestoreBootstrap),
635 jcr->where?jcr->where:NPRT(job->RestoreWhere),
637 jcr->fileset->hdr.name,
638 jcr->client->hdr.name,
639 jcr->store->hdr.name,
640 bstrutime(dt, sizeof(dt), jcr->sched_time),
641 jcr->catalog->hdr.name,
644 bsendmsg(ua, _("Run Restore job\n"
656 NPRT(jcr->RestoreBootstrap),
657 jcr->where?jcr->where:NPRT(job->RestoreWhere),
659 jcr->client->hdr.name,
660 jcr->store->hdr.name,
661 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
662 bstrutime(dt, sizeof(dt), jcr->sched_time),
663 jcr->catalog->hdr.name,
668 jcr->JobLevel = L_FULL; /* default level */
669 bsendmsg(ua, _("Run Restore job\n"
682 NPRT(jcr->RestoreBootstrap),
683 jcr->where?jcr->where:NPRT(job->RestoreWhere),
685 jcr->fileset->hdr.name,
686 jcr->client->hdr.name,
687 jcr->store->hdr.name,
688 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
689 bstrutime(dt, sizeof(dt), jcr->sched_time),
690 jcr->catalog->hdr.name,
694 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
698 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
702 * At user request modify parameters of job to be run.
704 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
707 start_prompt(ua, _("Parameters to modify:\n"));
708 add_prompt(ua, _("Level")); /* 0 */
709 add_prompt(ua, _("Storage")); /* 1 */
710 add_prompt(ua, _("Job")); /* 2 */
711 add_prompt(ua, _("FileSet")); /* 3 */
712 add_prompt(ua, _("Client")); /* 4 */
713 add_prompt(ua, _("When")); /* 5 */
714 add_prompt(ua, _("Priority")); /* 6 */
715 if (jcr->JobType == JT_BACKUP ||
716 jcr->JobType == JT_VERIFY) {
717 add_prompt(ua, _("Pool")); /* 7 */
718 if (jcr->JobType == JT_VERIFY) {
719 add_prompt(ua, _("Verify Job")); /* 8 */
721 } else if (jcr->JobType == JT_RESTORE) {
722 add_prompt(ua, _("Bootstrap")); /* 7 */
723 add_prompt(ua, _("Where")); /* 8 */
724 add_prompt(ua, _("Replace")); /* 9 */
725 add_prompt(ua, _("JobId")); /* 10 */
727 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
730 if (jcr->JobType == JT_BACKUP) {
731 start_prompt(ua, _("Levels:\n"));
732 add_prompt(ua, _("Base"));
733 add_prompt(ua, _("Full"));
734 add_prompt(ua, _("Incremental"));
735 add_prompt(ua, _("Differential"));
736 add_prompt(ua, _("Since"));
737 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
739 jcr->JobLevel = L_BASE;
742 jcr->JobLevel = L_FULL;
745 jcr->JobLevel = L_INCREMENTAL;
748 jcr->JobLevel = L_DIFFERENTIAL;
751 jcr->JobLevel = L_SINCE;
757 } else if (jcr->JobType == JT_VERIFY) {
758 start_prompt(ua, _("Levels:\n"));
759 add_prompt(ua, _("Initialize Catalog"));
760 add_prompt(ua, _("Verify Catalog"));
761 add_prompt(ua, _("Verify Volume to Catalog"));
762 add_prompt(ua, _("Verify Disk to Catalog"));
763 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
764 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
766 jcr->JobLevel = L_VERIFY_INIT;
769 jcr->JobLevel = L_VERIFY_CATALOG;
772 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
775 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
778 jcr->JobLevel = L_VERIFY_DATA;
785 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
790 store = select_storage_resource(ua);
792 set_storage(jcr, store);
798 job = select_job_resource(ua);
801 set_jcr_defaults(jcr, job);
807 fileset = select_fileset_resource(ua);
809 jcr->fileset = fileset;
815 client = select_client_resource(ua);
817 jcr->client = client;
823 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
826 if (ua->cmd[0] == 0) {
827 jcr->sched_time = time(NULL);
829 jcr->sched_time = str_to_utime(ua->cmd);
830 if (jcr->sched_time == 0) {
831 bsendmsg(ua, _("Invalid time, using current time.\n"));
832 jcr->sched_time = time(NULL);
838 if (!get_pint(ua, _("Enter new Priority: "))) {
841 if (ua->pint32_val == 0) {
842 bsendmsg(ua, _("Priority must be a positive integer.\n"));
844 jcr->JobPriority = ua->pint32_val;
848 /* Pool or Bootstrap depending on JobType */
849 if (jcr->JobType == JT_BACKUP ||
850 jcr->JobType == JT_VERIFY) { /* Pool */
851 pool = select_pool_resource(ua);
860 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
863 if (jcr->RestoreBootstrap) {
864 free(jcr->RestoreBootstrap);
865 jcr->RestoreBootstrap = NULL;
867 if (ua->cmd[0] != 0) {
868 jcr->RestoreBootstrap = bstrdup(ua->cmd);
869 fd = fopen(jcr->RestoreBootstrap, "rb");
871 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
872 jcr->RestoreBootstrap, strerror(errno));
873 free(jcr->RestoreBootstrap);
874 jcr->RestoreBootstrap = NULL;
882 if (jcr->JobType == JT_VERIFY) {
883 verify_job = select_job_resource(ua);
885 jcr->verify_job = verify_job;
890 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
897 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
900 jcr->where = bstrdup(ua->cmd);
904 start_prompt(ua, _("Replace:\n"));
905 for (i=0; ReplaceOptions[i].name; i++) {
906 add_prompt(ua, ReplaceOptions[i].name);
908 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
910 jcr->replace = ReplaceOptions[opt].token;
915 jid = NULL; /* force reprompt */
916 jcr->RestoreJobId = 0;
917 if (jcr->RestoreBootstrap) {
918 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
921 case -1: /* error or cancel */
929 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
931 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
933 JobId = run_job(jcr);
935 bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
936 "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
937 time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
938 jcr->Job, jcr->JobLevel, jcr->JobPriority);
940 free_jcr(jcr); /* release jcr */
942 bsendmsg(ua, _("Job failed.\n"));
945 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
951 bsendmsg(ua, _("Job not run.\n"));
953 return 0; /* do not run */