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->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_maxschedruntime(jcr)) {
276 jcr->setJobStatus(JS_Canceled);
277 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run 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);
363 sm_check(__FILE__, __LINE__, true);
369 * Cancel a job -- typically called by the UA (Console program), but may also
370 * be called by the job watchdog.
372 * Returns: true if cancel appears to be successful
373 * false on failure. Message sent to ua->jcr.
375 bool cancel_job(UAContext *ua, JCR *jcr)
379 int32_t old_status = jcr->JobStatus;
381 jcr->setJobStatus(JS_Canceled);
383 switch (old_status) {
386 case JS_WaitClientRes:
387 case JS_WaitStoreRes:
388 case JS_WaitPriority:
390 case JS_WaitStartTime:
391 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
392 edit_uint64(jcr->JobId, ed1), jcr->Job);
393 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
397 /* Cancel File daemon */
398 if (jcr->file_bsock) {
399 ua->jcr->client = jcr->client;
400 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
401 ua->error_msg(_("Failed to connect to File daemon.\n"));
404 Dmsg0(200, "Connected to file daemon\n");
405 fd = ua->jcr->file_bsock;
406 fd->fsend("cancel Job=%s\n", jcr->Job);
407 while (fd->recv() >= 0) {
408 ua->send_msg("%s", fd->msg);
410 fd->signal(BNET_TERMINATE);
412 ua->jcr->file_bsock = NULL;
413 jcr->file_bsock->set_terminated();
414 if (jcr->my_thread_id) {
415 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
416 Dmsg1(800, "Send kill to jid=%d\n", jcr->JobId);
420 /* Cancel Storage daemon */
421 if (jcr->store_bsock) {
422 if (!ua->jcr->wstorage) {
424 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
426 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
431 store.store = jcr->rstore;
433 store.store = jcr->wstore;
435 set_wstorage(ua->jcr, &store);
438 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
439 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
442 Dmsg0(200, "Connected to storage daemon\n");
443 sd = ua->jcr->store_bsock;
444 sd->fsend("cancel Job=%s\n", jcr->Job);
445 while (sd->recv() >= 0) {
446 ua->send_msg("%s", sd->msg);
448 sd->signal(BNET_TERMINATE);
450 ua->jcr->store_bsock = NULL;
451 jcr->store_bsock->set_timed_out();
452 jcr->store_bsock->set_terminated();
453 if (jcr->SD_msg_chan) {
454 Dmsg2(400, "kill jobid=%d use=%d\n", (int)jcr->JobId, jcr->use_count());
455 pthread_kill(jcr->SD_msg_chan, TIMEOUT_SIGNAL);
457 if (jcr->my_thread_id) {
458 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
467 void cancel_storage_daemon_job(JCR *jcr)
469 if (jcr->sd_canceled) {
470 return; /* cancel only once */
473 UAContext *ua = new_ua_context(jcr);
474 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
477 ua->jcr = control_jcr;
478 if (jcr->store_bsock) {
479 if (!ua->jcr->wstorage) {
481 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
483 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
488 store.store = jcr->rstore;
490 store.store = jcr->wstore;
492 set_wstorage(ua->jcr, &store);
495 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
498 Dmsg0(200, "Connected to storage daemon\n");
499 sd = ua->jcr->store_bsock;
500 sd->fsend("cancel Job=%s\n", jcr->Job);
501 while (sd->recv() >= 0) {
503 sd->signal(BNET_TERMINATE);
505 ua->jcr->store_bsock = NULL;
506 jcr->sd_canceled = true;
507 jcr->store_bsock->set_timed_out();
508 jcr->store_bsock->set_terminated();
509 if (jcr->SD_msg_chan) {
510 Dmsg2(400, "kill jobid=%d use=%d\n", (int)jcr->JobId, jcr->use_count());
511 pthread_kill(jcr->SD_msg_chan, TIMEOUT_SIGNAL);
513 if (jcr->my_thread_id) {
514 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
518 free_jcr(control_jcr);
522 static void job_monitor_destructor(watchdog_t *self)
524 JCR *control_jcr = (JCR *)self->data;
526 free_jcr(control_jcr);
529 static void job_monitor_watchdog(watchdog_t *self)
531 JCR *control_jcr, *jcr;
533 control_jcr = (JCR *)self->data;
536 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
541 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
542 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
546 /* check MaxWaitTime */
547 if (job_check_maxwaittime(jcr)) {
548 jcr->setJobStatus(JS_Canceled);
549 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
551 /* check MaxRunTime */
552 } else if (job_check_maxruntime(jcr)) {
553 jcr->setJobStatus(JS_Canceled);
554 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
556 /* check MaxRunSchedTime */
557 } else if (job_check_maxschedruntime(jcr)) {
558 jcr->setJobStatus(JS_Canceled);
559 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
564 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
565 UAContext *ua = new_ua_context(jcr);
566 ua->jcr = control_jcr;
569 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
573 /* Keep reference counts correct */
578 * Check if the maxwaittime has expired and it is possible
581 static bool job_check_maxwaittime(JCR *jcr)
587 if (!job_waiting(jcr)) {
591 if (jcr->wait_time) {
592 current = watchdog_time - jcr->wait_time;
595 Dmsg2(200, "check maxwaittime %u >= %u\n",
596 current + jcr->wait_time_sum, job->MaxWaitTime);
597 if (job->MaxWaitTime != 0 &&
598 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
606 * Check if maxruntime has expired and if the job can be
609 static bool job_check_maxruntime(JCR *jcr)
615 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
618 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
619 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
622 run_time = watchdog_time - jcr->start_time;
623 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
624 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
625 job->IncMaxRunTime, job->DiffMaxRunTime);
627 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
628 run_time >= job->FullMaxRunTime) {
629 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
631 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
632 run_time >= job->DiffMaxRunTime) {
633 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
635 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
636 run_time >= job->IncMaxRunTime) {
637 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
639 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
640 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
648 * Check if MaxRunSchedTime has expired and if the job can be
651 static bool job_check_maxschedruntime(JCR *jcr)
653 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
656 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
657 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
658 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
666 * Get or create a Pool record with the given name.
667 * Returns: 0 on error
670 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
674 memset(&pr, 0, sizeof(pr));
675 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
676 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
678 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
679 /* Try to create the pool */
680 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
681 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
682 db_strerror(jcr->db));
685 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
692 * Check for duplicate jobs.
693 * Returns: true if current job should continue
694 * false if current job should terminate
696 bool allow_duplicate_job(JCR *jcr)
699 JCR *djcr; /* possible duplicate job */
701 if (job->AllowDuplicateJobs) {
704 Dmsg0(800, "Enter allow_duplicate_job\n");
706 * After this point, we do not want to allow any duplicate
711 if (jcr == djcr || djcr->JobId == 0) {
712 continue; /* do not cancel this job or consoles */
714 if (strcmp(job->name(), djcr->job->name()) == 0) {
715 bool cancel_dup = false;
716 bool cancel_me = false;
717 if (job->DuplicateJobProximity > 0) {
718 utime_t now = (utime_t)time(NULL);
719 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
720 continue; /* not really a duplicate */
723 if (job->CancelLowerLevelDuplicates &&
724 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
725 switch (jcr->getJobLevel()) {
727 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
728 djcr->getJobLevel() == L_INCREMENTAL) {
733 if (djcr->getJobLevel() == L_INCREMENTAL) {
736 if (djcr->getJobLevel() == L_FULL) {
741 if (djcr->getJobLevel() == L_FULL ||
742 djcr->getJobLevel() == L_DIFFERENTIAL) {
747 * cancel_dup will be done below
750 /* Zap current job */
751 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
753 break; /* get out of foreach_jcr */
756 /* Cancel one of the two jobs (me or dup) */
757 /* If CancelQueuedDuplicates is set do so only if job is queued */
758 if (job->CancelQueuedDuplicates) {
759 switch (djcr->JobStatus) {
762 case JS_WaitClientRes:
763 case JS_WaitStoreRes:
764 case JS_WaitPriority:
766 case JS_WaitStartTime:
767 cancel_dup = true; /* cancel queued duplicate */
773 if (cancel_dup || job->CancelRunningDuplicates) {
774 /* Zap the duplicated job djcr */
775 UAContext *ua = new_ua_context(jcr);
776 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
777 cancel_job(ua, djcr);
778 bmicrosleep(0, 500000);
779 cancel_job(ua, djcr);
781 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
783 /* Zap current job */
784 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
786 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
788 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
789 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
790 break; /* did our work, get out of foreach loop */
798 void apply_pool_overrides(JCR *jcr)
800 bool pool_override = false;
802 if (jcr->run_pool_override) {
803 pm_strcpy(jcr->pool_source, _("Run pool override"));
806 * Apply any level related Pool selections
808 switch (jcr->getJobLevel()) {
810 if (jcr->full_pool) {
811 jcr->pool = jcr->full_pool;
812 pool_override = true;
813 if (jcr->run_full_pool_override) {
814 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
816 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
822 jcr->pool = jcr->inc_pool;
823 pool_override = true;
824 if (jcr->run_inc_pool_override) {
825 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
827 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
832 if (jcr->diff_pool) {
833 jcr->pool = jcr->diff_pool;
834 pool_override = true;
835 if (jcr->run_diff_pool_override) {
836 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
838 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
843 /* Update catalog if pool overridden */
844 if (pool_override && jcr->pool->catalog) {
845 jcr->catalog = jcr->pool->catalog;
846 pm_strcpy(jcr->catalog_source, _("Pool resource"));
852 * Get or create a Client record for this Job
854 bool get_or_create_client_record(JCR *jcr)
858 memset(&cr, 0, sizeof(cr));
859 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
860 cr.AutoPrune = jcr->client->AutoPrune;
861 cr.FileRetention = jcr->client->FileRetention;
862 cr.JobRetention = jcr->client->JobRetention;
863 if (!jcr->client_name) {
864 jcr->client_name = get_pool_memory(PM_NAME);
866 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
867 if (!db_create_client_record(jcr, jcr->db, &cr)) {
868 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
869 db_strerror(jcr->db));
872 jcr->jr.ClientId = cr.ClientId;
874 if (!jcr->client_uname) {
875 jcr->client_uname = get_pool_memory(PM_NAME);
877 pm_strcpy(jcr->client_uname, cr.Uname);
879 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
884 bool get_or_create_fileset_record(JCR *jcr)
888 * Get or Create FileSet record
890 memset(&fsr, 0, sizeof(FILESET_DBR));
891 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
892 if (jcr->fileset->have_MD5) {
893 struct MD5Context md5c;
894 unsigned char digest[MD5HashSize];
895 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
896 MD5Final(digest, &md5c);
898 * Keep the flag (last arg) set to false otherwise old FileSets will
899 * get new MD5 sums and the user will get Full backups on everything
901 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
902 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
904 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
906 if (!jcr->fileset->ignore_fs_changes ||
907 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
908 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
909 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
910 fsr.FileSet, db_strerror(jcr->db));
914 jcr->jr.FileSetId = fsr.FileSetId;
915 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
916 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
921 void init_jcr_job_record(JCR *jcr)
923 jcr->jr.SchedTime = jcr->sched_time;
924 jcr->jr.StartTime = jcr->start_time;
925 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
926 jcr->jr.JobType = jcr->getJobType();
927 jcr->jr.JobLevel = jcr->getJobLevel();
928 jcr->jr.JobStatus = jcr->JobStatus;
929 jcr->jr.JobId = jcr->JobId;
930 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
931 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
935 * Write status and such in DB
937 void update_job_end_record(JCR *jcr)
939 jcr->jr.EndTime = time(NULL);
940 jcr->end_time = jcr->jr.EndTime;
941 jcr->jr.JobId = jcr->JobId;
942 jcr->jr.JobStatus = jcr->JobStatus;
943 jcr->jr.JobFiles = jcr->JobFiles;
944 jcr->jr.JobBytes = jcr->JobBytes;
945 jcr->jr.ReadBytes = jcr->ReadBytes;
946 jcr->jr.VolSessionId = jcr->VolSessionId;
947 jcr->jr.VolSessionTime = jcr->VolSessionTime;
948 jcr->jr.JobErrors = jcr->JobErrors;
949 jcr->jr.HasBase = jcr->HasBase;
950 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
951 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
952 db_strerror(jcr->db));
957 * Takes base_name and appends (unique) current
958 * date and time to form unique job name.
960 * Note, the seconds are actually a sequence number. This
961 * permits us to start a maximum fo 59 unique jobs a second, which
962 * should be sufficient.
964 * Returns: unique job name in jcr->Job
965 * date/time in jcr->start_time
967 void create_unique_job_name(JCR *jcr, const char *base_name)
969 /* Job start mutex */
970 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
971 static time_t last_start_time = 0;
973 time_t now = time(NULL);
975 char dt[MAX_TIME_LENGTH];
976 char name[MAX_NAME_LENGTH];
980 /* Guarantee unique start time -- maximum one per second, and
981 * thus unique Job Name
983 P(mutex); /* lock creation of jobs */
985 if (seq > 59) { /* wrap as if it is seconds */
987 while (now == last_start_time) {
988 bmicrosleep(0, 500000);
992 last_start_time = now;
993 V(mutex); /* allow creation of jobs */
994 jcr->start_time = now;
995 /* Form Unique JobName */
996 (void)localtime_r(&now, &tm);
997 /* Use only characters that are permitted in Windows filenames */
998 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
999 len = strlen(dt) + 5; /* dt + .%02d EOS */
1000 bstrncpy(name, base_name, sizeof(name));
1001 name[sizeof(name)-len] = 0; /* truncate if too long */
1002 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
1003 /* Convert spaces into underscores */
1004 for (p=jcr->Job; *p; p++) {
1009 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1012 /* Called directly from job rescheduling */
1013 void dird_free_jcr_pointers(JCR *jcr)
1015 if (jcr->sd_auth_key) {
1016 free(jcr->sd_auth_key);
1017 jcr->sd_auth_key = NULL;
1023 if (jcr->file_bsock) {
1024 Dmsg0(200, "Close File bsock\n");
1025 bnet_close(jcr->file_bsock);
1026 jcr->file_bsock = NULL;
1028 if (jcr->store_bsock) {
1029 Dmsg0(200, "Close Store bsock\n");
1030 bnet_close(jcr->store_bsock);
1031 jcr->store_bsock = NULL;
1034 Dmsg0(200, "Free JCR fname\n");
1035 free_pool_memory(jcr->fname);
1038 if (jcr->RestoreBootstrap) {
1039 free(jcr->RestoreBootstrap);
1040 jcr->RestoreBootstrap = NULL;
1042 if (jcr->client_uname) {
1043 free_pool_memory(jcr->client_uname);
1044 jcr->client_uname = NULL;
1047 free_pool_memory(jcr->attr);
1057 * Free the Job Control Record if no one is still using it.
1058 * Called from main free_jcr() routine in src/lib/jcr.c so
1059 * that we can do our Director specific cleanup of the jcr.
1061 void dird_free_jcr(JCR *jcr)
1063 Dmsg0(200, "Start dird free_jcr\n");
1065 dird_free_jcr_pointers(jcr);
1066 if (jcr->term_wait_inited) {
1067 pthread_cond_destroy(&jcr->term_wait);
1068 jcr->term_wait_inited = false;
1070 if (jcr->db_batch) {
1071 db_close_database(jcr, jcr->db_batch);
1072 jcr->db_batch = NULL;
1073 jcr->batch_started = false;
1076 db_close_database(jcr, jcr->db);
1080 Dmsg0(200, "Free JCR stime\n");
1081 free_pool_memory(jcr->stime);
1085 Dmsg0(200, "Free JCR fname\n");
1086 free_pool_memory(jcr->fname);
1089 if (jcr->pool_source) {
1090 free_pool_memory(jcr->pool_source);
1091 jcr->pool_source = NULL;
1093 if (jcr->catalog_source) {
1094 free_pool_memory(jcr->catalog_source);
1095 jcr->catalog_source = NULL;
1097 if (jcr->rpool_source) {
1098 free_pool_memory(jcr->rpool_source);
1099 jcr->rpool_source = NULL;
1101 if (jcr->wstore_source) {
1102 free_pool_memory(jcr->wstore_source);
1103 jcr->wstore_source = NULL;
1105 if (jcr->rstore_source) {
1106 free_pool_memory(jcr->rstore_source);
1107 jcr->rstore_source = NULL;
1110 /* Delete lists setup to hold storage pointers */
1111 free_rwstorage(jcr);
1113 jcr->job_end_push.destroy();
1115 if (jcr->JobId != 0)
1116 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1118 free_plugins(jcr); /* release instantiated plugins */
1120 Dmsg0(200, "End dird free_jcr\n");
1124 * The Job storage definition must be either in the Job record
1125 * or in the Pool record. The Pool record overrides the Job
1128 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1130 if (run && run->pool && run->pool->storage) {
1131 store->store = (STORE *)run->pool->storage->first();
1132 pm_strcpy(store->store_source, _("Run pool override"));
1135 if (run && run->storage) {
1136 store->store = run->storage;
1137 pm_strcpy(store->store_source, _("Run storage override"));
1140 if (job->pool->storage) {
1141 store->store = (STORE *)job->pool->storage->first();
1142 pm_strcpy(store->store_source, _("Pool resource"));
1144 store->store = (STORE *)job->storage->first();
1145 pm_strcpy(store->store_source, _("Job resource"));
1150 * Set some defaults in the JCR necessary to
1151 * run. These items are pulled from the job
1152 * definition as defaults, but can be overridden
1153 * later either by the Run record in the Schedule resource,
1154 * or by the Console program.
1156 void set_jcr_defaults(JCR *jcr, JOB *job)
1159 jcr->set_JobType(job->JobType);
1160 jcr->JobStatus = JS_Created;
1162 switch (jcr->getJobType()) {
1164 jcr->set_JobLevel(L_NONE);
1167 jcr->set_JobLevel(job->JobLevel);
1172 jcr->fname = get_pool_memory(PM_FNAME);
1174 if (!jcr->pool_source) {
1175 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1176 pm_strcpy(jcr->pool_source, _("unknown source"));
1178 if (!jcr->catalog_source) {
1179 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1180 pm_strcpy(jcr->catalog_source, _("unknown source"));
1183 jcr->JobPriority = job->Priority;
1184 /* Copy storage definitions -- deleted in dir_free_jcr above */
1186 copy_rwstorage(jcr, job->storage, _("Job resource"));
1188 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1190 jcr->client = job->client;
1191 if (!jcr->client_name) {
1192 jcr->client_name = get_pool_memory(PM_NAME);
1194 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1195 pm_strcpy(jcr->pool_source, _("Job resource"));
1196 jcr->pool = job->pool;
1197 jcr->full_pool = job->full_pool;
1198 jcr->inc_pool = job->inc_pool;
1199 jcr->diff_pool = job->diff_pool;
1200 if (job->pool->catalog) {
1201 jcr->catalog = job->pool->catalog;
1202 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1204 jcr->catalog = job->client->catalog;
1205 pm_strcpy(jcr->catalog_source, _("Client resource"));
1207 jcr->fileset = job->fileset;
1208 jcr->messages = job->messages;
1209 jcr->spool_data = job->spool_data;
1210 jcr->spool_size = job->spool_size;
1211 jcr->write_part_after_job = job->write_part_after_job;
1212 jcr->accurate = job->accurate;
1213 if (jcr->RestoreBootstrap) {
1214 free(jcr->RestoreBootstrap);
1215 jcr->RestoreBootstrap = NULL;
1217 /* This can be overridden by Console program */
1218 if (job->RestoreBootstrap) {
1219 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1221 /* This can be overridden by Console program */
1222 jcr->verify_job = job->verify_job;
1223 /* If no default level given, set one */
1224 if (jcr->getJobLevel() == 0) {
1225 switch (jcr->getJobType()) {
1227 jcr->set_JobLevel(L_VERIFY_CATALOG);
1230 jcr->set_JobLevel(L_INCREMENTAL);
1234 jcr->set_JobLevel(L_NONE);
1237 jcr->set_JobLevel(L_FULL);
1244 * Copy the storage definitions from an alist to the JCR
1246 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1248 if (jcr->JobReads()) {
1249 copy_rstorage(jcr, storage, where);
1251 copy_wstorage(jcr, storage, where);
1255 /* Set storage override. Releases any previous storage definition */
1256 void set_rwstorage(JCR *jcr, USTORE *store)
1259 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1262 if (jcr->JobReads()) {
1263 set_rstorage(jcr, store);
1265 set_wstorage(jcr, store);
1268 void free_rwstorage(JCR *jcr)
1275 * Copy the storage definitions from an alist to the JCR
1277 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1281 if (jcr->rstorage) {
1282 delete jcr->rstorage;
1284 jcr->rstorage = New(alist(10, not_owned_by_alist));
1285 foreach_alist(st, storage) {
1286 jcr->rstorage->append(st);
1288 if (!jcr->rstore_source) {
1289 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1291 pm_strcpy(jcr->rstore_source, where);
1292 if (jcr->rstorage) {
1293 jcr->rstore = (STORE *)jcr->rstorage->first();
1299 /* Set storage override. Remove all previous storage */
1300 void set_rstorage(JCR *jcr, USTORE *store)
1304 if (!store->store) {
1307 if (jcr->rstorage) {
1310 if (!jcr->rstorage) {
1311 jcr->rstorage = New(alist(10, not_owned_by_alist));
1313 jcr->rstore = store->store;
1314 if (!jcr->rstore_source) {
1315 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1317 pm_strcpy(jcr->rstore_source, store->store_source);
1318 foreach_alist(storage, jcr->rstorage) {
1319 if (store->store == storage) {
1323 /* Store not in list, so add it */
1324 jcr->rstorage->prepend(store->store);
1327 void free_rstorage(JCR *jcr)
1329 if (jcr->rstorage) {
1330 delete jcr->rstorage;
1331 jcr->rstorage = NULL;
1337 * Copy the storage definitions from an alist to the JCR
1339 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1343 if (jcr->wstorage) {
1344 delete jcr->wstorage;
1346 jcr->wstorage = New(alist(10, not_owned_by_alist));
1347 foreach_alist(st, storage) {
1348 Dmsg1(100, "wstorage=%s\n", st->name());
1349 jcr->wstorage->append(st);
1351 if (!jcr->wstore_source) {
1352 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1354 pm_strcpy(jcr->wstore_source, where);
1355 if (jcr->wstorage) {
1356 jcr->wstore = (STORE *)jcr->wstorage->first();
1357 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1363 /* Set storage override. Remove all previous storage */
1364 void set_wstorage(JCR *jcr, USTORE *store)
1368 if (!store->store) {
1371 if (jcr->wstorage) {
1374 if (!jcr->wstorage) {
1375 jcr->wstorage = New(alist(10, not_owned_by_alist));
1377 jcr->wstore = store->store;
1378 if (!jcr->wstore_source) {
1379 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1381 pm_strcpy(jcr->wstore_source, store->store_source);
1382 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1383 foreach_alist(storage, jcr->wstorage) {
1384 if (store->store == storage) {
1388 /* Store not in list, so add it */
1389 jcr->wstorage->prepend(store->store);
1392 void free_wstorage(JCR *jcr)
1394 if (jcr->wstorage) {
1395 delete jcr->wstorage;
1396 jcr->wstorage = NULL;
1401 char *job_code_callback_clones(JCR *jcr, const char* param)
1403 if (param[0] == 'p') {
1404 return jcr->pool->name();
1409 void create_clones(JCR *jcr)
1412 * Fire off any clone jobs (run directives)
1414 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1415 if (!jcr->cloned && jcr->job->run_cmds) {
1417 JOB *job = jcr->job;
1418 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1419 UAContext *ua = new_ua_context(jcr);
1421 foreach_alist(runcmd, job->run_cmds) {
1422 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1423 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1424 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1425 parse_ua_args(ua); /* parse command */
1426 int stat = run_cmd(ua, ua->cmd);
1428 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1431 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1434 free_ua_context(ua);
1435 free_pool_memory(cmd);
1440 * Given: a JobId in jcr->previous_jr.JobId,
1441 * this subroutine writes a bsr file to restore that job.
1442 * Returns: -1 on error
1443 * number of files if OK
1445 int create_restore_bootstrap_file(JCR *jcr)
1451 memset(&rx, 0, sizeof(rx));
1453 rx.JobIds = (char *)"";
1454 rx.bsr->JobId = jcr->previous_jr.JobId;
1455 ua = new_ua_context(jcr);
1456 if (!complete_bsr(ua, rx.bsr)) {
1460 rx.bsr->fi = new_findex();
1461 rx.bsr->fi->findex = 1;
1462 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1463 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1464 if (jcr->ExpectedFiles == 0) {
1468 free_ua_context(ua);
1470 jcr->needs_sd = true;
1471 return jcr->ExpectedFiles;
1474 free_ua_context(ua);
1479 /* TODO: redirect command ouput to job log */
1480 bool run_console_command(JCR *jcr, const char *cmd)
1484 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1485 ua = new_ua_context(ljcr);
1486 /* run from runscript and check if commands are autorized */
1487 ua->runscript = true;
1488 Mmsg(ua->cmd, "%s", cmd);
1489 Dmsg1(100, "Console command: %s\n", ua->cmd);
1491 ok= do_a_command(ua);
1492 free_ua_context(ua);