2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 jcr->setJobStatus(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");
176 new_plugins(jcr); /* instantiate plugins for this jcr */
177 generate_plugin_event(jcr, bEventJobStart);
179 if (job_canceled(jcr)) {
183 if (jcr->JobReads() && !jcr->rstorage) {
184 if (jcr->job->storage) {
185 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
187 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
190 if (!jcr->JobReads()) {
195 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
196 * this allows us to setup a proper job start record for restarting
197 * in case of later errors.
199 switch (jcr->get_JobType()) {
201 if (!do_backup_init(jcr)) {
202 backup_cleanup(jcr, JS_ErrorTerminated);
207 if (!do_verify_init(jcr)) {
208 verify_cleanup(jcr, JS_ErrorTerminated);
213 if (!do_restore_init(jcr)) {
214 restore_cleanup(jcr, JS_ErrorTerminated);
219 if (!do_admin_init(jcr)) {
220 admin_cleanup(jcr, JS_ErrorTerminated);
226 if (!do_migration_init(jcr)) {
227 migration_cleanup(jcr, JS_ErrorTerminated);
232 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
233 set_jcr_job_status(jcr, JS_ErrorTerminated);
237 generate_job_event(jcr, "JobInit");
238 generate_plugin_event(jcr, bEventJobInit);
246 void update_job_end(JCR *jcr, int TermCode)
248 dequeue_messages(jcr); /* display any queued messages */
249 set_jcr_job_status(jcr, TermCode);
250 update_job_end_record(jcr);
254 * This is the engine called by jobq.c:jobq_add() when we were pulled
255 * from the work queue.
256 * At this point, we are running in our own thread and all
257 * necessary resources are allocated -- see jobq.c
259 static void *job_thread(void *arg)
261 JCR *jcr = (JCR *)arg;
263 pthread_detach(pthread_self());
266 Dmsg0(200, "=====Start Job=========\n");
267 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
268 jcr->start_time = time(NULL); /* set the real start time */
269 jcr->jr.StartTime = jcr->start_time;
271 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
272 (utime_t)(jcr->start_time - jcr->sched_time)) {
273 jcr->setJobStatus(JS_Canceled);
274 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
277 if (job_check_maxschedruntime(jcr)) {
278 jcr->setJobStatus(JS_Canceled);
279 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
282 /* TODO : check if it is used somewhere */
283 if (jcr->job->RunScripts == NULL) {
284 Dmsg0(200, "Warning, job->RunScripts is empty\n");
285 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
288 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
289 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
292 /* Run any script BeforeJob on dird */
293 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
296 * We re-update the job start record so that the start
297 * time is set after the run before job. This avoids
298 * that any files created by the run before job will
299 * be saved twice. They will be backed up in the current
300 * job, but not in the next one unless they are changed.
301 * Without this, they will be backed up in this job and
302 * in the next job run because in that case, their date
303 * is after the start of this run.
305 jcr->start_time = time(NULL);
306 jcr->jr.StartTime = jcr->start_time;
307 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
308 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
310 generate_job_event(jcr, "JobRun");
311 generate_plugin_event(jcr, bEventJobRun);
313 switch (jcr->get_JobType()) {
315 if (!job_canceled(jcr) && do_backup(jcr)) {
318 backup_cleanup(jcr, JS_ErrorTerminated);
322 if (!job_canceled(jcr) && do_verify(jcr)) {
325 verify_cleanup(jcr, JS_ErrorTerminated);
329 if (!job_canceled(jcr) && do_restore(jcr)) {
332 restore_cleanup(jcr, JS_ErrorTerminated);
336 if (!job_canceled(jcr) && do_admin(jcr)) {
339 admin_cleanup(jcr, JS_ErrorTerminated);
344 if (!job_canceled(jcr) && do_migration(jcr)) {
347 migration_cleanup(jcr, JS_ErrorTerminated);
351 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
355 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
357 /* Send off any queued messages */
358 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
359 dequeue_messages(jcr);
362 generate_daemon_event(jcr, "JobEnd");
363 generate_plugin_event(jcr, bEventJobEnd);
364 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
365 sm_check(__FILE__, __LINE__, true);
371 * Cancel a job -- typically called by the UA (Console program), but may also
372 * be called by the job watchdog.
374 * Returns: true if cancel appears to be successful
375 * false on failure. Message sent to ua->jcr.
377 bool cancel_job(UAContext *ua, JCR *jcr)
381 int32_t old_status = jcr->JobStatus;
383 set_jcr_job_status(jcr, JS_Canceled);
385 switch (old_status) {
388 case JS_WaitClientRes:
389 case JS_WaitStoreRes:
390 case JS_WaitPriority:
392 case JS_WaitStartTime:
393 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
394 edit_uint64(jcr->JobId, ed1), jcr->Job);
395 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
399 /* Cancel File daemon */
400 if (jcr->file_bsock) {
401 ua->jcr->client = jcr->client;
402 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
403 ua->error_msg(_("Failed to connect to File daemon.\n"));
406 Dmsg0(200, "Connected to file daemon\n");
407 fd = ua->jcr->file_bsock;
408 fd->fsend("cancel Job=%s\n", jcr->Job);
409 while (fd->recv() >= 0) {
410 ua->send_msg("%s", fd->msg);
412 fd->signal(BNET_TERMINATE);
414 ua->jcr->file_bsock = NULL;
417 /* Cancel Storage daemon */
418 if (jcr->store_bsock) {
419 if (!ua->jcr->wstorage) {
421 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
423 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
428 store.store = jcr->rstore;
430 store.store = jcr->wstore;
432 set_wstorage(ua->jcr, &store);
435 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
436 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
439 Dmsg0(200, "Connected to storage daemon\n");
440 sd = ua->jcr->store_bsock;
441 sd->fsend("cancel Job=%s\n", jcr->Job);
442 while (sd->recv() >= 0) {
443 ua->send_msg("%s", sd->msg);
445 sd->signal(BNET_TERMINATE);
447 ua->jcr->store_bsock = NULL;
455 void cancel_storage_daemon_job(JCR *jcr)
457 if (jcr->sd_canceled) {
458 return; /* cancel only once */
461 UAContext *ua = new_ua_context(jcr);
462 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
465 ua->jcr = control_jcr;
466 if (jcr->store_bsock) {
467 if (!ua->jcr->wstorage) {
469 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
471 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
476 store.store = jcr->rstore;
478 store.store = jcr->wstore;
480 set_wstorage(ua->jcr, &store);
483 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
486 Dmsg0(200, "Connected to storage daemon\n");
487 sd = ua->jcr->store_bsock;
488 sd->fsend("cancel Job=%s\n", jcr->Job);
489 while (sd->recv() >= 0) {
491 sd->signal(BNET_TERMINATE);
493 ua->jcr->store_bsock = NULL;
494 jcr->sd_canceled = true;
497 free_jcr(control_jcr);
501 static void job_monitor_destructor(watchdog_t *self)
503 JCR *control_jcr = (JCR *)self->data;
505 free_jcr(control_jcr);
508 static void job_monitor_watchdog(watchdog_t *self)
510 JCR *control_jcr, *jcr;
512 control_jcr = (JCR *)self->data;
515 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
520 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
521 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
525 /* check MaxWaitTime */
526 if (job_check_maxwaittime(jcr)) {
527 set_jcr_job_status(jcr, JS_Canceled);
528 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
530 /* check MaxRunTime */
531 } else if (job_check_maxruntime(jcr)) {
532 set_jcr_job_status(jcr, JS_Canceled);
533 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
535 /* check MaxRunSchedTime */
536 } else if (job_check_maxschedruntime(jcr)) {
537 set_jcr_job_status(jcr, JS_Canceled);
538 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
543 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
544 UAContext *ua = new_ua_context(jcr);
545 ua->jcr = control_jcr;
548 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
552 /* Keep reference counts correct */
557 * Check if the maxwaittime has expired and it is possible
560 static bool job_check_maxwaittime(JCR *jcr)
566 if (!job_waiting(jcr)) {
570 if (jcr->wait_time) {
571 current = watchdog_time - jcr->wait_time;
574 Dmsg2(200, "check maxwaittime %u >= %u\n",
575 current + jcr->wait_time_sum, job->MaxWaitTime);
576 if (job->MaxWaitTime != 0 &&
577 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
585 * Check if maxruntime has expired and if the job can be
588 static bool job_check_maxruntime(JCR *jcr)
594 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
597 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
598 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
601 run_time = watchdog_time - jcr->start_time;
602 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
603 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
604 job->IncMaxRunTime, job->DiffMaxRunTime);
606 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
607 run_time >= job->FullMaxRunTime) {
608 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
610 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
611 run_time >= job->DiffMaxRunTime) {
612 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
614 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
615 run_time >= job->IncMaxRunTime) {
616 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
618 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
619 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
627 * Check if MaxRunSchedTime has expired and if the job can be
630 static bool job_check_maxschedruntime(JCR *jcr)
632 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
635 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
636 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
637 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
645 * Get or create a Pool record with the given name.
646 * Returns: 0 on error
649 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
653 memset(&pr, 0, sizeof(pr));
654 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
655 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
657 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
658 /* Try to create the pool */
659 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
660 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
661 db_strerror(jcr->db));
664 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
671 * Check for duplicate jobs.
672 * Returns: true if current job should continue
673 * false if current job should terminate
675 bool allow_duplicate_job(JCR *jcr)
678 JCR *djcr; /* possible duplicate */
680 if (job->AllowDuplicateJobs) {
683 if (!job->AllowHigherDuplicates) {
685 if (jcr == djcr || djcr->JobId == 0) {
686 continue; /* do not cancel this job or consoles */
688 if (strcmp(job->name(), djcr->job->name()) == 0) {
689 bool cancel_queued = false;
690 if (job->DuplicateJobProximity > 0) {
691 utime_t now = (utime_t)time(NULL);
692 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
693 continue; /* not really a duplicate */
697 /* If CancelQueuedDuplicates is set do so only if job is queued */
698 if (job->CancelQueuedDuplicates) {
699 switch (djcr->JobStatus) {
702 case JS_WaitClientRes:
703 case JS_WaitStoreRes:
704 case JS_WaitPriority:
706 case JS_WaitStartTime:
707 cancel_queued = true;
713 if (cancel_queued || job->CancelRunningDuplicates) {
714 UAContext *ua = new_ua_context(djcr);
715 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
717 cancel_job(ua, djcr);
719 Dmsg2(800, "Have cancelled JCR %p JobId=%d\n", djcr, djcr->JobId);
721 /* Zap current job */
722 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
725 break; /* did our work, get out */
733 void apply_pool_overrides(JCR *jcr)
735 bool pool_override = false;
737 if (jcr->run_pool_override) {
738 pm_strcpy(jcr->pool_source, _("Run pool override"));
741 * Apply any level related Pool selections
743 switch (jcr->get_JobLevel()) {
745 if (jcr->full_pool) {
746 jcr->pool = jcr->full_pool;
747 pool_override = true;
748 if (jcr->run_full_pool_override) {
749 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
751 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
757 jcr->pool = jcr->inc_pool;
758 pool_override = true;
759 if (jcr->run_inc_pool_override) {
760 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
762 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
767 if (jcr->diff_pool) {
768 jcr->pool = jcr->diff_pool;
769 pool_override = true;
770 if (jcr->run_diff_pool_override) {
771 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
773 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
778 /* Update catalog if pool overridden */
779 if (pool_override && jcr->pool->catalog) {
780 jcr->catalog = jcr->pool->catalog;
781 pm_strcpy(jcr->catalog_source, _("Pool resource"));
787 * Get or create a Client record for this Job
789 bool get_or_create_client_record(JCR *jcr)
793 memset(&cr, 0, sizeof(cr));
794 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
795 cr.AutoPrune = jcr->client->AutoPrune;
796 cr.FileRetention = jcr->client->FileRetention;
797 cr.JobRetention = jcr->client->JobRetention;
798 if (!jcr->client_name) {
799 jcr->client_name = get_pool_memory(PM_NAME);
801 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
802 if (!db_create_client_record(jcr, jcr->db, &cr)) {
803 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
804 db_strerror(jcr->db));
807 jcr->jr.ClientId = cr.ClientId;
809 if (!jcr->client_uname) {
810 jcr->client_uname = get_pool_memory(PM_NAME);
812 pm_strcpy(jcr->client_uname, cr.Uname);
814 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
819 bool get_or_create_fileset_record(JCR *jcr)
823 * Get or Create FileSet record
825 memset(&fsr, 0, sizeof(FILESET_DBR));
826 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
827 if (jcr->fileset->have_MD5) {
828 struct MD5Context md5c;
829 unsigned char digest[MD5HashSize];
830 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
831 MD5Final(digest, &md5c);
833 * Keep the flag (last arg) set to false otherwise old FileSets will
834 * get new MD5 sums and the user will get Full backups on everything
836 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
837 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
839 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
841 if (!jcr->fileset->ignore_fs_changes ||
842 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
843 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
844 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
845 fsr.FileSet, db_strerror(jcr->db));
849 jcr->jr.FileSetId = fsr.FileSetId;
850 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
851 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
856 void init_jcr_job_record(JCR *jcr)
858 jcr->jr.SchedTime = jcr->sched_time;
859 jcr->jr.StartTime = jcr->start_time;
860 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
861 jcr->jr.JobType = jcr->get_JobType();
862 jcr->jr.JobLevel = jcr->get_JobLevel();
863 jcr->jr.JobStatus = jcr->JobStatus;
864 jcr->jr.JobId = jcr->JobId;
865 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
866 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
870 * Write status and such in DB
872 void update_job_end_record(JCR *jcr)
874 jcr->jr.EndTime = time(NULL);
875 jcr->end_time = jcr->jr.EndTime;
876 jcr->jr.JobId = jcr->JobId;
877 jcr->jr.JobStatus = jcr->JobStatus;
878 jcr->jr.JobFiles = jcr->JobFiles;
879 jcr->jr.JobBytes = jcr->JobBytes;
880 jcr->jr.ReadBytes = jcr->ReadBytes;
881 jcr->jr.VolSessionId = jcr->VolSessionId;
882 jcr->jr.VolSessionTime = jcr->VolSessionTime;
883 jcr->jr.JobErrors = jcr->JobErrors;
884 jcr->jr.HasBase = jcr->HasBase;
885 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
886 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
887 db_strerror(jcr->db));
892 * Takes base_name and appends (unique) current
893 * date and time to form unique job name.
895 * Note, the seconds are actually a sequence number. This
896 * permits us to start a maximum fo 59 unique jobs a second, which
897 * should be sufficient.
899 * Returns: unique job name in jcr->Job
900 * date/time in jcr->start_time
902 void create_unique_job_name(JCR *jcr, const char *base_name)
904 /* Job start mutex */
905 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
906 static time_t last_start_time = 0;
908 time_t now = time(NULL);
910 char dt[MAX_TIME_LENGTH];
911 char name[MAX_NAME_LENGTH];
915 /* Guarantee unique start time -- maximum one per second, and
916 * thus unique Job Name
918 P(mutex); /* lock creation of jobs */
920 if (seq > 59) { /* wrap as if it is seconds */
922 while (now == last_start_time) {
923 bmicrosleep(0, 500000);
927 last_start_time = now;
928 V(mutex); /* allow creation of jobs */
929 jcr->start_time = now;
930 /* Form Unique JobName */
931 (void)localtime_r(&now, &tm);
932 /* Use only characters that are permitted in Windows filenames */
933 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
934 len = strlen(dt) + 5; /* dt + .%02d EOS */
935 bstrncpy(name, base_name, sizeof(name));
936 name[sizeof(name)-len] = 0; /* truncate if too long */
937 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
938 /* Convert spaces into underscores */
939 for (p=jcr->Job; *p; p++) {
944 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
947 /* Called directly from job rescheduling */
948 void dird_free_jcr_pointers(JCR *jcr)
950 if (jcr->sd_auth_key) {
951 free(jcr->sd_auth_key);
952 jcr->sd_auth_key = NULL;
958 if (jcr->file_bsock) {
959 Dmsg0(200, "Close File bsock\n");
960 bnet_close(jcr->file_bsock);
961 jcr->file_bsock = NULL;
963 if (jcr->store_bsock) {
964 Dmsg0(200, "Close Store bsock\n");
965 bnet_close(jcr->store_bsock);
966 jcr->store_bsock = NULL;
969 Dmsg0(200, "Free JCR fname\n");
970 free_pool_memory(jcr->fname);
973 if (jcr->RestoreBootstrap) {
974 free(jcr->RestoreBootstrap);
975 jcr->RestoreBootstrap = NULL;
977 if (jcr->client_uname) {
978 free_pool_memory(jcr->client_uname);
979 jcr->client_uname = NULL;
982 free_pool_memory(jcr->attr);
992 * Free the Job Control Record if no one is still using it.
993 * Called from main free_jcr() routine in src/lib/jcr.c so
994 * that we can do our Director specific cleanup of the jcr.
996 void dird_free_jcr(JCR *jcr)
998 Dmsg0(200, "Start dird free_jcr\n");
1000 dird_free_jcr_pointers(jcr);
1001 if (jcr->term_wait_inited) {
1002 pthread_cond_destroy(&jcr->term_wait);
1003 jcr->term_wait_inited = false;
1005 if (jcr->db_batch) {
1006 db_close_database(jcr, jcr->db_batch);
1007 jcr->db_batch = NULL;
1008 jcr->batch_started = false;
1011 db_close_database(jcr, jcr->db);
1015 Dmsg0(200, "Free JCR stime\n");
1016 free_pool_memory(jcr->stime);
1020 Dmsg0(200, "Free JCR fname\n");
1021 free_pool_memory(jcr->fname);
1024 if (jcr->pool_source) {
1025 free_pool_memory(jcr->pool_source);
1026 jcr->pool_source = NULL;
1028 if (jcr->catalog_source) {
1029 free_pool_memory(jcr->catalog_source);
1030 jcr->catalog_source = NULL;
1032 if (jcr->rpool_source) {
1033 free_pool_memory(jcr->rpool_source);
1034 jcr->rpool_source = NULL;
1036 if (jcr->wstore_source) {
1037 free_pool_memory(jcr->wstore_source);
1038 jcr->wstore_source = NULL;
1040 if (jcr->rstore_source) {
1041 free_pool_memory(jcr->rstore_source);
1042 jcr->rstore_source = NULL;
1045 /* Delete lists setup to hold storage pointers */
1046 free_rwstorage(jcr);
1048 jcr->job_end_push.destroy();
1050 if (jcr->JobId != 0)
1051 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1053 free_plugins(jcr); /* release instantiated plugins */
1055 Dmsg0(200, "End dird free_jcr\n");
1059 * The Job storage definition must be either in the Job record
1060 * or in the Pool record. The Pool record overrides the Job
1063 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1065 if (run && run->pool && run->pool->storage) {
1066 store->store = (STORE *)run->pool->storage->first();
1067 pm_strcpy(store->store_source, _("Run pool override"));
1070 if (run && run->storage) {
1071 store->store = run->storage;
1072 pm_strcpy(store->store_source, _("Run storage override"));
1075 if (job->pool->storage) {
1076 store->store = (STORE *)job->pool->storage->first();
1077 pm_strcpy(store->store_source, _("Pool resource"));
1079 store->store = (STORE *)job->storage->first();
1080 pm_strcpy(store->store_source, _("Job resource"));
1085 * Set some defaults in the JCR necessary to
1086 * run. These items are pulled from the job
1087 * definition as defaults, but can be overridden
1088 * later either by the Run record in the Schedule resource,
1089 * or by the Console program.
1091 void set_jcr_defaults(JCR *jcr, JOB *job)
1094 jcr->set_JobType(job->JobType);
1095 jcr->JobStatus = JS_Created;
1097 switch (jcr->get_JobType()) {
1099 jcr->set_JobLevel(L_NONE);
1102 jcr->set_JobLevel(job->JobLevel);
1107 jcr->fname = get_pool_memory(PM_FNAME);
1109 if (!jcr->pool_source) {
1110 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1111 pm_strcpy(jcr->pool_source, _("unknown source"));
1113 if (!jcr->catalog_source) {
1114 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1115 pm_strcpy(jcr->catalog_source, _("unknown source"));
1118 jcr->JobPriority = job->Priority;
1119 /* Copy storage definitions -- deleted in dir_free_jcr above */
1121 copy_rwstorage(jcr, job->storage, _("Job resource"));
1123 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1125 jcr->client = job->client;
1126 if (!jcr->client_name) {
1127 jcr->client_name = get_pool_memory(PM_NAME);
1129 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1130 pm_strcpy(jcr->pool_source, _("Job resource"));
1131 jcr->pool = job->pool;
1132 jcr->full_pool = job->full_pool;
1133 jcr->inc_pool = job->inc_pool;
1134 jcr->diff_pool = job->diff_pool;
1135 if (job->pool->catalog) {
1136 jcr->catalog = job->pool->catalog;
1137 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1139 jcr->catalog = job->client->catalog;
1140 pm_strcpy(jcr->catalog_source, _("Client resource"));
1142 jcr->fileset = job->fileset;
1143 jcr->messages = job->messages;
1144 jcr->spool_data = job->spool_data;
1145 jcr->spool_size = job->spool_size;
1146 jcr->write_part_after_job = job->write_part_after_job;
1147 jcr->accurate = job->accurate;
1148 if (jcr->RestoreBootstrap) {
1149 free(jcr->RestoreBootstrap);
1150 jcr->RestoreBootstrap = NULL;
1152 /* This can be overridden by Console program */
1153 if (job->RestoreBootstrap) {
1154 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1156 /* This can be overridden by Console program */
1157 jcr->verify_job = job->verify_job;
1158 /* If no default level given, set one */
1159 if (jcr->get_JobLevel() == 0) {
1160 switch (jcr->get_JobType()) {
1162 jcr->set_JobLevel(L_VERIFY_CATALOG);
1165 jcr->set_JobLevel(L_INCREMENTAL);
1169 jcr->set_JobLevel(L_NONE);
1172 jcr->set_JobLevel(L_FULL);
1179 * Copy the storage definitions from an alist to the JCR
1181 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1183 if (jcr->JobReads()) {
1184 copy_rstorage(jcr, storage, where);
1186 copy_wstorage(jcr, storage, where);
1190 /* Set storage override. Releases any previous storage definition */
1191 void set_rwstorage(JCR *jcr, USTORE *store)
1194 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1197 if (jcr->JobReads()) {
1198 set_rstorage(jcr, store);
1200 set_wstorage(jcr, store);
1203 void free_rwstorage(JCR *jcr)
1210 * Copy the storage definitions from an alist to the JCR
1212 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1216 if (jcr->rstorage) {
1217 delete jcr->rstorage;
1219 jcr->rstorage = New(alist(10, not_owned_by_alist));
1220 foreach_alist(st, storage) {
1221 jcr->rstorage->append(st);
1223 if (!jcr->rstore_source) {
1224 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1226 pm_strcpy(jcr->rstore_source, where);
1227 if (jcr->rstorage) {
1228 jcr->rstore = (STORE *)jcr->rstorage->first();
1234 /* Set storage override. Remove all previous storage */
1235 void set_rstorage(JCR *jcr, USTORE *store)
1239 if (!store->store) {
1242 if (jcr->rstorage) {
1245 if (!jcr->rstorage) {
1246 jcr->rstorage = New(alist(10, not_owned_by_alist));
1248 jcr->rstore = store->store;
1249 if (!jcr->rstore_source) {
1250 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1252 pm_strcpy(jcr->rstore_source, store->store_source);
1253 foreach_alist(storage, jcr->rstorage) {
1254 if (store->store == storage) {
1258 /* Store not in list, so add it */
1259 jcr->rstorage->prepend(store->store);
1262 void free_rstorage(JCR *jcr)
1264 if (jcr->rstorage) {
1265 delete jcr->rstorage;
1266 jcr->rstorage = NULL;
1272 * Copy the storage definitions from an alist to the JCR
1274 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1278 if (jcr->wstorage) {
1279 delete jcr->wstorage;
1281 jcr->wstorage = New(alist(10, not_owned_by_alist));
1282 foreach_alist(st, storage) {
1283 Dmsg1(100, "wstorage=%s\n", st->name());
1284 jcr->wstorage->append(st);
1286 if (!jcr->wstore_source) {
1287 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1289 pm_strcpy(jcr->wstore_source, where);
1290 if (jcr->wstorage) {
1291 jcr->wstore = (STORE *)jcr->wstorage->first();
1292 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1298 /* Set storage override. Remove all previous storage */
1299 void set_wstorage(JCR *jcr, USTORE *store)
1303 if (!store->store) {
1306 if (jcr->wstorage) {
1309 if (!jcr->wstorage) {
1310 jcr->wstorage = New(alist(10, not_owned_by_alist));
1312 jcr->wstore = store->store;
1313 if (!jcr->wstore_source) {
1314 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1316 pm_strcpy(jcr->wstore_source, store->store_source);
1317 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1318 foreach_alist(storage, jcr->wstorage) {
1319 if (store->store == storage) {
1323 /* Store not in list, so add it */
1324 jcr->wstorage->prepend(store->store);
1327 void free_wstorage(JCR *jcr)
1329 if (jcr->wstorage) {
1330 delete jcr->wstorage;
1331 jcr->wstorage = NULL;
1336 char *job_code_callback_clones(JCR *jcr, const char* param)
1338 if (param[0] == 'p') {
1339 return jcr->pool->name();
1344 void create_clones(JCR *jcr)
1347 * Fire off any clone jobs (run directives)
1349 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1350 if (!jcr->cloned && jcr->job->run_cmds) {
1352 JOB *job = jcr->job;
1353 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1354 UAContext *ua = new_ua_context(jcr);
1356 foreach_alist(runcmd, job->run_cmds) {
1357 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1358 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1359 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1360 parse_ua_args(ua); /* parse command */
1361 int stat = run_cmd(ua, ua->cmd);
1363 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1366 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1369 free_ua_context(ua);
1370 free_pool_memory(cmd);
1375 * Given: a JobId in jcr->previous_jr.JobId,
1376 * this subroutine writes a bsr file to restore that job.
1377 * Returns: -1 on error
1378 * number of files if OK
1380 int create_restore_bootstrap_file(JCR *jcr)
1386 memset(&rx, 0, sizeof(rx));
1388 rx.JobIds = (char *)"";
1389 rx.bsr->JobId = jcr->previous_jr.JobId;
1390 ua = new_ua_context(jcr);
1391 if (!complete_bsr(ua, rx.bsr)) {
1395 rx.bsr->fi = new_findex();
1396 rx.bsr->fi->findex = 1;
1397 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1398 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1399 if (jcr->ExpectedFiles == 0) {
1403 free_ua_context(ua);
1405 jcr->needs_sd = true;
1406 return jcr->ExpectedFiles;
1409 free_ua_context(ua);
1414 /* TODO: redirect command ouput to job log */
1415 bool run_console_command(JCR *jcr, const char *cmd)
1419 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1420 ua = new_ua_context(ljcr);
1421 /* run from runscript and check if commands are autorized */
1422 ua->runscript = true;
1423 Mmsg(ua->cmd, "%s", cmd);
1424 Dmsg1(100, "Console command: %s\n", ua->cmd);
1426 ok= do_a_command(ua);
1427 free_ua_context(ua);