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 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");
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);
206 if (!do_verify_init(jcr)) {
207 verify_cleanup(jcr, JS_ErrorTerminated);
211 if (!do_restore_init(jcr)) {
212 restore_cleanup(jcr, JS_ErrorTerminated);
216 if (!do_admin_init(jcr)) {
217 admin_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_migration_init(jcr)) {
223 migration_cleanup(jcr, JS_ErrorTerminated);
227 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
228 set_jcr_job_status(jcr, JS_ErrorTerminated);
232 generate_job_event(jcr, "JobInit");
233 generate_plugin_event(jcr, bEventJobInit);
241 void update_job_end(JCR *jcr, int TermCode)
243 dequeue_messages(jcr); /* display any queued messages */
244 set_jcr_job_status(jcr, TermCode);
245 update_job_end_record(jcr);
249 * This is the engine called by jobq.c:jobq_add() when we were pulled
250 * from the work queue.
251 * At this point, we are running in our own thread and all
252 * necessary resources are allocated -- see jobq.c
254 static void *job_thread(void *arg)
256 JCR *jcr = (JCR *)arg;
258 pthread_detach(pthread_self());
261 Dmsg0(200, "=====Start Job=========\n");
262 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
263 jcr->start_time = time(NULL); /* set the real start time */
264 jcr->jr.StartTime = jcr->start_time;
266 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
267 (utime_t)(jcr->start_time - jcr->sched_time)) {
268 set_jcr_job_status(jcr, JS_Canceled);
269 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
272 if (job_check_maxschedruntime(jcr)) {
273 set_jcr_job_status(jcr, JS_Canceled);
274 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
277 /* TODO : check if it is used somewhere */
278 if (jcr->job->RunScripts == NULL) {
279 Dmsg0(200, "Warning, job->RunScripts is empty\n");
280 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
283 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
284 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
287 /* Run any script BeforeJob on dird */
288 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
291 * We re-update the job start record so that the start
292 * time is set after the run before job. This avoids
293 * that any files created by the run before job will
294 * be saved twice. They will be backed up in the current
295 * job, but not in the next one unless they are changed.
296 * Without this, they will be backed up in this job and
297 * in the next job run because in that case, their date
298 * is after the start of this run.
300 jcr->start_time = time(NULL);
301 jcr->jr.StartTime = jcr->start_time;
302 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
303 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
305 generate_job_event(jcr, "JobRun");
306 generate_plugin_event(jcr, bEventJobRun);
308 switch (jcr->get_JobType()) {
310 if (!job_canceled(jcr) && do_backup(jcr)) {
313 backup_cleanup(jcr, JS_ErrorTerminated);
317 if (!job_canceled(jcr) && do_verify(jcr)) {
320 verify_cleanup(jcr, JS_ErrorTerminated);
324 if (!job_canceled(jcr) && do_restore(jcr)) {
327 restore_cleanup(jcr, JS_ErrorTerminated);
331 if (!job_canceled(jcr) && do_admin(jcr)) {
334 admin_cleanup(jcr, JS_ErrorTerminated);
339 if (!job_canceled(jcr) && do_migration(jcr)) {
342 migration_cleanup(jcr, JS_ErrorTerminated);
346 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->get_JobType());
350 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
352 /* Send off any queued messages */
353 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
354 dequeue_messages(jcr);
357 generate_daemon_event(jcr, "JobEnd");
358 generate_plugin_event(jcr, bEventJobEnd);
359 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
360 sm_check(__FILE__, __LINE__, true);
366 * Cancel a job -- typically called by the UA (Console program), but may also
367 * be called by the job watchdog.
369 * Returns: true if cancel appears to be successful
370 * false on failure. Message sent to ua->jcr.
372 bool cancel_job(UAContext *ua, JCR *jcr)
376 int32_t old_status = jcr->JobStatus;
378 set_jcr_job_status(jcr, JS_Canceled);
380 switch (old_status) {
383 case JS_WaitClientRes:
384 case JS_WaitStoreRes:
385 case JS_WaitPriority:
387 case JS_WaitStartTime:
388 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
389 edit_uint64(jcr->JobId, ed1), jcr->Job);
390 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
394 /* Cancel File daemon */
395 if (jcr->file_bsock) {
396 ua->jcr->client = jcr->client;
397 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
398 ua->error_msg(_("Failed to connect to File daemon.\n"));
401 Dmsg0(200, "Connected to file daemon\n");
402 fd = ua->jcr->file_bsock;
403 fd->fsend("cancel Job=%s\n", jcr->Job);
404 while (fd->recv() >= 0) {
405 ua->send_msg("%s", fd->msg);
407 fd->signal(BNET_TERMINATE);
409 ua->jcr->file_bsock = NULL;
412 /* Cancel Storage daemon */
413 if (jcr->store_bsock) {
414 if (!ua->jcr->wstorage) {
416 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
418 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
423 store.store = jcr->rstore;
425 store.store = jcr->wstore;
427 set_wstorage(ua->jcr, &store);
430 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
431 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
434 Dmsg0(200, "Connected to storage daemon\n");
435 sd = ua->jcr->store_bsock;
436 sd->fsend("cancel Job=%s\n", jcr->Job);
437 while (sd->recv() >= 0) {
438 ua->send_msg("%s", sd->msg);
440 sd->signal(BNET_TERMINATE);
442 ua->jcr->store_bsock = NULL;
449 void cancel_storage_daemon_job(JCR *jcr)
451 UAContext *ua = new_ua_context(jcr);
452 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
455 ua->jcr = control_jcr;
456 if (jcr->store_bsock) {
457 if (!ua->jcr->wstorage) {
459 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
461 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
466 store.store = jcr->rstore;
468 store.store = jcr->wstore;
470 set_wstorage(ua->jcr, &store);
473 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
476 Dmsg0(200, "Connected to storage daemon\n");
477 sd = ua->jcr->store_bsock;
478 sd->fsend("cancel Job=%s\n", jcr->Job);
479 while (sd->recv() >= 0) {
481 sd->signal(BNET_TERMINATE);
483 ua->jcr->store_bsock = NULL;
486 free_jcr(control_jcr);
490 static void job_monitor_destructor(watchdog_t *self)
492 JCR *control_jcr = (JCR *)self->data;
494 free_jcr(control_jcr);
497 static void job_monitor_watchdog(watchdog_t *self)
499 JCR *control_jcr, *jcr;
501 control_jcr = (JCR *)self->data;
504 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
509 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
510 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
514 /* check MaxWaitTime */
515 if (job_check_maxwaittime(jcr)) {
516 set_jcr_job_status(jcr, JS_Canceled);
517 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
519 /* check MaxRunTime */
520 } else if (job_check_maxruntime(jcr)) {
521 set_jcr_job_status(jcr, JS_Canceled);
522 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
524 /* check MaxRunSchedTime */
525 } else if (job_check_maxschedruntime(jcr)) {
526 set_jcr_job_status(jcr, JS_Canceled);
527 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
532 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
533 UAContext *ua = new_ua_context(jcr);
534 ua->jcr = control_jcr;
537 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
541 /* Keep reference counts correct */
546 * Check if the maxwaittime has expired and it is possible
549 static bool job_check_maxwaittime(JCR *jcr)
555 if (!job_waiting(jcr)) {
559 if (jcr->wait_time) {
560 current = watchdog_time - jcr->wait_time;
563 Dmsg2(200, "check maxwaittime %u >= %u\n",
564 current + jcr->wait_time_sum, job->MaxWaitTime);
565 if (job->MaxWaitTime != 0 &&
566 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
574 * Check if maxruntime has expired and if the job can be
577 static bool job_check_maxruntime(JCR *jcr)
583 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
586 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
587 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
590 run_time = watchdog_time - jcr->start_time;
591 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
592 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
593 job->IncMaxRunTime, job->DiffMaxRunTime);
595 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
596 run_time >= job->FullMaxRunTime) {
597 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
599 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
600 run_time >= job->DiffMaxRunTime) {
601 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
603 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
604 run_time >= job->IncMaxRunTime) {
605 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
607 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
608 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
616 * Check if MaxRunSchedTime has expired and if the job can be
619 static bool job_check_maxschedruntime(JCR *jcr)
621 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
624 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
625 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
626 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
634 * Get or create a Pool record with the given name.
635 * Returns: 0 on error
638 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
642 memset(&pr, 0, sizeof(pr));
643 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
644 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
646 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
647 /* Try to create the pool */
648 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
649 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
650 db_strerror(jcr->db));
653 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
660 * Check for duplicate jobs.
661 * Returns: true if current job should continue
662 * false if current job should terminate
664 bool allow_duplicate_job(JCR *jcr)
667 JCR *djcr; /* possible duplicate */
669 if (job->AllowDuplicateJobs) {
672 if (!job->AllowHigherDuplicates) {
676 continue; /* do not cancel this job */
678 if (strcmp(job->name(), djcr->job->name()) == 0) {
679 bool cancel_queued = false;
680 if (job->DuplicateJobProximity > 0) {
681 utime_t now = (utime_t)time(NULL);
682 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
683 continue; /* not really a duplicate */
687 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
688 /* Zap current job */
689 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
690 edit_uint64(djcr->JobId, ec1));
693 /* If CancelQueuedDuplicates is set do so only if job is queued */
694 if (job->CancelQueuedDuplicates) {
695 switch (djcr->JobStatus) {
698 case JS_WaitClientRes:
699 case JS_WaitStoreRes:
700 case JS_WaitPriority:
702 case JS_WaitStartTime:
703 cancel_queued = true;
709 if (cancel_queued || job->CancelRunningDuplicates) {
710 UAContext *ua = new_ua_context(djcr);
711 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
712 edit_uint64(djcr->JobId, ec1));
714 cancel_job(ua, djcr);
716 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
725 void apply_pool_overrides(JCR *jcr)
727 bool pool_override = false;
729 if (jcr->run_pool_override) {
730 pm_strcpy(jcr->pool_source, _("Run pool override"));
733 * Apply any level related Pool selections
735 switch (jcr->get_JobLevel()) {
737 if (jcr->full_pool) {
738 jcr->pool = jcr->full_pool;
739 pool_override = true;
740 if (jcr->run_full_pool_override) {
741 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
743 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
749 jcr->pool = jcr->inc_pool;
750 pool_override = true;
751 if (jcr->run_inc_pool_override) {
752 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
754 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
759 if (jcr->diff_pool) {
760 jcr->pool = jcr->diff_pool;
761 pool_override = true;
762 if (jcr->run_diff_pool_override) {
763 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
765 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
770 /* Update catalog if pool overridden */
771 if (pool_override && jcr->pool->catalog) {
772 jcr->catalog = jcr->pool->catalog;
773 pm_strcpy(jcr->catalog_source, _("Pool resource"));
779 * Get or create a Client record for this Job
781 bool get_or_create_client_record(JCR *jcr)
785 memset(&cr, 0, sizeof(cr));
786 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
787 cr.AutoPrune = jcr->client->AutoPrune;
788 cr.FileRetention = jcr->client->FileRetention;
789 cr.JobRetention = jcr->client->JobRetention;
790 if (!jcr->client_name) {
791 jcr->client_name = get_pool_memory(PM_NAME);
793 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
794 if (!db_create_client_record(jcr, jcr->db, &cr)) {
795 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
796 db_strerror(jcr->db));
799 jcr->jr.ClientId = cr.ClientId;
801 if (!jcr->client_uname) {
802 jcr->client_uname = get_pool_memory(PM_NAME);
804 pm_strcpy(jcr->client_uname, cr.Uname);
806 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
811 bool get_or_create_fileset_record(JCR *jcr)
815 * Get or Create FileSet record
817 memset(&fsr, 0, sizeof(FILESET_DBR));
818 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
819 if (jcr->fileset->have_MD5) {
820 struct MD5Context md5c;
821 unsigned char digest[MD5HashSize];
822 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
823 MD5Final(digest, &md5c);
825 * Keep the flag (last arg) set to false otherwise old FileSets will
826 * get new MD5 sums and the user will get Full backups on everything
828 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
829 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
831 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
833 if (!jcr->fileset->ignore_fs_changes ||
834 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
835 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
836 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
837 fsr.FileSet, db_strerror(jcr->db));
841 jcr->jr.FileSetId = fsr.FileSetId;
842 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
843 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
848 void init_jcr_job_record(JCR *jcr)
850 jcr->jr.SchedTime = jcr->sched_time;
851 jcr->jr.StartTime = jcr->start_time;
852 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
853 jcr->jr.JobType = jcr->get_JobType();
854 jcr->jr.JobLevel = jcr->get_JobLevel();
855 jcr->jr.JobStatus = jcr->JobStatus;
856 jcr->jr.JobId = jcr->JobId;
857 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
858 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
862 * Write status and such in DB
864 void update_job_end_record(JCR *jcr)
866 jcr->jr.EndTime = time(NULL);
867 jcr->end_time = jcr->jr.EndTime;
868 jcr->jr.JobId = jcr->JobId;
869 jcr->jr.JobStatus = jcr->JobStatus;
870 jcr->jr.JobFiles = jcr->JobFiles;
871 jcr->jr.JobBytes = jcr->JobBytes;
872 jcr->jr.ReadBytes = jcr->ReadBytes;
873 jcr->jr.VolSessionId = jcr->VolSessionId;
874 jcr->jr.VolSessionTime = jcr->VolSessionTime;
875 jcr->jr.JobErrors = jcr->JobErrors;
876 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
877 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
878 db_strerror(jcr->db));
883 * Takes base_name and appends (unique) current
884 * date and time to form unique job name.
886 * Note, the seconds are actually a sequence number. This
887 * permits us to start a maximum fo 59 unique jobs a second, which
888 * should be sufficient.
890 * Returns: unique job name in jcr->Job
891 * date/time in jcr->start_time
893 void create_unique_job_name(JCR *jcr, const char *base_name)
895 /* Job start mutex */
896 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
897 static time_t last_start_time = 0;
899 time_t now = time(NULL);
901 char dt[MAX_TIME_LENGTH];
902 char name[MAX_NAME_LENGTH];
906 /* Guarantee unique start time -- maximum one per second, and
907 * thus unique Job Name
909 P(mutex); /* lock creation of jobs */
911 if (seq > 59) { /* wrap as if it is seconds */
913 while (now == last_start_time) {
914 bmicrosleep(0, 500000);
918 last_start_time = now;
919 V(mutex); /* allow creation of jobs */
920 jcr->start_time = now;
921 /* Form Unique JobName */
922 (void)localtime_r(&now, &tm);
923 /* Use only characters that are permitted in Windows filenames */
924 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
925 len = strlen(dt) + 5; /* dt + .%02d EOS */
926 bstrncpy(name, base_name, sizeof(name));
927 name[sizeof(name)-len] = 0; /* truncate if too long */
928 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
929 /* Convert spaces into underscores */
930 for (p=jcr->Job; *p; p++) {
935 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
938 /* Called directly from job rescheduling */
939 void dird_free_jcr_pointers(JCR *jcr)
941 if (jcr->sd_auth_key) {
942 free(jcr->sd_auth_key);
943 jcr->sd_auth_key = NULL;
949 if (jcr->file_bsock) {
950 Dmsg0(200, "Close File bsock\n");
951 bnet_close(jcr->file_bsock);
952 jcr->file_bsock = NULL;
954 if (jcr->store_bsock) {
955 Dmsg0(200, "Close Store bsock\n");
956 bnet_close(jcr->store_bsock);
957 jcr->store_bsock = NULL;
960 Dmsg0(200, "Free JCR fname\n");
961 free_pool_memory(jcr->fname);
964 if (jcr->RestoreBootstrap) {
965 free(jcr->RestoreBootstrap);
966 jcr->RestoreBootstrap = NULL;
968 if (jcr->client_uname) {
969 free_pool_memory(jcr->client_uname);
970 jcr->client_uname = NULL;
973 free_pool_memory(jcr->attr);
983 * Free the Job Control Record if no one is still using it.
984 * Called from main free_jcr() routine in src/lib/jcr.c so
985 * that we can do our Director specific cleanup of the jcr.
987 void dird_free_jcr(JCR *jcr)
989 Dmsg0(200, "Start dird free_jcr\n");
991 dird_free_jcr_pointers(jcr);
992 if (jcr->term_wait_inited) {
993 pthread_cond_destroy(&jcr->term_wait);
994 jcr->term_wait_inited = false;
997 db_close_database(jcr, jcr->db_batch);
998 jcr->db_batch = NULL;
999 jcr->batch_started = false;
1002 db_close_database(jcr, jcr->db);
1006 Dmsg0(200, "Free JCR stime\n");
1007 free_pool_memory(jcr->stime);
1011 Dmsg0(200, "Free JCR fname\n");
1012 free_pool_memory(jcr->fname);
1015 if (jcr->pool_source) {
1016 free_pool_memory(jcr->pool_source);
1017 jcr->pool_source = NULL;
1019 if (jcr->catalog_source) {
1020 free_pool_memory(jcr->catalog_source);
1021 jcr->catalog_source = NULL;
1023 if (jcr->rpool_source) {
1024 free_pool_memory(jcr->rpool_source);
1025 jcr->rpool_source = NULL;
1027 if (jcr->wstore_source) {
1028 free_pool_memory(jcr->wstore_source);
1029 jcr->wstore_source = NULL;
1031 if (jcr->rstore_source) {
1032 free_pool_memory(jcr->rstore_source);
1033 jcr->rstore_source = NULL;
1036 /* Delete lists setup to hold storage pointers */
1037 free_rwstorage(jcr);
1039 jcr->job_end_push.destroy();
1041 if (jcr->JobId != 0)
1042 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1044 free_plugins(jcr); /* release instantiated plugins */
1046 Dmsg0(200, "End dird free_jcr\n");
1050 * The Job storage definition must be either in the Job record
1051 * or in the Pool record. The Pool record overrides the Job
1054 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1056 if (run && run->pool && run->pool->storage) {
1057 store->store = (STORE *)run->pool->storage->first();
1058 pm_strcpy(store->store_source, _("Run pool override"));
1061 if (run && run->storage) {
1062 store->store = run->storage;
1063 pm_strcpy(store->store_source, _("Run storage override"));
1066 if (job->pool->storage) {
1067 store->store = (STORE *)job->pool->storage->first();
1068 pm_strcpy(store->store_source, _("Pool resource"));
1070 store->store = (STORE *)job->storage->first();
1071 pm_strcpy(store->store_source, _("Job resource"));
1076 * Set some defaults in the JCR necessary to
1077 * run. These items are pulled from the job
1078 * definition as defaults, but can be overridden
1079 * later either by the Run record in the Schedule resource,
1080 * or by the Console program.
1082 void set_jcr_defaults(JCR *jcr, JOB *job)
1085 jcr->set_JobType(job->JobType);
1086 jcr->JobStatus = JS_Created;
1088 switch (jcr->get_JobType()) {
1090 jcr->set_JobLevel(L_NONE);
1093 jcr->set_JobLevel(job->JobLevel);
1098 jcr->fname = get_pool_memory(PM_FNAME);
1100 if (!jcr->pool_source) {
1101 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1102 pm_strcpy(jcr->pool_source, _("unknown source"));
1104 if (!jcr->catalog_source) {
1105 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1106 pm_strcpy(jcr->catalog_source, _("unknown source"));
1109 jcr->JobPriority = job->Priority;
1110 /* Copy storage definitions -- deleted in dir_free_jcr above */
1112 copy_rwstorage(jcr, job->storage, _("Job resource"));
1114 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1116 jcr->client = job->client;
1117 if (!jcr->client_name) {
1118 jcr->client_name = get_pool_memory(PM_NAME);
1120 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1121 pm_strcpy(jcr->pool_source, _("Job resource"));
1122 jcr->pool = job->pool;
1123 jcr->full_pool = job->full_pool;
1124 jcr->inc_pool = job->inc_pool;
1125 jcr->diff_pool = job->diff_pool;
1126 if (job->pool->catalog) {
1127 jcr->catalog = job->pool->catalog;
1128 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1130 jcr->catalog = job->client->catalog;
1131 pm_strcpy(jcr->catalog_source, _("Client resource"));
1133 jcr->fileset = job->fileset;
1134 jcr->messages = job->messages;
1135 jcr->spool_data = job->spool_data;
1136 jcr->spool_size = job->spool_size;
1137 jcr->write_part_after_job = job->write_part_after_job;
1138 jcr->accurate = job->accurate;
1139 if (jcr->RestoreBootstrap) {
1140 free(jcr->RestoreBootstrap);
1141 jcr->RestoreBootstrap = NULL;
1143 /* This can be overridden by Console program */
1144 if (job->RestoreBootstrap) {
1145 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1147 /* This can be overridden by Console program */
1148 jcr->verify_job = job->verify_job;
1149 /* If no default level given, set one */
1150 if (jcr->get_JobLevel() == 0) {
1151 switch (jcr->get_JobType()) {
1153 jcr->set_JobLevel(L_VERIFY_CATALOG);
1156 jcr->set_JobLevel(L_INCREMENTAL);
1160 jcr->set_JobLevel(L_NONE);
1163 jcr->set_JobLevel(L_FULL);
1170 * Copy the storage definitions from an alist to the JCR
1172 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1174 if (jcr->JobReads()) {
1175 copy_rstorage(jcr, storage, where);
1177 copy_wstorage(jcr, storage, where);
1181 /* Set storage override. Releases any previous storage definition */
1182 void set_rwstorage(JCR *jcr, USTORE *store)
1185 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1188 if (jcr->JobReads()) {
1189 set_rstorage(jcr, store);
1191 set_wstorage(jcr, store);
1194 void free_rwstorage(JCR *jcr)
1201 * Copy the storage definitions from an alist to the JCR
1203 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1207 if (jcr->rstorage) {
1208 delete jcr->rstorage;
1210 jcr->rstorage = New(alist(10, not_owned_by_alist));
1211 foreach_alist(st, storage) {
1212 jcr->rstorage->append(st);
1214 if (!jcr->rstore_source) {
1215 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1217 pm_strcpy(jcr->rstore_source, where);
1218 if (jcr->rstorage) {
1219 jcr->rstore = (STORE *)jcr->rstorage->first();
1225 /* Set storage override. Remove all previous storage */
1226 void set_rstorage(JCR *jcr, USTORE *store)
1230 if (!store->store) {
1233 if (jcr->rstorage) {
1236 if (!jcr->rstorage) {
1237 jcr->rstorage = New(alist(10, not_owned_by_alist));
1239 jcr->rstore = store->store;
1240 if (!jcr->rstore_source) {
1241 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1243 pm_strcpy(jcr->rstore_source, store->store_source);
1244 foreach_alist(storage, jcr->rstorage) {
1245 if (store->store == storage) {
1249 /* Store not in list, so add it */
1250 jcr->rstorage->prepend(store->store);
1253 void free_rstorage(JCR *jcr)
1255 if (jcr->rstorage) {
1256 delete jcr->rstorage;
1257 jcr->rstorage = NULL;
1263 * Copy the storage definitions from an alist to the JCR
1265 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1269 if (jcr->wstorage) {
1270 delete jcr->wstorage;
1272 jcr->wstorage = New(alist(10, not_owned_by_alist));
1273 foreach_alist(st, storage) {
1274 Dmsg1(100, "wstorage=%s\n", st->name());
1275 jcr->wstorage->append(st);
1277 if (!jcr->wstore_source) {
1278 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1280 pm_strcpy(jcr->wstore_source, where);
1281 if (jcr->wstorage) {
1282 jcr->wstore = (STORE *)jcr->wstorage->first();
1283 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1289 /* Set storage override. Remove all previous storage */
1290 void set_wstorage(JCR *jcr, USTORE *store)
1294 if (!store->store) {
1297 if (jcr->wstorage) {
1300 if (!jcr->wstorage) {
1301 jcr->wstorage = New(alist(10, not_owned_by_alist));
1303 jcr->wstore = store->store;
1304 if (!jcr->wstore_source) {
1305 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1307 pm_strcpy(jcr->wstore_source, store->store_source);
1308 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1309 foreach_alist(storage, jcr->wstorage) {
1310 if (store->store == storage) {
1314 /* Store not in list, so add it */
1315 jcr->wstorage->prepend(store->store);
1318 void free_wstorage(JCR *jcr)
1320 if (jcr->wstorage) {
1321 delete jcr->wstorage;
1322 jcr->wstorage = NULL;
1327 char *job_code_callback_clones(JCR *jcr, const char* param)
1329 if (param[0] == 'p') {
1330 return jcr->pool->name();
1335 void create_clones(JCR *jcr)
1338 * Fire off any clone jobs (run directives)
1340 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1341 if (!jcr->cloned && jcr->job->run_cmds) {
1343 JOB *job = jcr->job;
1344 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1345 UAContext *ua = new_ua_context(jcr);
1347 foreach_alist(runcmd, job->run_cmds) {
1348 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1349 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1350 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1351 parse_ua_args(ua); /* parse command */
1352 int stat = run_cmd(ua, ua->cmd);
1354 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1357 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1360 free_ua_context(ua);
1361 free_pool_memory(cmd);
1366 * Given: a JobId in jcr->previous_jr.JobId,
1367 * this subroutine writes a bsr file to restore that job.
1369 bool create_restore_bootstrap_file(JCR *jcr)
1373 memset(&rx, 0, sizeof(rx));
1375 rx.JobIds = (char *)"";
1376 rx.bsr->JobId = jcr->previous_jr.JobId;
1377 ua = new_ua_context(jcr);
1378 if (!complete_bsr(ua, rx.bsr)) {
1381 rx.bsr->fi = new_findex();
1382 rx.bsr->fi->findex = 1;
1383 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1384 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1385 if (jcr->ExpectedFiles == 0) {
1388 free_ua_context(ua);
1390 jcr->needs_sd = true;
1394 free_ua_context(ua);
1399 /* TODO: redirect command ouput to job log */
1400 bool run_console_command(JCR *jcr, const char *cmd)
1404 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1405 ua = new_ua_context(ljcr);
1406 /* run from runscript and check if commands are autorized */
1407 ua->runscript = true;
1408 Mmsg(ua->cmd, "%s", cmd);
1409 Dmsg1(100, "Console command: %s\n", ua->cmd);
1411 ok= do_a_command(ua);
1412 free_ua_context(ua);