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(150, "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(150, "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 update_job_end_record(jcr);
229 * This is the engine called by jobq.c:jobq_add() when we were pulled
230 * from the work queue.
231 * At this point, we are running in our own thread and all
232 * necessary resources are allocated -- see jobq.c
234 static void *job_thread(void *arg)
236 JCR *jcr = (JCR *)arg;
238 jcr->my_thread_id = pthread_self();
239 pthread_detach(jcr->my_thread_id);
240 sm_check(__FILE__, __LINE__, true);
242 Dmsg0(200, "=====Start Job=========\n");
243 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
244 jcr->start_time = time(NULL); /* set the real start time */
245 jcr->jr.StartTime = jcr->start_time;
247 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
248 (utime_t)(jcr->start_time - jcr->sched_time)) {
249 set_jcr_job_status(jcr, JS_Canceled);
250 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
253 /* TODO : check if it is used somewhere */
254 if (jcr->job->RunScripts == NULL) {
255 Dmsg0(200, "Warning, job->RunScripts is empty\n");
256 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
259 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
260 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
263 /* Run any script BeforeJob on dird */
264 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
266 if (job_canceled(jcr)) {
267 update_job_end(jcr, jcr->JobStatus);
271 * We re-update the job start record so that the start
272 * time is set after the run before job. This avoids
273 * that any files created by the run before job will
274 * be saved twice. They will be backed up in the current
275 * job, but not in the next one unless they are changed.
276 * Without this, they will be backed up in this job and
277 * in the next job run because in that case, their date
278 * is after the start of this run.
280 jcr->start_time = time(NULL);
281 jcr->jr.StartTime = jcr->start_time;
282 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
283 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
285 generate_job_event(jcr, "JobRun");
287 switch (jcr->JobType) {
289 if (do_backup(jcr)) {
292 backup_cleanup(jcr, JS_ErrorTerminated);
296 if (do_verify(jcr)) {
299 verify_cleanup(jcr, JS_ErrorTerminated);
303 if (do_restore(jcr)) {
306 restore_cleanup(jcr, JS_ErrorTerminated);
313 admin_cleanup(jcr, JS_ErrorTerminated);
319 if (do_migration(jcr)) {
322 migration_cleanup(jcr, JS_ErrorTerminated);
326 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
331 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
333 /* Send off any queued messages */
334 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
335 dequeue_messages(jcr);
338 generate_daemon_event(jcr, "JobEnd");
339 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
340 sm_check(__FILE__, __LINE__, true);
346 * Cancel a job -- typically called by the UA (Console program), but may also
347 * be called by the job watchdog.
349 * Returns: true if cancel appears to be successful
350 * false on failure. Message sent to ua->jcr.
352 bool cancel_job(UAContext *ua, JCR *jcr)
357 set_jcr_job_status(jcr, JS_Canceled);
359 switch (jcr->JobStatus) {
362 case JS_WaitClientRes:
363 case JS_WaitStoreRes:
364 case JS_WaitPriority:
366 case JS_WaitStartTime:
367 bsendmsg(ua, _("JobId %s, Job %s marked to be canceled.\n"),
368 edit_uint64(jcr->JobId, ed1), jcr->Job);
369 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
373 /* Cancel File daemon */
374 if (jcr->file_bsock) {
375 ua->jcr->client = jcr->client;
376 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
377 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
380 Dmsg0(200, "Connected to file daemon\n");
381 fd = ua->jcr->file_bsock;
382 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
383 while (bnet_recv(fd) >= 0) {
384 bsendmsg(ua, "%s", fd->msg);
386 bnet_sig(fd, BNET_TERMINATE);
388 ua->jcr->file_bsock = NULL;
391 /* Cancel Storage daemon */
392 if (jcr->store_bsock) {
393 if (!ua->jcr->wstorage) {
395 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
397 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
402 store.store = jcr->rstore;
404 store.store = jcr->wstore;
406 set_wstorage(ua->jcr, &store);
409 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
410 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
413 Dmsg0(200, "Connected to storage daemon\n");
414 sd = ua->jcr->store_bsock;
415 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
416 while (bnet_recv(sd) >= 0) {
417 bsendmsg(ua, "%s", sd->msg);
419 bnet_sig(sd, BNET_TERMINATE);
421 ua->jcr->store_bsock = NULL;
429 static void job_monitor_destructor(watchdog_t *self)
431 JCR *control_jcr = (JCR *)self->data;
433 free_jcr(control_jcr);
436 static void job_monitor_watchdog(watchdog_t *self)
438 JCR *control_jcr, *jcr;
440 control_jcr = (JCR *)self->data;
442 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
447 if (jcr->JobId == 0 || job_canceled(jcr)) {
448 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
452 /* check MaxWaitTime */
453 if (job_check_maxwaittime(control_jcr, jcr)) {
454 set_jcr_job_status(jcr, JS_Canceled);
455 Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
457 /* check MaxRunTime */
458 } else if (job_check_maxruntime(control_jcr, jcr)) {
459 set_jcr_job_status(jcr, JS_Canceled);
460 Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
465 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
466 UAContext *ua = new_ua_context(jcr);
467 ua->jcr = control_jcr;
470 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
474 /* Keep reference counts correct */
479 * Check if the maxwaittime has expired and it is possible
482 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
487 if (job_canceled(jcr)) {
488 return false; /* already canceled */
490 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
491 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
494 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
495 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
497 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
498 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
500 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
501 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
503 } else if (job->MaxWaitTime != 0 &&
504 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
512 * Check if maxruntime has expired and if the job can be
515 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
517 if (jcr->job->MaxRunTime == 0 || job_canceled(jcr)) {
520 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
521 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
522 jcr, jcr->Job, jcr->job->MaxRunTime);
530 * Get or create a Pool record with the given name.
531 * Returns: 0 on error
534 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
538 memset(&pr, 0, sizeof(pr));
539 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
540 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
542 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
543 /* Try to create the pool */
544 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
545 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
546 db_strerror(jcr->db));
549 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
555 void apply_pool_overrides(JCR *jcr)
557 if (jcr->run_pool_override) {
558 pm_strcpy(jcr->pool_source, _("Run pool override"));
561 * Apply any level related Pool selections
563 switch (jcr->JobLevel) {
565 if (jcr->full_pool) {
566 jcr->pool = jcr->full_pool;
567 if (jcr->run_full_pool_override) {
568 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
570 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
576 jcr->pool = jcr->inc_pool;
577 if (jcr->run_inc_pool_override) {
578 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
580 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
585 if (jcr->diff_pool) {
586 jcr->pool = jcr->diff_pool;
587 if (jcr->run_diff_pool_override) {
588 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
590 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
599 * Get or create a Client record for this Job
601 bool get_or_create_client_record(JCR *jcr)
605 memset(&cr, 0, sizeof(cr));
606 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
607 cr.AutoPrune = jcr->client->AutoPrune;
608 cr.FileRetention = jcr->client->FileRetention;
609 cr.JobRetention = jcr->client->JobRetention;
610 if (!jcr->client_name) {
611 jcr->client_name = get_pool_memory(PM_NAME);
613 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
614 if (!db_create_client_record(jcr, jcr->db, &cr)) {
615 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
616 db_strerror(jcr->db));
619 jcr->jr.ClientId = cr.ClientId;
621 if (!jcr->client_uname) {
622 jcr->client_uname = get_pool_memory(PM_NAME);
624 pm_strcpy(jcr->client_uname, cr.Uname);
626 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
631 bool get_or_create_fileset_record(JCR *jcr)
635 * Get or Create FileSet record
637 memset(&fsr, 0, sizeof(FILESET_DBR));
638 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
639 if (jcr->fileset->have_MD5) {
640 struct MD5Context md5c;
641 unsigned char digest[MD5HashSize];
642 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
643 MD5Final(digest, &md5c);
645 * Keep the flag (last arg) set to false otherwise old FileSets will
646 * get new MD5 sums and the user will get Full backups on everything
648 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
649 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
651 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
653 if (!jcr->fileset->ignore_fs_changes ||
654 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
655 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
656 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
657 fsr.FileSet, db_strerror(jcr->db));
661 jcr->jr.FileSetId = fsr.FileSetId;
662 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
663 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
668 void init_jcr_job_record(JCR *jcr)
670 jcr->jr.SchedTime = jcr->sched_time;
671 jcr->jr.StartTime = jcr->start_time;
672 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
673 jcr->jr.JobType = jcr->JobType;
674 jcr->jr.JobLevel = jcr->JobLevel;
675 jcr->jr.JobStatus = jcr->JobStatus;
676 jcr->jr.JobId = jcr->JobId;
677 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
678 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
682 * Write status and such in DB
684 void update_job_end_record(JCR *jcr)
686 jcr->jr.EndTime = time(NULL);
687 jcr->end_time = jcr->jr.EndTime;
688 jcr->jr.JobId = jcr->JobId;
689 jcr->jr.JobStatus = jcr->JobStatus;
690 jcr->jr.JobFiles = jcr->JobFiles;
691 jcr->jr.JobBytes = jcr->JobBytes;
692 jcr->jr.VolSessionId = jcr->VolSessionId;
693 jcr->jr.VolSessionTime = jcr->VolSessionTime;
694 jcr->jr.JobErrors = jcr->Errors;
695 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
696 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
697 db_strerror(jcr->db));
702 * Takes base_name and appends (unique) current
703 * date and time to form unique job name.
705 * Returns: unique job name in jcr->Job
706 * date/time in jcr->start_time
708 void create_unique_job_name(JCR *jcr, const char *base_name)
710 /* Job start mutex */
711 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
712 static time_t last_start_time = 0;
715 char dt[MAX_TIME_LENGTH];
716 char name[MAX_NAME_LENGTH];
719 /* Guarantee unique start time -- maximum one per second, and
720 * thus unique Job Name
722 P(mutex); /* lock creation of jobs */
724 while (now == last_start_time) {
725 bmicrosleep(0, 500000);
728 last_start_time = now;
729 V(mutex); /* allow creation of jobs */
730 jcr->start_time = now;
731 /* Form Unique JobName */
732 (void)localtime_r(&now, &tm);
733 /* Use only characters that are permitted in Windows filenames */
734 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
735 bstrncpy(name, base_name, sizeof(name));
736 name[sizeof(name)-22] = 0; /* truncate if too long */
737 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
738 /* Convert spaces into underscores */
739 for (p=jcr->Job; *p; p++) {
746 /* Called directly from job rescheduling */
747 void dird_free_jcr_pointers(JCR *jcr)
749 if (jcr->sd_auth_key) {
750 free(jcr->sd_auth_key);
751 jcr->sd_auth_key = NULL;
757 if (jcr->file_bsock) {
758 Dmsg0(200, "Close File bsock\n");
759 bnet_close(jcr->file_bsock);
760 jcr->file_bsock = NULL;
762 if (jcr->store_bsock) {
763 Dmsg0(200, "Close Store bsock\n");
764 bnet_close(jcr->store_bsock);
765 jcr->store_bsock = NULL;
768 Dmsg0(200, "Free JCR fname\n");
769 free_pool_memory(jcr->fname);
772 if (jcr->RestoreBootstrap) {
773 free(jcr->RestoreBootstrap);
774 jcr->RestoreBootstrap = NULL;
776 if (jcr->client_uname) {
777 free_pool_memory(jcr->client_uname);
778 jcr->client_uname = NULL;
781 free_pool_memory(jcr->attr);
791 * Free the Job Control Record if no one is still using it.
792 * Called from main free_jcr() routine in src/lib/jcr.c so
793 * that we can do our Director specific cleanup of the jcr.
795 void dird_free_jcr(JCR *jcr)
797 Dmsg0(200, "Start dird free_jcr\n");
799 dird_free_jcr_pointers(jcr);
800 if (jcr->term_wait_inited) {
801 pthread_cond_destroy(&jcr->term_wait);
802 jcr->term_wait_inited = false;
805 db_close_database(jcr, jcr->db);
809 db_close_database(jcr, jcr->db_batch);
810 jcr->db_batch = NULL;
813 Dmsg0(200, "Free JCR stime\n");
814 free_pool_memory(jcr->stime);
818 Dmsg0(200, "Free JCR fname\n");
819 free_pool_memory(jcr->fname);
822 if (jcr->pool_source) {
823 free_pool_memory(jcr->pool_source);
824 jcr->pool_source = NULL;
826 if (jcr->rpool_source) {
827 free_pool_memory(jcr->rpool_source);
828 jcr->rpool_source = NULL;
830 if (jcr->wstore_source) {
831 free_pool_memory(jcr->wstore_source);
832 jcr->wstore_source = NULL;
834 if (jcr->rstore_source) {
835 free_pool_memory(jcr->rstore_source);
836 jcr->rstore_source = NULL;
839 /* Delete lists setup to hold storage pointers */
842 jcr->job_end_push.destroy();
843 Dmsg0(200, "End dird free_jcr\n");
847 * The Job storage definition must be either in the Job record
848 * or in the Pool record. The Pool record overrides the Job
851 void get_job_storage(USTORE *store, JOB *job, RUN *run)
853 if (run && run->pool && run->pool->storage) {
854 store->store = (STORE *)run->pool->storage->first();
855 pm_strcpy(store->store_source, _("Run pool override"));
858 if (run && run->storage) {
859 store->store = run->storage;
860 pm_strcpy(store->store_source, _("Run storage override"));
863 if (job->pool->storage) {
864 store->store = (STORE *)job->pool->storage->first();
865 pm_strcpy(store->store_source, _("Pool resource"));
867 store->store = (STORE *)job->storage->first();
868 pm_strcpy(store->store_source, _("Job resource"));
873 * Set some defaults in the JCR necessary to
874 * run. These items are pulled from the job
875 * definition as defaults, but can be overridden
876 * later either by the Run record in the Schedule resource,
877 * or by the Console program.
879 void set_jcr_defaults(JCR *jcr, JOB *job)
882 jcr->JobType = job->JobType;
883 switch (jcr->JobType) {
886 jcr->JobLevel = L_NONE;
889 if (!jcr->rpool_source) {
890 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
891 pm_strcpy(jcr->rpool_source, _("unknown source"));
893 /* Fall-through wanted */
895 jcr->JobLevel = job->JobLevel;
899 jcr->fname = get_pool_memory(PM_FNAME);
901 if (!jcr->pool_source) {
902 jcr->pool_source = get_pool_memory(PM_MESSAGE);
903 pm_strcpy(jcr->pool_source, _("unknown source"));
906 jcr->JobPriority = job->Priority;
907 /* Copy storage definitions -- deleted in dir_free_jcr above */
909 copy_rwstorage(jcr, job->storage, _("Job resource"));
911 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
913 jcr->client = job->client;
914 if (!jcr->client_name) {
915 jcr->client_name = get_pool_memory(PM_NAME);
917 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
918 pm_strcpy(jcr->pool_source, _("Job resource"));
919 jcr->pool = job->pool;
920 jcr->full_pool = job->full_pool;
921 jcr->inc_pool = job->inc_pool;
922 jcr->diff_pool = job->diff_pool;
923 jcr->catalog = job->client->catalog;
924 jcr->fileset = job->fileset;
925 jcr->messages = job->messages;
926 jcr->spool_data = job->spool_data;
927 jcr->write_part_after_job = job->write_part_after_job;
928 if (jcr->RestoreBootstrap) {
929 free(jcr->RestoreBootstrap);
930 jcr->RestoreBootstrap = NULL;
932 /* This can be overridden by Console program */
933 if (job->RestoreBootstrap) {
934 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
936 /* This can be overridden by Console program */
937 jcr->verify_job = job->verify_job;
938 /* If no default level given, set one */
939 if (jcr->JobLevel == 0) {
940 switch (jcr->JobType) {
942 jcr->JobLevel = L_VERIFY_CATALOG;
945 jcr->JobLevel = L_INCREMENTAL;
949 jcr->JobLevel = L_NONE;
952 jcr->JobLevel = L_FULL;
959 * Copy the storage definitions from an alist to the JCR
961 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
963 switch(jcr->JobType) {
967 copy_rstorage(jcr, storage, where);
970 copy_wstorage(jcr, storage, where);
976 /* Set storage override */
977 void set_rwstorage(JCR *jcr, USTORE *store)
980 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
983 switch(jcr->JobType) {
987 set_rstorage(jcr, store);
990 set_wstorage(jcr, store);
995 void free_rwstorage(JCR *jcr)
1002 * Copy the storage definitions from an alist to the JCR
1004 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1008 if (jcr->rstorage) {
1009 delete jcr->rstorage;
1011 jcr->rstorage = New(alist(10, not_owned_by_alist));
1012 foreach_alist(st, storage) {
1013 jcr->rstorage->append(st);
1015 if (!jcr->rstore_source) {
1016 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1018 pm_strcpy(jcr->rstore_source, where);
1019 if (jcr->rstorage) {
1020 jcr->rstore = (STORE *)jcr->rstorage->first();
1026 /* Set storage override */
1027 void set_rstorage(JCR *jcr, USTORE *store)
1031 if (!store->store) {
1034 if (!jcr->rstorage) {
1035 jcr->rstorage = New(alist(10, not_owned_by_alist));
1037 jcr->rstore = store->store;
1038 if (!jcr->rstore_source) {
1039 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1041 pm_strcpy(jcr->rstore_source, store->store_source);
1042 foreach_alist(storage, jcr->rstorage) {
1043 if (store->store == storage) {
1047 /* Store not in list, so add it */
1048 jcr->rstorage->prepend(store->store);
1051 void free_rstorage(JCR *jcr)
1053 if (jcr->rstorage) {
1054 delete jcr->rstorage;
1055 jcr->rstorage = NULL;
1061 * Copy the storage definitions from an alist to the JCR
1063 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1067 if (jcr->wstorage) {
1068 delete jcr->wstorage;
1070 jcr->wstorage = New(alist(10, not_owned_by_alist));
1071 foreach_alist(st, storage) {
1072 Dmsg1(100, "wstorage=%s\n", st->name());
1073 jcr->wstorage->append(st);
1075 if (!jcr->wstore_source) {
1076 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1078 pm_strcpy(jcr->wstore_source, where);
1079 if (jcr->wstorage) {
1080 jcr->wstore = (STORE *)jcr->wstorage->first();
1081 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1087 /* Set storage override */
1088 void set_wstorage(JCR *jcr, USTORE *store)
1092 if (!store->store) {
1095 if (!jcr->wstorage) {
1096 jcr->wstorage = New(alist(10, not_owned_by_alist));
1098 jcr->wstore = store->store;
1099 if (!jcr->wstore_source) {
1100 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1102 pm_strcpy(jcr->wstore_source, store->store_source);
1103 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1104 foreach_alist(storage, jcr->wstorage) {
1105 if (store->store == storage) {
1109 /* Store not in list, so add it */
1110 jcr->wstorage->prepend(store->store);
1113 void free_wstorage(JCR *jcr)
1115 if (jcr->wstorage) {
1116 delete jcr->wstorage;
1117 jcr->wstorage = NULL;
1122 void create_clones(JCR *jcr)
1125 * Fire off any clone jobs (run directives)
1127 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1128 if (!jcr->cloned && jcr->job->run_cmds) {
1130 JOB *job = jcr->job;
1131 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1132 UAContext *ua = new_ua_context(jcr);
1134 foreach_alist(runcmd, job->run_cmds) {
1135 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1136 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1137 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1138 parse_ua_args(ua); /* parse command */
1139 int stat = run_cmd(ua, ua->cmd);
1141 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1143 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1146 free_ua_context(ua);
1147 free_pool_memory(cmd);
1151 bool create_restore_bootstrap_file(JCR *jcr)
1155 memset(&rx, 0, sizeof(rx));
1158 rx.bsr->JobId = jcr->previous_jr.JobId;
1159 ua = new_ua_context(jcr);
1160 complete_bsr(ua, rx.bsr);
1161 rx.bsr->fi = new_findex();
1162 rx.bsr->fi->findex = 1;
1163 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1164 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1165 if (jcr->ExpectedFiles == 0) {
1166 free_ua_context(ua);
1170 free_ua_context(ua);
1172 jcr->needs_sd = true;