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;
109 Dmsg0(50, "Open database\n");
110 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
111 jcr->catalog->db_password, jcr->catalog->db_address,
112 jcr->catalog->db_port, jcr->catalog->db_socket,
113 jcr->catalog->mult_db_connections);
114 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
115 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
116 jcr->catalog->db_name);
118 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
122 Dmsg0(50, "DB opened\n");
127 create_unique_job_name(jcr, jcr->job->hdr.name);
128 set_jcr_job_status(jcr, JS_Created);
129 init_jcr_job_record(jcr);
130 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
131 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
134 jcr->JobId = jcr->jr.JobId;
135 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
136 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
138 generate_daemon_event(jcr, "JobStart");
140 if (!get_or_create_client_record(jcr)) {
144 if (job_canceled(jcr)) {
148 Dmsg0(200, "Add jrc to work queue\n");
156 free_memory(jcr->fname);
165 * This is the engine called by jobq.c:jobq_add() when we were pulled
166 * from the work queue.
167 * At this point, we are running in our own thread and all
168 * necessary resources are allocated -- see jobq.c
170 static void *job_thread(void *arg)
172 JCR *jcr = (JCR *)arg;
174 jcr->my_thread_id = pthread_self();
175 pthread_detach(jcr->my_thread_id);
176 sm_check(__FILE__, __LINE__, true);
178 Dmsg0(200, "=====Start Job=========\n");
179 jcr->start_time = time(NULL); /* set the real start time */
180 jcr->jr.StartTime = jcr->start_time;
182 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
183 (utime_t)(jcr->start_time - jcr->sched_time)) {
184 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
185 set_jcr_job_status(jcr, JS_Canceled);
189 * Note, we continue, even if the job is canceled above. This
190 * will permit proper setting of the job start record and
191 * the error (cancel) will be picked up below.
194 generate_job_event(jcr, "JobInit");
195 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
198 jcr->fname = get_pool_memory(PM_FNAME);
202 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
203 * this allows us to setup a proper job start record for restarting
204 * in case of later errors.
206 switch (jcr->JobType) {
208 if (!do_backup_init(jcr)) {
209 backup_cleanup(jcr, JS_ErrorTerminated);
213 if (!do_verify_init(jcr)) {
214 verify_cleanup(jcr, JS_ErrorTerminated);
218 if (!do_restore_init(jcr)) {
219 restore_cleanup(jcr, JS_ErrorTerminated);
223 if (!do_admin_init(jcr)) {
224 admin_cleanup(jcr, JS_ErrorTerminated);
228 if (!do_migration_init(jcr)) {
229 migration_cleanup(jcr, JS_ErrorTerminated);
233 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
234 set_jcr_job_status(jcr, JS_ErrorTerminated);
238 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
239 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
242 if (job_canceled(jcr)) {
243 update_job_end_record(jcr);
248 if (jcr->job->RunBeforeJob) {
249 POOLMEM *before = get_pool_memory(PM_FNAME);
252 char line[MAXSTRING];
254 before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
255 bpipe = open_bpipe(before, 0, "r");
256 free_pool_memory(before);
257 while (fgets(line, sizeof(line), bpipe->rfd)) {
258 Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
260 status = close_bpipe(bpipe);
263 Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
264 set_jcr_job_status(jcr, JS_FatalError);
265 update_job_end_record(jcr);
270 generate_job_event(jcr, "JobRun");
272 switch (jcr->JobType) {
274 if (do_backup(jcr)) {
277 backup_cleanup(jcr, JS_ErrorTerminated);
281 if (do_verify(jcr)) {
284 verify_cleanup(jcr, JS_ErrorTerminated);
288 if (do_restore(jcr)) {
291 restore_cleanup(jcr, JS_ErrorTerminated);
298 admin_cleanup(jcr, JS_ErrorTerminated);
304 if (do_migration(jcr)) {
307 migration_cleanup(jcr, JS_ErrorTerminated);
311 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
314 if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
315 (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
316 POOLMEM *after = get_pool_memory(PM_FNAME);
319 char line[MAXSTRING];
321 if (jcr->JobStatus == JS_Terminated) {
322 after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
324 after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
326 bpipe = open_bpipe(after, 0, "r");
327 free_pool_memory(after);
328 while (fgets(line, sizeof(line), bpipe->rfd)) {
329 Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
331 status = close_bpipe(bpipe);
333 * Note, if we get an error here, do not mark the
334 * job in error, simply report the error condition.
338 if (jcr->JobStatus == JS_Terminated) {
339 Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
341 Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
345 /* Send off any queued messages */
346 if (jcr->msg_queue->size() > 0) {
347 dequeue_messages(jcr);
352 generate_daemon_event(jcr, "JobEnd");
353 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
354 sm_check(__FILE__, __LINE__, true);
360 * Cancel a job -- typically called by the UA (Console program), but may also
361 * be called by the job watchdog.
363 * Returns: true if cancel appears to be successful
364 * false on failure. Message sent to ua->jcr.
366 bool cancel_job(UAContext *ua, JCR *jcr)
370 set_jcr_job_status(jcr, JS_Canceled);
372 switch (jcr->JobStatus) {
375 case JS_WaitClientRes:
376 case JS_WaitStoreRes:
377 case JS_WaitPriority:
379 case JS_WaitStartTime:
380 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
381 jcr->JobId, jcr->Job);
382 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
386 /* Cancel File daemon */
387 if (jcr->file_bsock) {
388 ua->jcr->client = jcr->client;
389 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
390 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
393 Dmsg0(200, "Connected to file daemon\n");
394 fd = ua->jcr->file_bsock;
395 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
396 while (bnet_recv(fd) >= 0) {
397 bsendmsg(ua, "%s", fd->msg);
399 bnet_sig(fd, BNET_TERMINATE);
401 ua->jcr->file_bsock = NULL;
404 /* Cancel Storage daemon */
405 if (jcr->store_bsock) {
406 if (!ua->jcr->storage) {
407 copy_storage(ua->jcr, jcr->storage);
409 set_storage(ua->jcr, jcr->store);
411 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
412 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
415 Dmsg0(200, "Connected to storage daemon\n");
416 sd = ua->jcr->store_bsock;
417 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
418 while (bnet_recv(sd) >= 0) {
419 bsendmsg(ua, "%s", sd->msg);
421 bnet_sig(sd, BNET_TERMINATE);
423 ua->jcr->store_bsock = NULL;
431 static void job_monitor_destructor(watchdog_t *self)
433 JCR *control_jcr = (JCR *)self->data;
435 free_jcr(control_jcr);
438 static void job_monitor_watchdog(watchdog_t *self)
440 JCR *control_jcr, *jcr;
442 control_jcr = (JCR *)self->data;
444 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
449 if (jcr->JobId == 0) {
450 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
455 /* check MaxWaitTime */
456 cancel = job_check_maxwaittime(control_jcr, jcr);
458 /* check MaxRunTime */
459 cancel |= job_check_maxruntime(control_jcr, jcr);
462 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
463 jcr, jcr->JobId, jcr->Job);
465 UAContext *ua = new_ua_context(jcr);
466 ua->jcr = control_jcr;
470 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
473 /* Keep reference counts correct */
479 * Check if the maxwaittime has expired and it is possible
482 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
485 bool ok_to_cancel = false;
488 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
489 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
492 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
493 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
495 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
496 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
498 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
499 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
501 } else if (job->MaxWaitTime != 0 &&
502 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
508 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
510 jcr->JobId, jcr->Job, job->MaxWaitTime);
511 switch (jcr->JobStatus) {
516 case JS_WaitStoreRes:
517 case JS_WaitClientRes:
519 case JS_WaitPriority:
521 case JS_WaitStartTime:
523 Dmsg0(200, "JCR blocked in #1\n");
526 Dmsg0(800, "JCR running, checking SD status\n");
527 switch (jcr->SDJobStatus) {
532 Dmsg0(800, "JCR blocked in #2\n");
535 Dmsg0(800, "JCR not blocked in #2\n");
540 case JS_ErrorTerminated:
543 Dmsg0(800, "JCR already dead in #3\n");
546 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
549 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
550 cancel ? "" : "do not ", jcr, jcr->job);
556 * Check if maxruntime has expired and if the job can be
559 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
563 if (jcr->job->MaxRunTime == 0) {
566 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
567 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
568 jcr, jcr->Job, jcr->job->MaxRunTime);
572 switch (jcr->JobStatus) {
578 case JS_WaitStoreRes:
579 case JS_WaitClientRes:
581 case JS_WaitPriority:
583 case JS_WaitStartTime:
588 case JS_ErrorTerminated:
594 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
598 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
599 cancel ? "" : "do not ", jcr, jcr->job);
606 * Get or create a Client record for this Job
608 bool get_or_create_client_record(JCR *jcr)
612 memset(&cr, 0, sizeof(cr));
613 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
614 cr.AutoPrune = jcr->client->AutoPrune;
615 cr.FileRetention = jcr->client->FileRetention;
616 cr.JobRetention = jcr->client->JobRetention;
617 if (!jcr->client_name) {
618 jcr->client_name = get_pool_memory(PM_NAME);
620 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
621 if (!db_create_client_record(jcr, jcr->db, &cr)) {
622 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
623 db_strerror(jcr->db));
626 jcr->jr.ClientId = cr.ClientId;
628 if (!jcr->client_uname) {
629 jcr->client_uname = get_pool_memory(PM_NAME);
631 pm_strcpy(jcr->client_uname, cr.Uname);
633 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
638 bool get_or_create_fileset_record(JCR *jcr)
642 * Get or Create FileSet record
644 memset(&fsr, 0, sizeof(FILESET_DBR));
645 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
646 if (jcr->fileset->have_MD5) {
647 struct MD5Context md5c;
648 unsigned char digest[MD5HashSize];
649 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
650 MD5Final(digest, &md5c);
651 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
652 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
654 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
656 if (!jcr->fileset->ignore_fs_changes ||
657 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
658 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
659 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
660 fsr.FileSet, db_strerror(jcr->db));
664 jcr->jr.FileSetId = fsr.FileSetId;
665 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
666 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
671 void init_jcr_job_record(JCR *jcr)
673 jcr->jr.SchedTime = jcr->sched_time;
674 jcr->jr.StartTime = jcr->start_time;
675 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
676 jcr->jr.JobType = jcr->JobType;
677 jcr->jr.JobLevel = jcr->JobLevel;
678 jcr->jr.JobStatus = jcr->JobStatus;
679 jcr->jr.JobId = jcr->JobId;
680 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
681 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
685 * Write status and such in DB
687 void update_job_end_record(JCR *jcr)
689 jcr->jr.EndTime = time(NULL);
690 jcr->end_time = jcr->jr.EndTime;
691 jcr->jr.JobId = jcr->JobId;
692 jcr->jr.JobStatus = jcr->JobStatus;
693 jcr->jr.JobFiles = jcr->JobFiles;
694 jcr->jr.JobBytes = jcr->JobBytes;
695 jcr->jr.VolSessionId = jcr->VolSessionId;
696 jcr->jr.VolSessionTime = jcr->VolSessionTime;
697 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
698 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
699 db_strerror(jcr->db));
704 * Takes base_name and appends (unique) current
705 * date and time to form unique job name.
707 * Returns: unique job name in jcr->Job
708 * date/time in jcr->start_time
710 void create_unique_job_name(JCR *jcr, const char *base_name)
712 /* Job start mutex */
713 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
714 static time_t last_start_time = 0;
717 char dt[MAX_TIME_LENGTH];
718 char name[MAX_NAME_LENGTH];
721 /* Guarantee unique start time -- maximum one per second, and
722 * thus unique Job Name
724 P(mutex); /* lock creation of jobs */
726 while (now == last_start_time) {
727 bmicrosleep(0, 500000);
730 last_start_time = now;
731 V(mutex); /* allow creation of jobs */
732 jcr->start_time = now;
733 /* Form Unique JobName */
734 localtime_r(&now, &tm);
735 /* Use only characters that are permitted in Windows filenames */
736 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
737 bstrncpy(name, base_name, sizeof(name));
738 name[sizeof(name)-22] = 0; /* truncate if too long */
739 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
740 /* Convert spaces into underscores */
741 for (p=jcr->Job; *p; p++) {
748 /* Called directly from job rescheduling */
749 void dird_free_jcr_pointers(JCR *jcr)
751 if (jcr->sd_auth_key) {
752 free(jcr->sd_auth_key);
753 jcr->sd_auth_key = NULL;
759 if (jcr->file_bsock) {
760 Dmsg0(200, "Close File bsock\n");
761 bnet_close(jcr->file_bsock);
762 jcr->file_bsock = NULL;
764 if (jcr->store_bsock) {
765 Dmsg0(200, "Close Store bsock\n");
766 bnet_close(jcr->store_bsock);
767 jcr->store_bsock = NULL;
770 Dmsg0(200, "Free JCR fname\n");
771 free_pool_memory(jcr->fname);
775 Dmsg0(200, "Free JCR stime\n");
776 free_pool_memory(jcr->stime);
779 if (jcr->RestoreBootstrap) {
780 free(jcr->RestoreBootstrap);
781 jcr->RestoreBootstrap = NULL;
783 if (jcr->client_uname) {
784 free_pool_memory(jcr->client_uname);
785 jcr->client_uname = NULL;
787 if (jcr->term_wait_inited) {
788 pthread_cond_destroy(&jcr->term_wait);
789 jcr->term_wait_inited = false;
792 free_pool_memory(jcr->attr);
802 * Free the Job Control Record if no one is still using it.
803 * Called from main free_jcr() routine in src/lib/jcr.c so
804 * that we can do our Director specific cleanup of the jcr.
806 void dird_free_jcr(JCR *jcr)
808 Dmsg0(200, "Start dird free_jcr\n");
810 dird_free_jcr_pointers(jcr);
812 /* Delete lists setup to hold storage pointers */
816 jcr->job_end_push.destroy();
817 Dmsg0(200, "End dird free_jcr\n");
821 * Set some defaults in the JCR necessary to
822 * run. These items are pulled from the job
823 * definition as defaults, but can be overridden
824 * later either by the Run record in the Schedule resource,
825 * or by the Console program.
827 void set_jcr_defaults(JCR *jcr, JOB *job)
830 jcr->JobType = job->JobType;
831 switch (jcr->JobType) {
834 jcr->JobLevel = L_NONE;
837 jcr->JobLevel = job->JobLevel;
840 jcr->JobPriority = job->Priority;
841 /* Copy storage definitions -- deleted in dir_free_jcr above */
842 copy_storage(jcr, job->storage);
843 jcr->client = job->client;
844 if (!jcr->client_name) {
845 jcr->client_name = get_pool_memory(PM_NAME);
847 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
848 jcr->pool = job->pool;
849 jcr->full_pool = job->full_pool;
850 jcr->inc_pool = job->inc_pool;
851 jcr->dif_pool = job->dif_pool;
852 jcr->catalog = job->client->catalog;
853 jcr->fileset = job->fileset;
854 jcr->messages = job->messages;
855 jcr->spool_data = job->spool_data;
856 jcr->write_part_after_job = job->write_part_after_job;
857 if (jcr->RestoreBootstrap) {
858 free(jcr->RestoreBootstrap);
859 jcr->RestoreBootstrap = NULL;
861 /* This can be overridden by Console program */
862 if (job->RestoreBootstrap) {
863 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
865 /* This can be overridden by Console program */
866 jcr->verify_job = job->verify_job;
867 /* If no default level given, set one */
868 if (jcr->JobLevel == 0) {
869 switch (jcr->JobType) {
871 jcr->JobLevel = L_VERIFY_CATALOG;
874 jcr->JobLevel = L_INCREMENTAL;
878 jcr->JobLevel = L_NONE;
888 * Copy the storage definitions from an alist to the JCR
890 void copy_storage(JCR *jcr, alist *storage)
897 jcr->storage = New(alist(10, not_owned_by_alist));
898 foreach_alist(st, storage) {
899 jcr->storage->append(st);
903 jcr->store = (STORE *)jcr->storage->first();
908 /* Set storage override */
909 void set_storage(JCR *jcr, STORE *store)
914 foreach_alist(storage, jcr->storage) {
915 if (store == storage) {
919 /* Store not in list, so add it */
920 jcr->storage->prepend(store);
923 void create_clones(JCR *jcr)
926 * Fire off any clone jobs (run directives)
928 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
929 if (!jcr->cloned && jcr->job->run_cmds) {
932 POOLMEM *cmd = get_pool_memory(PM_FNAME);
933 UAContext *ua = new_ua_context(jcr);
935 foreach_alist(runcmd, job->run_cmds) {
936 cmd = edit_job_codes(jcr, cmd, runcmd, "");
937 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
938 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
939 parse_ua_args(ua); /* parse command */
940 int stat = run_cmd(ua, ua->cmd);
942 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
944 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
948 free_pool_memory(cmd);
952 bool create_restore_bootstrap_file(JCR *jcr)
956 memset(&rx, 0, sizeof(rx));
959 rx.bsr->JobId = jcr->previous_jr.JobId;
960 ua = new_ua_context(jcr);
961 complete_bsr(ua, rx.bsr);
962 rx.bsr->fi = new_findex();
963 rx.bsr->fi->findex = 1;
964 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
965 jcr->ExpectedFiles = write_bsr_file(ua, rx);
966 if (jcr->ExpectedFiles == 0) {
971 if (jcr->RestoreBootstrap) {
972 free(jcr->RestoreBootstrap);
974 POOLMEM *fname = get_pool_memory(PM_MESSAGE);
975 make_unique_restore_filename(ua, &fname);
976 jcr->RestoreBootstrap = bstrdup(fname);
979 free_pool_memory(fname);
980 jcr->needs_sd = true;