3 * Bacula Director -- Run Command
5 * Kern Sibbald, December MMI
11 Copyright (C) 2001-2004 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
33 /* Imported subroutines */
35 /* Imported variables */
36 extern struct s_kw ReplaceOptions[];
39 * For Backup and Verify Jobs
40 * run [job=]<job-name> level=<level-name>
43 * run <job-name> jobid=nn
49 int run_cmd(UAContext *ua, const char *cmd)
52 char *job_name, *level_name, *jid, *store_name, *pool_name;
53 char *where, *fileset_name, *client_name, *bootstrap;
55 char *when, *verify_job_name, *catalog_name;
57 int i, j, opt, files = 0;
60 JOB *verify_job = NULL;
62 CLIENT *client = NULL;
63 FILESET *fileset = NULL;
65 static const char *kw[] = { /* command line arguments */
66 N_("job"), /* Used in a switch() */
70 N_("fileset"), /* 4 */
72 N_("storage"), /* 6 */
76 N_("bootstrap"), /* 10 */
77 N_("replace"), /* 11 */
79 N_("priority"), /* 13 */
80 N_("yes"), /* 14 -- if you change this change YES_POS too */
81 N_("verifyjob"), /* 15 */
82 N_("files"), /* 16 number of files to restore */
83 N_("catalog"), /* 17 override catalog */
103 verify_job_name = NULL;
106 for (i=1; i<ua->argc; i++) {
107 Dmsg2(800, "Doing arg %d = %s\n", i, ua->argk[i]);
109 /* Keep looking until we find a good keyword */
110 for (j=0; !kw_ok && kw[j]; j++) {
111 if (strcasecmp(ua->argk[i], _(kw[j])) == 0) {
112 /* Note, yes and run have no value, so do not err */
113 if (!ua->argv[i] && j != YES_POS /*yes*/) {
114 bsendmsg(ua, _("Value missing for keyword %s\n"), ua->argk[i]);
117 Dmsg1(800, "Got keyword=%s\n", kw[j]);
121 bsendmsg(ua, _("Job name specified twice.\n"));
124 job_name = ua->argv[i];
129 bsendmsg(ua, _("JobId specified twice.\n"));
138 bsendmsg(ua, _("Client specified twice.\n"));
141 client_name = ua->argv[i];
144 case 4: /* fileset */
146 bsendmsg(ua, _("FileSet specified twice.\n"));
149 fileset_name = ua->argv[i];
154 bsendmsg(ua, _("Level specified twice.\n"));
157 level_name = ua->argv[i];
160 case 6: /* storage */
163 bsendmsg(ua, _("Storage specified twice.\n"));
166 store_name = ua->argv[i];
171 bsendmsg(ua, _("Pool specified twice.\n"));
174 pool_name = ua->argv[i];
179 bsendmsg(ua, _("Where specified twice.\n"));
185 case 10: /* bootstrap */
187 bsendmsg(ua, _("Bootstrap specified twice.\n"));
190 bootstrap = ua->argv[i];
193 case 11: /* replace */
195 bsendmsg(ua, _("Replace specified twice.\n"));
198 replace = ua->argv[i];
203 bsendmsg(ua, _("When specified twice.\n"));
209 case 13: /* Priority */
211 bsendmsg(ua, _("Priority specified twice.\n"));
214 Priority = atoi(ua->argv[i]);
216 bsendmsg(ua, _("Priority must be positive nonzero setting it to 10.\n"));
224 case 15: /* Verify Job */
225 if (verify_job_name) {
226 bsendmsg(ua, _("Verify Job specified twice.\n"));
229 verify_job_name = ua->argv[i];
233 files = atoi(ua->argv[i]);
237 case 17: /* catalog */
238 catalog_name = ua->argv[i];
245 } /* end strcase compare */
246 } /* end keyword loop */
248 * End of keyword for loop -- if not found, we got a bogus keyword
251 Dmsg1(200, "%s not found\n", ua->argk[i]);
253 * Special case for Job Name, it can be the first
254 * keyword that has no value.
256 if (!job_name && !ua->argv[i]) {
257 job_name = ua->argk[i]; /* use keyword as job name */
258 Dmsg1(200, "Set jobname=%s\n", job_name);
260 bsendmsg(ua, _("Invalid keyword: %s\n"), ua->argk[i]);
264 } /* end argc loop */
266 Dmsg0(800, "Done scan.\n");
269 if (catalog_name != NULL) {
270 catalog = (CAT *)GetResWithName(R_CATALOG, catalog_name);
271 if (catalog == NULL) {
272 bsendmsg(ua, _("Catalog \"%s\" not found\n"), catalog_name);
276 Dmsg1(200, "Using catalog=%s\n", catalog_name);
280 job = (JOB *)GetResWithName(R_JOB, job_name);
282 if (*job_name != 0) {
283 bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
285 job = select_job_resource(ua);
287 Dmsg1(200, "Found job=%s\n", job_name);
290 bsendmsg(ua, _("A job name must be specified.\n"));
291 job = select_job_resource(ua);
295 } else if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
296 bsendmsg(ua, _("No authorization. Job \"%s\".\n"),
302 store = (STORE *)GetResWithName(R_STORAGE, store_name);
304 if (*store_name != 0) {
305 bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
307 store = select_storage_resource(ua);
310 store = (STORE *)job->storage[0]->first(); /* use default */
314 } else if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
315 bsendmsg(ua, _("No authorization. Storage \"%s\".\n"),
319 Dmsg1(200, "Using storage=%s\n", store->hdr.name);
322 pool = (POOL *)GetResWithName(R_POOL, pool_name);
324 if (*pool_name != 0) {
325 bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
327 pool = select_pool_resource(ua);
330 pool = job->pool; /* use default */
334 } else if (!acl_access_ok(ua, Pool_ACL, store->hdr.name)) {
335 bsendmsg(ua, _("No authorization. Pool \"%s\".\n"),
339 Dmsg1(200, "Using pool\n", pool->hdr.name);
342 client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
344 if (*client_name != 0) {
345 bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
347 client = select_client_resource(ua);
350 client = job->client; /* use default */
354 } else if (!acl_access_ok(ua, Client_ACL, store->hdr.name)) {
355 bsendmsg(ua, _("No authorization. Client \"%s\".\n"),
359 Dmsg1(200, "Using client=%s\n", client->hdr.name);
362 fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
364 bsendmsg(ua, _("FileSet \"%s\" not found.\n"), fileset_name);
365 fileset = select_fileset_resource(ua);
368 fileset = job->fileset; /* use default */
372 } else if (!acl_access_ok(ua, FileSet_ACL, store->hdr.name)) {
373 bsendmsg(ua, _("No authorization. FileSet \"%s\".\n"),
378 if (verify_job_name) {
379 verify_job = (JOB *)GetResWithName(R_JOB, verify_job_name);
381 bsendmsg(ua, _("Verify Job \"%s\" not found.\n"), verify_job_name);
382 verify_job = select_job_resource(ua);
385 verify_job = job->verify_job;
389 * Create JCR to run job. NOTE!!! after this point, free_jcr()
392 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
393 set_jcr_defaults(jcr, job);
395 jcr->verify_job = verify_job;
397 /* If specific name given, zap all other stores */
399 for (i=0; i < MAX_STORE; i++) {
400 jcr->storage[i] = NULL;
403 jcr->client = client;
404 jcr->fileset = fileset;
406 jcr->ExpectedFiles = files;
407 if (catalog != NULL) {
408 jcr->catalog = catalog;
414 jcr->where = bstrdup(where);
418 jcr->sched_time = str_to_utime(when);
419 if (jcr->sched_time == 0) {
420 bsendmsg(ua, _("Invalid time, using current time.\n"));
421 jcr->sched_time = time(NULL);
426 if (jcr->RestoreBootstrap) {
427 free(jcr->RestoreBootstrap);
429 jcr->RestoreBootstrap = bstrdup(bootstrap);
434 for (i=0; ReplaceOptions[i].name; i++) {
435 if (strcasecmp(replace, ReplaceOptions[i].name) == 0) {
436 jcr->replace = ReplaceOptions[i].token;
440 bsendmsg(ua, _("Invalid replace option: %s\n"), replace);
443 } else if (job->replace) {
444 jcr->replace = job->replace;
446 jcr->replace = REPLACE_ALWAYS;
450 jcr->JobPriority = Priority;
453 if (find_arg(ua, _("fdcalled")) > 0) {
454 jcr->file_bsock = dup_bsock(ua->UA_sock);
459 replace = ReplaceOptions[0].name;
460 for (i=0; ReplaceOptions[i].name; i++) {
461 if (ReplaceOptions[i].token == jcr->replace) {
462 replace = ReplaceOptions[i].name;
466 if (!get_level_from_name(jcr, level_name)) {
467 bsendmsg(ua, _("Level %s not valid.\n"), level_name);
472 jcr->RestoreJobId = atoi(jid);
475 /* Run without prompting? */
476 if (ua->batch || find_arg(ua, _("yes")) > 0) {
481 * Prompt User to see if all run job parameters are correct, and
482 * allow him to modify them.
484 Dmsg1(20, "JobType=%c\n", jcr->JobType);
485 switch (jcr->JobType) {
487 char dt[MAX_TIME_LENGTH];
489 bsendmsg(ua, _("Run %s job\n\
498 jcr->fileset->hdr.name,
499 NPRT(jcr->client->hdr.name),
500 NPRT(jcr->store->hdr.name),
501 bstrutime(dt, sizeof(dt), jcr->sched_time),
503 jcr->JobLevel = L_FULL;
507 if (jcr->JobType == JT_BACKUP) {
508 bsendmsg(ua, _("Run %s job\n\
519 jcr->fileset->hdr.name,
520 level_to_str(jcr->JobLevel),
521 jcr->client->hdr.name,
522 jcr->store->hdr.name,
523 NPRT(jcr->pool->hdr.name),
524 bstrutime(dt, sizeof(dt), jcr->sched_time),
526 } else { /* JT_VERIFY */
528 if (jcr->verify_job) {
529 Name = jcr->verify_job->hdr.name;
533 bsendmsg(ua, _("Run %s job\n\
545 jcr->fileset->hdr.name,
546 level_to_str(jcr->JobLevel),
547 jcr->client->hdr.name,
548 jcr->store->hdr.name,
549 NPRT(jcr->pool->hdr.name),
551 bstrutime(dt, sizeof(dt), jcr->sched_time),
556 if (jcr->RestoreJobId == 0 && !jcr->RestoreBootstrap) {
558 jcr->RestoreJobId = atoi(jid);
560 if (!get_pint(ua, _("Please enter a JobId for restore: "))) {
563 jcr->RestoreJobId = ua->pint32_val;
566 jcr->JobLevel = L_FULL; /* default level */
567 Dmsg1(20, "JobId to restore=%d\n", jcr->RestoreJobId);
568 if (jcr->RestoreJobId == 0) {
569 bsendmsg(ua, _("Run Restore job\n"
581 NPRT(jcr->RestoreBootstrap),
582 jcr->where?jcr->where:NPRT(job->RestoreWhere),
584 jcr->fileset->hdr.name,
585 jcr->client->hdr.name,
586 jcr->store->hdr.name,
587 bstrutime(dt, sizeof(dt), jcr->sched_time),
588 jcr->catalog->hdr.name,
591 bsendmsg(ua, _("Run Restore job\n"
603 NPRT(jcr->RestoreBootstrap),
604 jcr->where?jcr->where:NPRT(job->RestoreWhere),
606 jcr->client->hdr.name,
607 jcr->store->hdr.name,
608 jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
609 bstrutime(dt, sizeof(dt), jcr->sched_time),
610 jcr->catalog->hdr.name,
615 bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
620 if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) {
624 * At user request modify parameters of job to be run.
626 if (ua->cmd[0] == 0) {
629 if (strncasecmp(ua->cmd, _("mod"), strlen(ua->cmd)) == 0) {
632 start_prompt(ua, _("Parameters to modify:\n"));
633 add_prompt(ua, _("Level")); /* 0 */
634 add_prompt(ua, _("Storage")); /* 1 */
635 add_prompt(ua, _("Job")); /* 2 */
636 add_prompt(ua, _("FileSet")); /* 3 */
637 add_prompt(ua, _("Client")); /* 4 */
638 add_prompt(ua, _("When")); /* 5 */
639 add_prompt(ua, _("Priority")); /* 6 */
640 if (jcr->JobType == JT_BACKUP ||
641 jcr->JobType == JT_VERIFY) {
642 add_prompt(ua, _("Pool")); /* 7 */
643 if (jcr->JobType == JT_VERIFY) {
644 add_prompt(ua, _("Verify Job")); /* 8 */
646 } else if (jcr->JobType == JT_RESTORE) {
647 add_prompt(ua, _("Bootstrap")); /* 7 */
648 add_prompt(ua, _("Where")); /* 8 */
649 add_prompt(ua, _("Replace")); /* 9 */
650 add_prompt(ua, _("JobId")); /* 10 */
652 switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
655 if (jcr->JobType == JT_BACKUP) {
656 start_prompt(ua, _("Levels:\n"));
657 add_prompt(ua, _("Base"));
658 add_prompt(ua, _("Full"));
659 add_prompt(ua, _("Incremental"));
660 add_prompt(ua, _("Differential"));
661 add_prompt(ua, _("Since"));
662 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
664 jcr->JobLevel = L_BASE;
667 jcr->JobLevel = L_FULL;
670 jcr->JobLevel = L_INCREMENTAL;
673 jcr->JobLevel = L_DIFFERENTIAL;
676 jcr->JobLevel = L_SINCE;
682 } else if (jcr->JobType == JT_VERIFY) {
683 start_prompt(ua, _("Levels:\n"));
684 add_prompt(ua, _("Initialize Catalog"));
685 add_prompt(ua, _("Verify Catalog"));
686 add_prompt(ua, _("Verify Volume to Catalog"));
687 add_prompt(ua, _("Verify Disk to Catalog"));
688 add_prompt(ua, _("Verify Volume Data (not yet implemented)"));
689 switch (do_prompt(ua, "", _("Select level"), NULL, 0)) {
691 jcr->JobLevel = L_VERIFY_INIT;
694 jcr->JobLevel = L_VERIFY_CATALOG;
697 jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
700 jcr->JobLevel = L_VERIFY_DISK_TO_CATALOG;
703 jcr->JobLevel = L_VERIFY_DATA;
710 bsendmsg(ua, _("Level not appropriate for this Job. Cannot be changed.\n"));
715 store = select_storage_resource(ua);
723 job = select_job_resource(ua);
726 set_jcr_defaults(jcr, job);
732 fileset = select_fileset_resource(ua);
734 jcr->fileset = fileset;
740 client = select_client_resource(ua);
742 jcr->client = client;
748 if (!get_cmd(ua, _("Please enter desired start time as YYYY-MM-DD HH:MM:SS (return for now): "))) {
751 if (ua->cmd[0] == 0) {
752 jcr->sched_time = time(NULL);
754 jcr->sched_time = str_to_utime(ua->cmd);
755 if (jcr->sched_time == 0) {
756 bsendmsg(ua, _("Invalid time, using current time.\n"));
757 jcr->sched_time = time(NULL);
763 if (!get_pint(ua, _("Enter new Priority: "))) {
766 if (ua->pint32_val == 0) {
767 bsendmsg(ua, _("Priority must be a positive integer.\n"));
769 jcr->JobPriority = ua->pint32_val;
773 /* Pool or Bootstrap depending on JobType */
774 if (jcr->JobType == JT_BACKUP ||
775 jcr->JobType == JT_VERIFY) { /* Pool */
776 pool = select_pool_resource(ua);
785 if (!get_cmd(ua, _("Please enter the Bootstrap file name: "))) {
788 if (jcr->RestoreBootstrap) {
789 free(jcr->RestoreBootstrap);
790 jcr->RestoreBootstrap = NULL;
792 if (ua->cmd[0] != 0) {
793 jcr->RestoreBootstrap = bstrdup(ua->cmd);
794 fd = fopen(jcr->RestoreBootstrap, "r");
796 bsendmsg(ua, _("Warning cannot open %s: ERR=%s\n"),
797 jcr->RestoreBootstrap, strerror(errno));
798 free(jcr->RestoreBootstrap);
799 jcr->RestoreBootstrap = NULL;
807 if (jcr->JobType == JT_VERIFY) {
808 verify_job = select_job_resource(ua);
810 jcr->verify_job = verify_job;
815 if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) {
822 if (ua->cmd[0] == '/' && ua->cmd[1] == 0) {
825 jcr->where = bstrdup(ua->cmd);
829 start_prompt(ua, _("Replace:\n"));
830 for (i=0; ReplaceOptions[i].name; i++) {
831 add_prompt(ua, ReplaceOptions[i].name);
833 opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
835 jcr->replace = ReplaceOptions[opt].token;
840 jid = NULL; /* force reprompt */
841 jcr->RestoreJobId = 0;
842 if (jcr->RestoreBootstrap) {
843 bsendmsg(ua, _("You must set the bootstrap file to NULL to be able to specify a JobId.\n"));
852 if (strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) {
854 Dmsg1(200, "Calling run_job job=%x\n", jcr->job);
856 JobId = run_job(jcr);
857 free_jcr(jcr); /* release jcr */
859 bsendmsg(ua, _("Job failed.\n"));
861 bsendmsg(ua, _("Job started. JobId=%u\n"), JobId);
867 bsendmsg(ua, _("Job not run.\n"));
869 return 0; /* do not run */