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"));
188 if (!acl_access_ok(ua, Where_ACL, where)) {
189 bsendmsg(ua, _("Forbidden \"where\" specified.\n"));
194 case 10: /* bootstrap */
196 bsendmsg(ua, _("Bootstrap specified twice.\n"));
199 bootstrap = ua->argv[i];
202 case 11: /* replace */
204 bsendmsg(ua, _("Replace specified twice.\n"));
207 replace = ua->argv[i];
212 bsendmsg(ua, _("When specified twice.\n"));
218 case 13: /* Priority */
220 bsendmsg(ua, _("Priority specified twice.\n"));
223 Priority = atoi(ua->argv[i]);
225 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
233 case 15: /* Verify Job */
234 if (verify_job_name) {
235 bsendmsg(ua, _("Verify Job specified twice.\n"));
238 verify_job_name = ua->argv[i];
242 files = atoi(ua->argv[i]);
246 case 17: /* catalog */
247 catalog_name = ua->argv[i];
256 case 19: /* cloned */
261 case 20: /* write verify list output */
262 verify_list = ua->argv[i];
265 case 21: /* Migration Job */
266 if (previous_job_name) {
267 bsendmsg(ua, _("Migration Job specified twice.\n"));
270 previous_job_name = ua->argv[i];
278 } /* end strcase compare */
279 } /* end keyword loop */
281 * End of keyword for loop -- if not found, we got a bogus keyword
284 Dmsg1(800, "%s not found\n", ua->argk[i]);
286 * Special case for Job Name, it can be the first
287 * keyword that has no value.
289 if (!job_name && !ua->argv[i]) {
290 job_name = ua->argk[i]; /* use keyword as job name */
291 Dmsg1(800, "Set jobname=%s\n", job_name);
293 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
297 } /* end argc loop */
299 Dmsg0(800, "Done scan.\n");
302 if (catalog_name != NULL) {
303 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
304 if (catalog == NULL) {
305 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
309 Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
313 job = (JOB *)GetResWithName(R_JOB, job_name);
315 if (*job_name != 0) {
316 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
318 job = select_job_resource(ua);
320 Dmsg1(800, "Found job=%s\n", job_name);
323 bsendmsg(ua, _("A job name must be specified.\n"));
324 job = select_job_resource(ua);
328 } else if (!acl_access_ok(ua, Job_ACL, job->name())) {
329 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
335 store = (STORE *)GetResWithName(R_STORAGE, store_name);
337 if (*store_name != 0) {
338 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
340 store = select_storage_resource(ua);
343 store = (STORE *)job->storage->first(); /* use default */
347 } else if (!acl_access_ok(ua, Storage_ACL, store->name())) {
348 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
352 Dmsg1(800, "Using storage=%s\n", store->name());
355 pool = (POOL *)GetResWithName(R_POOL, pool_name);
357 if (*pool_name != 0) {
358 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
360 pool = select_pool_resource(ua);
363 pool = job->pool; /* use default */
367 } else if (!acl_access_ok(ua, Pool_ACL, pool->name())) {
368 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
372 Dmsg1(800, "Using pool\n", pool->name());
375 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
377 if (*client_name != 0) {
378 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
380 client = select_client_resource(ua);
383 client = job->client; /* use default */
387 } else if (!acl_access_ok(ua, Client_ACL, client->name())) {
388 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
392 Dmsg1(800, "Using client=%s\n", client->name());
395 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
397 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
398 fileset = select_fileset_resource(ua);
401 fileset = job->fileset; /* use default */
405 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
406 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
411 if (verify_job_name) {
412 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
414 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
415 verify_job = select_job_resource(ua);
418 verify_job = job->verify_job;
421 if (previous_job_name) {
422 previous_job = (JOB *)GetResWithName(R_JOB, previous_job_name);
424 bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), previous_job_name);
425 previous_job = select_job_resource(ua);
428 previous_job = job->verify_job;
433 * Create JCR to run job. NOTE!!! after this point, free_jcr()
436 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
437 set_jcr_defaults(jcr, job);
439 jcr->verify_job = verify_job;
440 jcr->previous_job = previous_job;
441 set_rwstorage(jcr, store);
442 jcr->client = client;
443 jcr->fileset = fileset;
445 jcr->ExpectedFiles = files;
446 if (catalog != NULL) {
447 jcr->catalog = catalog;
453 jcr->where = bstrdup(where);
457 jcr->sched_time = str_to_utime(when);
458 if (jcr->sched_time == 0) {
459 bsendmsg(ua, _("Invalid time, using current time.\n"));
460 jcr->sched_time = time(NULL);
465 if (jcr->RestoreBootstrap) {
466 free(jcr->RestoreBootstrap);
468 jcr->RestoreBootstrap = bstrdup(bootstrap);
473 for (i=0; ReplaceOptions[i].name; i++) {
474 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
475 jcr->replace = ReplaceOptions[i].token;
479 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
482 } else if (job->replace) {
483 jcr->replace = job->replace;
485 jcr->replace = REPLACE_ALWAYS;
489 jcr->JobPriority = Priority;
494 jcr->stime = get_pool_memory(PM_MESSAGE);
496 pm_strcpy(jcr->stime, since);
499 jcr->cloned = cloned;
501 if (find_arg(ua, NT_("fdcalled")) > 0) {
502 jcr->file_bsock = dup_bsock(ua->UA_sock);
507 replace = ReplaceOptions[0].name;
508 for (i=0; ReplaceOptions[i].name; i++) {
509 if (ReplaceOptions[i].token == jcr->replace) {
510 replace = ReplaceOptions[i].name;
514 if (!get_level_from_name(jcr, level_name)) {
515 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
520 /* Note, this is also MigrateJobId */
521 jcr->RestoreJobId = str_to_int64(jid);
524 /* Run without prompting? */
525 if (ua->batch || find_arg(ua, NT_("yes")) > 0) {
530 * Prompt User to see if all run job parameters are correct, and
531 * allow him to modify them.
533 Dmsg1(800, "JobType=%c\n", jcr->JobType);
534 switch (jcr->JobType) {
536 char dt[MAX_TIME_LENGTH];
538 bsendmsg(ua, _("Run %s job\n"
547 jcr->fileset->name(),
548 NPRT(jcr->client->name()),
549 NPRT(jcr->wstore->name()),
550 bstrutime(dt, sizeof(dt), jcr->sched_time),
552 jcr->JobLevel = L_FULL;
556 if (jcr->JobType == JT_BACKUP) {
557 bsendmsg(ua, _("Run %s job\n"
568 jcr->fileset->name(),
569 level_to_str(jcr->JobLevel),
572 NPRT(jcr->pool->name()),
573 bstrutime(dt, sizeof(dt), jcr->sched_time),
575 } else { /* JT_VERIFY */
577 if (jcr->verify_job) {
578 Name = jcr->verify_job->name();
583 verify_list = job->WriteVerifyList;
588 bsendmsg(ua, _("Run %s job\n"
601 jcr->fileset->name(),
602 level_to_str(jcr->JobLevel),
605 NPRT(jcr->pool->name()),
608 bstrutime(dt, sizeof(dt), jcr->sched_time),
613 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
615 jcr->RestoreJobId = str_to_int64(jid);
617 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
620 jcr->RestoreJobId = ua->int64_val;
623 jcr->JobLevel = L_FULL; /* default level */
624 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
625 if (jcr->RestoreJobId == 0) {
626 bsendmsg(ua, _("Run Restore job\n"
638 NPRT(jcr->RestoreBootstrap),
639 jcr->where?jcr->where:NPRT(job->RestoreWhere),
641 jcr->fileset->name(),
644 bstrutime(dt, sizeof(dt), jcr->sched_time),
645 jcr->catalog->name(),
648 bsendmsg(ua, _("Run Restore job\n"
660 NPRT(jcr->RestoreBootstrap),
661 jcr->where?jcr->where:NPRT(job->RestoreWhere),
665 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
666 bstrutime(dt, sizeof(dt), jcr->sched_time),
667 jcr->catalog->name(),
672 jcr->JobLevel = L_FULL; /* default level */
673 bsendmsg(ua, _("Run Migration job\n"
684 NPRT(jcr->RestoreBootstrap),
685 jcr->fileset->name(),
688 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
689 bstrutime(dt, sizeof(dt), jcr->sched_time),
690 jcr->catalog->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_rwstorage(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 */