2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 set_jcr_job_status(jcr, 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");
145 jcr->fname = get_pool_memory(PM_FNAME);
147 if (!jcr->pool_source) {
148 jcr->pool_source = get_pool_memory(PM_MESSAGE);
149 pm_strcpy(jcr->pool_source, _("unknown source"));
151 Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
153 if (jcr->JobType == JT_MIGRATE || jcr->JobType == JT_COPY) {
154 if (!jcr->rpool_source) {
155 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
156 pm_strcpy(jcr->rpool_source, _("unknown source"));
163 init_jcr_job_record(jcr);
164 if (!get_or_create_client_record(jcr)) {
168 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
169 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
172 jcr->JobId = jcr->jr.JobId;
173 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
174 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
176 generate_daemon_event(jcr, "JobStart");
178 if (job_canceled(jcr)) {
183 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
184 * this allows us to setup a proper job start record for restarting
185 * in case of later errors.
187 switch (jcr->JobType) {
189 if (!do_backup_init(jcr)) {
190 backup_cleanup(jcr, JS_ErrorTerminated);
194 if (!do_verify_init(jcr)) {
195 verify_cleanup(jcr, JS_ErrorTerminated);
199 if (!do_restore_init(jcr)) {
200 restore_cleanup(jcr, JS_ErrorTerminated);
204 if (!do_admin_init(jcr)) {
205 admin_cleanup(jcr, JS_ErrorTerminated);
210 if (!do_migration_init(jcr)) {
211 migration_cleanup(jcr, JS_ErrorTerminated);
215 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
216 set_jcr_job_status(jcr, JS_ErrorTerminated);
220 generate_job_event(jcr, "JobInit");
228 void update_job_end(JCR *jcr, int TermCode)
230 dequeue_messages(jcr); /* display any queued messages */
231 set_jcr_job_status(jcr, TermCode);
232 update_job_end_record(jcr);
236 * This is the engine called by jobq.c:jobq_add() when we were pulled
237 * from the work queue.
238 * At this point, we are running in our own thread and all
239 * necessary resources are allocated -- see jobq.c
241 static void *job_thread(void *arg)
243 JCR *jcr = (JCR *)arg;
245 pthread_detach(pthread_self());
248 Dmsg0(200, "=====Start Job=========\n");
249 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
250 jcr->start_time = time(NULL); /* set the real start time */
251 jcr->jr.StartTime = jcr->start_time;
253 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
254 (utime_t)(jcr->start_time - jcr->sched_time)) {
255 set_jcr_job_status(jcr, JS_Canceled);
256 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
259 if (job_check_maxschedruntime(jcr)) {
260 set_jcr_job_status(jcr, JS_Canceled);
261 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
264 /* TODO : check if it is used somewhere */
265 if (jcr->job->RunScripts == NULL) {
266 Dmsg0(200, "Warning, job->RunScripts is empty\n");
267 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
270 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
271 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
274 /* Run any script BeforeJob on dird */
275 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
277 if (job_canceled(jcr)) {
278 update_job_end(jcr, jcr->JobStatus);
282 * We re-update the job start record so that the start
283 * time is set after the run before job. This avoids
284 * that any files created by the run before job will
285 * be saved twice. They will be backed up in the current
286 * job, but not in the next one unless they are changed.
287 * Without this, they will be backed up in this job and
288 * in the next job run because in that case, their date
289 * is after the start of this run.
291 jcr->start_time = time(NULL);
292 jcr->jr.StartTime = jcr->start_time;
293 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
294 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
296 generate_job_event(jcr, "JobRun");
298 switch (jcr->JobType) {
300 if (do_backup(jcr)) {
303 backup_cleanup(jcr, JS_ErrorTerminated);
307 if (do_verify(jcr)) {
310 verify_cleanup(jcr, JS_ErrorTerminated);
314 if (do_restore(jcr)) {
317 restore_cleanup(jcr, JS_ErrorTerminated);
324 admin_cleanup(jcr, JS_ErrorTerminated);
329 if (do_migration(jcr)) {
332 migration_cleanup(jcr, JS_ErrorTerminated);
336 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
341 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
343 /* Send off any queued messages */
344 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
345 dequeue_messages(jcr);
348 generate_daemon_event(jcr, "JobEnd");
349 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
350 sm_check(__FILE__, __LINE__, true);
356 * Cancel a job -- typically called by the UA (Console program), but may also
357 * be called by the job watchdog.
359 * Returns: true if cancel appears to be successful
360 * false on failure. Message sent to ua->jcr.
362 bool cancel_job(UAContext *ua, JCR *jcr)
367 set_jcr_job_status(jcr, JS_Canceled);
369 switch (jcr->JobStatus) {
372 case JS_WaitClientRes:
373 case JS_WaitStoreRes:
374 case JS_WaitPriority:
376 case JS_WaitStartTime:
377 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
378 edit_uint64(jcr->JobId, ed1), jcr->Job);
379 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
383 /* Cancel File daemon */
384 if (jcr->file_bsock) {
385 ua->jcr->client = jcr->client;
386 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
387 ua->error_msg(_("Failed to connect to File daemon.\n"));
390 Dmsg0(200, "Connected to file daemon\n");
391 fd = ua->jcr->file_bsock;
392 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
393 while (bnet_recv(fd) >= 0) {
394 ua->send_msg("%s", fd->msg);
396 bnet_sig(fd, BNET_TERMINATE);
398 ua->jcr->file_bsock = NULL;
401 /* Cancel Storage daemon */
402 if (jcr->store_bsock) {
403 if (!ua->jcr->wstorage) {
405 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
407 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
412 store.store = jcr->rstore;
414 store.store = jcr->wstore;
416 set_wstorage(ua->jcr, &store);
419 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
420 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
423 Dmsg0(200, "Connected to storage daemon\n");
424 sd = ua->jcr->store_bsock;
425 sd->fsend("cancel Job=%s\n", jcr->Job);
426 while (sd->recv() >= 0) {
427 ua->send_msg("%s", sd->msg);
429 sd->signal(BNET_TERMINATE);
431 ua->jcr->store_bsock = NULL;
438 void cancel_storage_daemon_job(JCR *jcr)
440 UAContext *ua = new_ua_context(jcr);
441 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
444 ua->jcr = control_jcr;
445 if (jcr->store_bsock) {
446 if (!ua->jcr->wstorage) {
448 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
450 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
455 store.store = jcr->rstore;
457 store.store = jcr->wstore;
459 set_wstorage(ua->jcr, &store);
462 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
465 Dmsg0(200, "Connected to storage daemon\n");
466 sd = ua->jcr->store_bsock;
467 sd->fsend("cancel Job=%s\n", jcr->Job);
468 while (sd->recv() >= 0) {
470 sd->signal(BNET_TERMINATE);
472 ua->jcr->store_bsock = NULL;
475 free_jcr(control_jcr);
479 static void job_monitor_destructor(watchdog_t *self)
481 JCR *control_jcr = (JCR *)self->data;
483 free_jcr(control_jcr);
486 static void job_monitor_watchdog(watchdog_t *self)
488 JCR *control_jcr, *jcr;
490 control_jcr = (JCR *)self->data;
493 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
498 if (jcr->JobId == 0 || job_canceled(jcr)) {
499 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
503 /* check MaxWaitTime */
504 if (job_check_maxwaittime(jcr)) {
505 set_jcr_job_status(jcr, JS_Canceled);
506 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
508 /* check MaxRunTime */
509 } else if (job_check_maxruntime(jcr)) {
510 set_jcr_job_status(jcr, JS_Canceled);
511 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
513 /* check MaxRunSchedTime */
514 } else if (job_check_maxschedruntime(jcr)) {
515 set_jcr_job_status(jcr, JS_Canceled);
516 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
521 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
522 UAContext *ua = new_ua_context(jcr);
523 ua->jcr = control_jcr;
526 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
530 /* Keep reference counts correct */
535 * Check if the maxwaittime has expired and it is possible
538 static bool job_check_maxwaittime(JCR *jcr)
543 if (!job_waiting(jcr)) {
546 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
547 if (job->MaxWaitTime != 0 &&
548 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
556 * Check if maxruntime has expired and if the job can be
559 static bool job_check_maxruntime(JCR *jcr)
564 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
567 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
568 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
571 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
572 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
573 job->IncMaxRunTime, job->DiffMaxRunTime);
575 if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
576 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
578 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
579 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
581 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
582 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
584 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
592 * Check if MaxRunSchedTime has expired and if the job can be
595 static bool job_check_maxschedruntime(JCR *jcr)
597 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
600 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
601 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
602 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
610 * Get or create a Pool record with the given name.
611 * Returns: 0 on error
614 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
618 memset(&pr, 0, sizeof(pr));
619 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
620 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
622 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
623 /* Try to create the pool */
624 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
625 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
626 db_strerror(jcr->db));
629 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
636 * Check for duplicate jobs.
637 * Returns: true if current job should continue
638 * false if current job should terminate
640 bool allow_duplicate_job(JCR *jcr)
643 JCR *djcr; /* possible duplicate */
645 if (job->AllowDuplicateJobs) {
648 if (!job->AllowHigherDuplicates) {
651 if (strcmp(job->name(), djcr->job->name()) == 0) {
652 bool cancel_queued = false;
653 if (job->DuplicateJobProximity > 0) {
654 time_t now = time(NULL);
655 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
656 continue; /* not really a duplicate */
660 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
661 /* Zap current job */
662 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
663 edit_uint64(djcr->JobId, ec1));
666 /* If CancelQueuedDuplicates is set do so only if job is queued */
667 if (job->CancelQueuedDuplicates) {
668 switch (djcr->JobStatus) {
671 case JS_WaitClientRes:
672 case JS_WaitStoreRes:
673 case JS_WaitPriority:
675 case JS_WaitStartTime:
676 cancel_queued = true;
682 if (cancel_queued || job->CancelRunningDuplicates) {
683 UAContext *ua = new_ua_context(djcr);
684 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
685 edit_uint64(djcr->JobId, ec1));
687 cancel_job(ua, djcr);
689 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
697 void apply_pool_overrides(JCR *jcr)
699 bool pool_override = false;
701 if (jcr->run_pool_override) {
702 pm_strcpy(jcr->pool_source, _("Run pool override"));
705 * Apply any level related Pool selections
707 switch (jcr->JobLevel) {
709 if (jcr->full_pool) {
710 jcr->pool = jcr->full_pool;
711 pool_override = true;
712 if (jcr->run_full_pool_override) {
713 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
715 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
721 jcr->pool = jcr->inc_pool;
722 pool_override = true;
723 if (jcr->run_inc_pool_override) {
724 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
726 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
731 if (jcr->diff_pool) {
732 jcr->pool = jcr->diff_pool;
733 pool_override = true;
734 if (jcr->run_diff_pool_override) {
735 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
737 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
742 /* Update catalog if pool overridden */
743 if (pool_override && jcr->pool->catalog) {
744 jcr->catalog = jcr->pool->catalog;
745 pm_strcpy(jcr->catalog_source, _("Pool resource"));
751 * Get or create a Client record for this Job
753 bool get_or_create_client_record(JCR *jcr)
757 memset(&cr, 0, sizeof(cr));
758 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
759 cr.AutoPrune = jcr->client->AutoPrune;
760 cr.FileRetention = jcr->client->FileRetention;
761 cr.JobRetention = jcr->client->JobRetention;
762 if (!jcr->client_name) {
763 jcr->client_name = get_pool_memory(PM_NAME);
765 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
766 if (!db_create_client_record(jcr, jcr->db, &cr)) {
767 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
768 db_strerror(jcr->db));
771 jcr->jr.ClientId = cr.ClientId;
773 if (!jcr->client_uname) {
774 jcr->client_uname = get_pool_memory(PM_NAME);
776 pm_strcpy(jcr->client_uname, cr.Uname);
778 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
783 bool get_or_create_fileset_record(JCR *jcr)
787 * Get or Create FileSet record
789 memset(&fsr, 0, sizeof(FILESET_DBR));
790 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
791 if (jcr->fileset->have_MD5) {
792 struct MD5Context md5c;
793 unsigned char digest[MD5HashSize];
794 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
795 MD5Final(digest, &md5c);
797 * Keep the flag (last arg) set to false otherwise old FileSets will
798 * get new MD5 sums and the user will get Full backups on everything
800 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
801 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
803 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
805 if (!jcr->fileset->ignore_fs_changes ||
806 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
807 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
808 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
809 fsr.FileSet, db_strerror(jcr->db));
813 jcr->jr.FileSetId = fsr.FileSetId;
814 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
815 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
820 void init_jcr_job_record(JCR *jcr)
822 jcr->jr.SchedTime = jcr->sched_time;
823 jcr->jr.StartTime = jcr->start_time;
824 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
825 jcr->jr.JobType = jcr->JobType;
826 jcr->jr.JobLevel = jcr->JobLevel;
827 jcr->jr.JobStatus = jcr->JobStatus;
828 jcr->jr.JobId = jcr->JobId;
829 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
830 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
834 * Write status and such in DB
836 void update_job_end_record(JCR *jcr)
838 jcr->jr.EndTime = time(NULL);
839 jcr->end_time = jcr->jr.EndTime;
840 jcr->jr.JobId = jcr->JobId;
841 jcr->jr.JobStatus = jcr->JobStatus;
842 jcr->jr.JobFiles = jcr->JobFiles;
843 jcr->jr.JobBytes = jcr->JobBytes;
844 jcr->jr.VolSessionId = jcr->VolSessionId;
845 jcr->jr.VolSessionTime = jcr->VolSessionTime;
846 jcr->jr.JobErrors = jcr->Errors;
847 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr, jcr->job->stats_enabled)) {
848 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
849 db_strerror(jcr->db));
854 * Takes base_name and appends (unique) current
855 * date and time to form unique job name.
857 * Note, the seconds are actually a sequence number. This
858 * permits us to start a maximum fo 59 unique jobs a second, which
859 * should be sufficient.
861 * Returns: unique job name in jcr->Job
862 * date/time in jcr->start_time
864 void create_unique_job_name(JCR *jcr, const char *base_name)
866 /* Job start mutex */
867 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
868 static time_t last_start_time = 0;
872 char dt[MAX_TIME_LENGTH];
873 char name[MAX_NAME_LENGTH];
876 /* Guarantee unique start time -- maximum one per second, and
877 * thus unique Job Name
879 P(mutex); /* lock creation of jobs */
882 if (seq > 59) { /* wrap as if it is seconds */
884 while (now == last_start_time) {
885 bmicrosleep(0, 500000);
889 last_start_time = now;
890 V(mutex); /* allow creation of jobs */
891 jcr->start_time = now;
892 /* Form Unique JobName */
893 (void)localtime_r(&now, &tm);
894 /* Use only characters that are permitted in Windows filenames */
895 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
896 bstrncpy(name, base_name, sizeof(name));
897 name[sizeof(name)-22] = 0; /* truncate if too long */
898 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
899 /* Convert spaces into underscores */
900 for (p=jcr->Job; *p; p++) {
907 /* Called directly from job rescheduling */
908 void dird_free_jcr_pointers(JCR *jcr)
910 if (jcr->sd_auth_key) {
911 free(jcr->sd_auth_key);
912 jcr->sd_auth_key = NULL;
918 if (jcr->file_bsock) {
919 Dmsg0(200, "Close File bsock\n");
920 bnet_close(jcr->file_bsock);
921 jcr->file_bsock = NULL;
923 if (jcr->store_bsock) {
924 Dmsg0(200, "Close Store bsock\n");
925 bnet_close(jcr->store_bsock);
926 jcr->store_bsock = NULL;
929 Dmsg0(200, "Free JCR fname\n");
930 free_pool_memory(jcr->fname);
933 if (jcr->RestoreBootstrap) {
934 free(jcr->RestoreBootstrap);
935 jcr->RestoreBootstrap = NULL;
937 if (jcr->client_uname) {
938 free_pool_memory(jcr->client_uname);
939 jcr->client_uname = NULL;
942 free_pool_memory(jcr->attr);
952 * Free the Job Control Record if no one is still using it.
953 * Called from main free_jcr() routine in src/lib/jcr.c so
954 * that we can do our Director specific cleanup of the jcr.
956 void dird_free_jcr(JCR *jcr)
958 Dmsg0(200, "Start dird free_jcr\n");
960 dird_free_jcr_pointers(jcr);
961 if (jcr->term_wait_inited) {
962 pthread_cond_destroy(&jcr->term_wait);
963 jcr->term_wait_inited = false;
965 if (jcr->db_batch && jcr->db_batch != jcr->db) {
966 db_close_database(jcr, jcr->db_batch);
968 jcr->db_batch = NULL;
970 db_close_database(jcr, jcr->db);
974 Dmsg0(200, "Free JCR stime\n");
975 free_pool_memory(jcr->stime);
979 Dmsg0(200, "Free JCR fname\n");
980 free_pool_memory(jcr->fname);
983 if (jcr->pool_source) {
984 free_pool_memory(jcr->pool_source);
985 jcr->pool_source = NULL;
987 if (jcr->catalog_source) {
988 free_pool_memory(jcr->catalog_source);
989 jcr->catalog_source = NULL;
991 if (jcr->rpool_source) {
992 free_pool_memory(jcr->rpool_source);
993 jcr->rpool_source = NULL;
995 if (jcr->wstore_source) {
996 free_pool_memory(jcr->wstore_source);
997 jcr->wstore_source = NULL;
999 if (jcr->rstore_source) {
1000 free_pool_memory(jcr->rstore_source);
1001 jcr->rstore_source = NULL;
1004 /* Delete lists setup to hold storage pointers */
1005 free_rwstorage(jcr);
1007 jcr->job_end_push.destroy();
1009 if (jcr->JobId != 0)
1010 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1012 Dmsg0(200, "End dird free_jcr\n");
1016 * The Job storage definition must be either in the Job record
1017 * or in the Pool record. The Pool record overrides the Job
1020 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1022 if (run && run->pool && run->pool->storage) {
1023 store->store = (STORE *)run->pool->storage->first();
1024 pm_strcpy(store->store_source, _("Run pool override"));
1027 if (run && run->storage) {
1028 store->store = run->storage;
1029 pm_strcpy(store->store_source, _("Run storage override"));
1032 if (job->pool->storage) {
1033 store->store = (STORE *)job->pool->storage->first();
1034 pm_strcpy(store->store_source, _("Pool resource"));
1036 store->store = (STORE *)job->storage->first();
1037 pm_strcpy(store->store_source, _("Job resource"));
1042 * Set some defaults in the JCR necessary to
1043 * run. These items are pulled from the job
1044 * definition as defaults, but can be overridden
1045 * later either by the Run record in the Schedule resource,
1046 * or by the Console program.
1048 void set_jcr_defaults(JCR *jcr, JOB *job)
1051 jcr->JobType = job->JobType;
1052 jcr->JobStatus = JS_Created;
1053 switch (jcr->JobType) {
1055 jcr->JobLevel = L_NONE;
1061 jcr->JobReads = true;
1062 jcr->JobLevel = job->JobLevel;
1065 jcr->JobLevel = job->JobLevel;
1066 if (jcr->JobLevel == L_VIRTUAL_FULL) {
1067 jcr->JobReads = true;
1071 jcr->JobLevel = job->JobLevel;
1074 if (jcr->JobReads) {
1075 if (!jcr->rpool_source) {
1076 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
1077 pm_strcpy(jcr->rpool_source, _("unknown source"));
1081 jcr->fname = get_pool_memory(PM_FNAME);
1083 if (!jcr->pool_source) {
1084 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1085 pm_strcpy(jcr->pool_source, _("unknown source"));
1087 if (!jcr->catalog_source) {
1088 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1089 pm_strcpy(jcr->catalog_source, _("unknown source"));
1092 jcr->JobPriority = job->Priority;
1093 /* Copy storage definitions -- deleted in dir_free_jcr above */
1095 copy_rwstorage(jcr, job->storage, _("Job resource"));
1097 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1099 jcr->client = job->client;
1100 if (!jcr->client_name) {
1101 jcr->client_name = get_pool_memory(PM_NAME);
1103 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1104 pm_strcpy(jcr->pool_source, _("Job resource"));
1105 jcr->pool = job->pool;
1106 jcr->full_pool = job->full_pool;
1107 jcr->inc_pool = job->inc_pool;
1108 jcr->diff_pool = job->diff_pool;
1109 if (job->pool->catalog) {
1110 jcr->catalog = job->pool->catalog;
1111 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1113 jcr->catalog = job->client->catalog;
1114 pm_strcpy(jcr->catalog_source, _("Client resource"));
1116 jcr->fileset = job->fileset;
1117 jcr->messages = job->messages;
1118 jcr->spool_data = job->spool_data;
1119 jcr->spool_size = job->spool_size;
1120 jcr->write_part_after_job = job->write_part_after_job;
1121 jcr->accurate = job->accurate;
1122 if (jcr->RestoreBootstrap) {
1123 free(jcr->RestoreBootstrap);
1124 jcr->RestoreBootstrap = NULL;
1126 /* This can be overridden by Console program */
1127 if (job->RestoreBootstrap) {
1128 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1130 /* This can be overridden by Console program */
1131 jcr->verify_job = job->verify_job;
1132 /* If no default level given, set one */
1133 if (jcr->JobLevel == 0) {
1134 switch (jcr->JobType) {
1136 jcr->JobLevel = L_VERIFY_CATALOG;
1139 jcr->JobLevel = L_INCREMENTAL;
1143 jcr->JobLevel = L_NONE;
1146 jcr->JobLevel = L_FULL;
1153 * Copy the storage definitions from an alist to the JCR
1155 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1157 if (jcr->JobReads) {
1158 copy_rstorage(jcr, storage, where);
1160 copy_wstorage(jcr, storage, where);
1165 /* Set storage override. Releases any previous storage definition */
1166 void set_rwstorage(JCR *jcr, USTORE *store)
1169 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1172 if (jcr->JobReads) {
1173 set_rstorage(jcr, store);
1175 set_wstorage(jcr, store);
1179 void free_rwstorage(JCR *jcr)
1186 * Copy the storage definitions from an alist to the JCR
1188 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1192 if (jcr->rstorage) {
1193 delete jcr->rstorage;
1195 jcr->rstorage = New(alist(10, not_owned_by_alist));
1196 foreach_alist(st, storage) {
1197 jcr->rstorage->append(st);
1199 if (!jcr->rstore_source) {
1200 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1202 pm_strcpy(jcr->rstore_source, where);
1203 if (jcr->rstorage) {
1204 jcr->rstore = (STORE *)jcr->rstorage->first();
1210 /* Set storage override. Remove all previous storage */
1211 void set_rstorage(JCR *jcr, USTORE *store)
1215 if (!store->store) {
1218 if (jcr->rstorage) {
1221 if (!jcr->rstorage) {
1222 jcr->rstorage = New(alist(10, not_owned_by_alist));
1224 jcr->rstore = store->store;
1225 if (!jcr->rstore_source) {
1226 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1228 pm_strcpy(jcr->rstore_source, store->store_source);
1229 foreach_alist(storage, jcr->rstorage) {
1230 if (store->store == storage) {
1234 /* Store not in list, so add it */
1235 jcr->rstorage->prepend(store->store);
1238 void free_rstorage(JCR *jcr)
1240 if (jcr->rstorage) {
1241 delete jcr->rstorage;
1242 jcr->rstorage = NULL;
1248 * Copy the storage definitions from an alist to the JCR
1250 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1254 if (jcr->wstorage) {
1255 delete jcr->wstorage;
1257 jcr->wstorage = New(alist(10, not_owned_by_alist));
1258 foreach_alist(st, storage) {
1259 Dmsg1(100, "wstorage=%s\n", st->name());
1260 jcr->wstorage->append(st);
1262 if (!jcr->wstore_source) {
1263 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1265 pm_strcpy(jcr->wstore_source, where);
1266 if (jcr->wstorage) {
1267 jcr->wstore = (STORE *)jcr->wstorage->first();
1268 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1274 /* Set storage override. Remove all previous storage */
1275 void set_wstorage(JCR *jcr, USTORE *store)
1279 if (!store->store) {
1282 if (jcr->wstorage) {
1285 if (!jcr->wstorage) {
1286 jcr->wstorage = New(alist(10, not_owned_by_alist));
1288 jcr->wstore = store->store;
1289 if (!jcr->wstore_source) {
1290 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1292 pm_strcpy(jcr->wstore_source, store->store_source);
1293 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1294 foreach_alist(storage, jcr->wstorage) {
1295 if (store->store == storage) {
1299 /* Store not in list, so add it */
1300 jcr->wstorage->prepend(store->store);
1303 void free_wstorage(JCR *jcr)
1305 if (jcr->wstorage) {
1306 delete jcr->wstorage;
1307 jcr->wstorage = NULL;
1312 char *job_code_callback_clones(JCR *jcr, const char* param)
1314 if (param[0] == 'p') {
1315 return jcr->pool->name();
1320 void create_clones(JCR *jcr)
1323 * Fire off any clone jobs (run directives)
1325 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1326 if (!jcr->cloned && jcr->job->run_cmds) {
1328 JOB *job = jcr->job;
1329 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1330 UAContext *ua = new_ua_context(jcr);
1332 foreach_alist(runcmd, job->run_cmds) {
1333 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1334 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1335 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1336 parse_ua_args(ua); /* parse command */
1337 int stat = run_cmd(ua, ua->cmd);
1339 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1341 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1344 free_ua_context(ua);
1345 free_pool_memory(cmd);
1350 * Given: a JobId in jcr->previous_jr.JobId,
1351 * this subroutine writes a bsr file to restore that job.
1353 bool create_restore_bootstrap_file(JCR *jcr)
1357 memset(&rx, 0, sizeof(rx));
1359 rx.JobIds = (char *)"";
1360 rx.bsr->JobId = jcr->previous_jr.JobId;
1361 ua = new_ua_context(jcr);
1362 complete_bsr(ua, rx.bsr);
1363 rx.bsr->fi = new_findex();
1364 rx.bsr->fi->findex = 1;
1365 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1366 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1367 if (jcr->ExpectedFiles == 0) {
1368 free_ua_context(ua);
1372 free_ua_context(ua);
1374 jcr->needs_sd = true;
1378 bool run_console_command(JCR *jcr, const char *cmd){
1382 ua = new_ua_context(jcr);
1383 Mmsg(ua->cmd, "%s", cmd);
1384 Dmsg1(100, "Console command: %s\n", ua->cmd);
1386 ok= do_a_command(ua);
1387 free_ua_context(ua);