3 * Bacula Director Job processing routines
5 * Kern Sibbald, October MM
10 Bacula® - The Network Backup Solution
12 Copyright (C) 2000-2007 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->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"));
147 Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
148 if (jcr->JobType == JT_MIGRATE) {
149 if (!jcr->rpool_source) {
150 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
151 pm_strcpy(jcr->rpool_source, _("unknown source"));
158 init_jcr_job_record(jcr);
159 if (!get_or_create_client_record(jcr)) {
163 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
164 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
167 jcr->JobId = jcr->jr.JobId;
168 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
169 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
171 generate_daemon_event(jcr, "JobStart");
173 if (job_canceled(jcr)) {
178 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
179 * this allows us to setup a proper job start record for restarting
180 * in case of later errors.
182 switch (jcr->JobType) {
184 if (!do_backup_init(jcr)) {
185 backup_cleanup(jcr, JS_ErrorTerminated);
189 if (!do_verify_init(jcr)) {
190 verify_cleanup(jcr, JS_ErrorTerminated);
194 if (!do_restore_init(jcr)) {
195 restore_cleanup(jcr, JS_ErrorTerminated);
199 if (!do_admin_init(jcr)) {
200 admin_cleanup(jcr, JS_ErrorTerminated);
204 if (!do_migration_init(jcr)) {
205 migration_cleanup(jcr, JS_ErrorTerminated);
209 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
210 set_jcr_job_status(jcr, JS_ErrorTerminated);
214 generate_job_event(jcr, "JobInit");
221 void update_job_end(JCR *jcr, int TermCode)
223 dequeue_messages(jcr); /* display any queued messages */
224 set_jcr_job_status(jcr, TermCode);
225 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
226 update_job_end_record(jcr);
230 * This is the engine called by jobq.c:jobq_add() when we were pulled
231 * from the work queue.
232 * At this point, we are running in our own thread and all
233 * necessary resources are allocated -- see jobq.c
235 static void *job_thread(void *arg)
237 JCR *jcr = (JCR *)arg;
239 jcr->my_thread_id = pthread_self();
240 pthread_detach(jcr->my_thread_id);
241 sm_check(__FILE__, __LINE__, true);
243 Dmsg0(200, "=====Start Job=========\n");
244 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
245 jcr->start_time = time(NULL); /* set the real start time */
246 jcr->jr.StartTime = jcr->start_time;
248 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
249 (utime_t)(jcr->start_time - jcr->sched_time)) {
250 set_jcr_job_status(jcr, JS_Canceled);
251 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
254 /* TODO : check if it is used somewhere */
255 if (jcr->job->RunScripts == NULL) {
256 Dmsg0(200, "Warning, job->RunScripts is empty\n");
257 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
260 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
261 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
264 /* Run any script BeforeJob on dird */
265 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
267 if (job_canceled(jcr)) {
268 update_job_end(jcr, jcr->JobStatus);
272 * We re-update the job start record so that the start
273 * time is set after the run before job. This avoids
274 * that any files created by the run before job will
275 * be saved twice. They will be backed up in the current
276 * job, but not in the next one unless they are changed.
277 * Without this, they will be backed up in this job and
278 * in the next job run because in that case, their date
279 * is after the start of this run.
281 jcr->start_time = time(NULL);
282 jcr->jr.StartTime = jcr->start_time;
283 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
284 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
286 generate_job_event(jcr, "JobRun");
288 switch (jcr->JobType) {
290 if (do_backup(jcr)) {
293 backup_cleanup(jcr, JS_ErrorTerminated);
297 if (do_verify(jcr)) {
300 verify_cleanup(jcr, JS_ErrorTerminated);
304 if (do_restore(jcr)) {
307 restore_cleanup(jcr, JS_ErrorTerminated);
314 admin_cleanup(jcr, JS_ErrorTerminated);
320 if (do_migration(jcr)) {
323 migration_cleanup(jcr, JS_ErrorTerminated);
327 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
331 /* Send off any queued messages */
332 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
333 dequeue_messages(jcr);
337 generate_daemon_event(jcr, "JobEnd");
338 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
339 sm_check(__FILE__, __LINE__, true);
345 * Cancel a job -- typically called by the UA (Console program), but may also
346 * be called by the job watchdog.
348 * Returns: true if cancel appears to be successful
349 * false on failure. Message sent to ua->jcr.
351 bool cancel_job(UAContext *ua, JCR *jcr)
356 set_jcr_job_status(jcr, JS_Canceled);
358 switch (jcr->JobStatus) {
361 case JS_WaitClientRes:
362 case JS_WaitStoreRes:
363 case JS_WaitPriority:
365 case JS_WaitStartTime:
366 bsendmsg(ua, _("JobId %s, Job %s marked to be canceled.\n"),
367 edit_uint64(jcr->JobId, ed1), jcr->Job);
368 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
372 /* Cancel File daemon */
373 if (jcr->file_bsock) {
374 ua->jcr->client = jcr->client;
375 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
376 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
379 Dmsg0(200, "Connected to file daemon\n");
380 fd = ua->jcr->file_bsock;
381 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
382 while (bnet_recv(fd) >= 0) {
383 bsendmsg(ua, "%s", fd->msg);
385 bnet_sig(fd, BNET_TERMINATE);
387 ua->jcr->file_bsock = NULL;
390 /* Cancel Storage daemon */
391 if (jcr->store_bsock) {
392 if (!ua->jcr->wstorage) {
394 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
396 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
401 store.store = jcr->rstore;
403 store.store = jcr->wstore;
405 set_wstorage(ua->jcr, &store);
408 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
409 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
412 Dmsg0(200, "Connected to storage daemon\n");
413 sd = ua->jcr->store_bsock;
414 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
415 while (bnet_recv(sd) >= 0) {
416 bsendmsg(ua, "%s", sd->msg);
418 bnet_sig(sd, BNET_TERMINATE);
420 ua->jcr->store_bsock = NULL;
428 static void job_monitor_destructor(watchdog_t *self)
430 JCR *control_jcr = (JCR *)self->data;
432 free_jcr(control_jcr);
435 static void job_monitor_watchdog(watchdog_t *self)
437 JCR *control_jcr, *jcr;
439 control_jcr = (JCR *)self->data;
441 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
446 if (jcr->JobId == 0 || job_canceled(jcr)) {
447 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
451 /* check MaxWaitTime */
452 if (job_check_maxwaittime(control_jcr, jcr)) {
453 set_jcr_job_status(jcr, JS_Canceled);
454 Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
456 /* check MaxRunTime */
457 } else if (job_check_maxruntime(control_jcr, jcr)) {
458 set_jcr_job_status(jcr, JS_Canceled);
459 Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
464 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
465 UAContext *ua = new_ua_context(jcr);
466 ua->jcr = control_jcr;
469 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
473 /* Keep reference counts correct */
478 * Check if the maxwaittime has expired and it is possible
481 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
486 if (job_canceled(jcr)) {
487 return false; /* already canceled */
489 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
490 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
493 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
494 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
496 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
497 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
499 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
500 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
502 } else if (job->MaxWaitTime != 0 &&
503 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
511 * Check if maxruntime has expired and if the job can be
514 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
516 if (jcr->job->MaxRunTime == 0 || job_canceled(jcr)) {
519 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
520 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
521 jcr, jcr->Job, jcr->job->MaxRunTime);
529 * Get or create a Pool record with the given name.
530 * Returns: 0 on error
533 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
537 memset(&pr, 0, sizeof(pr));
538 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
539 Dmsg1(010, "get_or_create_pool=%s\n", pool_name);
541 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
542 /* Try to create the pool */
543 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
544 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
545 db_strerror(jcr->db));
548 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
554 void apply_pool_overrides(JCR *jcr)
556 if (jcr->run_pool_override) {
557 pm_strcpy(jcr->pool_source, _("Run pool override"));
560 * Apply any level related Pool selections
562 switch (jcr->JobLevel) {
564 if (jcr->full_pool) {
565 jcr->pool = jcr->full_pool;
566 if (jcr->run_full_pool_override) {
567 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
569 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
575 jcr->pool = jcr->inc_pool;
576 if (jcr->run_inc_pool_override) {
577 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
579 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
584 if (jcr->diff_pool) {
585 jcr->pool = jcr->diff_pool;
586 if (jcr->run_diff_pool_override) {
587 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
589 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
598 * Get or create a Client record for this Job
600 bool get_or_create_client_record(JCR *jcr)
604 memset(&cr, 0, sizeof(cr));
605 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
606 cr.AutoPrune = jcr->client->AutoPrune;
607 cr.FileRetention = jcr->client->FileRetention;
608 cr.JobRetention = jcr->client->JobRetention;
609 if (!jcr->client_name) {
610 jcr->client_name = get_pool_memory(PM_NAME);
612 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
613 if (!db_create_client_record(jcr, jcr->db, &cr)) {
614 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
615 db_strerror(jcr->db));
618 jcr->jr.ClientId = cr.ClientId;
620 if (!jcr->client_uname) {
621 jcr->client_uname = get_pool_memory(PM_NAME);
623 pm_strcpy(jcr->client_uname, cr.Uname);
625 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
630 bool get_or_create_fileset_record(JCR *jcr)
634 * Get or Create FileSet record
636 memset(&fsr, 0, sizeof(FILESET_DBR));
637 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
638 if (jcr->fileset->have_MD5) {
639 struct MD5Context md5c;
640 unsigned char digest[MD5HashSize];
641 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
642 MD5Final(digest, &md5c);
644 * Keep the flag (last arg) set to false otherwise old FileSets will
645 * get new MD5 sums and the user will get Full backups on everything
647 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
648 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
650 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
652 if (!jcr->fileset->ignore_fs_changes ||
653 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
654 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
655 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
656 fsr.FileSet, db_strerror(jcr->db));
660 jcr->jr.FileSetId = fsr.FileSetId;
661 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
662 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
667 void init_jcr_job_record(JCR *jcr)
669 jcr->jr.SchedTime = jcr->sched_time;
670 jcr->jr.StartTime = jcr->start_time;
671 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
672 jcr->jr.JobType = jcr->JobType;
673 jcr->jr.JobLevel = jcr->JobLevel;
674 jcr->jr.JobStatus = jcr->JobStatus;
675 jcr->jr.JobId = jcr->JobId;
676 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
677 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
681 * Write status and such in DB
683 void update_job_end_record(JCR *jcr)
685 jcr->jr.EndTime = time(NULL);
686 jcr->end_time = jcr->jr.EndTime;
687 jcr->jr.JobId = jcr->JobId;
688 jcr->jr.JobStatus = jcr->JobStatus;
689 jcr->jr.JobFiles = jcr->JobFiles;
690 jcr->jr.JobBytes = jcr->JobBytes;
691 jcr->jr.VolSessionId = jcr->VolSessionId;
692 jcr->jr.VolSessionTime = jcr->VolSessionTime;
693 jcr->jr.JobErrors = jcr->Errors;
694 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
695 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
696 db_strerror(jcr->db));
701 * Takes base_name and appends (unique) current
702 * date and time to form unique job name.
704 * Returns: unique job name in jcr->Job
705 * date/time in jcr->start_time
707 void create_unique_job_name(JCR *jcr, const char *base_name)
709 /* Job start mutex */
710 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
711 static time_t last_start_time = 0;
714 char dt[MAX_TIME_LENGTH];
715 char name[MAX_NAME_LENGTH];
718 /* Guarantee unique start time -- maximum one per second, and
719 * thus unique Job Name
721 P(mutex); /* lock creation of jobs */
723 while (now == last_start_time) {
724 bmicrosleep(0, 500000);
727 last_start_time = now;
728 V(mutex); /* allow creation of jobs */
729 jcr->start_time = now;
730 /* Form Unique JobName */
731 (void)localtime_r(&now, &tm);
732 /* Use only characters that are permitted in Windows filenames */
733 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
734 bstrncpy(name, base_name, sizeof(name));
735 name[sizeof(name)-22] = 0; /* truncate if too long */
736 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
737 /* Convert spaces into underscores */
738 for (p=jcr->Job; *p; p++) {
745 /* Called directly from job rescheduling */
746 void dird_free_jcr_pointers(JCR *jcr)
748 if (jcr->sd_auth_key) {
749 free(jcr->sd_auth_key);
750 jcr->sd_auth_key = NULL;
756 if (jcr->file_bsock) {
757 Dmsg0(200, "Close File bsock\n");
758 bnet_close(jcr->file_bsock);
759 jcr->file_bsock = NULL;
761 if (jcr->store_bsock) {
762 Dmsg0(200, "Close Store bsock\n");
763 bnet_close(jcr->store_bsock);
764 jcr->store_bsock = NULL;
767 Dmsg0(200, "Free JCR fname\n");
768 free_pool_memory(jcr->fname);
771 if (jcr->RestoreBootstrap) {
772 free(jcr->RestoreBootstrap);
773 jcr->RestoreBootstrap = NULL;
775 if (jcr->client_uname) {
776 free_pool_memory(jcr->client_uname);
777 jcr->client_uname = NULL;
780 free_pool_memory(jcr->attr);
790 * Free the Job Control Record if no one is still using it.
791 * Called from main free_jcr() routine in src/lib/jcr.c so
792 * that we can do our Director specific cleanup of the jcr.
794 void dird_free_jcr(JCR *jcr)
796 Dmsg0(200, "Start dird free_jcr\n");
798 dird_free_jcr_pointers(jcr);
799 if (jcr->term_wait_inited) {
800 pthread_cond_destroy(&jcr->term_wait);
801 jcr->term_wait_inited = false;
804 db_close_database(jcr, jcr->db);
808 db_close_database(jcr, jcr->db_batch);
809 jcr->db_batch = NULL;
812 Dmsg0(200, "Free JCR stime\n");
813 free_pool_memory(jcr->stime);
817 Dmsg0(200, "Free JCR fname\n");
818 free_pool_memory(jcr->fname);
821 if (jcr->pool_source) {
822 free_pool_memory(jcr->pool_source);
823 jcr->pool_source = NULL;
825 if (jcr->rpool_source) {
826 free_pool_memory(jcr->rpool_source);
827 jcr->rpool_source = NULL;
829 if (jcr->wstore_source) {
830 free_pool_memory(jcr->wstore_source);
831 jcr->wstore_source = NULL;
833 if (jcr->rstore_source) {
834 free_pool_memory(jcr->rstore_source);
835 jcr->rstore_source = NULL;
838 /* Delete lists setup to hold storage pointers */
841 jcr->job_end_push.destroy();
842 Dmsg0(200, "End dird free_jcr\n");
846 * The Job storage definition must be either in the Job record
847 * or in the Pool record. The Pool record overrides the Job
850 void get_job_storage(USTORE *store, JOB *job, RUN *run)
852 if (run && run->pool && run->pool->storage) {
853 store->store = (STORE *)run->pool->storage->first();
854 pm_strcpy(store->store_source, _("Run pool override"));
857 if (run && run->storage) {
858 store->store = run->storage;
859 pm_strcpy(store->store_source, _("Run storage override"));
862 if (job->pool->storage) {
863 store->store = (STORE *)job->pool->storage->first();
864 pm_strcpy(store->store_source, _("Pool resource"));
866 store->store = (STORE *)job->storage->first();
867 pm_strcpy(store->store_source, _("Job resource"));
872 * Set some defaults in the JCR necessary to
873 * run. These items are pulled from the job
874 * definition as defaults, but can be overridden
875 * later either by the Run record in the Schedule resource,
876 * or by the Console program.
878 void set_jcr_defaults(JCR *jcr, JOB *job)
881 jcr->JobType = job->JobType;
882 switch (jcr->JobType) {
885 jcr->JobLevel = L_NONE;
888 if (!jcr->rpool_source) {
889 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
890 pm_strcpy(jcr->rpool_source, _("unknown source"));
892 /* Fall-through wanted */
894 jcr->JobLevel = job->JobLevel;
898 jcr->fname = get_pool_memory(PM_FNAME);
900 if (!jcr->pool_source) {
901 jcr->pool_source = get_pool_memory(PM_MESSAGE);
902 pm_strcpy(jcr->pool_source, _("unknown source"));
905 jcr->JobPriority = job->Priority;
906 /* Copy storage definitions -- deleted in dir_free_jcr above */
908 copy_rwstorage(jcr, job->storage, _("Job resource"));
910 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
912 jcr->client = job->client;
913 if (!jcr->client_name) {
914 jcr->client_name = get_pool_memory(PM_NAME);
916 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
917 pm_strcpy(jcr->pool_source, _("Job resource"));
918 jcr->pool = job->pool;
919 jcr->full_pool = job->full_pool;
920 jcr->inc_pool = job->inc_pool;
921 jcr->diff_pool = job->diff_pool;
922 jcr->catalog = job->client->catalog;
923 jcr->fileset = job->fileset;
924 jcr->messages = job->messages;
925 jcr->spool_data = job->spool_data;
926 jcr->write_part_after_job = job->write_part_after_job;
927 if (jcr->RestoreBootstrap) {
928 free(jcr->RestoreBootstrap);
929 jcr->RestoreBootstrap = NULL;
931 /* This can be overridden by Console program */
932 if (job->RestoreBootstrap) {
933 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
935 /* This can be overridden by Console program */
936 jcr->verify_job = job->verify_job;
937 /* If no default level given, set one */
938 if (jcr->JobLevel == 0) {
939 switch (jcr->JobType) {
941 jcr->JobLevel = L_VERIFY_CATALOG;
944 jcr->JobLevel = L_INCREMENTAL;
948 jcr->JobLevel = L_NONE;
951 jcr->JobLevel = L_FULL;
958 * Copy the storage definitions from an alist to the JCR
960 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
962 switch(jcr->JobType) {
966 copy_rstorage(jcr, storage, where);
969 copy_wstorage(jcr, storage, where);
975 /* Set storage override */
976 void set_rwstorage(JCR *jcr, USTORE *store)
979 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
982 switch(jcr->JobType) {
986 set_rstorage(jcr, store);
989 set_wstorage(jcr, store);
994 void free_rwstorage(JCR *jcr)
1001 * Copy the storage definitions from an alist to the JCR
1003 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1007 if (jcr->rstorage) {
1008 delete jcr->rstorage;
1010 jcr->rstorage = New(alist(10, not_owned_by_alist));
1011 foreach_alist(st, storage) {
1012 jcr->rstorage->append(st);
1014 if (!jcr->rstore_source) {
1015 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1017 pm_strcpy(jcr->rstore_source, where);
1018 if (jcr->rstorage) {
1019 jcr->rstore = (STORE *)jcr->rstorage->first();
1025 /* Set storage override */
1026 void set_rstorage(JCR *jcr, USTORE *store)
1030 if (!store->store) {
1033 if (!jcr->rstorage) {
1034 jcr->rstorage = New(alist(10, not_owned_by_alist));
1036 jcr->rstore = store->store;
1037 if (!jcr->rstore_source) {
1038 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1040 pm_strcpy(jcr->rstore_source, store->store_source);
1041 foreach_alist(storage, jcr->rstorage) {
1042 if (store->store == storage) {
1046 /* Store not in list, so add it */
1047 jcr->rstorage->prepend(store->store);
1050 void free_rstorage(JCR *jcr)
1052 if (jcr->rstorage) {
1053 delete jcr->rstorage;
1054 jcr->rstorage = NULL;
1060 * Copy the storage definitions from an alist to the JCR
1062 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1066 if (jcr->wstorage) {
1067 delete jcr->wstorage;
1069 jcr->wstorage = New(alist(10, not_owned_by_alist));
1070 foreach_alist(st, storage) {
1071 Dmsg1(50, "storage=%s\n", st->name());
1072 jcr->wstorage->append(st);
1074 if (!jcr->wstore_source) {
1075 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1077 pm_strcpy(jcr->wstore_source, where);
1078 if (jcr->wstorage) {
1079 jcr->wstore = (STORE *)jcr->wstorage->first();
1080 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1086 /* Set storage override */
1087 void set_wstorage(JCR *jcr, USTORE *store)
1091 if (!store->store) {
1094 if (!jcr->wstorage) {
1095 jcr->wstorage = New(alist(10, not_owned_by_alist));
1097 jcr->wstore = store->store;
1098 if (!jcr->wstore_source) {
1099 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1101 pm_strcpy(jcr->wstore_source, store->store_source);
1102 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1103 foreach_alist(storage, jcr->wstorage) {
1104 if (store->store == storage) {
1108 /* Store not in list, so add it */
1109 jcr->wstorage->prepend(store->store);
1112 void free_wstorage(JCR *jcr)
1114 if (jcr->wstorage) {
1115 delete jcr->wstorage;
1116 jcr->wstorage = NULL;
1121 void create_clones(JCR *jcr)
1124 * Fire off any clone jobs (run directives)
1126 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1127 if (!jcr->cloned && jcr->job->run_cmds) {
1129 JOB *job = jcr->job;
1130 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1131 UAContext *ua = new_ua_context(jcr);
1133 foreach_alist(runcmd, job->run_cmds) {
1134 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1135 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1136 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1137 parse_ua_args(ua); /* parse command */
1138 int stat = run_cmd(ua, ua->cmd);
1140 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1142 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1145 free_ua_context(ua);
1146 free_pool_memory(cmd);
1150 bool create_restore_bootstrap_file(JCR *jcr)
1154 memset(&rx, 0, sizeof(rx));
1157 rx.bsr->JobId = jcr->previous_jr.JobId;
1158 ua = new_ua_context(jcr);
1159 complete_bsr(ua, rx.bsr);
1160 rx.bsr->fi = new_findex();
1161 rx.bsr->fi->findex = 1;
1162 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1163 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1164 if (jcr->ExpectedFiles == 0) {
1165 free_ua_context(ua);
1169 free_ua_context(ua);
1171 jcr->needs_sd = true;