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));
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 switch (jcr->JobType) {
157 jcr->JobReads = true;
160 if (jcr->JobLevel == L_VIRTUAL_FULL) {
161 jcr->JobReads = true;
168 if (!jcr->rpool_source) {
169 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
170 pm_strcpy(jcr->rpool_source, _("unknown source"));
177 init_jcr_job_record(jcr);
178 if (!get_or_create_client_record(jcr)) {
182 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
183 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
186 jcr->JobId = jcr->jr.JobId;
187 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
188 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
190 generate_daemon_event(jcr, "JobStart");
192 if (job_canceled(jcr)) {
197 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
198 * this allows us to setup a proper job start record for restarting
199 * in case of later errors.
201 switch (jcr->JobType) {
203 if (!do_backup_init(jcr)) {
204 backup_cleanup(jcr, JS_ErrorTerminated);
208 if (!do_verify_init(jcr)) {
209 verify_cleanup(jcr, JS_ErrorTerminated);
213 if (!do_restore_init(jcr)) {
214 restore_cleanup(jcr, JS_ErrorTerminated);
218 if (!do_admin_init(jcr)) {
219 admin_cleanup(jcr, JS_ErrorTerminated);
224 if (!do_migration_init(jcr)) {
225 migration_cleanup(jcr, JS_ErrorTerminated);
229 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
230 set_jcr_job_status(jcr, JS_ErrorTerminated);
234 generate_job_event(jcr, "JobInit");
242 void update_job_end(JCR *jcr, int TermCode)
244 dequeue_messages(jcr); /* display any queued messages */
245 set_jcr_job_status(jcr, TermCode);
246 update_job_end_record(jcr);
250 * This is the engine called by jobq.c:jobq_add() when we were pulled
251 * from the work queue.
252 * At this point, we are running in our own thread and all
253 * necessary resources are allocated -- see jobq.c
255 static void *job_thread(void *arg)
257 JCR *jcr = (JCR *)arg;
259 pthread_detach(pthread_self());
262 Dmsg0(200, "=====Start Job=========\n");
263 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
264 jcr->start_time = time(NULL); /* set the real start time */
265 jcr->jr.StartTime = jcr->start_time;
267 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
268 (utime_t)(jcr->start_time - jcr->sched_time)) {
269 set_jcr_job_status(jcr, JS_Canceled);
270 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
273 if (job_check_maxschedruntime(jcr)) {
274 set_jcr_job_status(jcr, JS_Canceled);
275 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max sched run time exceeded.\n"));
278 /* TODO : check if it is used somewhere */
279 if (jcr->job->RunScripts == NULL) {
280 Dmsg0(200, "Warning, job->RunScripts is empty\n");
281 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
284 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
285 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
288 /* Run any script BeforeJob on dird */
289 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
291 if (job_canceled(jcr)) {
292 update_job_end(jcr, jcr->JobStatus);
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");
312 switch (jcr->JobType) {
314 if (do_backup(jcr)) {
317 backup_cleanup(jcr, JS_ErrorTerminated);
321 if (do_verify(jcr)) {
324 verify_cleanup(jcr, JS_ErrorTerminated);
328 if (do_restore(jcr)) {
331 restore_cleanup(jcr, JS_ErrorTerminated);
338 admin_cleanup(jcr, JS_ErrorTerminated);
343 if (do_migration(jcr)) {
346 migration_cleanup(jcr, JS_ErrorTerminated);
350 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->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 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
364 sm_check(__FILE__, __LINE__, true);
370 * Cancel a job -- typically called by the UA (Console program), but may also
371 * be called by the job watchdog.
373 * Returns: true if cancel appears to be successful
374 * false on failure. Message sent to ua->jcr.
376 bool cancel_job(UAContext *ua, JCR *jcr)
381 set_jcr_job_status(jcr, JS_Canceled);
383 switch (jcr->JobStatus) {
386 case JS_WaitClientRes:
387 case JS_WaitStoreRes:
388 case JS_WaitPriority:
390 case JS_WaitStartTime:
391 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
392 edit_uint64(jcr->JobId, ed1), jcr->Job);
393 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
397 /* Cancel File daemon */
398 if (jcr->file_bsock) {
399 ua->jcr->client = jcr->client;
400 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
401 ua->error_msg(_("Failed to connect to File daemon.\n"));
404 Dmsg0(200, "Connected to file daemon\n");
405 fd = ua->jcr->file_bsock;
406 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
407 while (bnet_recv(fd) >= 0) {
408 ua->send_msg("%s", fd->msg);
410 bnet_sig(fd, BNET_TERMINATE);
412 ua->jcr->file_bsock = NULL;
415 /* Cancel Storage daemon */
416 if (jcr->store_bsock) {
417 if (!ua->jcr->wstorage) {
419 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
421 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
426 store.store = jcr->rstore;
428 store.store = jcr->wstore;
430 set_wstorage(ua->jcr, &store);
433 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
434 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
437 Dmsg0(200, "Connected to storage daemon\n");
438 sd = ua->jcr->store_bsock;
439 sd->fsend("cancel Job=%s\n", jcr->Job);
440 while (sd->recv() >= 0) {
441 ua->send_msg("%s", sd->msg);
443 sd->signal(BNET_TERMINATE);
445 ua->jcr->store_bsock = NULL;
452 void cancel_storage_daemon_job(JCR *jcr)
454 UAContext *ua = new_ua_context(jcr);
455 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
458 ua->jcr = control_jcr;
459 if (jcr->store_bsock) {
460 if (!ua->jcr->wstorage) {
462 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
464 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
469 store.store = jcr->rstore;
471 store.store = jcr->wstore;
473 set_wstorage(ua->jcr, &store);
476 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
479 Dmsg0(200, "Connected to storage daemon\n");
480 sd = ua->jcr->store_bsock;
481 sd->fsend("cancel Job=%s\n", jcr->Job);
482 while (sd->recv() >= 0) {
484 sd->signal(BNET_TERMINATE);
486 ua->jcr->store_bsock = NULL;
489 free_jcr(control_jcr);
493 static void job_monitor_destructor(watchdog_t *self)
495 JCR *control_jcr = (JCR *)self->data;
497 free_jcr(control_jcr);
500 static void job_monitor_watchdog(watchdog_t *self)
502 JCR *control_jcr, *jcr;
504 control_jcr = (JCR *)self->data;
507 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
512 if (jcr->JobId == 0 || job_canceled(jcr)) {
513 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
517 /* check MaxWaitTime */
518 if (job_check_maxwaittime(jcr)) {
519 set_jcr_job_status(jcr, JS_Canceled);
520 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
522 /* check MaxRunTime */
523 } else if (job_check_maxruntime(jcr)) {
524 set_jcr_job_status(jcr, JS_Canceled);
525 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
527 /* check MaxRunSchedTime */
528 } else if (job_check_maxschedruntime(jcr)) {
529 set_jcr_job_status(jcr, JS_Canceled);
530 Qmsg(jcr, M_FATAL, 0, _("Max sched run time exceeded. Job canceled.\n"));
535 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
536 UAContext *ua = new_ua_context(jcr);
537 ua->jcr = control_jcr;
540 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
544 /* Keep reference counts correct */
549 * Check if the maxwaittime has expired and it is possible
552 static bool job_check_maxwaittime(JCR *jcr)
557 if (!job_waiting(jcr)) {
560 Dmsg3(200, "check maxwaittime %u - %u >= %u\n", watchdog_time, jcr->wait_time, job->MaxWaitTime);
561 if (job->MaxWaitTime != 0 &&
562 (watchdog_time - jcr->wait_time) >= job->MaxWaitTime) {
570 * Check if maxruntime has expired and if the job can be
573 static bool job_check_maxruntime(JCR *jcr)
578 if (job_canceled(jcr) || jcr->JobStatus == JS_Created) {
581 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
582 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
585 Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
586 watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime,
587 job->IncMaxRunTime, job->DiffMaxRunTime);
589 if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
590 (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
592 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
593 (watchdog_time - jcr->start_time) >= job->DiffMaxRunTime) {
595 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
596 (watchdog_time - jcr->start_time) >= job->IncMaxRunTime) {
598 } else if ((watchdog_time - jcr->start_time) >= job->MaxRunTime) {
606 * Check if MaxRunSchedTime has expired and if the job can be
609 static bool job_check_maxschedruntime(JCR *jcr)
611 if (jcr->job->MaxRunSchedTime == 0 || job_canceled(jcr)) {
614 if ((watchdog_time - jcr->sched_time) < jcr->job->MaxRunSchedTime) {
615 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
616 jcr, jcr->Job, jcr->job->MaxRunSchedTime);
624 * Get or create a Pool record with the given name.
625 * Returns: 0 on error
628 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
632 memset(&pr, 0, sizeof(pr));
633 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
634 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
636 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
637 /* Try to create the pool */
638 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
639 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
640 db_strerror(jcr->db));
643 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
650 * Check for duplicate jobs.
651 * Returns: true if current job should continue
652 * false if current job should terminate
654 bool allow_duplicate_job(JCR *jcr)
657 JCR *djcr; /* possible duplicate */
659 if (job->AllowDuplicateJobs) {
662 if (!job->AllowHigherDuplicates) {
665 if (strcmp(job->name(), djcr->job->name()) == 0) {
666 bool cancel_queued = false;
667 if (job->DuplicateJobProximity > 0) {
668 time_t now = time(NULL);
669 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
670 continue; /* not really a duplicate */
674 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
675 /* Zap current job */
676 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed. JobId=%s\n"),
677 edit_uint64(djcr->JobId, ec1));
680 /* If CancelQueuedDuplicates is set do so only if job is queued */
681 if (job->CancelQueuedDuplicates) {
682 switch (djcr->JobStatus) {
685 case JS_WaitClientRes:
686 case JS_WaitStoreRes:
687 case JS_WaitPriority:
689 case JS_WaitStartTime:
690 cancel_queued = true;
696 if (cancel_queued || job->CancelRunningDuplicates) {
697 UAContext *ua = new_ua_context(djcr);
698 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
699 edit_uint64(djcr->JobId, ec1));
701 cancel_job(ua, djcr);
703 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
711 void apply_pool_overrides(JCR *jcr)
713 bool pool_override = false;
715 if (jcr->run_pool_override) {
716 pm_strcpy(jcr->pool_source, _("Run pool override"));
719 * Apply any level related Pool selections
721 switch (jcr->JobLevel) {
723 if (jcr->full_pool) {
724 jcr->pool = jcr->full_pool;
725 pool_override = true;
726 if (jcr->run_full_pool_override) {
727 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
729 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
735 jcr->pool = jcr->inc_pool;
736 pool_override = true;
737 if (jcr->run_inc_pool_override) {
738 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
740 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
745 if (jcr->diff_pool) {
746 jcr->pool = jcr->diff_pool;
747 pool_override = true;
748 if (jcr->run_diff_pool_override) {
749 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
751 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
756 /* Update catalog if pool overridden */
757 if (pool_override && jcr->pool->catalog) {
758 jcr->catalog = jcr->pool->catalog;
759 pm_strcpy(jcr->catalog_source, _("Pool resource"));
765 * Get or create a Client record for this Job
767 bool get_or_create_client_record(JCR *jcr)
771 memset(&cr, 0, sizeof(cr));
772 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
773 cr.AutoPrune = jcr->client->AutoPrune;
774 cr.FileRetention = jcr->client->FileRetention;
775 cr.JobRetention = jcr->client->JobRetention;
776 if (!jcr->client_name) {
777 jcr->client_name = get_pool_memory(PM_NAME);
779 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
780 if (!db_create_client_record(jcr, jcr->db, &cr)) {
781 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
782 db_strerror(jcr->db));
785 jcr->jr.ClientId = cr.ClientId;
787 if (!jcr->client_uname) {
788 jcr->client_uname = get_pool_memory(PM_NAME);
790 pm_strcpy(jcr->client_uname, cr.Uname);
792 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
797 bool get_or_create_fileset_record(JCR *jcr)
801 * Get or Create FileSet record
803 memset(&fsr, 0, sizeof(FILESET_DBR));
804 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
805 if (jcr->fileset->have_MD5) {
806 struct MD5Context md5c;
807 unsigned char digest[MD5HashSize];
808 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
809 MD5Final(digest, &md5c);
811 * Keep the flag (last arg) set to false otherwise old FileSets will
812 * get new MD5 sums and the user will get Full backups on everything
814 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
815 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
817 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
819 if (!jcr->fileset->ignore_fs_changes ||
820 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
821 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
822 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
823 fsr.FileSet, db_strerror(jcr->db));
827 jcr->jr.FileSetId = fsr.FileSetId;
828 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
829 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
834 void init_jcr_job_record(JCR *jcr)
836 jcr->jr.SchedTime = jcr->sched_time;
837 jcr->jr.StartTime = jcr->start_time;
838 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
839 jcr->jr.JobType = jcr->JobType;
840 jcr->jr.JobLevel = jcr->JobLevel;
841 jcr->jr.JobStatus = jcr->JobStatus;
842 jcr->jr.JobId = jcr->JobId;
843 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
844 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
848 * Write status and such in DB
850 void update_job_end_record(JCR *jcr)
852 jcr->jr.EndTime = time(NULL);
853 jcr->end_time = jcr->jr.EndTime;
854 jcr->jr.JobId = jcr->JobId;
855 jcr->jr.JobStatus = jcr->JobStatus;
856 jcr->jr.JobFiles = jcr->JobFiles;
857 jcr->jr.JobBytes = jcr->JobBytes;
858 jcr->jr.VolSessionId = jcr->VolSessionId;
859 jcr->jr.VolSessionTime = jcr->VolSessionTime;
860 jcr->jr.JobErrors = jcr->Errors;
861 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr, jcr->job->stats_enabled)) {
862 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
863 db_strerror(jcr->db));
868 * Takes base_name and appends (unique) current
869 * date and time to form unique job name.
871 * Note, the seconds are actually a sequence number. This
872 * permits us to start a maximum fo 59 unique jobs a second, which
873 * should be sufficient.
875 * Returns: unique job name in jcr->Job
876 * date/time in jcr->start_time
878 void create_unique_job_name(JCR *jcr, const char *base_name)
880 /* Job start mutex */
881 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
882 static time_t last_start_time = 0;
886 char dt[MAX_TIME_LENGTH];
887 char name[MAX_NAME_LENGTH];
890 /* Guarantee unique start time -- maximum one per second, and
891 * thus unique Job Name
893 P(mutex); /* lock creation of jobs */
896 if (seq > 59) { /* wrap as if it is seconds */
898 while (now == last_start_time) {
899 bmicrosleep(0, 500000);
903 last_start_time = now;
904 V(mutex); /* allow creation of jobs */
905 jcr->start_time = now;
906 /* Form Unique JobName */
907 (void)localtime_r(&now, &tm);
908 /* Use only characters that are permitted in Windows filenames */
909 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
910 bstrncpy(name, base_name, sizeof(name));
911 name[sizeof(name)-22] = 0; /* truncate if too long */
912 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
913 /* Convert spaces into underscores */
914 for (p=jcr->Job; *p; p++) {
921 /* Called directly from job rescheduling */
922 void dird_free_jcr_pointers(JCR *jcr)
924 if (jcr->sd_auth_key) {
925 free(jcr->sd_auth_key);
926 jcr->sd_auth_key = NULL;
932 if (jcr->file_bsock) {
933 Dmsg0(200, "Close File bsock\n");
934 bnet_close(jcr->file_bsock);
935 jcr->file_bsock = NULL;
937 if (jcr->store_bsock) {
938 Dmsg0(200, "Close Store bsock\n");
939 bnet_close(jcr->store_bsock);
940 jcr->store_bsock = NULL;
943 Dmsg0(200, "Free JCR fname\n");
944 free_pool_memory(jcr->fname);
947 if (jcr->RestoreBootstrap) {
948 free(jcr->RestoreBootstrap);
949 jcr->RestoreBootstrap = NULL;
951 if (jcr->client_uname) {
952 free_pool_memory(jcr->client_uname);
953 jcr->client_uname = NULL;
956 free_pool_memory(jcr->attr);
966 * Free the Job Control Record if no one is still using it.
967 * Called from main free_jcr() routine in src/lib/jcr.c so
968 * that we can do our Director specific cleanup of the jcr.
970 void dird_free_jcr(JCR *jcr)
972 Dmsg0(200, "Start dird free_jcr\n");
974 dird_free_jcr_pointers(jcr);
975 if (jcr->term_wait_inited) {
976 pthread_cond_destroy(&jcr->term_wait);
977 jcr->term_wait_inited = false;
979 if (jcr->db_batch && jcr->db_batch != jcr->db) {
980 db_close_database(jcr, jcr->db_batch);
982 jcr->db_batch = NULL;
984 db_close_database(jcr, jcr->db);
988 Dmsg0(200, "Free JCR stime\n");
989 free_pool_memory(jcr->stime);
993 Dmsg0(200, "Free JCR fname\n");
994 free_pool_memory(jcr->fname);
997 if (jcr->pool_source) {
998 free_pool_memory(jcr->pool_source);
999 jcr->pool_source = NULL;
1001 if (jcr->catalog_source) {
1002 free_pool_memory(jcr->catalog_source);
1003 jcr->catalog_source = NULL;
1005 if (jcr->rpool_source) {
1006 free_pool_memory(jcr->rpool_source);
1007 jcr->rpool_source = NULL;
1009 if (jcr->wstore_source) {
1010 free_pool_memory(jcr->wstore_source);
1011 jcr->wstore_source = NULL;
1013 if (jcr->rstore_source) {
1014 free_pool_memory(jcr->rstore_source);
1015 jcr->rstore_source = NULL;
1018 /* Delete lists setup to hold storage pointers */
1019 free_rwstorage(jcr);
1021 jcr->job_end_push.destroy();
1023 if (jcr->JobId != 0)
1024 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1026 Dmsg0(200, "End dird free_jcr\n");
1030 * The Job storage definition must be either in the Job record
1031 * or in the Pool record. The Pool record overrides the Job
1034 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1036 if (run && run->pool && run->pool->storage) {
1037 store->store = (STORE *)run->pool->storage->first();
1038 pm_strcpy(store->store_source, _("Run pool override"));
1041 if (run && run->storage) {
1042 store->store = run->storage;
1043 pm_strcpy(store->store_source, _("Run storage override"));
1046 if (job->pool->storage) {
1047 store->store = (STORE *)job->pool->storage->first();
1048 pm_strcpy(store->store_source, _("Pool resource"));
1050 store->store = (STORE *)job->storage->first();
1051 pm_strcpy(store->store_source, _("Job resource"));
1056 * Set some defaults in the JCR necessary to
1057 * run. These items are pulled from the job
1058 * definition as defaults, but can be overridden
1059 * later either by the Run record in the Schedule resource,
1060 * or by the Console program.
1062 void set_jcr_defaults(JCR *jcr, JOB *job)
1065 jcr->JobType = job->JobType;
1066 jcr->JobStatus = JS_Created;
1068 switch (jcr->JobType) {
1070 jcr->JobLevel = L_NONE;
1073 jcr->JobLevel = job->JobLevel;
1078 jcr->fname = get_pool_memory(PM_FNAME);
1080 if (!jcr->pool_source) {
1081 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1082 pm_strcpy(jcr->pool_source, _("unknown source"));
1084 if (!jcr->catalog_source) {
1085 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1086 pm_strcpy(jcr->catalog_source, _("unknown source"));
1089 jcr->JobPriority = job->Priority;
1090 /* Copy storage definitions -- deleted in dir_free_jcr above */
1092 copy_rwstorage(jcr, job->storage, _("Job resource"));
1094 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1096 jcr->client = job->client;
1097 if (!jcr->client_name) {
1098 jcr->client_name = get_pool_memory(PM_NAME);
1100 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1101 pm_strcpy(jcr->pool_source, _("Job resource"));
1102 jcr->pool = job->pool;
1103 jcr->full_pool = job->full_pool;
1104 jcr->inc_pool = job->inc_pool;
1105 jcr->diff_pool = job->diff_pool;
1106 if (job->pool->catalog) {
1107 jcr->catalog = job->pool->catalog;
1108 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1110 jcr->catalog = job->client->catalog;
1111 pm_strcpy(jcr->catalog_source, _("Client resource"));
1113 jcr->fileset = job->fileset;
1114 jcr->messages = job->messages;
1115 jcr->spool_data = job->spool_data;
1116 jcr->spool_size = job->spool_size;
1117 jcr->write_part_after_job = job->write_part_after_job;
1118 jcr->accurate = job->accurate;
1119 if (jcr->RestoreBootstrap) {
1120 free(jcr->RestoreBootstrap);
1121 jcr->RestoreBootstrap = NULL;
1123 /* This can be overridden by Console program */
1124 if (job->RestoreBootstrap) {
1125 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1127 /* This can be overridden by Console program */
1128 jcr->verify_job = job->verify_job;
1129 /* If no default level given, set one */
1130 if (jcr->JobLevel == 0) {
1131 switch (jcr->JobType) {
1133 jcr->JobLevel = L_VERIFY_CATALOG;
1136 jcr->JobLevel = L_INCREMENTAL;
1140 jcr->JobLevel = L_NONE;
1143 jcr->JobLevel = L_FULL;
1150 * Copy the storage definitions from an alist to the JCR
1152 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1154 if (jcr->JobReads) {
1155 copy_rstorage(jcr, storage, where);
1157 copy_wstorage(jcr, storage, where);
1161 /* Set storage override. Releases any previous storage definition */
1162 void set_rwstorage(JCR *jcr, USTORE *store)
1165 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1168 if (jcr->JobReads) {
1169 set_rstorage(jcr, store);
1171 set_wstorage(jcr, store);
1174 void free_rwstorage(JCR *jcr)
1181 * Copy the storage definitions from an alist to the JCR
1183 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1187 if (jcr->rstorage) {
1188 delete jcr->rstorage;
1190 jcr->rstorage = New(alist(10, not_owned_by_alist));
1191 foreach_alist(st, storage) {
1192 jcr->rstorage->append(st);
1194 if (!jcr->rstore_source) {
1195 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1197 pm_strcpy(jcr->rstore_source, where);
1198 if (jcr->rstorage) {
1199 jcr->rstore = (STORE *)jcr->rstorage->first();
1205 /* Set storage override. Remove all previous storage */
1206 void set_rstorage(JCR *jcr, USTORE *store)
1210 if (!store->store) {
1213 if (jcr->rstorage) {
1216 if (!jcr->rstorage) {
1217 jcr->rstorage = New(alist(10, not_owned_by_alist));
1219 jcr->rstore = store->store;
1220 if (!jcr->rstore_source) {
1221 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1223 pm_strcpy(jcr->rstore_source, store->store_source);
1224 foreach_alist(storage, jcr->rstorage) {
1225 if (store->store == storage) {
1229 /* Store not in list, so add it */
1230 jcr->rstorage->prepend(store->store);
1233 void free_rstorage(JCR *jcr)
1235 if (jcr->rstorage) {
1236 delete jcr->rstorage;
1237 jcr->rstorage = NULL;
1243 * Copy the storage definitions from an alist to the JCR
1245 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1249 if (jcr->wstorage) {
1250 delete jcr->wstorage;
1252 jcr->wstorage = New(alist(10, not_owned_by_alist));
1253 foreach_alist(st, storage) {
1254 Dmsg1(100, "wstorage=%s\n", st->name());
1255 jcr->wstorage->append(st);
1257 if (!jcr->wstore_source) {
1258 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1260 pm_strcpy(jcr->wstore_source, where);
1261 if (jcr->wstorage) {
1262 jcr->wstore = (STORE *)jcr->wstorage->first();
1263 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1269 /* Set storage override. Remove all previous storage */
1270 void set_wstorage(JCR *jcr, USTORE *store)
1274 if (!store->store) {
1277 if (jcr->wstorage) {
1280 if (!jcr->wstorage) {
1281 jcr->wstorage = New(alist(10, not_owned_by_alist));
1283 jcr->wstore = store->store;
1284 if (!jcr->wstore_source) {
1285 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1287 pm_strcpy(jcr->wstore_source, store->store_source);
1288 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1289 foreach_alist(storage, jcr->wstorage) {
1290 if (store->store == storage) {
1294 /* Store not in list, so add it */
1295 jcr->wstorage->prepend(store->store);
1298 void free_wstorage(JCR *jcr)
1300 if (jcr->wstorage) {
1301 delete jcr->wstorage;
1302 jcr->wstorage = NULL;
1307 char *job_code_callback_clones(JCR *jcr, const char* param)
1309 if (param[0] == 'p') {
1310 return jcr->pool->name();
1315 void create_clones(JCR *jcr)
1318 * Fire off any clone jobs (run directives)
1320 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1321 if (!jcr->cloned && jcr->job->run_cmds) {
1323 JOB *job = jcr->job;
1324 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1325 UAContext *ua = new_ua_context(jcr);
1327 foreach_alist(runcmd, job->run_cmds) {
1328 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_clones);
1329 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1330 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1331 parse_ua_args(ua); /* parse command */
1332 int stat = run_cmd(ua, ua->cmd);
1334 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1336 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1339 free_ua_context(ua);
1340 free_pool_memory(cmd);
1345 * Given: a JobId in jcr->previous_jr.JobId,
1346 * this subroutine writes a bsr file to restore that job.
1348 bool create_restore_bootstrap_file(JCR *jcr)
1352 memset(&rx, 0, sizeof(rx));
1354 rx.JobIds = (char *)"";
1355 rx.bsr->JobId = jcr->previous_jr.JobId;
1356 ua = new_ua_context(jcr);
1357 complete_bsr(ua, rx.bsr);
1358 rx.bsr->fi = new_findex();
1359 rx.bsr->fi->findex = 1;
1360 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1361 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1362 if (jcr->ExpectedFiles == 0) {
1363 free_ua_context(ua);
1367 free_ua_context(ua);
1369 jcr->needs_sd = true;
1373 bool run_console_command(JCR *jcr, const char *cmd){
1377 ua = new_ua_context(jcr);
1378 Mmsg(ua->cmd, "%s", cmd);
1379 Dmsg1(100, "Console command: %s\n", ua->cmd);
1381 ok= do_a_command(ua);
1382 free_ua_context(ua);