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 ammended 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;
53 int i, j, opt, files = 0;
56 JOB *verify_job = NULL;
58 CLIENT *client = NULL;
59 FILESET *fileset = NULL;
61 static const char *kw[] = { /* command line arguments */
62 "job", /* Used in a switch() */
76 "yes", /* 14 -- if you change this change YES_POS too */
78 "files", /* 16 number of files to restore */
79 "catalog", /* 17 override catalog */
80 "since", /* 18 since */
81 "cloned", /* 19 cloned */
101 verify_job_name = NULL;
104 for (i=1; i<ua->argc; i++) {
105 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
107 /* Keep looking until we find a good keyword */
108 for (j=0; !kw_ok && kw[j]; j++) {
109 if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
110 /* Note, yes and run have no value, so do not err */
111 if (!ua->argv[i] && j != YES_POS /*yes*/) {
112 bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
115 Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
119 bsendmsg(ua, _("Job name specified twice.\n"));
122 job_name = ua->argv[i];
127 bsendmsg(ua, _("JobId specified twice.\n"));
136 bsendmsg(ua, _("Client specified twice.\n"));
139 client_name = ua->argv[i];
142 case 4: /* fileset */
144 bsendmsg(ua, _("FileSet specified twice.\n"));
147 fileset_name = ua->argv[i];
152 bsendmsg(ua, _("Level specified twice.\n"));
155 level_name = ua->argv[i];
158 case 6: /* storage */
161 bsendmsg(ua, _("Storage specified twice.\n"));
164 store_name = ua->argv[i];
169 bsendmsg(ua, _("Pool specified twice.\n"));
172 pool_name = ua->argv[i];
177 bsendmsg(ua, _("Where specified twice.\n"));
183 case 10: /* bootstrap */
185 bsendmsg(ua, _("Bootstrap specified twice.\n"));
188 bootstrap = ua->argv[i];
191 case 11: /* replace */
193 bsendmsg(ua, _("Replace specified twice.\n"));
196 replace = ua->argv[i];
201 bsendmsg(ua, _("When specified twice.\n"));
207 case 13: /* Priority */
209 bsendmsg(ua, _("Priority specified twice.\n"));
212 Priority = atoi(ua->argv[i]);
214 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
222 case 15: /* Verify Job */
223 if (verify_job_name) {
224 bsendmsg(ua, _("Verify Job specified twice.\n"));
227 verify_job_name = ua->argv[i];
231 files = atoi(ua->argv[i]);
235 case 17: /* catalog */
236 catalog_name = ua->argv[i];
245 case 19: /* cloned */
253 } /* end strcase compare */
254 } /* end keyword loop */
256 * End of keyword for loop -- if not found, we got a bogus keyword
259 Dmsg1(800, "%s not found\n", ua->argk[i]);
261 * Special case for Job Name, it can be the first
262 * keyword that has no value.
264 if (!job_name && !ua->argv[i]) {
265 job_name = ua->argk[i]; /* use keyword as job name */
266 Dmsg1(800, "Set jobname=%s\n", job_name);
268 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
272 } /* end argc loop */
274 Dmsg0(800, "Done scan.\n");
277 if (catalog_name != NULL) {
278 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
279 if (catalog == NULL) {
280 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
284 Dmsg1(800, "Using catalog=%s\n", NPRT(catalog_name));
288 job = (JOB *)GetResWithName(R_JOB, job_name);
290 if (*job_name != 0) {
291 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
293 job = select_job_resource(ua);
295 Dmsg1(800, "Found job=%s\n", job_name);
298 bsendmsg(ua, _("A job name must be specified.\n"));
299 job = select_job_resource(ua);
303 } else if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
304 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
310 store = (STORE *)GetResWithName(R_STORAGE, store_name);
312 if (*store_name != 0) {
313 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
315 store = select_storage_resource(ua);
318 store = (STORE *)job->storage->first(); /* use default */
322 } else if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
323 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
327 Dmsg1(800, "Using storage=%s\n", store->hdr.name);
330 pool = (POOL *)GetResWithName(R_POOL, pool_name);
332 if (*pool_name != 0) {
333 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
335 pool = select_pool_resource(ua);
338 pool = job->pool; /* use default */
342 } else if (!acl_access_ok(ua, Pool_ACL, pool->hdr.name)) {
343 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
347 Dmsg1(800, "Using pool\n", pool->hdr.name);
350 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
352 if (*client_name != 0) {
353 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
355 client = select_client_resource(ua);
358 client = job->client; /* use default */
362 } else if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) {
363 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
367 Dmsg1(800, "Using client=%s\n", client->hdr.name);
370 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
372 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
373 fileset = select_fileset_resource(ua);
376 fileset = job->fileset; /* use default */
380 } else if (!acl_access_ok(ua, FileSet_ACL, fileset->hdr.name)) {
381 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
386 if (verify_job_name) {
387 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
389 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
390 verify_job = select_job_resource(ua);
393 verify_job = job->verify_job;
397 * Create JCR to run job. NOTE!!! after this point, free_jcr()
400 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
401 set_jcr_defaults(jcr, job);
403 jcr->verify_job = verify_job;
404 set_storage(jcr, store);
405 jcr->client = client;
406 jcr->fileset = fileset;
408 jcr->ExpectedFiles = files;
409 if (catalog != NULL) {
410 jcr->catalog = catalog;
416 jcr->where = bstrdup(where);
420 jcr->sched_time = str_to_utime(when);
421 if (jcr->sched_time == 0) {
422 bsendmsg(ua, _("Invalid time, using current time.\n"));
423 jcr->sched_time = time(NULL);
428 if (jcr->RestoreBootstrap) {
429 free(jcr->RestoreBootstrap);
431 jcr->RestoreBootstrap = bstrdup(bootstrap);
436 for (i=0; ReplaceOptions[i].name; i++) {
437 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
438 jcr->replace = ReplaceOptions[i].token;
442 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
445 } else if (job->replace) {
446 jcr->replace = job->replace;
448 jcr->replace = REPLACE_ALWAYS;
452 jcr->JobPriority = Priority;
457 jcr->stime = get_pool_memory(PM_MESSAGE);
459 pm_strcpy(jcr->stime, since);
462 jcr->cloned = cloned;
464 if (find_arg(ua, _("fdcalled")) > 0) {
465 jcr->file_bsock = dup_bsock(ua->UA_sock);
470 replace = ReplaceOptions[0].name;
471 for (i=0; ReplaceOptions[i].name; i++) {
472 if (ReplaceOptions[i].token == jcr->replace) {
473 replace = ReplaceOptions[i].name;
477 if (!get_level_from_name(jcr, level_name)) {
478 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
483 jcr->RestoreJobId = str_to_int64(jid);
486 /* Run without prompting? */
487 if (ua->batch || find_arg(ua, _("yes")) > 0) {
492 * Prompt User to see if all run job parameters are correct, and
493 * allow him to modify them.
495 Dmsg1(800, "JobType=%c\n", jcr->JobType);
496 switch (jcr->JobType) {
498 char dt[MAX_TIME_LENGTH];
500 bsendmsg(ua, _("Run %s job\n"
509 jcr->fileset->hdr.name,
510 NPRT(jcr->client->hdr.name),
511 NPRT(jcr->store->hdr.name),
512 bstrutime(dt, sizeof(dt), jcr->sched_time),
514 jcr->JobLevel = L_FULL;
518 if (jcr->JobType == JT_BACKUP) {
519 bsendmsg(ua, _("Run %s job\n"
530 jcr->fileset->hdr.name,
531 level_to_str(jcr->JobLevel),
532 jcr->client->hdr.name,
533 jcr->store->hdr.name,
534 NPRT(jcr->pool->hdr.name),
535 bstrutime(dt, sizeof(dt), jcr->sched_time),
537 } else { /* JT_VERIFY */
539 if (jcr->verify_job) {
540 Name = jcr->verify_job->hdr.name;
544 bsendmsg(ua, _("Run %s job\n"
556 jcr->fileset->hdr.name,
557 level_to_str(jcr->JobLevel),
558 jcr->client->hdr.name,
559 jcr->store->hdr.name,
560 NPRT(jcr->pool->hdr.name),
562 bstrutime(dt, sizeof(dt), jcr->sched_time),
567 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
569 jcr->RestoreJobId = str_to_int64(jid);
571 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
574 jcr->RestoreJobId = ua->int64_val;
577 jcr->JobLevel = L_FULL; /* default level */
578 Dmsg1(800, "JobId to restore=%d\n", jcr->RestoreJobId);
579 if (jcr->RestoreJobId == 0) {
580 bsendmsg(ua, _("Run Restore job\n"
592 NPRT(jcr->RestoreBootstrap),
593 jcr->where?jcr->where:NPRT(job->RestoreWhere),
595 jcr->fileset->hdr.name,
596 jcr->client->hdr.name,
597 jcr->store->hdr.name,
598 bstrutime(dt, sizeof(dt), jcr->sched_time),
599 jcr->catalog->hdr.name,
602 bsendmsg(ua, _("Run Restore job\n"
614 NPRT(jcr->RestoreBootstrap),
615 jcr->where?jcr->where:NPRT(job->RestoreWhere),
617 jcr->client->hdr.name,
618 jcr->store->hdr.name,
619 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
620 bstrutime(dt, sizeof(dt), jcr->sched_time),
621 jcr->catalog->hdr.name,
626 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
631 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
635 * At user request modify parameters of job to be run.
637 if (ua->cmd[0] != 0 && strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
640 start_prompt(ua, _("Parameters to modify:\n"));
641 add_prompt(ua, _("Level")); /* 0 */
642 add_prompt(ua, _("Storage")); /* 1 */
643 add_prompt(ua, _("Job")); /* 2 */
644 add_prompt(ua, _("FileSet")); /* 3 */
645 add_prompt(ua, _("Client")); /* 4 */
646 add_prompt(ua, _("When")); /* 5 */
647 add_prompt(ua, _("Priority")); /* 6 */
648 if (jcr->JobType == JT_BACKUP ||
649 jcr->JobType == JT_VERIFY) {
650 add_prompt(ua, _("Pool")); /* 7 */
651 if (jcr->JobType == JT_VERIFY) {
652 add_prompt(ua, _("Verify Job")); /* 8 */
654 } else if (jcr->JobType == JT_RESTORE) {
655 add_prompt(ua, _("Bootstrap")); /* 7 */
656 add_prompt(ua, _("Where")); /* 8 */
657 add_prompt(ua, _("Replace")); /* 9 */
658 add_prompt(ua, _("JobId")); /* 10 */
660 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
663 if (jcr->JobType == JT_BACKUP) {
664 start_prompt(ua, _("Levels:\n"));
665 add_prompt(ua, _("Base"));
666 add_prompt(ua, _("Full"));
667 add_prompt(ua, _("Incremental"));
668 add_prompt(ua, _("Differential"));
669 add_prompt(ua, _("Since"));
670 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
672 jcr->JobLevel = L_BASE;
675 jcr->JobLevel = L_FULL;
678 jcr->JobLevel = L_INCREMENTAL;
681 jcr->JobLevel = L_DIFFERENTIAL;
684 jcr->JobLevel = L_SINCE;
690 } else if (jcr->JobType == JT_VERIFY) {
691 start_prompt(ua, _("Levels:\n"));
692 add_prompt(ua, _("Initialize Catalog"));
693 add_prompt(ua, _("Verify Catalog"));
694 add_prompt(ua, _("Verify Volume to Catalog"));
695 add_prompt(ua, _("Verify Disk to Catalog"));
696 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
697 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
699 jcr->JobLevel = L_VERIFY_INIT;
702 jcr->JobLevel = L_VERIFY_CATALOG;
705 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
708 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
711 jcr->JobLevel = L_VERIFY_DATA;
718 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
723 store = select_storage_resource(ua);
725 set_storage(jcr, store);
731 job = select_job_resource(ua);
734 set_jcr_defaults(jcr, job);
740 fileset = select_fileset_resource(ua);
742 jcr->fileset = fileset;
748 client = select_client_resource(ua);
750 jcr->client = client;
756 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
759 if (ua->cmd[0] == 0) {
760 jcr->sched_time = time(NULL);
762 jcr->sched_time = str_to_utime(ua->cmd);
763 if (jcr->sched_time == 0) {
764 bsendmsg(ua, _("Invalid time, using current time.\n"));
765 jcr->sched_time = time(NULL);
771 if (!get_pint(ua, _("Enter new Priority: "))) {
774 if (ua->pint32_val == 0) {
775 bsendmsg(ua, _("Priority must be a positive integer.\n"));
777 jcr->JobPriority = ua->pint32_val;
781 /* Pool or Bootstrap depending on JobType */
782 if (jcr->JobType == JT_BACKUP ||
783 jcr->JobType == JT_VERIFY) { /* Pool */
784 pool = select_pool_resource(ua);
793 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
796 if (jcr->RestoreBootstrap) {
797 free(jcr->RestoreBootstrap);
798 jcr->RestoreBootstrap = NULL;
800 if (ua->cmd[0] != 0) {
801 jcr->RestoreBootstrap = bstrdup(ua->cmd);
802 fd = fopen(jcr->RestoreBootstrap, "r");
804 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
805 jcr->RestoreBootstrap, strerror(errno));
806 free(jcr->RestoreBootstrap);
807 jcr->RestoreBootstrap = NULL;
815 if (jcr->JobType == JT_VERIFY) {
816 verify_job = select_job_resource(ua);
818 jcr->verify_job = verify_job;
823 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
830 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
833 jcr->where = bstrdup(ua->cmd);
837 start_prompt(ua, _("Replace:\n"));
838 for (i=0; ReplaceOptions[i].name; i++) {
839 add_prompt(ua, ReplaceOptions[i].name);
841 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
843 jcr->replace = ReplaceOptions[opt].token;
848 jid = NULL; /* force reprompt */
849 jcr->RestoreJobId = 0;
850 if (jcr->RestoreBootstrap) {
851 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
860 if (ua->cmd[0] == 0 || strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
862 Dmsg1(800, "Calling run_job job=%x\n", jcr->job);
864 JobId = run_job(jcr);
865 free_jcr(jcr); /* release jcr */
867 bsendmsg(ua, _("Job failed.\n"));
870 bsendmsg(ua, _("Job started. JobId=%s\n"), edit_int64(JobId,ed1));
876 bsendmsg(ua, _("Job not run.\n"));
878 return 0; /* do not run */