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)) {
182 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
183 * this allows us to setup a proper job start record for restarting
184 * in case of later errors.
186 switch (jcr->get_JobType()) {
188 if (!do_backup_init(jcr)) {
189 backup_cleanup(jcr, JS_ErrorTerminated);
193 if (!do_verify_init(jcr)) {
194 verify_cleanup(jcr, JS_ErrorTerminated);
198 if (!do_restore_init(jcr)) {
199 restore_cleanup(jcr, JS_ErrorTerminated);
203 if (!do_admin_init(jcr)) {
204 admin_cleanup(jcr, JS_ErrorTerminated);
209 if (!do_migration_init(jcr)) {
210 migration_cleanup(jcr, JS_ErrorTerminated);
214 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
215 set_jcr_job_status(jcr, JS_ErrorTerminated);
219 generate_job_event(jcr, "JobInit");
227 void update_job_end(JCR *jcr, int TermCode)
229 dequeue_messages(jcr); /* display any queued messages */
230 set_jcr_job_status(jcr, TermCode);
231 update_job_end_record(jcr);
235 * This is the engine called by jobq.c:jobq_add() when we were pulled
236 * from the work queue.
237 * At this point, we are running in our own thread and all
238 * necessary resources are allocated -- see jobq.c
240 static void *job_thread(void *arg)
242 JCR *jcr = (JCR *)arg;
244 pthread_detach(pthread_self());
247 Dmsg0(200, "=====Start Job=========\n");
248 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
249 jcr->start_time = time(NULL); /* set the real start time */
250 jcr->jr.StartTime = jcr->start_time;
252 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
253 (utime_t)(jcr->start_time - jcr->sched_time)) {
254 set_jcr_job_status(jcr, JS_Canceled);
255 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
258 if (job_check_maxschedruntime(jcr)) {
259 set_jcr_job_status(jcr, JS_Canceled);
260 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
263 /* TODO : check if it is used somewhere */
264 if (jcr->job->RunScripts == NULL) {
265 Dmsg0(200, "Warning, job->RunScripts is empty\n");
266 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
269 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
270 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
273 /* Run any script BeforeJob on dird */
274 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
276 if (job_canceled(jcr)) {
277 update_job_end(jcr, jcr->JobStatus);
281 * We re-update the job start record so that the start
282 * time is set after the run before job. This avoids
283 * that any files created by the run before job will
284 * be saved twice. They will be backed up in the current
285 * job, but not in the next one unless they are changed.
286 * Without this, they will be backed up in this job and
287 * in the next job run because in that case, their date
288 * is after the start of this run.
290 jcr->start_time = time(NULL);
291 jcr->jr.StartTime = jcr->start_time;
292 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
293 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
295 generate_job_event(jcr, "JobRun");
297 switch (jcr->get_JobType()) {
299 if (do_backup(jcr)) {
302 backup_cleanup(jcr, JS_ErrorTerminated);
306 if (do_verify(jcr)) {
309 verify_cleanup(jcr, JS_ErrorTerminated);
313 if (do_restore(jcr)) {
316 restore_cleanup(jcr, JS_ErrorTerminated);
323 admin_cleanup(jcr, JS_ErrorTerminated);
328 if (do_migration(jcr)) {
331 migration_cleanup(jcr, JS_ErrorTerminated);
335 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
340 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
342 /* Send off any queued messages */
343 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
344 dequeue_messages(jcr);
347 generate_daemon_event(jcr, "JobEnd");
348 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
349 sm_check(__FILE__, __LINE__, true);
355 * Cancel a job -- typically called by the UA (Console program), but may also
356 * be called by the job watchdog.
358 * Returns: true if cancel appears to be successful
359 * false on failure. Message sent to ua->jcr.
361 bool cancel_job(UAContext *ua, JCR *jcr)
366 set_jcr_job_status(jcr, JS_Canceled);
368 switch (jcr->JobStatus) {
371 case JS_WaitClientRes:
372 case JS_WaitStoreRes:
373 case JS_WaitPriority:
375 case JS_WaitStartTime:
376 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
377 edit_uint64(jcr->JobId, ed1), jcr->Job);
378 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
382 /* Cancel File daemon */
383 if (jcr->file_bsock) {
384 ua->jcr->client = jcr->client;
385 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
386 ua->error_msg(_("Failed to connect to File daemon.\n"));
389 Dmsg0(200, "Connected to file daemon\n");
390 fd = ua->jcr->file_bsock;
391 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
392 while (bnet_recv(fd) >= 0) {
393 ua->send_msg("%s", fd->msg);
395 bnet_sig(fd, BNET_TERMINATE);
397 ua->jcr->file_bsock = NULL;
400 /* Cancel Storage daemon */
401 if (jcr->store_bsock) {
402 if (!ua->jcr->wstorage) {
404 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
406 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
411 store.store = jcr->rstore;
413 store.store = jcr->wstore;
415 set_wstorage(ua->jcr, &store);
418 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
419 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
422 Dmsg0(200, "Connected to storage daemon\n");
423 sd = ua->jcr->store_bsock;
424 sd->fsend("cancel Job=%s\n", jcr->Job);
425 while (sd->recv() >= 0) {
426 ua->send_msg("%s", sd->msg);
428 sd->signal(BNET_TERMINATE);
430 ua->jcr->store_bsock = NULL;
437 void cancel_storage_daemon_job(JCR *jcr)
439 UAContext *ua = new_ua_context(jcr);
440 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
443 ua->jcr = control_jcr;
444 if (jcr->store_bsock) {
445 if (!ua->jcr->wstorage) {
447 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
449 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
454 store.store = jcr->rstore;
456 store.store = jcr->wstore;
458 set_wstorage(ua->jcr, &store);
461 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
464 Dmsg0(200, "Connected to storage daemon\n");
465 sd = ua->jcr->store_bsock;
466 sd->fsend("cancel Job=%s\n", jcr->Job);
467 while (sd->recv() >= 0) {
469 sd->signal(BNET_TERMINATE);
471 ua->jcr->store_bsock = NULL;
474 free_jcr(control_jcr);
478 static void job_monitor_destructor(watchdog_t *self)
480 JCR *control_jcr = (JCR *)self->data;
482 free_jcr(control_jcr);
485 static void job_monitor_watchdog(watchdog_t *self)
487 JCR *control_jcr, *jcr;
489 control_jcr = (JCR *)self->data;
492 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
497 if (jcr->JobId == 0 || job_canceled(jcr)) {
498 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
502 /* check MaxWaitTime */
503 if (job_check_maxwaittime(jcr)) {
504 set_jcr_job_status(jcr, JS_Canceled);
505 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
507 /* check MaxRunTime */
508 } else if (job_check_maxruntime(jcr)) {
509 set_jcr_job_status(jcr, JS_Canceled);
510 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
512 /* check MaxRunSchedTime */
513 } else if (job_check_maxschedruntime(jcr)) {
514 set_jcr_job_status(jcr, JS_Canceled);
515 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
520 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
521 UAContext *ua = new_ua_context(jcr);
522 ua->jcr = control_jcr;
525 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
529 /* Keep reference counts correct */
534 * Check if the maxwaittime has expired and it is possible
537 static bool job_check_maxwaittime(JCR *jcr)
542 if (!job_waiting(jcr)) {
545 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
546 if (job->MaxWaitTime != 0 &&
547 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
555 * Check if maxruntime has expired and if the job can be
558 static bool job_check_maxruntime(JCR *jcr)
563 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
566 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
567 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
570 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
571 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
572 job->IncMaxRunTime, job->DiffMaxRunTime);
574 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
575 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
577 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
578 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
580 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
581 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
583 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
591 * Check if MaxRunSchedTime has expired and if the job can be
594 static bool job_check_maxschedruntime(JCR *jcr)
596 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
599 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
600 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
601 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
609 * Get or create a Pool record with the given name.
610 * Returns: 0 on error
613 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
617 memset(&pr, 0, sizeof(pr));
618 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
619 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
621 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
622 /* Try to create the pool */
623 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
624 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
625 db_strerror(jcr->db));
628 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
635 * Check for duplicate jobs.
636 * Returns: true if current job should continue
637 * false if current job should terminate
639 bool allow_duplicate_job(JCR *jcr)
642 JCR *djcr; /* possible duplicate */
644 if (job->AllowDuplicateJobs) {
647 if (!job->AllowHigherDuplicates) {
650 if (strcmp(job->name(), djcr->job->name()) == 0) {
651 bool cancel_queued = false;
652 if (job->DuplicateJobProximity > 0) {
653 time_t now = time(NULL);
654 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
655 continue; /* not really a duplicate */
659 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
660 /* Zap current job */
661 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
662 edit_uint64(djcr->JobId, ec1));
665 /* If CancelQueuedDuplicates is set do so only if job is queued */
666 if (job->CancelQueuedDuplicates) {
667 switch (djcr->JobStatus) {
670 case JS_WaitClientRes:
671 case JS_WaitStoreRes:
672 case JS_WaitPriority:
674 case JS_WaitStartTime:
675 cancel_queued = true;
681 if (cancel_queued || job->CancelRunningDuplicates) {
682 UAContext *ua = new_ua_context(djcr);
683 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
684 edit_uint64(djcr->JobId, ec1));
686 cancel_job(ua, djcr);
688 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
696 void apply_pool_overrides(JCR *jcr)
698 bool pool_override = false;
700 if (jcr->run_pool_override) {
701 pm_strcpy(jcr->pool_source, _("Run pool override"));
704 * Apply any level related Pool selections
706 switch (jcr->get_JobLevel()) {
708 if (jcr->full_pool) {
709 jcr->pool = jcr->full_pool;
710 pool_override = true;
711 if (jcr->run_full_pool_override) {
712 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
714 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
720 jcr->pool = jcr->inc_pool;
721 pool_override = true;
722 if (jcr->run_inc_pool_override) {
723 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
725 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
730 if (jcr->diff_pool) {
731 jcr->pool = jcr->diff_pool;
732 pool_override = true;
733 if (jcr->run_diff_pool_override) {
734 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
736 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
741 /* Update catalog if pool overridden */
742 if (pool_override && jcr->pool->catalog) {
743 jcr->catalog = jcr->pool->catalog;
744 pm_strcpy(jcr->catalog_source, _("Pool resource"));
750 * Get or create a Client record for this Job
752 bool get_or_create_client_record(JCR *jcr)
756 memset(&cr, 0, sizeof(cr));
757 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
758 cr.AutoPrune = jcr->client->AutoPrune;
759 cr.FileRetention = jcr->client->FileRetention;
760 cr.JobRetention = jcr->client->JobRetention;
761 if (!jcr->client_name) {
762 jcr->client_name = get_pool_memory(PM_NAME);
764 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
765 if (!db_create_client_record(jcr, jcr->db, &cr)) {
766 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
767 db_strerror(jcr->db));
770 jcr->jr.ClientId = cr.ClientId;
772 if (!jcr->client_uname) {
773 jcr->client_uname = get_pool_memory(PM_NAME);
775 pm_strcpy(jcr->client_uname, cr.Uname);
777 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
782 bool get_or_create_fileset_record(JCR *jcr)
786 * Get or Create FileSet record
788 memset(&fsr, 0, sizeof(FILESET_DBR));
789 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
790 if (jcr->fileset->have_MD5) {
791 struct MD5Context md5c;
792 unsigned char digest[MD5HashSize];
793 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
794 MD5Final(digest, &md5c);
796 * Keep the flag (last arg) set to false otherwise old FileSets will
797 * get new MD5 sums and the user will get Full backups on everything
799 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
800 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
802 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
804 if (!jcr->fileset->ignore_fs_changes ||
805 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
806 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
807 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
808 fsr.FileSet, db_strerror(jcr->db));
812 jcr->jr.FileSetId = fsr.FileSetId;
813 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
814 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
819 void init_jcr_job_record(JCR *jcr)
821 jcr->jr.SchedTime = jcr->sched_time;
822 jcr->jr.StartTime = jcr->start_time;
823 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
824 jcr->jr.JobType = jcr->get_JobType();
825 jcr->jr.JobLevel = jcr->get_JobLevel();
826 jcr->jr.JobStatus = jcr->JobStatus;
827 jcr->jr.JobId = jcr->JobId;
828 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
829 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
833 * Write status and such in DB
835 void update_job_end_record(JCR *jcr)
837 jcr->jr.EndTime = time(NULL);
838 jcr->end_time = jcr->jr.EndTime;
839 jcr->jr.JobId = jcr->JobId;
840 jcr->jr.JobStatus = jcr->JobStatus;
841 jcr->jr.JobFiles = jcr->JobFiles;
842 jcr->jr.JobBytes = jcr->JobBytes;
843 jcr->jr.VolSessionId = jcr->VolSessionId;
844 jcr->jr.VolSessionTime = jcr->VolSessionTime;
845 jcr->jr.JobErrors = jcr->Errors;
846 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr, jcr->job->stats_enabled)) {
847 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
848 db_strerror(jcr->db));
853 * Takes base_name and appends (unique) current
854 * date and time to form unique job name.
856 * Note, the seconds are actually a sequence number. This
857 * permits us to start a maximum fo 59 unique jobs a second, which
858 * should be sufficient.
860 * Returns: unique job name in jcr->Job
861 * date/time in jcr->start_time
863 void create_unique_job_name(JCR *jcr, const char *base_name)
865 /* Job start mutex */
866 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
867 static time_t last_start_time = 0;
871 char dt[MAX_TIME_LENGTH];
872 char name[MAX_NAME_LENGTH];
875 /* Guarantee unique start time -- maximum one per second, and
876 * thus unique Job Name
878 P(mutex); /* lock creation of jobs */
881 if (seq > 59) { /* wrap as if it is seconds */
883 while (now == last_start_time) {
884 bmicrosleep(0, 500000);
888 last_start_time = now;
889 V(mutex); /* allow creation of jobs */
890 jcr->start_time = now;
891 /* Form Unique JobName */
892 (void)localtime_r(&now, &tm);
893 /* Use only characters that are permitted in Windows filenames */
894 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
895 bstrncpy(name, base_name, sizeof(name));
896 name[sizeof(name)-22] = 0; /* truncate if too long */
897 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
898 /* Convert spaces into underscores */
899 for (p=jcr->Job; *p; p++) {
906 /* Called directly from job rescheduling */
907 void dird_free_jcr_pointers(JCR *jcr)
909 if (jcr->sd_auth_key) {
910 free(jcr->sd_auth_key);
911 jcr->sd_auth_key = NULL;
917 if (jcr->file_bsock) {
918 Dmsg0(200, "Close File bsock\n");
919 bnet_close(jcr->file_bsock);
920 jcr->file_bsock = NULL;
922 if (jcr->store_bsock) {
923 Dmsg0(200, "Close Store bsock\n");
924 bnet_close(jcr->store_bsock);
925 jcr->store_bsock = NULL;
928 Dmsg0(200, "Free JCR fname\n");
929 free_pool_memory(jcr->fname);
932 if (jcr->RestoreBootstrap) {
933 free(jcr->RestoreBootstrap);
934 jcr->RestoreBootstrap = NULL;
936 if (jcr->client_uname) {
937 free_pool_memory(jcr->client_uname);
938 jcr->client_uname = NULL;
941 free_pool_memory(jcr->attr);
951 * Free the Job Control Record if no one is still using it.
952 * Called from main free_jcr() routine in src/lib/jcr.c so
953 * that we can do our Director specific cleanup of the jcr.
955 void dird_free_jcr(JCR *jcr)
957 Dmsg0(200, "Start dird free_jcr\n");
959 dird_free_jcr_pointers(jcr);
960 if (jcr->term_wait_inited) {
961 pthread_cond_destroy(&jcr->term_wait);
962 jcr->term_wait_inited = false;
964 if (jcr->db_batch && jcr->db_batch != jcr->db) {
965 db_close_database(jcr, jcr->db_batch);
967 jcr->db_batch = NULL;
969 db_close_database(jcr, jcr->db);
973 Dmsg0(200, "Free JCR stime\n");
974 free_pool_memory(jcr->stime);
978 Dmsg0(200, "Free JCR fname\n");
979 free_pool_memory(jcr->fname);
982 if (jcr->pool_source) {
983 free_pool_memory(jcr->pool_source);
984 jcr->pool_source = NULL;
986 if (jcr->catalog_source) {
987 free_pool_memory(jcr->catalog_source);
988 jcr->catalog_source = NULL;
990 if (jcr->rpool_source) {
991 free_pool_memory(jcr->rpool_source);
992 jcr->rpool_source = NULL;
994 if (jcr->wstore_source) {
995 free_pool_memory(jcr->wstore_source);
996 jcr->wstore_source = NULL;
998 if (jcr->rstore_source) {
999 free_pool_memory(jcr->rstore_source);
1000 jcr->rstore_source = NULL;
1003 /* Delete lists setup to hold storage pointers */
1004 free_rwstorage(jcr);
1006 jcr->job_end_push.destroy();
1008 if (jcr->JobId != 0)
1009 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1011 Dmsg0(200, "End dird free_jcr\n");
1015 * The Job storage definition must be either in the Job record
1016 * or in the Pool record. The Pool record overrides the Job
1019 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1021 if (run && run->pool && run->pool->storage) {
1022 store->store = (STORE *)run->pool->storage->first();
1023 pm_strcpy(store->store_source, _("Run pool override"));
1026 if (run && run->storage) {
1027 store->store = run->storage;
1028 pm_strcpy(store->store_source, _("Run storage override"));
1031 if (job->pool->storage) {
1032 store->store = (STORE *)job->pool->storage->first();
1033 pm_strcpy(store->store_source, _("Pool resource"));
1035 store->store = (STORE *)job->storage->first();
1036 pm_strcpy(store->store_source, _("Job resource"));
1041 * Set some defaults in the JCR necessary to
1042 * run. These items are pulled from the job
1043 * definition as defaults, but can be overridden
1044 * later either by the Run record in the Schedule resource,
1045 * or by the Console program.
1047 void set_jcr_defaults(JCR *jcr, JOB *job)
1050 jcr->set_JobType(job->JobType);
1051 jcr->JobStatus = JS_Created;
1053 switch (jcr->get_JobType()) {
1055 jcr->set_JobLevel(L_NONE);
1058 jcr->set_JobLevel(job->JobLevel);
1063 jcr->fname = get_pool_memory(PM_FNAME);
1065 if (!jcr->pool_source) {
1066 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1067 pm_strcpy(jcr->pool_source, _("unknown source"));
1069 if (!jcr->catalog_source) {
1070 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1071 pm_strcpy(jcr->catalog_source, _("unknown source"));
1074 jcr->JobPriority = job->Priority;
1075 /* Copy storage definitions -- deleted in dir_free_jcr above */
1077 copy_rwstorage(jcr, job->storage, _("Job resource"));
1079 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1081 jcr->client = job->client;
1082 if (!jcr->client_name) {
1083 jcr->client_name = get_pool_memory(PM_NAME);
1085 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1086 pm_strcpy(jcr->pool_source, _("Job resource"));
1087 jcr->pool = job->pool;
1088 jcr->full_pool = job->full_pool;
1089 jcr->inc_pool = job->inc_pool;
1090 jcr->diff_pool = job->diff_pool;
1091 if (job->pool->catalog) {
1092 jcr->catalog = job->pool->catalog;
1093 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1095 jcr->catalog = job->client->catalog;
1096 pm_strcpy(jcr->catalog_source, _("Client resource"));
1098 jcr->fileset = job->fileset;
1099 jcr->messages = job->messages;
1100 jcr->spool_data = job->spool_data;
1101 jcr->spool_size = job->spool_size;
1102 jcr->write_part_after_job = job->write_part_after_job;
1103 jcr->accurate = job->accurate;
1104 if (jcr->RestoreBootstrap) {
1105 free(jcr->RestoreBootstrap);
1106 jcr->RestoreBootstrap = NULL;
1108 /* This can be overridden by Console program */
1109 if (job->RestoreBootstrap) {
1110 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1112 /* This can be overridden by Console program */
1113 jcr->verify_job = job->verify_job;
1114 /* If no default level given, set one */
1115 if (jcr->get_JobLevel() == 0) {
1116 switch (jcr->get_JobType()) {
1118 jcr->set_JobLevel(L_VERIFY_CATALOG);
1121 jcr->set_JobLevel(L_INCREMENTAL);
1125 jcr->set_JobLevel(L_NONE);
1128 jcr->set_JobLevel(L_FULL);
1135 * Copy the storage definitions from an alist to the JCR
1137 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1139 if (jcr->JobReads()) {
1140 copy_rstorage(jcr, storage, where);
1142 copy_wstorage(jcr, storage, where);
1146 /* Set storage override. Releases any previous storage definition */
1147 void set_rwstorage(JCR *jcr, USTORE *store)
1150 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1153 if (jcr->JobReads()) {
1154 set_rstorage(jcr, store);
1156 set_wstorage(jcr, store);
1159 void free_rwstorage(JCR *jcr)
1166 * Copy the storage definitions from an alist to the JCR
1168 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1172 if (jcr->rstorage) {
1173 delete jcr->rstorage;
1175 jcr->rstorage = New(alist(10, not_owned_by_alist));
1176 foreach_alist(st, storage) {
1177 jcr->rstorage->append(st);
1179 if (!jcr->rstore_source) {
1180 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1182 pm_strcpy(jcr->rstore_source, where);
1183 if (jcr->rstorage) {
1184 jcr->rstore = (STORE *)jcr->rstorage->first();
1190 /* Set storage override. Remove all previous storage */
1191 void set_rstorage(JCR *jcr, USTORE *store)
1195 if (!store->store) {
1198 if (jcr->rstorage) {
1201 if (!jcr->rstorage) {
1202 jcr->rstorage = New(alist(10, not_owned_by_alist));
1204 jcr->rstore = store->store;
1205 if (!jcr->rstore_source) {
1206 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1208 pm_strcpy(jcr->rstore_source, store->store_source);
1209 foreach_alist(storage, jcr->rstorage) {
1210 if (store->store == storage) {
1214 /* Store not in list, so add it */
1215 jcr->rstorage->prepend(store->store);
1218 void free_rstorage(JCR *jcr)
1220 if (jcr->rstorage) {
1221 delete jcr->rstorage;
1222 jcr->rstorage = NULL;
1228 * Copy the storage definitions from an alist to the JCR
1230 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1234 if (jcr->wstorage) {
1235 delete jcr->wstorage;
1237 jcr->wstorage = New(alist(10, not_owned_by_alist));
1238 foreach_alist(st, storage) {
1239 Dmsg1(100, "wstorage=%s\n", st->name());
1240 jcr->wstorage->append(st);
1242 if (!jcr->wstore_source) {
1243 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1245 pm_strcpy(jcr->wstore_source, where);
1246 if (jcr->wstorage) {
1247 jcr->wstore = (STORE *)jcr->wstorage->first();
1248 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1254 /* Set storage override. Remove all previous storage */
1255 void set_wstorage(JCR *jcr, USTORE *store)
1259 if (!store->store) {
1262 if (jcr->wstorage) {
1265 if (!jcr->wstorage) {
1266 jcr->wstorage = New(alist(10, not_owned_by_alist));
1268 jcr->wstore = store->store;
1269 if (!jcr->wstore_source) {
1270 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1272 pm_strcpy(jcr->wstore_source, store->store_source);
1273 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1274 foreach_alist(storage, jcr->wstorage) {
1275 if (store->store == storage) {
1279 /* Store not in list, so add it */
1280 jcr->wstorage->prepend(store->store);
1283 void free_wstorage(JCR *jcr)
1285 if (jcr->wstorage) {
1286 delete jcr->wstorage;
1287 jcr->wstorage = NULL;
1292 char *job_code_callback_clones(JCR *jcr, const char* param)
1294 if (param[0] == 'p') {
1295 return jcr->pool->name();
1300 void create_clones(JCR *jcr)
1303 * Fire off any clone jobs (run directives)
1305 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1306 if (!jcr->cloned && jcr->job->run_cmds) {
1308 JOB *job = jcr->job;
1309 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1310 UAContext *ua = new_ua_context(jcr);
1312 foreach_alist(runcmd, job->run_cmds) {
1313 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1314 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1315 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1316 parse_ua_args(ua); /* parse command */
1317 int stat = run_cmd(ua, ua->cmd);
1319 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1321 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1324 free_ua_context(ua);
1325 free_pool_memory(cmd);
1330 * Given: a JobId in jcr->previous_jr.JobId,
1331 * this subroutine writes a bsr file to restore that job.
1333 bool create_restore_bootstrap_file(JCR *jcr)
1337 memset(&rx, 0, sizeof(rx));
1339 rx.JobIds = (char *)"";
1340 rx.bsr->JobId = jcr->previous_jr.JobId;
1341 ua = new_ua_context(jcr);
1342 complete_bsr(ua, rx.bsr);
1343 rx.bsr->fi = new_findex();
1344 rx.bsr->fi->findex = 1;
1345 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1346 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1347 if (jcr->ExpectedFiles == 0) {
1348 free_ua_context(ua);
1352 free_ua_context(ua);
1354 jcr->needs_sd = true;
1358 bool run_console_command(JCR *jcr, const char *cmd){
1362 ua = new_ua_context(jcr);
1363 Mmsg(ua->cmd, "%s", cmd);
1364 Dmsg1(100, "Console command: %s\n", ua->cmd);
1366 ok= do_a_command(ua);
1367 free_ua_context(ua);