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 generate_job_event(jcr, "JobRun");
271 switch (jcr->JobType) {
273 if (do_backup(jcr)) {
276 backup_cleanup(jcr, JS_ErrorTerminated);
280 if (do_verify(jcr)) {
283 verify_cleanup(jcr, JS_ErrorTerminated);
287 if (do_restore(jcr)) {
290 restore_cleanup(jcr, JS_ErrorTerminated);
297 admin_cleanup(jcr, JS_ErrorTerminated);
303 if (do_migration(jcr)) {
306 migration_cleanup(jcr, JS_ErrorTerminated);
310 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
313 if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
314 (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
315 POOLMEM *after = get_pool_memory(PM_FNAME);
318 char line[MAXSTRING];
320 if (jcr->JobStatus == JS_Terminated) {
321 after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
323 after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
325 bpipe = open_bpipe(after, 0, "r");
326 free_pool_memory(after);
327 while (fgets(line, sizeof(line), bpipe->rfd)) {
328 Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
330 status = close_bpipe(bpipe);
332 * Note, if we get an error here, do not mark the
333 * job in error, simply report the error condition.
337 if (jcr->JobStatus == JS_Terminated) {
338 Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
340 Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
344 /* Send off any queued messages */
345 if (jcr->msg_queue->size() > 0) {
346 dequeue_messages(jcr);
351 generate_daemon_event(jcr, "JobEnd");
352 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
353 sm_check(__FILE__, __LINE__, true);
359 * Cancel a job -- typically called by the UA (Console program), but may also
360 * be called by the job watchdog.
362 * Returns: true if cancel appears to be successful
363 * false on failure. Message sent to ua->jcr.
365 bool cancel_job(UAContext *ua, JCR *jcr)
369 set_jcr_job_status(jcr, JS_Canceled);
371 switch (jcr->JobStatus) {
374 case JS_WaitClientRes:
375 case JS_WaitStoreRes:
376 case JS_WaitPriority:
378 case JS_WaitStartTime:
379 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
380 jcr->JobId, jcr->Job);
381 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
385 /* Cancel File daemon */
386 if (jcr->file_bsock) {
387 ua->jcr->client = jcr->client;
388 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
389 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
392 Dmsg0(200, "Connected to file daemon\n");
393 fd = ua->jcr->file_bsock;
394 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
395 while (bnet_recv(fd) >= 0) {
396 bsendmsg(ua, "%s", fd->msg);
398 bnet_sig(fd, BNET_TERMINATE);
400 ua->jcr->file_bsock = NULL;
403 /* Cancel Storage daemon */
404 if (jcr->store_bsock) {
405 if (!ua->jcr->storage) {
406 copy_storage(ua->jcr, jcr->storage);
408 set_storage(ua->jcr, jcr->store);
410 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
411 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
414 Dmsg0(200, "Connected to storage daemon\n");
415 sd = ua->jcr->store_bsock;
416 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
417 while (bnet_recv(sd) >= 0) {
418 bsendmsg(ua, "%s", sd->msg);
420 bnet_sig(sd, BNET_TERMINATE);
422 ua->jcr->store_bsock = NULL;
430 static void job_monitor_destructor(watchdog_t *self)
432 JCR *control_jcr = (JCR *)self->data;
434 free_jcr(control_jcr);
437 static void job_monitor_watchdog(watchdog_t *self)
439 JCR *control_jcr, *jcr;
441 control_jcr = (JCR *)self->data;
443 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
448 if (jcr->JobId == 0) {
449 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
454 /* check MaxWaitTime */
455 cancel = job_check_maxwaittime(control_jcr, jcr);
457 /* check MaxRunTime */
458 cancel |= job_check_maxruntime(control_jcr, jcr);
461 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
462 jcr, jcr->JobId, jcr->Job);
464 UAContext *ua = new_ua_context(jcr);
465 ua->jcr = control_jcr;
469 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
472 /* Keep reference counts correct */
478 * Check if the maxwaittime has expired and it is possible
481 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
484 bool ok_to_cancel = false;
487 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
488 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
491 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
492 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
494 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
495 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
497 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
498 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
500 } else if (job->MaxWaitTime != 0 &&
501 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
507 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
509 jcr->JobId, jcr->Job, job->MaxWaitTime);
510 switch (jcr->JobStatus) {
515 case JS_WaitStoreRes:
516 case JS_WaitClientRes:
518 case JS_WaitPriority:
520 case JS_WaitStartTime:
522 Dmsg0(200, "JCR blocked in #1\n");
525 Dmsg0(800, "JCR running, checking SD status\n");
526 switch (jcr->SDJobStatus) {
531 Dmsg0(800, "JCR blocked in #2\n");
534 Dmsg0(800, "JCR not blocked in #2\n");
539 case JS_ErrorTerminated:
542 Dmsg0(800, "JCR already dead in #3\n");
545 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
548 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
549 cancel ? "" : "do not ", jcr, jcr->job);
555 * Check if maxruntime has expired and if the job can be
558 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
562 if (jcr->job->MaxRunTime == 0) {
565 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
566 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
567 jcr, jcr->Job, jcr->job->MaxRunTime);
571 switch (jcr->JobStatus) {
577 case JS_WaitStoreRes:
578 case JS_WaitClientRes:
580 case JS_WaitPriority:
582 case JS_WaitStartTime:
587 case JS_ErrorTerminated:
593 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
597 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
598 cancel ? "" : "do not ", jcr, jcr->job);
605 * Get or create a Client record for this Job
607 bool get_or_create_client_record(JCR *jcr)
611 memset(&cr, 0, sizeof(cr));
612 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
613 cr.AutoPrune = jcr->client->AutoPrune;
614 cr.FileRetention = jcr->client->FileRetention;
615 cr.JobRetention = jcr->client->JobRetention;
616 if (!jcr->client_name) {
617 jcr->client_name = get_pool_memory(PM_NAME);
619 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
620 if (!db_create_client_record(jcr, jcr->db, &cr)) {
621 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
622 db_strerror(jcr->db));
625 jcr->jr.ClientId = cr.ClientId;
627 if (!jcr->client_uname) {
628 jcr->client_uname = get_pool_memory(PM_NAME);
630 pm_strcpy(jcr->client_uname, cr.Uname);
632 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
637 bool get_or_create_fileset_record(JCR *jcr)
641 * Get or Create FileSet record
643 memset(&fsr, 0, sizeof(FILESET_DBR));
644 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
645 if (jcr->fileset->have_MD5) {
646 struct MD5Context md5c;
647 unsigned char digest[MD5HashSize];
648 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
649 MD5Final(digest, &md5c);
650 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
651 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
653 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
655 if (!jcr->fileset->ignore_fs_changes ||
656 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
657 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
658 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
659 fsr.FileSet, db_strerror(jcr->db));
663 jcr->jr.FileSetId = fsr.FileSetId;
664 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
665 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
670 void init_jcr_job_record(JCR *jcr)
672 jcr->jr.SchedTime = jcr->sched_time;
673 jcr->jr.StartTime = jcr->start_time;
674 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
675 jcr->jr.JobType = jcr->JobType;
676 jcr->jr.JobLevel = jcr->JobLevel;
677 jcr->jr.JobStatus = jcr->JobStatus;
678 jcr->jr.JobId = jcr->JobId;
679 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
680 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
684 * Write status and such in DB
686 void update_job_end_record(JCR *jcr)
688 jcr->jr.EndTime = time(NULL);
689 jcr->end_time = jcr->jr.EndTime;
690 jcr->jr.JobId = jcr->JobId;
691 jcr->jr.JobStatus = jcr->JobStatus;
692 jcr->jr.JobFiles = jcr->JobFiles;
693 jcr->jr.JobBytes = jcr->JobBytes;
694 jcr->jr.VolSessionId = jcr->VolSessionId;
695 jcr->jr.VolSessionTime = jcr->VolSessionTime;
696 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
697 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
698 db_strerror(jcr->db));
703 * Takes base_name and appends (unique) current
704 * date and time to form unique job name.
706 * Returns: unique job name in jcr->Job
707 * date/time in jcr->start_time
709 void create_unique_job_name(JCR *jcr, const char *base_name)
711 /* Job start mutex */
712 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
713 static time_t last_start_time = 0;
716 char dt[MAX_TIME_LENGTH];
717 char name[MAX_NAME_LENGTH];
720 /* Guarantee unique start time -- maximum one per second, and
721 * thus unique Job Name
723 P(mutex); /* lock creation of jobs */
725 while (now == last_start_time) {
726 bmicrosleep(0, 500000);
729 last_start_time = now;
730 V(mutex); /* allow creation of jobs */
731 jcr->start_time = now;
732 /* Form Unique JobName */
733 localtime_r(&now, &tm);
734 /* Use only characters that are permitted in Windows filenames */
735 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
736 bstrncpy(name, base_name, sizeof(name));
737 name[sizeof(name)-22] = 0; /* truncate if too long */
738 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
739 /* Convert spaces into underscores */
740 for (p=jcr->Job; *p; p++) {
747 /* Called directly from job rescheduling */
748 void dird_free_jcr_pointers(JCR *jcr)
750 if (jcr->sd_auth_key) {
751 free(jcr->sd_auth_key);
752 jcr->sd_auth_key = NULL;
758 if (jcr->file_bsock) {
759 Dmsg0(200, "Close File bsock\n");
760 bnet_close(jcr->file_bsock);
761 jcr->file_bsock = NULL;
763 if (jcr->store_bsock) {
764 Dmsg0(200, "Close Store bsock\n");
765 bnet_close(jcr->store_bsock);
766 jcr->store_bsock = NULL;
769 Dmsg0(200, "Free JCR fname\n");
770 free_pool_memory(jcr->fname);
774 Dmsg0(200, "Free JCR stime\n");
775 free_pool_memory(jcr->stime);
778 if (jcr->RestoreBootstrap) {
779 free(jcr->RestoreBootstrap);
780 jcr->RestoreBootstrap = NULL;
782 if (jcr->client_uname) {
783 free_pool_memory(jcr->client_uname);
784 jcr->client_uname = NULL;
787 free_pool_memory(jcr->attr);
797 * Free the Job Control Record if no one is still using it.
798 * Called from main free_jcr() routine in src/lib/jcr.c so
799 * that we can do our Director specific cleanup of the jcr.
801 void dird_free_jcr(JCR *jcr)
803 Dmsg0(200, "Start dird free_jcr\n");
805 dird_free_jcr_pointers(jcr);
806 if (jcr->term_wait_inited) {
807 pthread_cond_destroy(&jcr->term_wait);
808 jcr->term_wait_inited = false;
811 /* Delete lists setup to hold storage pointers */
815 jcr->job_end_push.destroy();
816 Dmsg0(200, "End dird free_jcr\n");
820 * Set some defaults in the JCR necessary to
821 * run. These items are pulled from the job
822 * definition as defaults, but can be overridden
823 * later either by the Run record in the Schedule resource,
824 * or by the Console program.
826 void set_jcr_defaults(JCR *jcr, JOB *job)
829 jcr->JobType = job->JobType;
830 switch (jcr->JobType) {
833 jcr->JobLevel = L_NONE;
836 jcr->JobLevel = job->JobLevel;
839 jcr->JobPriority = job->Priority;
840 /* Copy storage definitions -- deleted in dir_free_jcr above */
841 copy_storage(jcr, job->storage);
842 jcr->client = job->client;
843 if (!jcr->client_name) {
844 jcr->client_name = get_pool_memory(PM_NAME);
846 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
847 jcr->pool = job->pool;
848 jcr->full_pool = job->full_pool;
849 jcr->inc_pool = job->inc_pool;
850 jcr->dif_pool = job->dif_pool;
851 jcr->catalog = job->client->catalog;
852 jcr->fileset = job->fileset;
853 jcr->messages = job->messages;
854 jcr->spool_data = job->spool_data;
855 jcr->write_part_after_job = job->write_part_after_job;
856 if (jcr->RestoreBootstrap) {
857 free(jcr->RestoreBootstrap);
858 jcr->RestoreBootstrap = NULL;
860 /* This can be overridden by Console program */
861 if (job->RestoreBootstrap) {
862 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
864 /* This can be overridden by Console program */
865 jcr->verify_job = job->verify_job;
866 /* If no default level given, set one */
867 if (jcr->JobLevel == 0) {
868 switch (jcr->JobType) {
870 jcr->JobLevel = L_VERIFY_CATALOG;
873 jcr->JobLevel = L_INCREMENTAL;
877 jcr->JobLevel = L_NONE;
887 * Copy the storage definitions from an alist to the JCR
889 void copy_storage(JCR *jcr, alist *storage)
896 jcr->storage = New(alist(10, not_owned_by_alist));
897 foreach_alist(st, storage) {
898 jcr->storage->append(st);
902 jcr->store = (STORE *)jcr->storage->first();
907 /* Set storage override */
908 void set_storage(JCR *jcr, STORE *store)
913 foreach_alist(storage, jcr->storage) {
914 if (store == storage) {
918 /* Store not in list, so add it */
919 jcr->storage->prepend(store);
922 void create_clones(JCR *jcr)
925 * Fire off any clone jobs (run directives)
927 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
928 if (!jcr->cloned && jcr->job->run_cmds) {
931 POOLMEM *cmd = get_pool_memory(PM_FNAME);
932 UAContext *ua = new_ua_context(jcr);
934 foreach_alist(runcmd, job->run_cmds) {
935 cmd = edit_job_codes(jcr, cmd, runcmd, "");
936 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
937 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
938 parse_ua_args(ua); /* parse command */
939 int stat = run_cmd(ua, ua->cmd);
941 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
943 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
947 free_pool_memory(cmd);
951 bool create_restore_bootstrap_file(JCR *jcr)
955 memset(&rx, 0, sizeof(rx));
958 rx.bsr->JobId = jcr->previous_jr.JobId;
959 ua = new_ua_context(jcr);
960 complete_bsr(ua, rx.bsr);
961 rx.bsr->fi = new_findex();
962 rx.bsr->fi->findex = 1;
963 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
964 jcr->ExpectedFiles = write_bsr_file(ua, rx);
965 if (jcr->ExpectedFiles == 0) {
972 jcr->needs_sd = true;