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 Dmsg0(200, "Add jrc to work queue\n");
91 /* Queue the job to be run */
92 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
94 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
102 bool setup_job(JCR *jcr)
107 sm_check(__FILE__, __LINE__, true);
108 init_msg(jcr, jcr->messages);
110 /* Initialize termination condition variable */
111 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
113 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
116 jcr->term_wait_inited = true;
118 create_unique_job_name(jcr, jcr->job->hdr.name);
119 set_jcr_job_status(jcr, JS_Created);
125 Dmsg0(50, "Open database\n");
126 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
127 jcr->catalog->db_password, jcr->catalog->db_address,
128 jcr->catalog->db_port, jcr->catalog->db_socket,
129 jcr->catalog->mult_db_connections);
130 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
131 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
132 jcr->catalog->db_name);
134 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
138 Dmsg0(50, "DB opened\n");
141 jcr->fname = get_pool_memory(PM_FNAME);
143 if (!jcr->pool_source) {
144 jcr->pool_source = get_pool_memory(PM_MESSAGE);
145 pm_strcpy(jcr->pool_source, _("unknown source"));
151 init_jcr_job_record(jcr);
152 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
153 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
156 jcr->JobId = jcr->jr.JobId;
157 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
158 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
160 if (!get_or_create_client_record(jcr)) {
164 generate_daemon_event(jcr, "JobStart");
166 if (job_canceled(jcr)) {
172 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
173 * this allows us to setup a proper job start record for restarting
174 * in case of later errors.
176 switch (jcr->JobType) {
178 if (!do_backup_init(jcr)) {
179 backup_cleanup(jcr, JS_ErrorTerminated);
183 if (!do_verify_init(jcr)) {
184 verify_cleanup(jcr, JS_ErrorTerminated);
188 if (!do_restore_init(jcr)) {
189 restore_cleanup(jcr, JS_ErrorTerminated);
193 if (!do_admin_init(jcr)) {
194 admin_cleanup(jcr, JS_ErrorTerminated);
198 if (!do_migration_init(jcr)) {
199 migration_cleanup(jcr, JS_ErrorTerminated);
203 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
204 set_jcr_job_status(jcr, JS_ErrorTerminated);
208 generate_job_event(jcr, "JobInit");
217 * This is the engine called by jobq.c:jobq_add() when we were pulled
218 * from the work queue.
219 * At this point, we are running in our own thread and all
220 * necessary resources are allocated -- see jobq.c
222 static void *job_thread(void *arg)
224 JCR *jcr = (JCR *)arg;
226 jcr->my_thread_id = pthread_self();
227 pthread_detach(jcr->my_thread_id);
228 sm_check(__FILE__, __LINE__, true);
230 Dmsg0(200, "=====Start Job=========\n");
231 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
232 jcr->start_time = time(NULL); /* set the real start time */
233 jcr->jr.StartTime = jcr->start_time;
235 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
236 (utime_t)(jcr->start_time - jcr->sched_time)) {
237 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
238 set_jcr_job_status(jcr, JS_Canceled);
241 /* TODO : check if it is used somewhere */
242 if (jcr->job->RunScripts == NULL) {
243 Dmsg0(200, "Warning, job->RunScripts is empty\n");
244 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
247 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
248 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
251 /* Run any script BeforeJob on dird */
252 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
254 if (job_canceled(jcr)) {
255 update_job_end_record(jcr);
259 * We re-update the job start record so that the start
260 * time is set after the run before job. This avoids
261 * that any files created by the run before job will
262 * be saved twice. They will be backed up in the current
263 * job, but not in the next one unless they are changed.
264 * Without this, they will be backed up in this job and
265 * in the next job run because in that case, their date
266 * is after the start of this run.
268 jcr->start_time = time(NULL);
269 jcr->jr.StartTime = jcr->start_time;
270 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
271 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
273 generate_job_event(jcr, "JobRun");
275 switch (jcr->JobType) {
277 if (do_backup(jcr)) {
280 backup_cleanup(jcr, JS_ErrorTerminated);
284 if (do_verify(jcr)) {
287 verify_cleanup(jcr, JS_ErrorTerminated);
291 if (do_restore(jcr)) {
294 restore_cleanup(jcr, JS_ErrorTerminated);
301 admin_cleanup(jcr, JS_ErrorTerminated);
307 if (do_migration(jcr)) {
310 migration_cleanup(jcr, JS_ErrorTerminated);
314 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
318 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
320 /* Send off any queued messages */
321 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
322 dequeue_messages(jcr);
326 generate_daemon_event(jcr, "JobEnd");
327 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
328 sm_check(__FILE__, __LINE__, true);
334 * Cancel a job -- typically called by the UA (Console program), but may also
335 * be called by the job watchdog.
337 * Returns: true if cancel appears to be successful
338 * false on failure. Message sent to ua->jcr.
340 bool cancel_job(UAContext *ua, JCR *jcr)
344 set_jcr_job_status(jcr, JS_Canceled);
346 switch (jcr->JobStatus) {
349 case JS_WaitClientRes:
350 case JS_WaitStoreRes:
351 case JS_WaitPriority:
353 case JS_WaitStartTime:
354 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
355 jcr->JobId, jcr->Job);
356 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
360 /* Cancel File daemon */
361 if (jcr->file_bsock) {
362 ua->jcr->client = jcr->client;
363 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
364 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
367 Dmsg0(200, "Connected to file daemon\n");
368 fd = ua->jcr->file_bsock;
369 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
370 while (bnet_recv(fd) >= 0) {
371 bsendmsg(ua, "%s", fd->msg);
373 bnet_sig(fd, BNET_TERMINATE);
375 ua->jcr->file_bsock = NULL;
378 /* Cancel Storage daemon */
379 if (jcr->store_bsock) {
380 if (!ua->jcr->wstorage) {
382 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
384 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
389 store.store = jcr->rstore;
390 pm_strcpy(store.store_source, jcr->rstore_source);
392 store.store = jcr->wstore;
393 pm_strcpy(store.store_source, jcr->wstore_source);
395 set_wstorage(ua->jcr, &store);
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->wstore_source) {
838 free_pool_memory(jcr->wstore_source);
839 jcr->wstore_source = NULL;
841 if (jcr->rstore_source) {
842 free_pool_memory(jcr->rstore_source);
843 jcr->rstore_source = NULL;
846 Dmsg0(200, "Free JCR stime\n");
847 free_pool_memory(jcr->stime);
850 if (jcr->RestoreBootstrap) {
851 free(jcr->RestoreBootstrap);
852 jcr->RestoreBootstrap = NULL;
854 if (jcr->client_uname) {
855 free_pool_memory(jcr->client_uname);
856 jcr->client_uname = NULL;
859 free_pool_memory(jcr->attr);
869 * Free the Job Control Record if no one is still using it.
870 * Called from main free_jcr() routine in src/lib/jcr.c so
871 * that we can do our Director specific cleanup of the jcr.
873 void dird_free_jcr(JCR *jcr)
875 Dmsg0(200, "Start dird free_jcr\n");
877 dird_free_jcr_pointers(jcr);
878 if (jcr->term_wait_inited) {
879 pthread_cond_destroy(&jcr->term_wait);
880 jcr->term_wait_inited = false;
883 /* Delete lists setup to hold storage pointers */
886 jcr->job_end_push.destroy();
887 Dmsg0(200, "End dird free_jcr\n");
891 * The Job storage definition must be either in the Job record
892 * or in the Pool record. The Pool record overrides the Job
895 void get_job_storage(USTORE *store, JOB *job, RUN *run)
897 if (run && run->pool && run->pool->storage) {
898 store->store = (STORE *)run->pool->storage->first();
899 pm_strcpy(store->store_source, _("Run pool override"));
902 if (run && run->storage) {
903 store->store = run->storage;
904 pm_strcpy(store->store_source, _("Run storage override"));
907 if (job->pool->storage) {
908 store->store = (STORE *)job->pool->storage->first();
909 pm_strcpy(store->store_source, _("Pool resource"));
911 store->store = (STORE *)job->storage->first();
912 pm_strcpy(store->store_source, _("Job resource"));
917 * Set some defaults in the JCR necessary to
918 * run. These items are pulled from the job
919 * definition as defaults, but can be overridden
920 * later either by the Run record in the Schedule resource,
921 * or by the Console program.
923 void set_jcr_defaults(JCR *jcr, JOB *job)
926 jcr->JobType = job->JobType;
927 switch (jcr->JobType) {
930 jcr->JobLevel = L_NONE;
933 jcr->JobLevel = job->JobLevel;
937 jcr->fname = get_pool_memory(PM_FNAME);
939 if (!jcr->pool_source) {
940 jcr->pool_source = get_pool_memory(PM_MESSAGE);
941 pm_strcpy(jcr->pool_source, _("unknown source"));
943 jcr->JobPriority = job->Priority;
944 /* Copy storage definitions -- deleted in dir_free_jcr above */
946 copy_rwstorage(jcr, job->storage, _("Job resource"));
948 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
950 jcr->client = job->client;
951 if (!jcr->client_name) {
952 jcr->client_name = get_pool_memory(PM_NAME);
954 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
955 pm_strcpy(jcr->pool_source, _("Job resource"));
956 jcr->pool = job->pool;
957 jcr->full_pool = job->full_pool;
958 jcr->inc_pool = job->inc_pool;
959 jcr->diff_pool = job->diff_pool;
960 jcr->catalog = job->client->catalog;
961 jcr->fileset = job->fileset;
962 jcr->messages = job->messages;
963 jcr->spool_data = job->spool_data;
964 jcr->write_part_after_job = job->write_part_after_job;
965 if (jcr->RestoreBootstrap) {
966 free(jcr->RestoreBootstrap);
967 jcr->RestoreBootstrap = NULL;
969 /* This can be overridden by Console program */
970 if (job->RestoreBootstrap) {
971 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
973 /* This can be overridden by Console program */
974 jcr->verify_job = job->verify_job;
975 /* If no default level given, set one */
976 if (jcr->JobLevel == 0) {
977 switch (jcr->JobType) {
979 jcr->JobLevel = L_VERIFY_CATALOG;
982 jcr->JobLevel = L_INCREMENTAL;
986 jcr->JobLevel = L_NONE;
989 jcr->JobLevel = L_FULL;
996 * Copy the storage definitions from an alist to the JCR
998 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1000 switch(jcr->JobType) {
1004 copy_rstorage(jcr, storage, where);
1007 copy_wstorage(jcr, storage, where);
1013 /* Set storage override */
1014 void set_rwstorage(JCR *jcr, USTORE *store)
1017 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1020 switch(jcr->JobType) {
1024 set_rstorage(jcr, store);
1027 set_wstorage(jcr, store);
1032 void free_rwstorage(JCR *jcr)
1039 * Copy the storage definitions from an alist to the JCR
1041 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1045 if (jcr->rstorage) {
1046 delete jcr->rstorage;
1048 jcr->rstorage = New(alist(10, not_owned_by_alist));
1049 foreach_alist(st, storage) {
1050 jcr->rstorage->append(st);
1052 if (!jcr->rstore_source) {
1053 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1055 pm_strcpy(jcr->rstore_source, where);
1056 if (jcr->rstorage) {
1057 jcr->rstore = (STORE *)jcr->rstorage->first();
1063 /* Set storage override */
1064 void set_rstorage(JCR *jcr, USTORE *store)
1068 if (!store->store) {
1071 if (!jcr->rstorage) {
1072 jcr->rstorage = New(alist(10, not_owned_by_alist));
1074 jcr->rstore = store->store;
1075 if (!jcr->rstore_source) {
1076 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1078 pm_strcpy(jcr->rstore_source, store->store_source);
1079 foreach_alist(storage, jcr->rstorage) {
1080 if (store->store == storage) {
1084 /* Store not in list, so add it */
1085 jcr->rstorage->prepend(store->store);
1088 void free_rstorage(JCR *jcr)
1090 if (jcr->rstorage) {
1091 delete jcr->rstorage;
1092 jcr->rstorage = NULL;
1098 * Copy the storage definitions from an alist to the JCR
1100 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1104 if (jcr->wstorage) {
1105 delete jcr->wstorage;
1107 jcr->wstorage = New(alist(10, not_owned_by_alist));
1108 foreach_alist(st, storage) {
1109 Dmsg1(50, "storage=%s\n", st->name());
1110 jcr->wstorage->append(st);
1112 if (!jcr->wstore_source) {
1113 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1115 pm_strcpy(jcr->wstore_source, where);
1116 if (jcr->wstorage) {
1117 jcr->wstore = (STORE *)jcr->wstorage->first();
1118 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1124 /* Set storage override */
1125 void set_wstorage(JCR *jcr, USTORE *store)
1129 if (!store->store) {
1132 if (!jcr->wstorage) {
1133 jcr->wstorage = New(alist(10, not_owned_by_alist));
1135 jcr->wstore = store->store;
1136 if (!jcr->wstore_source) {
1137 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1139 pm_strcpy(jcr->wstore_source, store->store_source);
1140 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1141 foreach_alist(storage, jcr->wstorage) {
1142 if (store->store == storage) {
1146 /* Store not in list, so add it */
1147 jcr->wstorage->prepend(store->store);
1150 void free_wstorage(JCR *jcr)
1152 if (jcr->wstorage) {
1153 delete jcr->wstorage;
1154 jcr->wstorage = NULL;
1159 void create_clones(JCR *jcr)
1162 * Fire off any clone jobs (run directives)
1164 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1165 if (!jcr->cloned && jcr->job->run_cmds) {
1167 JOB *job = jcr->job;
1168 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1169 UAContext *ua = new_ua_context(jcr);
1171 foreach_alist(runcmd, job->run_cmds) {
1172 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1173 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1174 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1175 parse_ua_args(ua); /* parse command */
1176 int stat = run_cmd(ua, ua->cmd);
1178 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1180 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1183 free_ua_context(ua);
1184 free_pool_memory(cmd);
1188 bool create_restore_bootstrap_file(JCR *jcr)
1192 memset(&rx, 0, sizeof(rx));
1195 rx.bsr->JobId = jcr->previous_jr.JobId;
1196 ua = new_ua_context(jcr);
1197 complete_bsr(ua, rx.bsr);
1198 rx.bsr->fi = new_findex();
1199 rx.bsr->fi->findex = 1;
1200 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1201 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1202 if (jcr->ExpectedFiles == 0) {
1203 free_ua_context(ua);
1207 free_ua_context(ua);
1209 jcr->needs_sd = true;