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);
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 set_jcr_job_status(jcr, 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 set_jcr_job_status(jcr, JS_Canceled);
274 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
277 if (job_check_maxschedruntime(jcr)) {
278 set_jcr_job_status(jcr, 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;
454 void cancel_storage_daemon_job(JCR *jcr)
456 UAContext *ua = new_ua_context(jcr);
457 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
460 ua->jcr = control_jcr;
461 if (jcr->store_bsock) {
462 if (!ua->jcr->wstorage) {
464 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
466 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
471 store.store = jcr->rstore;
473 store.store = jcr->wstore;
475 set_wstorage(ua->jcr, &store);
478 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
481 Dmsg0(200, "Connected to storage daemon\n");
482 sd = ua->jcr->store_bsock;
483 sd->fsend("cancel Job=%s\n", jcr->Job);
484 while (sd->recv() >= 0) {
486 sd->signal(BNET_TERMINATE);
488 ua->jcr->store_bsock = NULL;
491 free_jcr(control_jcr);
495 static void job_monitor_destructor(watchdog_t *self)
497 JCR *control_jcr = (JCR *)self->data;
499 free_jcr(control_jcr);
502 static void job_monitor_watchdog(watchdog_t *self)
504 JCR *control_jcr, *jcr;
506 control_jcr = (JCR *)self->data;
509 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
514 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
515 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
519 /* check MaxWaitTime */
520 if (job_check_maxwaittime(jcr)) {
521 set_jcr_job_status(jcr, JS_Canceled);
522 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
524 /* check MaxRunTime */
525 } else if (job_check_maxruntime(jcr)) {
526 set_jcr_job_status(jcr, JS_Canceled);
527 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
529 /* check MaxRunSchedTime */
530 } else if (job_check_maxschedruntime(jcr)) {
531 set_jcr_job_status(jcr, JS_Canceled);
532 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
537 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
538 UAContext *ua = new_ua_context(jcr);
539 ua->jcr = control_jcr;
542 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
546 /* Keep reference counts correct */
551 * Check if the maxwaittime has expired and it is possible
554 static bool job_check_maxwaittime(JCR *jcr)
560 if (!job_waiting(jcr)) {
564 if (jcr->wait_time) {
565 current = watchdog_time - jcr->wait_time;
568 Dmsg2(200, "check maxwaittime %u >= %u\n",
569 current + jcr->wait_time_sum, job->MaxWaitTime);
570 if (job->MaxWaitTime != 0 &&
571 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
579 * Check if maxruntime has expired and if the job can be
582 static bool job_check_maxruntime(JCR *jcr)
588 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
591 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
592 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
595 run_time = watchdog_time - jcr->start_time;
596 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
597 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
598 job->IncMaxRunTime, job->DiffMaxRunTime);
600 if (jcr->get_JobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
601 run_time >= job->FullMaxRunTime) {
602 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
604 } else if (jcr->get_JobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
605 run_time >= job->DiffMaxRunTime) {
606 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
608 } else if (jcr->get_JobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
609 run_time >= job->IncMaxRunTime) {
610 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
612 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
613 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
621 * Check if MaxRunSchedTime has expired and if the job can be
624 static bool job_check_maxschedruntime(JCR *jcr)
626 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
629 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
630 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
631 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
639 * Get or create a Pool record with the given name.
640 * Returns: 0 on error
643 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
647 memset(&pr, 0, sizeof(pr));
648 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
649 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
651 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
652 /* Try to create the pool */
653 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
654 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
655 db_strerror(jcr->db));
658 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
665 * Check for duplicate jobs.
666 * Returns: true if current job should continue
667 * false if current job should terminate
669 bool allow_duplicate_job(JCR *jcr)
672 JCR *djcr; /* possible duplicate */
674 if (job->AllowDuplicateJobs) {
677 if (!job->AllowHigherDuplicates) {
681 continue; /* do not cancel this job */
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 (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
693 /* Zap current job */
694 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
695 edit_uint64(djcr->JobId, ec1));
698 /* If CancelQueuedDuplicates is set do so only if job is queued */
699 if (job->CancelQueuedDuplicates) {
700 switch (djcr->JobStatus) {
703 case JS_WaitClientRes:
704 case JS_WaitStoreRes:
705 case JS_WaitPriority:
707 case JS_WaitStartTime:
708 cancel_queued = true;
714 if (cancel_queued || job->CancelRunningDuplicates) {
715 UAContext *ua = new_ua_context(djcr);
716 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
717 edit_uint64(djcr->JobId, ec1));
719 cancel_job(ua, djcr);
721 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
730 void apply_pool_overrides(JCR *jcr)
732 bool pool_override = false;
734 if (jcr->run_pool_override) {
735 pm_strcpy(jcr->pool_source, _("Run pool override"));
738 * Apply any level related Pool selections
740 switch (jcr->get_JobLevel()) {
742 if (jcr->full_pool) {
743 jcr->pool = jcr->full_pool;
744 pool_override = true;
745 if (jcr->run_full_pool_override) {
746 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
748 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
754 jcr->pool = jcr->inc_pool;
755 pool_override = true;
756 if (jcr->run_inc_pool_override) {
757 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
759 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
764 if (jcr->diff_pool) {
765 jcr->pool = jcr->diff_pool;
766 pool_override = true;
767 if (jcr->run_diff_pool_override) {
768 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
770 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
775 /* Update catalog if pool overridden */
776 if (pool_override && jcr->pool->catalog) {
777 jcr->catalog = jcr->pool->catalog;
778 pm_strcpy(jcr->catalog_source, _("Pool resource"));
784 * Get or create a Client record for this Job
786 bool get_or_create_client_record(JCR *jcr)
790 memset(&cr, 0, sizeof(cr));
791 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
792 cr.AutoPrune = jcr->client->AutoPrune;
793 cr.FileRetention = jcr->client->FileRetention;
794 cr.JobRetention = jcr->client->JobRetention;
795 if (!jcr->client_name) {
796 jcr->client_name = get_pool_memory(PM_NAME);
798 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
799 if (!db_create_client_record(jcr, jcr->db, &cr)) {
800 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
801 db_strerror(jcr->db));
804 jcr->jr.ClientId = cr.ClientId;
806 if (!jcr->client_uname) {
807 jcr->client_uname = get_pool_memory(PM_NAME);
809 pm_strcpy(jcr->client_uname, cr.Uname);
811 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
816 bool get_or_create_fileset_record(JCR *jcr)
820 * Get or Create FileSet record
822 memset(&fsr, 0, sizeof(FILESET_DBR));
823 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
824 if (jcr->fileset->have_MD5) {
825 struct MD5Context md5c;
826 unsigned char digest[MD5HashSize];
827 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
828 MD5Final(digest, &md5c);
830 * Keep the flag (last arg) set to false otherwise old FileSets will
831 * get new MD5 sums and the user will get Full backups on everything
833 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
834 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
836 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
838 if (!jcr->fileset->ignore_fs_changes ||
839 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
840 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
841 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
842 fsr.FileSet, db_strerror(jcr->db));
846 jcr->jr.FileSetId = fsr.FileSetId;
847 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
848 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
853 void init_jcr_job_record(JCR *jcr)
855 jcr->jr.SchedTime = jcr->sched_time;
856 jcr->jr.StartTime = jcr->start_time;
857 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
858 jcr->jr.JobType = jcr->get_JobType();
859 jcr->jr.JobLevel = jcr->get_JobLevel();
860 jcr->jr.JobStatus = jcr->JobStatus;
861 jcr->jr.JobId = jcr->JobId;
862 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
863 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
867 * Write status and such in DB
869 void update_job_end_record(JCR *jcr)
871 jcr->jr.EndTime = time(NULL);
872 jcr->end_time = jcr->jr.EndTime;
873 jcr->jr.JobId = jcr->JobId;
874 jcr->jr.JobStatus = jcr->JobStatus;
875 jcr->jr.JobFiles = jcr->JobFiles;
876 jcr->jr.JobBytes = jcr->JobBytes;
877 jcr->jr.ReadBytes = jcr->ReadBytes;
878 jcr->jr.VolSessionId = jcr->VolSessionId;
879 jcr->jr.VolSessionTime = jcr->VolSessionTime;
880 jcr->jr.JobErrors = jcr->JobErrors;
881 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
882 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
883 db_strerror(jcr->db));
888 * Takes base_name and appends (unique) current
889 * date and time to form unique job name.
891 * Note, the seconds are actually a sequence number. This
892 * permits us to start a maximum fo 59 unique jobs a second, which
893 * should be sufficient.
895 * Returns: unique job name in jcr->Job
896 * date/time in jcr->start_time
898 void create_unique_job_name(JCR *jcr, const char *base_name)
900 /* Job start mutex */
901 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
902 static time_t last_start_time = 0;
904 time_t now = time(NULL);
906 char dt[MAX_TIME_LENGTH];
907 char name[MAX_NAME_LENGTH];
911 /* Guarantee unique start time -- maximum one per second, and
912 * thus unique Job Name
914 P(mutex); /* lock creation of jobs */
916 if (seq > 59) { /* wrap as if it is seconds */
918 while (now == last_start_time) {
919 bmicrosleep(0, 500000);
923 last_start_time = now;
924 V(mutex); /* allow creation of jobs */
925 jcr->start_time = now;
926 /* Form Unique JobName */
927 (void)localtime_r(&now, &tm);
928 /* Use only characters that are permitted in Windows filenames */
929 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
930 len = strlen(dt) + 5; /* dt + .%02d EOS */
931 bstrncpy(name, base_name, sizeof(name));
932 name[sizeof(name)-len] = 0; /* truncate if too long */
933 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, seq); /* add date & time */
934 /* Convert spaces into underscores */
935 for (p=jcr->Job; *p; p++) {
940 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
943 /* Called directly from job rescheduling */
944 void dird_free_jcr_pointers(JCR *jcr)
946 if (jcr->sd_auth_key) {
947 free(jcr->sd_auth_key);
948 jcr->sd_auth_key = NULL;
954 if (jcr->file_bsock) {
955 Dmsg0(200, "Close File bsock\n");
956 bnet_close(jcr->file_bsock);
957 jcr->file_bsock = NULL;
959 if (jcr->store_bsock) {
960 Dmsg0(200, "Close Store bsock\n");
961 bnet_close(jcr->store_bsock);
962 jcr->store_bsock = NULL;
965 Dmsg0(200, "Free JCR fname\n");
966 free_pool_memory(jcr->fname);
969 if (jcr->RestoreBootstrap) {
970 free(jcr->RestoreBootstrap);
971 jcr->RestoreBootstrap = NULL;
973 if (jcr->client_uname) {
974 free_pool_memory(jcr->client_uname);
975 jcr->client_uname = NULL;
978 free_pool_memory(jcr->attr);
988 * Free the Job Control Record if no one is still using it.
989 * Called from main free_jcr() routine in src/lib/jcr.c so
990 * that we can do our Director specific cleanup of the jcr.
992 void dird_free_jcr(JCR *jcr)
994 Dmsg0(200, "Start dird free_jcr\n");
996 dird_free_jcr_pointers(jcr);
997 if (jcr->term_wait_inited) {
998 pthread_cond_destroy(&jcr->term_wait);
999 jcr->term_wait_inited = false;
1001 if (jcr->db_batch) {
1002 db_close_database(jcr, jcr->db_batch);
1003 jcr->db_batch = NULL;
1004 jcr->batch_started = false;
1007 db_close_database(jcr, jcr->db);
1011 Dmsg0(200, "Free JCR stime\n");
1012 free_pool_memory(jcr->stime);
1016 Dmsg0(200, "Free JCR fname\n");
1017 free_pool_memory(jcr->fname);
1020 if (jcr->pool_source) {
1021 free_pool_memory(jcr->pool_source);
1022 jcr->pool_source = NULL;
1024 if (jcr->catalog_source) {
1025 free_pool_memory(jcr->catalog_source);
1026 jcr->catalog_source = NULL;
1028 if (jcr->rpool_source) {
1029 free_pool_memory(jcr->rpool_source);
1030 jcr->rpool_source = NULL;
1032 if (jcr->wstore_source) {
1033 free_pool_memory(jcr->wstore_source);
1034 jcr->wstore_source = NULL;
1036 if (jcr->rstore_source) {
1037 free_pool_memory(jcr->rstore_source);
1038 jcr->rstore_source = NULL;
1041 /* Delete lists setup to hold storage pointers */
1042 free_rwstorage(jcr);
1044 jcr->job_end_push.destroy();
1046 if (jcr->JobId != 0)
1047 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1049 free_plugins(jcr); /* release instantiated plugins */
1051 Dmsg0(200, "End dird free_jcr\n");
1055 * The Job storage definition must be either in the Job record
1056 * or in the Pool record. The Pool record overrides the Job
1059 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1061 if (run && run->pool && run->pool->storage) {
1062 store->store = (STORE *)run->pool->storage->first();
1063 pm_strcpy(store->store_source, _("Run pool override"));
1066 if (run && run->storage) {
1067 store->store = run->storage;
1068 pm_strcpy(store->store_source, _("Run storage override"));
1071 if (job->pool->storage) {
1072 store->store = (STORE *)job->pool->storage->first();
1073 pm_strcpy(store->store_source, _("Pool resource"));
1075 store->store = (STORE *)job->storage->first();
1076 pm_strcpy(store->store_source, _("Job resource"));
1081 * Set some defaults in the JCR necessary to
1082 * run. These items are pulled from the job
1083 * definition as defaults, but can be overridden
1084 * later either by the Run record in the Schedule resource,
1085 * or by the Console program.
1087 void set_jcr_defaults(JCR *jcr, JOB *job)
1090 jcr->set_JobType(job->JobType);
1091 jcr->JobStatus = JS_Created;
1093 switch (jcr->get_JobType()) {
1095 jcr->set_JobLevel(L_NONE);
1098 jcr->set_JobLevel(job->JobLevel);
1103 jcr->fname = get_pool_memory(PM_FNAME);
1105 if (!jcr->pool_source) {
1106 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1107 pm_strcpy(jcr->pool_source, _("unknown source"));
1109 if (!jcr->catalog_source) {
1110 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1111 pm_strcpy(jcr->catalog_source, _("unknown source"));
1114 jcr->JobPriority = job->Priority;
1115 /* Copy storage definitions -- deleted in dir_free_jcr above */
1117 copy_rwstorage(jcr, job->storage, _("Job resource"));
1119 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1121 jcr->client = job->client;
1122 if (!jcr->client_name) {
1123 jcr->client_name = get_pool_memory(PM_NAME);
1125 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1126 pm_strcpy(jcr->pool_source, _("Job resource"));
1127 jcr->pool = job->pool;
1128 jcr->full_pool = job->full_pool;
1129 jcr->inc_pool = job->inc_pool;
1130 jcr->diff_pool = job->diff_pool;
1131 if (job->pool->catalog) {
1132 jcr->catalog = job->pool->catalog;
1133 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1135 jcr->catalog = job->client->catalog;
1136 pm_strcpy(jcr->catalog_source, _("Client resource"));
1138 jcr->fileset = job->fileset;
1139 jcr->messages = job->messages;
1140 jcr->spool_data = job->spool_data;
1141 jcr->spool_size = job->spool_size;
1142 jcr->write_part_after_job = job->write_part_after_job;
1143 jcr->accurate = job->accurate;
1144 if (jcr->RestoreBootstrap) {
1145 free(jcr->RestoreBootstrap);
1146 jcr->RestoreBootstrap = NULL;
1148 /* This can be overridden by Console program */
1149 if (job->RestoreBootstrap) {
1150 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1152 /* This can be overridden by Console program */
1153 jcr->verify_job = job->verify_job;
1154 /* If no default level given, set one */
1155 if (jcr->get_JobLevel() == 0) {
1156 switch (jcr->get_JobType()) {
1158 jcr->set_JobLevel(L_VERIFY_CATALOG);
1161 jcr->set_JobLevel(L_INCREMENTAL);
1165 jcr->set_JobLevel(L_NONE);
1168 jcr->set_JobLevel(L_FULL);
1175 * Copy the storage definitions from an alist to the JCR
1177 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1179 if (jcr->JobReads()) {
1180 copy_rstorage(jcr, storage, where);
1182 copy_wstorage(jcr, storage, where);
1186 /* Set storage override. Releases any previous storage definition */
1187 void set_rwstorage(JCR *jcr, USTORE *store)
1190 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1193 if (jcr->JobReads()) {
1194 set_rstorage(jcr, store);
1196 set_wstorage(jcr, store);
1199 void free_rwstorage(JCR *jcr)
1206 * Copy the storage definitions from an alist to the JCR
1208 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1212 if (jcr->rstorage) {
1213 delete jcr->rstorage;
1215 jcr->rstorage = New(alist(10, not_owned_by_alist));
1216 foreach_alist(st, storage) {
1217 jcr->rstorage->append(st);
1219 if (!jcr->rstore_source) {
1220 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1222 pm_strcpy(jcr->rstore_source, where);
1223 if (jcr->rstorage) {
1224 jcr->rstore = (STORE *)jcr->rstorage->first();
1230 /* Set storage override. Remove all previous storage */
1231 void set_rstorage(JCR *jcr, USTORE *store)
1235 if (!store->store) {
1238 if (jcr->rstorage) {
1241 if (!jcr->rstorage) {
1242 jcr->rstorage = New(alist(10, not_owned_by_alist));
1244 jcr->rstore = store->store;
1245 if (!jcr->rstore_source) {
1246 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1248 pm_strcpy(jcr->rstore_source, store->store_source);
1249 foreach_alist(storage, jcr->rstorage) {
1250 if (store->store == storage) {
1254 /* Store not in list, so add it */
1255 jcr->rstorage->prepend(store->store);
1258 void free_rstorage(JCR *jcr)
1260 if (jcr->rstorage) {
1261 delete jcr->rstorage;
1262 jcr->rstorage = NULL;
1268 * Copy the storage definitions from an alist to the JCR
1270 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1274 if (jcr->wstorage) {
1275 delete jcr->wstorage;
1277 jcr->wstorage = New(alist(10, not_owned_by_alist));
1278 foreach_alist(st, storage) {
1279 Dmsg1(100, "wstorage=%s\n", st->name());
1280 jcr->wstorage->append(st);
1282 if (!jcr->wstore_source) {
1283 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1285 pm_strcpy(jcr->wstore_source, where);
1286 if (jcr->wstorage) {
1287 jcr->wstore = (STORE *)jcr->wstorage->first();
1288 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1294 /* Set storage override. Remove all previous storage */
1295 void set_wstorage(JCR *jcr, USTORE *store)
1299 if (!store->store) {
1302 if (jcr->wstorage) {
1305 if (!jcr->wstorage) {
1306 jcr->wstorage = New(alist(10, not_owned_by_alist));
1308 jcr->wstore = store->store;
1309 if (!jcr->wstore_source) {
1310 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1312 pm_strcpy(jcr->wstore_source, store->store_source);
1313 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1314 foreach_alist(storage, jcr->wstorage) {
1315 if (store->store == storage) {
1319 /* Store not in list, so add it */
1320 jcr->wstorage->prepend(store->store);
1323 void free_wstorage(JCR *jcr)
1325 if (jcr->wstorage) {
1326 delete jcr->wstorage;
1327 jcr->wstorage = NULL;
1332 char *job_code_callback_clones(JCR *jcr, const char* param)
1334 if (param[0] == 'p') {
1335 return jcr->pool->name();
1340 void create_clones(JCR *jcr)
1343 * Fire off any clone jobs (run directives)
1345 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1346 if (!jcr->cloned && jcr->job->run_cmds) {
1348 JOB *job = jcr->job;
1349 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1350 UAContext *ua = new_ua_context(jcr);
1352 foreach_alist(runcmd, job->run_cmds) {
1353 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1354 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1355 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1356 parse_ua_args(ua); /* parse command */
1357 int stat = run_cmd(ua, ua->cmd);
1359 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1362 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1365 free_ua_context(ua);
1366 free_pool_memory(cmd);
1371 * Given: a JobId in jcr->previous_jr.JobId,
1372 * this subroutine writes a bsr file to restore that job.
1374 bool create_restore_bootstrap_file(JCR *jcr)
1378 memset(&rx, 0, sizeof(rx));
1380 rx.JobIds = (char *)"";
1381 rx.bsr->JobId = jcr->previous_jr.JobId;
1382 ua = new_ua_context(jcr);
1383 if (!complete_bsr(ua, rx.bsr)) {
1386 rx.bsr->fi = new_findex();
1387 rx.bsr->fi->findex = 1;
1388 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1389 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1390 if (jcr->ExpectedFiles == 0) {
1393 free_ua_context(ua);
1395 jcr->needs_sd = true;
1399 free_ua_context(ua);
1404 /* TODO: redirect command ouput to job log */
1405 bool run_console_command(JCR *jcr, const char *cmd)
1409 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1410 ua = new_ua_context(ljcr);
1411 /* run from runscript and check if commands are autorized */
1412 ua->runscript = true;
1413 Mmsg(ua->cmd, "%s", cmd);
1414 Dmsg1(100, "Console command: %s\n", ua->cmd);
1416 ok= do_a_command(ua);
1417 free_ua_context(ua);