2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director Job processing routines
32 * Kern Sibbald, October MM
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.bstrerror(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.bstrerror(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.bstrerror(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(100, "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));
135 db_close_database(jcr, jcr->db);
139 Dmsg0(150, "DB opened\n");
142 jcr->fname = get_pool_memory(PM_FNAME);
144 if (!jcr->pool_source) {
145 jcr->pool_source = get_pool_memory(PM_MESSAGE);
146 pm_strcpy(jcr->pool_source, _("unknown source"));
148 Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
149 if (jcr->JobType == JT_MIGRATE) {
150 if (!jcr->rpool_source) {
151 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
152 pm_strcpy(jcr->rpool_source, _("unknown source"));
159 init_jcr_job_record(jcr);
160 if (!get_or_create_client_record(jcr)) {
164 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
165 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
168 jcr->JobId = jcr->jr.JobId;
169 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
170 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
172 generate_daemon_event(jcr, "JobStart");
174 if (job_canceled(jcr)) {
179 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
180 * this allows us to setup a proper job start record for restarting
181 * in case of later errors.
183 switch (jcr->JobType) {
185 if (!do_backup_init(jcr)) {
186 backup_cleanup(jcr, JS_ErrorTerminated);
190 if (!do_verify_init(jcr)) {
191 verify_cleanup(jcr, JS_ErrorTerminated);
195 if (!do_restore_init(jcr)) {
196 restore_cleanup(jcr, JS_ErrorTerminated);
200 if (!do_admin_init(jcr)) {
201 admin_cleanup(jcr, JS_ErrorTerminated);
205 if (!do_migration_init(jcr)) {
206 migration_cleanup(jcr, JS_ErrorTerminated);
210 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
211 set_jcr_job_status(jcr, JS_ErrorTerminated);
215 generate_job_event(jcr, "JobInit");
222 void update_job_end(JCR *jcr, int TermCode)
224 dequeue_messages(jcr); /* display any queued messages */
225 set_jcr_job_status(jcr, TermCode);
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);
332 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
334 /* Send off any queued messages */
335 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
336 dequeue_messages(jcr);
339 generate_daemon_event(jcr, "JobEnd");
340 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
341 sm_check(__FILE__, __LINE__, true);
347 * Cancel a job -- typically called by the UA (Console program), but may also
348 * be called by the job watchdog.
350 * Returns: true if cancel appears to be successful
351 * false on failure. Message sent to ua->jcr.
353 bool cancel_job(UAContext *ua, JCR *jcr)
358 set_jcr_job_status(jcr, JS_Canceled);
360 switch (jcr->JobStatus) {
363 case JS_WaitClientRes:
364 case JS_WaitStoreRes:
365 case JS_WaitPriority:
367 case JS_WaitStartTime:
368 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
369 edit_uint64(jcr->JobId, ed1), jcr->Job);
370 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
374 /* Cancel File daemon */
375 if (jcr->file_bsock) {
376 ua->jcr->client = jcr->client;
377 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
378 ua->error_msg(_("Failed to connect to File daemon.\n"));
381 Dmsg0(200, "Connected to file daemon\n");
382 fd = ua->jcr->file_bsock;
383 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
384 while (bnet_recv(fd) >= 0) {
385 ua->send_msg("%s", fd->msg);
387 bnet_sig(fd, BNET_TERMINATE);
389 ua->jcr->file_bsock = NULL;
392 /* Cancel Storage daemon */
393 if (jcr->store_bsock) {
394 if (!ua->jcr->wstorage) {
396 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
398 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
403 store.store = jcr->rstore;
405 store.store = jcr->wstore;
407 set_wstorage(ua->jcr, &store);
410 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
411 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
414 Dmsg0(200, "Connected to storage daemon\n");
415 sd = ua->jcr->store_bsock;
416 sd->fsend("cancel Job=%s\n", jcr->Job);
417 while (sd->recv() >= 0) {
418 ua->send_msg("%s", sd->msg);
420 sd->signal(BNET_TERMINATE);
422 ua->jcr->store_bsock = NULL;
430 static void job_monitor_destructor(watchdog_t *self)
432 JCR *control_jcr = (JCR *)self->data;
434 free_jcr(control_jcr);
437 static void job_monitor_watchdog(watchdog_t *self)
439 JCR *control_jcr, *jcr;
441 control_jcr = (JCR *)self->data;
443 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
448 if (jcr->JobId == 0 || job_canceled(jcr)) {
449 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
453 /* check MaxWaitTime */
454 if (job_check_maxwaittime(control_jcr, jcr)) {
455 set_jcr_job_status(jcr, JS_Canceled);
456 Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
458 /* check MaxRunTime */
459 } else if (job_check_maxruntime(control_jcr, jcr)) {
460 set_jcr_job_status(jcr, JS_Canceled);
461 Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
466 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
467 UAContext *ua = new_ua_context(jcr);
468 ua->jcr = control_jcr;
471 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
475 /* Keep reference counts correct */
480 * Check if the maxwaittime has expired and it is possible
483 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
488 if (job_canceled(jcr)) {
489 return false; /* already canceled */
491 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
492 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
495 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
496 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
498 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
499 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
501 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
502 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
504 } else if (job->MaxWaitTime != 0 &&
505 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
513 * Check if maxruntime has expired and if the job can be
516 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
518 if (jcr->job->MaxRunTime == 0 || job_canceled(jcr)) {
521 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
522 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
523 jcr, jcr->Job, jcr->job->MaxRunTime);
531 * Get or create a Pool record with the given name.
532 * Returns: 0 on error
535 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
539 memset(&pr, 0, sizeof(pr));
540 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
541 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
543 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
544 /* Try to create the pool */
545 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
546 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
547 db_strerror(jcr->db));
550 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
556 void apply_pool_overrides(JCR *jcr)
558 if (jcr->run_pool_override) {
559 pm_strcpy(jcr->pool_source, _("Run pool override"));
562 * Apply any level related Pool selections
564 switch (jcr->JobLevel) {
566 if (jcr->full_pool) {
567 jcr->pool = jcr->full_pool;
568 if (jcr->run_full_pool_override) {
569 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
571 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
577 jcr->pool = jcr->inc_pool;
578 if (jcr->run_inc_pool_override) {
579 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
581 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
586 if (jcr->diff_pool) {
587 jcr->pool = jcr->diff_pool;
588 if (jcr->run_diff_pool_override) {
589 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
591 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
600 * Get or create a Client record for this Job
602 bool get_or_create_client_record(JCR *jcr)
606 memset(&cr, 0, sizeof(cr));
607 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
608 cr.AutoPrune = jcr->client->AutoPrune;
609 cr.FileRetention = jcr->client->FileRetention;
610 cr.JobRetention = jcr->client->JobRetention;
611 if (!jcr->client_name) {
612 jcr->client_name = get_pool_memory(PM_NAME);
614 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
615 if (!db_create_client_record(jcr, jcr->db, &cr)) {
616 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
617 db_strerror(jcr->db));
620 jcr->jr.ClientId = cr.ClientId;
622 if (!jcr->client_uname) {
623 jcr->client_uname = get_pool_memory(PM_NAME);
625 pm_strcpy(jcr->client_uname, cr.Uname);
627 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
632 bool get_or_create_fileset_record(JCR *jcr)
636 * Get or Create FileSet record
638 memset(&fsr, 0, sizeof(FILESET_DBR));
639 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
640 if (jcr->fileset->have_MD5) {
641 struct MD5Context md5c;
642 unsigned char digest[MD5HashSize];
643 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
644 MD5Final(digest, &md5c);
646 * Keep the flag (last arg) set to false otherwise old FileSets will
647 * get new MD5 sums and the user will get Full backups on everything
649 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
650 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
652 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
654 if (!jcr->fileset->ignore_fs_changes ||
655 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
656 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
657 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
658 fsr.FileSet, db_strerror(jcr->db));
662 jcr->jr.FileSetId = fsr.FileSetId;
663 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
664 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
669 void init_jcr_job_record(JCR *jcr)
671 jcr->jr.SchedTime = jcr->sched_time;
672 jcr->jr.StartTime = jcr->start_time;
673 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
674 jcr->jr.JobType = jcr->JobType;
675 jcr->jr.JobLevel = jcr->JobLevel;
676 jcr->jr.JobStatus = jcr->JobStatus;
677 jcr->jr.JobId = jcr->JobId;
678 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
679 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
683 * Write status and such in DB
685 void update_job_end_record(JCR *jcr)
687 jcr->jr.EndTime = time(NULL);
688 jcr->end_time = jcr->jr.EndTime;
689 jcr->jr.JobId = jcr->JobId;
690 jcr->jr.JobStatus = jcr->JobStatus;
691 jcr->jr.JobFiles = jcr->JobFiles;
692 jcr->jr.JobBytes = jcr->JobBytes;
693 jcr->jr.VolSessionId = jcr->VolSessionId;
694 jcr->jr.VolSessionTime = jcr->VolSessionTime;
695 jcr->jr.JobErrors = jcr->Errors;
696 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
697 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
698 db_strerror(jcr->db));
703 * Takes base_name and appends (unique) current
704 * date and time to form unique job name.
706 * Returns: unique job name in jcr->Job
707 * date/time in jcr->start_time
709 void create_unique_job_name(JCR *jcr, const char *base_name)
711 /* Job start mutex */
712 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
713 static time_t last_start_time = 0;
716 char dt[MAX_TIME_LENGTH];
717 char name[MAX_NAME_LENGTH];
720 /* Guarantee unique start time -- maximum one per second, and
721 * thus unique Job Name
723 P(mutex); /* lock creation of jobs */
725 while (now == last_start_time) {
726 bmicrosleep(0, 500000);
729 last_start_time = now;
730 V(mutex); /* allow creation of jobs */
731 jcr->start_time = now;
732 /* Form Unique JobName */
733 (void)localtime_r(&now, &tm);
734 /* Use only characters that are permitted in Windows filenames */
735 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
736 bstrncpy(name, base_name, sizeof(name));
737 name[sizeof(name)-22] = 0; /* truncate if too long */
738 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
739 /* Convert spaces into underscores */
740 for (p=jcr->Job; *p; p++) {
747 /* Called directly from job rescheduling */
748 void dird_free_jcr_pointers(JCR *jcr)
750 if (jcr->sd_auth_key) {
751 free(jcr->sd_auth_key);
752 jcr->sd_auth_key = NULL;
758 if (jcr->file_bsock) {
759 Dmsg0(200, "Close File bsock\n");
760 bnet_close(jcr->file_bsock);
761 jcr->file_bsock = NULL;
763 if (jcr->store_bsock) {
764 Dmsg0(200, "Close Store bsock\n");
765 bnet_close(jcr->store_bsock);
766 jcr->store_bsock = NULL;
769 Dmsg0(200, "Free JCR fname\n");
770 free_pool_memory(jcr->fname);
773 if (jcr->RestoreBootstrap) {
774 free(jcr->RestoreBootstrap);
775 jcr->RestoreBootstrap = NULL;
777 if (jcr->client_uname) {
778 free_pool_memory(jcr->client_uname);
779 jcr->client_uname = NULL;
782 free_pool_memory(jcr->attr);
792 * Free the Job Control Record if no one is still using it.
793 * Called from main free_jcr() routine in src/lib/jcr.c so
794 * that we can do our Director specific cleanup of the jcr.
796 void dird_free_jcr(JCR *jcr)
798 Dmsg0(200, "Start dird free_jcr\n");
800 dird_free_jcr_pointers(jcr);
801 if (jcr->term_wait_inited) {
802 pthread_cond_destroy(&jcr->term_wait);
803 jcr->term_wait_inited = false;
805 if (jcr->db_batch && jcr->db_batch != jcr->db) {
806 db_close_database(jcr, jcr->db_batch);
808 jcr->db_batch = NULL;
810 db_close_database(jcr, jcr->db);
814 Dmsg0(200, "Free JCR stime\n");
815 free_pool_memory(jcr->stime);
819 Dmsg0(200, "Free JCR fname\n");
820 free_pool_memory(jcr->fname);
823 if (jcr->pool_source) {
824 free_pool_memory(jcr->pool_source);
825 jcr->pool_source = NULL;
827 if (jcr->rpool_source) {
828 free_pool_memory(jcr->rpool_source);
829 jcr->rpool_source = NULL;
831 if (jcr->wstore_source) {
832 free_pool_memory(jcr->wstore_source);
833 jcr->wstore_source = NULL;
835 if (jcr->rstore_source) {
836 free_pool_memory(jcr->rstore_source);
837 jcr->rstore_source = NULL;
840 /* Delete lists setup to hold storage pointers */
843 jcr->job_end_push.destroy();
844 Dmsg0(200, "End dird free_jcr\n");
848 * The Job storage definition must be either in the Job record
849 * or in the Pool record. The Pool record overrides the Job
852 void get_job_storage(USTORE *store, JOB *job, RUN *run)
854 if (run && run->pool && run->pool->storage) {
855 store->store = (STORE *)run->pool->storage->first();
856 pm_strcpy(store->store_source, _("Run pool override"));
859 if (run && run->storage) {
860 store->store = run->storage;
861 pm_strcpy(store->store_source, _("Run storage override"));
864 if (job->pool->storage) {
865 store->store = (STORE *)job->pool->storage->first();
866 pm_strcpy(store->store_source, _("Pool resource"));
868 store->store = (STORE *)job->storage->first();
869 pm_strcpy(store->store_source, _("Job resource"));
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 if (!jcr->rpool_source) {
891 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
892 pm_strcpy(jcr->rpool_source, _("unknown source"));
894 /* Fall-through wanted */
896 jcr->JobLevel = job->JobLevel;
900 jcr->fname = get_pool_memory(PM_FNAME);
902 if (!jcr->pool_source) {
903 jcr->pool_source = get_pool_memory(PM_MESSAGE);
904 pm_strcpy(jcr->pool_source, _("unknown source"));
907 jcr->JobPriority = job->Priority;
908 /* Copy storage definitions -- deleted in dir_free_jcr above */
910 copy_rwstorage(jcr, job->storage, _("Job resource"));
912 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
914 jcr->client = job->client;
915 if (!jcr->client_name) {
916 jcr->client_name = get_pool_memory(PM_NAME);
918 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
919 pm_strcpy(jcr->pool_source, _("Job resource"));
920 jcr->pool = job->pool;
921 jcr->full_pool = job->full_pool;
922 jcr->inc_pool = job->inc_pool;
923 jcr->diff_pool = job->diff_pool;
924 jcr->catalog = job->client->catalog;
925 jcr->fileset = job->fileset;
926 jcr->messages = job->messages;
927 jcr->spool_data = job->spool_data;
928 jcr->write_part_after_job = job->write_part_after_job;
929 if (jcr->RestoreBootstrap) {
930 free(jcr->RestoreBootstrap);
931 jcr->RestoreBootstrap = NULL;
933 /* This can be overridden by Console program */
934 if (job->RestoreBootstrap) {
935 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
937 /* This can be overridden by Console program */
938 jcr->verify_job = job->verify_job;
939 /* If no default level given, set one */
940 if (jcr->JobLevel == 0) {
941 switch (jcr->JobType) {
943 jcr->JobLevel = L_VERIFY_CATALOG;
946 jcr->JobLevel = L_INCREMENTAL;
950 jcr->JobLevel = L_NONE;
953 jcr->JobLevel = L_FULL;
960 * Copy the storage definitions from an alist to the JCR
962 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
964 switch(jcr->JobType) {
968 copy_rstorage(jcr, storage, where);
971 copy_wstorage(jcr, storage, where);
977 /* Set storage override */
978 void set_rwstorage(JCR *jcr, USTORE *store)
981 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
984 switch(jcr->JobType) {
988 set_rstorage(jcr, store);
991 set_wstorage(jcr, store);
996 void free_rwstorage(JCR *jcr)
1003 * Copy the storage definitions from an alist to the JCR
1005 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1009 if (jcr->rstorage) {
1010 delete jcr->rstorage;
1012 jcr->rstorage = New(alist(10, not_owned_by_alist));
1013 foreach_alist(st, storage) {
1014 jcr->rstorage->append(st);
1016 if (!jcr->rstore_source) {
1017 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1019 pm_strcpy(jcr->rstore_source, where);
1020 if (jcr->rstorage) {
1021 jcr->rstore = (STORE *)jcr->rstorage->first();
1027 /* Set storage override */
1028 void set_rstorage(JCR *jcr, USTORE *store)
1032 if (!store->store) {
1035 if (!jcr->rstorage) {
1036 jcr->rstorage = New(alist(10, not_owned_by_alist));
1038 jcr->rstore = store->store;
1039 if (!jcr->rstore_source) {
1040 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1042 pm_strcpy(jcr->rstore_source, store->store_source);
1043 foreach_alist(storage, jcr->rstorage) {
1044 if (store->store == storage) {
1048 /* Store not in list, so add it */
1049 jcr->rstorage->prepend(store->store);
1052 void free_rstorage(JCR *jcr)
1054 if (jcr->rstorage) {
1055 delete jcr->rstorage;
1056 jcr->rstorage = NULL;
1062 * Copy the storage definitions from an alist to the JCR
1064 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1068 if (jcr->wstorage) {
1069 delete jcr->wstorage;
1071 jcr->wstorage = New(alist(10, not_owned_by_alist));
1072 foreach_alist(st, storage) {
1073 Dmsg1(100, "wstorage=%s\n", st->name());
1074 jcr->wstorage->append(st);
1076 if (!jcr->wstore_source) {
1077 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1079 pm_strcpy(jcr->wstore_source, where);
1080 if (jcr->wstorage) {
1081 jcr->wstore = (STORE *)jcr->wstorage->first();
1082 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1088 /* Set storage override */
1089 void set_wstorage(JCR *jcr, USTORE *store)
1093 if (!store->store) {
1096 if (!jcr->wstorage) {
1097 jcr->wstorage = New(alist(10, not_owned_by_alist));
1099 jcr->wstore = store->store;
1100 if (!jcr->wstore_source) {
1101 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1103 pm_strcpy(jcr->wstore_source, store->store_source);
1104 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1105 foreach_alist(storage, jcr->wstorage) {
1106 if (store->store == storage) {
1110 /* Store not in list, so add it */
1111 jcr->wstorage->prepend(store->store);
1114 void free_wstorage(JCR *jcr)
1116 if (jcr->wstorage) {
1117 delete jcr->wstorage;
1118 jcr->wstorage = NULL;
1123 void create_clones(JCR *jcr)
1126 * Fire off any clone jobs (run directives)
1128 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1129 if (!jcr->cloned && jcr->job->run_cmds) {
1131 JOB *job = jcr->job;
1132 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1133 UAContext *ua = new_ua_context(jcr);
1135 foreach_alist(runcmd, job->run_cmds) {
1136 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1137 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1138 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1139 parse_ua_args(ua); /* parse command */
1140 int stat = run_cmd(ua, ua->cmd);
1142 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1144 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1147 free_ua_context(ua);
1148 free_pool_memory(cmd);
1152 bool create_restore_bootstrap_file(JCR *jcr)
1156 memset(&rx, 0, sizeof(rx));
1159 rx.bsr->JobId = jcr->previous_jr.JobId;
1160 ua = new_ua_context(jcr);
1161 complete_bsr(ua, rx.bsr);
1162 rx.bsr->fi = new_findex();
1163 rx.bsr->fi->findex = 1;
1164 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1165 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1166 if (jcr->ExpectedFiles == 0) {
1167 free_ua_context(ua);
1171 free_ua_context(ua);
1173 jcr->needs_sd = true;