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");
288 * We re-update the job start record so that the start
289 * time is set after the run before job. This avoids
290 * that any files created by the run before job will
291 * be saved twice. They will be backed up in the current
292 * job, but not in the next one unless they are changed.
293 * Without this, they will be backed up in this job and
294 * in the next job run because in that case, their date
295 * is after the start of this run.
297 jcr->start_time = time(NULL);
298 jcr->jr.StartTime = jcr->start_time;
299 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
300 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
302 generate_job_event(jcr, "JobRun");
304 switch (jcr->get_JobType()) {
306 if (!job_canceled(jcr) && do_backup(jcr)) {
309 backup_cleanup(jcr, JS_ErrorTerminated);
313 if (!job_canceled(jcr) && do_verify(jcr)) {
316 verify_cleanup(jcr, JS_ErrorTerminated);
320 if (!job_canceled(jcr) && do_restore(jcr)) {
323 restore_cleanup(jcr, JS_ErrorTerminated);
327 if (!job_canceled(jcr) && do_admin(jcr)) {
330 admin_cleanup(jcr, JS_ErrorTerminated);
335 if (!job_canceled(jcr) && do_migration(jcr)) {
338 migration_cleanup(jcr, JS_ErrorTerminated);
342 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
346 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
348 /* Send off any queued messages */
349 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
350 dequeue_messages(jcr);
353 generate_daemon_event(jcr, "JobEnd");
354 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
355 sm_check(__FILE__, __LINE__, true);
361 * Cancel a job -- typically called by the UA (Console program), but may also
362 * be called by the job watchdog.
364 * Returns: true if cancel appears to be successful
365 * false on failure. Message sent to ua->jcr.
367 bool cancel_job(UAContext *ua, JCR *jcr)
371 int32_t old_status = jcr->JobStatus;
373 set_jcr_job_status(jcr, JS_Canceled);
375 switch (old_status) {
378 case JS_WaitClientRes:
379 case JS_WaitStoreRes:
380 case JS_WaitPriority:
382 case JS_WaitStartTime:
383 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
384 edit_uint64(jcr->JobId, ed1), jcr->Job);
385 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
389 /* Cancel File daemon */
390 if (jcr->file_bsock) {
391 ua->jcr->client = jcr->client;
392 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
393 ua->error_msg(_("Failed to connect to File daemon.\n"));
396 Dmsg0(200, "Connected to file daemon\n");
397 fd = ua->jcr->file_bsock;
398 fd->fsend("cancel Job=%s\n", jcr->Job);
399 while (fd->recv() >= 0) {
400 ua->send_msg("%s", fd->msg);
402 fd->signal(BNET_TERMINATE);
404 ua->jcr->file_bsock = NULL;
407 /* Cancel Storage daemon */
408 if (jcr->store_bsock) {
409 if (!ua->jcr->wstorage) {
411 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
413 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
418 store.store = jcr->rstore;
420 store.store = jcr->wstore;
422 set_wstorage(ua->jcr, &store);
425 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
426 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
429 Dmsg0(200, "Connected to storage daemon\n");
430 sd = ua->jcr->store_bsock;
431 sd->fsend("cancel Job=%s\n", jcr->Job);
432 while (sd->recv() >= 0) {
433 ua->send_msg("%s", sd->msg);
435 sd->signal(BNET_TERMINATE);
437 ua->jcr->store_bsock = NULL;
444 void cancel_storage_daemon_job(JCR *jcr)
446 UAContext *ua = new_ua_context(jcr);
447 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
450 ua->jcr = control_jcr;
451 if (jcr->store_bsock) {
452 if (!ua->jcr->wstorage) {
454 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
456 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
461 store.store = jcr->rstore;
463 store.store = jcr->wstore;
465 set_wstorage(ua->jcr, &store);
468 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
471 Dmsg0(200, "Connected to storage daemon\n");
472 sd = ua->jcr->store_bsock;
473 sd->fsend("cancel Job=%s\n", jcr->Job);
474 while (sd->recv() >= 0) {
476 sd->signal(BNET_TERMINATE);
478 ua->jcr->store_bsock = NULL;
481 free_jcr(control_jcr);
485 static void job_monitor_destructor(watchdog_t *self)
487 JCR *control_jcr = (JCR *)self->data;
489 free_jcr(control_jcr);
492 static void job_monitor_watchdog(watchdog_t *self)
494 JCR *control_jcr, *jcr;
496 control_jcr = (JCR *)self->data;
499 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
504 if (jcr->JobId == 0 || job_canceled(jcr)) {
505 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
509 /* check MaxWaitTime */
510 if (job_check_maxwaittime(jcr)) {
511 set_jcr_job_status(jcr, JS_Canceled);
512 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
514 /* check MaxRunTime */
515 } else if (job_check_maxruntime(jcr)) {
516 set_jcr_job_status(jcr, JS_Canceled);
517 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
519 /* check MaxRunSchedTime */
520 } else if (job_check_maxschedruntime(jcr)) {
521 set_jcr_job_status(jcr, JS_Canceled);
522 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
527 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
528 UAContext *ua = new_ua_context(jcr);
529 ua->jcr = control_jcr;
532 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
536 /* Keep reference counts correct */
541 * Check if the maxwaittime has expired and it is possible
544 static bool job_check_maxwaittime(JCR *jcr)
549 if (!job_waiting(jcr)) {
552 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
553 if (job->MaxWaitTime != 0 &&
554 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
562 * Check if maxruntime has expired and if the job can be
565 static bool job_check_maxruntime(JCR *jcr)
570 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
573 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
574 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
577 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
578 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
579 job->IncMaxRunTime, job->DiffMaxRunTime);
581 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
582 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
584 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
585 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
587 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
588 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
590 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
598 * Check if MaxRunSchedTime has expired and if the job can be
601 static bool job_check_maxschedruntime(JCR *jcr)
603 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
606 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
607 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
608 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
616 * Get or create a Pool record with the given name.
617 * Returns: 0 on error
620 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
624 memset(&pr, 0, sizeof(pr));
625 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
626 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
628 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
629 /* Try to create the pool */
630 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
631 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
632 db_strerror(jcr->db));
635 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
642 * Check for duplicate jobs.
643 * Returns: true if current job should continue
644 * false if current job should terminate
646 bool allow_duplicate_job(JCR *jcr)
649 JCR *djcr; /* possible duplicate */
651 if (job->AllowDuplicateJobs) {
654 if (!job->AllowHigherDuplicates) {
657 if (strcmp(job->name(), djcr->job->name()) == 0) {
658 bool cancel_queued = false;
659 if (job->DuplicateJobProximity > 0) {
660 utime_t now = (utime_t)time(NULL);
661 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
662 continue; /* not really a duplicate */
666 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
667 /* Zap current job */
668 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
669 edit_uint64(djcr->JobId, ec1));
672 /* If CancelQueuedDuplicates is set do so only if job is queued */
673 if (job->CancelQueuedDuplicates) {
674 switch (djcr->JobStatus) {
677 case JS_WaitClientRes:
678 case JS_WaitStoreRes:
679 case JS_WaitPriority:
681 case JS_WaitStartTime:
682 cancel_queued = true;
688 if (cancel_queued || job->CancelRunningDuplicates) {
689 UAContext *ua = new_ua_context(djcr);
690 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
691 edit_uint64(djcr->JobId, ec1));
693 cancel_job(ua, djcr);
695 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
704 void apply_pool_overrides(JCR *jcr)
706 bool pool_override = false;
708 if (jcr->run_pool_override) {
709 pm_strcpy(jcr->pool_source, _("Run pool override"));
712 * Apply any level related Pool selections
714 switch (jcr->get_JobLevel()) {
716 if (jcr->full_pool) {
717 jcr->pool = jcr->full_pool;
718 pool_override = true;
719 if (jcr->run_full_pool_override) {
720 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
722 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
728 jcr->pool = jcr->inc_pool;
729 pool_override = true;
730 if (jcr->run_inc_pool_override) {
731 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
733 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
738 if (jcr->diff_pool) {
739 jcr->pool = jcr->diff_pool;
740 pool_override = true;
741 if (jcr->run_diff_pool_override) {
742 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
744 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
749 /* Update catalog if pool overridden */
750 if (pool_override && jcr->pool->catalog) {
751 jcr->catalog = jcr->pool->catalog;
752 pm_strcpy(jcr->catalog_source, _("Pool resource"));
758 * Get or create a Client record for this Job
760 bool get_or_create_client_record(JCR *jcr)
764 memset(&cr, 0, sizeof(cr));
765 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
766 cr.AutoPrune = jcr->client->AutoPrune;
767 cr.FileRetention = jcr->client->FileRetention;
768 cr.JobRetention = jcr->client->JobRetention;
769 if (!jcr->client_name) {
770 jcr->client_name = get_pool_memory(PM_NAME);
772 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
773 if (!db_create_client_record(jcr, jcr->db, &cr)) {
774 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
775 db_strerror(jcr->db));
778 jcr->jr.ClientId = cr.ClientId;
780 if (!jcr->client_uname) {
781 jcr->client_uname = get_pool_memory(PM_NAME);
783 pm_strcpy(jcr->client_uname, cr.Uname);
785 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
790 bool get_or_create_fileset_record(JCR *jcr)
794 * Get or Create FileSet record
796 memset(&fsr, 0, sizeof(FILESET_DBR));
797 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
798 if (jcr->fileset->have_MD5) {
799 struct MD5Context md5c;
800 unsigned char digest[MD5HashSize];
801 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
802 MD5Final(digest, &md5c);
804 * Keep the flag (last arg) set to false otherwise old FileSets will
805 * get new MD5 sums and the user will get Full backups on everything
807 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
808 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
810 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
812 if (!jcr->fileset->ignore_fs_changes ||
813 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
814 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
815 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
816 fsr.FileSet, db_strerror(jcr->db));
820 jcr->jr.FileSetId = fsr.FileSetId;
821 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
822 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
827 void init_jcr_job_record(JCR *jcr)
829 jcr->jr.SchedTime = jcr->sched_time;
830 jcr->jr.StartTime = jcr->start_time;
831 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
832 jcr->jr.JobType = jcr->get_JobType();
833 jcr->jr.JobLevel = jcr->get_JobLevel();
834 jcr->jr.JobStatus = jcr->JobStatus;
835 jcr->jr.JobId = jcr->JobId;
836 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
837 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
841 * Write status and such in DB
843 void update_job_end_record(JCR *jcr)
845 jcr->jr.EndTime = time(NULL);
846 jcr->end_time = jcr->jr.EndTime;
847 jcr->jr.JobId = jcr->JobId;
848 jcr->jr.JobStatus = jcr->JobStatus;
849 jcr->jr.JobFiles = jcr->JobFiles;
850 jcr->jr.JobBytes = jcr->JobBytes;
851 jcr->jr.VolSessionId = jcr->VolSessionId;
852 jcr->jr.VolSessionTime = jcr->VolSessionTime;
853 jcr->jr.JobErrors = jcr->Errors;
854 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
855 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
856 db_strerror(jcr->db));
861 * Takes base_name and appends (unique) current
862 * date and time to form unique job name.
864 * Note, the seconds are actually a sequence number. This
865 * permits us to start a maximum fo 59 unique jobs a second, which
866 * should be sufficient.
868 * Returns: unique job name in jcr->Job
869 * date/time in jcr->start_time
871 void create_unique_job_name(JCR *jcr, const char *base_name)
873 /* Job start mutex */
874 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
875 static time_t last_start_time = 0;
877 time_t now = time(NULL);
879 char dt[MAX_TIME_LENGTH];
880 char name[MAX_NAME_LENGTH];
884 /* Guarantee unique start time -- maximum one per second, and
885 * thus unique Job Name
887 P(mutex); /* lock creation of jobs */
889 if (seq > 59) { /* wrap as if it is seconds */
891 while (now == last_start_time) {
892 bmicrosleep(0, 500000);
896 last_start_time = now;
897 V(mutex); /* allow creation of jobs */
898 jcr->start_time = now;
899 /* Form Unique JobName */
900 (void)localtime_r(&now, &tm);
901 /* Use only characters that are permitted in Windows filenames */
902 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
903 len = strlen(dt) + 5; /* dt + .%02d EOS */
904 bstrncpy(name, base_name, sizeof(name));
905 name[sizeof(name)-len] = 0; /* truncate if too long */
906 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
907 /* Convert spaces into underscores */
908 for (p=jcr->Job; *p; p++) {
913 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
916 /* Called directly from job rescheduling */
917 void dird_free_jcr_pointers(JCR *jcr)
919 if (jcr->sd_auth_key) {
920 free(jcr->sd_auth_key);
921 jcr->sd_auth_key = NULL;
927 if (jcr->file_bsock) {
928 Dmsg0(200, "Close File bsock\n");
929 bnet_close(jcr->file_bsock);
930 jcr->file_bsock = NULL;
932 if (jcr->store_bsock) {
933 Dmsg0(200, "Close Store bsock\n");
934 bnet_close(jcr->store_bsock);
935 jcr->store_bsock = NULL;
938 Dmsg0(200, "Free JCR fname\n");
939 free_pool_memory(jcr->fname);
942 if (jcr->RestoreBootstrap) {
943 free(jcr->RestoreBootstrap);
944 jcr->RestoreBootstrap = NULL;
946 if (jcr->client_uname) {
947 free_pool_memory(jcr->client_uname);
948 jcr->client_uname = NULL;
951 free_pool_memory(jcr->attr);
961 * Free the Job Control Record if no one is still using it.
962 * Called from main free_jcr() routine in src/lib/jcr.c so
963 * that we can do our Director specific cleanup of the jcr.
965 void dird_free_jcr(JCR *jcr)
967 Dmsg0(200, "Start dird free_jcr\n");
969 dird_free_jcr_pointers(jcr);
970 if (jcr->term_wait_inited) {
971 pthread_cond_destroy(&jcr->term_wait);
972 jcr->term_wait_inited = false;
975 db_close_database(jcr, jcr->db_batch);
976 jcr->db_batch = NULL;
977 jcr->batch_started = false;
980 db_close_database(jcr, jcr->db);
984 Dmsg0(200, "Free JCR stime\n");
985 free_pool_memory(jcr->stime);
989 Dmsg0(200, "Free JCR fname\n");
990 free_pool_memory(jcr->fname);
993 if (jcr->pool_source) {
994 free_pool_memory(jcr->pool_source);
995 jcr->pool_source = NULL;
997 if (jcr->catalog_source) {
998 free_pool_memory(jcr->catalog_source);
999 jcr->catalog_source = NULL;
1001 if (jcr->rpool_source) {
1002 free_pool_memory(jcr->rpool_source);
1003 jcr->rpool_source = NULL;
1005 if (jcr->wstore_source) {
1006 free_pool_memory(jcr->wstore_source);
1007 jcr->wstore_source = NULL;
1009 if (jcr->rstore_source) {
1010 free_pool_memory(jcr->rstore_source);
1011 jcr->rstore_source = NULL;
1014 /* Delete lists setup to hold storage pointers */
1015 free_rwstorage(jcr);
1017 jcr->job_end_push.destroy();
1019 if (jcr->JobId != 0)
1020 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1022 Dmsg0(200, "End dird free_jcr\n");
1026 * The Job storage definition must be either in the Job record
1027 * or in the Pool record. The Pool record overrides the Job
1030 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1032 if (run && run->pool && run->pool->storage) {
1033 store->store = (STORE *)run->pool->storage->first();
1034 pm_strcpy(store->store_source, _("Run pool override"));
1037 if (run && run->storage) {
1038 store->store = run->storage;
1039 pm_strcpy(store->store_source, _("Run storage override"));
1042 if (job->pool->storage) {
1043 store->store = (STORE *)job->pool->storage->first();
1044 pm_strcpy(store->store_source, _("Pool resource"));
1046 store->store = (STORE *)job->storage->first();
1047 pm_strcpy(store->store_source, _("Job resource"));
1052 * Set some defaults in the JCR necessary to
1053 * run. These items are pulled from the job
1054 * definition as defaults, but can be overridden
1055 * later either by the Run record in the Schedule resource,
1056 * or by the Console program.
1058 void set_jcr_defaults(JCR *jcr, JOB *job)
1061 jcr->set_JobType(job->JobType);
1062 jcr->JobStatus = JS_Created;
1064 switch (jcr->get_JobType()) {
1066 jcr->set_JobLevel(L_NONE);
1069 jcr->set_JobLevel(job->JobLevel);
1074 jcr->fname = get_pool_memory(PM_FNAME);
1076 if (!jcr->pool_source) {
1077 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1078 pm_strcpy(jcr->pool_source, _("unknown source"));
1080 if (!jcr->catalog_source) {
1081 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1082 pm_strcpy(jcr->catalog_source, _("unknown source"));
1085 jcr->JobPriority = job->Priority;
1086 /* Copy storage definitions -- deleted in dir_free_jcr above */
1088 copy_rwstorage(jcr, job->storage, _("Job resource"));
1090 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1092 jcr->client = job->client;
1093 if (!jcr->client_name) {
1094 jcr->client_name = get_pool_memory(PM_NAME);
1096 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1097 pm_strcpy(jcr->pool_source, _("Job resource"));
1098 jcr->pool = job->pool;
1099 jcr->full_pool = job->full_pool;
1100 jcr->inc_pool = job->inc_pool;
1101 jcr->diff_pool = job->diff_pool;
1102 if (job->pool->catalog) {
1103 jcr->catalog = job->pool->catalog;
1104 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1106 jcr->catalog = job->client->catalog;
1107 pm_strcpy(jcr->catalog_source, _("Client resource"));
1109 jcr->fileset = job->fileset;
1110 jcr->messages = job->messages;
1111 jcr->spool_data = job->spool_data;
1112 jcr->spool_size = job->spool_size;
1113 jcr->write_part_after_job = job->write_part_after_job;
1114 jcr->accurate = job->accurate;
1115 if (jcr->RestoreBootstrap) {
1116 free(jcr->RestoreBootstrap);
1117 jcr->RestoreBootstrap = NULL;
1119 /* This can be overridden by Console program */
1120 if (job->RestoreBootstrap) {
1121 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1123 /* This can be overridden by Console program */
1124 jcr->verify_job = job->verify_job;
1125 /* If no default level given, set one */
1126 if (jcr->get_JobLevel() == 0) {
1127 switch (jcr->get_JobType()) {
1129 jcr->set_JobLevel(L_VERIFY_CATALOG);
1132 jcr->set_JobLevel(L_INCREMENTAL);
1136 jcr->set_JobLevel(L_NONE);
1139 jcr->set_JobLevel(L_FULL);
1146 * Copy the storage definitions from an alist to the JCR
1148 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1150 if (jcr->JobReads()) {
1151 copy_rstorage(jcr, storage, where);
1153 copy_wstorage(jcr, storage, where);
1157 /* Set storage override. Releases any previous storage definition */
1158 void set_rwstorage(JCR *jcr, USTORE *store)
1161 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1164 if (jcr->JobReads()) {
1165 set_rstorage(jcr, store);
1167 set_wstorage(jcr, store);
1170 void free_rwstorage(JCR *jcr)
1177 * Copy the storage definitions from an alist to the JCR
1179 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1183 if (jcr->rstorage) {
1184 delete jcr->rstorage;
1186 jcr->rstorage = New(alist(10, not_owned_by_alist));
1187 foreach_alist(st, storage) {
1188 jcr->rstorage->append(st);
1190 if (!jcr->rstore_source) {
1191 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1193 pm_strcpy(jcr->rstore_source, where);
1194 if (jcr->rstorage) {
1195 jcr->rstore = (STORE *)jcr->rstorage->first();
1201 /* Set storage override. Remove all previous storage */
1202 void set_rstorage(JCR *jcr, USTORE *store)
1206 if (!store->store) {
1209 if (jcr->rstorage) {
1212 if (!jcr->rstorage) {
1213 jcr->rstorage = New(alist(10, not_owned_by_alist));
1215 jcr->rstore = store->store;
1216 if (!jcr->rstore_source) {
1217 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1219 pm_strcpy(jcr->rstore_source, store->store_source);
1220 foreach_alist(storage, jcr->rstorage) {
1221 if (store->store == storage) {
1225 /* Store not in list, so add it */
1226 jcr->rstorage->prepend(store->store);
1229 void free_rstorage(JCR *jcr)
1231 if (jcr->rstorage) {
1232 delete jcr->rstorage;
1233 jcr->rstorage = NULL;
1239 * Copy the storage definitions from an alist to the JCR
1241 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1245 if (jcr->wstorage) {
1246 delete jcr->wstorage;
1248 jcr->wstorage = New(alist(10, not_owned_by_alist));
1249 foreach_alist(st, storage) {
1250 Dmsg1(100, "wstorage=%s\n", st->name());
1251 jcr->wstorage->append(st);
1253 if (!jcr->wstore_source) {
1254 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1256 pm_strcpy(jcr->wstore_source, where);
1257 if (jcr->wstorage) {
1258 jcr->wstore = (STORE *)jcr->wstorage->first();
1259 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1265 /* Set storage override. Remove all previous storage */
1266 void set_wstorage(JCR *jcr, USTORE *store)
1270 if (!store->store) {
1273 if (jcr->wstorage) {
1276 if (!jcr->wstorage) {
1277 jcr->wstorage = New(alist(10, not_owned_by_alist));
1279 jcr->wstore = store->store;
1280 if (!jcr->wstore_source) {
1281 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1283 pm_strcpy(jcr->wstore_source, store->store_source);
1284 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1285 foreach_alist(storage, jcr->wstorage) {
1286 if (store->store == storage) {
1290 /* Store not in list, so add it */
1291 jcr->wstorage->prepend(store->store);
1294 void free_wstorage(JCR *jcr)
1296 if (jcr->wstorage) {
1297 delete jcr->wstorage;
1298 jcr->wstorage = NULL;
1303 char *job_code_callback_clones(JCR *jcr, const char* param)
1305 if (param[0] == 'p') {
1306 return jcr->pool->name();
1311 void create_clones(JCR *jcr)
1314 * Fire off any clone jobs (run directives)
1316 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1317 if (!jcr->cloned && jcr->job->run_cmds) {
1319 JOB *job = jcr->job;
1320 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1321 UAContext *ua = new_ua_context(jcr);
1323 foreach_alist(runcmd, job->run_cmds) {
1324 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1325 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1326 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1327 parse_ua_args(ua); /* parse command */
1328 int stat = run_cmd(ua, ua->cmd);
1330 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1332 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1335 free_ua_context(ua);
1336 free_pool_memory(cmd);
1341 * Given: a JobId in jcr->previous_jr.JobId,
1342 * this subroutine writes a bsr file to restore that job.
1344 bool create_restore_bootstrap_file(JCR *jcr)
1348 memset(&rx, 0, sizeof(rx));
1350 rx.JobIds = (char *)"";
1351 rx.bsr->JobId = jcr->previous_jr.JobId;
1352 ua = new_ua_context(jcr);
1353 complete_bsr(ua, rx.bsr);
1354 rx.bsr->fi = new_findex();
1355 rx.bsr->fi->findex = 1;
1356 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1357 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1358 if (jcr->ExpectedFiles == 0) {
1359 free_ua_context(ua);
1363 free_ua_context(ua);
1365 jcr->needs_sd = true;
1369 /* TODO: redirect command ouput to job log */
1370 bool run_console_command(JCR *jcr, const char *cmd){
1373 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1374 ua = new_ua_context(ljcr);
1375 /* run from runscript and check if commands are autorized */
1376 ua->runscript = true;
1377 Mmsg(ua->cmd, "%s", cmd);
1378 Dmsg1(100, "Console command: %s\n", ua->cmd);
1380 ok= do_a_command(ua);
1381 free_ua_context(ua);