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)
376 int32_t old_status = jcr->JobStatus;
378 set_jcr_job_status(jcr, JS_Canceled);
380 switch (old_status) {
383 case JS_WaitClientRes:
384 case JS_WaitStoreRes:
385 case JS_WaitPriority:
387 case JS_WaitStartTime:
388 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
389 edit_uint64(jcr->JobId, ed1), jcr->Job);
390 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
394 /* Cancel File daemon */
395 if (jcr->file_bsock) {
396 ua->jcr->client = jcr->client;
397 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
398 ua->error_msg(_("Failed to connect to File daemon.\n"));
401 Dmsg0(200, "Connected to file daemon\n");
402 fd = ua->jcr->file_bsock;
403 fd->fsend("cancel Job=%s\n", jcr->Job);
404 while (fd->recv() >= 0) {
405 ua->send_msg("%s", fd->msg);
407 fd->signal(BNET_TERMINATE);
409 ua->jcr->file_bsock = NULL;
412 /* Cancel Storage daemon */
413 if (jcr->store_bsock) {
414 if (!ua->jcr->wstorage) {
416 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
418 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
423 store.store = jcr->rstore;
425 store.store = jcr->wstore;
427 set_wstorage(ua->jcr, &store);
430 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
431 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
434 Dmsg0(200, "Connected to storage daemon\n");
435 sd = ua->jcr->store_bsock;
436 sd->fsend("cancel Job=%s\n", jcr->Job);
437 while (sd->recv() >= 0) {
438 ua->send_msg("%s", sd->msg);
440 sd->signal(BNET_TERMINATE);
442 ua->jcr->store_bsock = NULL;
449 void cancel_storage_daemon_job(JCR *jcr)
451 UAContext *ua = new_ua_context(jcr);
452 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
455 ua->jcr = control_jcr;
456 if (jcr->store_bsock) {
457 if (!ua->jcr->wstorage) {
459 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
461 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
466 store.store = jcr->rstore;
468 store.store = jcr->wstore;
470 set_wstorage(ua->jcr, &store);
473 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
476 Dmsg0(200, "Connected to storage daemon\n");
477 sd = ua->jcr->store_bsock;
478 sd->fsend("cancel Job=%s\n", jcr->Job);
479 while (sd->recv() >= 0) {
481 sd->signal(BNET_TERMINATE);
483 ua->jcr->store_bsock = NULL;
486 free_jcr(control_jcr);
490 static void job_monitor_destructor(watchdog_t *self)
492 JCR *control_jcr = (JCR *)self->data;
494 free_jcr(control_jcr);
497 static void job_monitor_watchdog(watchdog_t *self)
499 JCR *control_jcr, *jcr;
501 control_jcr = (JCR *)self->data;
504 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
509 if (jcr->JobId == 0 || job_canceled(jcr)) {
510 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
514 /* check MaxWaitTime */
515 if (job_check_maxwaittime(jcr)) {
516 set_jcr_job_status(jcr, JS_Canceled);
517 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
519 /* check MaxRunTime */
520 } else if (job_check_maxruntime(jcr)) {
521 set_jcr_job_status(jcr, JS_Canceled);
522 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
524 /* check MaxRunSchedTime */
525 } else if (job_check_maxschedruntime(jcr)) {
526 set_jcr_job_status(jcr, JS_Canceled);
527 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
532 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
533 UAContext *ua = new_ua_context(jcr);
534 ua->jcr = control_jcr;
537 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
541 /* Keep reference counts correct */
546 * Check if the maxwaittime has expired and it is possible
549 static bool job_check_maxwaittime(JCR *jcr)
554 if (!job_waiting(jcr)) {
557 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
558 if (job->MaxWaitTime != 0 &&
559 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
567 * Check if maxruntime has expired and if the job can be
570 static bool job_check_maxruntime(JCR *jcr)
575 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
578 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
579 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
582 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
583 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
584 job->IncMaxRunTime, job->DiffMaxRunTime);
586 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
587 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
589 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
590 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
592 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
593 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
595 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
603 * Check if MaxRunSchedTime has expired and if the job can be
606 static bool job_check_maxschedruntime(JCR *jcr)
608 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
611 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
612 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
613 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
621 * Get or create a Pool record with the given name.
622 * Returns: 0 on error
625 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
629 memset(&pr, 0, sizeof(pr));
630 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
631 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
633 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
634 /* Try to create the pool */
635 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
636 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
637 db_strerror(jcr->db));
640 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
647 * Check for duplicate jobs.
648 * Returns: true if current job should continue
649 * false if current job should terminate
651 bool allow_duplicate_job(JCR *jcr)
654 JCR *djcr; /* possible duplicate */
656 if (job->AllowDuplicateJobs) {
659 if (!job->AllowHigherDuplicates) {
662 if (strcmp(job->name(), djcr->job->name()) == 0) {
663 bool cancel_queued = false;
664 if (job->DuplicateJobProximity > 0) {
665 time_t now = time(NULL);
666 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
667 continue; /* not really a duplicate */
671 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
672 /* Zap current job */
673 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
674 edit_uint64(djcr->JobId, ec1));
677 /* If CancelQueuedDuplicates is set do so only if job is queued */
678 if (job->CancelQueuedDuplicates) {
679 switch (djcr->JobStatus) {
682 case JS_WaitClientRes:
683 case JS_WaitStoreRes:
684 case JS_WaitPriority:
686 case JS_WaitStartTime:
687 cancel_queued = true;
693 if (cancel_queued || job->CancelRunningDuplicates) {
694 UAContext *ua = new_ua_context(djcr);
695 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
696 edit_uint64(djcr->JobId, ec1));
698 cancel_job(ua, djcr);
700 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
708 void apply_pool_overrides(JCR *jcr)
710 bool pool_override = false;
712 if (jcr->run_pool_override) {
713 pm_strcpy(jcr->pool_source, _("Run pool override"));
716 * Apply any level related Pool selections
718 switch (jcr->get_JobLevel()) {
720 if (jcr->full_pool) {
721 jcr->pool = jcr->full_pool;
722 pool_override = true;
723 if (jcr->run_full_pool_override) {
724 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
726 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
732 jcr->pool = jcr->inc_pool;
733 pool_override = true;
734 if (jcr->run_inc_pool_override) {
735 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
737 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
742 if (jcr->diff_pool) {
743 jcr->pool = jcr->diff_pool;
744 pool_override = true;
745 if (jcr->run_diff_pool_override) {
746 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
748 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
753 /* Update catalog if pool overridden */
754 if (pool_override && jcr->pool->catalog) {
755 jcr->catalog = jcr->pool->catalog;
756 pm_strcpy(jcr->catalog_source, _("Pool resource"));
762 * Get or create a Client record for this Job
764 bool get_or_create_client_record(JCR *jcr)
768 memset(&cr, 0, sizeof(cr));
769 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
770 cr.AutoPrune = jcr->client->AutoPrune;
771 cr.FileRetention = jcr->client->FileRetention;
772 cr.JobRetention = jcr->client->JobRetention;
773 if (!jcr->client_name) {
774 jcr->client_name = get_pool_memory(PM_NAME);
776 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
777 if (!db_create_client_record(jcr, jcr->db, &cr)) {
778 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
779 db_strerror(jcr->db));
782 jcr->jr.ClientId = cr.ClientId;
784 if (!jcr->client_uname) {
785 jcr->client_uname = get_pool_memory(PM_NAME);
787 pm_strcpy(jcr->client_uname, cr.Uname);
789 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
794 bool get_or_create_fileset_record(JCR *jcr)
798 * Get or Create FileSet record
800 memset(&fsr, 0, sizeof(FILESET_DBR));
801 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
802 if (jcr->fileset->have_MD5) {
803 struct MD5Context md5c;
804 unsigned char digest[MD5HashSize];
805 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
806 MD5Final(digest, &md5c);
808 * Keep the flag (last arg) set to false otherwise old FileSets will
809 * get new MD5 sums and the user will get Full backups on everything
811 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
812 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
814 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
816 if (!jcr->fileset->ignore_fs_changes ||
817 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
818 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
819 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
820 fsr.FileSet, db_strerror(jcr->db));
824 jcr->jr.FileSetId = fsr.FileSetId;
825 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
826 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
831 void init_jcr_job_record(JCR *jcr)
833 jcr->jr.SchedTime = jcr->sched_time;
834 jcr->jr.StartTime = jcr->start_time;
835 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
836 jcr->jr.JobType = jcr->get_JobType();
837 jcr->jr.JobLevel = jcr->get_JobLevel();
838 jcr->jr.JobStatus = jcr->JobStatus;
839 jcr->jr.JobId = jcr->JobId;
840 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
841 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
845 * Write status and such in DB
847 void update_job_end_record(JCR *jcr)
849 jcr->jr.EndTime = time(NULL);
850 jcr->end_time = jcr->jr.EndTime;
851 jcr->jr.JobId = jcr->JobId;
852 jcr->jr.JobStatus = jcr->JobStatus;
853 jcr->jr.JobFiles = jcr->JobFiles;
854 jcr->jr.JobBytes = jcr->JobBytes;
855 jcr->jr.VolSessionId = jcr->VolSessionId;
856 jcr->jr.VolSessionTime = jcr->VolSessionTime;
857 jcr->jr.JobErrors = jcr->Errors;
858 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
859 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
860 db_strerror(jcr->db));
865 * Takes base_name and appends (unique) current
866 * date and time to form unique job name.
868 * Note, the seconds are actually a sequence number. This
869 * permits us to start a maximum fo 59 unique jobs a second, which
870 * should be sufficient.
872 * Returns: unique job name in jcr->Job
873 * date/time in jcr->start_time
875 void create_unique_job_name(JCR *jcr, const char *base_name)
877 /* Job start mutex */
878 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
879 static time_t last_start_time = 0;
883 char dt[MAX_TIME_LENGTH];
884 char name[MAX_NAME_LENGTH];
887 /* Guarantee unique start time -- maximum one per second, and
888 * thus unique Job Name
890 P(mutex); /* lock creation of jobs */
893 if (seq > 59) { /* wrap as if it is seconds */
895 while (now == last_start_time) {
896 bmicrosleep(0, 500000);
900 last_start_time = now;
901 V(mutex); /* allow creation of jobs */
902 jcr->start_time = now;
903 /* Form Unique JobName */
904 (void)localtime_r(&now, &tm);
905 /* Use only characters that are permitted in Windows filenames */
906 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
907 bstrncpy(name, base_name, sizeof(name));
908 name[sizeof(name)-22] = 0; /* truncate if too long */
909 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
910 /* Convert spaces into underscores */
911 for (p=jcr->Job; *p; p++) {
918 /* Called directly from job rescheduling */
919 void dird_free_jcr_pointers(JCR *jcr)
921 if (jcr->sd_auth_key) {
922 free(jcr->sd_auth_key);
923 jcr->sd_auth_key = NULL;
929 if (jcr->file_bsock) {
930 Dmsg0(200, "Close File bsock\n");
931 bnet_close(jcr->file_bsock);
932 jcr->file_bsock = NULL;
934 if (jcr->store_bsock) {
935 Dmsg0(200, "Close Store bsock\n");
936 bnet_close(jcr->store_bsock);
937 jcr->store_bsock = NULL;
940 Dmsg0(200, "Free JCR fname\n");
941 free_pool_memory(jcr->fname);
944 if (jcr->RestoreBootstrap) {
945 free(jcr->RestoreBootstrap);
946 jcr->RestoreBootstrap = NULL;
948 if (jcr->client_uname) {
949 free_pool_memory(jcr->client_uname);
950 jcr->client_uname = NULL;
953 free_pool_memory(jcr->attr);
963 * Free the Job Control Record if no one is still using it.
964 * Called from main free_jcr() routine in src/lib/jcr.c so
965 * that we can do our Director specific cleanup of the jcr.
967 void dird_free_jcr(JCR *jcr)
969 Dmsg0(200, "Start dird free_jcr\n");
971 dird_free_jcr_pointers(jcr);
972 if (jcr->term_wait_inited) {
973 pthread_cond_destroy(&jcr->term_wait);
974 jcr->term_wait_inited = false;
977 db_close_database(jcr, jcr->db_batch);
978 jcr->db_batch = NULL;
979 jcr->batch_started = false;
982 db_close_database(jcr, jcr->db);
986 Dmsg0(200, "Free JCR stime\n");
987 free_pool_memory(jcr->stime);
991 Dmsg0(200, "Free JCR fname\n");
992 free_pool_memory(jcr->fname);
995 if (jcr->pool_source) {
996 free_pool_memory(jcr->pool_source);
997 jcr->pool_source = NULL;
999 if (jcr->catalog_source) {
1000 free_pool_memory(jcr->catalog_source);
1001 jcr->catalog_source = NULL;
1003 if (jcr->rpool_source) {
1004 free_pool_memory(jcr->rpool_source);
1005 jcr->rpool_source = NULL;
1007 if (jcr->wstore_source) {
1008 free_pool_memory(jcr->wstore_source);
1009 jcr->wstore_source = NULL;
1011 if (jcr->rstore_source) {
1012 free_pool_memory(jcr->rstore_source);
1013 jcr->rstore_source = NULL;
1016 /* Delete lists setup to hold storage pointers */
1017 free_rwstorage(jcr);
1019 jcr->job_end_push.destroy();
1021 if (jcr->JobId != 0)
1022 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1024 Dmsg0(200, "End dird free_jcr\n");
1028 * The Job storage definition must be either in the Job record
1029 * or in the Pool record. The Pool record overrides the Job
1032 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1034 if (run && run->pool && run->pool->storage) {
1035 store->store = (STORE *)run->pool->storage->first();
1036 pm_strcpy(store->store_source, _("Run pool override"));
1039 if (run && run->storage) {
1040 store->store = run->storage;
1041 pm_strcpy(store->store_source, _("Run storage override"));
1044 if (job->pool->storage) {
1045 store->store = (STORE *)job->pool->storage->first();
1046 pm_strcpy(store->store_source, _("Pool resource"));
1048 store->store = (STORE *)job->storage->first();
1049 pm_strcpy(store->store_source, _("Job resource"));
1054 * Set some defaults in the JCR necessary to
1055 * run. These items are pulled from the job
1056 * definition as defaults, but can be overridden
1057 * later either by the Run record in the Schedule resource,
1058 * or by the Console program.
1060 void set_jcr_defaults(JCR *jcr, JOB *job)
1063 jcr->set_JobType(job->JobType);
1064 jcr->JobStatus = JS_Created;
1066 switch (jcr->get_JobType()) {
1068 jcr->set_JobLevel(L_NONE);
1071 jcr->set_JobLevel(job->JobLevel);
1076 jcr->fname = get_pool_memory(PM_FNAME);
1078 if (!jcr->pool_source) {
1079 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1080 pm_strcpy(jcr->pool_source, _("unknown source"));
1082 if (!jcr->catalog_source) {
1083 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1084 pm_strcpy(jcr->catalog_source, _("unknown source"));
1087 jcr->JobPriority = job->Priority;
1088 /* Copy storage definitions -- deleted in dir_free_jcr above */
1090 copy_rwstorage(jcr, job->storage, _("Job resource"));
1092 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1094 jcr->client = job->client;
1095 if (!jcr->client_name) {
1096 jcr->client_name = get_pool_memory(PM_NAME);
1098 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1099 pm_strcpy(jcr->pool_source, _("Job resource"));
1100 jcr->pool = job->pool;
1101 jcr->full_pool = job->full_pool;
1102 jcr->inc_pool = job->inc_pool;
1103 jcr->diff_pool = job->diff_pool;
1104 if (job->pool->catalog) {
1105 jcr->catalog = job->pool->catalog;
1106 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1108 jcr->catalog = job->client->catalog;
1109 pm_strcpy(jcr->catalog_source, _("Client resource"));
1111 jcr->fileset = job->fileset;
1112 jcr->messages = job->messages;
1113 jcr->spool_data = job->spool_data;
1114 jcr->spool_size = job->spool_size;
1115 jcr->write_part_after_job = job->write_part_after_job;
1116 jcr->accurate = job->accurate;
1117 if (jcr->RestoreBootstrap) {
1118 free(jcr->RestoreBootstrap);
1119 jcr->RestoreBootstrap = NULL;
1121 /* This can be overridden by Console program */
1122 if (job->RestoreBootstrap) {
1123 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1125 /* This can be overridden by Console program */
1126 jcr->verify_job = job->verify_job;
1127 /* If no default level given, set one */
1128 if (jcr->get_JobLevel() == 0) {
1129 switch (jcr->get_JobType()) {
1131 jcr->set_JobLevel(L_VERIFY_CATALOG);
1134 jcr->set_JobLevel(L_INCREMENTAL);
1138 jcr->set_JobLevel(L_NONE);
1141 jcr->set_JobLevel(L_FULL);
1148 * Copy the storage definitions from an alist to the JCR
1150 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1152 if (jcr->JobReads()) {
1153 copy_rstorage(jcr, storage, where);
1155 copy_wstorage(jcr, storage, where);
1159 /* Set storage override. Releases any previous storage definition */
1160 void set_rwstorage(JCR *jcr, USTORE *store)
1163 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1166 if (jcr->JobReads()) {
1167 set_rstorage(jcr, store);
1169 set_wstorage(jcr, store);
1172 void free_rwstorage(JCR *jcr)
1179 * Copy the storage definitions from an alist to the JCR
1181 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1185 if (jcr->rstorage) {
1186 delete jcr->rstorage;
1188 jcr->rstorage = New(alist(10, not_owned_by_alist));
1189 foreach_alist(st, storage) {
1190 jcr->rstorage->append(st);
1192 if (!jcr->rstore_source) {
1193 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1195 pm_strcpy(jcr->rstore_source, where);
1196 if (jcr->rstorage) {
1197 jcr->rstore = (STORE *)jcr->rstorage->first();
1203 /* Set storage override. Remove all previous storage */
1204 void set_rstorage(JCR *jcr, USTORE *store)
1208 if (!store->store) {
1211 if (jcr->rstorage) {
1214 if (!jcr->rstorage) {
1215 jcr->rstorage = New(alist(10, not_owned_by_alist));
1217 jcr->rstore = store->store;
1218 if (!jcr->rstore_source) {
1219 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1221 pm_strcpy(jcr->rstore_source, store->store_source);
1222 foreach_alist(storage, jcr->rstorage) {
1223 if (store->store == storage) {
1227 /* Store not in list, so add it */
1228 jcr->rstorage->prepend(store->store);
1231 void free_rstorage(JCR *jcr)
1233 if (jcr->rstorage) {
1234 delete jcr->rstorage;
1235 jcr->rstorage = NULL;
1241 * Copy the storage definitions from an alist to the JCR
1243 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1247 if (jcr->wstorage) {
1248 delete jcr->wstorage;
1250 jcr->wstorage = New(alist(10, not_owned_by_alist));
1251 foreach_alist(st, storage) {
1252 Dmsg1(100, "wstorage=%s\n", st->name());
1253 jcr->wstorage->append(st);
1255 if (!jcr->wstore_source) {
1256 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1258 pm_strcpy(jcr->wstore_source, where);
1259 if (jcr->wstorage) {
1260 jcr->wstore = (STORE *)jcr->wstorage->first();
1261 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1267 /* Set storage override. Remove all previous storage */
1268 void set_wstorage(JCR *jcr, USTORE *store)
1272 if (!store->store) {
1275 if (jcr->wstorage) {
1278 if (!jcr->wstorage) {
1279 jcr->wstorage = New(alist(10, not_owned_by_alist));
1281 jcr->wstore = store->store;
1282 if (!jcr->wstore_source) {
1283 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1285 pm_strcpy(jcr->wstore_source, store->store_source);
1286 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1287 foreach_alist(storage, jcr->wstorage) {
1288 if (store->store == storage) {
1292 /* Store not in list, so add it */
1293 jcr->wstorage->prepend(store->store);
1296 void free_wstorage(JCR *jcr)
1298 if (jcr->wstorage) {
1299 delete jcr->wstorage;
1300 jcr->wstorage = NULL;
1305 char *job_code_callback_clones(JCR *jcr, const char* param)
1307 if (param[0] == 'p') {
1308 return jcr->pool->name();
1313 void create_clones(JCR *jcr)
1316 * Fire off any clone jobs (run directives)
1318 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1319 if (!jcr->cloned && jcr->job->run_cmds) {
1321 JOB *job = jcr->job;
1322 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1323 UAContext *ua = new_ua_context(jcr);
1325 foreach_alist(runcmd, job->run_cmds) {
1326 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1327 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1328 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1329 parse_ua_args(ua); /* parse command */
1330 int stat = run_cmd(ua, ua->cmd);
1332 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1334 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1337 free_ua_context(ua);
1338 free_pool_memory(cmd);
1343 * Given: a JobId in jcr->previous_jr.JobId,
1344 * this subroutine writes a bsr file to restore that job.
1346 bool create_restore_bootstrap_file(JCR *jcr)
1350 memset(&rx, 0, sizeof(rx));
1352 rx.JobIds = (char *)"";
1353 rx.bsr->JobId = jcr->previous_jr.JobId;
1354 ua = new_ua_context(jcr);
1355 complete_bsr(ua, rx.bsr);
1356 rx.bsr->fi = new_findex();
1357 rx.bsr->fi->findex = 1;
1358 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1359 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1360 if (jcr->ExpectedFiles == 0) {
1361 free_ua_context(ua);
1365 free_ua_context(ua);
1367 jcr->needs_sd = true;
1371 bool run_console_command(JCR *jcr, const char *cmd){
1375 ua = new_ua_context(jcr);
1376 Mmsg(ua->cmd, "%s", cmd);
1377 Dmsg1(100, "Console command: %s\n", ua->cmd);
1379 ok= do_a_command(ua);
1380 free_ua_context(ua);