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 */
42 void init_job_server(int max_workers)
47 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
49 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror(stat));
52 wd->callback = job_monitor_watchdog;
53 wd->destructor = job_monitor_destructor;
56 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
57 register_watchdog(wd);
60 void term_job_server()
62 jobq_destroy(&job_queue); /* ignore any errors */
66 * Run a job -- typically called by the scheduler, but may also
67 * be called by the UA (Console program).
69 * Returns: 0 on failure
73 JobId_t run_job(JCR *jcr)
77 /* Queue the job to be run */
78 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
80 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror(stat));
88 bool setup_job(JCR *jcr)
93 sm_check(__FILE__, __LINE__, true);
94 init_msg(jcr, jcr->messages);
96 /* Initialize termination condition variable */
97 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
99 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror(errstat));
102 jcr->term_wait_inited = true;
104 create_unique_job_name(jcr, jcr->job->hdr.name);
105 set_jcr_job_status(jcr, JS_Created);
111 Dmsg0(50, "Open database\n");
112 jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
113 jcr->catalog->db_password, jcr->catalog->db_address,
114 jcr->catalog->db_port, jcr->catalog->db_socket,
115 jcr->catalog->mult_db_connections);
116 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
117 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
118 jcr->catalog->db_name);
120 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
124 Dmsg0(50, "DB opened\n");
127 jcr->fname = get_pool_memory(PM_FNAME);
129 if (!jcr->pool_source) {
130 jcr->pool_source = get_pool_memory(PM_MESSAGE);
131 pm_strcpy(jcr->pool_source, _("unknown source"));
133 if (!jcr->storage_source) {
134 jcr->storage_source = get_pool_memory(PM_MESSAGE);
135 pm_strcpy(jcr->storage_source, _("unknown source"));
141 init_jcr_job_record(jcr);
142 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
143 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
146 jcr->JobId = jcr->jr.JobId;
147 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
148 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
150 generate_daemon_event(jcr, "JobStart");
152 if (!get_or_create_client_record(jcr)) {
156 if (job_canceled(jcr)) {
162 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
163 * this allows us to setup a proper job start record for restarting
164 * in case of later errors.
166 switch (jcr->JobType) {
168 if (!do_backup_init(jcr)) {
169 backup_cleanup(jcr, JS_ErrorTerminated);
173 if (!do_verify_init(jcr)) {
174 verify_cleanup(jcr, JS_ErrorTerminated);
178 if (!do_restore_init(jcr)) {
179 restore_cleanup(jcr, JS_ErrorTerminated);
183 if (!do_admin_init(jcr)) {
184 admin_cleanup(jcr, JS_ErrorTerminated);
188 if (!do_migration_init(jcr)) {
189 migration_cleanup(jcr, JS_ErrorTerminated);
193 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
194 set_jcr_job_status(jcr, JS_ErrorTerminated);
198 generate_job_event(jcr, "JobInit");
200 Dmsg0(200, "Add jrc to work queue\n");
209 * This is the engine called by jobq.c:jobq_add() when we were pulled
210 * from the work queue.
211 * At this point, we are running in our own thread and all
212 * necessary resources are allocated -- see jobq.c
214 static void *job_thread(void *arg)
216 JCR *jcr = (JCR *)arg;
218 jcr->my_thread_id = pthread_self();
219 pthread_detach(jcr->my_thread_id);
220 sm_check(__FILE__, __LINE__, true);
222 Dmsg0(200, "=====Start Job=========\n");
223 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
224 jcr->start_time = time(NULL); /* set the real start time */
225 jcr->jr.StartTime = jcr->start_time;
227 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
228 (utime_t)(jcr->start_time - jcr->sched_time)) {
229 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
230 set_jcr_job_status(jcr, JS_Canceled);
233 /* TODO : check if it is used somewhere */
234 if (jcr->job->RunScripts == NULL) {
235 Dmsg0(200, "Warning, job->RunScripts is empty\n");
236 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
239 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
240 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
243 if (job_canceled(jcr)) {
244 update_job_end_record(jcr);
246 /* Run any script BeforeJob on dird */
247 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
250 * We re-update the job start record so that the start
251 * time is set after the run before job. This avoids
252 * that any files created by the run before job will
253 * be saved twice. They will be backed up in the current
254 * job, but not in the next one unless they are changed.
255 * Without this, they will be backed up in this job and
256 * in the next job run because in that case, their date
257 * is after the start of this run.
259 jcr->start_time = time(NULL);
260 jcr->jr.StartTime = jcr->start_time;
261 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
262 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
264 generate_job_event(jcr, "JobRun");
266 switch (jcr->JobType) {
268 if (do_backup(jcr)) {
271 backup_cleanup(jcr, JS_ErrorTerminated);
275 if (do_verify(jcr)) {
278 verify_cleanup(jcr, JS_ErrorTerminated);
282 if (do_restore(jcr)) {
285 restore_cleanup(jcr, JS_ErrorTerminated);
292 admin_cleanup(jcr, JS_ErrorTerminated);
298 if (do_migration(jcr)) {
301 migration_cleanup(jcr, JS_ErrorTerminated);
305 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
309 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
311 /* Send off any queued messages */
312 if (jcr->msg_queue->size() > 0) {
313 dequeue_messages(jcr);
317 generate_daemon_event(jcr, "JobEnd");
318 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
319 sm_check(__FILE__, __LINE__, true);
325 * Cancel a job -- typically called by the UA (Console program), but may also
326 * be called by the job watchdog.
328 * Returns: true if cancel appears to be successful
329 * false on failure. Message sent to ua->jcr.
331 bool cancel_job(UAContext *ua, JCR *jcr)
335 set_jcr_job_status(jcr, JS_Canceled);
337 switch (jcr->JobStatus) {
340 case JS_WaitClientRes:
341 case JS_WaitStoreRes:
342 case JS_WaitPriority:
344 case JS_WaitStartTime:
345 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
346 jcr->JobId, jcr->Job);
347 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
351 /* Cancel File daemon */
352 if (jcr->file_bsock) {
353 ua->jcr->client = jcr->client;
354 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
355 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
358 Dmsg0(200, "Connected to file daemon\n");
359 fd = ua->jcr->file_bsock;
360 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
361 while (bnet_recv(fd) >= 0) {
362 bsendmsg(ua, "%s", fd->msg);
364 bnet_sig(fd, BNET_TERMINATE);
366 ua->jcr->file_bsock = NULL;
369 /* Cancel Storage daemon */
370 if (jcr->store_bsock) {
371 if (!ua->jcr->wstorage) {
373 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
375 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
379 set_wstorage(ua->jcr, jcr->rstore);
381 set_wstorage(ua->jcr, jcr->wstore);
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, sizeof(fsr.MD5), (char *)digest, MD5HashSize, true);
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 (void)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 */
863 jcr->job_end_push.destroy();
864 Dmsg0(200, "End dird free_jcr\n");
868 * Set some defaults in the JCR necessary to
869 * run. These items are pulled from the job
870 * definition as defaults, but can be overridden
871 * later either by the Run record in the Schedule resource,
872 * or by the Console program.
874 void set_jcr_defaults(JCR *jcr, JOB *job)
877 jcr->JobType = job->JobType;
878 switch (jcr->JobType) {
881 jcr->JobLevel = L_NONE;
884 jcr->JobLevel = job->JobLevel;
888 jcr->fname = get_pool_memory(PM_FNAME);
890 if (!jcr->pool_source) {
891 jcr->pool_source = get_pool_memory(PM_MESSAGE);
892 pm_strcpy(jcr->pool_source, _("unknown source"));
894 if (!jcr->storage_source) {
895 jcr->storage_source = get_pool_memory(PM_MESSAGE);
896 pm_strcpy(jcr->storage_source, _("unknown source"));
898 jcr->JobPriority = job->Priority;
899 /* Copy storage definitions -- deleted in dir_free_jcr above */
900 copy_rwstorage(jcr, job->storage, _("Job resource"));
901 jcr->client = job->client;
902 if (!jcr->client_name) {
903 jcr->client_name = get_pool_memory(PM_NAME);
905 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
906 pm_strcpy(jcr->pool_source, _("Job resource"));
907 jcr->pool = job->pool;
908 jcr->full_pool = job->full_pool;
909 jcr->inc_pool = job->inc_pool;
910 jcr->diff_pool = job->diff_pool;
911 jcr->catalog = job->client->catalog;
912 jcr->fileset = job->fileset;
913 jcr->messages = job->messages;
914 jcr->spool_data = job->spool_data;
915 jcr->write_part_after_job = job->write_part_after_job;
916 if (jcr->RestoreBootstrap) {
917 free(jcr->RestoreBootstrap);
918 jcr->RestoreBootstrap = NULL;
920 /* This can be overridden by Console program */
921 if (job->RestoreBootstrap) {
922 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
924 /* This can be overridden by Console program */
925 jcr->verify_job = job->verify_job;
926 /* If no default level given, set one */
927 if (jcr->JobLevel == 0) {
928 switch (jcr->JobType) {
930 jcr->JobLevel = L_VERIFY_CATALOG;
933 jcr->JobLevel = L_INCREMENTAL;
937 jcr->JobLevel = L_NONE;
946 * Copy the storage definitions from an alist to the JCR
948 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
950 copy_rstorage(jcr, storage, where);
951 copy_wstorage(jcr, storage, where);
955 /* Set storage override */
956 void set_rwstorage(JCR *jcr, STORE *store)
958 set_rstorage(jcr, store);
959 set_wstorage(jcr, store);
962 void free_rwstorage(JCR *jcr)
969 * Copy the storage definitions from an alist to the JCR
971 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
976 delete jcr->rstorage;
978 jcr->rstorage = New(alist(10, not_owned_by_alist));
979 foreach_alist(st, storage) {
980 jcr->rstorage->append(st);
982 pm_strcpy(jcr->storage_source, where);
985 jcr->rstore = (STORE *)jcr->rstorage->first();
990 /* Set storage override */
991 void set_rstorage(JCR *jcr, STORE *store)
996 foreach_alist(storage, jcr->rstorage) {
997 if (store == storage) {
1001 /* Store not in list, so add it */
1002 jcr->rstorage->prepend(store);
1005 void free_rstorage(JCR *jcr)
1007 if (jcr->rstorage) {
1008 delete jcr->rstorage;
1009 jcr->rstorage = NULL;
1015 * Copy the storage definitions from an alist to the JCR
1017 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1021 if (jcr->wstorage) {
1022 delete jcr->wstorage;
1024 jcr->wstorage = New(alist(10, not_owned_by_alist));
1025 foreach_alist(st, storage) {
1026 jcr->wstorage->append(st);
1028 pm_strcpy(jcr->storage_source, where);
1030 if (jcr->wstorage) {
1031 jcr->wstore = (STORE *)jcr->wstorage->first();
1036 /* Set storage override */
1037 void set_wstorage(JCR *jcr, STORE *store)
1041 jcr->wstore = store;
1042 foreach_alist(storage, jcr->wstorage) {
1043 if (store == storage) {
1047 /* Store not in list, so add it */
1048 jcr->wstorage->prepend(store);
1051 void free_wstorage(JCR *jcr)
1053 if (jcr->wstorage) {
1054 delete jcr->wstorage;
1055 jcr->wstorage = NULL;
1062 void create_clones(JCR *jcr)
1065 * Fire off any clone jobs (run directives)
1067 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1068 if (!jcr->cloned && jcr->job->run_cmds) {
1070 JOB *job = jcr->job;
1071 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1072 UAContext *ua = new_ua_context(jcr);
1074 foreach_alist(runcmd, job->run_cmds) {
1075 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1076 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1077 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1078 parse_ua_args(ua); /* parse command */
1079 int stat = run_cmd(ua, ua->cmd);
1081 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1083 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1086 free_ua_context(ua);
1087 free_pool_memory(cmd);
1091 bool create_restore_bootstrap_file(JCR *jcr)
1095 memset(&rx, 0, sizeof(rx));
1098 rx.bsr->JobId = jcr->previous_jr.JobId;
1099 ua = new_ua_context(jcr);
1100 complete_bsr(ua, rx.bsr);
1101 rx.bsr->fi = new_findex();
1102 rx.bsr->fi->findex = 1;
1103 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1104 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1105 if (jcr->ExpectedFiles == 0) {
1106 free_ua_context(ua);
1110 free_ua_context(ua);
1112 jcr->needs_sd = true;