2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula Director Job processing routines
22 * Kern Sibbald, October MM
28 /* Forward referenced subroutines */
29 static void *job_thread(void *arg);
30 static void job_monitor_watchdog(watchdog_t *self);
31 static void job_monitor_destructor(watchdog_t *self);
32 static bool job_check_maxwaittime(JCR *jcr);
33 static bool job_check_maxruntime(JCR *jcr);
34 static bool job_check_maxrunschedtime(JCR *jcr);
36 /* Imported subroutines */
37 extern void term_scheduler();
38 extern void term_ua_server();
40 /* Imported variables */
44 void init_job_server(int max_workers)
49 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
51 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
54 wd->callback = job_monitor_watchdog;
55 wd->destructor = job_monitor_destructor;
58 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
59 register_watchdog(wd);
62 void term_job_server()
64 jobq_destroy(&job_queue); /* ignore any errors */
68 * Run a job -- typically called by the scheduler, but may also
69 * be called by the UA (Console program).
71 * Returns: 0 on failure
75 JobId_t run_job(JCR *jcr)
79 Dmsg0(200, "Add jrc to work queue\n");
80 /* Queue the job to be run */
81 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
83 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
91 bool setup_job(JCR *jcr)
97 init_msg(jcr, jcr->messages, job_code_callback_director);
99 /* Initialize termination condition variable */
100 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
102 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
106 jcr->term_wait_inited = true;
108 create_unique_job_name(jcr, jcr->job->name());
109 jcr->setJobStatus(JS_Created);
115 Dmsg0(100, "Open database\n");
116 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
117 jcr->catalog->db_user, jcr->catalog->db_password,
118 jcr->catalog->db_address, jcr->catalog->db_port,
119 jcr->catalog->db_socket, jcr->catalog->db_ssl_mode,
120 jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert,
121 jcr->catalog->db_ssl_ca, jcr->catalog->db_ssl_capath,
122 jcr->catalog->db_ssl_cipher,
123 jcr->catalog->mult_db_connections,
124 jcr->catalog->disable_batch_insert);
125 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
126 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
127 jcr->catalog->db_name);
129 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
130 db_close_database(jcr, jcr->db);
136 Dmsg0(150, "DB opened\n");
138 jcr->fname = get_pool_memory(PM_FNAME);
140 if (!jcr->pool_source) {
141 jcr->pool_source = get_pool_memory(PM_MESSAGE);
142 pm_strcpy(jcr->pool_source, _("unknown source"));
144 if (!jcr->next_pool_source) {
145 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
146 pm_strcpy(jcr->next_pool_source, _("unknown source"));
149 if (jcr->JobReads()) {
150 if (!jcr->rpool_source) {
151 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
152 pm_strcpy(jcr->rpool_source, _("unknown source"));
159 init_jcr_job_record(jcr);
160 if (!get_or_create_client_record(jcr)) {
164 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
165 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
168 jcr->JobId = jcr->jr.JobId;
169 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
170 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
172 generate_daemon_event(jcr, "JobStart");
173 new_plugins(jcr); /* instantiate plugins for this jcr */
174 generate_plugin_event(jcr, bDirEventJobStart);
176 if (job_canceled(jcr)) {
180 if (jcr->JobReads() && !jcr->rstorage) {
181 if (jcr->job->storage) {
182 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
184 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
187 if (!jcr->JobReads()) {
192 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
193 * this allows us to setup a proper job start record for restarting
194 * in case of later errors.
196 switch (jcr->getJobType()) {
198 if (!do_backup_init(jcr)) {
199 backup_cleanup(jcr, JS_ErrorTerminated);
204 if (!do_verify_init(jcr)) {
205 verify_cleanup(jcr, JS_ErrorTerminated);
210 if (!do_restore_init(jcr)) {
211 restore_cleanup(jcr, JS_ErrorTerminated);
216 if (!do_admin_init(jcr)) {
217 admin_cleanup(jcr, JS_ErrorTerminated);
223 if (!do_mac_init(jcr)) {
224 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
229 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
230 jcr->setJobStatus(JS_ErrorTerminated);
234 generate_plugin_event(jcr, bDirEventJobInit);
243 * Setup a job for a resume command
245 static bool setup_resume_job(JCR *jcr, JOB_DBR *jr)
250 init_msg(jcr, jcr->messages);
252 /* Initialize termination condition variable */
253 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
255 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
259 jcr->term_wait_inited = true;
261 jcr->setJobStatus(JS_Created);
267 Dmsg0(100, "Open database\n");
268 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
269 jcr->catalog->db_user, jcr->catalog->db_password,
270 jcr->catalog->db_address, jcr->catalog->db_port,
271 jcr->catalog->db_socket, jcr->catalog->db_ssl_mode,
272 jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert,
273 jcr->catalog->db_ssl_ca, jcr->catalog->db_ssl_capath,
274 jcr->catalog->db_ssl_cipher,
275 jcr->catalog->mult_db_connections,
276 jcr->catalog->disable_batch_insert);
277 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
278 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
279 jcr->catalog->db_name);
281 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
282 db_close_database(jcr, jcr->db);
287 Dmsg0(100, "DB opened\n");
289 jcr->fname = get_pool_memory(PM_FNAME);
291 if (!jcr->pool_source) {
292 jcr->pool_source = get_pool_memory(PM_MESSAGE);
293 pm_strcpy(jcr->pool_source, _("unknown source"));
295 if (!jcr->next_pool_source) {
296 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
297 pm_strcpy(jcr->next_pool_source, _("unknown source"));
302 * Setup Job record. Make sure original job is Incomplete.
304 memcpy(&jcr->jr, jr, sizeof(JOB_DBR));
305 jcr->sched_time = jcr->jr.SchedTime;
306 jcr->start_time = jcr->jr.StartTime;
307 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
308 jcr->setJobType(jcr->jr.JobType);
309 jcr->setJobLevel(jcr->jr.JobLevel);
310 jcr->JobId = jcr->jr.JobId;
311 if (!get_or_create_client_record(jcr)) {
312 Dmsg0(100, "Could not create client record.\n");
316 Dmsg6(100, "Got job record JobId=%d Job=%s Name=%s Type=%c Level=%c Status=%c\n",
317 jcr->jr.JobId, jcr->jr.Job, jcr->jr.Name, jcr->jr.JobType, jcr->jr.JobLevel,
319 if (jcr->jr.JobStatus != JS_Incomplete) {
320 /* ***FIXME*** add error message */
321 Dmsg1(100, "Job is not an Incomplete: status=%c\n", jcr->jr.JobStatus);
324 bstrncpy(jcr->Job, jcr->jr.Job, sizeof(jcr->Job));
325 jcr->setJobType(jcr->jr.JobType);
326 jcr->setJobLevel(jcr->jr.JobLevel);
328 generate_daemon_event(jcr, "JobStart");
329 new_plugins(jcr); /* instantiate plugins for this jcr */
330 generate_plugin_event(jcr, bDirEventJobStart);
332 if (job_canceled(jcr)) {
333 Dmsg0(100, "Oops. Job canceled\n");
337 /* Re-run the old job */
338 jcr->rerunning = true;
341 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
342 * this allows us to setup a proper job start record for restarting
343 * in case of later errors.
345 switch (jcr->getJobType()) {
347 if (!do_backup_init(jcr)) {
348 backup_cleanup(jcr, JS_ErrorTerminated);
353 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
354 jcr->setJobStatus(JS_ErrorTerminated);
358 generate_plugin_event(jcr, bDirEventJobInit);
366 JobId_t resume_job(JCR *jcr, JOB_DBR *jr)
369 if (setup_resume_job(jcr, jr)) {
370 Dmsg0(200, "Add jrc to work queue\n");
371 /* Queue the job to be run */
372 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
374 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
384 void update_job_end(JCR *jcr, int TermCode)
386 dequeue_messages(jcr); /* display any queued messages */
387 jcr->setJobStatus(TermCode);
388 update_job_end_record(jcr);
392 * This is the engine called by jobq.c:jobq_add() when we were pulled
393 * from the work queue.
394 * At this point, we are running in our own thread and all
395 * necessary resources are allocated -- see jobq.c
397 static void *job_thread(void *arg)
399 JCR *jcr = (JCR *)arg;
401 pthread_detach(pthread_self());
404 Dmsg0(200, "=====Start Job=========\n");
405 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
406 jcr->start_time = time(NULL); /* set the real start time */
407 jcr->jr.StartTime = jcr->start_time;
409 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
410 (utime_t)(jcr->start_time - jcr->sched_time)) {
411 jcr->setJobStatus(JS_Canceled);
412 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
415 if (job_check_maxrunschedtime(jcr)) {
416 jcr->setJobStatus(JS_Canceled);
417 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
420 /* TODO : check if it is used somewhere */
421 if (jcr->job->RunScripts == NULL) {
422 Dmsg0(200, "Warning, job->RunScripts is empty\n");
423 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
426 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
427 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
430 /* Run any script BeforeJob on dird */
431 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
434 * We re-update the job start record so that the start
435 * time is set after the run before job. This avoids
436 * that any files created by the run before job will
437 * be saved twice. They will be backed up in the current
438 * job, but not in the next one unless they are changed.
439 * Without this, they will be backed up in this job and
440 * in the next job run because in that case, their date
441 * is after the start of this run.
443 jcr->start_time = time(NULL);
444 jcr->jr.StartTime = jcr->start_time;
445 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
446 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
448 generate_plugin_event(jcr, bDirEventJobRun);
450 switch (jcr->getJobType()) {
452 if (!job_canceled(jcr) && do_backup(jcr)) {
455 backup_cleanup(jcr, JS_ErrorTerminated);
459 if (!job_canceled(jcr) && do_verify(jcr)) {
462 verify_cleanup(jcr, JS_ErrorTerminated);
466 if (!job_canceled(jcr) && do_restore(jcr)) {
469 restore_cleanup(jcr, JS_ErrorTerminated);
473 if (!job_canceled(jcr) && do_admin(jcr)) {
476 admin_cleanup(jcr, JS_ErrorTerminated);
481 if (!job_canceled(jcr) && do_mac(jcr)) {
484 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
488 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
492 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
494 /* Send off any queued messages */
495 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
496 dequeue_messages(jcr);
499 generate_daemon_event(jcr, "JobEnd");
500 generate_plugin_event(jcr, bDirEventJobEnd);
501 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
506 void sd_msg_thread_send_signal(JCR *jcr, int sig)
509 if ( !jcr->sd_msg_thread_done
510 && jcr->SD_msg_chan_started
511 && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
513 Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
514 pthread_kill(jcr->SD_msg_chan, sig);
519 static bool cancel_file_daemon_job(UAContext *ua, const char *cmd, JCR *jcr)
524 Dmsg0(100, "No client to cancel\n");
527 old_client = ua->jcr->client;
528 ua->jcr->client = jcr->client;
529 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
530 ua->error_msg(_("Failed to connect to File daemon.\n"));
531 ua->jcr->client = old_client;
534 Dmsg3(10, "Connected to file daemon %s for cancel ua.jcr=%p jcr=%p\n",
535 ua->jcr->client->name(), ua->jcr, jcr);
536 BSOCK *fd = ua->jcr->file_bsock;
537 fd->fsend("%s Job=%s\n", cmd, jcr->Job);
538 while (fd->recv() >= 0) {
539 ua->send_msg("%s", fd->msg);
541 fd->signal(BNET_TERMINATE);
542 free_bsock(ua->jcr->file_bsock);
543 ua->jcr->client = old_client;
547 static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
549 if (jcr->store_bsock) {
551 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
553 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
558 store.store = jcr->rstore;
560 store.store = jcr->wstore;
562 set_wstorage(ua->jcr, &store);
565 if (!ua->jcr->wstore) {
566 ua->error_msg(_("Failed to select Storage daemon.\n"));
570 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
571 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
575 Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
576 ua->jcr->wstore->name(), ua->jcr, jcr);
578 BSOCK *sd = ua->jcr->store_bsock;
579 sd->fsend("%s Job=%s\n", cmd, jcr->Job);
580 while (sd->recv() >= 0) {
581 ua->send_msg("%s", sd->msg);
583 sd->signal(BNET_TERMINATE);
584 free_bsock(ua->jcr->store_bsock);
588 /* The FD is not connected, so we try to complete JCR fields and send
589 * the cancel command.
591 int cancel_inactive_job(UAContext *ua)
598 JCR *jcr = new_jcr(sizeof(JCR), dird_free_jcr);
600 memset(&jr, 0, sizeof(jr));
601 memset(&cr, 0, sizeof(cr));
603 if ((i = find_arg_with_value(ua, "jobid")) > 0) {
604 jr.JobId = str_to_int64(ua->argv[i]);
606 } else if ((i = find_arg_with_value(ua, "ujobid")) > 0) {
607 bstrncpy(jr.Job, ua->argv[i], sizeof(jr.Job));
610 ua->error_msg(_("jobid/ujobid argument not found.\n"));
614 if (!open_client_db(ua)) {
618 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
619 ua->error_msg(_("Job %ld/%s not found in database.\n"), jr.JobId, jr.Job);
623 if (!acl_access_ok(ua, Job_ACL, jr.Name)) {
624 ua->error_msg(_("Job %s is not accessible from this console\n"), jr.Name);
628 cr.ClientId = jr.ClientId;
629 if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
630 ua->error_msg(_("Client %ld not found in database.\n"), jr.ClientId);
634 if (acl_access_client_ok(ua, cr.Name, jr.JobType)) {
635 client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
637 jcr->client = client;
639 Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
646 jcr->JobId = jr.JobId;
647 bstrncpy(jcr->Job, jr.Job, sizeof(jcr->Job));
649 cancel_file_daemon_job(ua, "cancel", jcr);
651 /* At this time, we can't really guess the storage name from
654 store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
659 set_wstorage(jcr, &store);
660 cancel_sd_job(ua, "cancel", jcr);
669 * Cancel a job -- typically called by the UA (Console program), but may also
670 * be called by the job watchdog.
672 * Returns: true if cancel appears to be successful
673 * false on failure. Message sent to ua->jcr.
676 cancel_job(UAContext *ua, JCR *jcr, int wait, bool cancel)
679 int32_t old_status = jcr->JobStatus;
681 const char *reason, *cmd;
683 if (!cancel) { /* stop the job */
684 if (!jcr->can_be_stopped()) {
685 ua->error_msg(_("Cannot stop JobId %s, Job %s is not a regular Backup Job\n"),
686 edit_uint64(jcr->JobId, ed1), jcr->Job);
692 status = JS_Canceled;
693 reason = _("canceled");
696 status = JS_Incomplete;
697 reason = _("stopped");
699 jcr->RescheduleIncompleteJobs = false; /* do not restart */
702 jcr->setJobStatus(status);
704 switch (old_status) {
707 case JS_WaitClientRes:
708 case JS_WaitStoreRes:
709 case JS_WaitPriority:
711 case JS_WaitStartTime:
713 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
714 edit_uint64(jcr->JobId, ed1), jcr->Job,
716 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
721 /* Cancel File daemon */
722 if (jcr->file_bsock) {
724 /* do not return now, we want to try to cancel the sd */
725 tid = start_bsock_timer(jcr->file_bsock, 120);
726 cancel_file_daemon_job(ua, cmd, jcr);
727 stop_bsock_timer(tid);
730 /* We test file_bsock because the previous operation can take
733 if (jcr->file_bsock && cancel) {
734 jcr->file_bsock->set_terminated();
735 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
738 /* Cancel Storage daemon */
739 if (jcr->store_bsock) {
741 /* do not return now, we want to try to cancel the sd socket */
742 tid = start_bsock_timer(jcr->store_bsock, 120);
743 cancel_sd_job(ua, cmd, jcr);
744 stop_bsock_timer(tid);
747 /* We test file_bsock because the previous operation can take
750 if (jcr->store_bsock && cancel) {
751 jcr->store_bsock->set_timed_out();
752 jcr->store_bsock->set_terminated();
753 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
754 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
757 /* Cancel Copy/Migration Storage daemon */
759 /* The wjcr is valid until we call free_jcr(jcr) */
760 JCR *wjcr = jcr->wjcr;
762 if (wjcr->store_bsock) {
764 /* do not return now, we want to try to cancel the sd socket */
765 tid = start_bsock_timer(wjcr->store_bsock, 120);
766 cancel_sd_job(ua, cmd, wjcr);
767 stop_bsock_timer(tid);
769 /* We test store_bsock because the previous operation can take
772 if (wjcr->store_bsock && cancel) {
773 wjcr->store_bsock->set_timed_out();
774 wjcr->store_bsock->set_terminated();
775 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
776 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
785 void cancel_storage_daemon_job(JCR *jcr)
787 if (jcr->sd_canceled) {
788 return; /* cancel only once */
791 UAContext *ua = new_ua_context(jcr);
792 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
795 ua->jcr = control_jcr;
796 if (jcr->store_bsock) {
797 if (!ua->jcr->wstorage) {
799 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
801 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
806 store.store = jcr->rstore;
808 store.store = jcr->wstore;
810 set_wstorage(ua->jcr, &store);
813 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
816 Dmsg0(200, "Connected to storage daemon\n");
817 sd = ua->jcr->store_bsock;
818 sd->fsend("cancel Job=%s\n", jcr->Job);
819 while (sd->recv() >= 0) {
821 sd->signal(BNET_TERMINATE);
822 free_bsock(ua->jcr->store_bsock);
823 jcr->sd_canceled = true;
824 jcr->store_bsock->set_timed_out();
825 jcr->store_bsock->set_terminated();
826 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
827 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
830 free_jcr(control_jcr);
834 static void job_monitor_destructor(watchdog_t *self)
836 JCR *control_jcr = (JCR *)self->data;
838 free_jcr(control_jcr);
841 extern "C" void *cancel_thread(void *arg)
843 JCR *jcr = (JCR *)arg;
847 pthread_detach(pthread_self());
848 ua = new_ua_context(jcr);
849 control_jcr = new_control_jcr("*CancelThread*", JT_SYSTEM);
850 ua->jcr = control_jcr;
852 Dmsg3(400, "Cancelling JCR %p JobId=%d (%s)\n", jcr, jcr->JobId, jcr->Job);
853 cancel_job(ua, jcr, 120);
854 Dmsg2(400, "Have cancelled JCR %p JobId=%d\n", jcr, jcr->JobId);
857 free_jcr(control_jcr);
862 static void job_monitor_watchdog(watchdog_t *wd)
867 Dmsg1(800, "job_monitor_watchdog %p called\n", wd);
872 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
873 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
877 /* check MaxWaitTime */
878 if (job_check_maxwaittime(jcr)) {
879 jcr->setJobStatus(JS_Canceled);
880 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
882 /* check MaxRunTime */
883 } else if (job_check_maxruntime(jcr)) {
884 jcr->setJobStatus(JS_Canceled);
885 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
887 /* check MaxRunSchedTime */
888 } else if (job_check_maxrunschedtime(jcr)) {
889 jcr->setJobStatus(JS_Canceled);
890 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
897 jcr->inc_use_count();
898 if ((status=pthread_create(&thid, NULL, cancel_thread, (void *)jcr)) != 0) {
900 Jmsg1(jcr, M_WARNING, 0, _("Cannot create cancel thread: ERR=%s\n"), be.bstrerror(status));
905 /* Keep reference counts correct */
910 * Check if the maxwaittime has expired and it is possible
913 static bool job_check_maxwaittime(JCR *jcr)
919 if (!job_waiting(jcr)) {
923 if (jcr->wait_time) {
924 current = watchdog_time - jcr->wait_time;
927 Dmsg2(200, "check maxwaittime %u >= %u\n",
928 current + jcr->wait_time_sum, job->MaxWaitTime);
929 if (job->MaxWaitTime != 0 &&
930 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
938 * Check if maxruntime has expired and if the job can be
941 static bool job_check_maxruntime(JCR *jcr)
947 if (job_canceled(jcr) || !jcr->job_started) {
950 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
951 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
954 run_time = watchdog_time - jcr->start_time;
955 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
956 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
957 job->IncMaxRunTime, job->DiffMaxRunTime);
959 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
960 run_time >= job->FullMaxRunTime) {
961 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
963 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
964 run_time >= job->DiffMaxRunTime) {
965 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
967 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
968 run_time >= job->IncMaxRunTime) {
969 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
971 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
972 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
980 * Check if MaxRunSchedTime has expired and if the job can be
983 static bool job_check_maxrunschedtime(JCR *jcr)
985 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
988 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
989 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
990 jcr, jcr->Job, jcr->MaxRunSchedTime);
998 * Get or create a Pool record with the given name.
999 * Returns: 0 on error
1002 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
1006 memset(&pr, 0, sizeof(pr));
1007 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
1008 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
1010 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
1011 /* Try to create the pool */
1012 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
1013 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
1014 db_strerror(jcr->db));
1017 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
1024 * Check for duplicate jobs.
1025 * Returns: true if current job should continue
1026 * false if current job should terminate
1028 bool allow_duplicate_job(JCR *jcr)
1030 JOB *job = jcr->job;
1031 JCR *djcr; /* possible duplicate job */
1033 /* Is AllowDuplicateJobs is set or is duplicate checking
1034 * disabled for this job? */
1035 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
1038 Dmsg0(800, "Enter allow_duplicate_job\n");
1040 * After this point, we do not want to allow any duplicate
1045 if (jcr == djcr || djcr->is_internal_job() || !djcr->job) {
1046 continue; /* do not cancel this job or consoles */
1048 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1049 * if so do not check it against other jobs */
1050 if (djcr->IgnoreDuplicateJobChecking) {
1053 if ((strcmp(job->name(), djcr->job->name()) == 0) &&
1054 djcr->getJobType() == jcr->getJobType()) /* A duplicate is about the same name and the same type */
1056 bool cancel_dup = false;
1057 bool cancel_me = false;
1058 if (job->DuplicateJobProximity > 0) {
1059 utime_t now = (utime_t)time(NULL);
1060 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1061 continue; /* not really a duplicate */
1064 if (job->CancelLowerLevelDuplicates &&
1065 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1066 switch (jcr->getJobLevel()) {
1068 case L_VIRTUAL_FULL:
1069 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1070 djcr->getJobLevel() == L_INCREMENTAL) {
1074 case L_DIFFERENTIAL:
1075 if (djcr->getJobLevel() == L_INCREMENTAL) {
1078 if (djcr->getJobLevel() == L_FULL) {
1083 if (djcr->getJobLevel() == L_FULL ||
1084 djcr->getJobLevel() == L_DIFFERENTIAL) {
1089 * cancel_dup will be done below
1092 /* Zap current job */
1093 jcr->setJobStatus(JS_Canceled);
1094 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1096 break; /* get out of foreach_jcr */
1099 /* Cancel one of the two jobs (me or dup) */
1100 /* If CancelQueuedDuplicates is set do so only if job is queued */
1101 if (job->CancelQueuedDuplicates) {
1102 switch (djcr->JobStatus) {
1105 case JS_WaitClientRes:
1106 case JS_WaitStoreRes:
1107 case JS_WaitPriority:
1108 case JS_WaitMaxJobs:
1109 case JS_WaitStartTime:
1111 cancel_dup = true; /* cancel queued duplicate */
1117 if (cancel_dup || job->CancelRunningDuplicates) {
1118 /* Zap the duplicated job djcr */
1119 UAContext *ua = new_ua_context(jcr);
1120 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1121 cancel_job(ua, djcr, 60);
1122 bmicrosleep(0, 500000);
1123 djcr->setJobStatus(JS_Canceled);
1124 cancel_job(ua, djcr, 60);
1125 free_ua_context(ua);
1126 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1128 /* Zap current job */
1129 jcr->setJobStatus(JS_Canceled);
1130 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1132 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1134 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1135 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1136 break; /* did our work, get out of foreach loop */
1145 * Apply pool overrides to get the storage properly setup.
1147 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1151 Dmsg1(100, "Original pool=%s\n", opool->name());
1152 if (jcr->cmdline_next_pool_override) {
1153 /* Can be Command line or User input */
1154 source = NPRT(jcr->next_pool_source);
1155 } else if (jcr->run_next_pool_override) {
1156 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1157 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1158 source = _("Run NextPool override");
1159 } else if (jcr->job->next_pool) {
1160 /* Use Job Next Pool */
1161 jcr->next_pool = jcr->job->next_pool;
1162 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1163 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1164 source = _("Job's NextPool resource");
1166 /* Default to original pool->NextPool */
1167 jcr->next_pool = opool->NextPool;
1168 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1169 if (jcr->next_pool) {
1170 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1172 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1173 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1174 source = _("Pool's NextPool resource");
1178 * If the original backup pool has a NextPool, make sure a
1179 * record exists in the database.
1181 if (jcr->next_pool) {
1182 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1183 if (jcr->jr.PoolId == 0) {
1188 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1192 /* Set write pool and source. Not read pool is in rpool. */
1193 jcr->pool = jcr->next_pool;
1194 pm_strcpy(jcr->pool_source, source);
1200 void apply_pool_overrides(JCR *jcr)
1202 bool pool_override = false;
1204 if (jcr->run_pool_override) {
1205 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1208 * Apply any level related Pool selections
1210 switch (jcr->getJobLevel()) {
1212 if (jcr->full_pool) {
1213 jcr->pool = jcr->full_pool;
1214 pool_override = true;
1215 if (jcr->run_full_pool_override) {
1216 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1218 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1222 case L_VIRTUAL_FULL:
1223 if (jcr->vfull_pool) {
1224 jcr->pool = jcr->vfull_pool;
1225 pool_override = true;
1226 if (jcr->run_vfull_pool_override) {
1227 pm_strcpy(jcr->pool_source, _("Run VFullPool override"));
1229 pm_strcpy(jcr->pool_source, _("Job VFullPool override"));
1234 if (jcr->inc_pool) {
1235 jcr->pool = jcr->inc_pool;
1236 pool_override = true;
1237 if (jcr->run_inc_pool_override) {
1238 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1240 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1244 case L_DIFFERENTIAL:
1245 if (jcr->diff_pool) {
1246 jcr->pool = jcr->diff_pool;
1247 pool_override = true;
1248 if (jcr->run_diff_pool_override) {
1249 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1251 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1256 /* Update catalog if pool overridden */
1257 if (pool_override && jcr->pool->catalog) {
1258 jcr->catalog = jcr->pool->catalog;
1259 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1265 * Get or create a Client record for this Job
1267 bool get_or_create_client_record(JCR *jcr)
1272 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1275 memset(&cr, 0, sizeof(cr));
1276 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1277 cr.AutoPrune = jcr->client->AutoPrune;
1278 cr.FileRetention = jcr->client->FileRetention;
1279 cr.JobRetention = jcr->client->JobRetention;
1280 if (!jcr->client_name) {
1281 jcr->client_name = get_pool_memory(PM_NAME);
1283 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1284 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1285 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1286 db_strerror(jcr->db));
1289 jcr->jr.ClientId = cr.ClientId;
1291 if (!jcr->client_uname) {
1292 jcr->client_uname = get_pool_memory(PM_NAME);
1294 pm_strcpy(jcr->client_uname, cr.Uname);
1296 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1302 * Get or Create FileSet record
1304 bool get_or_create_fileset_record(JCR *jcr)
1308 memset(&fsr, 0, sizeof(FILESET_DBR));
1309 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1310 if (jcr->fileset->have_MD5) {
1311 struct MD5Context md5c;
1312 unsigned char digest[MD5HashSize];
1313 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1314 MD5Final(digest, &md5c);
1316 * Keep the flag (last arg) set to false otherwise old FileSets will
1317 * get new MD5 sums and the user will get Full backups on everything
1319 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1320 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1322 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1324 if (!jcr->fileset->ignore_fs_changes ||
1325 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1326 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1327 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1328 fsr.FileSet, db_strerror(jcr->db));
1332 jcr->jr.FileSetId = fsr.FileSetId;
1333 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1334 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1339 void init_jcr_job_record(JCR *jcr)
1341 jcr->jr.SchedTime = jcr->sched_time;
1342 jcr->jr.StartTime = jcr->start_time;
1343 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1344 jcr->jr.JobType = jcr->getJobType();
1345 jcr->jr.JobLevel = jcr->getJobLevel();
1346 jcr->jr.JobStatus = jcr->JobStatus;
1347 jcr->jr.JobId = jcr->JobId;
1348 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1349 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1353 * Write status and such in DB
1355 void update_job_end_record(JCR *jcr)
1357 jcr->jr.EndTime = time(NULL);
1358 jcr->end_time = jcr->jr.EndTime;
1359 jcr->jr.JobId = jcr->JobId;
1360 jcr->jr.JobStatus = jcr->JobStatus;
1361 jcr->jr.JobFiles = jcr->JobFiles;
1362 jcr->jr.JobBytes = jcr->JobBytes;
1363 jcr->jr.ReadBytes = jcr->ReadBytes;
1364 jcr->jr.VolSessionId = jcr->VolSessionId;
1365 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1366 jcr->jr.JobErrors = jcr->JobErrors + jcr->SDErrors;
1367 jcr->jr.HasBase = jcr->HasBase;
1368 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1369 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1370 db_strerror(jcr->db));
1375 * Takes base_name and appends (unique) current
1376 * date and time to form unique job name.
1378 * Note, the seconds are actually a sequence number. This
1379 * permits us to start a maximum fo 59 unique jobs a second, which
1380 * should be sufficient.
1382 * Returns: unique job name in jcr->Job
1383 * date/time in jcr->start_time
1385 void create_unique_job_name(JCR *jcr, const char *base_name)
1387 /* Job start mutex */
1388 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1389 static time_t last_start_time = 0;
1391 time_t now = time(NULL);
1393 char dt[MAX_TIME_LENGTH];
1394 char name[MAX_NAME_LENGTH];
1399 /* Guarantee unique start time -- maximum one per second, and
1400 * thus unique Job Name
1402 P(mutex); /* lock creation of jobs */
1404 if (seq > 59) { /* wrap as if it is seconds */
1406 while (now == last_start_time) {
1407 bmicrosleep(0, 500000);
1411 last_start_time = now;
1413 V(mutex); /* allow creation of jobs */
1414 jcr->start_time = now;
1415 /* Form Unique JobName */
1416 (void)localtime_r(&now, &tm);
1417 /* Use only characters that are permitted in Windows filenames */
1418 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1419 len = strlen(dt) + 5; /* dt + .%02d EOS */
1420 bstrncpy(name, base_name, sizeof(name));
1421 name[sizeof(name)-len] = 0; /* truncate if too long */
1422 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1423 /* Convert spaces into underscores */
1424 for (p=jcr->Job; *p; p++) {
1429 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1432 /* Called directly from job rescheduling */
1433 void dird_free_jcr_pointers(JCR *jcr)
1435 /* Close but do not free bsock packets */
1436 if (jcr->file_bsock) {
1437 Dmsg0(200, "Close File bsock\n");
1438 jcr->file_bsock->close();
1440 if (jcr->store_bsock) {
1441 Dmsg0(200, "Close Store bsock\n");
1442 jcr->store_bsock->close();
1445 bfree_and_null(jcr->sd_auth_key);
1446 bfree_and_null(jcr->where);
1447 bfree_and_null(jcr->RestoreBootstrap);
1448 jcr->cached_attribute = false;
1449 bfree_and_null(jcr->ar);
1451 free_and_null_pool_memory(jcr->JobIds);
1452 free_and_null_pool_memory(jcr->client_uname);
1453 free_and_null_pool_memory(jcr->attr);
1454 free_and_null_pool_memory(jcr->fname);
1455 free_and_null_pool_memory(jcr->media_type);
1459 * Free the Job Control Record if no one is still using it.
1460 * Called from main free_jcr() routine in src/lib/jcr.c so
1461 * that we can do our Director specific cleanup of the jcr.
1463 void dird_free_jcr(JCR *jcr)
1465 Dmsg0(200, "Start dird free_jcr\n");
1467 dird_free_jcr_pointers(jcr);
1468 if (jcr->bsr_list) {
1469 free_bsr(jcr->bsr_list);
1470 jcr->bsr_list = NULL;
1473 free_jcr(jcr->wjcr);
1476 /* Free bsock packets */
1477 free_bsock(jcr->file_bsock);
1478 free_bsock(jcr->store_bsock);
1479 if (jcr->term_wait_inited) {
1480 pthread_cond_destroy(&jcr->term_wait);
1481 jcr->term_wait_inited = false;
1483 if (jcr->db_batch) {
1484 db_close_database(jcr, jcr->db_batch);
1485 jcr->db_batch = NULL;
1486 jcr->batch_started = false;
1489 db_close_database(jcr, jcr->db);
1493 free_and_null_pool_memory(jcr->stime);
1494 free_and_null_pool_memory(jcr->fname);
1495 free_and_null_pool_memory(jcr->pool_source);
1496 free_and_null_pool_memory(jcr->next_pool_source);
1497 free_and_null_pool_memory(jcr->catalog_source);
1498 free_and_null_pool_memory(jcr->rpool_source);
1499 free_and_null_pool_memory(jcr->wstore_source);
1500 free_and_null_pool_memory(jcr->rstore_source);
1501 free_and_null_pool_memory(jcr->next_vol_list);
1502 free_and_null_pool_memory(jcr->component_fname);
1504 /* Delete lists setup to hold storage pointers */
1505 free_rwstorage(jcr);
1507 jcr->job_end_push.destroy();
1509 if (jcr->JobId != 0)
1510 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1512 if (jcr->plugin_config) {
1513 free_plugin_config_items(jcr->plugin_config);
1514 delete jcr->plugin_config;
1515 jcr->plugin_config = NULL;
1517 free_plugins(jcr); /* release instantiated plugins */
1519 garbage_collect_memory_pool();
1521 Dmsg0(200, "End dird free_jcr\n");
1525 * The Job storage definition must be either in the Job record
1526 * or in the Pool record. The Pool record overrides the Job
1529 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1531 if (run && run->pool && run->pool->storage) {
1532 store->store = (STORE *)run->pool->storage->first();
1533 pm_strcpy(store->store_source, _("Run pool override"));
1536 if (run && run->storage) {
1537 store->store = run->storage;
1538 pm_strcpy(store->store_source, _("Run storage override"));
1541 if (job->pool->storage) {
1542 store->store = (STORE *)job->pool->storage->first();
1543 pm_strcpy(store->store_source, _("Pool resource"));
1545 store->store = (STORE *)job->storage->first();
1546 pm_strcpy(store->store_source, _("Job resource"));
1551 * Set some defaults in the JCR necessary to
1552 * run. These items are pulled from the job
1553 * definition as defaults, but can be overridden
1554 * later either by the Run record in the Schedule resource,
1555 * or by the Console program.
1557 void set_jcr_defaults(JCR *jcr, JOB *job)
1560 jcr->setJobType(job->JobType);
1561 jcr->JobStatus = JS_Created;
1563 switch (jcr->getJobType()) {
1565 jcr->setJobLevel(L_NONE);
1568 jcr->setJobLevel(job->JobLevel);
1571 if (!jcr->next_vol_list) {
1572 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1575 jcr->fname = get_pool_memory(PM_FNAME);
1577 if (!jcr->pool_source) {
1578 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1580 if (!jcr->next_pool_source) {
1581 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1583 if (!jcr->catalog_source) {
1584 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1587 jcr->JobPriority = job->Priority;
1588 /* Copy storage definitions -- deleted in dir_free_jcr above */
1590 copy_rwstorage(jcr, job->storage, _("Job resource"));
1592 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1594 jcr->client = job->client;
1595 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1596 if (!jcr->client_name) {
1597 jcr->client_name = get_pool_memory(PM_NAME);
1599 pm_strcpy(jcr->client_name, jcr->client->name());
1600 jcr->pool = job->pool;
1601 pm_strcpy(jcr->pool_source, _("Job resource"));
1602 if (job->next_pool) {
1603 /* Use Job's Next Pool */
1604 jcr->next_pool = job->next_pool;
1605 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1607 /* Default to original pool->NextPool */
1608 jcr->next_pool = job->pool->NextPool;
1609 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1611 jcr->full_pool = job->full_pool;
1612 jcr->vfull_pool = job->vfull_pool;
1613 jcr->inc_pool = job->inc_pool;
1614 jcr->diff_pool = job->diff_pool;
1615 if (job->pool->catalog) {
1616 jcr->catalog = job->pool->catalog;
1617 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1619 jcr->catalog = job->client->catalog;
1620 pm_strcpy(jcr->catalog_source, _("Client resource"));
1622 jcr->fileset = job->fileset;
1623 jcr->accurate = job->accurate;
1624 jcr->messages = job->messages;
1625 jcr->spool_data = job->spool_data;
1626 jcr->spool_size = job->spool_size;
1627 jcr->write_part_after_job = job->write_part_after_job;
1628 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1629 /* This can be overridden by Console program */
1630 bfree_and_null(jcr->RestoreBootstrap);
1631 if (job->RestoreBootstrap) {
1632 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1634 /* This can be overridden by Console program */
1635 jcr->verify_job = job->verify_job;
1636 /* If no default level given, set one */
1637 if (jcr->getJobLevel() == 0) {
1638 switch (jcr->getJobType()) {
1640 jcr->setJobLevel(L_VERIFY_CATALOG);
1643 jcr->setJobLevel(L_INCREMENTAL);
1647 jcr->setJobLevel(L_NONE);
1650 jcr->setJobLevel(L_FULL);
1657 * Copy the storage definitions from an alist to the JCR
1659 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1661 if (jcr->JobReads()) {
1662 copy_rstorage(jcr, storage, where);
1664 copy_wstorage(jcr, storage, where);
1668 /* Set storage override. Releases any previous storage definition */
1669 void set_rwstorage(JCR *jcr, USTORE *store)
1672 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1675 if (jcr->JobReads()) {
1676 set_rstorage(jcr, store);
1678 set_wstorage(jcr, store);
1681 void free_rwstorage(JCR *jcr)
1688 * Copy the storage definitions from an alist to the JCR
1690 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1694 if (jcr->rstorage) {
1695 delete jcr->rstorage;
1697 jcr->rstorage = New(alist(10, not_owned_by_alist));
1698 foreach_alist(st, storage) {
1699 jcr->rstorage->append(st);
1701 if (!jcr->rstore_source) {
1702 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1704 pm_strcpy(jcr->rstore_source, where);
1705 if (jcr->rstorage) {
1706 jcr->rstore = (STORE *)jcr->rstorage->first();
1712 /* Set storage override. Remove all previous storage */
1713 void set_rstorage(JCR *jcr, USTORE *store)
1717 if (!store->store) {
1720 if (jcr->rstorage) {
1723 if (!jcr->rstorage) {
1724 jcr->rstorage = New(alist(10, not_owned_by_alist));
1726 jcr->rstore = store->store;
1727 if (!jcr->rstore_source) {
1728 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1730 pm_strcpy(jcr->rstore_source, store->store_source);
1731 foreach_alist(storage, jcr->rstorage) {
1732 if (store->store == storage) {
1736 /* Store not in list, so add it */
1737 jcr->rstorage->prepend(store->store);
1740 void free_rstorage(JCR *jcr)
1742 if (jcr->rstorage) {
1743 delete jcr->rstorage;
1744 jcr->rstorage = NULL;
1750 * Copy the storage definitions from an alist to the JCR
1752 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1756 if (jcr->wstorage) {
1757 delete jcr->wstorage;
1759 jcr->wstorage = New(alist(10, not_owned_by_alist));
1760 foreach_alist(st, storage) {
1761 Dmsg1(100, "wstorage=%s\n", st->name());
1762 jcr->wstorage->append(st);
1764 if (!jcr->wstore_source) {
1765 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1767 pm_strcpy(jcr->wstore_source, where);
1768 if (jcr->wstorage) {
1769 jcr->wstore = (STORE *)jcr->wstorage->first();
1770 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1776 /* Set storage override. Remove all previous storage */
1777 void set_wstorage(JCR *jcr, USTORE *store)
1781 if (!store->store) {
1784 if (jcr->wstorage) {
1787 if (!jcr->wstorage) {
1788 jcr->wstorage = New(alist(10, not_owned_by_alist));
1790 jcr->wstore = store->store;
1791 if (!jcr->wstore_source) {
1792 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1794 pm_strcpy(jcr->wstore_source, store->store_source);
1795 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1796 foreach_alist(storage, jcr->wstorage) {
1797 if (store->store == storage) {
1801 /* Store not in list, so add it */
1802 jcr->wstorage->prepend(store->store);
1805 void free_wstorage(JCR *jcr)
1807 if (jcr->wstorage) {
1808 delete jcr->wstorage;
1809 jcr->wstorage = NULL;
1814 void create_clones(JCR *jcr)
1817 * Fire off any clone jobs (run directives)
1819 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1820 if (!jcr->cloned && jcr->job->run_cmds) {
1822 JOB *job = jcr->job;
1823 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1824 UAContext *ua = new_ua_context(jcr);
1826 foreach_alist(runcmd, job->run_cmds) {
1827 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1828 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1829 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1830 parse_ua_args(ua); /* parse command */
1831 int stat = run_cmd(ua, ua->cmd);
1833 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1836 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1839 free_ua_context(ua);
1840 free_pool_memory(cmd);
1845 * Given: a JobId and FileIndex
1846 * this subroutine writes a bsr file to restore that job.
1847 * Returns: -1 on error
1848 * number of files if OK
1850 int create_restore_bootstrap_file(JCR *jcr, JobId_t jobid, int findex1, int findex2)
1856 memset(&rx, 0, sizeof(rx));
1857 rx.JobIds = (char *)"";
1859 rx.bsr_list = create_bsr_list(jobid, findex1, findex2);
1861 ua = new_ua_context(jcr);
1862 if (!complete_bsr(ua, rx.bsr_list)) {
1867 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1868 if (jcr->ExpectedFiles == 0) {
1872 free_ua_context(ua);
1873 free_bsr(rx.bsr_list);
1874 jcr->needs_sd = true;
1875 return jcr->ExpectedFiles;
1878 free_ua_context(ua);
1879 free_bsr(rx.bsr_list);
1884 * Given: a JobId in jcr->previous_jr.JobId,
1885 * this subroutine writes a bsr file to restore that job.
1886 * Returns: -1 on error
1887 * number of files if OK
1889 int create_restore_bootstrap_file(JCR *jcr)
1891 return create_restore_bootstrap_file(jcr, jcr->previous_jr.JobId, 1, jcr->previous_jr.JobFiles);
1894 /* TODO: redirect command ouput to job log */
1895 bool run_console_command(JCR *jcr, const char *cmd)
1899 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1900 ua = new_ua_context(ljcr);
1901 /* run from runscript and check if commands are authorized */
1902 ua->runscript = true;
1903 Mmsg(ua->cmd, "%s", cmd);
1904 Dmsg1(100, "Console command: %s\n", ua->cmd);
1906 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1907 ok = do_a_dot_command(ua);
1909 ok = do_a_command(ua);
1912 free_ua_context(ua);