3 * Bacula Director Job processing routines
5 * Kern Sibbald, October MM
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
14 The main author of Bacula is Kern Sibbald, with contributions from
15 many others, a complete list can be found in the file AUTHORS.
16 This program is Free Software; you can redistribute it and/or
17 modify it under the terms of version two of the GNU General Public
18 License as published by the Free Software Foundation plus additions
19 that are listed in the file LICENSE.
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 Bacula® is a registered trademark of John Walker.
32 The licensor of Bacula is the Free Software Foundation Europe
33 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
34 Switzerland, email:ftf@fsfeurope.org.
40 /* Forward referenced subroutines */
41 static void *job_thread(void *arg);
42 static void job_monitor_watchdog(watchdog_t *self);
43 static void job_monitor_destructor(watchdog_t *self);
44 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
45 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
47 /* Imported subroutines */
48 extern void term_scheduler();
49 extern void term_ua_server();
51 /* Imported variables */
55 void init_job_server(int max_workers)
60 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
62 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror(stat));
65 wd->callback = job_monitor_watchdog;
66 wd->destructor = job_monitor_destructor;
69 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
70 register_watchdog(wd);
73 void term_job_server()
75 jobq_destroy(&job_queue); /* ignore any errors */
79 * Run a job -- typically called by the scheduler, but may also
80 * be called by the UA (Console program).
82 * Returns: 0 on failure
86 JobId_t run_job(JCR *jcr)
90 /* Queue the job to be run */
91 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
93 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
101 bool setup_job(JCR *jcr)
106 sm_check(__FILE__, __LINE__, true);
107 init_msg(jcr, jcr->messages);
109 /* Initialize termination condition variable */
110 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
112 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
115 jcr->term_wait_inited = true;
117 create_unique_job_name(jcr, jcr->job->hdr.name);
118 set_jcr_job_status(jcr, JS_Created);
124 Dmsg0(50, "Open database\n");
125 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
126 jcr->catalog->db_password, jcr->catalog->db_address,
127 jcr->catalog->db_port, jcr->catalog->db_socket,
128 jcr->catalog->mult_db_connections);
129 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
130 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
131 jcr->catalog->db_name);
133 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
137 Dmsg0(50, "DB opened\n");
140 jcr->fname = get_pool_memory(PM_FNAME);
142 if (!jcr->pool_source) {
143 jcr->pool_source = get_pool_memory(PM_MESSAGE);
144 pm_strcpy(jcr->pool_source, _("unknown source"));
146 if (!jcr->storage_source) {
147 jcr->storage_source = get_pool_memory(PM_MESSAGE);
148 pm_strcpy(jcr->storage_source, _("unknown source"));
154 init_jcr_job_record(jcr);
155 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
156 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
159 jcr->JobId = jcr->jr.JobId;
160 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
161 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
163 generate_daemon_event(jcr, "JobStart");
165 if (!get_or_create_client_record(jcr)) {
169 if (job_canceled(jcr)) {
175 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
176 * this allows us to setup a proper job start record for restarting
177 * in case of later errors.
179 switch (jcr->JobType) {
181 if (!do_backup_init(jcr)) {
182 backup_cleanup(jcr, JS_ErrorTerminated);
186 if (!do_verify_init(jcr)) {
187 verify_cleanup(jcr, JS_ErrorTerminated);
191 if (!do_restore_init(jcr)) {
192 restore_cleanup(jcr, JS_ErrorTerminated);
196 if (!do_admin_init(jcr)) {
197 admin_cleanup(jcr, JS_ErrorTerminated);
201 if (!do_migration_init(jcr)) {
202 migration_cleanup(jcr, JS_ErrorTerminated);
206 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
207 set_jcr_job_status(jcr, JS_ErrorTerminated);
211 generate_job_event(jcr, "JobInit");
213 Dmsg0(200, "Add jrc to work queue\n");
222 * This is the engine called by jobq.c:jobq_add() when we were pulled
223 * from the work queue.
224 * At this point, we are running in our own thread and all
225 * necessary resources are allocated -- see jobq.c
227 static void *job_thread(void *arg)
229 JCR *jcr = (JCR *)arg;
231 jcr->my_thread_id = pthread_self();
232 pthread_detach(jcr->my_thread_id);
233 sm_check(__FILE__, __LINE__, true);
235 Dmsg0(200, "=====Start Job=========\n");
236 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
237 jcr->start_time = time(NULL); /* set the real start time */
238 jcr->jr.StartTime = jcr->start_time;
240 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
241 (utime_t)(jcr->start_time - jcr->sched_time)) {
242 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
243 set_jcr_job_status(jcr, JS_Canceled);
246 /* TODO : check if it is used somewhere */
247 if (jcr->job->RunScripts == NULL) {
248 Dmsg0(200, "Warning, job->RunScripts is empty\n");
249 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
252 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
253 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
256 /* Run any script BeforeJob on dird */
257 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
259 if (job_canceled(jcr)) {
260 update_job_end_record(jcr);
264 * We re-update the job start record so that the start
265 * time is set after the run before job. This avoids
266 * that any files created by the run before job will
267 * be saved twice. They will be backed up in the current
268 * job, but not in the next one unless they are changed.
269 * Without this, they will be backed up in this job and
270 * in the next job run because in that case, their date
271 * is after the start of this run.
273 jcr->start_time = time(NULL);
274 jcr->jr.StartTime = jcr->start_time;
275 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
276 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
278 generate_job_event(jcr, "JobRun");
280 switch (jcr->JobType) {
282 if (do_backup(jcr)) {
285 backup_cleanup(jcr, JS_ErrorTerminated);
289 if (do_verify(jcr)) {
292 verify_cleanup(jcr, JS_ErrorTerminated);
296 if (do_restore(jcr)) {
299 restore_cleanup(jcr, JS_ErrorTerminated);
306 admin_cleanup(jcr, JS_ErrorTerminated);
312 if (do_migration(jcr)) {
315 migration_cleanup(jcr, JS_ErrorTerminated);
319 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
323 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
325 /* Send off any queued messages */
326 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
327 dequeue_messages(jcr);
331 generate_daemon_event(jcr, "JobEnd");
332 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
333 sm_check(__FILE__, __LINE__, true);
339 * Cancel a job -- typically called by the UA (Console program), but may also
340 * be called by the job watchdog.
342 * Returns: true if cancel appears to be successful
343 * false on failure. Message sent to ua->jcr.
345 bool cancel_job(UAContext *ua, JCR *jcr)
349 set_jcr_job_status(jcr, JS_Canceled);
351 switch (jcr->JobStatus) {
354 case JS_WaitClientRes:
355 case JS_WaitStoreRes:
356 case JS_WaitPriority:
358 case JS_WaitStartTime:
359 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
360 jcr->JobId, jcr->Job);
361 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
365 /* Cancel File daemon */
366 if (jcr->file_bsock) {
367 ua->jcr->client = jcr->client;
368 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
369 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
372 Dmsg0(200, "Connected to file daemon\n");
373 fd = ua->jcr->file_bsock;
374 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
375 while (bnet_recv(fd) >= 0) {
376 bsendmsg(ua, "%s", fd->msg);
378 bnet_sig(fd, BNET_TERMINATE);
380 ua->jcr->file_bsock = NULL;
383 /* Cancel Storage daemon */
384 if (jcr->store_bsock) {
385 if (!ua->jcr->wstorage) {
387 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
389 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
393 set_wstorage(ua->jcr, jcr->rstore);
395 set_wstorage(ua->jcr, jcr->wstore);
398 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
399 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
402 Dmsg0(200, "Connected to storage daemon\n");
403 sd = ua->jcr->store_bsock;
404 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
405 while (bnet_recv(sd) >= 0) {
406 bsendmsg(ua, "%s", sd->msg);
408 bnet_sig(sd, BNET_TERMINATE);
410 ua->jcr->store_bsock = NULL;
418 static void job_monitor_destructor(watchdog_t *self)
420 JCR *control_jcr = (JCR *)self->data;
422 free_jcr(control_jcr);
425 static void job_monitor_watchdog(watchdog_t *self)
427 JCR *control_jcr, *jcr;
429 control_jcr = (JCR *)self->data;
431 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
436 if (jcr->JobId == 0) {
437 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
442 /* check MaxWaitTime */
443 cancel = job_check_maxwaittime(control_jcr, jcr);
445 /* check MaxRunTime */
446 cancel |= job_check_maxruntime(control_jcr, jcr);
449 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
450 jcr, jcr->JobId, jcr->Job);
452 UAContext *ua = new_ua_context(jcr);
453 ua->jcr = control_jcr;
457 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
460 /* Keep reference counts correct */
466 * Check if the maxwaittime has expired and it is possible
469 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
472 bool ok_to_cancel = false;
475 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
476 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
479 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
480 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
482 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
483 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
485 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
486 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
488 } else if (job->MaxWaitTime != 0 &&
489 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
495 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
497 jcr->JobId, jcr->Job, job->MaxWaitTime);
498 switch (jcr->JobStatus) {
503 case JS_WaitStoreRes:
504 case JS_WaitClientRes:
506 case JS_WaitPriority:
508 case JS_WaitStartTime:
510 Dmsg0(200, "JCR blocked in #1\n");
513 Dmsg0(800, "JCR running, checking SD status\n");
514 switch (jcr->SDJobStatus) {
519 Dmsg0(800, "JCR blocked in #2\n");
522 Dmsg0(800, "JCR not blocked in #2\n");
527 case JS_ErrorTerminated:
530 Dmsg0(800, "JCR already dead in #3\n");
533 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
536 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
537 cancel ? "" : "do not ", jcr, jcr->job);
543 * Check if maxruntime has expired and if the job can be
546 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
550 if (jcr->job->MaxRunTime == 0) {
553 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
554 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
555 jcr, jcr->Job, jcr->job->MaxRunTime);
559 switch (jcr->JobStatus) {
565 case JS_WaitStoreRes:
566 case JS_WaitClientRes:
568 case JS_WaitPriority:
570 case JS_WaitStartTime:
575 case JS_ErrorTerminated:
581 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
585 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
586 cancel ? "" : "do not ", jcr, jcr->job);
592 * Get or create a Pool record with the given name.
593 * Returns: 0 on error
596 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
600 memset(&pr, 0, sizeof(pr));
601 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
603 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
604 /* Try to create the pool */
605 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
606 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
607 db_strerror(jcr->db));
610 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
616 void apply_pool_overrides(JCR *jcr)
618 if (jcr->run_pool_override) {
619 pm_strcpy(jcr->pool_source, _("Run Pool override"));
622 * Apply any level related Pool selections
624 switch (jcr->JobLevel) {
626 if (jcr->full_pool) {
627 jcr->pool = jcr->full_pool;
628 if (jcr->run_full_pool_override) {
629 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
631 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
637 jcr->pool = jcr->inc_pool;
638 if (jcr->run_inc_pool_override) {
639 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
641 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
646 if (jcr->diff_pool) {
647 jcr->pool = jcr->diff_pool;
648 if (jcr->run_diff_pool_override) {
649 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
651 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
660 * Get or create a Client record for this Job
662 bool get_or_create_client_record(JCR *jcr)
666 memset(&cr, 0, sizeof(cr));
667 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
668 cr.AutoPrune = jcr->client->AutoPrune;
669 cr.FileRetention = jcr->client->FileRetention;
670 cr.JobRetention = jcr->client->JobRetention;
671 if (!jcr->client_name) {
672 jcr->client_name = get_pool_memory(PM_NAME);
674 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
675 if (!db_create_client_record(jcr, jcr->db, &cr)) {
676 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
677 db_strerror(jcr->db));
680 jcr->jr.ClientId = cr.ClientId;
682 if (!jcr->client_uname) {
683 jcr->client_uname = get_pool_memory(PM_NAME);
685 pm_strcpy(jcr->client_uname, cr.Uname);
687 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
692 bool get_or_create_fileset_record(JCR *jcr)
696 * Get or Create FileSet record
698 memset(&fsr, 0, sizeof(FILESET_DBR));
699 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
700 if (jcr->fileset->have_MD5) {
701 struct MD5Context md5c;
702 unsigned char digest[MD5HashSize];
703 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
704 MD5Final(digest, &md5c);
706 * Keep the flag (last arg) set to false otherwise old FileSets will
707 * get new MD5 sums and the user will get Full backups on everything
709 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
710 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
712 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
714 if (!jcr->fileset->ignore_fs_changes ||
715 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
716 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
717 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
718 fsr.FileSet, db_strerror(jcr->db));
722 jcr->jr.FileSetId = fsr.FileSetId;
723 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
724 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
729 void init_jcr_job_record(JCR *jcr)
731 jcr->jr.SchedTime = jcr->sched_time;
732 jcr->jr.StartTime = jcr->start_time;
733 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
734 jcr->jr.JobType = jcr->JobType;
735 jcr->jr.JobLevel = jcr->JobLevel;
736 jcr->jr.JobStatus = jcr->JobStatus;
737 jcr->jr.JobId = jcr->JobId;
738 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
739 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
743 * Write status and such in DB
745 void update_job_end_record(JCR *jcr)
747 jcr->jr.EndTime = time(NULL);
748 jcr->end_time = jcr->jr.EndTime;
749 jcr->jr.JobId = jcr->JobId;
750 jcr->jr.JobStatus = jcr->JobStatus;
751 jcr->jr.JobFiles = jcr->JobFiles;
752 jcr->jr.JobBytes = jcr->JobBytes;
753 jcr->jr.VolSessionId = jcr->VolSessionId;
754 jcr->jr.VolSessionTime = jcr->VolSessionTime;
755 jcr->jr.JobErrors = jcr->Errors;
756 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
757 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
758 db_strerror(jcr->db));
763 * Takes base_name and appends (unique) current
764 * date and time to form unique job name.
766 * Returns: unique job name in jcr->Job
767 * date/time in jcr->start_time
769 void create_unique_job_name(JCR *jcr, const char *base_name)
771 /* Job start mutex */
772 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
773 static time_t last_start_time = 0;
776 char dt[MAX_TIME_LENGTH];
777 char name[MAX_NAME_LENGTH];
780 /* Guarantee unique start time -- maximum one per second, and
781 * thus unique Job Name
783 P(mutex); /* lock creation of jobs */
785 while (now == last_start_time) {
786 bmicrosleep(0, 500000);
789 last_start_time = now;
790 V(mutex); /* allow creation of jobs */
791 jcr->start_time = now;
792 /* Form Unique JobName */
793 (void)localtime_r(&now, &tm);
794 /* Use only characters that are permitted in Windows filenames */
795 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
796 bstrncpy(name, base_name, sizeof(name));
797 name[sizeof(name)-22] = 0; /* truncate if too long */
798 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
799 /* Convert spaces into underscores */
800 for (p=jcr->Job; *p; p++) {
807 /* Called directly from job rescheduling */
808 void dird_free_jcr_pointers(JCR *jcr)
810 if (jcr->sd_auth_key) {
811 free(jcr->sd_auth_key);
812 jcr->sd_auth_key = NULL;
818 if (jcr->file_bsock) {
819 Dmsg0(200, "Close File bsock\n");
820 bnet_close(jcr->file_bsock);
821 jcr->file_bsock = NULL;
823 if (jcr->store_bsock) {
824 Dmsg0(200, "Close Store bsock\n");
825 bnet_close(jcr->store_bsock);
826 jcr->store_bsock = NULL;
829 Dmsg0(200, "Free JCR fname\n");
830 free_pool_memory(jcr->fname);
833 if (jcr->pool_source) {
834 free_pool_memory(jcr->pool_source);
835 jcr->pool_source = NULL;
837 if (jcr->storage_source) {
838 free_pool_memory(jcr->storage_source);
839 jcr->storage_source = NULL;
842 Dmsg0(200, "Free JCR stime\n");
843 free_pool_memory(jcr->stime);
846 if (jcr->RestoreBootstrap) {
847 free(jcr->RestoreBootstrap);
848 jcr->RestoreBootstrap = NULL;
850 if (jcr->client_uname) {
851 free_pool_memory(jcr->client_uname);
852 jcr->client_uname = NULL;
855 free_pool_memory(jcr->attr);
865 * Free the Job Control Record if no one is still using it.
866 * Called from main free_jcr() routine in src/lib/jcr.c so
867 * that we can do our Director specific cleanup of the jcr.
869 void dird_free_jcr(JCR *jcr)
871 Dmsg0(200, "Start dird free_jcr\n");
873 dird_free_jcr_pointers(jcr);
874 if (jcr->term_wait_inited) {
875 pthread_cond_destroy(&jcr->term_wait);
876 jcr->term_wait_inited = false;
879 /* Delete lists setup to hold storage pointers */
882 jcr->job_end_push.destroy();
883 Dmsg0(200, "End dird free_jcr\n");
887 * Set some defaults in the JCR necessary to
888 * run. These items are pulled from the job
889 * definition as defaults, but can be overridden
890 * later either by the Run record in the Schedule resource,
891 * or by the Console program.
893 void set_jcr_defaults(JCR *jcr, JOB *job)
896 jcr->JobType = job->JobType;
897 switch (jcr->JobType) {
900 jcr->JobLevel = L_NONE;
903 jcr->JobLevel = job->JobLevel;
907 jcr->fname = get_pool_memory(PM_FNAME);
909 if (!jcr->pool_source) {
910 jcr->pool_source = get_pool_memory(PM_MESSAGE);
911 pm_strcpy(jcr->pool_source, _("unknown source"));
913 if (!jcr->storage_source) {
914 jcr->storage_source = get_pool_memory(PM_MESSAGE);
915 pm_strcpy(jcr->storage_source, _("unknown source"));
917 jcr->JobPriority = job->Priority;
918 /* Copy storage definitions -- deleted in dir_free_jcr above */
919 copy_rwstorage(jcr, job->storage, _("Job resource"));
920 jcr->client = job->client;
921 if (!jcr->client_name) {
922 jcr->client_name = get_pool_memory(PM_NAME);
924 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
925 pm_strcpy(jcr->pool_source, _("Job resource"));
926 jcr->pool = job->pool;
927 jcr->full_pool = job->full_pool;
928 jcr->inc_pool = job->inc_pool;
929 jcr->diff_pool = job->diff_pool;
930 jcr->catalog = job->client->catalog;
931 jcr->fileset = job->fileset;
932 jcr->messages = job->messages;
933 jcr->spool_data = job->spool_data;
934 jcr->write_part_after_job = job->write_part_after_job;
935 if (jcr->RestoreBootstrap) {
936 free(jcr->RestoreBootstrap);
937 jcr->RestoreBootstrap = NULL;
939 /* This can be overridden by Console program */
940 if (job->RestoreBootstrap) {
941 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
943 /* This can be overridden by Console program */
944 jcr->verify_job = job->verify_job;
945 /* If no default level given, set one */
946 if (jcr->JobLevel == 0) {
947 switch (jcr->JobType) {
949 jcr->JobLevel = L_VERIFY_CATALOG;
952 jcr->JobLevel = L_INCREMENTAL;
956 jcr->JobLevel = L_NONE;
965 * Copy the storage definitions from an alist to the JCR
967 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
969 copy_rstorage(jcr, storage, where);
970 copy_wstorage(jcr, storage, where);
974 /* Set storage override */
975 void set_rwstorage(JCR *jcr, STORE *store)
977 set_rstorage(jcr, store);
978 set_wstorage(jcr, store);
981 void free_rwstorage(JCR *jcr)
988 * Copy the storage definitions from an alist to the JCR
990 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
995 delete jcr->rstorage;
997 jcr->rstorage = New(alist(10, not_owned_by_alist));
998 foreach_alist(st, storage) {
999 jcr->rstorage->append(st);
1001 pm_strcpy(jcr->storage_source, where);
1003 if (jcr->rstorage) {
1004 jcr->rstore = (STORE *)jcr->rstorage->first();
1009 /* Set storage override */
1010 void set_rstorage(JCR *jcr, STORE *store)
1014 jcr->rstore = store;
1015 foreach_alist(storage, jcr->rstorage) {
1016 if (store == storage) {
1020 /* Store not in list, so add it */
1021 jcr->rstorage->prepend(store);
1024 void free_rstorage(JCR *jcr)
1026 if (jcr->rstorage) {
1027 delete jcr->rstorage;
1028 jcr->rstorage = NULL;
1034 * Copy the storage definitions from an alist to the JCR
1036 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1040 if (jcr->wstorage) {
1041 delete jcr->wstorage;
1043 jcr->wstorage = New(alist(10, not_owned_by_alist));
1044 foreach_alist(st, storage) {
1045 jcr->wstorage->append(st);
1047 pm_strcpy(jcr->storage_source, where);
1049 if (jcr->wstorage) {
1050 jcr->wstore = (STORE *)jcr->wstorage->first();
1055 /* Set storage override */
1056 void set_wstorage(JCR *jcr, STORE *store)
1060 jcr->wstore = store;
1061 foreach_alist(storage, jcr->wstorage) {
1062 if (store == storage) {
1066 /* Store not in list, so add it */
1067 jcr->wstorage->prepend(store);
1070 void free_wstorage(JCR *jcr)
1072 if (jcr->wstorage) {
1073 delete jcr->wstorage;
1074 jcr->wstorage = NULL;
1081 void create_clones(JCR *jcr)
1084 * Fire off any clone jobs (run directives)
1086 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1087 if (!jcr->cloned && jcr->job->run_cmds) {
1089 JOB *job = jcr->job;
1090 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1091 UAContext *ua = new_ua_context(jcr);
1093 foreach_alist(runcmd, job->run_cmds) {
1094 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1095 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1096 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1097 parse_ua_args(ua); /* parse command */
1098 int stat = run_cmd(ua, ua->cmd);
1100 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1102 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1105 free_ua_context(ua);
1106 free_pool_memory(cmd);
1110 bool create_restore_bootstrap_file(JCR *jcr)
1114 memset(&rx, 0, sizeof(rx));
1117 rx.bsr->JobId = jcr->previous_jr.JobId;
1118 ua = new_ua_context(jcr);
1119 complete_bsr(ua, rx.bsr);
1120 rx.bsr->fi = new_findex();
1121 rx.bsr->fi->findex = 1;
1122 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1123 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1124 if (jcr->ExpectedFiles == 0) {
1125 free_ua_context(ua);
1129 free_ua_context(ua);
1131 jcr->needs_sd = true;