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 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 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_maxschedruntime(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));
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(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
128 jcr->catalog->db_user,
129 jcr->catalog->db_password, jcr->catalog->db_address,
130 jcr->catalog->db_port, jcr->catalog->db_socket,
131 jcr->catalog->mult_db_connections);
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->comment = get_pool_memory(PM_MESSAGE);
144 *jcr->comment = '\0';
147 jcr->fname = get_pool_memory(PM_FNAME);
149 if (!jcr->pool_source) {
150 jcr->pool_source = get_pool_memory(PM_MESSAGE);
151 pm_strcpy(jcr->pool_source, _("unknown source"));
154 if (jcr->JobReads()) {
155 if (!jcr->rpool_source) {
156 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
157 pm_strcpy(jcr->rpool_source, _("unknown source"));
164 init_jcr_job_record(jcr);
165 if (!get_or_create_client_record(jcr)) {
169 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
170 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
173 jcr->JobId = jcr->jr.JobId;
174 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
175 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
177 generate_daemon_event(jcr, "JobStart");
178 new_plugins(jcr); /* instantiate plugins for this jcr */
179 generate_plugin_event(jcr, bEventJobStart);
181 if (job_canceled(jcr)) {
185 if (jcr->JobReads() && !jcr->rstorage) {
186 if (jcr->job->storage) {
187 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
189 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
192 if (!jcr->JobReads()) {
197 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
198 * this allows us to setup a proper job start record for restarting
199 * in case of later errors.
201 switch (jcr->getJobType()) {
203 if (!do_backup_init(jcr)) {
204 backup_cleanup(jcr, JS_ErrorTerminated);
209 if (!do_verify_init(jcr)) {
210 verify_cleanup(jcr, JS_ErrorTerminated);
215 if (!do_restore_init(jcr)) {
216 restore_cleanup(jcr, JS_ErrorTerminated);
221 if (!do_admin_init(jcr)) {
222 admin_cleanup(jcr, JS_ErrorTerminated);
228 if (!do_migration_init(jcr)) {
229 migration_cleanup(jcr, JS_ErrorTerminated);
234 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
235 jcr->setJobStatus(JS_ErrorTerminated);
239 generate_job_event(jcr, "JobInit");
240 generate_plugin_event(jcr, bEventJobInit);
248 void update_job_end(JCR *jcr, int TermCode)
250 dequeue_messages(jcr); /* display any queued messages */
251 jcr->setJobStatus(TermCode);
252 update_job_end_record(jcr);
256 * This is the engine called by jobq.c:jobq_add() when we were pulled
257 * from the work queue.
258 * At this point, we are running in our own thread and all
259 * necessary resources are allocated -- see jobq.c
261 static void *job_thread(void *arg)
263 JCR *jcr = (JCR *)arg;
265 pthread_detach(pthread_self());
268 Dmsg0(200, "=====Start Job=========\n");
269 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
270 jcr->start_time = time(NULL); /* set the real start time */
271 jcr->jr.StartTime = jcr->start_time;
273 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
274 (utime_t)(jcr->start_time - jcr->sched_time)) {
275 jcr->setJobStatus(JS_Canceled);
276 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
279 if (job_check_maxschedruntime(jcr)) {
280 jcr->setJobStatus(JS_Canceled);
281 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
284 /* TODO : check if it is used somewhere */
285 if (jcr->job->RunScripts == NULL) {
286 Dmsg0(200, "Warning, job->RunScripts is empty\n");
287 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
290 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
291 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
294 /* Run any script BeforeJob on dird */
295 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
298 * We re-update the job start record so that the start
299 * time is set after the run before job. This avoids
300 * that any files created by the run before job will
301 * be saved twice. They will be backed up in the current
302 * job, but not in the next one unless they are changed.
303 * Without this, they will be backed up in this job and
304 * in the next job run because in that case, their date
305 * is after the start of this run.
307 jcr->start_time = time(NULL);
308 jcr->jr.StartTime = jcr->start_time;
309 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
310 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
312 generate_job_event(jcr, "JobRun");
313 generate_plugin_event(jcr, bEventJobRun);
315 switch (jcr->getJobType()) {
317 if (!job_canceled(jcr) && do_backup(jcr)) {
320 backup_cleanup(jcr, JS_ErrorTerminated);
324 if (!job_canceled(jcr) && do_verify(jcr)) {
327 verify_cleanup(jcr, JS_ErrorTerminated);
331 if (!job_canceled(jcr) && do_restore(jcr)) {
334 restore_cleanup(jcr, JS_ErrorTerminated);
338 if (!job_canceled(jcr) && do_admin(jcr)) {
341 admin_cleanup(jcr, JS_ErrorTerminated);
346 if (!job_canceled(jcr) && do_migration(jcr)) {
349 migration_cleanup(jcr, JS_ErrorTerminated);
353 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
357 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
359 /* Send off any queued messages */
360 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
361 dequeue_messages(jcr);
364 generate_daemon_event(jcr, "JobEnd");
365 generate_plugin_event(jcr, bEventJobEnd);
366 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
367 sm_check(__FILE__, __LINE__, true);
373 * Cancel a job -- typically called by the UA (Console program), but may also
374 * be called by the job watchdog.
376 * Returns: true if cancel appears to be successful
377 * false on failure. Message sent to ua->jcr.
379 bool cancel_job(UAContext *ua, JCR *jcr)
383 int32_t old_status = jcr->JobStatus;
385 jcr->setJobStatus(JS_Canceled);
387 switch (old_status) {
390 case JS_WaitClientRes:
391 case JS_WaitStoreRes:
392 case JS_WaitPriority:
394 case JS_WaitStartTime:
395 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
396 edit_uint64(jcr->JobId, ed1), jcr->Job);
397 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
401 /* Cancel File daemon */
402 if (jcr->file_bsock) {
403 ua->jcr->client = jcr->client;
404 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
405 ua->error_msg(_("Failed to connect to File daemon.\n"));
408 Dmsg0(200, "Connected to file daemon\n");
409 fd = ua->jcr->file_bsock;
410 fd->fsend("cancel Job=%s\n", jcr->Job);
411 while (fd->recv() >= 0) {
412 ua->send_msg("%s", fd->msg);
414 fd->signal(BNET_TERMINATE);
416 ua->jcr->file_bsock = NULL;
417 jcr->file_bsock->set_terminated();
418 if (jcr->my_thread_id) {
419 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
420 Dmsg1(800, "Send kill to jid=%d\n", jcr->JobId);
424 /* Cancel Storage daemon */
425 if (jcr->store_bsock) {
426 if (!ua->jcr->wstorage) {
428 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
430 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
435 store.store = jcr->rstore;
437 store.store = jcr->wstore;
439 set_wstorage(ua->jcr, &store);
442 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
443 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
446 Dmsg0(200, "Connected to storage daemon\n");
447 sd = ua->jcr->store_bsock;
448 sd->fsend("cancel Job=%s\n", jcr->Job);
449 while (sd->recv() >= 0) {
450 ua->send_msg("%s", sd->msg);
452 sd->signal(BNET_TERMINATE);
454 ua->jcr->store_bsock = NULL;
455 jcr->store_bsock->set_timed_out();
456 jcr->store_bsock->set_terminated();
457 if (jcr->SD_msg_chan) {
458 Dmsg2(400, "kill jobid=%d use=%d\n", (int)jcr->JobId, jcr->use_count());
459 pthread_kill(jcr->SD_msg_chan, TIMEOUT_SIGNAL);
461 if (jcr->my_thread_id) {
462 pthread_kill(jcr->my_thread_id, 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 if (jcr->SD_msg_chan) {
514 Dmsg2(400, "kill jobid=%d use=%d\n", (int)jcr->JobId, jcr->use_count());
515 pthread_kill(jcr->SD_msg_chan, TIMEOUT_SIGNAL);
517 if (jcr->my_thread_id) {
518 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
522 free_jcr(control_jcr);
526 static void job_monitor_destructor(watchdog_t *self)
528 JCR *control_jcr = (JCR *)self->data;
530 free_jcr(control_jcr);
533 static void job_monitor_watchdog(watchdog_t *self)
535 JCR *control_jcr, *jcr;
537 control_jcr = (JCR *)self->data;
540 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
545 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
546 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
550 /* check MaxWaitTime */
551 if (job_check_maxwaittime(jcr)) {
552 jcr->setJobStatus(JS_Canceled);
553 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
555 /* check MaxRunTime */
556 } else if (job_check_maxruntime(jcr)) {
557 jcr->setJobStatus(JS_Canceled);
558 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
560 /* check MaxRunSchedTime */
561 } else if (job_check_maxschedruntime(jcr)) {
562 jcr->setJobStatus(JS_Canceled);
563 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
568 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
569 UAContext *ua = new_ua_context(jcr);
570 ua->jcr = control_jcr;
573 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
577 /* Keep reference counts correct */
582 * Check if the maxwaittime has expired and it is possible
585 static bool job_check_maxwaittime(JCR *jcr)
591 if (!job_waiting(jcr)) {
595 if (jcr->wait_time) {
596 current = watchdog_time - jcr->wait_time;
599 Dmsg2(200, "check maxwaittime %u >= %u\n",
600 current + jcr->wait_time_sum, job->MaxWaitTime);
601 if (job->MaxWaitTime != 0 &&
602 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
610 * Check if maxruntime has expired and if the job can be
613 static bool job_check_maxruntime(JCR *jcr)
619 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
622 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
623 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
626 run_time = watchdog_time - jcr->start_time;
627 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
628 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
629 job->IncMaxRunTime, job->DiffMaxRunTime);
631 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
632 run_time >= job->FullMaxRunTime) {
633 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
635 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
636 run_time >= job->DiffMaxRunTime) {
637 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
639 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
640 run_time >= job->IncMaxRunTime) {
641 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
643 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
644 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
652 * Check if MaxRunSchedTime has expired and if the job can be
655 static bool job_check_maxschedruntime(JCR *jcr)
657 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
660 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
661 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
662 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
670 * Get or create a Pool record with the given name.
671 * Returns: 0 on error
674 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
678 memset(&pr, 0, sizeof(pr));
679 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
680 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
682 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
683 /* Try to create the pool */
684 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
685 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
686 db_strerror(jcr->db));
689 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
696 * Check for duplicate jobs.
697 * Returns: true if current job should continue
698 * false if current job should terminate
700 bool allow_duplicate_job(JCR *jcr)
703 JCR *djcr; /* possible duplicate job */
705 if (job->AllowDuplicateJobs) {
708 Dmsg0(800, "Enter allow_duplicate_job\n");
710 * After this point, we do not want to allow any duplicate
715 if (jcr == djcr || djcr->JobId == 0) {
716 continue; /* do not cancel this job or consoles */
718 if (strcmp(job->name(), djcr->job->name()) == 0) {
719 bool cancel_dup = false;
720 bool cancel_me = false;
721 if (job->DuplicateJobProximity > 0) {
722 utime_t now = (utime_t)time(NULL);
723 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
724 continue; /* not really a duplicate */
727 if (job->CancelLowerLevelDuplicates &&
728 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
729 switch (jcr->getJobLevel()) {
731 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
732 djcr->getJobLevel() == L_INCREMENTAL) {
737 if (djcr->getJobLevel() == L_INCREMENTAL) {
740 if (djcr->getJobLevel() == L_FULL) {
745 if (djcr->getJobLevel() == L_FULL ||
746 djcr->getJobLevel() == L_DIFFERENTIAL) {
751 * cancel_dup will be done below
754 /* Zap current job */
755 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
757 break; /* get out of foreach_jcr */
760 /* Cancel one of the two jobs (me or dup) */
761 /* If CancelQueuedDuplicates is set do so only if job is queued */
762 if (job->CancelQueuedDuplicates) {
763 switch (djcr->JobStatus) {
766 case JS_WaitClientRes:
767 case JS_WaitStoreRes:
768 case JS_WaitPriority:
770 case JS_WaitStartTime:
771 cancel_dup = true; /* cancel queued duplicate */
777 if (cancel_dup || job->CancelRunningDuplicates) {
778 /* Zap the duplicated job djcr */
779 UAContext *ua = new_ua_context(jcr);
780 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
781 cancel_job(ua, djcr);
782 bmicrosleep(0, 500000);
783 cancel_job(ua, djcr);
785 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
787 /* Zap current job */
788 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
790 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
792 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
793 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
794 break; /* did our work, get out of foreach loop */
802 void apply_pool_overrides(JCR *jcr)
804 bool pool_override = false;
806 if (jcr->run_pool_override) {
807 pm_strcpy(jcr->pool_source, _("Run pool override"));
810 * Apply any level related Pool selections
812 switch (jcr->getJobLevel()) {
814 if (jcr->full_pool) {
815 jcr->pool = jcr->full_pool;
816 pool_override = true;
817 if (jcr->run_full_pool_override) {
818 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
820 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
826 jcr->pool = jcr->inc_pool;
827 pool_override = true;
828 if (jcr->run_inc_pool_override) {
829 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
831 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
836 if (jcr->diff_pool) {
837 jcr->pool = jcr->diff_pool;
838 pool_override = true;
839 if (jcr->run_diff_pool_override) {
840 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
842 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
847 /* Update catalog if pool overridden */
848 if (pool_override && jcr->pool->catalog) {
849 jcr->catalog = jcr->pool->catalog;
850 pm_strcpy(jcr->catalog_source, _("Pool resource"));
856 * Get or create a Client record for this Job
858 bool get_or_create_client_record(JCR *jcr)
862 memset(&cr, 0, sizeof(cr));
863 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
864 cr.AutoPrune = jcr->client->AutoPrune;
865 cr.FileRetention = jcr->client->FileRetention;
866 cr.JobRetention = jcr->client->JobRetention;
867 if (!jcr->client_name) {
868 jcr->client_name = get_pool_memory(PM_NAME);
870 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
871 if (!db_create_client_record(jcr, jcr->db, &cr)) {
872 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
873 db_strerror(jcr->db));
876 jcr->jr.ClientId = cr.ClientId;
878 if (!jcr->client_uname) {
879 jcr->client_uname = get_pool_memory(PM_NAME);
881 pm_strcpy(jcr->client_uname, cr.Uname);
883 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
888 bool get_or_create_fileset_record(JCR *jcr)
892 * Get or Create FileSet record
894 memset(&fsr, 0, sizeof(FILESET_DBR));
895 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
896 if (jcr->fileset->have_MD5) {
897 struct MD5Context md5c;
898 unsigned char digest[MD5HashSize];
899 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
900 MD5Final(digest, &md5c);
902 * Keep the flag (last arg) set to false otherwise old FileSets will
903 * get new MD5 sums and the user will get Full backups on everything
905 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
906 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
908 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
910 if (!jcr->fileset->ignore_fs_changes ||
911 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
912 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
913 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
914 fsr.FileSet, db_strerror(jcr->db));
918 jcr->jr.FileSetId = fsr.FileSetId;
919 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
920 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
925 void init_jcr_job_record(JCR *jcr)
927 jcr->jr.SchedTime = jcr->sched_time;
928 jcr->jr.StartTime = jcr->start_time;
929 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
930 jcr->jr.JobType = jcr->getJobType();
931 jcr->jr.JobLevel = jcr->getJobLevel();
932 jcr->jr.JobStatus = jcr->JobStatus;
933 jcr->jr.JobId = jcr->JobId;
934 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
935 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
939 * Write status and such in DB
941 void update_job_end_record(JCR *jcr)
943 jcr->jr.EndTime = time(NULL);
944 jcr->end_time = jcr->jr.EndTime;
945 jcr->jr.JobId = jcr->JobId;
946 jcr->jr.JobStatus = jcr->JobStatus;
947 jcr->jr.JobFiles = jcr->JobFiles;
948 jcr->jr.JobBytes = jcr->JobBytes;
949 jcr->jr.ReadBytes = jcr->ReadBytes;
950 jcr->jr.VolSessionId = jcr->VolSessionId;
951 jcr->jr.VolSessionTime = jcr->VolSessionTime;
952 jcr->jr.JobErrors = jcr->JobErrors;
953 jcr->jr.HasBase = jcr->HasBase;
954 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
955 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
956 db_strerror(jcr->db));
961 * Takes base_name and appends (unique) current
962 * date and time to form unique job name.
964 * Note, the seconds are actually a sequence number. This
965 * permits us to start a maximum fo 59 unique jobs a second, which
966 * should be sufficient.
968 * Returns: unique job name in jcr->Job
969 * date/time in jcr->start_time
971 void create_unique_job_name(JCR *jcr, const char *base_name)
973 /* Job start mutex */
974 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
975 static time_t last_start_time = 0;
977 time_t now = time(NULL);
979 char dt[MAX_TIME_LENGTH];
980 char name[MAX_NAME_LENGTH];
984 /* Guarantee unique start time -- maximum one per second, and
985 * thus unique Job Name
987 P(mutex); /* lock creation of jobs */
989 if (seq > 59) { /* wrap as if it is seconds */
991 while (now == last_start_time) {
992 bmicrosleep(0, 500000);
996 last_start_time = now;
997 V(mutex); /* allow creation of jobs */
998 jcr->start_time = now;
999 /* Form Unique JobName */
1000 (void)localtime_r(&now, &tm);
1001 /* Use only characters that are permitted in Windows filenames */
1002 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1003 len = strlen(dt) + 5; /* dt + .%02d EOS */
1004 bstrncpy(name, base_name, sizeof(name));
1005 name[sizeof(name)-len] = 0; /* truncate if too long */
1006 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
1007 /* Convert spaces into underscores */
1008 for (p=jcr->Job; *p; p++) {
1013 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1016 /* Called directly from job rescheduling */
1017 void dird_free_jcr_pointers(JCR *jcr)
1019 if (jcr->sd_auth_key) {
1020 free(jcr->sd_auth_key);
1021 jcr->sd_auth_key = NULL;
1027 if (jcr->file_bsock) {
1028 Dmsg0(200, "Close File bsock\n");
1029 bnet_close(jcr->file_bsock);
1030 jcr->file_bsock = NULL;
1032 if (jcr->store_bsock) {
1033 Dmsg0(200, "Close Store bsock\n");
1034 bnet_close(jcr->store_bsock);
1035 jcr->store_bsock = NULL;
1038 free_pool_memory(jcr->comment);
1039 jcr->comment = NULL;
1042 Dmsg0(200, "Free JCR fname\n");
1043 free_pool_memory(jcr->fname);
1046 if (jcr->RestoreBootstrap) {
1047 free(jcr->RestoreBootstrap);
1048 jcr->RestoreBootstrap = NULL;
1050 if (jcr->client_uname) {
1051 free_pool_memory(jcr->client_uname);
1052 jcr->client_uname = NULL;
1055 free_pool_memory(jcr->attr);
1065 * Free the Job Control Record if no one is still using it.
1066 * Called from main free_jcr() routine in src/lib/jcr.c so
1067 * that we can do our Director specific cleanup of the jcr.
1069 void dird_free_jcr(JCR *jcr)
1071 Dmsg0(200, "Start dird free_jcr\n");
1073 dird_free_jcr_pointers(jcr);
1074 if (jcr->term_wait_inited) {
1075 pthread_cond_destroy(&jcr->term_wait);
1076 jcr->term_wait_inited = false;
1078 if (jcr->db_batch) {
1079 db_close_database(jcr, jcr->db_batch);
1080 jcr->db_batch = NULL;
1081 jcr->batch_started = false;
1084 db_close_database(jcr, jcr->db);
1088 Dmsg0(200, "Free JCR stime\n");
1089 free_pool_memory(jcr->stime);
1093 Dmsg0(200, "Free JCR fname\n");
1094 free_pool_memory(jcr->fname);
1097 if (jcr->pool_source) {
1098 free_pool_memory(jcr->pool_source);
1099 jcr->pool_source = NULL;
1101 if (jcr->catalog_source) {
1102 free_pool_memory(jcr->catalog_source);
1103 jcr->catalog_source = NULL;
1105 if (jcr->rpool_source) {
1106 free_pool_memory(jcr->rpool_source);
1107 jcr->rpool_source = NULL;
1109 if (jcr->wstore_source) {
1110 free_pool_memory(jcr->wstore_source);
1111 jcr->wstore_source = NULL;
1113 if (jcr->rstore_source) {
1114 free_pool_memory(jcr->rstore_source);
1115 jcr->rstore_source = NULL;
1118 /* Delete lists setup to hold storage pointers */
1119 free_rwstorage(jcr);
1121 jcr->job_end_push.destroy();
1123 if (jcr->JobId != 0)
1124 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1126 free_plugins(jcr); /* release instantiated plugins */
1128 Dmsg0(200, "End dird free_jcr\n");
1132 * The Job storage definition must be either in the Job record
1133 * or in the Pool record. The Pool record overrides the Job
1136 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1138 if (run && run->pool && run->pool->storage) {
1139 store->store = (STORE *)run->pool->storage->first();
1140 pm_strcpy(store->store_source, _("Run pool override"));
1143 if (run && run->storage) {
1144 store->store = run->storage;
1145 pm_strcpy(store->store_source, _("Run storage override"));
1148 if (job->pool->storage) {
1149 store->store = (STORE *)job->pool->storage->first();
1150 pm_strcpy(store->store_source, _("Pool resource"));
1152 store->store = (STORE *)job->storage->first();
1153 pm_strcpy(store->store_source, _("Job resource"));
1158 * Set some defaults in the JCR necessary to
1159 * run. These items are pulled from the job
1160 * definition as defaults, but can be overridden
1161 * later either by the Run record in the Schedule resource,
1162 * or by the Console program.
1164 void set_jcr_defaults(JCR *jcr, JOB *job)
1167 jcr->set_JobType(job->JobType);
1168 jcr->JobStatus = JS_Created;
1170 switch (jcr->getJobType()) {
1172 jcr->set_JobLevel(L_NONE);
1175 jcr->set_JobLevel(job->JobLevel);
1180 jcr->fname = get_pool_memory(PM_FNAME);
1182 if (!jcr->pool_source) {
1183 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1184 pm_strcpy(jcr->pool_source, _("unknown source"));
1186 if (!jcr->catalog_source) {
1187 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1188 pm_strcpy(jcr->catalog_source, _("unknown source"));
1191 jcr->JobPriority = job->Priority;
1192 /* Copy storage definitions -- deleted in dir_free_jcr above */
1194 copy_rwstorage(jcr, job->storage, _("Job resource"));
1196 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1198 jcr->client = job->client;
1199 if (!jcr->client_name) {
1200 jcr->client_name = get_pool_memory(PM_NAME);
1202 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1203 pm_strcpy(jcr->pool_source, _("Job resource"));
1204 jcr->pool = job->pool;
1205 jcr->full_pool = job->full_pool;
1206 jcr->inc_pool = job->inc_pool;
1207 jcr->diff_pool = job->diff_pool;
1208 if (job->pool->catalog) {
1209 jcr->catalog = job->pool->catalog;
1210 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1212 jcr->catalog = job->client->catalog;
1213 pm_strcpy(jcr->catalog_source, _("Client resource"));
1215 jcr->fileset = job->fileset;
1216 jcr->messages = job->messages;
1217 jcr->spool_data = job->spool_data;
1218 jcr->spool_size = job->spool_size;
1219 jcr->write_part_after_job = job->write_part_after_job;
1220 jcr->accurate = job->accurate;
1221 if (jcr->RestoreBootstrap) {
1222 free(jcr->RestoreBootstrap);
1223 jcr->RestoreBootstrap = NULL;
1225 /* This can be overridden by Console program */
1226 if (job->RestoreBootstrap) {
1227 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1229 /* This can be overridden by Console program */
1230 jcr->verify_job = job->verify_job;
1231 /* If no default level given, set one */
1232 if (jcr->getJobLevel() == 0) {
1233 switch (jcr->getJobType()) {
1235 jcr->set_JobLevel(L_VERIFY_CATALOG);
1238 jcr->set_JobLevel(L_INCREMENTAL);
1242 jcr->set_JobLevel(L_NONE);
1245 jcr->set_JobLevel(L_FULL);
1252 * Copy the storage definitions from an alist to the JCR
1254 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1256 if (jcr->JobReads()) {
1257 copy_rstorage(jcr, storage, where);
1259 copy_wstorage(jcr, storage, where);
1263 /* Set storage override. Releases any previous storage definition */
1264 void set_rwstorage(JCR *jcr, USTORE *store)
1267 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1270 if (jcr->JobReads()) {
1271 set_rstorage(jcr, store);
1273 set_wstorage(jcr, store);
1276 void free_rwstorage(JCR *jcr)
1283 * Copy the storage definitions from an alist to the JCR
1285 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1289 if (jcr->rstorage) {
1290 delete jcr->rstorage;
1292 jcr->rstorage = New(alist(10, not_owned_by_alist));
1293 foreach_alist(st, storage) {
1294 jcr->rstorage->append(st);
1296 if (!jcr->rstore_source) {
1297 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1299 pm_strcpy(jcr->rstore_source, where);
1300 if (jcr->rstorage) {
1301 jcr->rstore = (STORE *)jcr->rstorage->first();
1307 /* Set storage override. Remove all previous storage */
1308 void set_rstorage(JCR *jcr, USTORE *store)
1312 if (!store->store) {
1315 if (jcr->rstorage) {
1318 if (!jcr->rstorage) {
1319 jcr->rstorage = New(alist(10, not_owned_by_alist));
1321 jcr->rstore = store->store;
1322 if (!jcr->rstore_source) {
1323 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1325 pm_strcpy(jcr->rstore_source, store->store_source);
1326 foreach_alist(storage, jcr->rstorage) {
1327 if (store->store == storage) {
1331 /* Store not in list, so add it */
1332 jcr->rstorage->prepend(store->store);
1335 void free_rstorage(JCR *jcr)
1337 if (jcr->rstorage) {
1338 delete jcr->rstorage;
1339 jcr->rstorage = NULL;
1345 * Copy the storage definitions from an alist to the JCR
1347 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1351 if (jcr->wstorage) {
1352 delete jcr->wstorage;
1354 jcr->wstorage = New(alist(10, not_owned_by_alist));
1355 foreach_alist(st, storage) {
1356 Dmsg1(100, "wstorage=%s\n", st->name());
1357 jcr->wstorage->append(st);
1359 if (!jcr->wstore_source) {
1360 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1362 pm_strcpy(jcr->wstore_source, where);
1363 if (jcr->wstorage) {
1364 jcr->wstore = (STORE *)jcr->wstorage->first();
1365 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1371 /* Set storage override. Remove all previous storage */
1372 void set_wstorage(JCR *jcr, USTORE *store)
1376 if (!store->store) {
1379 if (jcr->wstorage) {
1382 if (!jcr->wstorage) {
1383 jcr->wstorage = New(alist(10, not_owned_by_alist));
1385 jcr->wstore = store->store;
1386 if (!jcr->wstore_source) {
1387 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1389 pm_strcpy(jcr->wstore_source, store->store_source);
1390 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1391 foreach_alist(storage, jcr->wstorage) {
1392 if (store->store == storage) {
1396 /* Store not in list, so add it */
1397 jcr->wstorage->prepend(store->store);
1400 void free_wstorage(JCR *jcr)
1402 if (jcr->wstorage) {
1403 delete jcr->wstorage;
1404 jcr->wstorage = NULL;
1409 char *job_code_callback_clones(JCR *jcr, const char* param)
1411 if (param[0] == 'p') {
1412 return jcr->pool->name();
1417 void create_clones(JCR *jcr)
1420 * Fire off any clone jobs (run directives)
1422 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1423 if (!jcr->cloned && jcr->job->run_cmds) {
1425 JOB *job = jcr->job;
1426 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1427 UAContext *ua = new_ua_context(jcr);
1429 foreach_alist(runcmd, job->run_cmds) {
1430 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1431 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1432 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1433 parse_ua_args(ua); /* parse command */
1434 int stat = run_cmd(ua, ua->cmd);
1436 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1439 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1442 free_ua_context(ua);
1443 free_pool_memory(cmd);
1448 * Given: a JobId in jcr->previous_jr.JobId,
1449 * this subroutine writes a bsr file to restore that job.
1450 * Returns: -1 on error
1451 * number of files if OK
1453 int create_restore_bootstrap_file(JCR *jcr)
1459 memset(&rx, 0, sizeof(rx));
1461 rx.JobIds = (char *)"";
1462 rx.bsr->JobId = jcr->previous_jr.JobId;
1463 ua = new_ua_context(jcr);
1464 if (!complete_bsr(ua, rx.bsr)) {
1468 rx.bsr->fi = new_findex();
1469 rx.bsr->fi->findex = 1;
1470 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1471 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1472 if (jcr->ExpectedFiles == 0) {
1476 free_ua_context(ua);
1478 jcr->needs_sd = true;
1479 return jcr->ExpectedFiles;
1482 free_ua_context(ua);
1487 /* TODO: redirect command ouput to job log */
1488 bool run_console_command(JCR *jcr, const char *cmd)
1492 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1493 ua = new_ua_context(ljcr);
1494 /* run from runscript and check if commands are autorized */
1495 ua->runscript = true;
1496 Mmsg(ua->cmd, "%s", cmd);
1497 Dmsg1(100, "Console command: %s\n", ua->cmd);
1499 ok= do_a_command(ua);
1500 free_ua_context(ua);