3 * Bacula Director -- Run Command
5 * Kern Sibbald, December MMI
10 Copyright (C) 2001-2005 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 *migration_job_name;
55 int i, j, opt, files = 0;
58 JOB *verify_job = NULL;
59 JOB *migration_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 migration_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 err */
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 (migration_job_name) {
263 bsendmsg(ua, _("Migration Job specified twice.\n"));
266 migration_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 (migration_job_name) {
418 migration_job = (JOB *)GetResWithName(R_JOB, migration_job_name);
419 if (!migration_job) {
420 bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), migration_job_name);
421 migration_job = select_job_resource(ua);
424 migration_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->migration_job = migration_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, N_("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 jcr->RestoreJobId = str_to_int64(jid);
519 /* Run without prompting? */
520 if (ua->batch || find_arg(ua, N_("yes")) > 0) {
525 * Prompt User to see if all run job parameters are correct, and
526 * allow him to modify them.
528 Dmsg1(800, "JobType=%c\n", jcr->JobType);
529 switch (jcr->JobType) {
531 char dt[MAX_TIME_LENGTH];
533 bsendmsg(ua, _("Run %s job\n"
542 jcr->fileset->hdr.name,
543 NPRT(jcr->client->hdr.name),
544 NPRT(jcr->store->hdr.name),
545 bstrutime(dt, sizeof(dt), jcr->sched_time),
547 jcr->JobLevel = L_FULL;
551 if (jcr->JobType == JT_BACKUP) {
552 bsendmsg(ua, _("Run %s job\n"
563 jcr->fileset->hdr.name,
564 level_to_str(jcr->JobLevel),
565 jcr->client->hdr.name,
566 jcr->store->hdr.name,
567 NPRT(jcr->pool->hdr.name),
568 bstrutime(dt, sizeof(dt), jcr->sched_time),
570 } else { /* JT_VERIFY */
572 if (jcr->verify_job) {
573 Name = jcr->verify_job->hdr.name;
578 verify_list = job->WriteVerifyList;
583 bsendmsg(ua, _("Run %s job\n"
596 jcr->fileset->hdr.name,
597 level_to_str(jcr->JobLevel),
598 jcr->client->hdr.name,
599 jcr->store->hdr.name,
600 NPRT(jcr->pool->hdr.name),
603 bstrutime(dt, sizeof(dt), jcr->sched_time),
608 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
610 jcr->RestoreJobId = str_to_int64(jid);
612 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
615 jcr->RestoreJobId = ua->int64_val;
618 jcr->JobLevel = L_FULL; /* default level */
619 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
620 if (jcr->RestoreJobId == 0) {
621 bsendmsg(ua, _("Run Restore job\n"
633 NPRT(jcr->RestoreBootstrap),
634 jcr->where?jcr->where:NPRT(job->RestoreWhere),
636 jcr->fileset->hdr.name,
637 jcr->client->hdr.name,
638 jcr->store->hdr.name,
639 bstrutime(dt, sizeof(dt), jcr->sched_time),
640 jcr->catalog->hdr.name,
643 bsendmsg(ua, _("Run Restore job\n"
655 NPRT(jcr->RestoreBootstrap),
656 jcr->where?jcr->where:NPRT(job->RestoreWhere),
658 jcr->client->hdr.name,
659 jcr->store->hdr.name,
660 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
661 bstrutime(dt, sizeof(dt), jcr->sched_time),
662 jcr->catalog->hdr.name,
667 jcr->JobLevel = L_FULL; /* default level */
668 bsendmsg(ua, _("Run Restore job\n"
676 "Migration Job: %s\n"
681 NPRT(jcr->RestoreBootstrap),
682 jcr->where?jcr->where:NPRT(job->RestoreWhere),
684 jcr->fileset->hdr.name,
685 jcr->client->hdr.name,
686 jcr->store->hdr.name,
687 jcr->migration_job->hdr.name,
688 bstrutime(dt, sizeof(dt), jcr->sched_time),
689 jcr->catalog->hdr.name,
693 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
697 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
701 * At user request modify parameters of job to be run.
703 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
706 start_prompt(ua, _("Parameters to modify:\n"));
707 add_prompt(ua, _("Level")); /* 0 */
708 add_prompt(ua, _("Storage")); /* 1 */
709 add_prompt(ua, _("Job")); /* 2 */
710 add_prompt(ua, _("FileSet")); /* 3 */
711 add_prompt(ua, _("Client")); /* 4 */
712 add_prompt(ua, _("When")); /* 5 */
713 add_prompt(ua, _("Priority")); /* 6 */
714 if (jcr->JobType == JT_BACKUP ||
715 jcr->JobType == JT_VERIFY) {
716 add_prompt(ua, _("Pool")); /* 7 */
717 if (jcr->JobType == JT_VERIFY) {
718 add_prompt(ua, _("Verify Job")); /* 8 */
720 } else if (jcr->JobType == JT_RESTORE) {
721 add_prompt(ua, _("Bootstrap")); /* 7 */
722 add_prompt(ua, _("Where")); /* 8 */
723 add_prompt(ua, _("Replace")); /* 9 */
724 add_prompt(ua, _("JobId")); /* 10 */
726 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
729 if (jcr->JobType == JT_BACKUP) {
730 start_prompt(ua, _("Levels:\n"));
731 add_prompt(ua, _("Base"));
732 add_prompt(ua, _("Full"));
733 add_prompt(ua, _("Incremental"));
734 add_prompt(ua, _("Differential"));
735 add_prompt(ua, _("Since"));
736 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
738 jcr->JobLevel = L_BASE;
741 jcr->JobLevel = L_FULL;
744 jcr->JobLevel = L_INCREMENTAL;
747 jcr->JobLevel = L_DIFFERENTIAL;
750 jcr->JobLevel = L_SINCE;
756 } else if (jcr->JobType == JT_VERIFY) {
757 start_prompt(ua, _("Levels:\n"));
758 add_prompt(ua, _("Initialize Catalog"));
759 add_prompt(ua, _("Verify Catalog"));
760 add_prompt(ua, _("Verify Volume to Catalog"));
761 add_prompt(ua, _("Verify Disk to Catalog"));
762 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
763 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
765 jcr->JobLevel = L_VERIFY_INIT;
768 jcr->JobLevel = L_VERIFY_CATALOG;
771 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
774 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
777 jcr->JobLevel = L_VERIFY_DATA;
784 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
789 store = select_storage_resource(ua);
791 set_storage(jcr, store);
797 job = select_job_resource(ua);
800 set_jcr_defaults(jcr, job);
806 fileset = select_fileset_resource(ua);
808 jcr->fileset = fileset;
814 client = select_client_resource(ua);
816 jcr->client = client;
822 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
825 if (ua->cmd[0] == 0) {
826 jcr->sched_time = time(NULL);
828 jcr->sched_time = str_to_utime(ua->cmd);
829 if (jcr->sched_time == 0) {
830 bsendmsg(ua, _("Invalid time, using current time.\n"));
831 jcr->sched_time = time(NULL);
837 if (!get_pint(ua, _("Enter new Priority: "))) {
840 if (ua->pint32_val == 0) {
841 bsendmsg(ua, _("Priority must be a positive integer.\n"));
843 jcr->JobPriority = ua->pint32_val;
847 /* Pool or Bootstrap depending on JobType */
848 if (jcr->JobType == JT_BACKUP ||
849 jcr->JobType == JT_VERIFY) { /* Pool */
850 pool = select_pool_resource(ua);
859 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
862 if (jcr->RestoreBootstrap) {
863 free(jcr->RestoreBootstrap);
864 jcr->RestoreBootstrap = NULL;
866 if (ua->cmd[0] != 0) {
867 jcr->RestoreBootstrap = bstrdup(ua->cmd);
868 fd = fopen(jcr->RestoreBootstrap, "r");
870 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
871 jcr->RestoreBootstrap, strerror(errno));
872 free(jcr->RestoreBootstrap);
873 jcr->RestoreBootstrap = NULL;
881 if (jcr->JobType == JT_VERIFY) {
882 verify_job = select_job_resource(ua);
884 jcr->verify_job = verify_job;
889 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
896 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
899 jcr->where = bstrdup(ua->cmd);
903 start_prompt(ua, _("Replace:\n"));
904 for (i=0; ReplaceOptions[i].name; i++) {
905 add_prompt(ua, ReplaceOptions[i].name);
907 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
909 jcr->replace = ReplaceOptions[opt].token;
914 jid = NULL; /* force reprompt */
915 jcr->RestoreJobId = 0;
916 if (jcr->RestoreBootstrap) {
917 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
920 case -1: /* error or cancel */
928 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
930 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
932 JobId = run_job(jcr);
933 free_jcr(jcr); /* release jcr */
935 bsendmsg(ua, _("Job failed.\n"));
938 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
944 bsendmsg(ua, _("Job not run.\n"));
946 return 0; /* do not run */