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->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->name())) {
344 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
348 Dmsg1(800, "Using storage=%s\n", store->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->name())) {
364 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
368 Dmsg1(800, "Using pool\n", pool->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->name())) {
384 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
388 Dmsg1(800, "Using client=%s\n", client->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->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_rwstorage(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->name(),
544 NPRT(jcr->client->name()),
545 NPRT(jcr->wstore->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->name(),
565 level_to_str(jcr->JobLevel),
568 NPRT(jcr->pool->name()),
569 bstrutime(dt, sizeof(dt), jcr->sched_time),
571 } else { /* JT_VERIFY */
573 if (jcr->verify_job) {
574 Name = jcr->verify_job->name();
579 verify_list = job->WriteVerifyList;
584 bsendmsg(ua, _("Run %s job\n"
597 jcr->fileset->name(),
598 level_to_str(jcr->JobLevel),
601 NPRT(jcr->pool->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->name(),
640 bstrutime(dt, sizeof(dt), jcr->sched_time),
641 jcr->catalog->name(),
644 bsendmsg(ua, _("Run Restore job\n"
656 NPRT(jcr->RestoreBootstrap),
657 jcr->where?jcr->where:NPRT(job->RestoreWhere),
661 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
662 bstrutime(dt, sizeof(dt), jcr->sched_time),
663 jcr->catalog->name(),
668 jcr->JobLevel = L_FULL; /* default level */
669 bsendmsg(ua, _("Run Migration job\n"
680 NPRT(jcr->RestoreBootstrap),
681 jcr->fileset->name(),
684 jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
685 bstrutime(dt, sizeof(dt), jcr->sched_time),
686 jcr->catalog->name(),
690 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
694 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
698 * At user request modify parameters of job to be run.
700 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
703 start_prompt(ua, _("Parameters to modify:\n"));
704 add_prompt(ua, _("Level")); /* 0 */
705 add_prompt(ua, _("Storage")); /* 1 */
706 add_prompt(ua, _("Job")); /* 2 */
707 add_prompt(ua, _("FileSet")); /* 3 */
708 add_prompt(ua, _("Client")); /* 4 */
709 add_prompt(ua, _("When")); /* 5 */
710 add_prompt(ua, _("Priority")); /* 6 */
711 if (jcr->JobType == JT_BACKUP ||
712 jcr->JobType == JT_VERIFY) {
713 add_prompt(ua, _("Pool")); /* 7 */
714 if (jcr->JobType == JT_VERIFY) {
715 add_prompt(ua, _("Verify Job")); /* 8 */
717 } else if (jcr->JobType == JT_RESTORE) {
718 add_prompt(ua, _("Bootstrap")); /* 7 */
719 add_prompt(ua, _("Where")); /* 8 */
720 add_prompt(ua, _("Replace")); /* 9 */
721 add_prompt(ua, _("JobId")); /* 10 */
723 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
726 if (jcr->JobType == JT_BACKUP) {
727 start_prompt(ua, _("Levels:\n"));
728 add_prompt(ua, _("Base"));
729 add_prompt(ua, _("Full"));
730 add_prompt(ua, _("Incremental"));
731 add_prompt(ua, _("Differential"));
732 add_prompt(ua, _("Since"));
733 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
735 jcr->JobLevel = L_BASE;
738 jcr->JobLevel = L_FULL;
741 jcr->JobLevel = L_INCREMENTAL;
744 jcr->JobLevel = L_DIFFERENTIAL;
747 jcr->JobLevel = L_SINCE;
753 } else if (jcr->JobType == JT_VERIFY) {
754 start_prompt(ua, _("Levels:\n"));
755 add_prompt(ua, _("Initialize Catalog"));
756 add_prompt(ua, _("Verify Catalog"));
757 add_prompt(ua, _("Verify Volume to Catalog"));
758 add_prompt(ua, _("Verify Disk to Catalog"));
759 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
760 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
762 jcr->JobLevel = L_VERIFY_INIT;
765 jcr->JobLevel = L_VERIFY_CATALOG;
768 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
771 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
774 jcr->JobLevel = L_VERIFY_DATA;
781 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
786 store = select_storage_resource(ua);
788 set_rwstorage(jcr, store);
794 job = select_job_resource(ua);
797 set_jcr_defaults(jcr, job);
803 fileset = select_fileset_resource(ua);
805 jcr->fileset = fileset;
811 client = select_client_resource(ua);
813 jcr->client = client;
819 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
822 if (ua->cmd[0] == 0) {
823 jcr->sched_time = time(NULL);
825 jcr->sched_time = str_to_utime(ua->cmd);
826 if (jcr->sched_time == 0) {
827 bsendmsg(ua, _("Invalid time, using current time.\n"));
828 jcr->sched_time = time(NULL);
834 if (!get_pint(ua, _("Enter new Priority: "))) {
837 if (ua->pint32_val == 0) {
838 bsendmsg(ua, _("Priority must be a positive integer.\n"));
840 jcr->JobPriority = ua->pint32_val;
844 /* Pool or Bootstrap depending on JobType */
845 if (jcr->JobType == JT_BACKUP ||
846 jcr->JobType == JT_VERIFY) { /* Pool */
847 pool = select_pool_resource(ua);
856 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
859 if (jcr->RestoreBootstrap) {
860 free(jcr->RestoreBootstrap);
861 jcr->RestoreBootstrap = NULL;
863 if (ua->cmd[0] != 0) {
864 jcr->RestoreBootstrap = bstrdup(ua->cmd);
865 fd = fopen(jcr->RestoreBootstrap, "rb");
867 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
868 jcr->RestoreBootstrap, strerror(errno));
869 free(jcr->RestoreBootstrap);
870 jcr->RestoreBootstrap = NULL;
878 if (jcr->JobType == JT_VERIFY) {
879 verify_job = select_job_resource(ua);
881 jcr->verify_job = verify_job;
886 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
893 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
896 jcr->where = bstrdup(ua->cmd);
900 start_prompt(ua, _("Replace:\n"));
901 for (i=0; ReplaceOptions[i].name; i++) {
902 add_prompt(ua, ReplaceOptions[i].name);
904 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
906 jcr->replace = ReplaceOptions[opt].token;
911 jid = NULL; /* force reprompt */
912 jcr->RestoreJobId = 0;
913 if (jcr->RestoreBootstrap) {
914 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
917 case -1: /* error or cancel */
925 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
927 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
929 JobId = run_job(jcr);
931 bsendmsg(ua, "<job director=\"console\" time=\"%u\" status=\"%c\" type=\"%c\" "
932 "jobid=\"%u\" job=\"%s\" level=\"%c\" finished=\"false\" priority=\"%u\"/>\n",
933 time(NULL), jcr->JobStatus, jcr->JobType, jcr->JobId,
934 jcr->Job, jcr->JobLevel, jcr->JobPriority);
936 free_jcr(jcr); /* release jcr */
938 bsendmsg(ua, _("Job failed.\n"));
941 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
947 bsendmsg(ua, _("Job not run.\n"));
949 return 0; /* do not run */