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>
37 * run <job-name> jobid=nn
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;
54 int i, j, opt, files = 0;
57 JOB *verify_job = NULL;
59 CLIENT *client = NULL;
60 FILESET *fileset = NULL;
62 static const char *kw[] = { /* command line arguments */
63 "job", /* Used in a switch() */
77 "yes", /* 14 -- if you change this change YES_POS too */
79 "files", /* 16 number of files to restore */
80 "catalog", /* 17 override catalog */
81 "since", /* 18 since */
82 "cloned", /* 19 cloned */
83 "verifylist", /* 20 verify output list */
103 verify_job_name = NULL;
107 for (i=1; i<ua->argc; i++) {
108 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
110 /* Keep looking until we find a good keyword */
111 for (j=0; !kw_ok && kw[j]; j++) {
112 if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
113 /* Note, yes and run have no value, so do not err */
114 if (!ua->argv[i] && j != YES_POS /*yes*/) {
115 bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
118 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
122 bsendmsg(ua, _("Job name specified twice.\n"));
125 job_name = ua->argv[i];
130 bsendmsg(ua, _("JobId specified twice.\n"));
139 bsendmsg(ua, _("Client specified twice.\n"));
142 client_name = ua->argv[i];
145 case 4: /* fileset */
147 bsendmsg(ua, _("FileSet specified twice.\n"));
150 fileset_name = ua->argv[i];
155 bsendmsg(ua, _("Level specified twice.\n"));
158 level_name = ua->argv[i];
161 case 6: /* storage */
164 bsendmsg(ua, _("Storage specified twice.\n"));
167 store_name = ua->argv[i];
172 bsendmsg(ua, _("Pool specified twice.\n"));
175 pool_name = ua->argv[i];
180 bsendmsg(ua, _("Where specified twice.\n"));
186 case 10: /* bootstrap */
188 bsendmsg(ua, _("Bootstrap specified twice.\n"));
191 bootstrap = ua->argv[i];
194 case 11: /* replace */
196 bsendmsg(ua, _("Replace specified twice.\n"));
199 replace = ua->argv[i];
204 bsendmsg(ua, _("When specified twice.\n"));
210 case 13: /* Priority */
212 bsendmsg(ua, _("Priority specified twice.\n"));
215 Priority = atoi(ua->argv[i]);
217 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
225 case 15: /* Verify Job */
226 if (verify_job_name) {
227 bsendmsg(ua, _("Verify Job specified twice.\n"));
230 verify_job_name = ua->argv[i];
234 files = atoi(ua->argv[i]);
238 case 17: /* catalog */
239 catalog_name = ua->argv[i];
248 case 19: /* cloned */
253 case 20: /* write verify list output */
254 verify_list = ua->argv[i];
261 } /* end strcase compare */
262 } /* end keyword loop */
264 * End of keyword for loop -- if not found, we got a bogus keyword
267 Dmsg1(800, "%s not found\n", ua->argk[i]);
269 * Special case for Job Name, it can be the first
270 * keyword that has no value.
272 if (!job_name && !ua->argv[i]) {
273 job_name = ua->argk[i]; /* use keyword as job name */
274 Dmsg1(800, "Set jobname=%s\n", job_name);
276 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
280 } /* end argc loop */
282 Dmsg0(800, "Done scan.\n");
285 if (catalog_name != NULL) {
286 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
287 if (catalog == NULL) {
288 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
292 Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
296 job = (JOB *)GetResWithName(R_JOB, job_name);
298 if (*job_name != 0) {
299 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
301 job = select_job_resource(ua);
303 Dmsg1(800, "Found job=%s\n", job_name);
306 bsendmsg(ua, _("A job name must be specified.\n"));
307 job = select_job_resource(ua);
311 } else if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
312 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
318 store = (STORE *)GetResWithName(R_STORAGE, store_name);
320 if (*store_name != 0) {
321 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
323 store = select_storage_resource(ua);
326 store = (STORE *)job->storage->first(); /* use default */
330 } else if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
331 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
335 Dmsg1(800, "Using storage=%s\n", store->hdr.name);
338 pool = (POOL *)GetResWithName(R_POOL, pool_name);
340 if (*pool_name != 0) {
341 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
343 pool = select_pool_resource(ua);
346 pool = job->pool; /* use default */
350 } else if (!acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
351 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
355 Dmsg1(800, "Using pool\n", pool->hdr.name);
358 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
360 if (*client_name != 0) {
361 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
363 client = select_client_resource(ua);
366 client = job->client; /* use default */
370 } else if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) {
371 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
375 Dmsg1(800, "Using client=%s\n", client->hdr.name);
378 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
380 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
381 fileset = select_fileset_resource(ua);
384 fileset = job->fileset; /* use default */
388 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->hdr.name)) {
389 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
394 if (verify_job_name) {
395 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
397 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
398 verify_job = select_job_resource(ua);
401 verify_job = job->verify_job;
405 * Create JCR to run job. NOTE!!! after this point, free_jcr()
408 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
409 set_jcr_defaults(jcr, job);
411 jcr->verify_job = verify_job;
412 set_storage(jcr, store);
413 jcr->client = client;
414 jcr->fileset = fileset;
416 jcr->ExpectedFiles = files;
417 if (catalog != NULL) {
418 jcr->catalog = catalog;
424 jcr->where = bstrdup(where);
428 jcr->sched_time = str_to_utime(when);
429 if (jcr->sched_time == 0) {
430 bsendmsg(ua, _("Invalid time, using current time.\n"));
431 jcr->sched_time = time(NULL);
436 if (jcr->RestoreBootstrap) {
437 free(jcr->RestoreBootstrap);
439 jcr->RestoreBootstrap = bstrdup(bootstrap);
444 for (i=0; ReplaceOptions[i].name; i++) {
445 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
446 jcr->replace = ReplaceOptions[i].token;
450 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
453 } else if (job->replace) {
454 jcr->replace = job->replace;
456 jcr->replace = REPLACE_ALWAYS;
460 jcr->JobPriority = Priority;
465 jcr->stime = get_pool_memory(PM_MESSAGE);
467 pm_strcpy(jcr->stime, since);
470 jcr->cloned = cloned;
472 if (find_arg(ua, N_("fdcalled")) > 0) {
473 jcr->file_bsock = dup_bsock(ua->UA_sock);
478 replace = ReplaceOptions[0].name;
479 for (i=0; ReplaceOptions[i].name; i++) {
480 if (ReplaceOptions[i].token == jcr->replace) {
481 replace = ReplaceOptions[i].name;
485 if (!get_level_from_name(jcr, level_name)) {
486 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
491 jcr->RestoreJobId = str_to_int64(jid);
494 /* Run without prompting? */
495 if (ua->batch || find_arg(ua, N_("yes")) > 0) {
500 * Prompt User to see if all run job parameters are correct, and
501 * allow him to modify them.
503 Dmsg1(800, "JobType=%c\n", jcr->JobType);
504 switch (jcr->JobType) {
506 char dt[MAX_TIME_LENGTH];
508 bsendmsg(ua, _("Run %s job\n"
517 jcr->fileset->hdr.name,
518 NPRT(jcr->client->hdr.name),
519 NPRT(jcr->store->hdr.name),
520 bstrutime(dt, sizeof(dt), jcr->sched_time),
522 jcr->JobLevel = L_FULL;
526 if (jcr->JobType == JT_BACKUP) {
527 bsendmsg(ua, _("Run %s job\n"
538 jcr->fileset->hdr.name,
539 level_to_str(jcr->JobLevel),
540 jcr->client->hdr.name,
541 jcr->store->hdr.name,
542 NPRT(jcr->pool->hdr.name),
543 bstrutime(dt, sizeof(dt), jcr->sched_time),
545 } else { /* JT_VERIFY */
547 if (jcr->verify_job) {
548 Name = jcr->verify_job->hdr.name;
553 verify_list = job->WriteVerifyList;
558 bsendmsg(ua, _("Run %s job\n"
571 jcr->fileset->hdr.name,
572 level_to_str(jcr->JobLevel),
573 jcr->client->hdr.name,
574 jcr->store->hdr.name,
575 NPRT(jcr->pool->hdr.name),
578 bstrutime(dt, sizeof(dt), jcr->sched_time),
583 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
585 jcr->RestoreJobId = str_to_int64(jid);
587 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
590 jcr->RestoreJobId = ua->int64_val;
593 jcr->JobLevel = L_FULL; /* default level */
594 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
595 if (jcr->RestoreJobId == 0) {
596 bsendmsg(ua, _("Run Restore job\n"
608 NPRT(jcr->RestoreBootstrap),
609 jcr->where?jcr->where:NPRT(job->RestoreWhere),
611 jcr->fileset->hdr.name,
612 jcr->client->hdr.name,
613 jcr->store->hdr.name,
614 bstrutime(dt, sizeof(dt), jcr->sched_time),
615 jcr->catalog->hdr.name,
618 bsendmsg(ua, _("Run Restore job\n"
630 NPRT(jcr->RestoreBootstrap),
631 jcr->where?jcr->where:NPRT(job->RestoreWhere),
633 jcr->client->hdr.name,
634 jcr->store->hdr.name,
635 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
636 bstrutime(dt, sizeof(dt), jcr->sched_time),
637 jcr->catalog->hdr.name,
642 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
646 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
650 * At user request modify parameters of job to be run.
652 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
655 start_prompt(ua, _("Parameters to modify:\n"));
656 add_prompt(ua, _("Level")); /* 0 */
657 add_prompt(ua, _("Storage")); /* 1 */
658 add_prompt(ua, _("Job")); /* 2 */
659 add_prompt(ua, _("FileSet")); /* 3 */
660 add_prompt(ua, _("Client")); /* 4 */
661 add_prompt(ua, _("When")); /* 5 */
662 add_prompt(ua, _("Priority")); /* 6 */
663 if (jcr->JobType == JT_BACKUP ||
664 jcr->JobType == JT_VERIFY) {
665 add_prompt(ua, _("Pool")); /* 7 */
666 if (jcr->JobType == JT_VERIFY) {
667 add_prompt(ua, _("Verify Job")); /* 8 */
669 } else if (jcr->JobType == JT_RESTORE) {
670 add_prompt(ua, _("Bootstrap")); /* 7 */
671 add_prompt(ua, _("Where")); /* 8 */
672 add_prompt(ua, _("Replace")); /* 9 */
673 add_prompt(ua, _("JobId")); /* 10 */
675 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
678 if (jcr->JobType == JT_BACKUP) {
679 start_prompt(ua, _("Levels:\n"));
680 add_prompt(ua, _("Base"));
681 add_prompt(ua, _("Full"));
682 add_prompt(ua, _("Incremental"));
683 add_prompt(ua, _("Differential"));
684 add_prompt(ua, _("Since"));
685 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
687 jcr->JobLevel = L_BASE;
690 jcr->JobLevel = L_FULL;
693 jcr->JobLevel = L_INCREMENTAL;
696 jcr->JobLevel = L_DIFFERENTIAL;
699 jcr->JobLevel = L_SINCE;
705 } else if (jcr->JobType == JT_VERIFY) {
706 start_prompt(ua, _("Levels:\n"));
707 add_prompt(ua, _("Initialize Catalog"));
708 add_prompt(ua, _("Verify Catalog"));
709 add_prompt(ua, _("Verify Volume to Catalog"));
710 add_prompt(ua, _("Verify Disk to Catalog"));
711 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
712 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
714 jcr->JobLevel = L_VERIFY_INIT;
717 jcr->JobLevel = L_VERIFY_CATALOG;
720 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
723 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
726 jcr->JobLevel = L_VERIFY_DATA;
733 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
738 store = select_storage_resource(ua);
740 set_storage(jcr, store);
746 job = select_job_resource(ua);
749 set_jcr_defaults(jcr, job);
755 fileset = select_fileset_resource(ua);
757 jcr->fileset = fileset;
763 client = select_client_resource(ua);
765 jcr->client = client;
771 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
774 if (ua->cmd[0] == 0) {
775 jcr->sched_time = time(NULL);
777 jcr->sched_time = str_to_utime(ua->cmd);
778 if (jcr->sched_time == 0) {
779 bsendmsg(ua, _("Invalid time, using current time.\n"));
780 jcr->sched_time = time(NULL);
786 if (!get_pint(ua, _("Enter new Priority: "))) {
789 if (ua->pint32_val == 0) {
790 bsendmsg(ua, _("Priority must be a positive integer.\n"));
792 jcr->JobPriority = ua->pint32_val;
796 /* Pool or Bootstrap depending on JobType */
797 if (jcr->JobType == JT_BACKUP ||
798 jcr->JobType == JT_VERIFY) { /* Pool */
799 pool = select_pool_resource(ua);
808 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
811 if (jcr->RestoreBootstrap) {
812 free(jcr->RestoreBootstrap);
813 jcr->RestoreBootstrap = NULL;
815 if (ua->cmd[0] != 0) {
816 jcr->RestoreBootstrap = bstrdup(ua->cmd);
817 fd = fopen(jcr->RestoreBootstrap, "r");
819 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
820 jcr->RestoreBootstrap, strerror(errno));
821 free(jcr->RestoreBootstrap);
822 jcr->RestoreBootstrap = NULL;
830 if (jcr->JobType == JT_VERIFY) {
831 verify_job = select_job_resource(ua);
833 jcr->verify_job = verify_job;
838 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
845 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
848 jcr->where = bstrdup(ua->cmd);
852 start_prompt(ua, _("Replace:\n"));
853 for (i=0; ReplaceOptions[i].name; i++) {
854 add_prompt(ua, ReplaceOptions[i].name);
856 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
858 jcr->replace = ReplaceOptions[opt].token;
863 jid = NULL; /* force reprompt */
864 jcr->RestoreJobId = 0;
865 if (jcr->RestoreBootstrap) {
866 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
869 case -1: /* error or cancel */
877 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
879 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
881 JobId = run_job(jcr);
882 free_jcr(jcr); /* release jcr */
884 bsendmsg(ua, _("Job failed.\n"));
887 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
893 bsendmsg(ua, _("Job not run.\n"));
895 return 0; /* do not run */