3 * Bacula Director Job processing routines
5 * Kern Sibbald, October MM
10 Copyright (C) 2000-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 /* Forward referenced subroutines */
28 static void *job_thread(void *arg);
29 static void job_monitor_watchdog(watchdog_t *self);
30 static void job_monitor_destructor(watchdog_t *self);
31 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
32 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
34 /* Imported subroutines */
35 extern void term_scheduler();
36 extern void term_ua_server();
38 /* Imported variables */
39 extern time_t watchdog_time;
43 void init_job_server(int max_workers)
48 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
50 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror(stat));
53 wd->callback = job_monitor_watchdog;
54 wd->destructor = job_monitor_destructor;
57 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
58 register_watchdog(wd);
61 void term_job_server()
63 jobq_destroy(&job_queue); /* ignore any errors */
67 * Run a job -- typically called by the scheduler, but may also
68 * be called by the UA (Console program).
70 * Returns: 0 on failure
74 JobId_t run_job(JCR *jcr)
78 /* Queue the job to be run */
79 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
81 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
89 bool setup_job(JCR *jcr)
94 sm_check(__FILE__, __LINE__, true);
95 init_msg(jcr, jcr->messages);
97 /* Initialize termination condition variable */
98 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
100 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
103 jcr->term_wait_inited = true;
105 create_unique_job_name(jcr, jcr->job->hdr.name);
106 set_jcr_job_status(jcr, JS_Created);
112 Dmsg0(50, "Open database\n");
113 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
114 jcr->catalog->db_password, jcr->catalog->db_address,
115 jcr->catalog->db_port, jcr->catalog->db_socket,
116 jcr->catalog->mult_db_connections);
117 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
118 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
119 jcr->catalog->db_name);
121 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
125 Dmsg0(50, "DB opened\n");
130 init_jcr_job_record(jcr);
131 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
132 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
135 jcr->JobId = jcr->jr.JobId;
136 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
137 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
139 generate_daemon_event(jcr, "JobStart");
141 if (!get_or_create_client_record(jcr)) {
145 if (job_canceled(jcr)) {
149 Dmsg0(200, "Add jrc to work queue\n");
156 free_memory(jcr->fname);
164 * This is the engine called by jobq.c:jobq_add() when we were pulled
165 * from the work queue.
166 * At this point, we are running in our own thread and all
167 * necessary resources are allocated -- see jobq.c
169 static void *job_thread(void *arg)
171 JCR *jcr = (JCR *)arg;
173 jcr->my_thread_id = pthread_self();
174 pthread_detach(jcr->my_thread_id);
175 sm_check(__FILE__, __LINE__, true);
177 Dmsg0(200, "=====Start Job=========\n");
178 jcr->start_time = time(NULL); /* set the real start time */
179 jcr->jr.StartTime = jcr->start_time;
181 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
182 (utime_t)(jcr->start_time - jcr->sched_time)) {
183 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
184 set_jcr_job_status(jcr, JS_Canceled);
188 * Note, we continue, even if the job is canceled above. This
189 * will permit proper setting of the job start record and
190 * the error (cancel) will be picked up below.
193 generate_job_event(jcr, "JobInit");
194 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
197 jcr->fname = get_pool_memory(PM_FNAME);
201 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
202 * this allows us to setup a proper job start record for restarting
203 * in case of later errors.
205 switch (jcr->JobType) {
207 if (!do_backup_init(jcr)) {
208 backup_cleanup(jcr, JS_ErrorTerminated);
212 if (!do_verify_init(jcr)) {
213 verify_cleanup(jcr, JS_ErrorTerminated);
217 if (!do_restore_init(jcr)) {
218 restore_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_admin_init(jcr)) {
223 admin_cleanup(jcr, JS_ErrorTerminated);
227 if (!do_migration_init(jcr)) {
228 migration_cleanup(jcr, JS_ErrorTerminated);
232 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
233 set_jcr_job_status(jcr, JS_ErrorTerminated);
237 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
238 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
241 if (job_canceled(jcr)) {
242 update_job_end_record(jcr);
247 if (jcr->job->RunBeforeJob) {
248 POOLMEM *before = get_pool_memory(PM_FNAME);
251 char line[MAXSTRING];
253 before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
254 bpipe = open_bpipe(before, 0, "r");
255 free_pool_memory(before);
256 while (fgets(line, sizeof(line), bpipe->rfd)) {
257 Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
259 status = close_bpipe(bpipe);
262 Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
263 set_jcr_job_status(jcr, JS_FatalError);
264 update_job_end_record(jcr);
269 * We re-update the job start record so that the start
270 * time is set after the run before job. This avoids
271 * that any files created by the run before job will
272 * be saved twice. They will be backed up in the current
273 * job, but not in the next one unless they are changed.
274 * Without this, they will be backed up in this job and
275 * in the next job run because in that case, their date
276 * is after the start of this run.
278 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
279 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
281 generate_job_event(jcr, "JobRun");
283 switch (jcr->JobType) {
285 if (do_backup(jcr)) {
288 backup_cleanup(jcr, JS_ErrorTerminated);
292 if (do_verify(jcr)) {
295 verify_cleanup(jcr, JS_ErrorTerminated);
299 if (do_restore(jcr)) {
302 restore_cleanup(jcr, JS_ErrorTerminated);
309 admin_cleanup(jcr, JS_ErrorTerminated);
315 if (do_migration(jcr)) {
318 migration_cleanup(jcr, JS_ErrorTerminated);
322 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
325 if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
326 (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
327 POOLMEM *after = get_pool_memory(PM_FNAME);
330 char line[MAXSTRING];
332 if (jcr->JobStatus == JS_Terminated) {
333 after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
335 after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
337 bpipe = open_bpipe(after, 0, "r");
338 free_pool_memory(after);
339 while (fgets(line, sizeof(line), bpipe->rfd)) {
340 Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
342 status = close_bpipe(bpipe);
344 * Note, if we get an error here, do not mark the
345 * job in error, simply report the error condition.
349 if (jcr->JobStatus == JS_Terminated) {
350 Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
352 Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
356 /* Send off any queued messages */
357 if (jcr->msg_queue->size() > 0) {
358 dequeue_messages(jcr);
363 generate_daemon_event(jcr, "JobEnd");
364 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
365 sm_check(__FILE__, __LINE__, true);
371 * Cancel a job -- typically called by the UA (Console program), but may also
372 * be called by the job watchdog.
374 * Returns: true if cancel appears to be successful
375 * false on failure. Message sent to ua->jcr.
377 bool cancel_job(UAContext *ua, JCR *jcr)
381 set_jcr_job_status(jcr, JS_Canceled);
383 switch (jcr->JobStatus) {
386 case JS_WaitClientRes:
387 case JS_WaitStoreRes:
388 case JS_WaitPriority:
390 case JS_WaitStartTime:
391 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
392 jcr->JobId, jcr->Job);
393 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
397 /* Cancel File daemon */
398 if (jcr->file_bsock) {
399 ua->jcr->client = jcr->client;
400 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
401 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
404 Dmsg0(200, "Connected to file daemon\n");
405 fd = ua->jcr->file_bsock;
406 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
407 while (bnet_recv(fd) >= 0) {
408 bsendmsg(ua, "%s", fd->msg);
410 bnet_sig(fd, BNET_TERMINATE);
412 ua->jcr->file_bsock = NULL;
415 /* Cancel Storage daemon */
416 if (jcr->store_bsock) {
417 if (!ua->jcr->storage) {
418 copy_storage(ua->jcr, jcr->storage);
420 set_storage(ua->jcr, jcr->store);
422 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
423 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
426 Dmsg0(200, "Connected to storage daemon\n");
427 sd = ua->jcr->store_bsock;
428 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
429 while (bnet_recv(sd) >= 0) {
430 bsendmsg(ua, "%s", sd->msg);
432 bnet_sig(sd, BNET_TERMINATE);
434 ua->jcr->store_bsock = NULL;
442 static void job_monitor_destructor(watchdog_t *self)
444 JCR *control_jcr = (JCR *)self->data;
446 free_jcr(control_jcr);
449 static void job_monitor_watchdog(watchdog_t *self)
451 JCR *control_jcr, *jcr;
453 control_jcr = (JCR *)self->data;
455 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
460 if (jcr->JobId == 0) {
461 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
466 /* check MaxWaitTime */
467 cancel = job_check_maxwaittime(control_jcr, jcr);
469 /* check MaxRunTime */
470 cancel |= job_check_maxruntime(control_jcr, jcr);
473 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
474 jcr, jcr->JobId, jcr->Job);
476 UAContext *ua = new_ua_context(jcr);
477 ua->jcr = control_jcr;
481 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
484 /* Keep reference counts correct */
490 * Check if the maxwaittime has expired and it is possible
493 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
496 bool ok_to_cancel = false;
499 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
500 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
503 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
504 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
506 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
507 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
509 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
510 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
512 } else if (job->MaxWaitTime != 0 &&
513 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
519 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
521 jcr->JobId, jcr->Job, job->MaxWaitTime);
522 switch (jcr->JobStatus) {
527 case JS_WaitStoreRes:
528 case JS_WaitClientRes:
530 case JS_WaitPriority:
532 case JS_WaitStartTime:
534 Dmsg0(200, "JCR blocked in #1\n");
537 Dmsg0(800, "JCR running, checking SD status\n");
538 switch (jcr->SDJobStatus) {
543 Dmsg0(800, "JCR blocked in #2\n");
546 Dmsg0(800, "JCR not blocked in #2\n");
551 case JS_ErrorTerminated:
554 Dmsg0(800, "JCR already dead in #3\n");
557 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
560 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
561 cancel ? "" : "do not ", jcr, jcr->job);
567 * Check if maxruntime has expired and if the job can be
570 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
574 if (jcr->job->MaxRunTime == 0) {
577 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
578 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
579 jcr, jcr->Job, jcr->job->MaxRunTime);
583 switch (jcr->JobStatus) {
589 case JS_WaitStoreRes:
590 case JS_WaitClientRes:
592 case JS_WaitPriority:
594 case JS_WaitStartTime:
599 case JS_ErrorTerminated:
605 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
609 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
610 cancel ? "" : "do not ", jcr, jcr->job);
617 * Get or create a Client record for this Job
619 bool get_or_create_client_record(JCR *jcr)
623 memset(&cr, 0, sizeof(cr));
624 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
625 cr.AutoPrune = jcr->client->AutoPrune;
626 cr.FileRetention = jcr->client->FileRetention;
627 cr.JobRetention = jcr->client->JobRetention;
628 if (!jcr->client_name) {
629 jcr->client_name = get_pool_memory(PM_NAME);
631 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
632 if (!db_create_client_record(jcr, jcr->db, &cr)) {
633 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
634 db_strerror(jcr->db));
637 jcr->jr.ClientId = cr.ClientId;
639 if (!jcr->client_uname) {
640 jcr->client_uname = get_pool_memory(PM_NAME);
642 pm_strcpy(jcr->client_uname, cr.Uname);
644 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
649 bool get_or_create_fileset_record(JCR *jcr)
653 * Get or Create FileSet record
655 memset(&fsr, 0, sizeof(FILESET_DBR));
656 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
657 if (jcr->fileset->have_MD5) {
658 struct MD5Context md5c;
659 unsigned char digest[MD5HashSize];
660 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
661 MD5Final(digest, &md5c);
662 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
663 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
665 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
667 if (!jcr->fileset->ignore_fs_changes ||
668 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
669 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
670 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
671 fsr.FileSet, db_strerror(jcr->db));
675 jcr->jr.FileSetId = fsr.FileSetId;
676 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
677 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
682 void init_jcr_job_record(JCR *jcr)
684 jcr->jr.SchedTime = jcr->sched_time;
685 jcr->jr.StartTime = jcr->start_time;
686 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
687 jcr->jr.JobType = jcr->JobType;
688 jcr->jr.JobLevel = jcr->JobLevel;
689 jcr->jr.JobStatus = jcr->JobStatus;
690 jcr->jr.JobId = jcr->JobId;
691 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
692 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
696 * Write status and such in DB
698 void update_job_end_record(JCR *jcr)
700 jcr->jr.EndTime = time(NULL);
701 jcr->end_time = jcr->jr.EndTime;
702 jcr->jr.JobId = jcr->JobId;
703 jcr->jr.JobStatus = jcr->JobStatus;
704 jcr->jr.JobFiles = jcr->JobFiles;
705 jcr->jr.JobBytes = jcr->JobBytes;
706 jcr->jr.VolSessionId = jcr->VolSessionId;
707 jcr->jr.VolSessionTime = jcr->VolSessionTime;
708 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
709 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
710 db_strerror(jcr->db));
715 * Takes base_name and appends (unique) current
716 * date and time to form unique job name.
718 * Returns: unique job name in jcr->Job
719 * date/time in jcr->start_time
721 void create_unique_job_name(JCR *jcr, const char *base_name)
723 /* Job start mutex */
724 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
725 static time_t last_start_time = 0;
728 char dt[MAX_TIME_LENGTH];
729 char name[MAX_NAME_LENGTH];
732 /* Guarantee unique start time -- maximum one per second, and
733 * thus unique Job Name
735 P(mutex); /* lock creation of jobs */
737 while (now == last_start_time) {
738 bmicrosleep(0, 500000);
741 last_start_time = now;
742 V(mutex); /* allow creation of jobs */
743 jcr->start_time = now;
744 /* Form Unique JobName */
745 localtime_r(&now, &tm);
746 /* Use only characters that are permitted in Windows filenames */
747 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
748 bstrncpy(name, base_name, sizeof(name));
749 name[sizeof(name)-22] = 0; /* truncate if too long */
750 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
751 /* Convert spaces into underscores */
752 for (p=jcr->Job; *p; p++) {
759 /* Called directly from job rescheduling */
760 void dird_free_jcr_pointers(JCR *jcr)
762 if (jcr->sd_auth_key) {
763 free(jcr->sd_auth_key);
764 jcr->sd_auth_key = NULL;
770 if (jcr->file_bsock) {
771 Dmsg0(200, "Close File bsock\n");
772 bnet_close(jcr->file_bsock);
773 jcr->file_bsock = NULL;
775 if (jcr->store_bsock) {
776 Dmsg0(200, "Close Store bsock\n");
777 bnet_close(jcr->store_bsock);
778 jcr->store_bsock = NULL;
781 Dmsg0(200, "Free JCR fname\n");
782 free_pool_memory(jcr->fname);
786 Dmsg0(200, "Free JCR stime\n");
787 free_pool_memory(jcr->stime);
790 if (jcr->RestoreBootstrap) {
791 free(jcr->RestoreBootstrap);
792 jcr->RestoreBootstrap = NULL;
794 if (jcr->client_uname) {
795 free_pool_memory(jcr->client_uname);
796 jcr->client_uname = NULL;
799 free_pool_memory(jcr->attr);
809 * Free the Job Control Record if no one is still using it.
810 * Called from main free_jcr() routine in src/lib/jcr.c so
811 * that we can do our Director specific cleanup of the jcr.
813 void dird_free_jcr(JCR *jcr)
815 Dmsg0(200, "Start dird free_jcr\n");
817 dird_free_jcr_pointers(jcr);
818 if (jcr->term_wait_inited) {
819 pthread_cond_destroy(&jcr->term_wait);
820 jcr->term_wait_inited = false;
823 /* Delete lists setup to hold storage pointers */
827 jcr->job_end_push.destroy();
828 Dmsg0(200, "End dird free_jcr\n");
832 * Set some defaults in the JCR necessary to
833 * run. These items are pulled from the job
834 * definition as defaults, but can be overridden
835 * later either by the Run record in the Schedule resource,
836 * or by the Console program.
838 void set_jcr_defaults(JCR *jcr, JOB *job)
841 jcr->JobType = job->JobType;
842 switch (jcr->JobType) {
845 jcr->JobLevel = L_NONE;
848 jcr->JobLevel = job->JobLevel;
851 jcr->JobPriority = job->Priority;
852 /* Copy storage definitions -- deleted in dir_free_jcr above */
853 copy_storage(jcr, job->storage);
854 jcr->client = job->client;
855 if (!jcr->client_name) {
856 jcr->client_name = get_pool_memory(PM_NAME);
858 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
859 jcr->pool = job->pool;
860 jcr->full_pool = job->full_pool;
861 jcr->inc_pool = job->inc_pool;
862 jcr->dif_pool = job->dif_pool;
863 jcr->catalog = job->client->catalog;
864 jcr->fileset = job->fileset;
865 jcr->messages = job->messages;
866 jcr->spool_data = job->spool_data;
867 jcr->write_part_after_job = job->write_part_after_job;
868 if (jcr->RestoreBootstrap) {
869 free(jcr->RestoreBootstrap);
870 jcr->RestoreBootstrap = NULL;
872 /* This can be overridden by Console program */
873 if (job->RestoreBootstrap) {
874 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
876 /* This can be overridden by Console program */
877 jcr->verify_job = job->verify_job;
878 /* If no default level given, set one */
879 if (jcr->JobLevel == 0) {
880 switch (jcr->JobType) {
882 jcr->JobLevel = L_VERIFY_CATALOG;
885 jcr->JobLevel = L_INCREMENTAL;
889 jcr->JobLevel = L_NONE;
899 * Copy the storage definitions from an alist to the JCR
901 void copy_storage(JCR *jcr, alist *storage)
908 jcr->storage = New(alist(10, not_owned_by_alist));
909 foreach_alist(st, storage) {
910 jcr->storage->append(st);
914 jcr->store = (STORE *)jcr->storage->first();
919 /* Set storage override */
920 void set_storage(JCR *jcr, STORE *store)
925 foreach_alist(storage, jcr->storage) {
926 if (store == storage) {
930 /* Store not in list, so add it */
931 jcr->storage->prepend(store);
934 void create_clones(JCR *jcr)
937 * Fire off any clone jobs (run directives)
939 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
940 if (!jcr->cloned && jcr->job->run_cmds) {
943 POOLMEM *cmd = get_pool_memory(PM_FNAME);
944 UAContext *ua = new_ua_context(jcr);
946 foreach_alist(runcmd, job->run_cmds) {
947 cmd = edit_job_codes(jcr, cmd, runcmd, "");
948 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
949 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
950 parse_ua_args(ua); /* parse command */
951 int stat = run_cmd(ua, ua->cmd);
953 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
955 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
959 free_pool_memory(cmd);
963 bool create_restore_bootstrap_file(JCR *jcr)
967 memset(&rx, 0, sizeof(rx));
970 rx.bsr->JobId = jcr->previous_jr.JobId;
971 ua = new_ua_context(jcr);
972 complete_bsr(ua, rx.bsr);
973 rx.bsr->fi = new_findex();
974 rx.bsr->fi->findex = 1;
975 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
976 jcr->ExpectedFiles = write_bsr_file(ua, rx);
977 if (jcr->ExpectedFiles == 0) {
984 jcr->needs_sd = true;