2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director Job processing routines
32 * Kern Sibbald, October MM
40 /* Forward referenced subroutines */
41 static void *job_thread(void *arg);
42 static void job_monitor_watchdog(watchdog_t *self);
43 static void job_monitor_destructor(watchdog_t *self);
44 static bool job_check_maxwaittime(JCR *jcr);
45 static bool job_check_maxruntime(JCR *jcr);
46 static bool job_check_maxschedruntime(JCR *jcr);
48 /* Imported subroutines */
49 extern void term_scheduler();
50 extern void term_ua_server();
52 /* Imported variables */
56 void init_job_server(int max_workers)
61 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
63 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
66 wd->callback = job_monitor_watchdog;
67 wd->destructor = job_monitor_destructor;
70 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
71 register_watchdog(wd);
74 void term_job_server()
76 jobq_destroy(&job_queue); /* ignore any errors */
80 * Run a job -- typically called by the scheduler, but may also
81 * be called by the UA (Console program).
83 * Returns: 0 on failure
87 JobId_t run_job(JCR *jcr)
91 Dmsg0(200, "Add jrc to work queue\n");
92 /* Queue the job to be run */
93 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
95 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
103 bool setup_job(JCR *jcr)
108 sm_check(__FILE__, __LINE__, true);
109 init_msg(jcr, jcr->messages);
111 /* Initialize termination condition variable */
112 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
114 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
117 jcr->term_wait_inited = true;
119 create_unique_job_name(jcr, jcr->job->name());
120 set_jcr_job_status(jcr, JS_Created);
126 Dmsg0(100, "Open database\n");
127 jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
128 jcr->catalog->db_user,
129 jcr->catalog->db_password, jcr->catalog->db_address,
130 jcr->catalog->db_port, jcr->catalog->db_socket,
131 jcr->catalog->mult_db_connections);
132 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
133 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
134 jcr->catalog->db_name);
136 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
137 db_close_database(jcr, jcr->db);
141 Dmsg0(150, "DB opened\n");
144 jcr->fname = get_pool_memory(PM_FNAME);
146 if (!jcr->pool_source) {
147 jcr->pool_source = get_pool_memory(PM_MESSAGE);
148 pm_strcpy(jcr->pool_source, _("unknown source"));
150 Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
151 if (jcr->JobType == JT_MIGRATE || jcr->JobType == JT_COPY) {
152 if (!jcr->rpool_source) {
153 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
154 pm_strcpy(jcr->rpool_source, _("unknown source"));
161 init_jcr_job_record(jcr);
162 if (!get_or_create_client_record(jcr)) {
166 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
167 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
170 jcr->JobId = jcr->jr.JobId;
171 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
172 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
174 generate_daemon_event(jcr, "JobStart");
176 if (job_canceled(jcr)) {
181 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
182 * this allows us to setup a proper job start record for restarting
183 * in case of later errors.
185 switch (jcr->JobType) {
187 if (!do_backup_init(jcr)) {
188 backup_cleanup(jcr, JS_ErrorTerminated);
192 if (!do_verify_init(jcr)) {
193 verify_cleanup(jcr, JS_ErrorTerminated);
197 if (!do_restore_init(jcr)) {
198 restore_cleanup(jcr, JS_ErrorTerminated);
202 if (!do_admin_init(jcr)) {
203 admin_cleanup(jcr, JS_ErrorTerminated);
208 if (!do_migration_init(jcr)) {
209 migration_cleanup(jcr, JS_ErrorTerminated);
213 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
214 set_jcr_job_status(jcr, JS_ErrorTerminated);
218 generate_job_event(jcr, "JobInit");
226 void update_job_end(JCR *jcr, int TermCode)
228 dequeue_messages(jcr); /* display any queued messages */
229 set_jcr_job_status(jcr, TermCode);
230 update_job_end_record(jcr);
234 * This is the engine called by jobq.c:jobq_add() when we were pulled
235 * from the work queue.
236 * At this point, we are running in our own thread and all
237 * necessary resources are allocated -- see jobq.c
239 static void *job_thread(void *arg)
241 JCR *jcr = (JCR *)arg;
243 pthread_detach(pthread_self());
246 Dmsg0(200, "=====Start Job=========\n");
247 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
248 jcr->start_time = time(NULL); /* set the real start time */
249 jcr->jr.StartTime = jcr->start_time;
251 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
252 (utime_t)(jcr->start_time - jcr->sched_time)) {
253 set_jcr_job_status(jcr, JS_Canceled);
254 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
257 if (job_check_maxschedruntime(jcr)) {
258 set_jcr_job_status(jcr, JS_Canceled);
259 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
262 /* TODO : check if it is used somewhere */
263 if (jcr->job->RunScripts == NULL) {
264 Dmsg0(200, "Warning, job->RunScripts is empty\n");
265 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
268 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
269 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
272 /* Run any script BeforeJob on dird */
273 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
275 if (job_canceled(jcr)) {
276 update_job_end(jcr, jcr->JobStatus);
280 * We re-update the job start record so that the start
281 * time is set after the run before job. This avoids
282 * that any files created by the run before job will
283 * be saved twice. They will be backed up in the current
284 * job, but not in the next one unless they are changed.
285 * Without this, they will be backed up in this job and
286 * in the next job run because in that case, their date
287 * is after the start of this run.
289 jcr->start_time = time(NULL);
290 jcr->jr.StartTime = jcr->start_time;
291 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
292 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
294 generate_job_event(jcr, "JobRun");
296 switch (jcr->JobType) {
298 if (do_backup(jcr)) {
301 backup_cleanup(jcr, JS_ErrorTerminated);
305 if (do_verify(jcr)) {
308 verify_cleanup(jcr, JS_ErrorTerminated);
312 if (do_restore(jcr)) {
315 restore_cleanup(jcr, JS_ErrorTerminated);
322 admin_cleanup(jcr, JS_ErrorTerminated);
327 if (do_migration(jcr)) {
330 migration_cleanup(jcr, JS_ErrorTerminated);
334 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
339 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
341 /* Send off any queued messages */
342 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
343 dequeue_messages(jcr);
346 generate_daemon_event(jcr, "JobEnd");
347 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
348 sm_check(__FILE__, __LINE__, true);
354 * Cancel a job -- typically called by the UA (Console program), but may also
355 * be called by the job watchdog.
357 * Returns: true if cancel appears to be successful
358 * false on failure. Message sent to ua->jcr.
360 bool cancel_job(UAContext *ua, JCR *jcr)
365 set_jcr_job_status(jcr, JS_Canceled);
367 switch (jcr->JobStatus) {
370 case JS_WaitClientRes:
371 case JS_WaitStoreRes:
372 case JS_WaitPriority:
374 case JS_WaitStartTime:
375 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
376 edit_uint64(jcr->JobId, ed1), jcr->Job);
377 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
381 /* Cancel File daemon */
382 if (jcr->file_bsock) {
383 ua->jcr->client = jcr->client;
384 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
385 ua->error_msg(_("Failed to connect to File daemon.\n"));
388 Dmsg0(200, "Connected to file daemon\n");
389 fd = ua->jcr->file_bsock;
390 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
391 while (bnet_recv(fd) >= 0) {
392 ua->send_msg("%s", fd->msg);
394 bnet_sig(fd, BNET_TERMINATE);
396 ua->jcr->file_bsock = NULL;
399 /* Cancel Storage daemon */
400 if (jcr->store_bsock) {
401 if (!ua->jcr->wstorage) {
403 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
405 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
410 store.store = jcr->rstore;
412 store.store = jcr->wstore;
414 set_wstorage(ua->jcr, &store);
417 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
418 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
421 Dmsg0(200, "Connected to storage daemon\n");
422 sd = ua->jcr->store_bsock;
423 sd->fsend("cancel Job=%s\n", jcr->Job);
424 while (sd->recv() >= 0) {
425 ua->send_msg("%s", sd->msg);
427 sd->signal(BNET_TERMINATE);
429 ua->jcr->store_bsock = NULL;
436 void cancel_storage_daemon_job(JCR *jcr)
438 UAContext *ua = new_ua_context(jcr);
439 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
442 ua->jcr = control_jcr;
443 if (jcr->store_bsock) {
444 if (!ua->jcr->wstorage) {
446 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
448 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
453 store.store = jcr->rstore;
455 store.store = jcr->wstore;
457 set_wstorage(ua->jcr, &store);
460 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
463 Dmsg0(200, "Connected to storage daemon\n");
464 sd = ua->jcr->store_bsock;
465 sd->fsend("cancel Job=%s\n", jcr->Job);
466 while (sd->recv() >= 0) {
468 sd->signal(BNET_TERMINATE);
470 ua->jcr->store_bsock = NULL;
473 free_jcr(control_jcr);
477 static void job_monitor_destructor(watchdog_t *self)
479 JCR *control_jcr = (JCR *)self->data;
481 free_jcr(control_jcr);
484 static void job_monitor_watchdog(watchdog_t *self)
486 JCR *control_jcr, *jcr;
488 control_jcr = (JCR *)self->data;
491 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
496 if (jcr->JobId == 0 || job_canceled(jcr)) {
497 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
501 /* check MaxWaitTime */
502 if (job_check_maxwaittime(jcr)) {
503 set_jcr_job_status(jcr, JS_Canceled);
504 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
506 /* check MaxRunTime */
507 } else if (job_check_maxruntime(jcr)) {
508 set_jcr_job_status(jcr, JS_Canceled);
509 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
511 /* check MaxRunSchedTime */
512 } else if (job_check_maxschedruntime(jcr)) {
513 set_jcr_job_status(jcr, JS_Canceled);
514 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
519 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
520 UAContext *ua = new_ua_context(jcr);
521 ua->jcr = control_jcr;
524 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
528 /* Keep reference counts correct */
533 * Check if the maxwaittime has expired and it is possible
536 static bool job_check_maxwaittime(JCR *jcr)
541 if (!job_waiting(jcr)) {
544 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
545 if (job->MaxWaitTime != 0 &&
546 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
554 * Check if maxruntime has expired and if the job can be
557 static bool job_check_maxruntime(JCR *jcr)
562 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
565 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
566 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
569 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
570 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
571 job->IncMaxRunTime, job->DiffMaxRunTime);
573 if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
574 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
576 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
577 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
579 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
580 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
582 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
590 * Check if MaxRunSchedTime has expired and if the job can be
593 static bool job_check_maxschedruntime(JCR *jcr)
595 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
598 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
599 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
600 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
608 * Get or create a Pool record with the given name.
609 * Returns: 0 on error
612 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
616 memset(&pr, 0, sizeof(pr));
617 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
618 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
620 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
621 /* Try to create the pool */
622 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
623 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
624 db_strerror(jcr->db));
627 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
634 * Check for duplicate jobs.
635 * Returns: true if current job should continue
636 * false if current job should terminate
638 bool allow_duplicate_job(JCR *jcr)
641 JCR *djcr; /* possible duplicate */
643 if (job->AllowDuplicateJobs) {
646 if (!job->AllowHigherDuplicates) {
649 if (strcmp(job->name(), djcr->job->name()) == 0) {
650 bool cancel_queued = false;
651 if (job->DuplicateJobProximity > 0) {
652 time_t now = time(NULL);
653 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
654 continue; /* not really a duplicate */
658 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
659 /* Zap current job */
660 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
661 edit_uint64(djcr->JobId, ec1));
664 /* If CancelQueuedDuplicates is set do so only if job is queued */
665 if (job->CancelQueuedDuplicates) {
666 switch (djcr->JobStatus) {
669 case JS_WaitClientRes:
670 case JS_WaitStoreRes:
671 case JS_WaitPriority:
673 case JS_WaitStartTime:
674 cancel_queued = true;
680 if (cancel_queued || job->CancelRunningDuplicates) {
681 UAContext *ua = new_ua_context(djcr);
682 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
683 edit_uint64(djcr->JobId, ec1));
685 cancel_job(ua, djcr);
687 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
695 void apply_pool_overrides(JCR *jcr)
697 bool pool_override = false;
699 if (jcr->run_pool_override) {
700 pm_strcpy(jcr->pool_source, _("Run pool override"));
703 * Apply any level related Pool selections
705 switch (jcr->JobLevel) {
707 if (jcr->full_pool) {
708 jcr->pool = jcr->full_pool;
709 pool_override = true;
710 if (jcr->run_full_pool_override) {
711 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
713 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
719 jcr->pool = jcr->inc_pool;
720 pool_override = true;
721 if (jcr->run_inc_pool_override) {
722 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
724 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
729 if (jcr->diff_pool) {
730 jcr->pool = jcr->diff_pool;
731 pool_override = true;
732 if (jcr->run_diff_pool_override) {
733 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
735 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
740 /* Update catalog if pool overridden */
741 if (pool_override && jcr->pool->catalog) {
742 jcr->catalog = jcr->pool->catalog;
743 pm_strcpy(jcr->catalog_source, _("Pool resource"));
749 * Get or create a Client record for this Job
751 bool get_or_create_client_record(JCR *jcr)
755 memset(&cr, 0, sizeof(cr));
756 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
757 cr.AutoPrune = jcr->client->AutoPrune;
758 cr.FileRetention = jcr->client->FileRetention;
759 cr.JobRetention = jcr->client->JobRetention;
760 if (!jcr->client_name) {
761 jcr->client_name = get_pool_memory(PM_NAME);
763 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
764 if (!db_create_client_record(jcr, jcr->db, &cr)) {
765 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
766 db_strerror(jcr->db));
769 jcr->jr.ClientId = cr.ClientId;
771 if (!jcr->client_uname) {
772 jcr->client_uname = get_pool_memory(PM_NAME);
774 pm_strcpy(jcr->client_uname, cr.Uname);
776 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
781 bool get_or_create_fileset_record(JCR *jcr)
785 * Get or Create FileSet record
787 memset(&fsr, 0, sizeof(FILESET_DBR));
788 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
789 if (jcr->fileset->have_MD5) {
790 struct MD5Context md5c;
791 unsigned char digest[MD5HashSize];
792 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
793 MD5Final(digest, &md5c);
795 * Keep the flag (last arg) set to false otherwise old FileSets will
796 * get new MD5 sums and the user will get Full backups on everything
798 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
799 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
801 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
803 if (!jcr->fileset->ignore_fs_changes ||
804 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
805 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
806 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
807 fsr.FileSet, db_strerror(jcr->db));
811 jcr->jr.FileSetId = fsr.FileSetId;
812 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
813 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
818 void init_jcr_job_record(JCR *jcr)
820 jcr->jr.SchedTime = jcr->sched_time;
821 jcr->jr.StartTime = jcr->start_time;
822 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
823 jcr->jr.JobType = jcr->JobType;
824 jcr->jr.JobLevel = jcr->JobLevel;
825 jcr->jr.JobStatus = jcr->JobStatus;
826 jcr->jr.JobId = jcr->JobId;
827 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
828 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
832 * Write status and such in DB
834 void update_job_end_record(JCR *jcr)
836 jcr->jr.EndTime = time(NULL);
837 jcr->end_time = jcr->jr.EndTime;
838 jcr->jr.JobId = jcr->JobId;
839 jcr->jr.JobStatus = jcr->JobStatus;
840 jcr->jr.JobFiles = jcr->JobFiles;
841 jcr->jr.JobBytes = jcr->JobBytes;
842 jcr->jr.VolSessionId = jcr->VolSessionId;
843 jcr->jr.VolSessionTime = jcr->VolSessionTime;
844 jcr->jr.JobErrors = jcr->Errors;
845 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr, jcr->job->stats_enabled)) {
846 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
847 db_strerror(jcr->db));
852 * Takes base_name and appends (unique) current
853 * date and time to form unique job name.
855 * Note, the seconds are actually a sequence number. This
856 * permits us to start a maximum fo 59 unique jobs a second, which
857 * should be sufficient.
859 * Returns: unique job name in jcr->Job
860 * date/time in jcr->start_time
862 void create_unique_job_name(JCR *jcr, const char *base_name)
864 /* Job start mutex */
865 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
866 static time_t last_start_time = 0;
870 char dt[MAX_TIME_LENGTH];
871 char name[MAX_NAME_LENGTH];
874 /* Guarantee unique start time -- maximum one per second, and
875 * thus unique Job Name
877 P(mutex); /* lock creation of jobs */
880 if (seq > 59) { /* wrap as if it is seconds */
882 while (now == last_start_time) {
883 bmicrosleep(0, 500000);
887 last_start_time = now;
888 V(mutex); /* allow creation of jobs */
889 jcr->start_time = now;
890 /* Form Unique JobName */
891 (void)localtime_r(&now, &tm);
892 /* Use only characters that are permitted in Windows filenames */
893 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
894 bstrncpy(name, base_name, sizeof(name));
895 name[sizeof(name)-22] = 0; /* truncate if too long */
896 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
897 /* Convert spaces into underscores */
898 for (p=jcr->Job; *p; p++) {
905 /* Called directly from job rescheduling */
906 void dird_free_jcr_pointers(JCR *jcr)
908 if (jcr->sd_auth_key) {
909 free(jcr->sd_auth_key);
910 jcr->sd_auth_key = NULL;
916 if (jcr->file_bsock) {
917 Dmsg0(200, "Close File bsock\n");
918 bnet_close(jcr->file_bsock);
919 jcr->file_bsock = NULL;
921 if (jcr->store_bsock) {
922 Dmsg0(200, "Close Store bsock\n");
923 bnet_close(jcr->store_bsock);
924 jcr->store_bsock = NULL;
927 Dmsg0(200, "Free JCR fname\n");
928 free_pool_memory(jcr->fname);
931 if (jcr->RestoreBootstrap) {
932 free(jcr->RestoreBootstrap);
933 jcr->RestoreBootstrap = NULL;
935 if (jcr->client_uname) {
936 free_pool_memory(jcr->client_uname);
937 jcr->client_uname = NULL;
940 free_pool_memory(jcr->attr);
950 * Free the Job Control Record if no one is still using it.
951 * Called from main free_jcr() routine in src/lib/jcr.c so
952 * that we can do our Director specific cleanup of the jcr.
954 void dird_free_jcr(JCR *jcr)
956 Dmsg0(200, "Start dird free_jcr\n");
958 dird_free_jcr_pointers(jcr);
959 if (jcr->term_wait_inited) {
960 pthread_cond_destroy(&jcr->term_wait);
961 jcr->term_wait_inited = false;
963 if (jcr->db_batch && jcr->db_batch != jcr->db) {
964 db_close_database(jcr, jcr->db_batch);
966 jcr->db_batch = NULL;
968 db_close_database(jcr, jcr->db);
972 Dmsg0(200, "Free JCR stime\n");
973 free_pool_memory(jcr->stime);
977 Dmsg0(200, "Free JCR fname\n");
978 free_pool_memory(jcr->fname);
981 if (jcr->pool_source) {
982 free_pool_memory(jcr->pool_source);
983 jcr->pool_source = NULL;
985 if (jcr->catalog_source) {
986 free_pool_memory(jcr->catalog_source);
987 jcr->catalog_source = NULL;
989 if (jcr->rpool_source) {
990 free_pool_memory(jcr->rpool_source);
991 jcr->rpool_source = NULL;
993 if (jcr->wstore_source) {
994 free_pool_memory(jcr->wstore_source);
995 jcr->wstore_source = NULL;
997 if (jcr->rstore_source) {
998 free_pool_memory(jcr->rstore_source);
999 jcr->rstore_source = NULL;
1002 /* Delete lists setup to hold storage pointers */
1003 free_rwstorage(jcr);
1005 jcr->job_end_push.destroy();
1007 if (jcr->JobId != 0)
1008 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1010 Dmsg0(200, "End dird free_jcr\n");
1014 * The Job storage definition must be either in the Job record
1015 * or in the Pool record. The Pool record overrides the Job
1018 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1020 if (run && run->pool && run->pool->storage) {
1021 store->store = (STORE *)run->pool->storage->first();
1022 pm_strcpy(store->store_source, _("Run pool override"));
1025 if (run && run->storage) {
1026 store->store = run->storage;
1027 pm_strcpy(store->store_source, _("Run storage override"));
1030 if (job->pool->storage) {
1031 store->store = (STORE *)job->pool->storage->first();
1032 pm_strcpy(store->store_source, _("Pool resource"));
1034 store->store = (STORE *)job->storage->first();
1035 pm_strcpy(store->store_source, _("Job resource"));
1040 * Set some defaults in the JCR necessary to
1041 * run. These items are pulled from the job
1042 * definition as defaults, but can be overridden
1043 * later either by the Run record in the Schedule resource,
1044 * or by the Console program.
1046 void set_jcr_defaults(JCR *jcr, JOB *job)
1049 jcr->JobType = job->JobType;
1050 jcr->JobStatus = JS_Created;
1051 switch (jcr->JobType) {
1054 jcr->JobLevel = L_NONE;
1058 if (!jcr->rpool_source) {
1059 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
1060 pm_strcpy(jcr->rpool_source, _("unknown source"));
1062 /* Fall-through wanted */
1064 jcr->JobLevel = job->JobLevel;
1068 jcr->fname = get_pool_memory(PM_FNAME);
1070 if (!jcr->pool_source) {
1071 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1072 pm_strcpy(jcr->pool_source, _("unknown source"));
1074 if (!jcr->catalog_source) {
1075 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1076 pm_strcpy(jcr->catalog_source, _("unknown source"));
1079 jcr->JobPriority = job->Priority;
1080 /* Copy storage definitions -- deleted in dir_free_jcr above */
1082 copy_rwstorage(jcr, job->storage, _("Job resource"));
1084 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1086 jcr->client = job->client;
1087 if (!jcr->client_name) {
1088 jcr->client_name = get_pool_memory(PM_NAME);
1090 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1091 pm_strcpy(jcr->pool_source, _("Job resource"));
1092 jcr->pool = job->pool;
1093 jcr->full_pool = job->full_pool;
1094 jcr->inc_pool = job->inc_pool;
1095 jcr->diff_pool = job->diff_pool;
1096 if (job->pool->catalog) {
1097 jcr->catalog = job->pool->catalog;
1098 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1100 jcr->catalog = job->client->catalog;
1101 pm_strcpy(jcr->catalog_source, _("Client resource"));
1103 jcr->fileset = job->fileset;
1104 jcr->messages = job->messages;
1105 jcr->spool_data = job->spool_data;
1106 jcr->spool_size = job->spool_size;
1107 jcr->write_part_after_job = job->write_part_after_job;
1108 jcr->accurate = job->accurate;
1109 if (jcr->RestoreBootstrap) {
1110 free(jcr->RestoreBootstrap);
1111 jcr->RestoreBootstrap = NULL;
1113 /* This can be overridden by Console program */
1114 if (job->RestoreBootstrap) {
1115 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1117 /* This can be overridden by Console program */
1118 jcr->verify_job = job->verify_job;
1119 /* If no default level given, set one */
1120 if (jcr->JobLevel == 0) {
1121 switch (jcr->JobType) {
1123 jcr->JobLevel = L_VERIFY_CATALOG;
1126 jcr->JobLevel = L_INCREMENTAL;
1130 jcr->JobLevel = L_NONE;
1133 jcr->JobLevel = L_FULL;
1140 * Copy the storage definitions from an alist to the JCR
1142 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1144 switch(jcr->JobType) {
1149 copy_rstorage(jcr, storage, where);
1152 copy_wstorage(jcr, storage, where);
1158 /* Set storage override. Releases any previous storage definition */
1159 void set_rwstorage(JCR *jcr, USTORE *store)
1162 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1165 switch(jcr->JobType) {
1170 set_rstorage(jcr, store);
1173 set_wstorage(jcr, store);
1178 void free_rwstorage(JCR *jcr)
1185 * Copy the storage definitions from an alist to the JCR
1187 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1191 if (jcr->rstorage) {
1192 delete jcr->rstorage;
1194 jcr->rstorage = New(alist(10, not_owned_by_alist));
1195 foreach_alist(st, storage) {
1196 jcr->rstorage->append(st);
1198 if (!jcr->rstore_source) {
1199 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1201 pm_strcpy(jcr->rstore_source, where);
1202 if (jcr->rstorage) {
1203 jcr->rstore = (STORE *)jcr->rstorage->first();
1209 /* Set storage override. Remove all previous storage */
1210 void set_rstorage(JCR *jcr, USTORE *store)
1214 if (!store->store) {
1217 if (jcr->rstorage) {
1220 if (!jcr->rstorage) {
1221 jcr->rstorage = New(alist(10, not_owned_by_alist));
1223 jcr->rstore = store->store;
1224 if (!jcr->rstore_source) {
1225 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1227 pm_strcpy(jcr->rstore_source, store->store_source);
1228 foreach_alist(storage, jcr->rstorage) {
1229 if (store->store == storage) {
1233 /* Store not in list, so add it */
1234 jcr->rstorage->prepend(store->store);
1237 void free_rstorage(JCR *jcr)
1239 if (jcr->rstorage) {
1240 delete jcr->rstorage;
1241 jcr->rstorage = NULL;
1247 * Copy the storage definitions from an alist to the JCR
1249 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1253 if (jcr->wstorage) {
1254 delete jcr->wstorage;
1256 jcr->wstorage = New(alist(10, not_owned_by_alist));
1257 foreach_alist(st, storage) {
1258 Dmsg1(100, "wstorage=%s\n", st->name());
1259 jcr->wstorage->append(st);
1261 if (!jcr->wstore_source) {
1262 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1264 pm_strcpy(jcr->wstore_source, where);
1265 if (jcr->wstorage) {
1266 jcr->wstore = (STORE *)jcr->wstorage->first();
1267 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1273 /* Set storage override. Remove all previous storage */
1274 void set_wstorage(JCR *jcr, USTORE *store)
1278 if (!store->store) {
1281 if (jcr->wstorage) {
1284 if (!jcr->wstorage) {
1285 jcr->wstorage = New(alist(10, not_owned_by_alist));
1287 jcr->wstore = store->store;
1288 if (!jcr->wstore_source) {
1289 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1291 pm_strcpy(jcr->wstore_source, store->store_source);
1292 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1293 foreach_alist(storage, jcr->wstorage) {
1294 if (store->store == storage) {
1298 /* Store not in list, so add it */
1299 jcr->wstorage->prepend(store->store);
1302 void free_wstorage(JCR *jcr)
1304 if (jcr->wstorage) {
1305 delete jcr->wstorage;
1306 jcr->wstorage = NULL;
1311 char *job_code_callback_clones(JCR *jcr, const char* param)
1313 if (param[0] == 'p') {
1314 return jcr->pool->name();
1319 void create_clones(JCR *jcr)
1322 * Fire off any clone jobs (run directives)
1324 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1325 if (!jcr->cloned && jcr->job->run_cmds) {
1327 JOB *job = jcr->job;
1328 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1329 UAContext *ua = new_ua_context(jcr);
1331 foreach_alist(runcmd, job->run_cmds) {
1332 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1333 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1334 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1335 parse_ua_args(ua); /* parse command */
1336 int stat = run_cmd(ua, ua->cmd);
1338 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1340 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1343 free_ua_context(ua);
1344 free_pool_memory(cmd);
1349 * Given: a JobId in jcr->previous_jr.JobId,
1350 * this subroutine writes a bsr file to restore that job.
1352 bool create_restore_bootstrap_file(JCR *jcr)
1356 memset(&rx, 0, sizeof(rx));
1358 rx.JobIds = (char *)"";
1359 rx.bsr->JobId = jcr->previous_jr.JobId;
1360 ua = new_ua_context(jcr);
1361 complete_bsr(ua, rx.bsr);
1362 rx.bsr->fi = new_findex();
1363 rx.bsr->fi->findex = 1;
1364 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1365 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1366 if (jcr->ExpectedFiles == 0) {
1367 free_ua_context(ua);
1371 free_ua_context(ua);
1373 jcr->needs_sd = true;
1377 bool run_console_command(JCR *jcr, const char *cmd){
1381 ua = new_ua_context(jcr);
1382 Mmsg(ua->cmd, "%s", cmd);
1383 Dmsg1(100, "Console command: %s\n", ua->cmd);
1385 ok= do_a_command(ua);
1386 free_ua_context(ua);