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_terminated();
456 if (jcr->my_thread_id) {
457 pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
466 void cancel_storage_daemon_job(JCR *jcr)
468 if (jcr->sd_canceled) {
469 return; /* cancel only once */
472 UAContext *ua = new_ua_context(jcr);
473 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
476 ua->jcr = control_jcr;
477 if (jcr->store_bsock) {
478 if (!ua->jcr->wstorage) {
480 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
482 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
487 store.store = jcr->rstore;
489 store.store = jcr->wstore;
491 set_wstorage(ua->jcr, &store);
494 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
497 Dmsg0(200, "Connected to storage daemon\n");
498 sd = ua->jcr->store_bsock;
499 sd->fsend("cancel Job=%s\n", jcr->Job);
500 while (sd->recv() >= 0) {
502 sd->signal(BNET_TERMINATE);
504 ua->jcr->store_bsock = NULL;
505 jcr->sd_canceled = true;
508 free_jcr(control_jcr);
512 static void job_monitor_destructor(watchdog_t *self)
514 JCR *control_jcr = (JCR *)self->data;
516 free_jcr(control_jcr);
519 static void job_monitor_watchdog(watchdog_t *self)
521 JCR *control_jcr, *jcr;
523 control_jcr = (JCR *)self->data;
526 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
531 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
532 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
536 /* check MaxWaitTime */
537 if (job_check_maxwaittime(jcr)) {
538 jcr->setJobStatus(JS_Canceled);
539 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
541 /* check MaxRunTime */
542 } else if (job_check_maxruntime(jcr)) {
543 jcr->setJobStatus(JS_Canceled);
544 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
546 /* check MaxRunSchedTime */
547 } else if (job_check_maxschedruntime(jcr)) {
548 jcr->setJobStatus(JS_Canceled);
549 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
554 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
555 UAContext *ua = new_ua_context(jcr);
556 ua->jcr = control_jcr;
559 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
563 /* Keep reference counts correct */
568 * Check if the maxwaittime has expired and it is possible
571 static bool job_check_maxwaittime(JCR *jcr)
577 if (!job_waiting(jcr)) {
581 if (jcr->wait_time) {
582 current = watchdog_time - jcr->wait_time;
585 Dmsg2(200, "check maxwaittime %u >= %u\n",
586 current + jcr->wait_time_sum, job->MaxWaitTime);
587 if (job->MaxWaitTime != 0 &&
588 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
596 * Check if maxruntime has expired and if the job can be
599 static bool job_check_maxruntime(JCR *jcr)
605 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
608 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
609 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
612 run_time = watchdog_time - jcr->start_time;
613 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
614 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
615 job->IncMaxRunTime, job->DiffMaxRunTime);
617 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
618 run_time >= job->FullMaxRunTime) {
619 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
621 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
622 run_time >= job->DiffMaxRunTime) {
623 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
625 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
626 run_time >= job->IncMaxRunTime) {
627 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
629 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
630 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
638 * Check if MaxRunSchedTime has expired and if the job can be
641 static bool job_check_maxschedruntime(JCR *jcr)
643 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
646 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
647 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
648 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
656 * Get or create a Pool record with the given name.
657 * Returns: 0 on error
660 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
664 memset(&pr, 0, sizeof(pr));
665 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
666 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
668 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
669 /* Try to create the pool */
670 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
671 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
672 db_strerror(jcr->db));
675 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
682 * Check for duplicate jobs.
683 * Returns: true if current job should continue
684 * false if current job should terminate
686 bool allow_duplicate_job(JCR *jcr)
689 JCR *djcr; /* possible duplicate job */
691 if (job->AllowDuplicateJobs) {
694 Dmsg0(800, "Enter allow_duplicate_job\n");
696 * After this point, we do not want to allow any duplicate
701 if (jcr == djcr || djcr->JobId == 0) {
702 continue; /* do not cancel this job or consoles */
704 if (strcmp(job->name(), djcr->job->name()) == 0) {
705 bool cancel_dup = false;
706 bool cancel_me = false;
707 if (job->DuplicateJobProximity > 0) {
708 utime_t now = (utime_t)time(NULL);
709 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
710 continue; /* not really a duplicate */
713 if (job->CancelLowerLevelDuplicates &&
714 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
715 switch (jcr->getJobLevel()) {
717 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
718 djcr->getJobLevel() == L_INCREMENTAL) {
723 if (djcr->getJobLevel() == L_INCREMENTAL) {
726 if (djcr->getJobLevel() == L_FULL) {
731 if (djcr->getJobLevel() == L_FULL ||
732 djcr->getJobLevel() == L_DIFFERENTIAL) {
737 * cancel_dup will be done below
740 /* Zap current job */
741 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
743 break; /* get out of foreach_jcr */
746 /* Cancel one of the two jobs (me or dup) */
747 /* If CancelQueuedDuplicates is set do so only if job is queued */
748 if (job->CancelQueuedDuplicates) {
749 switch (djcr->JobStatus) {
752 case JS_WaitClientRes:
753 case JS_WaitStoreRes:
754 case JS_WaitPriority:
756 case JS_WaitStartTime:
757 cancel_dup = true; /* cancel queued duplicate */
763 if (cancel_dup || job->CancelRunningDuplicates) {
764 /* Zap the duplicated job djcr */
765 UAContext *ua = new_ua_context(jcr);
766 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
767 cancel_job(ua, djcr);
769 if (djcr->my_thread_id) {
770 pthread_kill(djcr->my_thread_id, TIMEOUT_SIGNAL);
771 Dmsg1(800, "Send kill to jid=%d\n", djcr->JobId);
773 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
775 /* Zap current job */
776 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
778 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
780 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
781 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
782 break; /* did our work, get out of foreach loop */
790 void apply_pool_overrides(JCR *jcr)
792 bool pool_override = false;
794 if (jcr->run_pool_override) {
795 pm_strcpy(jcr->pool_source, _("Run pool override"));
798 * Apply any level related Pool selections
800 switch (jcr->getJobLevel()) {
802 if (jcr->full_pool) {
803 jcr->pool = jcr->full_pool;
804 pool_override = true;
805 if (jcr->run_full_pool_override) {
806 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
808 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
814 jcr->pool = jcr->inc_pool;
815 pool_override = true;
816 if (jcr->run_inc_pool_override) {
817 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
819 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
824 if (jcr->diff_pool) {
825 jcr->pool = jcr->diff_pool;
826 pool_override = true;
827 if (jcr->run_diff_pool_override) {
828 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
830 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
835 /* Update catalog if pool overridden */
836 if (pool_override && jcr->pool->catalog) {
837 jcr->catalog = jcr->pool->catalog;
838 pm_strcpy(jcr->catalog_source, _("Pool resource"));
844 * Get or create a Client record for this Job
846 bool get_or_create_client_record(JCR *jcr)
850 memset(&cr, 0, sizeof(cr));
851 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
852 cr.AutoPrune = jcr->client->AutoPrune;
853 cr.FileRetention = jcr->client->FileRetention;
854 cr.JobRetention = jcr->client->JobRetention;
855 if (!jcr->client_name) {
856 jcr->client_name = get_pool_memory(PM_NAME);
858 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
859 if (!db_create_client_record(jcr, jcr->db, &cr)) {
860 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
861 db_strerror(jcr->db));
864 jcr->jr.ClientId = cr.ClientId;
866 if (!jcr->client_uname) {
867 jcr->client_uname = get_pool_memory(PM_NAME);
869 pm_strcpy(jcr->client_uname, cr.Uname);
871 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
876 bool get_or_create_fileset_record(JCR *jcr)
880 * Get or Create FileSet record
882 memset(&fsr, 0, sizeof(FILESET_DBR));
883 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
884 if (jcr->fileset->have_MD5) {
885 struct MD5Context md5c;
886 unsigned char digest[MD5HashSize];
887 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
888 MD5Final(digest, &md5c);
890 * Keep the flag (last arg) set to false otherwise old FileSets will
891 * get new MD5 sums and the user will get Full backups on everything
893 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
894 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
896 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
898 if (!jcr->fileset->ignore_fs_changes ||
899 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
900 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
901 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
902 fsr.FileSet, db_strerror(jcr->db));
906 jcr->jr.FileSetId = fsr.FileSetId;
907 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
908 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
913 void init_jcr_job_record(JCR *jcr)
915 jcr->jr.SchedTime = jcr->sched_time;
916 jcr->jr.StartTime = jcr->start_time;
917 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
918 jcr->jr.JobType = jcr->getJobType();
919 jcr->jr.JobLevel = jcr->getJobLevel();
920 jcr->jr.JobStatus = jcr->JobStatus;
921 jcr->jr.JobId = jcr->JobId;
922 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
923 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
927 * Write status and such in DB
929 void update_job_end_record(JCR *jcr)
931 jcr->jr.EndTime = time(NULL);
932 jcr->end_time = jcr->jr.EndTime;
933 jcr->jr.JobId = jcr->JobId;
934 jcr->jr.JobStatus = jcr->JobStatus;
935 jcr->jr.JobFiles = jcr->JobFiles;
936 jcr->jr.JobBytes = jcr->JobBytes;
937 jcr->jr.ReadBytes = jcr->ReadBytes;
938 jcr->jr.VolSessionId = jcr->VolSessionId;
939 jcr->jr.VolSessionTime = jcr->VolSessionTime;
940 jcr->jr.JobErrors = jcr->JobErrors;
941 jcr->jr.HasBase = jcr->HasBase;
942 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
943 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
944 db_strerror(jcr->db));
949 * Takes base_name and appends (unique) current
950 * date and time to form unique job name.
952 * Note, the seconds are actually a sequence number. This
953 * permits us to start a maximum fo 59 unique jobs a second, which
954 * should be sufficient.
956 * Returns: unique job name in jcr->Job
957 * date/time in jcr->start_time
959 void create_unique_job_name(JCR *jcr, const char *base_name)
961 /* Job start mutex */
962 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
963 static time_t last_start_time = 0;
965 time_t now = time(NULL);
967 char dt[MAX_TIME_LENGTH];
968 char name[MAX_NAME_LENGTH];
972 /* Guarantee unique start time -- maximum one per second, and
973 * thus unique Job Name
975 P(mutex); /* lock creation of jobs */
977 if (seq > 59) { /* wrap as if it is seconds */
979 while (now == last_start_time) {
980 bmicrosleep(0, 500000);
984 last_start_time = now;
985 V(mutex); /* allow creation of jobs */
986 jcr->start_time = now;
987 /* Form Unique JobName */
988 (void)localtime_r(&now, &tm);
989 /* Use only characters that are permitted in Windows filenames */
990 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
991 len = strlen(dt) + 5; /* dt + .%02d EOS */
992 bstrncpy(name, base_name, sizeof(name));
993 name[sizeof(name)-len] = 0; /* truncate if too long */
994 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
995 /* Convert spaces into underscores */
996 for (p=jcr->Job; *p; p++) {
1001 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1004 /* Called directly from job rescheduling */
1005 void dird_free_jcr_pointers(JCR *jcr)
1007 if (jcr->sd_auth_key) {
1008 free(jcr->sd_auth_key);
1009 jcr->sd_auth_key = NULL;
1015 if (jcr->file_bsock) {
1016 Dmsg0(200, "Close File bsock\n");
1017 bnet_close(jcr->file_bsock);
1018 jcr->file_bsock = NULL;
1020 if (jcr->store_bsock) {
1021 Dmsg0(200, "Close Store bsock\n");
1022 bnet_close(jcr->store_bsock);
1023 jcr->store_bsock = NULL;
1026 free_pool_memory(jcr->comment);
1027 jcr->comment = NULL;
1030 Dmsg0(200, "Free JCR fname\n");
1031 free_pool_memory(jcr->fname);
1034 if (jcr->RestoreBootstrap) {
1035 free(jcr->RestoreBootstrap);
1036 jcr->RestoreBootstrap = NULL;
1038 if (jcr->client_uname) {
1039 free_pool_memory(jcr->client_uname);
1040 jcr->client_uname = NULL;
1043 free_pool_memory(jcr->attr);
1053 * Free the Job Control Record if no one is still using it.
1054 * Called from main free_jcr() routine in src/lib/jcr.c so
1055 * that we can do our Director specific cleanup of the jcr.
1057 void dird_free_jcr(JCR *jcr)
1059 Dmsg0(200, "Start dird free_jcr\n");
1061 dird_free_jcr_pointers(jcr);
1062 if (jcr->term_wait_inited) {
1063 pthread_cond_destroy(&jcr->term_wait);
1064 jcr->term_wait_inited = false;
1066 if (jcr->db_batch) {
1067 db_close_database(jcr, jcr->db_batch);
1068 jcr->db_batch = NULL;
1069 jcr->batch_started = false;
1072 db_close_database(jcr, jcr->db);
1076 Dmsg0(200, "Free JCR stime\n");
1077 free_pool_memory(jcr->stime);
1081 Dmsg0(200, "Free JCR fname\n");
1082 free_pool_memory(jcr->fname);
1085 if (jcr->pool_source) {
1086 free_pool_memory(jcr->pool_source);
1087 jcr->pool_source = NULL;
1089 if (jcr->catalog_source) {
1090 free_pool_memory(jcr->catalog_source);
1091 jcr->catalog_source = NULL;
1093 if (jcr->rpool_source) {
1094 free_pool_memory(jcr->rpool_source);
1095 jcr->rpool_source = NULL;
1097 if (jcr->wstore_source) {
1098 free_pool_memory(jcr->wstore_source);
1099 jcr->wstore_source = NULL;
1101 if (jcr->rstore_source) {
1102 free_pool_memory(jcr->rstore_source);
1103 jcr->rstore_source = NULL;
1106 /* Delete lists setup to hold storage pointers */
1107 free_rwstorage(jcr);
1109 jcr->job_end_push.destroy();
1111 if (jcr->JobId != 0)
1112 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1114 free_plugins(jcr); /* release instantiated plugins */
1116 Dmsg0(200, "End dird free_jcr\n");
1120 * The Job storage definition must be either in the Job record
1121 * or in the Pool record. The Pool record overrides the Job
1124 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1126 if (run && run->pool && run->pool->storage) {
1127 store->store = (STORE *)run->pool->storage->first();
1128 pm_strcpy(store->store_source, _("Run pool override"));
1131 if (run && run->storage) {
1132 store->store = run->storage;
1133 pm_strcpy(store->store_source, _("Run storage override"));
1136 if (job->pool->storage) {
1137 store->store = (STORE *)job->pool->storage->first();
1138 pm_strcpy(store->store_source, _("Pool resource"));
1140 store->store = (STORE *)job->storage->first();
1141 pm_strcpy(store->store_source, _("Job resource"));
1146 * Set some defaults in the JCR necessary to
1147 * run. These items are pulled from the job
1148 * definition as defaults, but can be overridden
1149 * later either by the Run record in the Schedule resource,
1150 * or by the Console program.
1152 void set_jcr_defaults(JCR *jcr, JOB *job)
1155 jcr->set_JobType(job->JobType);
1156 jcr->JobStatus = JS_Created;
1158 switch (jcr->getJobType()) {
1160 jcr->set_JobLevel(L_NONE);
1163 jcr->set_JobLevel(job->JobLevel);
1168 jcr->fname = get_pool_memory(PM_FNAME);
1170 if (!jcr->pool_source) {
1171 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1172 pm_strcpy(jcr->pool_source, _("unknown source"));
1174 if (!jcr->catalog_source) {
1175 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1176 pm_strcpy(jcr->catalog_source, _("unknown source"));
1179 jcr->JobPriority = job->Priority;
1180 /* Copy storage definitions -- deleted in dir_free_jcr above */
1182 copy_rwstorage(jcr, job->storage, _("Job resource"));
1184 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1186 jcr->client = job->client;
1187 if (!jcr->client_name) {
1188 jcr->client_name = get_pool_memory(PM_NAME);
1190 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1191 pm_strcpy(jcr->pool_source, _("Job resource"));
1192 jcr->pool = job->pool;
1193 jcr->full_pool = job->full_pool;
1194 jcr->inc_pool = job->inc_pool;
1195 jcr->diff_pool = job->diff_pool;
1196 if (job->pool->catalog) {
1197 jcr->catalog = job->pool->catalog;
1198 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1200 jcr->catalog = job->client->catalog;
1201 pm_strcpy(jcr->catalog_source, _("Client resource"));
1203 jcr->fileset = job->fileset;
1204 jcr->messages = job->messages;
1205 jcr->spool_data = job->spool_data;
1206 jcr->spool_size = job->spool_size;
1207 jcr->write_part_after_job = job->write_part_after_job;
1208 jcr->accurate = job->accurate;
1209 if (jcr->RestoreBootstrap) {
1210 free(jcr->RestoreBootstrap);
1211 jcr->RestoreBootstrap = NULL;
1213 /* This can be overridden by Console program */
1214 if (job->RestoreBootstrap) {
1215 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1217 /* This can be overridden by Console program */
1218 jcr->verify_job = job->verify_job;
1219 /* If no default level given, set one */
1220 if (jcr->getJobLevel() == 0) {
1221 switch (jcr->getJobType()) {
1223 jcr->set_JobLevel(L_VERIFY_CATALOG);
1226 jcr->set_JobLevel(L_INCREMENTAL);
1230 jcr->set_JobLevel(L_NONE);
1233 jcr->set_JobLevel(L_FULL);
1240 * Copy the storage definitions from an alist to the JCR
1242 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1244 if (jcr->JobReads()) {
1245 copy_rstorage(jcr, storage, where);
1247 copy_wstorage(jcr, storage, where);
1251 /* Set storage override. Releases any previous storage definition */
1252 void set_rwstorage(JCR *jcr, USTORE *store)
1255 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1258 if (jcr->JobReads()) {
1259 set_rstorage(jcr, store);
1261 set_wstorage(jcr, store);
1264 void free_rwstorage(JCR *jcr)
1271 * Copy the storage definitions from an alist to the JCR
1273 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1277 if (jcr->rstorage) {
1278 delete jcr->rstorage;
1280 jcr->rstorage = New(alist(10, not_owned_by_alist));
1281 foreach_alist(st, storage) {
1282 jcr->rstorage->append(st);
1284 if (!jcr->rstore_source) {
1285 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1287 pm_strcpy(jcr->rstore_source, where);
1288 if (jcr->rstorage) {
1289 jcr->rstore = (STORE *)jcr->rstorage->first();
1295 /* Set storage override. Remove all previous storage */
1296 void set_rstorage(JCR *jcr, USTORE *store)
1300 if (!store->store) {
1303 if (jcr->rstorage) {
1306 if (!jcr->rstorage) {
1307 jcr->rstorage = New(alist(10, not_owned_by_alist));
1309 jcr->rstore = store->store;
1310 if (!jcr->rstore_source) {
1311 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1313 pm_strcpy(jcr->rstore_source, store->store_source);
1314 foreach_alist(storage, jcr->rstorage) {
1315 if (store->store == storage) {
1319 /* Store not in list, so add it */
1320 jcr->rstorage->prepend(store->store);
1323 void free_rstorage(JCR *jcr)
1325 if (jcr->rstorage) {
1326 delete jcr->rstorage;
1327 jcr->rstorage = NULL;
1333 * Copy the storage definitions from an alist to the JCR
1335 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1339 if (jcr->wstorage) {
1340 delete jcr->wstorage;
1342 jcr->wstorage = New(alist(10, not_owned_by_alist));
1343 foreach_alist(st, storage) {
1344 Dmsg1(100, "wstorage=%s\n", st->name());
1345 jcr->wstorage->append(st);
1347 if (!jcr->wstore_source) {
1348 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1350 pm_strcpy(jcr->wstore_source, where);
1351 if (jcr->wstorage) {
1352 jcr->wstore = (STORE *)jcr->wstorage->first();
1353 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1359 /* Set storage override. Remove all previous storage */
1360 void set_wstorage(JCR *jcr, USTORE *store)
1364 if (!store->store) {
1367 if (jcr->wstorage) {
1370 if (!jcr->wstorage) {
1371 jcr->wstorage = New(alist(10, not_owned_by_alist));
1373 jcr->wstore = store->store;
1374 if (!jcr->wstore_source) {
1375 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1377 pm_strcpy(jcr->wstore_source, store->store_source);
1378 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1379 foreach_alist(storage, jcr->wstorage) {
1380 if (store->store == storage) {
1384 /* Store not in list, so add it */
1385 jcr->wstorage->prepend(store->store);
1388 void free_wstorage(JCR *jcr)
1390 if (jcr->wstorage) {
1391 delete jcr->wstorage;
1392 jcr->wstorage = NULL;
1397 char *job_code_callback_clones(JCR *jcr, const char* param)
1399 if (param[0] == 'p') {
1400 return jcr->pool->name();
1405 void create_clones(JCR *jcr)
1408 * Fire off any clone jobs (run directives)
1410 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1411 if (!jcr->cloned && jcr->job->run_cmds) {
1413 JOB *job = jcr->job;
1414 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1415 UAContext *ua = new_ua_context(jcr);
1417 foreach_alist(runcmd, job->run_cmds) {
1418 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1419 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1420 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1421 parse_ua_args(ua); /* parse command */
1422 int stat = run_cmd(ua, ua->cmd);
1424 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1427 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1430 free_ua_context(ua);
1431 free_pool_memory(cmd);
1436 * Given: a JobId in jcr->previous_jr.JobId,
1437 * this subroutine writes a bsr file to restore that job.
1438 * Returns: -1 on error
1439 * number of files if OK
1441 int create_restore_bootstrap_file(JCR *jcr)
1447 memset(&rx, 0, sizeof(rx));
1449 rx.JobIds = (char *)"";
1450 rx.bsr->JobId = jcr->previous_jr.JobId;
1451 ua = new_ua_context(jcr);
1452 if (!complete_bsr(ua, rx.bsr)) {
1456 rx.bsr->fi = new_findex();
1457 rx.bsr->fi->findex = 1;
1458 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1459 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1460 if (jcr->ExpectedFiles == 0) {
1464 free_ua_context(ua);
1466 jcr->needs_sd = true;
1467 return jcr->ExpectedFiles;
1470 free_ua_context(ua);
1475 /* TODO: redirect command ouput to job log */
1476 bool run_console_command(JCR *jcr, const char *cmd)
1480 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1481 ua = new_ua_context(ljcr);
1482 /* run from runscript and check if commands are autorized */
1483 ua->runscript = true;
1484 Mmsg(ua->cmd, "%s", cmd);
1485 Dmsg1(100, "Console command: %s\n", ua->cmd);
1487 ok= do_a_command(ua);
1488 free_ua_context(ua);