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 UAContext *ua = new_ua_context(jcr);
458 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
461 ua->jcr = control_jcr;
462 if (jcr->store_bsock) {
463 if (!ua->jcr->wstorage) {
465 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
467 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
472 store.store = jcr->rstore;
474 store.store = jcr->wstore;
476 set_wstorage(ua->jcr, &store);
479 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
482 Dmsg0(200, "Connected to storage daemon\n");
483 sd = ua->jcr->store_bsock;
484 sd->fsend("cancel Job=%s\n", jcr->Job);
485 while (sd->recv() >= 0) {
487 sd->signal(BNET_TERMINATE);
489 ua->jcr->store_bsock = NULL;
492 free_jcr(control_jcr);
496 static void job_monitor_destructor(watchdog_t *self)
498 JCR *control_jcr = (JCR *)self->data;
500 free_jcr(control_jcr);
503 static void job_monitor_watchdog(watchdog_t *self)
505 JCR *control_jcr, *jcr;
507 control_jcr = (JCR *)self->data;
510 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
515 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
516 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
520 /* check MaxWaitTime */
521 if (job_check_maxwaittime(jcr)) {
522 set_jcr_job_status(jcr, JS_Canceled);
523 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
525 /* check MaxRunTime */
526 } else if (job_check_maxruntime(jcr)) {
527 set_jcr_job_status(jcr, JS_Canceled);
528 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
530 /* check MaxRunSchedTime */
531 } else if (job_check_maxschedruntime(jcr)) {
532 set_jcr_job_status(jcr, JS_Canceled);
533 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
538 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
539 UAContext *ua = new_ua_context(jcr);
540 ua->jcr = control_jcr;
543 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
547 /* Keep reference counts correct */
552 * Check if the maxwaittime has expired and it is possible
555 static bool job_check_maxwaittime(JCR *jcr)
561 if (!job_waiting(jcr)) {
565 if (jcr->wait_time) {
566 current = watchdog_time - jcr->wait_time;
569 Dmsg2(200, "check maxwaittime %u >= %u\n",
570 current + jcr->wait_time_sum, job->MaxWaitTime);
571 if (job->MaxWaitTime != 0 &&
572 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
580 * Check if maxruntime has expired and if the job can be
583 static bool job_check_maxruntime(JCR *jcr)
589 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
592 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
593 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
596 run_time = watchdog_time - jcr->start_time;
597 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
598 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
599 job->IncMaxRunTime, job->DiffMaxRunTime);
601 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
602 run_time >= job->FullMaxRunTime) {
603 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
605 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
606 run_time >= job->DiffMaxRunTime) {
607 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
609 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
610 run_time >= job->IncMaxRunTime) {
611 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
613 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
614 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
622 * Check if MaxRunSchedTime has expired and if the job can be
625 static bool job_check_maxschedruntime(JCR *jcr)
627 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
630 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
631 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
632 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
640 * Get or create a Pool record with the given name.
641 * Returns: 0 on error
644 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
648 memset(&pr, 0, sizeof(pr));
649 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
650 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
652 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
653 /* Try to create the pool */
654 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
655 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
656 db_strerror(jcr->db));
659 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
666 * Check for duplicate jobs.
667 * Returns: true if current job should continue
668 * false if current job should terminate
670 bool allow_duplicate_job(JCR *jcr)
673 JCR *djcr; /* possible duplicate */
675 if (job->AllowDuplicateJobs) {
678 if (!job->AllowHigherDuplicates) {
680 if (jcr == djcr || djcr->JobId == 0) {
681 continue; /* do not cancel this job or consoles */
683 if (strcmp(job->name(), djcr->job->name()) == 0) {
684 bool cancel_queued = false;
685 if (job->DuplicateJobProximity > 0) {
686 utime_t now = (utime_t)time(NULL);
687 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
688 continue; /* not really a duplicate */
692 /* If CancelQueuedDuplicates is set do so only if job is queued */
693 if (job->CancelQueuedDuplicates) {
694 switch (djcr->JobStatus) {
697 case JS_WaitClientRes:
698 case JS_WaitStoreRes:
699 case JS_WaitPriority:
701 case JS_WaitStartTime:
702 cancel_queued = true;
708 if (cancel_queued || job->CancelRunningDuplicates) {
709 UAContext *ua = new_ua_context(djcr);
710 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
712 cancel_job(ua, djcr);
714 Dmsg2(800, "Have cancelled JCR %p JobId=%d\n", djcr, djcr->JobId);
716 /* Zap current job */
717 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
720 break; /* did our work, get out */
728 void apply_pool_overrides(JCR *jcr)
730 bool pool_override = false;
732 if (jcr->run_pool_override) {
733 pm_strcpy(jcr->pool_source, _("Run pool override"));
736 * Apply any level related Pool selections
738 switch (jcr->get_JobLevel()) {
740 if (jcr->full_pool) {
741 jcr->pool = jcr->full_pool;
742 pool_override = true;
743 if (jcr->run_full_pool_override) {
744 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
746 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
752 jcr->pool = jcr->inc_pool;
753 pool_override = true;
754 if (jcr->run_inc_pool_override) {
755 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
757 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
762 if (jcr->diff_pool) {
763 jcr->pool = jcr->diff_pool;
764 pool_override = true;
765 if (jcr->run_diff_pool_override) {
766 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
768 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
773 /* Update catalog if pool overridden */
774 if (pool_override && jcr->pool->catalog) {
775 jcr->catalog = jcr->pool->catalog;
776 pm_strcpy(jcr->catalog_source, _("Pool resource"));
782 * Get or create a Client record for this Job
784 bool get_or_create_client_record(JCR *jcr)
788 memset(&cr, 0, sizeof(cr));
789 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
790 cr.AutoPrune = jcr->client->AutoPrune;
791 cr.FileRetention = jcr->client->FileRetention;
792 cr.JobRetention = jcr->client->JobRetention;
793 if (!jcr->client_name) {
794 jcr->client_name = get_pool_memory(PM_NAME);
796 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
797 if (!db_create_client_record(jcr, jcr->db, &cr)) {
798 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
799 db_strerror(jcr->db));
802 jcr->jr.ClientId = cr.ClientId;
804 if (!jcr->client_uname) {
805 jcr->client_uname = get_pool_memory(PM_NAME);
807 pm_strcpy(jcr->client_uname, cr.Uname);
809 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
814 bool get_or_create_fileset_record(JCR *jcr)
818 * Get or Create FileSet record
820 memset(&fsr, 0, sizeof(FILESET_DBR));
821 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
822 if (jcr->fileset->have_MD5) {
823 struct MD5Context md5c;
824 unsigned char digest[MD5HashSize];
825 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
826 MD5Final(digest, &md5c);
828 * Keep the flag (last arg) set to false otherwise old FileSets will
829 * get new MD5 sums and the user will get Full backups on everything
831 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
832 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
834 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
836 if (!jcr->fileset->ignore_fs_changes ||
837 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
838 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
839 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
840 fsr.FileSet, db_strerror(jcr->db));
844 jcr->jr.FileSetId = fsr.FileSetId;
845 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
846 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
851 void init_jcr_job_record(JCR *jcr)
853 jcr->jr.SchedTime = jcr->sched_time;
854 jcr->jr.StartTime = jcr->start_time;
855 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
856 jcr->jr.JobType = jcr->get_JobType();
857 jcr->jr.JobLevel = jcr->get_JobLevel();
858 jcr->jr.JobStatus = jcr->JobStatus;
859 jcr->jr.JobId = jcr->JobId;
860 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
861 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
865 * Write status and such in DB
867 void update_job_end_record(JCR *jcr)
869 jcr->jr.EndTime = time(NULL);
870 jcr->end_time = jcr->jr.EndTime;
871 jcr->jr.JobId = jcr->JobId;
872 jcr->jr.JobStatus = jcr->JobStatus;
873 jcr->jr.JobFiles = jcr->JobFiles;
874 jcr->jr.JobBytes = jcr->JobBytes;
875 jcr->jr.ReadBytes = jcr->ReadBytes;
876 jcr->jr.VolSessionId = jcr->VolSessionId;
877 jcr->jr.VolSessionTime = jcr->VolSessionTime;
878 jcr->jr.JobErrors = jcr->JobErrors;
879 jcr->jr.HasBase = jcr->HasBase;
880 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
881 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
882 db_strerror(jcr->db));
887 * Takes base_name and appends (unique) current
888 * date and time to form unique job name.
890 * Note, the seconds are actually a sequence number. This
891 * permits us to start a maximum fo 59 unique jobs a second, which
892 * should be sufficient.
894 * Returns: unique job name in jcr->Job
895 * date/time in jcr->start_time
897 void create_unique_job_name(JCR *jcr, const char *base_name)
899 /* Job start mutex */
900 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
901 static time_t last_start_time = 0;
903 time_t now = time(NULL);
905 char dt[MAX_TIME_LENGTH];
906 char name[MAX_NAME_LENGTH];
910 /* Guarantee unique start time -- maximum one per second, and
911 * thus unique Job Name
913 P(mutex); /* lock creation of jobs */
915 if (seq > 59) { /* wrap as if it is seconds */
917 while (now == last_start_time) {
918 bmicrosleep(0, 500000);
922 last_start_time = now;
923 V(mutex); /* allow creation of jobs */
924 jcr->start_time = now;
925 /* Form Unique JobName */
926 (void)localtime_r(&now, &tm);
927 /* Use only characters that are permitted in Windows filenames */
928 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
929 len = strlen(dt) + 5; /* dt + .%02d EOS */
930 bstrncpy(name, base_name, sizeof(name));
931 name[sizeof(name)-len] = 0; /* truncate if too long */
932 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
933 /* Convert spaces into underscores */
934 for (p=jcr->Job; *p; p++) {
939 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
942 /* Called directly from job rescheduling */
943 void dird_free_jcr_pointers(JCR *jcr)
945 if (jcr->sd_auth_key) {
946 free(jcr->sd_auth_key);
947 jcr->sd_auth_key = NULL;
953 if (jcr->file_bsock) {
954 Dmsg0(200, "Close File bsock\n");
955 bnet_close(jcr->file_bsock);
956 jcr->file_bsock = NULL;
958 if (jcr->store_bsock) {
959 Dmsg0(200, "Close Store bsock\n");
960 bnet_close(jcr->store_bsock);
961 jcr->store_bsock = NULL;
964 Dmsg0(200, "Free JCR fname\n");
965 free_pool_memory(jcr->fname);
968 if (jcr->RestoreBootstrap) {
969 free(jcr->RestoreBootstrap);
970 jcr->RestoreBootstrap = NULL;
972 if (jcr->client_uname) {
973 free_pool_memory(jcr->client_uname);
974 jcr->client_uname = NULL;
977 free_pool_memory(jcr->attr);
987 * Free the Job Control Record if no one is still using it.
988 * Called from main free_jcr() routine in src/lib/jcr.c so
989 * that we can do our Director specific cleanup of the jcr.
991 void dird_free_jcr(JCR *jcr)
993 Dmsg0(200, "Start dird free_jcr\n");
995 dird_free_jcr_pointers(jcr);
996 if (jcr->term_wait_inited) {
997 pthread_cond_destroy(&jcr->term_wait);
998 jcr->term_wait_inited = false;
1000 if (jcr->db_batch) {
1001 db_close_database(jcr, jcr->db_batch);
1002 jcr->db_batch = NULL;
1003 jcr->batch_started = false;
1006 db_close_database(jcr, jcr->db);
1010 Dmsg0(200, "Free JCR stime\n");
1011 free_pool_memory(jcr->stime);
1015 Dmsg0(200, "Free JCR fname\n");
1016 free_pool_memory(jcr->fname);
1019 if (jcr->pool_source) {
1020 free_pool_memory(jcr->pool_source);
1021 jcr->pool_source = NULL;
1023 if (jcr->catalog_source) {
1024 free_pool_memory(jcr->catalog_source);
1025 jcr->catalog_source = NULL;
1027 if (jcr->rpool_source) {
1028 free_pool_memory(jcr->rpool_source);
1029 jcr->rpool_source = NULL;
1031 if (jcr->wstore_source) {
1032 free_pool_memory(jcr->wstore_source);
1033 jcr->wstore_source = NULL;
1035 if (jcr->rstore_source) {
1036 free_pool_memory(jcr->rstore_source);
1037 jcr->rstore_source = NULL;
1040 /* Delete lists setup to hold storage pointers */
1041 free_rwstorage(jcr);
1043 jcr->job_end_push.destroy();
1045 if (jcr->JobId != 0)
1046 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1048 free_plugins(jcr); /* release instantiated plugins */
1050 Dmsg0(200, "End dird free_jcr\n");
1054 * The Job storage definition must be either in the Job record
1055 * or in the Pool record. The Pool record overrides the Job
1058 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1060 if (run && run->pool && run->pool->storage) {
1061 store->store = (STORE *)run->pool->storage->first();
1062 pm_strcpy(store->store_source, _("Run pool override"));
1065 if (run && run->storage) {
1066 store->store = run->storage;
1067 pm_strcpy(store->store_source, _("Run storage override"));
1070 if (job->pool->storage) {
1071 store->store = (STORE *)job->pool->storage->first();
1072 pm_strcpy(store->store_source, _("Pool resource"));
1074 store->store = (STORE *)job->storage->first();
1075 pm_strcpy(store->store_source, _("Job resource"));
1080 * Set some defaults in the JCR necessary to
1081 * run. These items are pulled from the job
1082 * definition as defaults, but can be overridden
1083 * later either by the Run record in the Schedule resource,
1084 * or by the Console program.
1086 void set_jcr_defaults(JCR *jcr, JOB *job)
1089 jcr->set_JobType(job->JobType);
1090 jcr->JobStatus = JS_Created;
1092 switch (jcr->get_JobType()) {
1094 jcr->set_JobLevel(L_NONE);
1097 jcr->set_JobLevel(job->JobLevel);
1102 jcr->fname = get_pool_memory(PM_FNAME);
1104 if (!jcr->pool_source) {
1105 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1106 pm_strcpy(jcr->pool_source, _("unknown source"));
1108 if (!jcr->catalog_source) {
1109 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1110 pm_strcpy(jcr->catalog_source, _("unknown source"));
1113 jcr->JobPriority = job->Priority;
1114 /* Copy storage definitions -- deleted in dir_free_jcr above */
1116 copy_rwstorage(jcr, job->storage, _("Job resource"));
1118 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1120 jcr->client = job->client;
1121 if (!jcr->client_name) {
1122 jcr->client_name = get_pool_memory(PM_NAME);
1124 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1125 pm_strcpy(jcr->pool_source, _("Job resource"));
1126 jcr->pool = job->pool;
1127 jcr->full_pool = job->full_pool;
1128 jcr->inc_pool = job->inc_pool;
1129 jcr->diff_pool = job->diff_pool;
1130 if (job->pool->catalog) {
1131 jcr->catalog = job->pool->catalog;
1132 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1134 jcr->catalog = job->client->catalog;
1135 pm_strcpy(jcr->catalog_source, _("Client resource"));
1137 jcr->fileset = job->fileset;
1138 jcr->messages = job->messages;
1139 jcr->spool_data = job->spool_data;
1140 jcr->spool_size = job->spool_size;
1141 jcr->write_part_after_job = job->write_part_after_job;
1142 jcr->accurate = job->accurate;
1143 if (jcr->RestoreBootstrap) {
1144 free(jcr->RestoreBootstrap);
1145 jcr->RestoreBootstrap = NULL;
1147 /* This can be overridden by Console program */
1148 if (job->RestoreBootstrap) {
1149 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1151 /* This can be overridden by Console program */
1152 jcr->verify_job = job->verify_job;
1153 /* If no default level given, set one */
1154 if (jcr->get_JobLevel() == 0) {
1155 switch (jcr->get_JobType()) {
1157 jcr->set_JobLevel(L_VERIFY_CATALOG);
1160 jcr->set_JobLevel(L_INCREMENTAL);
1164 jcr->set_JobLevel(L_NONE);
1167 jcr->set_JobLevel(L_FULL);
1174 * Copy the storage definitions from an alist to the JCR
1176 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1178 if (jcr->JobReads()) {
1179 copy_rstorage(jcr, storage, where);
1181 copy_wstorage(jcr, storage, where);
1185 /* Set storage override. Releases any previous storage definition */
1186 void set_rwstorage(JCR *jcr, USTORE *store)
1189 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1192 if (jcr->JobReads()) {
1193 set_rstorage(jcr, store);
1195 set_wstorage(jcr, store);
1198 void free_rwstorage(JCR *jcr)
1205 * Copy the storage definitions from an alist to the JCR
1207 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1211 if (jcr->rstorage) {
1212 delete jcr->rstorage;
1214 jcr->rstorage = New(alist(10, not_owned_by_alist));
1215 foreach_alist(st, storage) {
1216 jcr->rstorage->append(st);
1218 if (!jcr->rstore_source) {
1219 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1221 pm_strcpy(jcr->rstore_source, where);
1222 if (jcr->rstorage) {
1223 jcr->rstore = (STORE *)jcr->rstorage->first();
1229 /* Set storage override. Remove all previous storage */
1230 void set_rstorage(JCR *jcr, USTORE *store)
1234 if (!store->store) {
1237 if (jcr->rstorage) {
1240 if (!jcr->rstorage) {
1241 jcr->rstorage = New(alist(10, not_owned_by_alist));
1243 jcr->rstore = store->store;
1244 if (!jcr->rstore_source) {
1245 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1247 pm_strcpy(jcr->rstore_source, store->store_source);
1248 foreach_alist(storage, jcr->rstorage) {
1249 if (store->store == storage) {
1253 /* Store not in list, so add it */
1254 jcr->rstorage->prepend(store->store);
1257 void free_rstorage(JCR *jcr)
1259 if (jcr->rstorage) {
1260 delete jcr->rstorage;
1261 jcr->rstorage = NULL;
1267 * Copy the storage definitions from an alist to the JCR
1269 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1273 if (jcr->wstorage) {
1274 delete jcr->wstorage;
1276 jcr->wstorage = New(alist(10, not_owned_by_alist));
1277 foreach_alist(st, storage) {
1278 Dmsg1(100, "wstorage=%s\n", st->name());
1279 jcr->wstorage->append(st);
1281 if (!jcr->wstore_source) {
1282 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1284 pm_strcpy(jcr->wstore_source, where);
1285 if (jcr->wstorage) {
1286 jcr->wstore = (STORE *)jcr->wstorage->first();
1287 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1293 /* Set storage override. Remove all previous storage */
1294 void set_wstorage(JCR *jcr, USTORE *store)
1298 if (!store->store) {
1301 if (jcr->wstorage) {
1304 if (!jcr->wstorage) {
1305 jcr->wstorage = New(alist(10, not_owned_by_alist));
1307 jcr->wstore = store->store;
1308 if (!jcr->wstore_source) {
1309 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1311 pm_strcpy(jcr->wstore_source, store->store_source);
1312 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1313 foreach_alist(storage, jcr->wstorage) {
1314 if (store->store == storage) {
1318 /* Store not in list, so add it */
1319 jcr->wstorage->prepend(store->store);
1322 void free_wstorage(JCR *jcr)
1324 if (jcr->wstorage) {
1325 delete jcr->wstorage;
1326 jcr->wstorage = NULL;
1331 char *job_code_callback_clones(JCR *jcr, const char* param)
1333 if (param[0] == 'p') {
1334 return jcr->pool->name();
1339 void create_clones(JCR *jcr)
1342 * Fire off any clone jobs (run directives)
1344 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1345 if (!jcr->cloned && jcr->job->run_cmds) {
1347 JOB *job = jcr->job;
1348 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1349 UAContext *ua = new_ua_context(jcr);
1351 foreach_alist(runcmd, job->run_cmds) {
1352 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1353 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1354 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1355 parse_ua_args(ua); /* parse command */
1356 int stat = run_cmd(ua, ua->cmd);
1358 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1361 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1364 free_ua_context(ua);
1365 free_pool_memory(cmd);
1370 * Given: a JobId in jcr->previous_jr.JobId,
1371 * this subroutine writes a bsr file to restore that job.
1372 * Returns: -1 on error
1373 * number of files if OK
1375 int create_restore_bootstrap_file(JCR *jcr)
1381 memset(&rx, 0, sizeof(rx));
1383 rx.JobIds = (char *)"";
1384 rx.bsr->JobId = jcr->previous_jr.JobId;
1385 ua = new_ua_context(jcr);
1386 if (!complete_bsr(ua, rx.bsr)) {
1390 rx.bsr->fi = new_findex();
1391 rx.bsr->fi->findex = 1;
1392 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1393 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1394 if (jcr->ExpectedFiles == 0) {
1398 free_ua_context(ua);
1400 jcr->needs_sd = true;
1401 return jcr->ExpectedFiles;
1404 free_ua_context(ua);
1409 /* TODO: redirect command ouput to job log */
1410 bool run_console_command(JCR *jcr, const char *cmd)
1414 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1415 ua = new_ua_context(ljcr);
1416 /* run from runscript and check if commands are autorized */
1417 ua->runscript = true;
1418 Mmsg(ua->cmd, "%s", cmd);
1419 Dmsg1(100, "Console command: %s\n", ua->cmd);
1421 ok= do_a_command(ua);
1422 free_ua_context(ua);