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 John Walker.
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 *control_jcr, JCR *jcr);
45 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr);
47 /* Imported subroutines */
48 extern void term_scheduler();
49 extern void term_ua_server();
51 /* Imported variables */
55 void init_job_server(int max_workers)
60 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
62 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
65 wd->callback = job_monitor_watchdog;
66 wd->destructor = job_monitor_destructor;
69 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
70 register_watchdog(wd);
73 void term_job_server()
75 jobq_destroy(&job_queue); /* ignore any errors */
79 * Run a job -- typically called by the scheduler, but may also
80 * be called by the UA (Console program).
82 * Returns: 0 on failure
86 JobId_t run_job(JCR *jcr)
90 Dmsg0(200, "Add jrc to work queue\n");
91 /* Queue the job to be run */
92 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
94 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
102 bool setup_job(JCR *jcr)
107 sm_check(__FILE__, __LINE__, true);
108 init_msg(jcr, jcr->messages);
110 /* Initialize termination condition variable */
111 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
113 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
116 jcr->term_wait_inited = true;
118 create_unique_job_name(jcr, jcr->job->name());
119 set_jcr_job_status(jcr, JS_Created);
125 Dmsg0(100, "Open database\n");
126 jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
127 jcr->catalog->db_user,
128 jcr->catalog->db_password, jcr->catalog->db_address,
129 jcr->catalog->db_port, jcr->catalog->db_socket,
130 jcr->catalog->mult_db_connections);
131 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
132 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
133 jcr->catalog->db_name);
135 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
136 db_close_database(jcr, jcr->db);
140 Dmsg0(150, "DB opened\n");
143 jcr->fname = get_pool_memory(PM_FNAME);
145 if (!jcr->pool_source) {
146 jcr->pool_source = get_pool_memory(PM_MESSAGE);
147 pm_strcpy(jcr->pool_source, _("unknown source"));
149 Dmsg2(500, "pool=%s (From %s)\n", jcr->pool->name(), jcr->pool_source);
150 if (jcr->JobType == JT_MIGRATE || jcr->JobType == JT_COPY) {
151 if (!jcr->rpool_source) {
152 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
153 pm_strcpy(jcr->rpool_source, _("unknown source"));
160 init_jcr_job_record(jcr);
161 if (!get_or_create_client_record(jcr)) {
165 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
166 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
169 jcr->JobId = jcr->jr.JobId;
170 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
171 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
173 generate_daemon_event(jcr, "JobStart");
175 if (job_canceled(jcr)) {
180 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
181 * this allows us to setup a proper job start record for restarting
182 * in case of later errors.
184 switch (jcr->JobType) {
186 if (!do_backup_init(jcr)) {
187 backup_cleanup(jcr, JS_ErrorTerminated);
191 if (!do_verify_init(jcr)) {
192 verify_cleanup(jcr, JS_ErrorTerminated);
196 if (!do_restore_init(jcr)) {
197 restore_cleanup(jcr, JS_ErrorTerminated);
201 if (!do_admin_init(jcr)) {
202 admin_cleanup(jcr, JS_ErrorTerminated);
207 if (!do_migration_init(jcr)) {
208 migration_cleanup(jcr, JS_ErrorTerminated);
212 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
213 set_jcr_job_status(jcr, JS_ErrorTerminated);
217 generate_job_event(jcr, "JobInit");
225 void update_job_end(JCR *jcr, int TermCode)
227 dequeue_messages(jcr); /* display any queued messages */
228 set_jcr_job_status(jcr, TermCode);
229 update_job_end_record(jcr);
233 * This is the engine called by jobq.c:jobq_add() when we were pulled
234 * from the work queue.
235 * At this point, we are running in our own thread and all
236 * necessary resources are allocated -- see jobq.c
238 static void *job_thread(void *arg)
240 JCR *jcr = (JCR *)arg;
242 pthread_detach(pthread_self());
245 Dmsg0(200, "=====Start Job=========\n");
246 set_jcr_job_status(jcr, JS_Running); /* this will be set only if no error */
247 jcr->start_time = time(NULL); /* set the real start time */
248 jcr->jr.StartTime = jcr->start_time;
250 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
251 (utime_t)(jcr->start_time - jcr->sched_time)) {
252 set_jcr_job_status(jcr, JS_Canceled);
253 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
256 /* TODO : check if it is used somewhere */
257 if (jcr->job->RunScripts == NULL) {
258 Dmsg0(200, "Warning, job->RunScripts is empty\n");
259 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
262 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
263 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
266 /* Run any script BeforeJob on dird */
267 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
269 if (job_canceled(jcr)) {
270 update_job_end(jcr, jcr->JobStatus);
274 * We re-update the job start record so that the start
275 * time is set after the run before job. This avoids
276 * that any files created by the run before job will
277 * be saved twice. They will be backed up in the current
278 * job, but not in the next one unless they are changed.
279 * Without this, they will be backed up in this job and
280 * in the next job run because in that case, their date
281 * is after the start of this run.
283 jcr->start_time = time(NULL);
284 jcr->jr.StartTime = jcr->start_time;
285 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
286 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
288 generate_job_event(jcr, "JobRun");
290 switch (jcr->JobType) {
292 if (do_backup(jcr)) {
295 backup_cleanup(jcr, JS_ErrorTerminated);
299 if (do_verify(jcr)) {
302 verify_cleanup(jcr, JS_ErrorTerminated);
306 if (do_restore(jcr)) {
309 restore_cleanup(jcr, JS_ErrorTerminated);
316 admin_cleanup(jcr, JS_ErrorTerminated);
321 if (do_migration(jcr)) {
324 migration_cleanup(jcr, JS_ErrorTerminated);
328 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->JobType);
333 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
335 /* Send off any queued messages */
336 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
337 dequeue_messages(jcr);
340 generate_daemon_event(jcr, "JobEnd");
341 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
342 sm_check(__FILE__, __LINE__, true);
348 * Cancel a job -- typically called by the UA (Console program), but may also
349 * be called by the job watchdog.
351 * Returns: true if cancel appears to be successful
352 * false on failure. Message sent to ua->jcr.
354 bool cancel_job(UAContext *ua, JCR *jcr)
359 set_jcr_job_status(jcr, JS_Canceled);
361 switch (jcr->JobStatus) {
364 case JS_WaitClientRes:
365 case JS_WaitStoreRes:
366 case JS_WaitPriority:
368 case JS_WaitStartTime:
369 ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"),
370 edit_uint64(jcr->JobId, ed1), jcr->Job);
371 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
375 /* Cancel File daemon */
376 if (jcr->file_bsock) {
377 ua->jcr->client = jcr->client;
378 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
379 ua->error_msg(_("Failed to connect to File daemon.\n"));
382 Dmsg0(200, "Connected to file daemon\n");
383 fd = ua->jcr->file_bsock;
384 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
385 while (bnet_recv(fd) >= 0) {
386 ua->send_msg("%s", fd->msg);
388 bnet_sig(fd, BNET_TERMINATE);
390 ua->jcr->file_bsock = NULL;
393 /* Cancel Storage daemon */
394 if (jcr->store_bsock) {
395 if (!ua->jcr->wstorage) {
397 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
399 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
404 store.store = jcr->rstore;
406 store.store = jcr->wstore;
408 set_wstorage(ua->jcr, &store);
411 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
412 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
415 Dmsg0(200, "Connected to storage daemon\n");
416 sd = ua->jcr->store_bsock;
417 sd->fsend("cancel Job=%s\n", jcr->Job);
418 while (sd->recv() >= 0) {
419 ua->send_msg("%s", sd->msg);
421 sd->signal(BNET_TERMINATE);
423 ua->jcr->store_bsock = NULL;
430 void cancel_storage_daemon_job(JCR *jcr)
432 UAContext *ua = new_ua_context(jcr);
433 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
436 ua->jcr = control_jcr;
437 if (jcr->store_bsock) {
438 if (!ua->jcr->wstorage) {
440 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
442 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
447 store.store = jcr->rstore;
449 store.store = jcr->wstore;
451 set_wstorage(ua->jcr, &store);
454 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
457 Dmsg0(200, "Connected to storage daemon\n");
458 sd = ua->jcr->store_bsock;
459 sd->fsend("cancel Job=%s\n", jcr->Job);
460 while (sd->recv() >= 0) {
462 sd->signal(BNET_TERMINATE);
464 ua->jcr->store_bsock = NULL;
467 free_jcr(control_jcr);
471 static void job_monitor_destructor(watchdog_t *self)
473 JCR *control_jcr = (JCR *)self->data;
475 free_jcr(control_jcr);
478 static void job_monitor_watchdog(watchdog_t *self)
480 JCR *control_jcr, *jcr;
482 control_jcr = (JCR *)self->data;
485 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
490 if (jcr->JobId == 0 || job_canceled(jcr)) {
491 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
495 /* check MaxWaitTime */
496 if (job_check_maxwaittime(control_jcr, jcr)) {
497 set_jcr_job_status(jcr, JS_Canceled);
498 Jmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
500 /* check MaxRunTime */
501 } else if (job_check_maxruntime(control_jcr, jcr)) {
502 set_jcr_job_status(jcr, JS_Canceled);
503 Jmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
508 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
509 UAContext *ua = new_ua_context(jcr);
510 ua->jcr = control_jcr;
513 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
517 /* Keep reference counts correct */
522 * Check if the maxwaittime has expired and it is possible
525 static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
530 if (job_canceled(jcr)) {
531 return false; /* already canceled */
533 if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
534 job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
537 if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
538 (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
540 } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
541 (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
543 } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
544 (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
546 } else if (job->MaxWaitTime != 0 &&
547 (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
555 * Check if maxruntime has expired and if the job can be
558 static bool job_check_maxruntime(JCR *control_jcr, JCR *jcr)
560 if (jcr->job->MaxRunTime == 0 || job_canceled(jcr) || jcr->JobStatus == JS_Created) {
563 if ((watchdog_time - jcr->start_time) < jcr->job->MaxRunTime) {
564 Dmsg3(200, "Job %p (%s) with MaxRunTime %d not expired\n",
565 jcr, jcr->Job, jcr->job->MaxRunTime);
573 * Get or create a Pool record with the given name.
574 * Returns: 0 on error
577 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
581 memset(&pr, 0, sizeof(pr));
582 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
583 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
585 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
586 /* Try to create the pool */
587 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
588 Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name,
589 db_strerror(jcr->db));
592 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
599 * Check for duplicate jobs.
600 * Returns: true if current job should continue
601 * false if current job should terminate
603 bool allow_duplicate_job(JCR *jcr)
606 JCR *djcr; /* possible duplicate */
608 if (job->AllowDuplicateJobs) {
611 if (!job->AllowHigherDuplicates) {
613 if (strcmp(job->name(), djcr->job->name()) == 0) {
614 bool cancel_queued = false;
615 if (job->DuplicateJobProximity > 0) {
616 time_t now = time(NULL);
617 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
618 continue; /* not really a duplicate */
622 if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) {
623 /* Zap current job */
624 Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed.\n"));
627 /* If CancelQueuedDuplicates is set do so only if job is queued */
628 if (job->CancelQueuedDuplicates) {
629 switch (djcr->JobStatus) {
632 case JS_WaitClientRes:
633 case JS_WaitStoreRes:
634 case JS_WaitPriority:
636 case JS_WaitStartTime:
637 cancel_queued = true;
643 if (cancel_queued || job->CancelRunningDuplicates) {
644 UAContext *ua = new_ua_context(djcr);
646 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"),
647 edit_uint64(djcr->JobId, ec1));
649 cancel_job(ua, djcr);
651 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId);
659 void apply_pool_overrides(JCR *jcr)
661 bool pool_override = false;
663 if (jcr->run_pool_override) {
664 pm_strcpy(jcr->pool_source, _("Run pool override"));
667 * Apply any level related Pool selections
669 switch (jcr->JobLevel) {
671 if (jcr->full_pool) {
672 jcr->pool = jcr->full_pool;
673 pool_override = true;
674 if (jcr->run_full_pool_override) {
675 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
677 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
683 jcr->pool = jcr->inc_pool;
684 pool_override = true;
685 if (jcr->run_inc_pool_override) {
686 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
688 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
693 if (jcr->diff_pool) {
694 jcr->pool = jcr->diff_pool;
695 pool_override = true;
696 if (jcr->run_diff_pool_override) {
697 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
699 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
704 /* Update catalog if pool overridden */
705 if (pool_override && jcr->pool->catalog) {
706 jcr->catalog = jcr->pool->catalog;
707 pm_strcpy(jcr->catalog_source, _("Pool resource"));
713 * Get or create a Client record for this Job
715 bool get_or_create_client_record(JCR *jcr)
719 memset(&cr, 0, sizeof(cr));
720 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
721 cr.AutoPrune = jcr->client->AutoPrune;
722 cr.FileRetention = jcr->client->FileRetention;
723 cr.JobRetention = jcr->client->JobRetention;
724 if (!jcr->client_name) {
725 jcr->client_name = get_pool_memory(PM_NAME);
727 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
728 if (!db_create_client_record(jcr, jcr->db, &cr)) {
729 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
730 db_strerror(jcr->db));
733 jcr->jr.ClientId = cr.ClientId;
735 if (!jcr->client_uname) {
736 jcr->client_uname = get_pool_memory(PM_NAME);
738 pm_strcpy(jcr->client_uname, cr.Uname);
740 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
745 bool get_or_create_fileset_record(JCR *jcr)
749 * Get or Create FileSet record
751 memset(&fsr, 0, sizeof(FILESET_DBR));
752 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
753 if (jcr->fileset->have_MD5) {
754 struct MD5Context md5c;
755 unsigned char digest[MD5HashSize];
756 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
757 MD5Final(digest, &md5c);
759 * Keep the flag (last arg) set to false otherwise old FileSets will
760 * get new MD5 sums and the user will get Full backups on everything
762 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
763 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
765 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
767 if (!jcr->fileset->ignore_fs_changes ||
768 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
769 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
770 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
771 fsr.FileSet, db_strerror(jcr->db));
775 jcr->jr.FileSetId = fsr.FileSetId;
776 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
777 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
782 void init_jcr_job_record(JCR *jcr)
784 jcr->jr.SchedTime = jcr->sched_time;
785 jcr->jr.StartTime = jcr->start_time;
786 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
787 jcr->jr.JobType = jcr->JobType;
788 jcr->jr.JobLevel = jcr->JobLevel;
789 jcr->jr.JobStatus = jcr->JobStatus;
790 jcr->jr.JobId = jcr->JobId;
791 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
792 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
796 * Write status and such in DB
798 void update_job_end_record(JCR *jcr)
800 jcr->jr.EndTime = time(NULL);
801 jcr->end_time = jcr->jr.EndTime;
802 jcr->jr.JobId = jcr->JobId;
803 jcr->jr.JobStatus = jcr->JobStatus;
804 jcr->jr.JobFiles = jcr->JobFiles;
805 jcr->jr.JobBytes = jcr->JobBytes;
806 jcr->jr.VolSessionId = jcr->VolSessionId;
807 jcr->jr.VolSessionTime = jcr->VolSessionTime;
808 jcr->jr.JobErrors = jcr->Errors;
809 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
810 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
811 db_strerror(jcr->db));
816 * Takes base_name and appends (unique) current
817 * date and time to form unique job name.
819 * Note, the seconds are actually a sequence number. This
820 * permits us to start a maximum fo 59 unique jobs a second, which
821 * should be sufficient.
823 * Returns: unique job name in jcr->Job
824 * date/time in jcr->start_time
826 void create_unique_job_name(JCR *jcr, const char *base_name)
828 /* Job start mutex */
829 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
830 static time_t last_start_time = 0;
834 char dt[MAX_TIME_LENGTH];
835 char name[MAX_NAME_LENGTH];
838 /* Guarantee unique start time -- maximum one per second, and
839 * thus unique Job Name
841 P(mutex); /* lock creation of jobs */
844 if (seq > 59) { /* wrap as if it is seconds */
846 while (now == last_start_time) {
847 bmicrosleep(0, 500000);
851 last_start_time = now;
852 V(mutex); /* allow creation of jobs */
853 jcr->start_time = now;
854 /* Form Unique JobName */
855 (void)localtime_r(&now, &tm);
856 /* Use only characters that are permitted in Windows filenames */
857 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M", &tm);
858 bstrncpy(name, base_name, sizeof(name));
859 name[sizeof(name)-22] = 0; /* truncate if too long */
860 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s.%02d", name, dt, seq); /* add date & time */
861 /* Convert spaces into underscores */
862 for (p=jcr->Job; *p; p++) {
869 /* Called directly from job rescheduling */
870 void dird_free_jcr_pointers(JCR *jcr)
872 if (jcr->sd_auth_key) {
873 free(jcr->sd_auth_key);
874 jcr->sd_auth_key = NULL;
880 if (jcr->file_bsock) {
881 Dmsg0(200, "Close File bsock\n");
882 bnet_close(jcr->file_bsock);
883 jcr->file_bsock = NULL;
885 if (jcr->store_bsock) {
886 Dmsg0(200, "Close Store bsock\n");
887 bnet_close(jcr->store_bsock);
888 jcr->store_bsock = NULL;
891 Dmsg0(200, "Free JCR fname\n");
892 free_pool_memory(jcr->fname);
895 if (jcr->RestoreBootstrap) {
896 free(jcr->RestoreBootstrap);
897 jcr->RestoreBootstrap = NULL;
899 if (jcr->client_uname) {
900 free_pool_memory(jcr->client_uname);
901 jcr->client_uname = NULL;
904 free_pool_memory(jcr->attr);
914 * Free the Job Control Record if no one is still using it.
915 * Called from main free_jcr() routine in src/lib/jcr.c so
916 * that we can do our Director specific cleanup of the jcr.
918 void dird_free_jcr(JCR *jcr)
920 Dmsg0(200, "Start dird free_jcr\n");
922 dird_free_jcr_pointers(jcr);
923 if (jcr->term_wait_inited) {
924 pthread_cond_destroy(&jcr->term_wait);
925 jcr->term_wait_inited = false;
927 if (jcr->db_batch && jcr->db_batch != jcr->db) {
928 db_close_database(jcr, jcr->db_batch);
930 jcr->db_batch = NULL;
932 db_close_database(jcr, jcr->db);
936 Dmsg0(200, "Free JCR stime\n");
937 free_pool_memory(jcr->stime);
941 Dmsg0(200, "Free JCR fname\n");
942 free_pool_memory(jcr->fname);
945 if (jcr->pool_source) {
946 free_pool_memory(jcr->pool_source);
947 jcr->pool_source = NULL;
949 if (jcr->catalog_source) {
950 free_pool_memory(jcr->catalog_source);
951 jcr->catalog_source = NULL;
953 if (jcr->rpool_source) {
954 free_pool_memory(jcr->rpool_source);
955 jcr->rpool_source = NULL;
957 if (jcr->wstore_source) {
958 free_pool_memory(jcr->wstore_source);
959 jcr->wstore_source = NULL;
961 if (jcr->rstore_source) {
962 free_pool_memory(jcr->rstore_source);
963 jcr->rstore_source = NULL;
966 /* Delete lists setup to hold storage pointers */
969 jcr->job_end_push.destroy();
972 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
974 Dmsg0(200, "End dird free_jcr\n");
978 * The Job storage definition must be either in the Job record
979 * or in the Pool record. The Pool record overrides the Job
982 void get_job_storage(USTORE *store, JOB *job, RUN *run)
984 if (run && run->pool && run->pool->storage) {
985 store->store = (STORE *)run->pool->storage->first();
986 pm_strcpy(store->store_source, _("Run pool override"));
989 if (run && run->storage) {
990 store->store = run->storage;
991 pm_strcpy(store->store_source, _("Run storage override"));
994 if (job->pool->storage) {
995 store->store = (STORE *)job->pool->storage->first();
996 pm_strcpy(store->store_source, _("Pool resource"));
998 store->store = (STORE *)job->storage->first();
999 pm_strcpy(store->store_source, _("Job resource"));
1004 * Set some defaults in the JCR necessary to
1005 * run. These items are pulled from the job
1006 * definition as defaults, but can be overridden
1007 * later either by the Run record in the Schedule resource,
1008 * or by the Console program.
1010 void set_jcr_defaults(JCR *jcr, JOB *job)
1013 jcr->JobType = job->JobType;
1014 jcr->JobStatus = JS_Created;
1015 switch (jcr->JobType) {
1018 jcr->JobLevel = L_NONE;
1022 if (!jcr->rpool_source) {
1023 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
1024 pm_strcpy(jcr->rpool_source, _("unknown source"));
1026 /* Fall-through wanted */
1028 jcr->JobLevel = job->JobLevel;
1032 jcr->fname = get_pool_memory(PM_FNAME);
1034 if (!jcr->pool_source) {
1035 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1036 pm_strcpy(jcr->pool_source, _("unknown source"));
1038 if (!jcr->catalog_source) {
1039 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1040 pm_strcpy(jcr->catalog_source, _("unknown source"));
1043 jcr->JobPriority = job->Priority;
1044 /* Copy storage definitions -- deleted in dir_free_jcr above */
1046 copy_rwstorage(jcr, job->storage, _("Job resource"));
1048 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1050 jcr->client = job->client;
1051 if (!jcr->client_name) {
1052 jcr->client_name = get_pool_memory(PM_NAME);
1054 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1055 pm_strcpy(jcr->pool_source, _("Job resource"));
1056 jcr->pool = job->pool;
1057 jcr->full_pool = job->full_pool;
1058 jcr->inc_pool = job->inc_pool;
1059 jcr->diff_pool = job->diff_pool;
1060 if (job->pool->catalog) {
1061 jcr->catalog = job->pool->catalog;
1062 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1064 jcr->catalog = job->client->catalog;
1065 pm_strcpy(jcr->catalog_source, _("Client resource"));
1067 jcr->fileset = job->fileset;
1068 jcr->messages = job->messages;
1069 jcr->spool_data = job->spool_data;
1070 jcr->spool_size = job->spool_size;
1071 jcr->write_part_after_job = job->write_part_after_job;
1072 jcr->accurate = job->accurate;
1073 if (jcr->RestoreBootstrap) {
1074 free(jcr->RestoreBootstrap);
1075 jcr->RestoreBootstrap = NULL;
1077 /* This can be overridden by Console program */
1078 if (job->RestoreBootstrap) {
1079 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1081 /* This can be overridden by Console program */
1082 jcr->verify_job = job->verify_job;
1083 /* If no default level given, set one */
1084 if (jcr->JobLevel == 0) {
1085 switch (jcr->JobType) {
1087 jcr->JobLevel = L_VERIFY_CATALOG;
1090 jcr->JobLevel = L_INCREMENTAL;
1094 jcr->JobLevel = L_NONE;
1097 jcr->JobLevel = L_FULL;
1104 * Copy the storage definitions from an alist to the JCR
1106 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1108 switch(jcr->JobType) {
1113 copy_rstorage(jcr, storage, where);
1116 copy_wstorage(jcr, storage, where);
1122 /* Set storage override. Releases any previous storage definition */
1123 void set_rwstorage(JCR *jcr, USTORE *store)
1126 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1129 switch(jcr->JobType) {
1134 set_rstorage(jcr, store);
1137 set_wstorage(jcr, store);
1142 void free_rwstorage(JCR *jcr)
1149 * Copy the storage definitions from an alist to the JCR
1151 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1155 if (jcr->rstorage) {
1156 delete jcr->rstorage;
1158 jcr->rstorage = New(alist(10, not_owned_by_alist));
1159 foreach_alist(st, storage) {
1160 jcr->rstorage->append(st);
1162 if (!jcr->rstore_source) {
1163 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1165 pm_strcpy(jcr->rstore_source, where);
1166 if (jcr->rstorage) {
1167 jcr->rstore = (STORE *)jcr->rstorage->first();
1173 /* Set storage override. Remove all previous storage */
1174 void set_rstorage(JCR *jcr, USTORE *store)
1178 if (!store->store) {
1181 if (jcr->rstorage) {
1184 if (!jcr->rstorage) {
1185 jcr->rstorage = New(alist(10, not_owned_by_alist));
1187 jcr->rstore = store->store;
1188 if (!jcr->rstore_source) {
1189 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1191 pm_strcpy(jcr->rstore_source, store->store_source);
1192 foreach_alist(storage, jcr->rstorage) {
1193 if (store->store == storage) {
1197 /* Store not in list, so add it */
1198 jcr->rstorage->prepend(store->store);
1201 void free_rstorage(JCR *jcr)
1203 if (jcr->rstorage) {
1204 delete jcr->rstorage;
1205 jcr->rstorage = NULL;
1211 * Copy the storage definitions from an alist to the JCR
1213 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1217 if (jcr->wstorage) {
1218 delete jcr->wstorage;
1220 jcr->wstorage = New(alist(10, not_owned_by_alist));
1221 foreach_alist(st, storage) {
1222 Dmsg1(100, "wstorage=%s\n", st->name());
1223 jcr->wstorage->append(st);
1225 if (!jcr->wstore_source) {
1226 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1228 pm_strcpy(jcr->wstore_source, where);
1229 if (jcr->wstorage) {
1230 jcr->wstore = (STORE *)jcr->wstorage->first();
1231 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1237 /* Set storage override. Remove all previous storage */
1238 void set_wstorage(JCR *jcr, USTORE *store)
1242 if (!store->store) {
1245 if (jcr->wstorage) {
1248 if (!jcr->wstorage) {
1249 jcr->wstorage = New(alist(10, not_owned_by_alist));
1251 jcr->wstore = store->store;
1252 if (!jcr->wstore_source) {
1253 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1255 pm_strcpy(jcr->wstore_source, store->store_source);
1256 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1257 foreach_alist(storage, jcr->wstorage) {
1258 if (store->store == storage) {
1262 /* Store not in list, so add it */
1263 jcr->wstorage->prepend(store->store);
1266 void free_wstorage(JCR *jcr)
1268 if (jcr->wstorage) {
1269 delete jcr->wstorage;
1270 jcr->wstorage = NULL;
1275 void create_clones(JCR *jcr)
1278 * Fire off any clone jobs (run directives)
1280 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1281 if (!jcr->cloned && jcr->job->run_cmds) {
1283 JOB *job = jcr->job;
1284 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1285 UAContext *ua = new_ua_context(jcr);
1287 foreach_alist(runcmd, job->run_cmds) {
1288 cmd = edit_job_codes(jcr, cmd, runcmd, "");
1289 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1290 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1291 parse_ua_args(ua); /* parse command */
1292 int stat = run_cmd(ua, ua->cmd);
1294 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job.\n"));
1296 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1299 free_ua_context(ua);
1300 free_pool_memory(cmd);
1304 bool create_restore_bootstrap_file(JCR *jcr)
1308 memset(&rx, 0, sizeof(rx));
1310 rx.JobIds = (char *)"";
1311 rx.bsr->JobId = jcr->previous_jr.JobId;
1312 ua = new_ua_context(jcr);
1313 complete_bsr(ua, rx.bsr);
1314 rx.bsr->fi = new_findex();
1315 rx.bsr->fi->findex = 1;
1316 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1317 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1318 if (jcr->ExpectedFiles == 0) {
1319 free_ua_context(ua);
1323 free_ua_context(ua);
1325 jcr->needs_sd = true;
1329 bool run_console_command(JCR *jcr, const char *cmd){
1333 ua = new_ua_context(jcr);
1334 Mmsg(ua->cmd, "%s", cmd);
1335 Dmsg1(100, "Console command: %s\n", ua->cmd);
1337 ok= do_a_command(ua);
1338 free_ua_context(ua);