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);
230 if (!do_mac_init(jcr)) { /* migration, archive, copy */
231 mac_cleanup(jcr, JS_ErrorTerminated);
235 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
236 set_jcr_job_status(jcr, JS_ErrorTerminated);
240 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
241 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
244 if (job_canceled(jcr)) {
245 update_job_end_record(jcr);
250 if (jcr->job->RunBeforeJob) {
251 POOLMEM *before = get_pool_memory(PM_FNAME);
254 char line[MAXSTRING];
256 before = edit_job_codes(jcr, before, jcr->job->RunBeforeJob, "");
257 bpipe = open_bpipe(before, 0, "r");
258 free_pool_memory(before);
259 while (fgets(line, sizeof(line), bpipe->rfd)) {
260 Jmsg(jcr, M_INFO, 0, _("RunBefore: %s"), line);
262 status = close_bpipe(bpipe);
265 Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror(status));
266 set_jcr_job_status(jcr, JS_FatalError);
267 update_job_end_record(jcr);
272 generate_job_event(jcr, "JobRun");
274 switch (jcr->JobType) {
276 if (do_backup(jcr)) {
279 backup_cleanup(jcr, JS_ErrorTerminated);
283 if (do_verify(jcr)) {
286 verify_cleanup(jcr, JS_ErrorTerminated);
290 if (do_restore(jcr)) {
293 restore_cleanup(jcr, JS_ErrorTerminated);
300 admin_cleanup(jcr, JS_ErrorTerminated);
306 if (do_mac(jcr)) { /* migration, archive, copy */
309 mac_cleanup(jcr, JS_ErrorTerminated);
313 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
316 if ((jcr->job->RunAfterJob && jcr->JobStatus == JS_Terminated) ||
317 (jcr->job->RunAfterFailedJob && jcr->JobStatus != JS_Terminated)) {
318 POOLMEM *after = get_pool_memory(PM_FNAME);
321 char line[MAXSTRING];
323 if (jcr->JobStatus == JS_Terminated) {
324 after = edit_job_codes(jcr, after, jcr->job->RunAfterJob, "");
326 after = edit_job_codes(jcr, after, jcr->job->RunAfterFailedJob, "");
328 bpipe = open_bpipe(after, 0, "r");
329 free_pool_memory(after);
330 while (fgets(line, sizeof(line), bpipe->rfd)) {
331 Jmsg(jcr, M_INFO, 0, _("RunAfter: %s"), line);
333 status = close_bpipe(bpipe);
335 * Note, if we get an error here, do not mark the
336 * job in error, simply report the error condition.
340 if (jcr->JobStatus == JS_Terminated) {
341 Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror(status));
343 Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror(status));
347 /* Send off any queued messages */
348 if (jcr->msg_queue->size() > 0) {
349 dequeue_messages(jcr);
354 generate_daemon_event(jcr, "JobEnd");
355 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
356 sm_check(__FILE__, __LINE__, true);
362 * Cancel a job -- typically called by the UA (Console program), but may also
363 * be called by the job watchdog.
365 * Returns: true if cancel appears to be successful
366 * false on failure. Message sent to ua->jcr.
368 bool cancel_job(UAContext *ua, JCR *jcr)
372 set_jcr_job_status(jcr, JS_Canceled);
374 switch (jcr->JobStatus) {
377 case JS_WaitClientRes:
378 case JS_WaitStoreRes:
379 case JS_WaitPriority:
381 case JS_WaitStartTime:
382 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
383 jcr->JobId, jcr->Job);
384 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
388 /* Cancel File daemon */
389 if (jcr->file_bsock) {
390 ua->jcr->client = jcr->client;
391 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
392 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
395 Dmsg0(200, "Connected to file daemon\n");
396 fd = ua->jcr->file_bsock;
397 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
398 while (bnet_recv(fd) >= 0) {
399 bsendmsg(ua, "%s", fd->msg);
401 bnet_sig(fd, BNET_TERMINATE);
403 ua->jcr->file_bsock = NULL;
406 /* Cancel Storage daemon */
407 if (jcr->store_bsock) {
408 if (!ua->jcr->storage) {
409 copy_storage(ua->jcr, jcr->storage);
411 set_storage(ua->jcr, jcr->store);
413 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
414 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
417 Dmsg0(200, "Connected to storage daemon\n");
418 sd = ua->jcr->store_bsock;
419 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
420 while (bnet_recv(sd) >= 0) {
421 bsendmsg(ua, "%s", sd->msg);
423 bnet_sig(sd, BNET_TERMINATE);
425 ua->jcr->store_bsock = NULL;
433 static void job_monitor_destructor(watchdog_t *self)
435 JCR *control_jcr = (JCR *)self->data;
437 free_jcr(control_jcr);
440 static void job_monitor_watchdog(watchdog_t *self)
442 JCR *control_jcr, *jcr;
444 control_jcr = (JCR *)self->data;
446 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
451 if (jcr->JobId == 0) {
452 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
457 /* check MaxWaitTime */
458 cancel = job_check_maxwaittime(control_jcr, jcr);
460 /* check MaxRunTime */
461 cancel |= job_check_maxruntime(control_jcr, jcr);
464 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
465 jcr, jcr->JobId, jcr->Job);
467 UAContext *ua = new_ua_context(jcr);
468 ua->jcr = control_jcr;
472 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
475 /* Keep reference counts correct */
481 * Check if the maxwaittime has expired and it is possible
484 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
487 bool ok_to_cancel = false;
490 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
491 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
494 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
495 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
497 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
498 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
500 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
501 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
503 } else if (job->MaxWaitTime != 0 &&
504 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
510 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
512 jcr->JobId, jcr->Job, job->MaxWaitTime);
513 switch (jcr->JobStatus) {
518 case JS_WaitStoreRes:
519 case JS_WaitClientRes:
521 case JS_WaitPriority:
523 case JS_WaitStartTime:
525 Dmsg0(200, "JCR blocked in #1\n");
528 Dmsg0(800, "JCR running, checking SD status\n");
529 switch (jcr->SDJobStatus) {
534 Dmsg0(800, "JCR blocked in #2\n");
537 Dmsg0(800, "JCR not blocked in #2\n");
542 case JS_ErrorTerminated:
545 Dmsg0(800, "JCR already dead in #3\n");
548 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
551 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
552 cancel ? "" : "do not ", jcr, jcr->job);
558 * Check if maxruntime has expired and if the job can be
561 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
565 if (jcr->job->MaxRunTime == 0) {
568 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
569 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
570 jcr, jcr->Job, jcr->job->MaxRunTime);
574 switch (jcr->JobStatus) {
580 case JS_WaitStoreRes:
581 case JS_WaitClientRes:
583 case JS_WaitPriority:
585 case JS_WaitStartTime:
590 case JS_ErrorTerminated:
596 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
600 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
601 cancel ? "" : "do not ", jcr, jcr->job);
608 * Get or create a Client record for this Job
610 bool get_or_create_client_record(JCR *jcr)
614 memset(&cr, 0, sizeof(cr));
615 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
616 cr.AutoPrune = jcr->client->AutoPrune;
617 cr.FileRetention = jcr->client->FileRetention;
618 cr.JobRetention = jcr->client->JobRetention;
619 if (!jcr->client_name) {
620 jcr->client_name = get_pool_memory(PM_NAME);
622 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
623 if (!db_create_client_record(jcr, jcr->db, &cr)) {
624 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
625 db_strerror(jcr->db));
628 jcr->jr.ClientId = cr.ClientId;
630 if (!jcr->client_uname) {
631 jcr->client_uname = get_pool_memory(PM_NAME);
633 pm_strcpy(jcr->client_uname, cr.Uname);
635 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
640 bool get_or_create_fileset_record(JCR *jcr)
644 * Get or Create FileSet record
646 memset(&fsr, 0, sizeof(FILESET_DBR));
647 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
648 if (jcr->fileset->have_MD5) {
649 struct MD5Context md5c;
650 unsigned char digest[MD5HashSize];
651 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
652 MD5Final(digest, &md5c);
653 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
654 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
656 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
658 if (!jcr->fileset->ignore_fs_changes ||
659 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
660 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
661 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
662 fsr.FileSet, db_strerror(jcr->db));
666 jcr->jr.FileSetId = fsr.FileSetId;
667 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
668 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
673 void init_jcr_job_record(JCR *jcr)
675 jcr->jr.SchedTime = jcr->sched_time;
676 jcr->jr.StartTime = jcr->start_time;
677 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
678 jcr->jr.JobType = jcr->JobType;
679 jcr->jr.JobLevel = jcr->JobLevel;
680 jcr->jr.JobStatus = jcr->JobStatus;
681 jcr->jr.JobId = jcr->JobId;
682 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
683 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
687 * Write status and such in DB
689 void update_job_end_record(JCR *jcr)
691 jcr->jr.EndTime = time(NULL);
692 jcr->end_time = jcr->jr.EndTime;
693 jcr->jr.JobId = jcr->JobId;
694 jcr->jr.JobStatus = jcr->JobStatus;
695 jcr->jr.JobFiles = jcr->JobFiles;
696 jcr->jr.JobBytes = jcr->JobBytes;
697 jcr->jr.VolSessionId = jcr->VolSessionId;
698 jcr->jr.VolSessionTime = jcr->VolSessionTime;
699 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
700 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
701 db_strerror(jcr->db));
706 * Takes base_name and appends (unique) current
707 * date and time to form unique job name.
709 * Returns: unique job name in jcr->Job
710 * date/time in jcr->start_time
712 void create_unique_job_name(JCR *jcr, const char *base_name)
714 /* Job start mutex */
715 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
716 static time_t last_start_time = 0;
719 char dt[MAX_TIME_LENGTH];
720 char name[MAX_NAME_LENGTH];
723 /* Guarantee unique start time -- maximum one per second, and
724 * thus unique Job Name
726 P(mutex); /* lock creation of jobs */
728 while (now == last_start_time) {
729 bmicrosleep(0, 500000);
732 last_start_time = now;
733 V(mutex); /* allow creation of jobs */
734 jcr->start_time = now;
735 /* Form Unique JobName */
736 localtime_r(&now, &tm);
737 /* Use only characters that are permitted in Windows filenames */
738 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
739 bstrncpy(name, base_name, sizeof(name));
740 name[sizeof(name)-22] = 0; /* truncate if too long */
741 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
742 /* Convert spaces into underscores */
743 for (p=jcr->Job; *p; p++) {
750 /* Called directly from job rescheduling */
751 void dird_free_jcr_pointers(JCR *jcr)
753 if (jcr->sd_auth_key) {
754 free(jcr->sd_auth_key);
755 jcr->sd_auth_key = NULL;
761 if (jcr->file_bsock) {
762 Dmsg0(200, "Close File bsock\n");
763 bnet_close(jcr->file_bsock);
764 jcr->file_bsock = NULL;
766 if (jcr->store_bsock) {
767 Dmsg0(200, "Close Store bsock\n");
768 bnet_close(jcr->store_bsock);
769 jcr->store_bsock = NULL;
772 Dmsg0(200, "Free JCR fname\n");
773 free_pool_memory(jcr->fname);
777 Dmsg0(200, "Free JCR stime\n");
778 free_pool_memory(jcr->stime);
781 if (jcr->RestoreBootstrap) {
782 free(jcr->RestoreBootstrap);
783 jcr->RestoreBootstrap = NULL;
785 if (jcr->client_uname) {
786 free_pool_memory(jcr->client_uname);
787 jcr->client_uname = NULL;
789 if (jcr->term_wait_inited) {
790 pthread_cond_destroy(&jcr->term_wait);
791 jcr->term_wait_inited = false;
794 free_pool_memory(jcr->attr);
804 * Free the Job Control Record if no one is still using it.
805 * Called from main free_jcr() routine in src/lib/jcr.c so
806 * that we can do our Director specific cleanup of the jcr.
808 void dird_free_jcr(JCR *jcr)
810 Dmsg0(200, "Start dird free_jcr\n");
812 dird_free_jcr_pointers(jcr);
814 /* Delete lists setup to hold storage pointers */
818 jcr->job_end_push.destroy();
819 Dmsg0(200, "End dird free_jcr\n");
823 * Set some defaults in the JCR necessary to
824 * run. These items are pulled from the job
825 * definition as defaults, but can be overridden
826 * later either by the Run record in the Schedule resource,
827 * or by the Console program.
829 void set_jcr_defaults(JCR *jcr, JOB *job)
832 jcr->JobType = job->JobType;
833 switch (jcr->JobType) {
836 jcr->JobLevel = L_NONE;
839 jcr->JobLevel = job->JobLevel;
842 jcr->JobPriority = job->Priority;
843 /* Copy storage definitions -- deleted in dir_free_jcr above */
844 copy_storage(jcr, job->storage);
845 jcr->client = job->client;
846 if (!jcr->client_name) {
847 jcr->client_name = get_pool_memory(PM_NAME);
849 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
850 jcr->pool = job->pool;
851 jcr->full_pool = job->full_pool;
852 jcr->inc_pool = job->inc_pool;
853 jcr->dif_pool = job->dif_pool;
854 jcr->catalog = job->client->catalog;
855 jcr->fileset = job->fileset;
856 jcr->messages = job->messages;
857 jcr->spool_data = job->spool_data;
858 jcr->write_part_after_job = job->write_part_after_job;
859 if (jcr->RestoreBootstrap) {
860 free(jcr->RestoreBootstrap);
861 jcr->RestoreBootstrap = NULL;
863 /* This can be overridden by Console program */
864 if (job->RestoreBootstrap) {
865 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
867 /* This can be overridden by Console program */
868 jcr->verify_job = job->verify_job;
869 /* If no default level given, set one */
870 if (jcr->JobLevel == 0) {
871 switch (jcr->JobType) {
873 jcr->JobLevel = L_VERIFY_CATALOG;
876 jcr->JobLevel = L_INCREMENTAL;
880 jcr->JobLevel = L_NONE;
890 * Copy the storage definitions from an alist to the JCR
892 void copy_storage(JCR *jcr, alist *storage)
899 jcr->storage = New(alist(10, not_owned_by_alist));
900 foreach_alist(st, storage) {
901 jcr->storage->append(st);
905 jcr->store = (STORE *)jcr->storage->first();
910 /* Set storage override */
911 void set_storage(JCR *jcr, STORE *store)
916 foreach_alist(storage, jcr->storage) {
917 if (store == storage) {
921 /* Store not in list, so add it */
922 jcr->storage->prepend(store);
925 void create_clones(JCR *jcr)
928 * Fire off any clone jobs (run directives)
930 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
931 if (!jcr->cloned && jcr->job->run_cmds) {
934 POOLMEM *cmd = get_pool_memory(PM_FNAME);
935 UAContext *ua = new_ua_context(jcr);
937 foreach_alist(runcmd, job->run_cmds) {
938 cmd = edit_job_codes(jcr, cmd, runcmd, "");
939 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
940 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
941 parse_ua_args(ua); /* parse command */
942 int stat = run_cmd(ua, ua->cmd);
944 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
946 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
950 free_pool_memory(cmd);
954 bool create_restore_bootstrap_file(JCR *jcr)
958 memset(&rx, 0, sizeof(rx));
961 rx.bsr->JobId = jcr->target_jr.JobId;
962 ua = new_ua_context(jcr);
963 complete_bsr(ua, rx.bsr);
964 rx.bsr->fi = new_findex();
965 rx.bsr->fi->findex = 1;
966 rx.bsr->fi->findex2 = jcr->target_jr.JobFiles;
967 jcr->ExpectedFiles = write_bsr_file(ua, rx);
968 if (jcr->ExpectedFiles == 0) {
973 if (jcr->RestoreBootstrap) {
974 free(jcr->RestoreBootstrap);
976 POOLMEM *fname = get_pool_memory(PM_MESSAGE);
977 make_unique_restore_filename(ua, &fname);
978 jcr->RestoreBootstrap = bstrdup(fname);
981 free_pool_memory(fname);
982 jcr->needs_sd = true;