2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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
40 /* Forward referenced subroutines */
41 static void *job_thread(void *arg);
42 static void job_monitor_watchdog(watchdog_t *self);
43 static void job_monitor_destructor(watchdog_t *self);
44 static bool job_check_maxwaittime(JCR *jcr);
45 static bool job_check_maxruntime(JCR *jcr);
46 static bool job_check_maxschedruntime(JCR *jcr);
48 /* Imported subroutines */
49 extern void term_scheduler();
50 extern void term_ua_server();
52 /* Imported variables */
56 void init_job_server(int max_workers)
61 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
63 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
66 wd->callback = job_monitor_watchdog;
67 wd->destructor = job_monitor_destructor;
70 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
71 register_watchdog(wd);
74 void term_job_server()
76 jobq_destroy(&job_queue); /* ignore any errors */
80 * Run a job -- typically called by the scheduler, but may also
81 * be called by the UA (Console program).
83 * Returns: 0 on failure
87 JobId_t run_job(JCR *jcr)
91 Dmsg0(200, "Add jrc to work queue\n");
92 /* Queue the job to be run */
93 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
95 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
103 bool setup_job(JCR *jcr)
108 sm_check(__FILE__, __LINE__, true);
109 init_msg(jcr, jcr->messages);
111 /* Initialize termination condition variable */
112 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
114 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
118 jcr->term_wait_inited = true;
120 create_unique_job_name(jcr, jcr->job->name());
121 jcr->setJobStatus(JS_Created);
127 Dmsg0(100, "Open database\n");
128 jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
129 jcr->catalog->db_user,
130 jcr->catalog->db_password, jcr->catalog->db_address,
131 jcr->catalog->db_port, jcr->catalog->db_socket,
132 jcr->catalog->mult_db_connections);
133 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
134 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
135 jcr->catalog->db_name);
137 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
138 db_close_database(jcr, jcr->db);
142 Dmsg0(150, "DB opened\n");
144 jcr->comment = get_pool_memory(PM_MESSAGE);
145 *jcr->comment = '\0';
148 jcr->fname = get_pool_memory(PM_FNAME);
150 if (!jcr->pool_source) {
151 jcr->pool_source = get_pool_memory(PM_MESSAGE);
152 pm_strcpy(jcr->pool_source, _("unknown source"));
155 if (jcr->JobReads()) {
156 if (!jcr->rpool_source) {
157 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
158 pm_strcpy(jcr->rpool_source, _("unknown source"));
165 init_jcr_job_record(jcr);
166 if (!get_or_create_client_record(jcr)) {
170 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
171 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
174 jcr->JobId = jcr->jr.JobId;
175 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
176 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
178 generate_daemon_event(jcr, "JobStart");
179 new_plugins(jcr); /* instantiate plugins for this jcr */
180 generate_plugin_event(jcr, bEventJobStart);
182 if (job_canceled(jcr)) {
186 if (jcr->JobReads() && !jcr->rstorage) {
187 if (jcr->job->storage) {
188 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
190 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
193 if (!jcr->JobReads()) {
198 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
199 * this allows us to setup a proper job start record for restarting
200 * in case of later errors.
202 switch (jcr->getJobType()) {
204 if (!do_backup_init(jcr)) {
205 backup_cleanup(jcr, JS_ErrorTerminated);
210 if (!do_verify_init(jcr)) {
211 verify_cleanup(jcr, JS_ErrorTerminated);
216 if (!do_restore_init(jcr)) {
217 restore_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_admin_init(jcr)) {
223 admin_cleanup(jcr, JS_ErrorTerminated);
229 if (!do_migration_init(jcr)) {
230 migration_cleanup(jcr, JS_ErrorTerminated);
235 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
236 jcr->setJobStatus(JS_ErrorTerminated);
240 generate_job_event(jcr, "JobInit");
241 generate_plugin_event(jcr, bEventJobInit);
249 void update_job_end(JCR *jcr, int TermCode)
251 dequeue_messages(jcr); /* display any queued messages */
252 jcr->setJobStatus(TermCode);
253 update_job_end_record(jcr);
257 * This is the engine called by jobq.c:jobq_add() when we were pulled
258 * from the work queue.
259 * At this point, we are running in our own thread and all
260 * necessary resources are allocated -- see jobq.c
262 static void *job_thread(void *arg)
264 JCR *jcr = (JCR *)arg;
266 pthread_detach(pthread_self());
269 Dmsg0(200, "=====Start Job=========\n");
270 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
271 jcr->start_time = time(NULL); /* set the real start time */
272 jcr->jr.StartTime = jcr->start_time;
274 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
275 (utime_t)(jcr->start_time - jcr->sched_time)) {
276 jcr->setJobStatus(JS_Canceled);
277 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
280 if (job_check_maxschedruntime(jcr)) {
281 jcr->setJobStatus(JS_Canceled);
282 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
285 /* TODO : check if it is used somewhere */
286 if (jcr->job->RunScripts == NULL) {
287 Dmsg0(200, "Warning, job->RunScripts is empty\n");
288 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
291 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
292 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
295 /* Run any script BeforeJob on dird */
296 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
299 * We re-update the job start record so that the start
300 * time is set after the run before job. This avoids
301 * that any files created by the run before job will
302 * be saved twice. They will be backed up in the current
303 * job, but not in the next one unless they are changed.
304 * Without this, they will be backed up in this job and
305 * in the next job run because in that case, their date
306 * is after the start of this run.
308 jcr->start_time = time(NULL);
309 jcr->jr.StartTime = jcr->start_time;
310 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
311 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
313 generate_job_event(jcr, "JobRun");
314 generate_plugin_event(jcr, bEventJobRun);
316 switch (jcr->getJobType()) {
318 if (!job_canceled(jcr) && do_backup(jcr)) {
321 backup_cleanup(jcr, JS_ErrorTerminated);
325 if (!job_canceled(jcr) && do_verify(jcr)) {
328 verify_cleanup(jcr, JS_ErrorTerminated);
332 if (!job_canceled(jcr) && do_restore(jcr)) {
335 restore_cleanup(jcr, JS_ErrorTerminated);
339 if (!job_canceled(jcr) && do_admin(jcr)) {
342 admin_cleanup(jcr, JS_ErrorTerminated);
347 if (!job_canceled(jcr) && do_migration(jcr)) {
350 migration_cleanup(jcr, JS_ErrorTerminated);
354 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
358 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
360 /* Send off any queued messages */
361 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
362 dequeue_messages(jcr);
365 generate_daemon_event(jcr, "JobEnd");
366 generate_plugin_event(jcr, bEventJobEnd);
367 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
368 sm_check(__FILE__, __LINE__, true);
374 * Cancel a job -- typically called by the UA (Console program), but may also
375 * be called by the job watchdog.
377 * Returns: true if cancel appears to be successful
378 * false on failure. Message sent to ua->jcr.
380 bool cancel_job(UAContext *ua, JCR *jcr)
384 int32_t old_status = jcr->JobStatus;
386 jcr->setJobStatus(JS_Canceled);
388 switch (old_status) {
391 case JS_WaitClientRes:
392 case JS_WaitStoreRes:
393 case JS_WaitPriority:
395 case JS_WaitStartTime:
396 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
397 edit_uint64(jcr->JobId, ed1), jcr->Job);
398 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
402 /* Cancel File daemon */
403 if (jcr->file_bsock) {
404 ua->jcr->client = jcr->client;
405 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
406 ua->error_msg(_("Failed to connect to File daemon.\n"));
409 Dmsg0(200, "Connected to file daemon\n");
410 fd = ua->jcr->file_bsock;
411 fd->fsend("cancel Job=%s\n", jcr->Job);
412 while (fd->recv() >= 0) {
413 ua->send_msg("%s", fd->msg);
415 fd->signal(BNET_TERMINATE);
417 ua->jcr->file_bsock = NULL;
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;
458 void cancel_storage_daemon_job(JCR *jcr)
460 if (jcr->sd_canceled) {
461 return; /* cancel only once */
464 UAContext *ua = new_ua_context(jcr);
465 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
468 ua->jcr = control_jcr;
469 if (jcr->store_bsock) {
470 if (!ua->jcr->wstorage) {
472 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
474 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
479 store.store = jcr->rstore;
481 store.store = jcr->wstore;
483 set_wstorage(ua->jcr, &store);
486 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
489 Dmsg0(200, "Connected to storage daemon\n");
490 sd = ua->jcr->store_bsock;
491 sd->fsend("cancel Job=%s\n", jcr->Job);
492 while (sd->recv() >= 0) {
494 sd->signal(BNET_TERMINATE);
496 ua->jcr->store_bsock = NULL;
497 jcr->sd_canceled = true;
500 free_jcr(control_jcr);
504 static void job_monitor_destructor(watchdog_t *self)
506 JCR *control_jcr = (JCR *)self->data;
508 free_jcr(control_jcr);
511 static void job_monitor_watchdog(watchdog_t *self)
513 JCR *control_jcr, *jcr;
515 control_jcr = (JCR *)self->data;
518 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
523 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
524 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
528 /* check MaxWaitTime */
529 if (job_check_maxwaittime(jcr)) {
530 jcr->setJobStatus(JS_Canceled);
531 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
533 /* check MaxRunTime */
534 } else if (job_check_maxruntime(jcr)) {
535 jcr->setJobStatus(JS_Canceled);
536 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
538 /* check MaxRunSchedTime */
539 } else if (job_check_maxschedruntime(jcr)) {
540 jcr->setJobStatus(JS_Canceled);
541 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
546 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
547 UAContext *ua = new_ua_context(jcr);
548 ua->jcr = control_jcr;
551 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
555 /* Keep reference counts correct */
560 * Check if the maxwaittime has expired and it is possible
563 static bool job_check_maxwaittime(JCR *jcr)
569 if (!job_waiting(jcr)) {
573 if (jcr->wait_time) {
574 current = watchdog_time - jcr->wait_time;
577 Dmsg2(200, "check maxwaittime %u >= %u\n",
578 current + jcr->wait_time_sum, job->MaxWaitTime);
579 if (job->MaxWaitTime != 0 &&
580 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
588 * Check if maxruntime has expired and if the job can be
591 static bool job_check_maxruntime(JCR *jcr)
597 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
600 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
601 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
604 run_time = watchdog_time - jcr->start_time;
605 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
606 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
607 job->IncMaxRunTime, job->DiffMaxRunTime);
609 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
610 run_time >= job->FullMaxRunTime) {
611 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
613 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
614 run_time >= job->DiffMaxRunTime) {
615 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
617 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
618 run_time >= job->IncMaxRunTime) {
619 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
621 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
622 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
630 * Check if MaxRunSchedTime has expired and if the job can be
633 static bool job_check_maxschedruntime(JCR *jcr)
635 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
638 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
639 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
640 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
648 * Get or create a Pool record with the given name.
649 * Returns: 0 on error
652 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
656 memset(&pr, 0, sizeof(pr));
657 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
658 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
660 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
661 /* Try to create the pool */
662 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
663 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
664 db_strerror(jcr->db));
667 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
674 * Check for duplicate jobs.
675 * Returns: true if current job should continue
676 * false if current job should terminate
678 bool allow_duplicate_job(JCR *jcr)
681 JCR *djcr; /* possible duplicate job */
683 if (job->AllowDuplicateJobs) {
687 * After this point, we do not want to allow any duplicate
692 if (jcr == djcr || djcr->JobId == 0) {
693 continue; /* do not cancel this job or consoles */
695 if (strcmp(job->name(), djcr->job->name()) == 0) {
696 bool cancel_dup = false;
697 bool cancel_me = true;
698 if (job->DuplicateJobProximity > 0) {
699 utime_t now = (utime_t)time(NULL);
700 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
701 continue; /* not really a duplicate */
704 if (job->CancelLowerLevelDuplicates &&
705 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
706 switch (jcr->getJobLevel()) {
708 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
709 djcr->getJobLevel() == L_INCREMENTAL) {
714 if (djcr->getJobLevel() == L_INCREMENTAL) {
717 if (djcr->getJobLevel() == L_FULL) {
722 if (djcr->getJobLevel() == L_FULL ||
723 djcr->getJobLevel() == L_DIFFERENTIAL) {
728 * cancel_dup will be done below
731 /* Zap current job */
732 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
734 break; /* get out of foreach_jcr */
737 /* Cancel one of the two jobs (me or dup) */
738 /* If CancelQueuedDuplicates is set do so only if job is queued */
739 if (job->CancelQueuedDuplicates) {
740 switch (djcr->JobStatus) {
743 case JS_WaitClientRes:
744 case JS_WaitStoreRes:
745 case JS_WaitPriority:
747 case JS_WaitStartTime:
748 cancel_dup = true; /* cancel queued duplicate */
754 if (cancel_dup || job->CancelRunningDuplicates) {
755 /* Zap the duplicated job djcr */
756 UAContext *ua = new_ua_context(djcr);
757 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
759 cancel_job(ua, djcr);
761 Dmsg2(800, "Have cancelled JCR %p JobId=%d\n", djcr, djcr->JobId);
763 /* Zap current job */
764 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
767 break; /* did our work, get out of foreach loop */
775 void apply_pool_overrides(JCR *jcr)
777 bool pool_override = false;
779 if (jcr->run_pool_override) {
780 pm_strcpy(jcr->pool_source, _("Run pool override"));
783 * Apply any level related Pool selections
785 switch (jcr->getJobLevel()) {
787 if (jcr->full_pool) {
788 jcr->pool = jcr->full_pool;
789 pool_override = true;
790 if (jcr->run_full_pool_override) {
791 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
793 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
799 jcr->pool = jcr->inc_pool;
800 pool_override = true;
801 if (jcr->run_inc_pool_override) {
802 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
804 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
809 if (jcr->diff_pool) {
810 jcr->pool = jcr->diff_pool;
811 pool_override = true;
812 if (jcr->run_diff_pool_override) {
813 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
815 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
820 /* Update catalog if pool overridden */
821 if (pool_override && jcr->pool->catalog) {
822 jcr->catalog = jcr->pool->catalog;
823 pm_strcpy(jcr->catalog_source, _("Pool resource"));
829 * Get or create a Client record for this Job
831 bool get_or_create_client_record(JCR *jcr)
835 memset(&cr, 0, sizeof(cr));
836 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
837 cr.AutoPrune = jcr->client->AutoPrune;
838 cr.FileRetention = jcr->client->FileRetention;
839 cr.JobRetention = jcr->client->JobRetention;
840 if (!jcr->client_name) {
841 jcr->client_name = get_pool_memory(PM_NAME);
843 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
844 if (!db_create_client_record(jcr, jcr->db, &cr)) {
845 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
846 db_strerror(jcr->db));
849 jcr->jr.ClientId = cr.ClientId;
851 if (!jcr->client_uname) {
852 jcr->client_uname = get_pool_memory(PM_NAME);
854 pm_strcpy(jcr->client_uname, cr.Uname);
856 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
861 bool get_or_create_fileset_record(JCR *jcr)
865 * Get or Create FileSet record
867 memset(&fsr, 0, sizeof(FILESET_DBR));
868 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
869 if (jcr->fileset->have_MD5) {
870 struct MD5Context md5c;
871 unsigned char digest[MD5HashSize];
872 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
873 MD5Final(digest, &md5c);
875 * Keep the flag (last arg) set to false otherwise old FileSets will
876 * get new MD5 sums and the user will get Full backups on everything
878 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
879 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
881 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
883 if (!jcr->fileset->ignore_fs_changes ||
884 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
885 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
886 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
887 fsr.FileSet, db_strerror(jcr->db));
891 jcr->jr.FileSetId = fsr.FileSetId;
892 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
893 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
898 void init_jcr_job_record(JCR *jcr)
900 jcr->jr.SchedTime = jcr->sched_time;
901 jcr->jr.StartTime = jcr->start_time;
902 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
903 jcr->jr.JobType = jcr->getJobType();
904 jcr->jr.JobLevel = jcr->getJobLevel();
905 jcr->jr.JobStatus = jcr->JobStatus;
906 jcr->jr.JobId = jcr->JobId;
907 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
908 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
912 * Write status and such in DB
914 void update_job_end_record(JCR *jcr)
916 jcr->jr.EndTime = time(NULL);
917 jcr->end_time = jcr->jr.EndTime;
918 jcr->jr.JobId = jcr->JobId;
919 jcr->jr.JobStatus = jcr->JobStatus;
920 jcr->jr.JobFiles = jcr->JobFiles;
921 jcr->jr.JobBytes = jcr->JobBytes;
922 jcr->jr.ReadBytes = jcr->ReadBytes;
923 jcr->jr.VolSessionId = jcr->VolSessionId;
924 jcr->jr.VolSessionTime = jcr->VolSessionTime;
925 jcr->jr.JobErrors = jcr->JobErrors;
926 jcr->jr.HasBase = jcr->HasBase;
927 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
928 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
929 db_strerror(jcr->db));
934 * Takes base_name and appends (unique) current
935 * date and time to form unique job name.
937 * Note, the seconds are actually a sequence number. This
938 * permits us to start a maximum fo 59 unique jobs a second, which
939 * should be sufficient.
941 * Returns: unique job name in jcr->Job
942 * date/time in jcr->start_time
944 void create_unique_job_name(JCR *jcr, const char *base_name)
946 /* Job start mutex */
947 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
948 static time_t last_start_time = 0;
950 time_t now = time(NULL);
952 char dt[MAX_TIME_LENGTH];
953 char name[MAX_NAME_LENGTH];
957 /* Guarantee unique start time -- maximum one per second, and
958 * thus unique Job Name
960 P(mutex); /* lock creation of jobs */
962 if (seq > 59) { /* wrap as if it is seconds */
964 while (now == last_start_time) {
965 bmicrosleep(0, 500000);
969 last_start_time = now;
970 V(mutex); /* allow creation of jobs */
971 jcr->start_time = now;
972 /* Form Unique JobName */
973 (void)localtime_r(&now, &tm);
974 /* Use only characters that are permitted in Windows filenames */
975 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
976 len = strlen(dt) + 5; /* dt + .%02d EOS */
977 bstrncpy(name, base_name, sizeof(name));
978 name[sizeof(name)-len] = 0; /* truncate if too long */
979 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
980 /* Convert spaces into underscores */
981 for (p=jcr->Job; *p; p++) {
986 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
989 /* Called directly from job rescheduling */
990 void dird_free_jcr_pointers(JCR *jcr)
992 if (jcr->sd_auth_key) {
993 free(jcr->sd_auth_key);
994 jcr->sd_auth_key = NULL;
1000 if (jcr->file_bsock) {
1001 Dmsg0(200, "Close File bsock\n");
1002 bnet_close(jcr->file_bsock);
1003 jcr->file_bsock = NULL;
1005 if (jcr->store_bsock) {
1006 Dmsg0(200, "Close Store bsock\n");
1007 bnet_close(jcr->store_bsock);
1008 jcr->store_bsock = NULL;
1011 free_pool_memory(jcr->comment);
1012 jcr->comment = NULL;
1015 Dmsg0(200, "Free JCR fname\n");
1016 free_pool_memory(jcr->fname);
1019 if (jcr->RestoreBootstrap) {
1020 free(jcr->RestoreBootstrap);
1021 jcr->RestoreBootstrap = NULL;
1023 if (jcr->client_uname) {
1024 free_pool_memory(jcr->client_uname);
1025 jcr->client_uname = NULL;
1028 free_pool_memory(jcr->attr);
1038 * Free the Job Control Record if no one is still using it.
1039 * Called from main free_jcr() routine in src/lib/jcr.c so
1040 * that we can do our Director specific cleanup of the jcr.
1042 void dird_free_jcr(JCR *jcr)
1044 Dmsg0(200, "Start dird free_jcr\n");
1046 dird_free_jcr_pointers(jcr);
1047 if (jcr->term_wait_inited) {
1048 pthread_cond_destroy(&jcr->term_wait);
1049 jcr->term_wait_inited = false;
1051 if (jcr->db_batch) {
1052 db_close_database(jcr, jcr->db_batch);
1053 jcr->db_batch = NULL;
1054 jcr->batch_started = false;
1057 db_close_database(jcr, jcr->db);
1061 Dmsg0(200, "Free JCR stime\n");
1062 free_pool_memory(jcr->stime);
1066 Dmsg0(200, "Free JCR fname\n");
1067 free_pool_memory(jcr->fname);
1070 if (jcr->pool_source) {
1071 free_pool_memory(jcr->pool_source);
1072 jcr->pool_source = NULL;
1074 if (jcr->catalog_source) {
1075 free_pool_memory(jcr->catalog_source);
1076 jcr->catalog_source = NULL;
1078 if (jcr->rpool_source) {
1079 free_pool_memory(jcr->rpool_source);
1080 jcr->rpool_source = NULL;
1082 if (jcr->wstore_source) {
1083 free_pool_memory(jcr->wstore_source);
1084 jcr->wstore_source = NULL;
1086 if (jcr->rstore_source) {
1087 free_pool_memory(jcr->rstore_source);
1088 jcr->rstore_source = NULL;
1091 /* Delete lists setup to hold storage pointers */
1092 free_rwstorage(jcr);
1094 jcr->job_end_push.destroy();
1096 if (jcr->JobId != 0)
1097 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1099 free_plugins(jcr); /* release instantiated plugins */
1101 Dmsg0(200, "End dird free_jcr\n");
1105 * The Job storage definition must be either in the Job record
1106 * or in the Pool record. The Pool record overrides the Job
1109 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1111 if (run && run->pool && run->pool->storage) {
1112 store->store = (STORE *)run->pool->storage->first();
1113 pm_strcpy(store->store_source, _("Run pool override"));
1116 if (run && run->storage) {
1117 store->store = run->storage;
1118 pm_strcpy(store->store_source, _("Run storage override"));
1121 if (job->pool->storage) {
1122 store->store = (STORE *)job->pool->storage->first();
1123 pm_strcpy(store->store_source, _("Pool resource"));
1125 store->store = (STORE *)job->storage->first();
1126 pm_strcpy(store->store_source, _("Job resource"));
1131 * Set some defaults in the JCR necessary to
1132 * run. These items are pulled from the job
1133 * definition as defaults, but can be overridden
1134 * later either by the Run record in the Schedule resource,
1135 * or by the Console program.
1137 void set_jcr_defaults(JCR *jcr, JOB *job)
1140 jcr->set_JobType(job->JobType);
1141 jcr->JobStatus = JS_Created;
1143 switch (jcr->getJobType()) {
1145 jcr->set_JobLevel(L_NONE);
1148 jcr->set_JobLevel(job->JobLevel);
1153 jcr->fname = get_pool_memory(PM_FNAME);
1155 if (!jcr->pool_source) {
1156 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1157 pm_strcpy(jcr->pool_source, _("unknown source"));
1159 if (!jcr->catalog_source) {
1160 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1161 pm_strcpy(jcr->catalog_source, _("unknown source"));
1164 jcr->JobPriority = job->Priority;
1165 /* Copy storage definitions -- deleted in dir_free_jcr above */
1167 copy_rwstorage(jcr, job->storage, _("Job resource"));
1169 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1171 jcr->client = job->client;
1172 if (!jcr->client_name) {
1173 jcr->client_name = get_pool_memory(PM_NAME);
1175 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1176 pm_strcpy(jcr->pool_source, _("Job resource"));
1177 jcr->pool = job->pool;
1178 jcr->full_pool = job->full_pool;
1179 jcr->inc_pool = job->inc_pool;
1180 jcr->diff_pool = job->diff_pool;
1181 if (job->pool->catalog) {
1182 jcr->catalog = job->pool->catalog;
1183 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1185 jcr->catalog = job->client->catalog;
1186 pm_strcpy(jcr->catalog_source, _("Client resource"));
1188 jcr->fileset = job->fileset;
1189 jcr->messages = job->messages;
1190 jcr->spool_data = job->spool_data;
1191 jcr->spool_size = job->spool_size;
1192 jcr->write_part_after_job = job->write_part_after_job;
1193 jcr->accurate = job->accurate;
1194 if (jcr->RestoreBootstrap) {
1195 free(jcr->RestoreBootstrap);
1196 jcr->RestoreBootstrap = NULL;
1198 /* This can be overridden by Console program */
1199 if (job->RestoreBootstrap) {
1200 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1202 /* This can be overridden by Console program */
1203 jcr->verify_job = job->verify_job;
1204 /* If no default level given, set one */
1205 if (jcr->getJobLevel() == 0) {
1206 switch (jcr->getJobType()) {
1208 jcr->set_JobLevel(L_VERIFY_CATALOG);
1211 jcr->set_JobLevel(L_INCREMENTAL);
1215 jcr->set_JobLevel(L_NONE);
1218 jcr->set_JobLevel(L_FULL);
1225 * Copy the storage definitions from an alist to the JCR
1227 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1229 if (jcr->JobReads()) {
1230 copy_rstorage(jcr, storage, where);
1232 copy_wstorage(jcr, storage, where);
1236 /* Set storage override. Releases any previous storage definition */
1237 void set_rwstorage(JCR *jcr, USTORE *store)
1240 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1243 if (jcr->JobReads()) {
1244 set_rstorage(jcr, store);
1246 set_wstorage(jcr, store);
1249 void free_rwstorage(JCR *jcr)
1256 * Copy the storage definitions from an alist to the JCR
1258 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1262 if (jcr->rstorage) {
1263 delete jcr->rstorage;
1265 jcr->rstorage = New(alist(10, not_owned_by_alist));
1266 foreach_alist(st, storage) {
1267 jcr->rstorage->append(st);
1269 if (!jcr->rstore_source) {
1270 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1272 pm_strcpy(jcr->rstore_source, where);
1273 if (jcr->rstorage) {
1274 jcr->rstore = (STORE *)jcr->rstorage->first();
1280 /* Set storage override. Remove all previous storage */
1281 void set_rstorage(JCR *jcr, USTORE *store)
1285 if (!store->store) {
1288 if (jcr->rstorage) {
1291 if (!jcr->rstorage) {
1292 jcr->rstorage = New(alist(10, not_owned_by_alist));
1294 jcr->rstore = store->store;
1295 if (!jcr->rstore_source) {
1296 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1298 pm_strcpy(jcr->rstore_source, store->store_source);
1299 foreach_alist(storage, jcr->rstorage) {
1300 if (store->store == storage) {
1304 /* Store not in list, so add it */
1305 jcr->rstorage->prepend(store->store);
1308 void free_rstorage(JCR *jcr)
1310 if (jcr->rstorage) {
1311 delete jcr->rstorage;
1312 jcr->rstorage = NULL;
1318 * Copy the storage definitions from an alist to the JCR
1320 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1324 if (jcr->wstorage) {
1325 delete jcr->wstorage;
1327 jcr->wstorage = New(alist(10, not_owned_by_alist));
1328 foreach_alist(st, storage) {
1329 Dmsg1(100, "wstorage=%s\n", st->name());
1330 jcr->wstorage->append(st);
1332 if (!jcr->wstore_source) {
1333 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1335 pm_strcpy(jcr->wstore_source, where);
1336 if (jcr->wstorage) {
1337 jcr->wstore = (STORE *)jcr->wstorage->first();
1338 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1344 /* Set storage override. Remove all previous storage */
1345 void set_wstorage(JCR *jcr, USTORE *store)
1349 if (!store->store) {
1352 if (jcr->wstorage) {
1355 if (!jcr->wstorage) {
1356 jcr->wstorage = New(alist(10, not_owned_by_alist));
1358 jcr->wstore = store->store;
1359 if (!jcr->wstore_source) {
1360 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1362 pm_strcpy(jcr->wstore_source, store->store_source);
1363 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1364 foreach_alist(storage, jcr->wstorage) {
1365 if (store->store == storage) {
1369 /* Store not in list, so add it */
1370 jcr->wstorage->prepend(store->store);
1373 void free_wstorage(JCR *jcr)
1375 if (jcr->wstorage) {
1376 delete jcr->wstorage;
1377 jcr->wstorage = NULL;
1382 char *job_code_callback_clones(JCR *jcr, const char* param)
1384 if (param[0] == 'p') {
1385 return jcr->pool->name();
1390 void create_clones(JCR *jcr)
1393 * Fire off any clone jobs (run directives)
1395 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1396 if (!jcr->cloned && jcr->job->run_cmds) {
1398 JOB *job = jcr->job;
1399 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1400 UAContext *ua = new_ua_context(jcr);
1402 foreach_alist(runcmd, job->run_cmds) {
1403 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1404 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1405 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1406 parse_ua_args(ua); /* parse command */
1407 int stat = run_cmd(ua, ua->cmd);
1409 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1412 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1415 free_ua_context(ua);
1416 free_pool_memory(cmd);
1421 * Given: a JobId in jcr->previous_jr.JobId,
1422 * this subroutine writes a bsr file to restore that job.
1423 * Returns: -1 on error
1424 * number of files if OK
1426 int create_restore_bootstrap_file(JCR *jcr)
1432 memset(&rx, 0, sizeof(rx));
1434 rx.JobIds = (char *)"";
1435 rx.bsr->JobId = jcr->previous_jr.JobId;
1436 ua = new_ua_context(jcr);
1437 if (!complete_bsr(ua, rx.bsr)) {
1441 rx.bsr->fi = new_findex();
1442 rx.bsr->fi->findex = 1;
1443 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1444 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1445 if (jcr->ExpectedFiles == 0) {
1449 free_ua_context(ua);
1451 jcr->needs_sd = true;
1452 return jcr->ExpectedFiles;
1455 free_ua_context(ua);
1460 /* TODO: redirect command ouput to job log */
1461 bool run_console_command(JCR *jcr, const char *cmd)
1465 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1466 ua = new_ua_context(ljcr);
1467 /* run from runscript and check if commands are autorized */
1468 ua->runscript = true;
1469 Mmsg(ua->cmd, "%s", cmd);
1470 Dmsg1(100, "Console command: %s\n", ua->cmd);
1472 ok= do_a_command(ua);
1473 free_ua_context(ua);