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 jcr->start_time = time(NULL);
279 jcr->jr.StartTime = jcr->start_time;
280 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
281 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
283 generate_job_event(jcr, "JobRun");
285 switch (jcr->JobType) {
287 if (do_backup(jcr)) {
290 backup_cleanup(jcr, JS_ErrorTerminated);
294 if (do_verify(jcr)) {
297 verify_cleanup(jcr, JS_ErrorTerminated);
301 if (do_restore(jcr)) {
304 restore_cleanup(jcr, JS_ErrorTerminated);
311 admin_cleanup(jcr, JS_ErrorTerminated);
317 if (do_migration(jcr)) {
320 migration_cleanup(jcr, JS_ErrorTerminated);
324 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
327 if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
328 (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
329 POOLMEM *after = get_pool_memory(PM_FNAME);
332 char line[MAXSTRING];
334 if (jcr->JobStatus == JS_Terminated) {
335 after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
337 after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
339 bpipe = open_bpipe(after, 0, "r");
340 free_pool_memory(after);
341 while (fgets(line, sizeof(line), bpipe->rfd)) {
342 Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
344 status = close_bpipe(bpipe);
346 * Note, if we get an error here, do not mark the
347 * job in error, simply report the error condition.
351 if (jcr->JobStatus == JS_Terminated) {
352 Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
354 Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
358 /* Send off any queued messages */
359 if (jcr->msg_queue->size() > 0) {
360 dequeue_messages(jcr);
365 generate_daemon_event(jcr, "JobEnd");
366 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
367 sm_check(__FILE__, __LINE__, true);
373 * Cancel a job -- typically called by the UA (Console program), but may also
374 * be called by the job watchdog.
376 * Returns: true if cancel appears to be successful
377 * false on failure. Message sent to ua->jcr.
379 bool cancel_job(UAContext *ua, JCR *jcr)
383 set_jcr_job_status(jcr, JS_Canceled);
385 switch (jcr->JobStatus) {
388 case JS_WaitClientRes:
389 case JS_WaitStoreRes:
390 case JS_WaitPriority:
392 case JS_WaitStartTime:
393 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
394 jcr->JobId, jcr->Job);
395 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
399 /* Cancel File daemon */
400 if (jcr->file_bsock) {
401 ua->jcr->client = jcr->client;
402 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
403 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
406 Dmsg0(200, "Connected to file daemon\n");
407 fd = ua->jcr->file_bsock;
408 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
409 while (bnet_recv(fd) >= 0) {
410 bsendmsg(ua, "%s", fd->msg);
412 bnet_sig(fd, BNET_TERMINATE);
414 ua->jcr->file_bsock = NULL;
417 /* Cancel Storage daemon */
418 if (jcr->store_bsock) {
419 if (!ua->jcr->storage) {
420 copy_storage(ua->jcr, jcr->storage);
422 set_storage(ua->jcr, jcr->store);
424 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
425 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
428 Dmsg0(200, "Connected to storage daemon\n");
429 sd = ua->jcr->store_bsock;
430 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
431 while (bnet_recv(sd) >= 0) {
432 bsendmsg(ua, "%s", sd->msg);
434 bnet_sig(sd, BNET_TERMINATE);
436 ua->jcr->store_bsock = NULL;
444 static void job_monitor_destructor(watchdog_t *self)
446 JCR *control_jcr = (JCR *)self->data;
448 free_jcr(control_jcr);
451 static void job_monitor_watchdog(watchdog_t *self)
453 JCR *control_jcr, *jcr;
455 control_jcr = (JCR *)self->data;
457 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
462 if (jcr->JobId == 0) {
463 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
468 /* check MaxWaitTime */
469 cancel = job_check_maxwaittime(control_jcr, jcr);
471 /* check MaxRunTime */
472 cancel |= job_check_maxruntime(control_jcr, jcr);
475 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
476 jcr, jcr->JobId, jcr->Job);
478 UAContext *ua = new_ua_context(jcr);
479 ua->jcr = control_jcr;
483 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
486 /* Keep reference counts correct */
492 * Check if the maxwaittime has expired and it is possible
495 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
498 bool ok_to_cancel = false;
501 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
502 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
505 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
506 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
508 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
509 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
511 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
512 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
514 } else if (job->MaxWaitTime != 0 &&
515 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
521 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
523 jcr->JobId, jcr->Job, job->MaxWaitTime);
524 switch (jcr->JobStatus) {
529 case JS_WaitStoreRes:
530 case JS_WaitClientRes:
532 case JS_WaitPriority:
534 case JS_WaitStartTime:
536 Dmsg0(200, "JCR blocked in #1\n");
539 Dmsg0(800, "JCR running, checking SD status\n");
540 switch (jcr->SDJobStatus) {
545 Dmsg0(800, "JCR blocked in #2\n");
548 Dmsg0(800, "JCR not blocked in #2\n");
553 case JS_ErrorTerminated:
556 Dmsg0(800, "JCR already dead in #3\n");
559 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
562 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
563 cancel ? "" : "do not ", jcr, jcr->job);
569 * Check if maxruntime has expired and if the job can be
572 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
576 if (jcr->job->MaxRunTime == 0) {
579 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
580 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
581 jcr, jcr->Job, jcr->job->MaxRunTime);
585 switch (jcr->JobStatus) {
591 case JS_WaitStoreRes:
592 case JS_WaitClientRes:
594 case JS_WaitPriority:
596 case JS_WaitStartTime:
601 case JS_ErrorTerminated:
607 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
611 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
612 cancel ? "" : "do not ", jcr, jcr->job);
619 * Get or create a Client record for this Job
621 bool get_or_create_client_record(JCR *jcr)
625 memset(&cr, 0, sizeof(cr));
626 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
627 cr.AutoPrune = jcr->client->AutoPrune;
628 cr.FileRetention = jcr->client->FileRetention;
629 cr.JobRetention = jcr->client->JobRetention;
630 if (!jcr->client_name) {
631 jcr->client_name = get_pool_memory(PM_NAME);
633 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
634 if (!db_create_client_record(jcr, jcr->db, &cr)) {
635 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
636 db_strerror(jcr->db));
639 jcr->jr.ClientId = cr.ClientId;
641 if (!jcr->client_uname) {
642 jcr->client_uname = get_pool_memory(PM_NAME);
644 pm_strcpy(jcr->client_uname, cr.Uname);
646 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
651 bool get_or_create_fileset_record(JCR *jcr)
655 * Get or Create FileSet record
657 memset(&fsr, 0, sizeof(FILESET_DBR));
658 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
659 if (jcr->fileset->have_MD5) {
660 struct MD5Context md5c;
661 unsigned char digest[MD5HashSize];
662 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
663 MD5Final(digest, &md5c);
664 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
665 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
667 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
669 if (!jcr->fileset->ignore_fs_changes ||
670 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
671 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
672 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
673 fsr.FileSet, db_strerror(jcr->db));
677 jcr->jr.FileSetId = fsr.FileSetId;
678 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
679 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
684 void init_jcr_job_record(JCR *jcr)
686 jcr->jr.SchedTime = jcr->sched_time;
687 jcr->jr.StartTime = jcr->start_time;
688 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
689 jcr->jr.JobType = jcr->JobType;
690 jcr->jr.JobLevel = jcr->JobLevel;
691 jcr->jr.JobStatus = jcr->JobStatus;
692 jcr->jr.JobId = jcr->JobId;
693 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
694 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
698 * Write status and such in DB
700 void update_job_end_record(JCR *jcr)
702 jcr->jr.EndTime = time(NULL);
703 jcr->end_time = jcr->jr.EndTime;
704 jcr->jr.JobId = jcr->JobId;
705 jcr->jr.JobStatus = jcr->JobStatus;
706 jcr->jr.JobFiles = jcr->JobFiles;
707 jcr->jr.JobBytes = jcr->JobBytes;
708 jcr->jr.VolSessionId = jcr->VolSessionId;
709 jcr->jr.VolSessionTime = jcr->VolSessionTime;
710 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
711 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
712 db_strerror(jcr->db));
717 * Takes base_name and appends (unique) current
718 * date and time to form unique job name.
720 * Returns: unique job name in jcr->Job
721 * date/time in jcr->start_time
723 void create_unique_job_name(JCR *jcr, const char *base_name)
725 /* Job start mutex */
726 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
727 static time_t last_start_time = 0;
730 char dt[MAX_TIME_LENGTH];
731 char name[MAX_NAME_LENGTH];
734 /* Guarantee unique start time -- maximum one per second, and
735 * thus unique Job Name
737 P(mutex); /* lock creation of jobs */
739 while (now == last_start_time) {
740 bmicrosleep(0, 500000);
743 last_start_time = now;
744 V(mutex); /* allow creation of jobs */
745 jcr->start_time = now;
746 /* Form Unique JobName */
747 localtime_r(&now, &tm);
748 /* Use only characters that are permitted in Windows filenames */
749 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
750 bstrncpy(name, base_name, sizeof(name));
751 name[sizeof(name)-22] = 0; /* truncate if too long */
752 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
753 /* Convert spaces into underscores */
754 for (p=jcr->Job; *p; p++) {
761 /* Called directly from job rescheduling */
762 void dird_free_jcr_pointers(JCR *jcr)
764 if (jcr->sd_auth_key) {
765 free(jcr->sd_auth_key);
766 jcr->sd_auth_key = NULL;
772 if (jcr->file_bsock) {
773 Dmsg0(200, "Close File bsock\n");
774 bnet_close(jcr->file_bsock);
775 jcr->file_bsock = NULL;
777 if (jcr->store_bsock) {
778 Dmsg0(200, "Close Store bsock\n");
779 bnet_close(jcr->store_bsock);
780 jcr->store_bsock = NULL;
783 Dmsg0(200, "Free JCR fname\n");
784 free_pool_memory(jcr->fname);
788 Dmsg0(200, "Free JCR stime\n");
789 free_pool_memory(jcr->stime);
792 if (jcr->RestoreBootstrap) {
793 free(jcr->RestoreBootstrap);
794 jcr->RestoreBootstrap = NULL;
796 if (jcr->client_uname) {
797 free_pool_memory(jcr->client_uname);
798 jcr->client_uname = NULL;
801 free_pool_memory(jcr->attr);
811 * Free the Job Control Record if no one is still using it.
812 * Called from main free_jcr() routine in src/lib/jcr.c so
813 * that we can do our Director specific cleanup of the jcr.
815 void dird_free_jcr(JCR *jcr)
817 Dmsg0(200, "Start dird free_jcr\n");
819 dird_free_jcr_pointers(jcr);
820 if (jcr->term_wait_inited) {
821 pthread_cond_destroy(&jcr->term_wait);
822 jcr->term_wait_inited = false;
825 /* Delete lists setup to hold storage pointers */
829 jcr->job_end_push.destroy();
830 Dmsg0(200, "End dird free_jcr\n");
834 * Set some defaults in the JCR necessary to
835 * run. These items are pulled from the job
836 * definition as defaults, but can be overridden
837 * later either by the Run record in the Schedule resource,
838 * or by the Console program.
840 void set_jcr_defaults(JCR *jcr, JOB *job)
843 jcr->JobType = job->JobType;
844 switch (jcr->JobType) {
847 jcr->JobLevel = L_NONE;
850 jcr->JobLevel = job->JobLevel;
853 jcr->JobPriority = job->Priority;
854 /* Copy storage definitions -- deleted in dir_free_jcr above */
855 copy_storage(jcr, job->storage);
856 jcr->client = job->client;
857 if (!jcr->client_name) {
858 jcr->client_name = get_pool_memory(PM_NAME);
860 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
861 jcr->pool = job->pool;
862 jcr->full_pool = job->full_pool;
863 jcr->inc_pool = job->inc_pool;
864 jcr->dif_pool = job->dif_pool;
865 jcr->catalog = job->client->catalog;
866 jcr->fileset = job->fileset;
867 jcr->messages = job->messages;
868 jcr->spool_data = job->spool_data;
869 jcr->write_part_after_job = job->write_part_after_job;
870 if (jcr->RestoreBootstrap) {
871 free(jcr->RestoreBootstrap);
872 jcr->RestoreBootstrap = NULL;
874 /* This can be overridden by Console program */
875 if (job->RestoreBootstrap) {
876 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
878 /* This can be overridden by Console program */
879 jcr->verify_job = job->verify_job;
880 /* If no default level given, set one */
881 if (jcr->JobLevel == 0) {
882 switch (jcr->JobType) {
884 jcr->JobLevel = L_VERIFY_CATALOG;
887 jcr->JobLevel = L_INCREMENTAL;
891 jcr->JobLevel = L_NONE;
901 * Copy the storage definitions from an alist to the JCR
903 void copy_storage(JCR *jcr, alist *storage)
910 jcr->storage = New(alist(10, not_owned_by_alist));
911 foreach_alist(st, storage) {
912 jcr->storage->append(st);
916 jcr->store = (STORE *)jcr->storage->first();
921 /* Set storage override */
922 void set_storage(JCR *jcr, STORE *store)
927 foreach_alist(storage, jcr->storage) {
928 if (store == storage) {
932 /* Store not in list, so add it */
933 jcr->storage->prepend(store);
936 void create_clones(JCR *jcr)
939 * Fire off any clone jobs (run directives)
941 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
942 if (!jcr->cloned && jcr->job->run_cmds) {
945 POOLMEM *cmd = get_pool_memory(PM_FNAME);
946 UAContext *ua = new_ua_context(jcr);
948 foreach_alist(runcmd, job->run_cmds) {
949 cmd = edit_job_codes(jcr, cmd, runcmd, "");
950 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
951 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
952 parse_ua_args(ua); /* parse command */
953 int stat = run_cmd(ua, ua->cmd);
955 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
957 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
961 free_pool_memory(cmd);
965 bool create_restore_bootstrap_file(JCR *jcr)
969 memset(&rx, 0, sizeof(rx));
972 rx.bsr->JobId = jcr->previous_jr.JobId;
973 ua = new_ua_context(jcr);
974 complete_bsr(ua, rx.bsr);
975 rx.bsr->fi = new_findex();
976 rx.bsr->fi->findex = 1;
977 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
978 jcr->ExpectedFiles = write_bsr_file(ua, rx);
979 if (jcr->ExpectedFiles == 0) {
986 jcr->needs_sd = true;