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 and included
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");
223 void update_job_end(JCR *jcr, int TermCode)
225 dequeue_messages(jcr); /* display any queued messages */
226 set_jcr_job_status(jcr, TermCode);
227 update_job_end_record(jcr);
231 * This is the engine called by jobq.c:jobq_add() when we were pulled
232 * from the work queue.
233 * At this point, we are running in our own thread and all
234 * necessary resources are allocated -- see jobq.c
236 static void *job_thread(void *arg)
238 JCR *jcr = (JCR *)arg;
240 jcr->my_thread_id = pthread_self();
241 pthread_detach(jcr->my_thread_id);
244 Dmsg0(200, "=====Start Job=========\n");
245 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
246 jcr->start_time = time(NULL); /* set the real start time */
247 jcr->jr.StartTime = jcr->start_time;
249 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
250 (utime_t)(jcr->start_time - jcr->sched_time)) {
251 set_jcr_job_status(jcr, JS_Canceled);
252 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
255 /* TODO : check if it is used somewhere */
256 if (jcr->job->RunScripts == NULL) {
257 Dmsg0(200, "Warning, job->RunScripts is empty\n");
258 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
261 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
262 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
265 /* Run any script BeforeJob on dird */
266 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
268 if (job_canceled(jcr)) {
269 update_job_end(jcr, jcr->JobStatus);
273 * We re-update the job start record so that the start
274 * time is set after the run before job. This avoids
275 * that any files created by the run before job will
276 * be saved twice. They will be backed up in the current
277 * job, but not in the next one unless they are changed.
278 * Without this, they will be backed up in this job and
279 * in the next job run because in that case, their date
280 * is after the start of this run.
282 jcr->start_time = time(NULL);
283 jcr->jr.StartTime = jcr->start_time;
284 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
285 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
287 generate_job_event(jcr, "JobRun");
289 switch (jcr->JobType) {
291 if (do_backup(jcr)) {
294 backup_cleanup(jcr, JS_ErrorTerminated);
298 if (do_verify(jcr)) {
301 verify_cleanup(jcr, JS_ErrorTerminated);
305 if (do_restore(jcr)) {
308 restore_cleanup(jcr, JS_ErrorTerminated);
315 admin_cleanup(jcr, JS_ErrorTerminated);
321 if (do_migration(jcr)) {
324 migration_cleanup(jcr, JS_ErrorTerminated);
328 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
333 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
335 /* Send off any queued messages */
336 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
337 dequeue_messages(jcr);
340 generate_daemon_event(jcr, "JobEnd");
341 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
342 sm_check(__FILE__, __LINE__, true);
348 * Cancel a job -- typically called by the UA (Console program), but may also
349 * be called by the job watchdog.
351 * Returns: true if cancel appears to be successful
352 * false on failure. Message sent to ua->jcr.
354 bool cancel_job(UAContext *ua, JCR *jcr)
359 set_jcr_job_status(jcr, JS_Canceled);
361 switch (jcr->JobStatus) {
364 case JS_WaitClientRes:
365 case JS_WaitStoreRes:
366 case JS_WaitPriority:
368 case JS_WaitStartTime:
369 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
370 edit_uint64(jcr->JobId, ed1), jcr->Job);
371 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
375 /* Cancel File daemon */
376 if (jcr->file_bsock) {
377 ua->jcr->client = jcr->client;
378 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
379 ua->error_msg(_("Failed to connect to File daemon.\n"));
382 Dmsg0(200, "Connected to file daemon\n");
383 fd = ua->jcr->file_bsock;
384 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
385 while (bnet_recv(fd) >= 0) {
386 ua->send_msg("%s", fd->msg);
388 bnet_sig(fd, BNET_TERMINATE);
390 ua->jcr->file_bsock = NULL;
393 /* Cancel Storage daemon */
394 if (jcr->store_bsock) {
395 if (!ua->jcr->wstorage) {
397 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
399 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
404 store.store = jcr->rstore;
406 store.store = jcr->wstore;
408 set_wstorage(ua->jcr, &store);
411 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
412 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
415 Dmsg0(200, "Connected to storage daemon\n");
416 sd = ua->jcr->store_bsock;
417 sd->fsend("cancel Job=%s\n", jcr->Job);
418 while (sd->recv() >= 0) {
419 ua->send_msg("%s", sd->msg);
421 sd->signal(BNET_TERMINATE);
423 ua->jcr->store_bsock = NULL;
431 static void job_monitor_destructor(watchdog_t *self)
433 JCR *control_jcr = (JCR *)self->data;
435 free_jcr(control_jcr);
438 static void job_monitor_watchdog(watchdog_t *self)
440 JCR *control_jcr, *jcr;
442 control_jcr = (JCR *)self->data;
445 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
450 if (jcr->JobId == 0 || job_canceled(jcr)) {
451 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
455 /* check MaxWaitTime */
456 if (job_check_maxwaittime(control_jcr, jcr)) {
457 set_jcr_job_status(jcr, JS_Canceled);
458 Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
460 /* check MaxRunTime */
461 } else if (job_check_maxruntime(control_jcr, jcr)) {
462 set_jcr_job_status(jcr, JS_Canceled);
463 Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
468 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
469 UAContext *ua = new_ua_context(jcr);
470 ua->jcr = control_jcr;
473 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
477 /* Keep reference counts correct */
482 * Check if the maxwaittime has expired and it is possible
485 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
490 if (job_canceled(jcr)) {
491 return false; /* already canceled */
493 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
494 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
497 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
498 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
500 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
501 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
503 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
504 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
506 } else if (job->MaxWaitTime != 0 &&
507 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
515 * Check if maxruntime has expired and if the job can be
518 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
520 if (jcr->job->MaxRunTime == 0 || job_canceled(jcr)) {
523 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
524 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
525 jcr, jcr->Job, jcr->job->MaxRunTime);
533 * Get or create a Pool record with the given name.
534 * Returns: 0 on error
537 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
541 memset(&pr, 0, sizeof(pr));
542 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
543 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
545 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
546 /* Try to create the pool */
547 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
548 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
549 db_strerror(jcr->db));
552 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
558 void apply_pool_overrides(JCR *jcr)
560 if (jcr->run_pool_override) {
561 pm_strcpy(jcr->pool_source, _("Run pool override"));
564 * Apply any level related Pool selections
566 switch (jcr->JobLevel) {
568 if (jcr->full_pool) {
569 jcr->pool = jcr->full_pool;
570 if (jcr->run_full_pool_override) {
571 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
573 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
579 jcr->pool = jcr->inc_pool;
580 if (jcr->run_inc_pool_override) {
581 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
583 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
588 if (jcr->diff_pool) {
589 jcr->pool = jcr->diff_pool;
590 if (jcr->run_diff_pool_override) {
591 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
593 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
602 * Get or create a Client record for this Job
604 bool get_or_create_client_record(JCR *jcr)
608 memset(&cr, 0, sizeof(cr));
609 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
610 cr.AutoPrune = jcr->client->AutoPrune;
611 cr.FileRetention = jcr->client->FileRetention;
612 cr.JobRetention = jcr->client->JobRetention;
613 if (!jcr->client_name) {
614 jcr->client_name = get_pool_memory(PM_NAME);
616 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
617 if (!db_create_client_record(jcr, jcr->db, &cr)) {
618 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
619 db_strerror(jcr->db));
622 jcr->jr.ClientId = cr.ClientId;
624 if (!jcr->client_uname) {
625 jcr->client_uname = get_pool_memory(PM_NAME);
627 pm_strcpy(jcr->client_uname, cr.Uname);
629 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
634 bool get_or_create_fileset_record(JCR *jcr)
638 * Get or Create FileSet record
640 memset(&fsr, 0, sizeof(FILESET_DBR));
641 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
642 if (jcr->fileset->have_MD5) {
643 struct MD5Context md5c;
644 unsigned char digest[MD5HashSize];
645 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
646 MD5Final(digest, &md5c);
648 * Keep the flag (last arg) set to false otherwise old FileSets will
649 * get new MD5 sums and the user will get Full backups on everything
651 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
652 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
654 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
656 if (!jcr->fileset->ignore_fs_changes ||
657 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
658 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
659 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
660 fsr.FileSet, db_strerror(jcr->db));
664 jcr->jr.FileSetId = fsr.FileSetId;
665 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
666 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
671 void init_jcr_job_record(JCR *jcr)
673 jcr->jr.SchedTime = jcr->sched_time;
674 jcr->jr.StartTime = jcr->start_time;
675 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
676 jcr->jr.JobType = jcr->JobType;
677 jcr->jr.JobLevel = jcr->JobLevel;
678 jcr->jr.JobStatus = jcr->JobStatus;
679 jcr->jr.JobId = jcr->JobId;
680 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
681 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
685 * Write status and such in DB
687 void update_job_end_record(JCR *jcr)
689 jcr->jr.EndTime = time(NULL);
690 jcr->end_time = jcr->jr.EndTime;
691 jcr->jr.JobId = jcr->JobId;
692 jcr->jr.JobStatus = jcr->JobStatus;
693 jcr->jr.JobFiles = jcr->JobFiles;
694 jcr->jr.JobBytes = jcr->JobBytes;
695 jcr->jr.VolSessionId = jcr->VolSessionId;
696 jcr->jr.VolSessionTime = jcr->VolSessionTime;
697 jcr->jr.JobErrors = jcr->Errors;
698 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
699 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
700 db_strerror(jcr->db));
705 * Takes base_name and appends (unique) current
706 * date and time to form unique job name.
708 * Returns: unique job name in jcr->Job
709 * date/time in jcr->start_time
711 void create_unique_job_name(JCR *jcr, const char *base_name)
713 /* Job start mutex */
714 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
715 static time_t last_start_time = 0;
718 char dt[MAX_TIME_LENGTH];
719 char name[MAX_NAME_LENGTH];
722 /* Guarantee unique start time -- maximum one per second, and
723 * thus unique Job Name
725 P(mutex); /* lock creation of jobs */
727 while (now == last_start_time) {
728 bmicrosleep(0, 500000);
731 last_start_time = now;
732 V(mutex); /* allow creation of jobs */
733 jcr->start_time = now;
734 /* Form Unique JobName */
735 (void)localtime_r(&now, &tm);
736 /* Use only characters that are permitted in Windows filenames */
737 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
738 bstrncpy(name, base_name, sizeof(name));
739 name[sizeof(name)-22] = 0; /* truncate if too long */
740 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s", name, dt); /* add date & time */
741 /* Convert spaces into underscores */
742 for (p=jcr->Job; *p; p++) {
749 /* Called directly from job rescheduling */
750 void dird_free_jcr_pointers(JCR *jcr)
752 if (jcr->sd_auth_key) {
753 free(jcr->sd_auth_key);
754 jcr->sd_auth_key = NULL;
760 if (jcr->file_bsock) {
761 Dmsg0(200, "Close File bsock\n");
762 bnet_close(jcr->file_bsock);
763 jcr->file_bsock = NULL;
765 if (jcr->store_bsock) {
766 Dmsg0(200, "Close Store bsock\n");
767 bnet_close(jcr->store_bsock);
768 jcr->store_bsock = NULL;
771 Dmsg0(200, "Free JCR fname\n");
772 free_pool_memory(jcr->fname);
775 if (jcr->RestoreBootstrap) {
776 free(jcr->RestoreBootstrap);
777 jcr->RestoreBootstrap = NULL;
779 if (jcr->client_uname) {
780 free_pool_memory(jcr->client_uname);
781 jcr->client_uname = NULL;
784 free_pool_memory(jcr->attr);
794 * Free the Job Control Record if no one is still using it.
795 * Called from main free_jcr() routine in src/lib/jcr.c so
796 * that we can do our Director specific cleanup of the jcr.
798 void dird_free_jcr(JCR *jcr)
800 Dmsg0(200, "Start dird free_jcr\n");
802 dird_free_jcr_pointers(jcr);
803 if (jcr->term_wait_inited) {
804 pthread_cond_destroy(&jcr->term_wait);
805 jcr->term_wait_inited = false;
807 if (jcr->db_batch && jcr->db_batch != jcr->db) {
808 db_close_database(jcr, jcr->db_batch);
810 jcr->db_batch = NULL;
812 db_close_database(jcr, jcr->db);
816 Dmsg0(200, "Free JCR stime\n");
817 free_pool_memory(jcr->stime);
821 Dmsg0(200, "Free JCR fname\n");
822 free_pool_memory(jcr->fname);
825 if (jcr->pool_source) {
826 free_pool_memory(jcr->pool_source);
827 jcr->pool_source = NULL;
829 if (jcr->rpool_source) {
830 free_pool_memory(jcr->rpool_source);
831 jcr->rpool_source = NULL;
833 if (jcr->wstore_source) {
834 free_pool_memory(jcr->wstore_source);
835 jcr->wstore_source = NULL;
837 if (jcr->rstore_source) {
838 free_pool_memory(jcr->rstore_source);
839 jcr->rstore_source = NULL;
842 /* Delete lists setup to hold storage pointers */
845 jcr->job_end_push.destroy();
846 Dmsg0(200, "End dird free_jcr\n");
850 * The Job storage definition must be either in the Job record
851 * or in the Pool record. The Pool record overrides the Job
854 void get_job_storage(USTORE *store, JOB *job, RUN *run)
856 if (run && run->pool && run->pool->storage) {
857 store->store = (STORE *)run->pool->storage->first();
858 pm_strcpy(store->store_source, _("Run pool override"));
861 if (run && run->storage) {
862 store->store = run->storage;
863 pm_strcpy(store->store_source, _("Run storage override"));
866 if (job->pool->storage) {
867 store->store = (STORE *)job->pool->storage->first();
868 pm_strcpy(store->store_source, _("Pool resource"));
870 store->store = (STORE *)job->storage->first();
871 pm_strcpy(store->store_source, _("Job resource"));
876 * Set some defaults in the JCR necessary to
877 * run. These items are pulled from the job
878 * definition as defaults, but can be overridden
879 * later either by the Run record in the Schedule resource,
880 * or by the Console program.
882 void set_jcr_defaults(JCR *jcr, JOB *job)
885 jcr->JobType = job->JobType;
886 switch (jcr->JobType) {
889 jcr->JobLevel = L_NONE;
892 if (!jcr->rpool_source) {
893 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
894 pm_strcpy(jcr->rpool_source, _("unknown source"));
896 /* Fall-through wanted */
898 jcr->JobLevel = job->JobLevel;
902 jcr->fname = get_pool_memory(PM_FNAME);
904 if (!jcr->pool_source) {
905 jcr->pool_source = get_pool_memory(PM_MESSAGE);
906 pm_strcpy(jcr->pool_source, _("unknown source"));
909 jcr->JobPriority = job->Priority;
910 /* Copy storage definitions -- deleted in dir_free_jcr above */
912 copy_rwstorage(jcr, job->storage, _("Job resource"));
914 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
916 jcr->client = job->client;
917 if (!jcr->client_name) {
918 jcr->client_name = get_pool_memory(PM_NAME);
920 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
921 pm_strcpy(jcr->pool_source, _("Job resource"));
922 jcr->pool = job->pool;
923 jcr->full_pool = job->full_pool;
924 jcr->inc_pool = job->inc_pool;
925 jcr->diff_pool = job->diff_pool;
926 jcr->catalog = job->client->catalog;
927 jcr->fileset = job->fileset;
928 jcr->messages = job->messages;
929 jcr->spool_data = job->spool_data;
930 jcr->write_part_after_job = job->write_part_after_job;
931 if (jcr->RestoreBootstrap) {
932 free(jcr->RestoreBootstrap);
933 jcr->RestoreBootstrap = NULL;
935 /* This can be overridden by Console program */
936 if (job->RestoreBootstrap) {
937 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
939 /* This can be overridden by Console program */
940 jcr->verify_job = job->verify_job;
941 /* If no default level given, set one */
942 if (jcr->JobLevel == 0) {
943 switch (jcr->JobType) {
945 jcr->JobLevel = L_VERIFY_CATALOG;
948 jcr->JobLevel = L_INCREMENTAL;
952 jcr->JobLevel = L_NONE;
955 jcr->JobLevel = L_FULL;
962 * Copy the storage definitions from an alist to the JCR
964 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
966 switch(jcr->JobType) {
970 copy_rstorage(jcr, storage, where);
973 copy_wstorage(jcr, storage, where);
979 /* Set storage override. Releases any previous storage definition */
980 void set_rwstorage(JCR *jcr, USTORE *store)
983 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
986 switch(jcr->JobType) {
990 set_rstorage(jcr, store);
993 set_wstorage(jcr, store);
998 void free_rwstorage(JCR *jcr)
1005 * Copy the storage definitions from an alist to the JCR
1007 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1011 if (jcr->rstorage) {
1012 delete jcr->rstorage;
1014 jcr->rstorage = New(alist(10, not_owned_by_alist));
1015 foreach_alist(st, storage) {
1016 jcr->rstorage->append(st);
1018 if (!jcr->rstore_source) {
1019 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1021 pm_strcpy(jcr->rstore_source, where);
1022 if (jcr->rstorage) {
1023 jcr->rstore = (STORE *)jcr->rstorage->first();
1029 /* Set storage override. Remove all previous storage */
1030 void set_rstorage(JCR *jcr, USTORE *store)
1034 if (!store->store) {
1037 if (jcr->rstorage) {
1040 if (!jcr->rstorage) {
1041 jcr->rstorage = New(alist(10, not_owned_by_alist));
1043 jcr->rstore = store->store;
1044 if (!jcr->rstore_source) {
1045 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1047 pm_strcpy(jcr->rstore_source, store->store_source);
1048 foreach_alist(storage, jcr->rstorage) {
1049 if (store->store == storage) {
1053 /* Store not in list, so add it */
1054 jcr->rstorage->prepend(store->store);
1057 void free_rstorage(JCR *jcr)
1059 if (jcr->rstorage) {
1060 delete jcr->rstorage;
1061 jcr->rstorage = NULL;
1067 * Copy the storage definitions from an alist to the JCR
1069 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1073 if (jcr->wstorage) {
1074 delete jcr->wstorage;
1076 jcr->wstorage = New(alist(10, not_owned_by_alist));
1077 foreach_alist(st, storage) {
1078 Dmsg1(100, "wstorage=%s\n", st->name());
1079 jcr->wstorage->append(st);
1081 if (!jcr->wstore_source) {
1082 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1084 pm_strcpy(jcr->wstore_source, where);
1085 if (jcr->wstorage) {
1086 jcr->wstore = (STORE *)jcr->wstorage->first();
1087 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1093 /* Set storage override. Remove all previous storage */
1094 void set_wstorage(JCR *jcr, USTORE *store)
1098 if (!store->store) {
1101 if (jcr->wstorage) {
1104 if (!jcr->wstorage) {
1105 jcr->wstorage = New(alist(10, not_owned_by_alist));
1107 jcr->wstore = store->store;
1108 if (!jcr->wstore_source) {
1109 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1111 pm_strcpy(jcr->wstore_source, store->store_source);
1112 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1113 foreach_alist(storage, jcr->wstorage) {
1114 if (store->store == storage) {
1118 /* Store not in list, so add it */
1119 jcr->wstorage->prepend(store->store);
1122 void free_wstorage(JCR *jcr)
1124 if (jcr->wstorage) {
1125 delete jcr->wstorage;
1126 jcr->wstorage = NULL;
1131 void create_clones(JCR *jcr)
1134 * Fire off any clone jobs (run directives)
1136 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1137 if (!jcr->cloned && jcr->job->run_cmds) {
1139 JOB *job = jcr->job;
1140 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1141 UAContext *ua = new_ua_context(jcr);
1143 foreach_alist(runcmd, job->run_cmds) {
1144 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1145 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1146 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1147 parse_ua_args(ua); /* parse command */
1148 int stat = run_cmd(ua, ua->cmd);
1150 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1152 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1155 free_ua_context(ua);
1156 free_pool_memory(cmd);
1160 bool create_restore_bootstrap_file(JCR *jcr)
1164 memset(&rx, 0, sizeof(rx));
1167 rx.bsr->JobId = jcr->previous_jr.JobId;
1168 ua = new_ua_context(jcr);
1169 complete_bsr(ua, rx.bsr);
1170 rx.bsr->fi = new_findex();
1171 rx.bsr->fi->findex = 1;
1172 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1173 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1174 if (jcr->ExpectedFiles == 0) {
1175 free_ua_context(ua);
1179 free_ua_context(ua);
1181 jcr->needs_sd = true;