3 * Bacula Director Job processing routines
5 * Kern Sibbald, October MM
10 Copyright (C) 2000-2006 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
27 /* Forward referenced subroutines */
28 static void *job_thread(void *arg);
29 static void job_monitor_watchdog(watchdog_t *self);
30 static void job_monitor_destructor(watchdog_t *self);
31 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr);
32 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
34 /* Imported subroutines */
35 extern void term_scheduler();
36 extern void term_ua_server();
38 /* Imported variables */
39 extern time_t watchdog_time;
43 void init_job_server(int max_workers)
48 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
50 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror(stat));
53 wd->callback = job_monitor_watchdog;
54 wd->destructor = job_monitor_destructor;
57 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
58 register_watchdog(wd);
61 void term_job_server()
63 jobq_destroy(&job_queue); /* ignore any errors */
67 * Run a job -- typically called by the scheduler, but may also
68 * be called by the UA (Console program).
70 * Returns: 0 on failure
74 JobId_t run_job(JCR *jcr)
78 /* Queue the job to be run */
79 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
81 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
89 bool setup_job(JCR *jcr)
94 sm_check(__FILE__, __LINE__, true);
95 init_msg(jcr, jcr->messages);
97 /* Initialize termination condition variable */
98 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
100 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
103 jcr->term_wait_inited = true;
105 create_unique_job_name(jcr, jcr->job->hdr.name);
106 set_jcr_job_status(jcr, JS_Created);
112 Dmsg0(50, "Open database\n");
113 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
114 jcr->catalog->db_password, jcr->catalog->db_address,
115 jcr->catalog->db_port, jcr->catalog->db_socket,
116 jcr->catalog->mult_db_connections);
117 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
118 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
119 jcr->catalog->db_name);
121 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
125 Dmsg0(50, "DB opened\n");
128 jcr->fname = get_pool_memory(PM_FNAME);
130 if (!jcr->pool_source) {
131 jcr->pool_source = get_pool_memory(PM_MESSAGE);
132 pm_strcpy(jcr->pool_source, _("unknown source"));
134 if (!jcr->storage_source) {
135 jcr->storage_source = get_pool_memory(PM_MESSAGE);
136 pm_strcpy(jcr->storage_source, _("unknown source"));
142 init_jcr_job_record(jcr);
143 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
144 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
147 jcr->JobId = jcr->jr.JobId;
148 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
149 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
151 generate_daemon_event(jcr, "JobStart");
153 if (!get_or_create_client_record(jcr)) {
157 if (job_canceled(jcr)) {
161 Dmsg0(200, "Add jrc to work queue\n");
170 * This is the engine called by jobq.c:jobq_add() when we were pulled
171 * from the work queue.
172 * At this point, we are running in our own thread and all
173 * necessary resources are allocated -- see jobq.c
175 static void *job_thread(void *arg)
177 JCR *jcr = (JCR *)arg;
179 jcr->my_thread_id = pthread_self();
180 pthread_detach(jcr->my_thread_id);
181 sm_check(__FILE__, __LINE__, true);
183 Dmsg0(200, "=====Start Job=========\n");
184 jcr->start_time = time(NULL); /* set the real start time */
185 jcr->jr.StartTime = jcr->start_time;
187 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
188 (utime_t)(jcr->start_time - jcr->sched_time)) {
189 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
190 set_jcr_job_status(jcr, JS_Canceled);
193 /* TODO : check if it is used somewhere */
194 if (jcr->job->RunScripts == NULL)
196 Dmsg0(200, "Warning, job->RunScripts is empty\n");
197 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
201 * Note, we continue, even if the job is canceled above. This
202 * will permit proper setting of the job start record and
203 * the error (cancel) will be picked up below.
206 generate_job_event(jcr, "JobInit");
207 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
211 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
212 * this allows us to setup a proper job start record for restarting
213 * in case of later errors.
215 switch (jcr->JobType) {
217 if (!do_backup_init(jcr)) {
218 backup_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_verify_init(jcr)) {
223 verify_cleanup(jcr, JS_ErrorTerminated);
227 if (!do_restore_init(jcr)) {
228 restore_cleanup(jcr, JS_ErrorTerminated);
232 if (!do_admin_init(jcr)) {
233 admin_cleanup(jcr, JS_ErrorTerminated);
237 if (!do_migration_init(jcr)) {
238 migration_cleanup(jcr, JS_ErrorTerminated);
242 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
243 set_jcr_job_status(jcr, JS_ErrorTerminated);
247 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
248 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
251 if (job_canceled(jcr)) {
252 update_job_end_record(jcr);
254 /* Run any script BeforeJob on dird */
255 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
258 * We re-update the job start record so that the start
259 * time is set after the run before job. This avoids
260 * that any files created by the run before job will
261 * be saved twice. They will be backed up in the current
262 * job, but not in the next one unless they are changed.
263 * Without this, they will be backed up in this job and
264 * in the next job run because in that case, their date
265 * is after the start of this run.
267 jcr->start_time = time(NULL);
268 jcr->jr.StartTime = jcr->start_time;
269 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
270 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
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_migration(jcr)) {
309 migration_cleanup(jcr, JS_ErrorTerminated);
313 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
317 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
319 /* Send off any queued messages */
320 if (jcr->msg_queue->size() > 0) {
321 dequeue_messages(jcr);
325 generate_daemon_event(jcr, "JobEnd");
326 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
327 sm_check(__FILE__, __LINE__, true);
333 * Cancel a job -- typically called by the UA (Console program), but may also
334 * be called by the job watchdog.
336 * Returns: true if cancel appears to be successful
337 * false on failure. Message sent to ua->jcr.
339 bool cancel_job(UAContext *ua, JCR *jcr)
343 set_jcr_job_status(jcr, JS_Canceled);
345 switch (jcr->JobStatus) {
348 case JS_WaitClientRes:
349 case JS_WaitStoreRes:
350 case JS_WaitPriority:
352 case JS_WaitStartTime:
353 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
354 jcr->JobId, jcr->Job);
355 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
359 /* Cancel File daemon */
360 if (jcr->file_bsock) {
361 ua->jcr->client = jcr->client;
362 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
363 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
366 Dmsg0(200, "Connected to file daemon\n");
367 fd = ua->jcr->file_bsock;
368 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
369 while (bnet_recv(fd) >= 0) {
370 bsendmsg(ua, "%s", fd->msg);
372 bnet_sig(fd, BNET_TERMINATE);
374 ua->jcr->file_bsock = NULL;
377 /* Cancel Storage daemon */
378 if (jcr->store_bsock) {
379 if (!ua->jcr->storage) {
380 copy_storage(ua->jcr, jcr->storage, _("Job resource"));
382 set_storage(ua->jcr, jcr->store);
384 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
385 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
388 Dmsg0(200, "Connected to storage daemon\n");
389 sd = ua->jcr->store_bsock;
390 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
391 while (bnet_recv(sd) >= 0) {
392 bsendmsg(ua, "%s", sd->msg);
394 bnet_sig(sd, BNET_TERMINATE);
396 ua->jcr->store_bsock = NULL;
404 static void job_monitor_destructor(watchdog_t *self)
406 JCR *control_jcr = (JCR *)self->data;
408 free_jcr(control_jcr);
411 static void job_monitor_watchdog(watchdog_t *self)
413 JCR *control_jcr, *jcr;
415 control_jcr = (JCR *)self->data;
417 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
422 if (jcr->JobId == 0) {
423 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
428 /* check MaxWaitTime */
429 cancel = job_check_maxwaittime(control_jcr, jcr);
431 /* check MaxRunTime */
432 cancel |= job_check_maxruntime(control_jcr, jcr);
435 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
436 jcr, jcr->JobId, jcr->Job);
438 UAContext *ua = new_ua_context(jcr);
439 ua->jcr = control_jcr;
443 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
446 /* Keep reference counts correct */
452 * Check if the maxwaittime has expired and it is possible
455 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
458 bool ok_to_cancel = false;
461 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
462 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
465 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
466 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
468 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
469 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
471 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
472 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
474 } else if (job->MaxWaitTime != 0 &&
475 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
481 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
483 jcr->JobId, jcr->Job, job->MaxWaitTime);
484 switch (jcr->JobStatus) {
489 case JS_WaitStoreRes:
490 case JS_WaitClientRes:
492 case JS_WaitPriority:
494 case JS_WaitStartTime:
496 Dmsg0(200, "JCR blocked in #1\n");
499 Dmsg0(800, "JCR running, checking SD status\n");
500 switch (jcr->SDJobStatus) {
505 Dmsg0(800, "JCR blocked in #2\n");
508 Dmsg0(800, "JCR not blocked in #2\n");
513 case JS_ErrorTerminated:
516 Dmsg0(800, "JCR already dead in #3\n");
519 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
522 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
523 cancel ? "" : "do not ", jcr, jcr->job);
529 * Check if maxruntime has expired and if the job can be
532 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
536 if (jcr->job->MaxRunTime == 0) {
539 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
540 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
541 jcr, jcr->Job, jcr->job->MaxRunTime);
545 switch (jcr->JobStatus) {
551 case JS_WaitStoreRes:
552 case JS_WaitClientRes:
554 case JS_WaitPriority:
556 case JS_WaitStartTime:
561 case JS_ErrorTerminated:
567 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
571 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
572 cancel ? "" : "do not ", jcr, jcr->job);
578 * Get or create a Pool record with the given name.
579 * Returns: 0 on error
582 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
586 memset(&pr, 0, sizeof(pr));
587 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
589 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
590 /* Try to create the pool */
591 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
592 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
593 db_strerror(jcr->db));
596 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
602 void apply_pool_overrides(JCR *jcr)
604 if (jcr->run_pool_override) {
605 pm_strcpy(jcr->pool_source, _("Run Pool override"));
608 * Apply any level related Pool selections
610 switch (jcr->JobLevel) {
612 if (jcr->full_pool) {
613 jcr->pool = jcr->full_pool;
614 if (jcr->run_full_pool_override) {
615 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
617 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
623 jcr->pool = jcr->inc_pool;
624 if (jcr->run_inc_pool_override) {
625 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
627 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
632 if (jcr->diff_pool) {
633 jcr->pool = jcr->diff_pool;
634 if (jcr->run_diff_pool_override) {
635 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
637 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
646 * Get or create a Client record for this Job
648 bool get_or_create_client_record(JCR *jcr)
652 memset(&cr, 0, sizeof(cr));
653 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
654 cr.AutoPrune = jcr->client->AutoPrune;
655 cr.FileRetention = jcr->client->FileRetention;
656 cr.JobRetention = jcr->client->JobRetention;
657 if (!jcr->client_name) {
658 jcr->client_name = get_pool_memory(PM_NAME);
660 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
661 if (!db_create_client_record(jcr, jcr->db, &cr)) {
662 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
663 db_strerror(jcr->db));
666 jcr->jr.ClientId = cr.ClientId;
668 if (!jcr->client_uname) {
669 jcr->client_uname = get_pool_memory(PM_NAME);
671 pm_strcpy(jcr->client_uname, cr.Uname);
673 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
678 bool get_or_create_fileset_record(JCR *jcr)
682 * Get or Create FileSet record
684 memset(&fsr, 0, sizeof(FILESET_DBR));
685 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
686 if (jcr->fileset->have_MD5) {
687 struct MD5Context md5c;
688 unsigned char digest[MD5HashSize];
689 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
690 MD5Final(digest, &md5c);
691 bin_to_base64(fsr.MD5, (char *)digest, MD5HashSize);
692 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
694 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
696 if (!jcr->fileset->ignore_fs_changes ||
697 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
698 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
699 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
700 fsr.FileSet, db_strerror(jcr->db));
704 jcr->jr.FileSetId = fsr.FileSetId;
705 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
706 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
711 void init_jcr_job_record(JCR *jcr)
713 jcr->jr.SchedTime = jcr->sched_time;
714 jcr->jr.StartTime = jcr->start_time;
715 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
716 jcr->jr.JobType = jcr->JobType;
717 jcr->jr.JobLevel = jcr->JobLevel;
718 jcr->jr.JobStatus = jcr->JobStatus;
719 jcr->jr.JobId = jcr->JobId;
720 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
721 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
725 * Write status and such in DB
727 void update_job_end_record(JCR *jcr)
729 jcr->jr.EndTime = time(NULL);
730 jcr->end_time = jcr->jr.EndTime;
731 jcr->jr.JobId = jcr->JobId;
732 jcr->jr.JobStatus = jcr->JobStatus;
733 jcr->jr.JobFiles = jcr->JobFiles;
734 jcr->jr.JobBytes = jcr->JobBytes;
735 jcr->jr.VolSessionId = jcr->VolSessionId;
736 jcr->jr.VolSessionTime = jcr->VolSessionTime;
737 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
738 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
739 db_strerror(jcr->db));
744 * Takes base_name and appends (unique) current
745 * date and time to form unique job name.
747 * Returns: unique job name in jcr->Job
748 * date/time in jcr->start_time
750 void create_unique_job_name(JCR *jcr, const char *base_name)
752 /* Job start mutex */
753 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
754 static time_t last_start_time = 0;
757 char dt[MAX_TIME_LENGTH];
758 char name[MAX_NAME_LENGTH];
761 /* Guarantee unique start time -- maximum one per second, and
762 * thus unique Job Name
764 P(mutex); /* lock creation of jobs */
766 while (now == last_start_time) {
767 bmicrosleep(0, 500000);
770 last_start_time = now;
771 V(mutex); /* allow creation of jobs */
772 jcr->start_time = now;
773 /* Form Unique JobName */
774 localtime_r(&now, &tm);
775 /* Use only characters that are permitted in Windows filenames */
776 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
777 bstrncpy(name, base_name, sizeof(name));
778 name[sizeof(name)-22] = 0; /* truncate if too long */
779 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
780 /* Convert spaces into underscores */
781 for (p=jcr->Job; *p; p++) {
788 /* Called directly from job rescheduling */
789 void dird_free_jcr_pointers(JCR *jcr)
791 if (jcr->sd_auth_key) {
792 free(jcr->sd_auth_key);
793 jcr->sd_auth_key = NULL;
799 if (jcr->file_bsock) {
800 Dmsg0(200, "Close File bsock\n");
801 bnet_close(jcr->file_bsock);
802 jcr->file_bsock = NULL;
804 if (jcr->store_bsock) {
805 Dmsg0(200, "Close Store bsock\n");
806 bnet_close(jcr->store_bsock);
807 jcr->store_bsock = NULL;
810 Dmsg0(200, "Free JCR fname\n");
811 free_pool_memory(jcr->fname);
814 if (jcr->pool_source) {
815 free_pool_memory(jcr->pool_source);
816 jcr->pool_source = NULL;
818 if (jcr->storage_source) {
819 free_pool_memory(jcr->storage_source);
820 jcr->storage_source = NULL;
823 Dmsg0(200, "Free JCR stime\n");
824 free_pool_memory(jcr->stime);
827 if (jcr->RestoreBootstrap) {
828 free(jcr->RestoreBootstrap);
829 jcr->RestoreBootstrap = NULL;
831 if (jcr->client_uname) {
832 free_pool_memory(jcr->client_uname);
833 jcr->client_uname = NULL;
836 free_pool_memory(jcr->attr);
846 * Free the Job Control Record if no one is still using it.
847 * Called from main free_jcr() routine in src/lib/jcr.c so
848 * that we can do our Director specific cleanup of the jcr.
850 void dird_free_jcr(JCR *jcr)
852 Dmsg0(200, "Start dird free_jcr\n");
854 dird_free_jcr_pointers(jcr);
855 if (jcr->term_wait_inited) {
856 pthread_cond_destroy(&jcr->term_wait);
857 jcr->term_wait_inited = false;
860 /* Delete lists setup to hold storage pointers */
864 jcr->job_end_push.destroy();
865 Dmsg0(200, "End dird free_jcr\n");
869 * Set some defaults in the JCR necessary to
870 * run. These items are pulled from the job
871 * definition as defaults, but can be overridden
872 * later either by the Run record in the Schedule resource,
873 * or by the Console program.
875 void set_jcr_defaults(JCR *jcr, JOB *job)
878 jcr->JobType = job->JobType;
879 switch (jcr->JobType) {
882 jcr->JobLevel = L_NONE;
885 jcr->JobLevel = job->JobLevel;
889 jcr->fname = get_pool_memory(PM_FNAME);
891 if (!jcr->pool_source) {
892 jcr->pool_source = get_pool_memory(PM_MESSAGE);
893 pm_strcpy(jcr->pool_source, _("unknown source"));
895 if (!jcr->storage_source) {
896 jcr->storage_source = get_pool_memory(PM_MESSAGE);
897 pm_strcpy(jcr->storage_source, _("unknown source"));
899 jcr->JobPriority = job->Priority;
900 /* Copy storage definitions -- deleted in dir_free_jcr above */
901 copy_storage(jcr, job->storage, _("Job resource"));
902 jcr->client = job->client;
903 if (!jcr->client_name) {
904 jcr->client_name = get_pool_memory(PM_NAME);
906 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
907 pm_strcpy(jcr->pool_source, _("Job resource"));
908 jcr->pool = job->pool;
909 jcr->full_pool = job->full_pool;
910 jcr->inc_pool = job->inc_pool;
911 jcr->diff_pool = job->diff_pool;
912 jcr->catalog = job->client->catalog;
913 jcr->fileset = job->fileset;
914 jcr->messages = job->messages;
915 jcr->spool_data = job->spool_data;
916 jcr->write_part_after_job = job->write_part_after_job;
917 if (jcr->RestoreBootstrap) {
918 free(jcr->RestoreBootstrap);
919 jcr->RestoreBootstrap = NULL;
921 /* This can be overridden by Console program */
922 if (job->RestoreBootstrap) {
923 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
925 /* This can be overridden by Console program */
926 jcr->verify_job = job->verify_job;
927 /* If no default level given, set one */
928 if (jcr->JobLevel == 0) {
929 switch (jcr->JobType) {
931 jcr->JobLevel = L_VERIFY_CATALOG;
934 jcr->JobLevel = L_INCREMENTAL;
938 jcr->JobLevel = L_NONE;
948 * Copy the storage definitions from an alist to the JCR
950 void copy_storage(JCR *jcr, alist *storage, const char *where)
957 jcr->storage = New(alist(10, not_owned_by_alist));
958 foreach_alist(st, storage) {
959 jcr->storage->append(st);
961 pm_strcpy(jcr->storage_source, where);
964 jcr->store = (STORE *)jcr->storage->first();
969 /* Set storage override */
970 void set_storage(JCR *jcr, STORE *store)
975 foreach_alist(storage, jcr->storage) {
976 if (store == storage) {
980 /* Store not in list, so add it */
981 jcr->storage->prepend(store);
984 void create_clones(JCR *jcr)
987 * Fire off any clone jobs (run directives)
989 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
990 if (!jcr->cloned && jcr->job->run_cmds) {
993 POOLMEM *cmd = get_pool_memory(PM_FNAME);
994 UAContext *ua = new_ua_context(jcr);
996 foreach_alist(runcmd, job->run_cmds) {
997 cmd = edit_job_codes(jcr, cmd, runcmd, "");
998 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
999 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1000 parse_ua_args(ua); /* parse command */
1001 int stat = run_cmd(ua, ua->cmd);
1003 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1005 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1008 free_ua_context(ua);
1009 free_pool_memory(cmd);
1013 bool create_restore_bootstrap_file(JCR *jcr)
1017 memset(&rx, 0, sizeof(rx));
1020 rx.bsr->JobId = jcr->previous_jr.JobId;
1021 ua = new_ua_context(jcr);
1022 complete_bsr(ua, rx.bsr);
1023 rx.bsr->fi = new_findex();
1024 rx.bsr->fi->findex = 1;
1025 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1026 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1027 if (jcr->ExpectedFiles == 0) {
1028 free_ua_context(ua);
1032 free_ua_context(ua);
1034 jcr->needs_sd = true;