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"));
152 if (jcr->JobReads()) {
153 if (!jcr->rpool_source) {
154 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
155 pm_strcpy(jcr->rpool_source, _("unknown source"));
162 init_jcr_job_record(jcr);
163 if (!get_or_create_client_record(jcr)) {
167 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
168 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
171 jcr->JobId = jcr->jr.JobId;
172 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
173 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
175 generate_daemon_event(jcr, "JobStart");
177 if (job_canceled(jcr)) {
181 if (jcr->JobReads() && !jcr->rstorage) {
182 if (jcr->job->storage) {
183 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
185 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
188 if (!jcr->JobReads()) {
193 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
194 * this allows us to setup a proper job start record for restarting
195 * in case of later errors.
197 switch (jcr->get_JobType()) {
199 if (!do_backup_init(jcr)) {
200 backup_cleanup(jcr, JS_ErrorTerminated);
204 if (!do_verify_init(jcr)) {
205 verify_cleanup(jcr, JS_ErrorTerminated);
209 if (!do_restore_init(jcr)) {
210 restore_cleanup(jcr, JS_ErrorTerminated);
214 if (!do_admin_init(jcr)) {
215 admin_cleanup(jcr, JS_ErrorTerminated);
220 if (!do_migration_init(jcr)) {
221 migration_cleanup(jcr, JS_ErrorTerminated);
225 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
226 set_jcr_job_status(jcr, JS_ErrorTerminated);
230 generate_job_event(jcr, "JobInit");
238 void update_job_end(JCR *jcr, int TermCode)
240 dequeue_messages(jcr); /* display any queued messages */
241 set_jcr_job_status(jcr, TermCode);
242 update_job_end_record(jcr);
246 * This is the engine called by jobq.c:jobq_add() when we were pulled
247 * from the work queue.
248 * At this point, we are running in our own thread and all
249 * necessary resources are allocated -- see jobq.c
251 static void *job_thread(void *arg)
253 JCR *jcr = (JCR *)arg;
255 pthread_detach(pthread_self());
258 Dmsg0(200, "=====Start Job=========\n");
259 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
260 jcr->start_time = time(NULL); /* set the real start time */
261 jcr->jr.StartTime = jcr->start_time;
263 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
264 (utime_t)(jcr->start_time - jcr->sched_time)) {
265 set_jcr_job_status(jcr, JS_Canceled);
266 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
269 if (job_check_maxschedruntime(jcr)) {
270 set_jcr_job_status(jcr, JS_Canceled);
271 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
274 /* TODO : check if it is used somewhere */
275 if (jcr->job->RunScripts == NULL) {
276 Dmsg0(200, "Warning, job->RunScripts is empty\n");
277 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
280 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
281 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
284 /* Run any script BeforeJob on dird */
285 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
287 if (job_canceled(jcr)) {
288 update_job_end(jcr, jcr->JobStatus);
292 * We re-update the job start record so that the start
293 * time is set after the run before job. This avoids
294 * that any files created by the run before job will
295 * be saved twice. They will be backed up in the current
296 * job, but not in the next one unless they are changed.
297 * Without this, they will be backed up in this job and
298 * in the next job run because in that case, their date
299 * is after the start of this run.
301 jcr->start_time = time(NULL);
302 jcr->jr.StartTime = jcr->start_time;
303 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
304 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
306 generate_job_event(jcr, "JobRun");
308 switch (jcr->get_JobType()) {
310 if (do_backup(jcr)) {
313 backup_cleanup(jcr, JS_ErrorTerminated);
317 if (do_verify(jcr)) {
320 verify_cleanup(jcr, JS_ErrorTerminated);
324 if (do_restore(jcr)) {
327 restore_cleanup(jcr, JS_ErrorTerminated);
334 admin_cleanup(jcr, JS_ErrorTerminated);
339 if (do_migration(jcr)) {
342 migration_cleanup(jcr, JS_ErrorTerminated);
346 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
351 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
353 /* Send off any queued messages */
354 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
355 dequeue_messages(jcr);
358 generate_daemon_event(jcr, "JobEnd");
359 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
360 sm_check(__FILE__, __LINE__, true);
366 * Cancel a job -- typically called by the UA (Console program), but may also
367 * be called by the job watchdog.
369 * Returns: true if cancel appears to be successful
370 * false on failure. Message sent to ua->jcr.
372 bool cancel_job(UAContext *ua, JCR *jcr)
377 set_jcr_job_status(jcr, JS_Canceled);
379 switch (jcr->JobStatus) {
382 case JS_WaitClientRes:
383 case JS_WaitStoreRes:
384 case JS_WaitPriority:
386 case JS_WaitStartTime:
387 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
388 edit_uint64(jcr->JobId, ed1), jcr->Job);
389 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
393 /* Cancel File daemon */
394 if (jcr->file_bsock) {
395 ua->jcr->client = jcr->client;
396 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
397 ua->error_msg(_("Failed to connect to File daemon.\n"));
400 Dmsg0(200, "Connected to file daemon\n");
401 fd = ua->jcr->file_bsock;
402 fd->fsend("cancel Job=%s\n", jcr->Job);
403 while (fd->recv() >= 0) {
404 ua->send_msg("%s", fd->msg);
406 fd->signal(BNET_TERMINATE);
408 ua->jcr->file_bsock = NULL;
411 /* Cancel Storage daemon */
412 if (jcr->store_bsock) {
413 if (!ua->jcr->wstorage) {
415 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
417 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
422 store.store = jcr->rstore;
424 store.store = jcr->wstore;
426 set_wstorage(ua->jcr, &store);
429 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
430 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
433 Dmsg0(200, "Connected to storage daemon\n");
434 sd = ua->jcr->store_bsock;
435 sd->fsend("cancel Job=%s\n", jcr->Job);
436 while (sd->recv() >= 0) {
437 ua->send_msg("%s", sd->msg);
439 sd->signal(BNET_TERMINATE);
441 ua->jcr->store_bsock = NULL;
448 void cancel_storage_daemon_job(JCR *jcr)
450 UAContext *ua = new_ua_context(jcr);
451 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
454 ua->jcr = control_jcr;
455 if (jcr->store_bsock) {
456 if (!ua->jcr->wstorage) {
458 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
460 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
465 store.store = jcr->rstore;
467 store.store = jcr->wstore;
469 set_wstorage(ua->jcr, &store);
472 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
475 Dmsg0(200, "Connected to storage daemon\n");
476 sd = ua->jcr->store_bsock;
477 sd->fsend("cancel Job=%s\n", jcr->Job);
478 while (sd->recv() >= 0) {
480 sd->signal(BNET_TERMINATE);
482 ua->jcr->store_bsock = NULL;
485 free_jcr(control_jcr);
489 static void job_monitor_destructor(watchdog_t *self)
491 JCR *control_jcr = (JCR *)self->data;
493 free_jcr(control_jcr);
496 static void job_monitor_watchdog(watchdog_t *self)
498 JCR *control_jcr, *jcr;
500 control_jcr = (JCR *)self->data;
503 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
508 if (jcr->JobId == 0 || job_canceled(jcr)) {
509 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
513 /* check MaxWaitTime */
514 if (job_check_maxwaittime(jcr)) {
515 set_jcr_job_status(jcr, JS_Canceled);
516 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
518 /* check MaxRunTime */
519 } else if (job_check_maxruntime(jcr)) {
520 set_jcr_job_status(jcr, JS_Canceled);
521 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
523 /* check MaxRunSchedTime */
524 } else if (job_check_maxschedruntime(jcr)) {
525 set_jcr_job_status(jcr, JS_Canceled);
526 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
531 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
532 UAContext *ua = new_ua_context(jcr);
533 ua->jcr = control_jcr;
536 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
540 /* Keep reference counts correct */
545 * Check if the maxwaittime has expired and it is possible
548 static bool job_check_maxwaittime(JCR *jcr)
553 if (!job_waiting(jcr)) {
556 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
557 if (job->MaxWaitTime != 0 &&
558 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
566 * Check if maxruntime has expired and if the job can be
569 static bool job_check_maxruntime(JCR *jcr)
574 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
577 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
578 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
581 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
582 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
583 job->IncMaxRunTime, job->DiffMaxRunTime);
585 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
586 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
588 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
589 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
591 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
592 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
594 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
602 * Check if MaxRunSchedTime has expired and if the job can be
605 static bool job_check_maxschedruntime(JCR *jcr)
607 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
610 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
611 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
612 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
620 * Get or create a Pool record with the given name.
621 * Returns: 0 on error
624 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
628 memset(&pr, 0, sizeof(pr));
629 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
630 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
632 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
633 /* Try to create the pool */
634 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
635 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
636 db_strerror(jcr->db));
639 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
646 * Check for duplicate jobs.
647 * Returns: true if current job should continue
648 * false if current job should terminate
650 bool allow_duplicate_job(JCR *jcr)
653 JCR *djcr; /* possible duplicate */
655 if (job->AllowDuplicateJobs) {
658 if (!job->AllowHigherDuplicates) {
661 if (strcmp(job->name(), djcr->job->name()) == 0) {
662 bool cancel_queued = false;
663 if (job->DuplicateJobProximity > 0) {
664 time_t now = time(NULL);
665 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
666 continue; /* not really a duplicate */
670 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
671 /* Zap current job */
672 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
673 edit_uint64(djcr->JobId, ec1));
676 /* If CancelQueuedDuplicates is set do so only if job is queued */
677 if (job->CancelQueuedDuplicates) {
678 switch (djcr->JobStatus) {
681 case JS_WaitClientRes:
682 case JS_WaitStoreRes:
683 case JS_WaitPriority:
685 case JS_WaitStartTime:
686 cancel_queued = true;
692 if (cancel_queued || job->CancelRunningDuplicates) {
693 UAContext *ua = new_ua_context(djcr);
694 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
695 edit_uint64(djcr->JobId, ec1));
697 cancel_job(ua, djcr);
699 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
707 void apply_pool_overrides(JCR *jcr)
709 bool pool_override = false;
711 if (jcr->run_pool_override) {
712 pm_strcpy(jcr->pool_source, _("Run pool override"));
715 * Apply any level related Pool selections
717 switch (jcr->get_JobLevel()) {
719 if (jcr->full_pool) {
720 jcr->pool = jcr->full_pool;
721 pool_override = true;
722 if (jcr->run_full_pool_override) {
723 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
725 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
731 jcr->pool = jcr->inc_pool;
732 pool_override = true;
733 if (jcr->run_inc_pool_override) {
734 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
736 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
741 if (jcr->diff_pool) {
742 jcr->pool = jcr->diff_pool;
743 pool_override = true;
744 if (jcr->run_diff_pool_override) {
745 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
747 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
752 /* Update catalog if pool overridden */
753 if (pool_override && jcr->pool->catalog) {
754 jcr->catalog = jcr->pool->catalog;
755 pm_strcpy(jcr->catalog_source, _("Pool resource"));
761 * Get or create a Client record for this Job
763 bool get_or_create_client_record(JCR *jcr)
767 memset(&cr, 0, sizeof(cr));
768 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
769 cr.AutoPrune = jcr->client->AutoPrune;
770 cr.FileRetention = jcr->client->FileRetention;
771 cr.JobRetention = jcr->client->JobRetention;
772 if (!jcr->client_name) {
773 jcr->client_name = get_pool_memory(PM_NAME);
775 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
776 if (!db_create_client_record(jcr, jcr->db, &cr)) {
777 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
778 db_strerror(jcr->db));
781 jcr->jr.ClientId = cr.ClientId;
783 if (!jcr->client_uname) {
784 jcr->client_uname = get_pool_memory(PM_NAME);
786 pm_strcpy(jcr->client_uname, cr.Uname);
788 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
793 bool get_or_create_fileset_record(JCR *jcr)
797 * Get or Create FileSet record
799 memset(&fsr, 0, sizeof(FILESET_DBR));
800 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
801 if (jcr->fileset->have_MD5) {
802 struct MD5Context md5c;
803 unsigned char digest[MD5HashSize];
804 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
805 MD5Final(digest, &md5c);
807 * Keep the flag (last arg) set to false otherwise old FileSets will
808 * get new MD5 sums and the user will get Full backups on everything
810 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
811 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
813 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
815 if (!jcr->fileset->ignore_fs_changes ||
816 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
817 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
818 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
819 fsr.FileSet, db_strerror(jcr->db));
823 jcr->jr.FileSetId = fsr.FileSetId;
824 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
825 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
830 void init_jcr_job_record(JCR *jcr)
832 jcr->jr.SchedTime = jcr->sched_time;
833 jcr->jr.StartTime = jcr->start_time;
834 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
835 jcr->jr.JobType = jcr->get_JobType();
836 jcr->jr.JobLevel = jcr->get_JobLevel();
837 jcr->jr.JobStatus = jcr->JobStatus;
838 jcr->jr.JobId = jcr->JobId;
839 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
840 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
844 * Write status and such in DB
846 void update_job_end_record(JCR *jcr)
848 jcr->jr.EndTime = time(NULL);
849 jcr->end_time = jcr->jr.EndTime;
850 jcr->jr.JobId = jcr->JobId;
851 jcr->jr.JobStatus = jcr->JobStatus;
852 jcr->jr.JobFiles = jcr->JobFiles;
853 jcr->jr.JobBytes = jcr->JobBytes;
854 jcr->jr.VolSessionId = jcr->VolSessionId;
855 jcr->jr.VolSessionTime = jcr->VolSessionTime;
856 jcr->jr.JobErrors = jcr->Errors;
857 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
858 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
859 db_strerror(jcr->db));
864 * Takes base_name and appends (unique) current
865 * date and time to form unique job name.
867 * Note, the seconds are actually a sequence number. This
868 * permits us to start a maximum fo 59 unique jobs a second, which
869 * should be sufficient.
871 * Returns: unique job name in jcr->Job
872 * date/time in jcr->start_time
874 void create_unique_job_name(JCR *jcr, const char *base_name)
876 /* Job start mutex */
877 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
878 static time_t last_start_time = 0;
882 char dt[MAX_TIME_LENGTH];
883 char name[MAX_NAME_LENGTH];
886 /* Guarantee unique start time -- maximum one per second, and
887 * thus unique Job Name
889 P(mutex); /* lock creation of jobs */
892 if (seq > 59) { /* wrap as if it is seconds */
894 while (now == last_start_time) {
895 bmicrosleep(0, 500000);
899 last_start_time = now;
900 V(mutex); /* allow creation of jobs */
901 jcr->start_time = now;
902 /* Form Unique JobName */
903 (void)localtime_r(&now, &tm);
904 /* Use only characters that are permitted in Windows filenames */
905 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
906 bstrncpy(name, base_name, sizeof(name));
907 name[sizeof(name)-22] = 0; /* truncate if too long */
908 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
909 /* Convert spaces into underscores */
910 for (p=jcr->Job; *p; p++) {
917 /* Called directly from job rescheduling */
918 void dird_free_jcr_pointers(JCR *jcr)
920 if (jcr->sd_auth_key) {
921 free(jcr->sd_auth_key);
922 jcr->sd_auth_key = NULL;
928 if (jcr->file_bsock) {
929 Dmsg0(200, "Close File bsock\n");
930 bnet_close(jcr->file_bsock);
931 jcr->file_bsock = NULL;
933 if (jcr->store_bsock) {
934 Dmsg0(200, "Close Store bsock\n");
935 bnet_close(jcr->store_bsock);
936 jcr->store_bsock = NULL;
939 Dmsg0(200, "Free JCR fname\n");
940 free_pool_memory(jcr->fname);
943 if (jcr->RestoreBootstrap) {
944 free(jcr->RestoreBootstrap);
945 jcr->RestoreBootstrap = NULL;
947 if (jcr->client_uname) {
948 free_pool_memory(jcr->client_uname);
949 jcr->client_uname = NULL;
952 free_pool_memory(jcr->attr);
962 * Free the Job Control Record if no one is still using it.
963 * Called from main free_jcr() routine in src/lib/jcr.c so
964 * that we can do our Director specific cleanup of the jcr.
966 void dird_free_jcr(JCR *jcr)
968 Dmsg0(200, "Start dird free_jcr\n");
970 dird_free_jcr_pointers(jcr);
971 if (jcr->term_wait_inited) {
972 pthread_cond_destroy(&jcr->term_wait);
973 jcr->term_wait_inited = false;
976 db_close_database(jcr, jcr->db_batch);
977 jcr->db_batch = NULL;
978 jcr->batch_started = false;
981 db_close_database(jcr, jcr->db);
985 Dmsg0(200, "Free JCR stime\n");
986 free_pool_memory(jcr->stime);
990 Dmsg0(200, "Free JCR fname\n");
991 free_pool_memory(jcr->fname);
994 if (jcr->pool_source) {
995 free_pool_memory(jcr->pool_source);
996 jcr->pool_source = NULL;
998 if (jcr->catalog_source) {
999 free_pool_memory(jcr->catalog_source);
1000 jcr->catalog_source = NULL;
1002 if (jcr->rpool_source) {
1003 free_pool_memory(jcr->rpool_source);
1004 jcr->rpool_source = NULL;
1006 if (jcr->wstore_source) {
1007 free_pool_memory(jcr->wstore_source);
1008 jcr->wstore_source = NULL;
1010 if (jcr->rstore_source) {
1011 free_pool_memory(jcr->rstore_source);
1012 jcr->rstore_source = NULL;
1015 /* Delete lists setup to hold storage pointers */
1016 free_rwstorage(jcr);
1018 jcr->job_end_push.destroy();
1020 if (jcr->JobId != 0)
1021 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1023 Dmsg0(200, "End dird free_jcr\n");
1027 * The Job storage definition must be either in the Job record
1028 * or in the Pool record. The Pool record overrides the Job
1031 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1033 if (run && run->pool && run->pool->storage) {
1034 store->store = (STORE *)run->pool->storage->first();
1035 pm_strcpy(store->store_source, _("Run pool override"));
1038 if (run && run->storage) {
1039 store->store = run->storage;
1040 pm_strcpy(store->store_source, _("Run storage override"));
1043 if (job->pool->storage) {
1044 store->store = (STORE *)job->pool->storage->first();
1045 pm_strcpy(store->store_source, _("Pool resource"));
1047 store->store = (STORE *)job->storage->first();
1048 pm_strcpy(store->store_source, _("Job resource"));
1053 * Set some defaults in the JCR necessary to
1054 * run. These items are pulled from the job
1055 * definition as defaults, but can be overridden
1056 * later either by the Run record in the Schedule resource,
1057 * or by the Console program.
1059 void set_jcr_defaults(JCR *jcr, JOB *job)
1062 jcr->set_JobType(job->JobType);
1063 jcr->JobStatus = JS_Created;
1065 switch (jcr->get_JobType()) {
1067 jcr->set_JobLevel(L_NONE);
1070 jcr->set_JobLevel(job->JobLevel);
1075 jcr->fname = get_pool_memory(PM_FNAME);
1077 if (!jcr->pool_source) {
1078 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1079 pm_strcpy(jcr->pool_source, _("unknown source"));
1081 if (!jcr->catalog_source) {
1082 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1083 pm_strcpy(jcr->catalog_source, _("unknown source"));
1086 jcr->JobPriority = job->Priority;
1087 /* Copy storage definitions -- deleted in dir_free_jcr above */
1089 copy_rwstorage(jcr, job->storage, _("Job resource"));
1091 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1093 jcr->client = job->client;
1094 if (!jcr->client_name) {
1095 jcr->client_name = get_pool_memory(PM_NAME);
1097 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1098 pm_strcpy(jcr->pool_source, _("Job resource"));
1099 jcr->pool = job->pool;
1100 jcr->full_pool = job->full_pool;
1101 jcr->inc_pool = job->inc_pool;
1102 jcr->diff_pool = job->diff_pool;
1103 if (job->pool->catalog) {
1104 jcr->catalog = job->pool->catalog;
1105 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1107 jcr->catalog = job->client->catalog;
1108 pm_strcpy(jcr->catalog_source, _("Client resource"));
1110 jcr->fileset = job->fileset;
1111 jcr->messages = job->messages;
1112 jcr->spool_data = job->spool_data;
1113 jcr->spool_size = job->spool_size;
1114 jcr->write_part_after_job = job->write_part_after_job;
1115 jcr->accurate = job->accurate;
1116 if (jcr->RestoreBootstrap) {
1117 free(jcr->RestoreBootstrap);
1118 jcr->RestoreBootstrap = NULL;
1120 /* This can be overridden by Console program */
1121 if (job->RestoreBootstrap) {
1122 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1124 /* This can be overridden by Console program */
1125 jcr->verify_job = job->verify_job;
1126 /* If no default level given, set one */
1127 if (jcr->get_JobLevel() == 0) {
1128 switch (jcr->get_JobType()) {
1130 jcr->set_JobLevel(L_VERIFY_CATALOG);
1133 jcr->set_JobLevel(L_INCREMENTAL);
1137 jcr->set_JobLevel(L_NONE);
1140 jcr->set_JobLevel(L_FULL);
1147 * Copy the storage definitions from an alist to the JCR
1149 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1151 if (jcr->JobReads()) {
1152 copy_rstorage(jcr, storage, where);
1154 copy_wstorage(jcr, storage, where);
1158 /* Set storage override. Releases any previous storage definition */
1159 void set_rwstorage(JCR *jcr, USTORE *store)
1162 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1165 if (jcr->JobReads()) {
1166 set_rstorage(jcr, store);
1168 set_wstorage(jcr, store);
1171 void free_rwstorage(JCR *jcr)
1178 * Copy the storage definitions from an alist to the JCR
1180 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1184 if (jcr->rstorage) {
1185 delete jcr->rstorage;
1187 jcr->rstorage = New(alist(10, not_owned_by_alist));
1188 foreach_alist(st, storage) {
1189 jcr->rstorage->append(st);
1191 if (!jcr->rstore_source) {
1192 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1194 pm_strcpy(jcr->rstore_source, where);
1195 if (jcr->rstorage) {
1196 jcr->rstore = (STORE *)jcr->rstorage->first();
1202 /* Set storage override. Remove all previous storage */
1203 void set_rstorage(JCR *jcr, USTORE *store)
1207 if (!store->store) {
1210 if (jcr->rstorage) {
1213 if (!jcr->rstorage) {
1214 jcr->rstorage = New(alist(10, not_owned_by_alist));
1216 jcr->rstore = store->store;
1217 if (!jcr->rstore_source) {
1218 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1220 pm_strcpy(jcr->rstore_source, store->store_source);
1221 foreach_alist(storage, jcr->rstorage) {
1222 if (store->store == storage) {
1226 /* Store not in list, so add it */
1227 jcr->rstorage->prepend(store->store);
1230 void free_rstorage(JCR *jcr)
1232 if (jcr->rstorage) {
1233 delete jcr->rstorage;
1234 jcr->rstorage = NULL;
1240 * Copy the storage definitions from an alist to the JCR
1242 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1246 if (jcr->wstorage) {
1247 delete jcr->wstorage;
1249 jcr->wstorage = New(alist(10, not_owned_by_alist));
1250 foreach_alist(st, storage) {
1251 Dmsg1(100, "wstorage=%s\n", st->name());
1252 jcr->wstorage->append(st);
1254 if (!jcr->wstore_source) {
1255 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1257 pm_strcpy(jcr->wstore_source, where);
1258 if (jcr->wstorage) {
1259 jcr->wstore = (STORE *)jcr->wstorage->first();
1260 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1266 /* Set storage override. Remove all previous storage */
1267 void set_wstorage(JCR *jcr, USTORE *store)
1271 if (!store->store) {
1274 if (jcr->wstorage) {
1277 if (!jcr->wstorage) {
1278 jcr->wstorage = New(alist(10, not_owned_by_alist));
1280 jcr->wstore = store->store;
1281 if (!jcr->wstore_source) {
1282 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1284 pm_strcpy(jcr->wstore_source, store->store_source);
1285 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1286 foreach_alist(storage, jcr->wstorage) {
1287 if (store->store == storage) {
1291 /* Store not in list, so add it */
1292 jcr->wstorage->prepend(store->store);
1295 void free_wstorage(JCR *jcr)
1297 if (jcr->wstorage) {
1298 delete jcr->wstorage;
1299 jcr->wstorage = NULL;
1304 char *job_code_callback_clones(JCR *jcr, const char* param)
1306 if (param[0] == 'p') {
1307 return jcr->pool->name();
1312 void create_clones(JCR *jcr)
1315 * Fire off any clone jobs (run directives)
1317 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1318 if (!jcr->cloned && jcr->job->run_cmds) {
1320 JOB *job = jcr->job;
1321 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1322 UAContext *ua = new_ua_context(jcr);
1324 foreach_alist(runcmd, job->run_cmds) {
1325 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1326 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1327 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1328 parse_ua_args(ua); /* parse command */
1329 int stat = run_cmd(ua, ua->cmd);
1331 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1333 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1336 free_ua_context(ua);
1337 free_pool_memory(cmd);
1342 * Given: a JobId in jcr->previous_jr.JobId,
1343 * this subroutine writes a bsr file to restore that job.
1345 bool create_restore_bootstrap_file(JCR *jcr)
1349 memset(&rx, 0, sizeof(rx));
1351 rx.JobIds = (char *)"";
1352 rx.bsr->JobId = jcr->previous_jr.JobId;
1353 ua = new_ua_context(jcr);
1354 complete_bsr(ua, rx.bsr);
1355 rx.bsr->fi = new_findex();
1356 rx.bsr->fi->findex = 1;
1357 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1358 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1359 if (jcr->ExpectedFiles == 0) {
1360 free_ua_context(ua);
1364 free_ua_context(ua);
1366 jcr->needs_sd = true;
1370 bool run_console_command(JCR *jcr, const char *cmd){
1374 ua = new_ua_context(jcr);
1375 Mmsg(ua->cmd, "%s", cmd);
1376 Dmsg1(100, "Console command: %s\n", ua->cmd);
1378 ok= do_a_command(ua);
1379 free_ua_context(ua);