2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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
39 /* Forward referenced subroutines */
40 static void *job_thread(void *arg);
41 static void job_monitor_watchdog(watchdog_t *self);
42 static void job_monitor_destructor(watchdog_t *self);
43 static bool job_check_maxwaittime(JCR *jcr);
44 static bool job_check_maxruntime(JCR *jcr);
45 static bool job_check_maxrunschedtime(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)
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));
117 jcr->term_wait_inited = true;
119 create_unique_job_name(jcr, jcr->job->name());
120 jcr->setJobStatus(JS_Created);
126 Dmsg0(100, "Open database\n");
127 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
128 jcr->catalog->db_user, jcr->catalog->db_password,
129 jcr->catalog->db_address, jcr->catalog->db_port,
130 jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
131 jcr->catalog->disable_batch_insert);
132 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
133 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
134 jcr->catalog->db_name);
136 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
137 db_close_database(jcr, jcr->db);
141 Dmsg0(150, "DB opened\n");
143 jcr->fname = get_pool_memory(PM_FNAME);
145 if (!jcr->pool_source) {
146 jcr->pool_source = get_pool_memory(PM_MESSAGE);
147 pm_strcpy(jcr->pool_source, _("unknown source"));
150 if (jcr->JobReads()) {
151 if (!jcr->rpool_source) {
152 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
153 pm_strcpy(jcr->rpool_source, _("unknown source"));
160 init_jcr_job_record(jcr);
161 if (!get_or_create_client_record(jcr)) {
165 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
166 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
169 jcr->JobId = jcr->jr.JobId;
170 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
171 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
173 generate_daemon_event(jcr, "JobStart");
174 new_plugins(jcr); /* instantiate plugins for this jcr */
175 generate_plugin_event(jcr, bEventJobStart);
177 if (job_canceled(jcr)) {
181 if (jcr->JobReads() && !jcr->rstorage) {
182 if (jcr->job->storage) {
183 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
185 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
188 if (!jcr->JobReads()) {
193 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
194 * this allows us to setup a proper job start record for restarting
195 * in case of later errors.
197 switch (jcr->getJobType()) {
199 if (!do_backup_init(jcr)) {
200 backup_cleanup(jcr, JS_ErrorTerminated);
205 if (!do_verify_init(jcr)) {
206 verify_cleanup(jcr, JS_ErrorTerminated);
211 if (!do_restore_init(jcr)) {
212 restore_cleanup(jcr, JS_ErrorTerminated);
217 if (!do_admin_init(jcr)) {
218 admin_cleanup(jcr, JS_ErrorTerminated);
224 if (!do_migration_init(jcr)) {
225 migration_cleanup(jcr, JS_ErrorTerminated);
230 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
231 jcr->setJobStatus(JS_ErrorTerminated);
235 generate_job_event(jcr, "JobInit");
236 generate_plugin_event(jcr, bEventJobInit);
244 void update_job_end(JCR *jcr, int TermCode)
246 dequeue_messages(jcr); /* display any queued messages */
247 jcr->setJobStatus(TermCode);
248 update_job_end_record(jcr);
252 * This is the engine called by jobq.c:jobq_add() when we were pulled
253 * from the work queue.
254 * At this point, we are running in our own thread and all
255 * necessary resources are allocated -- see jobq.c
257 static void *job_thread(void *arg)
259 JCR *jcr = (JCR *)arg;
261 pthread_detach(pthread_self());
264 Dmsg0(200, "=====Start Job=========\n");
265 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
266 jcr->start_time = time(NULL); /* set the real start time */
267 jcr->jr.StartTime = jcr->start_time;
269 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
270 (utime_t)(jcr->start_time - jcr->sched_time)) {
271 jcr->setJobStatus(JS_Canceled);
272 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
275 if (job_check_maxrunschedtime(jcr)) {
276 jcr->setJobStatus(JS_Canceled);
277 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
280 /* TODO : check if it is used somewhere */
281 if (jcr->job->RunScripts == NULL) {
282 Dmsg0(200, "Warning, job->RunScripts is empty\n");
283 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
286 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
287 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
290 /* Run any script BeforeJob on dird */
291 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
294 * We re-update the job start record so that the start
295 * time is set after the run before job. This avoids
296 * that any files created by the run before job will
297 * be saved twice. They will be backed up in the current
298 * job, but not in the next one unless they are changed.
299 * Without this, they will be backed up in this job and
300 * in the next job run because in that case, their date
301 * is after the start of this run.
303 jcr->start_time = time(NULL);
304 jcr->jr.StartTime = jcr->start_time;
305 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
306 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
308 generate_job_event(jcr, "JobRun");
309 generate_plugin_event(jcr, bEventJobRun);
311 switch (jcr->getJobType()) {
313 if (!job_canceled(jcr) && do_backup(jcr)) {
316 backup_cleanup(jcr, JS_ErrorTerminated);
320 if (!job_canceled(jcr) && do_verify(jcr)) {
323 verify_cleanup(jcr, JS_ErrorTerminated);
327 if (!job_canceled(jcr) && do_restore(jcr)) {
330 restore_cleanup(jcr, JS_ErrorTerminated);
334 if (!job_canceled(jcr) && do_admin(jcr)) {
337 admin_cleanup(jcr, JS_ErrorTerminated);
342 if (!job_canceled(jcr) && do_migration(jcr)) {
345 migration_cleanup(jcr, JS_ErrorTerminated);
349 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
353 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
355 /* Send off any queued messages */
356 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
357 dequeue_messages(jcr);
360 generate_daemon_event(jcr, "JobEnd");
361 generate_plugin_event(jcr, bEventJobEnd);
362 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
367 void sd_msg_thread_send_signal(JCR *jcr, int sig)
370 if ( !jcr->sd_msg_thread_done
372 && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
374 Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
375 pthread_kill(jcr->SD_msg_chan, sig);
381 * Cancel a job -- typically called by the UA (Console program), but may also
382 * be called by the job watchdog.
384 * Returns: true if cancel appears to be successful
385 * false on failure. Message sent to ua->jcr.
387 bool cancel_job(UAContext *ua, JCR *jcr)
391 int32_t old_status = jcr->JobStatus;
393 jcr->setJobStatus(JS_Canceled);
395 switch (old_status) {
398 case JS_WaitClientRes:
399 case JS_WaitStoreRes:
400 case JS_WaitPriority:
402 case JS_WaitStartTime:
403 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
404 edit_uint64(jcr->JobId, ed1), jcr->Job);
405 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
409 /* Cancel File daemon */
410 if (jcr->file_bsock) {
411 ua->jcr->client = jcr->client;
412 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
413 ua->error_msg(_("Failed to connect to File daemon.\n"));
416 Dmsg0(200, "Connected to file daemon\n");
417 fd = ua->jcr->file_bsock;
418 fd->fsend("cancel Job=%s\n", jcr->Job);
419 while (fd->recv() >= 0) {
420 ua->send_msg("%s", fd->msg);
422 fd->signal(BNET_TERMINATE);
424 ua->jcr->file_bsock = NULL;
425 jcr->file_bsock->set_terminated();
426 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
429 /* Cancel Storage daemon */
430 if (jcr->store_bsock) {
431 if (!ua->jcr->wstorage) {
433 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
435 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
440 store.store = jcr->rstore;
442 store.store = jcr->wstore;
444 set_wstorage(ua->jcr, &store);
447 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
448 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
451 Dmsg0(200, "Connected to storage daemon\n");
452 sd = ua->jcr->store_bsock;
453 sd->fsend("cancel Job=%s\n", jcr->Job);
454 while (sd->recv() >= 0) {
455 ua->send_msg("%s", sd->msg);
457 sd->signal(BNET_TERMINATE);
459 ua->jcr->store_bsock = NULL;
460 jcr->store_bsock->set_timed_out();
461 jcr->store_bsock->set_terminated();
462 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
463 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
471 void cancel_storage_daemon_job(JCR *jcr)
473 if (jcr->sd_canceled) {
474 return; /* cancel only once */
477 UAContext *ua = new_ua_context(jcr);
478 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
481 ua->jcr = control_jcr;
482 if (jcr->store_bsock) {
483 if (!ua->jcr->wstorage) {
485 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
487 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
492 store.store = jcr->rstore;
494 store.store = jcr->wstore;
496 set_wstorage(ua->jcr, &store);
499 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
502 Dmsg0(200, "Connected to storage daemon\n");
503 sd = ua->jcr->store_bsock;
504 sd->fsend("cancel Job=%s\n", jcr->Job);
505 while (sd->recv() >= 0) {
507 sd->signal(BNET_TERMINATE);
509 ua->jcr->store_bsock = NULL;
510 jcr->sd_canceled = true;
511 jcr->store_bsock->set_timed_out();
512 jcr->store_bsock->set_terminated();
513 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
514 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
517 free_jcr(control_jcr);
521 static void job_monitor_destructor(watchdog_t *self)
523 JCR *control_jcr = (JCR *)self->data;
525 free_jcr(control_jcr);
528 static void job_monitor_watchdog(watchdog_t *self)
530 JCR *control_jcr, *jcr;
532 control_jcr = (JCR *)self->data;
535 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
540 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
541 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
545 /* check MaxWaitTime */
546 if (job_check_maxwaittime(jcr)) {
547 jcr->setJobStatus(JS_Canceled);
548 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
550 /* check MaxRunTime */
551 } else if (job_check_maxruntime(jcr)) {
552 jcr->setJobStatus(JS_Canceled);
553 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
555 /* check MaxRunSchedTime */
556 } else if (job_check_maxrunschedtime(jcr)) {
557 jcr->setJobStatus(JS_Canceled);
558 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
563 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
564 UAContext *ua = new_ua_context(jcr);
565 ua->jcr = control_jcr;
568 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
572 /* Keep reference counts correct */
577 * Check if the maxwaittime has expired and it is possible
580 static bool job_check_maxwaittime(JCR *jcr)
586 if (!job_waiting(jcr)) {
590 if (jcr->wait_time) {
591 current = watchdog_time - jcr->wait_time;
594 Dmsg2(200, "check maxwaittime %u >= %u\n",
595 current + jcr->wait_time_sum, job->MaxWaitTime);
596 if (job->MaxWaitTime != 0 &&
597 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
605 * Check if maxruntime has expired and if the job can be
608 static bool job_check_maxruntime(JCR *jcr)
614 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
617 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
618 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
621 run_time = watchdog_time - jcr->start_time;
622 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
623 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
624 job->IncMaxRunTime, job->DiffMaxRunTime);
626 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
627 run_time >= job->FullMaxRunTime) {
628 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
630 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
631 run_time >= job->DiffMaxRunTime) {
632 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
634 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
635 run_time >= job->IncMaxRunTime) {
636 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
638 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
639 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
647 * Check if MaxRunSchedTime has expired and if the job can be
650 static bool job_check_maxrunschedtime(JCR *jcr)
652 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
655 if ((watchdog_time - jcr->sched_time) < jcr->MaxRunSchedTime) {
656 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
657 jcr, jcr->Job, jcr->MaxRunSchedTime);
665 * Get or create a Pool record with the given name.
666 * Returns: 0 on error
669 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
673 memset(&pr, 0, sizeof(pr));
674 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
675 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
677 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
678 /* Try to create the pool */
679 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
680 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
681 db_strerror(jcr->db));
684 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
691 * Check for duplicate jobs.
692 * Returns: true if current job should continue
693 * false if current job should terminate
695 bool allow_duplicate_job(JCR *jcr)
698 JCR *djcr; /* possible duplicate job */
699 bool cancel_dup = false;
700 bool cancel_me = false;
703 * See if AllowDuplicateJobs is set or
704 * if duplicate checking is disabled for this job.
706 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
710 Dmsg0(800, "Enter allow_duplicate_job\n");
713 * After this point, we do not want to allow any duplicate
718 if (jcr == djcr || djcr->JobId == 0) {
719 continue; /* do not cancel this job or consoles */
723 * See if this Job has the IgnoreDuplicateJobChecking flag set, ignore it
724 * for any checking against other jobs.
726 if (djcr->IgnoreDuplicateJobChecking) {
730 if (strcmp(job->name(), djcr->job->name()) == 0) {
731 if (job->DuplicateJobProximity > 0) {
732 utime_t now = (utime_t)time(NULL);
733 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
734 continue; /* not really a duplicate */
737 if (job->CancelLowerLevelDuplicates &&
738 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
739 switch (jcr->getJobLevel()) {
741 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
742 djcr->getJobLevel() == L_INCREMENTAL) {
747 if (djcr->getJobLevel() == L_INCREMENTAL) {
750 if (djcr->getJobLevel() == L_FULL) {
755 if (djcr->getJobLevel() == L_FULL ||
756 djcr->getJobLevel() == L_DIFFERENTIAL) {
761 * cancel_dup will be done below
764 /* Zap current job */
765 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
767 break; /* get out of foreach_jcr */
772 * Cancel one of the two jobs (me or dup)
773 * If CancelQueuedDuplicates is set do so only if job is queued.
775 if (job->CancelQueuedDuplicates) {
776 switch (djcr->JobStatus) {
779 case JS_WaitClientRes:
780 case JS_WaitStoreRes:
781 case JS_WaitPriority:
783 case JS_WaitStartTime:
784 cancel_dup = true; /* cancel queued duplicate */
791 if (cancel_dup || job->CancelRunningDuplicates) {
793 * Zap the duplicated job djcr
795 UAContext *ua = new_ua_context(jcr);
796 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
797 cancel_job(ua, djcr);
798 bmicrosleep(0, 500000);
799 cancel_job(ua, djcr);
801 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
806 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
808 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
810 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
811 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
812 break; /* did our work, get out of foreach loop */
820 void apply_pool_overrides(JCR *jcr)
822 bool pool_override = false;
824 if (jcr->run_pool_override) {
825 pm_strcpy(jcr->pool_source, _("Run pool override"));
828 * Apply any level related Pool selections
830 switch (jcr->getJobLevel()) {
832 if (jcr->full_pool) {
833 jcr->pool = jcr->full_pool;
834 pool_override = true;
835 if (jcr->run_full_pool_override) {
836 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
838 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
844 jcr->pool = jcr->inc_pool;
845 pool_override = true;
846 if (jcr->run_inc_pool_override) {
847 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
849 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
854 if (jcr->diff_pool) {
855 jcr->pool = jcr->diff_pool;
856 pool_override = true;
857 if (jcr->run_diff_pool_override) {
858 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
860 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
865 /* Update catalog if pool overridden */
866 if (pool_override && jcr->pool->catalog) {
867 jcr->catalog = jcr->pool->catalog;
868 pm_strcpy(jcr->catalog_source, _("Pool resource"));
874 * Get or create a Client record for this Job
876 bool get_or_create_client_record(JCR *jcr)
880 memset(&cr, 0, sizeof(cr));
881 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
882 cr.AutoPrune = jcr->client->AutoPrune;
883 cr.FileRetention = jcr->client->FileRetention;
884 cr.JobRetention = jcr->client->JobRetention;
885 if (!jcr->client_name) {
886 jcr->client_name = get_pool_memory(PM_NAME);
888 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
889 if (!db_create_client_record(jcr, jcr->db, &cr)) {
890 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
891 db_strerror(jcr->db));
894 jcr->jr.ClientId = cr.ClientId;
896 if (!jcr->client_uname) {
897 jcr->client_uname = get_pool_memory(PM_NAME);
899 pm_strcpy(jcr->client_uname, cr.Uname);
901 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
906 bool get_or_create_fileset_record(JCR *jcr)
910 * Get or Create FileSet record
912 memset(&fsr, 0, sizeof(FILESET_DBR));
913 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
914 if (jcr->fileset->have_MD5) {
915 struct MD5Context md5c;
916 unsigned char digest[MD5HashSize];
917 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
918 MD5Final(digest, &md5c);
920 * Keep the flag (last arg) set to false otherwise old FileSets will
921 * get new MD5 sums and the user will get Full backups on everything
923 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
924 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
926 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
928 if (!jcr->fileset->ignore_fs_changes ||
929 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
930 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
931 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
932 fsr.FileSet, db_strerror(jcr->db));
936 jcr->jr.FileSetId = fsr.FileSetId;
937 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
938 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
943 void init_jcr_job_record(JCR *jcr)
945 jcr->jr.SchedTime = jcr->sched_time;
946 jcr->jr.StartTime = jcr->start_time;
947 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
948 jcr->jr.JobType = jcr->getJobType();
949 jcr->jr.JobLevel = jcr->getJobLevel();
950 jcr->jr.JobStatus = jcr->JobStatus;
951 jcr->jr.JobId = jcr->JobId;
952 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
953 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
957 * Write status and such in DB
959 void update_job_end_record(JCR *jcr)
961 jcr->jr.EndTime = time(NULL);
962 jcr->end_time = jcr->jr.EndTime;
963 jcr->jr.JobId = jcr->JobId;
964 jcr->jr.JobStatus = jcr->JobStatus;
965 jcr->jr.JobFiles = jcr->JobFiles;
966 jcr->jr.JobBytes = jcr->JobBytes;
967 jcr->jr.ReadBytes = jcr->ReadBytes;
968 jcr->jr.VolSessionId = jcr->VolSessionId;
969 jcr->jr.VolSessionTime = jcr->VolSessionTime;
970 jcr->jr.JobErrors = jcr->JobErrors;
971 jcr->jr.HasBase = jcr->HasBase;
972 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
973 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
974 db_strerror(jcr->db));
979 * Takes base_name and appends (unique) current
980 * date and time to form unique job name.
982 * Note, the seconds are actually a sequence number. This
983 * permits us to start a maximum fo 59 unique jobs a second, which
984 * should be sufficient.
986 * Returns: unique job name in jcr->Job
987 * date/time in jcr->start_time
989 void create_unique_job_name(JCR *jcr, const char *base_name)
991 /* Job start mutex */
992 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
993 static time_t last_start_time = 0;
995 time_t now = time(NULL);
997 char dt[MAX_TIME_LENGTH];
998 char name[MAX_NAME_LENGTH];
1002 /* Guarantee unique start time -- maximum one per second, and
1003 * thus unique Job Name
1005 P(mutex); /* lock creation of jobs */
1007 if (seq > 59) { /* wrap as if it is seconds */
1009 while (now == last_start_time) {
1010 bmicrosleep(0, 500000);
1014 last_start_time = now;
1015 V(mutex); /* allow creation of jobs */
1016 jcr->start_time = now;
1017 /* Form Unique JobName */
1018 (void)localtime_r(&now, &tm);
1019 /* Use only characters that are permitted in Windows filenames */
1020 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1021 len = strlen(dt) + 5; /* dt + .%02d EOS */
1022 bstrncpy(name, base_name, sizeof(name));
1023 name[sizeof(name)-len] = 0; /* truncate if too long */
1024 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
1025 /* Convert spaces into underscores */
1026 for (p=jcr->Job; *p; p++) {
1031 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1034 /* Called directly from job rescheduling */
1035 void dird_free_jcr_pointers(JCR *jcr)
1037 if (jcr->file_bsock) {
1038 Dmsg0(200, "Close File bsock\n");
1039 bnet_close(jcr->file_bsock);
1040 jcr->file_bsock = NULL;
1042 if (jcr->store_bsock) {
1043 Dmsg0(200, "Close Store bsock\n");
1044 bnet_close(jcr->store_bsock);
1045 jcr->store_bsock = NULL;
1048 bfree_and_null(jcr->sd_auth_key);
1049 bfree_and_null(jcr->where);
1050 bfree_and_null(jcr->RestoreBootstrap);
1051 bfree_and_null(jcr->ar);
1053 free_and_null_pool_memory(jcr->JobIds);
1054 free_and_null_pool_memory(jcr->client_uname);
1055 free_and_null_pool_memory(jcr->attr);
1056 free_and_null_pool_memory(jcr->fname);
1060 * Free the Job Control Record if no one is still using it.
1061 * Called from main free_jcr() routine in src/lib/jcr.c so
1062 * that we can do our Director specific cleanup of the jcr.
1064 void dird_free_jcr(JCR *jcr)
1066 Dmsg0(200, "Start dird free_jcr\n");
1068 dird_free_jcr_pointers(jcr);
1069 if (jcr->term_wait_inited) {
1070 pthread_cond_destroy(&jcr->term_wait);
1071 jcr->term_wait_inited = false;
1073 if (jcr->db_batch) {
1074 db_close_database(jcr, jcr->db_batch);
1075 jcr->db_batch = NULL;
1076 jcr->batch_started = false;
1079 db_close_database(jcr, jcr->db);
1083 free_and_null_pool_memory(jcr->stime);
1084 free_and_null_pool_memory(jcr->fname);
1085 free_and_null_pool_memory(jcr->pool_source);
1086 free_and_null_pool_memory(jcr->catalog_source);
1087 free_and_null_pool_memory(jcr->rpool_source);
1088 free_and_null_pool_memory(jcr->wstore_source);
1089 free_and_null_pool_memory(jcr->rstore_source);
1091 /* Delete lists setup to hold storage pointers */
1092 free_rwstorage(jcr);
1094 jcr->job_end_push.destroy();
1096 if (jcr->JobId != 0)
1097 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1099 free_plugins(jcr); /* release instantiated plugins */
1101 Dmsg0(200, "End dird free_jcr\n");
1105 * The Job storage definition must be either in the Job record
1106 * or in the Pool record. The Pool record overrides the Job
1109 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1111 if (run && run->pool && run->pool->storage) {
1112 store->store = (STORE *)run->pool->storage->first();
1113 pm_strcpy(store->store_source, _("Run pool override"));
1116 if (run && run->storage) {
1117 store->store = run->storage;
1118 pm_strcpy(store->store_source, _("Run storage override"));
1121 if (job->pool->storage) {
1122 store->store = (STORE *)job->pool->storage->first();
1123 pm_strcpy(store->store_source, _("Pool resource"));
1125 store->store = (STORE *)job->storage->first();
1126 pm_strcpy(store->store_source, _("Job resource"));
1131 * Set some defaults in the JCR necessary to
1132 * run. These items are pulled from the job
1133 * definition as defaults, but can be overridden
1134 * later either by the Run record in the Schedule resource,
1135 * or by the Console program.
1137 void set_jcr_defaults(JCR *jcr, JOB *job)
1140 jcr->setJobType(job->JobType);
1141 jcr->JobStatus = JS_Created;
1143 switch (jcr->getJobType()) {
1145 jcr->setJobLevel(L_NONE);
1148 jcr->setJobLevel(job->JobLevel);
1153 jcr->fname = get_pool_memory(PM_FNAME);
1155 if (!jcr->pool_source) {
1156 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1157 pm_strcpy(jcr->pool_source, _("unknown source"));
1159 if (!jcr->catalog_source) {
1160 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1161 pm_strcpy(jcr->catalog_source, _("unknown source"));
1164 jcr->JobPriority = job->Priority;
1165 /* Copy storage definitions -- deleted in dir_free_jcr above */
1167 copy_rwstorage(jcr, job->storage, _("Job resource"));
1169 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1171 jcr->client = job->client;
1172 if (!jcr->client_name) {
1173 jcr->client_name = get_pool_memory(PM_NAME);
1175 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1176 pm_strcpy(jcr->pool_source, _("Job resource"));
1177 jcr->pool = job->pool;
1178 jcr->full_pool = job->full_pool;
1179 jcr->inc_pool = job->inc_pool;
1180 jcr->diff_pool = job->diff_pool;
1181 if (job->pool->catalog) {
1182 jcr->catalog = job->pool->catalog;
1183 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1185 jcr->catalog = job->client->catalog;
1186 pm_strcpy(jcr->catalog_source, _("Client resource"));
1188 jcr->fileset = job->fileset;
1189 jcr->accurate = job->accurate;
1190 jcr->messages = job->messages;
1191 jcr->spool_data = job->spool_data;
1192 jcr->spool_size = job->spool_size;
1193 jcr->write_part_after_job = job->write_part_after_job;
1194 jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
1195 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1196 if (jcr->RestoreBootstrap) {
1197 free(jcr->RestoreBootstrap);
1198 jcr->RestoreBootstrap = NULL;
1200 /* This can be overridden by Console program */
1201 if (job->RestoreBootstrap) {
1202 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1204 /* This can be overridden by Console program */
1205 jcr->verify_job = job->verify_job;
1206 /* If no default level given, set one */
1207 if (jcr->getJobLevel() == 0) {
1208 switch (jcr->getJobType()) {
1210 jcr->setJobLevel(L_VERIFY_CATALOG);
1213 jcr->setJobLevel(L_INCREMENTAL);
1217 jcr->setJobLevel(L_NONE);
1220 jcr->setJobLevel(L_FULL);
1227 * Copy the storage definitions from an alist to the JCR
1229 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1231 if (jcr->JobReads()) {
1232 copy_rstorage(jcr, storage, where);
1234 copy_wstorage(jcr, storage, where);
1238 /* Set storage override. Releases any previous storage definition */
1239 void set_rwstorage(JCR *jcr, USTORE *store)
1242 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1245 if (jcr->JobReads()) {
1246 set_rstorage(jcr, store);
1248 set_wstorage(jcr, store);
1251 void free_rwstorage(JCR *jcr)
1258 * Copy the storage definitions from an alist to the JCR
1260 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1264 if (jcr->rstorage) {
1265 delete jcr->rstorage;
1267 jcr->rstorage = New(alist(10, not_owned_by_alist));
1268 foreach_alist(st, storage) {
1269 jcr->rstorage->append(st);
1271 if (!jcr->rstore_source) {
1272 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1274 pm_strcpy(jcr->rstore_source, where);
1275 if (jcr->rstorage) {
1276 jcr->rstore = (STORE *)jcr->rstorage->first();
1282 /* Set storage override. Remove all previous storage */
1283 void set_rstorage(JCR *jcr, USTORE *store)
1287 if (!store->store) {
1290 if (jcr->rstorage) {
1293 if (!jcr->rstorage) {
1294 jcr->rstorage = New(alist(10, not_owned_by_alist));
1296 jcr->rstore = store->store;
1297 if (!jcr->rstore_source) {
1298 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1300 pm_strcpy(jcr->rstore_source, store->store_source);
1301 foreach_alist(storage, jcr->rstorage) {
1302 if (store->store == storage) {
1306 /* Store not in list, so add it */
1307 jcr->rstorage->prepend(store->store);
1310 void free_rstorage(JCR *jcr)
1312 if (jcr->rstorage) {
1313 delete jcr->rstorage;
1314 jcr->rstorage = NULL;
1320 * Copy the storage definitions from an alist to the JCR
1322 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1326 if (jcr->wstorage) {
1327 delete jcr->wstorage;
1329 jcr->wstorage = New(alist(10, not_owned_by_alist));
1330 foreach_alist(st, storage) {
1331 Dmsg1(100, "wstorage=%s\n", st->name());
1332 jcr->wstorage->append(st);
1334 if (!jcr->wstore_source) {
1335 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1337 pm_strcpy(jcr->wstore_source, where);
1338 if (jcr->wstorage) {
1339 jcr->wstore = (STORE *)jcr->wstorage->first();
1340 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1346 /* Set storage override. Remove all previous storage */
1347 void set_wstorage(JCR *jcr, USTORE *store)
1351 if (!store->store) {
1354 if (jcr->wstorage) {
1357 if (!jcr->wstorage) {
1358 jcr->wstorage = New(alist(10, not_owned_by_alist));
1360 jcr->wstore = store->store;
1361 if (!jcr->wstore_source) {
1362 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1364 pm_strcpy(jcr->wstore_source, store->store_source);
1365 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1366 foreach_alist(storage, jcr->wstorage) {
1367 if (store->store == storage) {
1371 /* Store not in list, so add it */
1372 jcr->wstorage->prepend(store->store);
1375 void free_wstorage(JCR *jcr)
1377 if (jcr->wstorage) {
1378 delete jcr->wstorage;
1379 jcr->wstorage = NULL;
1384 char *job_code_callback_clones(JCR *jcr, const char* param)
1386 if (param[0] == 'p') {
1387 return jcr->pool->name();
1392 void create_clones(JCR *jcr)
1395 * Fire off any clone jobs (run directives)
1397 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1398 if (!jcr->cloned && jcr->job->run_cmds) {
1400 JOB *job = jcr->job;
1401 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1402 UAContext *ua = new_ua_context(jcr);
1404 foreach_alist(runcmd, job->run_cmds) {
1405 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1406 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1407 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1408 parse_ua_args(ua); /* parse command */
1409 int stat = run_cmd(ua, ua->cmd);
1411 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1414 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1417 free_ua_context(ua);
1418 free_pool_memory(cmd);
1423 * Given: a JobId in jcr->previous_jr.JobId,
1424 * this subroutine writes a bsr file to restore that job.
1425 * Returns: -1 on error
1426 * number of files if OK
1428 int create_restore_bootstrap_file(JCR *jcr)
1434 memset(&rx, 0, sizeof(rx));
1436 rx.JobIds = (char *)"";
1437 rx.bsr->JobId = jcr->previous_jr.JobId;
1438 ua = new_ua_context(jcr);
1439 if (!complete_bsr(ua, rx.bsr)) {
1443 rx.bsr->fi = new_findex();
1444 rx.bsr->fi->findex = 1;
1445 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1446 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1447 if (jcr->ExpectedFiles == 0) {
1451 free_ua_context(ua);
1453 jcr->needs_sd = true;
1454 return jcr->ExpectedFiles;
1457 free_ua_context(ua);
1462 /* TODO: redirect command ouput to job log */
1463 bool run_console_command(JCR *jcr, const char *cmd)
1467 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1468 ua = new_ua_context(ljcr);
1469 /* run from runscript and check if commands are autorized */
1470 ua->runscript = true;
1471 Mmsg(ua->cmd, "%s", cmd);
1472 Dmsg1(100, "Console command: %s\n", ua->cmd);
1474 ok= do_a_command(ua);
1475 free_ua_context(ua);