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 /* Run any script BeforeJob on dird */
244 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
246 if (job_canceled(jcr)) {
247 update_job_end_record(jcr);
251 * We re-update the job start record so that the start
252 * time is set after the run before job. This avoids
253 * that any files created by the run before job will
254 * be saved twice. They will be backed up in the current
255 * job, but not in the next one unless they are changed.
256 * Without this, they will be backed up in this job and
257 * in the next job run because in that case, their date
258 * is after the start of this run.
260 jcr->start_time = time(NULL);
261 jcr->jr.StartTime = jcr->start_time;
262 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
263 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
265 generate_job_event(jcr, "JobRun");
267 switch (jcr->JobType) {
269 if (do_backup(jcr)) {
272 backup_cleanup(jcr, JS_ErrorTerminated);
276 if (do_verify(jcr)) {
279 verify_cleanup(jcr, JS_ErrorTerminated);
283 if (do_restore(jcr)) {
286 restore_cleanup(jcr, JS_ErrorTerminated);
293 admin_cleanup(jcr, JS_ErrorTerminated);
299 if (do_migration(jcr)) {
302 migration_cleanup(jcr, JS_ErrorTerminated);
306 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
310 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
312 /* Send off any queued messages */
313 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
314 dequeue_messages(jcr);
318 generate_daemon_event(jcr, "JobEnd");
319 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
320 sm_check(__FILE__, __LINE__, true);
326 * Cancel a job -- typically called by the UA (Console program), but may also
327 * be called by the job watchdog.
329 * Returns: true if cancel appears to be successful
330 * false on failure. Message sent to ua->jcr.
332 bool cancel_job(UAContext *ua, JCR *jcr)
336 set_jcr_job_status(jcr, JS_Canceled);
338 switch (jcr->JobStatus) {
341 case JS_WaitClientRes:
342 case JS_WaitStoreRes:
343 case JS_WaitPriority:
345 case JS_WaitStartTime:
346 bsendmsg(ua, _("JobId %d, Job %s marked to be canceled.\n"),
347 jcr->JobId, jcr->Job);
348 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
352 /* Cancel File daemon */
353 if (jcr->file_bsock) {
354 ua->jcr->client = jcr->client;
355 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
356 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
359 Dmsg0(200, "Connected to file daemon\n");
360 fd = ua->jcr->file_bsock;
361 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
362 while (bnet_recv(fd) >= 0) {
363 bsendmsg(ua, "%s", fd->msg);
365 bnet_sig(fd, BNET_TERMINATE);
367 ua->jcr->file_bsock = NULL;
370 /* Cancel Storage daemon */
371 if (jcr->store_bsock) {
372 if (!ua->jcr->wstorage) {
374 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
376 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
380 set_wstorage(ua->jcr, jcr->rstore);
382 set_wstorage(ua->jcr, jcr->wstore);
385 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
386 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
389 Dmsg0(200, "Connected to storage daemon\n");
390 sd = ua->jcr->store_bsock;
391 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
392 while (bnet_recv(sd) >= 0) {
393 bsendmsg(ua, "%s", sd->msg);
395 bnet_sig(sd, BNET_TERMINATE);
397 ua->jcr->store_bsock = NULL;
405 static void job_monitor_destructor(watchdog_t *self)
407 JCR *control_jcr = (JCR *)self->data;
409 free_jcr(control_jcr);
412 static void job_monitor_watchdog(watchdog_t *self)
414 JCR *control_jcr, *jcr;
416 control_jcr = (JCR *)self->data;
418 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
423 if (jcr->JobId == 0) {
424 Dmsg2(800, "Skipping JCR %p (%s) with JobId 0\n",
429 /* check MaxWaitTime */
430 cancel = job_check_maxwaittime(control_jcr, jcr);
432 /* check MaxRunTime */
433 cancel |= job_check_maxruntime(control_jcr, jcr);
436 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n",
437 jcr, jcr->JobId, jcr->Job);
439 UAContext *ua = new_ua_context(jcr);
440 ua->jcr = control_jcr;
444 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
447 /* Keep reference counts correct */
453 * Check if the maxwaittime has expired and it is possible
456 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
459 bool ok_to_cancel = false;
462 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
463 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
466 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
467 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
469 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
470 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
472 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
473 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
475 } else if (job->MaxWaitTime != 0 &&
476 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
482 Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
484 jcr->JobId, jcr->Job, job->MaxWaitTime);
485 switch (jcr->JobStatus) {
490 case JS_WaitStoreRes:
491 case JS_WaitClientRes:
493 case JS_WaitPriority:
495 case JS_WaitStartTime:
497 Dmsg0(200, "JCR blocked in #1\n");
500 Dmsg0(800, "JCR running, checking SD status\n");
501 switch (jcr->SDJobStatus) {
506 Dmsg0(800, "JCR blocked in #2\n");
509 Dmsg0(800, "JCR not blocked in #2\n");
514 case JS_ErrorTerminated:
517 Dmsg0(800, "JCR already dead in #3\n");
520 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
523 Dmsg3(800, "MaxWaitTime result: %scancel JCR %p (%s)\n",
524 cancel ? "" : "do not ", jcr, jcr->job);
530 * Check if maxruntime has expired and if the job can be
533 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
537 if (jcr->job->MaxRunTime == 0) {
540 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
541 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
542 jcr, jcr->Job, jcr->job->MaxRunTime);
546 switch (jcr->JobStatus) {
552 case JS_WaitStoreRes:
553 case JS_WaitClientRes:
555 case JS_WaitPriority:
557 case JS_WaitStartTime:
562 case JS_ErrorTerminated:
568 Jmsg1(jcr, M_ERROR, 0, _("Unhandled job status code %d\n"),
572 Dmsg3(200, "MaxRunTime result: %scancel JCR %p (%s)\n",
573 cancel ? "" : "do not ", jcr, jcr->job);
579 * Get or create a Pool record with the given name.
580 * Returns: 0 on error
583 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
587 memset(&pr, 0, sizeof(pr));
588 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
590 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
591 /* Try to create the pool */
592 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
593 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
594 db_strerror(jcr->db));
597 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
603 void apply_pool_overrides(JCR *jcr)
605 if (jcr->run_pool_override) {
606 pm_strcpy(jcr->pool_source, _("Run Pool override"));
609 * Apply any level related Pool selections
611 switch (jcr->JobLevel) {
613 if (jcr->full_pool) {
614 jcr->pool = jcr->full_pool;
615 if (jcr->run_full_pool_override) {
616 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
618 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
624 jcr->pool = jcr->inc_pool;
625 if (jcr->run_inc_pool_override) {
626 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
628 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
633 if (jcr->diff_pool) {
634 jcr->pool = jcr->diff_pool;
635 if (jcr->run_diff_pool_override) {
636 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
638 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
647 * Get or create a Client record for this Job
649 bool get_or_create_client_record(JCR *jcr)
653 memset(&cr, 0, sizeof(cr));
654 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
655 cr.AutoPrune = jcr->client->AutoPrune;
656 cr.FileRetention = jcr->client->FileRetention;
657 cr.JobRetention = jcr->client->JobRetention;
658 if (!jcr->client_name) {
659 jcr->client_name = get_pool_memory(PM_NAME);
661 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
662 if (!db_create_client_record(jcr, jcr->db, &cr)) {
663 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
664 db_strerror(jcr->db));
667 jcr->jr.ClientId = cr.ClientId;
669 if (!jcr->client_uname) {
670 jcr->client_uname = get_pool_memory(PM_NAME);
672 pm_strcpy(jcr->client_uname, cr.Uname);
674 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
679 bool get_or_create_fileset_record(JCR *jcr)
683 * Get or Create FileSet record
685 memset(&fsr, 0, sizeof(FILESET_DBR));
686 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
687 if (jcr->fileset->have_MD5) {
688 struct MD5Context md5c;
689 unsigned char digest[MD5HashSize];
690 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
691 MD5Final(digest, &md5c);
693 * Keep the flag (last arg) set to false otherwise old FileSets will
694 * get new MD5 sums and the user will get Full backups on everything
696 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
697 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
699 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
701 if (!jcr->fileset->ignore_fs_changes ||
702 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
703 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
704 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
705 fsr.FileSet, db_strerror(jcr->db));
709 jcr->jr.FileSetId = fsr.FileSetId;
710 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
711 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
716 void init_jcr_job_record(JCR *jcr)
718 jcr->jr.SchedTime = jcr->sched_time;
719 jcr->jr.StartTime = jcr->start_time;
720 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
721 jcr->jr.JobType = jcr->JobType;
722 jcr->jr.JobLevel = jcr->JobLevel;
723 jcr->jr.JobStatus = jcr->JobStatus;
724 jcr->jr.JobId = jcr->JobId;
725 bstrncpy(jcr->jr.Name, jcr->job->hdr.name, sizeof(jcr->jr.Name));
726 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
730 * Write status and such in DB
732 void update_job_end_record(JCR *jcr)
734 jcr->jr.EndTime = time(NULL);
735 jcr->end_time = jcr->jr.EndTime;
736 jcr->jr.JobId = jcr->JobId;
737 jcr->jr.JobStatus = jcr->JobStatus;
738 jcr->jr.JobFiles = jcr->JobFiles;
739 jcr->jr.JobBytes = jcr->JobBytes;
740 jcr->jr.VolSessionId = jcr->VolSessionId;
741 jcr->jr.VolSessionTime = jcr->VolSessionTime;
742 jcr->jr.JobErrors = jcr->Errors;
743 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
744 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
745 db_strerror(jcr->db));
750 * Takes base_name and appends (unique) current
751 * date and time to form unique job name.
753 * Returns: unique job name in jcr->Job
754 * date/time in jcr->start_time
756 void create_unique_job_name(JCR *jcr, const char *base_name)
758 /* Job start mutex */
759 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
760 static time_t last_start_time = 0;
763 char dt[MAX_TIME_LENGTH];
764 char name[MAX_NAME_LENGTH];
767 /* Guarantee unique start time -- maximum one per second, and
768 * thus unique Job Name
770 P(mutex); /* lock creation of jobs */
772 while (now == last_start_time) {
773 bmicrosleep(0, 500000);
776 last_start_time = now;
777 V(mutex); /* allow creation of jobs */
778 jcr->start_time = now;
779 /* Form Unique JobName */
780 (void)localtime_r(&now, &tm);
781 /* Use only characters that are permitted in Windows filenames */
782 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
783 bstrncpy(name, base_name, sizeof(name));
784 name[sizeof(name)-22] = 0; /* truncate if too long */
785 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
786 /* Convert spaces into underscores */
787 for (p=jcr->Job; *p; p++) {
794 /* Called directly from job rescheduling */
795 void dird_free_jcr_pointers(JCR *jcr)
797 if (jcr->sd_auth_key) {
798 free(jcr->sd_auth_key);
799 jcr->sd_auth_key = NULL;
805 if (jcr->file_bsock) {
806 Dmsg0(200, "Close File bsock\n");
807 bnet_close(jcr->file_bsock);
808 jcr->file_bsock = NULL;
810 if (jcr->store_bsock) {
811 Dmsg0(200, "Close Store bsock\n");
812 bnet_close(jcr->store_bsock);
813 jcr->store_bsock = NULL;
816 Dmsg0(200, "Free JCR fname\n");
817 free_pool_memory(jcr->fname);
820 if (jcr->pool_source) {
821 free_pool_memory(jcr->pool_source);
822 jcr->pool_source = NULL;
824 if (jcr->storage_source) {
825 free_pool_memory(jcr->storage_source);
826 jcr->storage_source = NULL;
829 Dmsg0(200, "Free JCR stime\n");
830 free_pool_memory(jcr->stime);
833 if (jcr->RestoreBootstrap) {
834 free(jcr->RestoreBootstrap);
835 jcr->RestoreBootstrap = NULL;
837 if (jcr->client_uname) {
838 free_pool_memory(jcr->client_uname);
839 jcr->client_uname = NULL;
842 free_pool_memory(jcr->attr);
852 * Free the Job Control Record if no one is still using it.
853 * Called from main free_jcr() routine in src/lib/jcr.c so
854 * that we can do our Director specific cleanup of the jcr.
856 void dird_free_jcr(JCR *jcr)
858 Dmsg0(200, "Start dird free_jcr\n");
860 dird_free_jcr_pointers(jcr);
861 if (jcr->term_wait_inited) {
862 pthread_cond_destroy(&jcr->term_wait);
863 jcr->term_wait_inited = false;
866 /* Delete lists setup to hold storage pointers */
869 jcr->job_end_push.destroy();
870 Dmsg0(200, "End dird free_jcr\n");
874 * Set some defaults in the JCR necessary to
875 * run. These items are pulled from the job
876 * definition as defaults, but can be overridden
877 * later either by the Run record in the Schedule resource,
878 * or by the Console program.
880 void set_jcr_defaults(JCR *jcr, JOB *job)
883 jcr->JobType = job->JobType;
884 switch (jcr->JobType) {
887 jcr->JobLevel = L_NONE;
890 jcr->JobLevel = job->JobLevel;
894 jcr->fname = get_pool_memory(PM_FNAME);
896 if (!jcr->pool_source) {
897 jcr->pool_source = get_pool_memory(PM_MESSAGE);
898 pm_strcpy(jcr->pool_source, _("unknown source"));
900 if (!jcr->storage_source) {
901 jcr->storage_source = get_pool_memory(PM_MESSAGE);
902 pm_strcpy(jcr->storage_source, _("unknown source"));
904 jcr->JobPriority = job->Priority;
905 /* Copy storage definitions -- deleted in dir_free_jcr above */
906 copy_rwstorage(jcr, job->storage, _("Job resource"));
907 jcr->client = job->client;
908 if (!jcr->client_name) {
909 jcr->client_name = get_pool_memory(PM_NAME);
911 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
912 pm_strcpy(jcr->pool_source, _("Job resource"));
913 jcr->pool = job->pool;
914 jcr->full_pool = job->full_pool;
915 jcr->inc_pool = job->inc_pool;
916 jcr->diff_pool = job->diff_pool;
917 jcr->catalog = job->client->catalog;
918 jcr->fileset = job->fileset;
919 jcr->messages = job->messages;
920 jcr->spool_data = job->spool_data;
921 jcr->write_part_after_job = job->write_part_after_job;
922 if (jcr->RestoreBootstrap) {
923 free(jcr->RestoreBootstrap);
924 jcr->RestoreBootstrap = NULL;
926 /* This can be overridden by Console program */
927 if (job->RestoreBootstrap) {
928 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
930 /* This can be overridden by Console program */
931 jcr->verify_job = job->verify_job;
932 /* If no default level given, set one */
933 if (jcr->JobLevel == 0) {
934 switch (jcr->JobType) {
936 jcr->JobLevel = L_VERIFY_CATALOG;
939 jcr->JobLevel = L_INCREMENTAL;
943 jcr->JobLevel = L_NONE;
952 * Copy the storage definitions from an alist to the JCR
954 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
956 copy_rstorage(jcr, storage, where);
957 copy_wstorage(jcr, storage, where);
961 /* Set storage override */
962 void set_rwstorage(JCR *jcr, STORE *store)
964 set_rstorage(jcr, store);
965 set_wstorage(jcr, store);
968 void free_rwstorage(JCR *jcr)
975 * Copy the storage definitions from an alist to the JCR
977 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
982 delete jcr->rstorage;
984 jcr->rstorage = New(alist(10, not_owned_by_alist));
985 foreach_alist(st, storage) {
986 jcr->rstorage->append(st);
988 pm_strcpy(jcr->storage_source, where);
991 jcr->rstore = (STORE *)jcr->rstorage->first();
996 /* Set storage override */
997 void set_rstorage(JCR *jcr, STORE *store)
1001 jcr->rstore = store;
1002 foreach_alist(storage, jcr->rstorage) {
1003 if (store == storage) {
1007 /* Store not in list, so add it */
1008 jcr->rstorage->prepend(store);
1011 void free_rstorage(JCR *jcr)
1013 if (jcr->rstorage) {
1014 delete jcr->rstorage;
1015 jcr->rstorage = NULL;
1021 * Copy the storage definitions from an alist to the JCR
1023 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1027 if (jcr->wstorage) {
1028 delete jcr->wstorage;
1030 jcr->wstorage = New(alist(10, not_owned_by_alist));
1031 foreach_alist(st, storage) {
1032 jcr->wstorage->append(st);
1034 pm_strcpy(jcr->storage_source, where);
1036 if (jcr->wstorage) {
1037 jcr->wstore = (STORE *)jcr->wstorage->first();
1042 /* Set storage override */
1043 void set_wstorage(JCR *jcr, STORE *store)
1047 jcr->wstore = store;
1048 foreach_alist(storage, jcr->wstorage) {
1049 if (store == storage) {
1053 /* Store not in list, so add it */
1054 jcr->wstorage->prepend(store);
1057 void free_wstorage(JCR *jcr)
1059 if (jcr->wstorage) {
1060 delete jcr->wstorage;
1061 jcr->wstorage = NULL;
1068 void create_clones(JCR *jcr)
1071 * Fire off any clone jobs (run directives)
1073 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1074 if (!jcr->cloned && jcr->job->run_cmds) {
1076 JOB *job = jcr->job;
1077 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1078 UAContext *ua = new_ua_context(jcr);
1080 foreach_alist(runcmd, job->run_cmds) {
1081 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1082 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1083 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1084 parse_ua_args(ua); /* parse command */
1085 int stat = run_cmd(ua, ua->cmd);
1087 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1089 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1092 free_ua_context(ua);
1093 free_pool_memory(cmd);
1097 bool create_restore_bootstrap_file(JCR *jcr)
1101 memset(&rx, 0, sizeof(rx));
1104 rx.bsr->JobId = jcr->previous_jr.JobId;
1105 ua = new_ua_context(jcr);
1106 complete_bsr(ua, rx.bsr);
1107 rx.bsr->fi = new_findex();
1108 rx.bsr->fi->findex = 1;
1109 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1110 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1111 if (jcr->ExpectedFiles == 0) {
1112 free_ua_context(ua);
1116 free_ua_context(ua);
1118 jcr->needs_sd = true;