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 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
686 status = JS_Canceled;
687 reason = _("canceled");
690 status = JS_Incomplete;
691 reason = _("stopped");
693 jcr->RescheduleIncompleteJobs = false; /* do not restart */
696 jcr->setJobStatus(status);
698 switch (old_status) {
701 case JS_WaitClientRes:
702 case JS_WaitStoreRes:
703 case JS_WaitPriority:
705 case JS_WaitStartTime:
707 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
708 edit_uint64(jcr->JobId, ed1), jcr->Job,
710 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
715 /* Cancel File daemon */
716 if (jcr->file_bsock) {
718 /* do not return now, we want to try to cancel the sd */
719 tid = start_bsock_timer(jcr->file_bsock, 120);
720 cancel_file_daemon_job(ua, cmd, jcr);
721 stop_bsock_timer(tid);
724 /* We test file_bsock because the previous operation can take
727 if (jcr->file_bsock && cancel) {
728 jcr->file_bsock->set_terminated();
729 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
732 /* Cancel Storage daemon */
733 if (jcr->store_bsock) {
735 /* do not return now, we want to try to cancel the sd socket */
736 tid = start_bsock_timer(jcr->store_bsock, 120);
737 cancel_sd_job(ua, cmd, jcr);
738 stop_bsock_timer(tid);
741 /* We test file_bsock because the previous operation can take
744 if (jcr->store_bsock && cancel) {
745 jcr->store_bsock->set_timed_out();
746 jcr->store_bsock->set_terminated();
747 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
748 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
751 /* Cancel Copy/Migration Storage daemon */
753 /* The wjcr is valid until we call free_jcr(jcr) */
754 JCR *wjcr = jcr->wjcr;
756 if (wjcr->store_bsock) {
758 /* do not return now, we want to try to cancel the sd socket */
759 tid = start_bsock_timer(wjcr->store_bsock, 120);
760 cancel_sd_job(ua, cmd, wjcr);
761 stop_bsock_timer(tid);
763 /* We test store_bsock because the previous operation can take
766 if (wjcr->store_bsock && cancel) {
767 wjcr->store_bsock->set_timed_out();
768 wjcr->store_bsock->set_terminated();
769 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
770 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
779 void cancel_storage_daemon_job(JCR *jcr)
781 if (jcr->sd_canceled) {
782 return; /* cancel only once */
785 UAContext *ua = new_ua_context(jcr);
786 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
789 ua->jcr = control_jcr;
790 if (jcr->store_bsock) {
791 if (!ua->jcr->wstorage) {
793 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
795 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
800 store.store = jcr->rstore;
802 store.store = jcr->wstore;
804 set_wstorage(ua->jcr, &store);
807 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
810 Dmsg0(200, "Connected to storage daemon\n");
811 sd = ua->jcr->store_bsock;
812 sd->fsend("cancel Job=%s\n", jcr->Job);
813 while (sd->recv() >= 0) {
815 sd->signal(BNET_TERMINATE);
816 free_bsock(ua->jcr->store_bsock);
817 jcr->sd_canceled = true;
818 jcr->store_bsock->set_timed_out();
819 jcr->store_bsock->set_terminated();
820 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
821 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
824 free_jcr(control_jcr);
828 static void job_monitor_destructor(watchdog_t *self)
830 JCR *control_jcr = (JCR *)self->data;
832 free_jcr(control_jcr);
835 extern "C" void *cancel_thread(void *arg)
837 JCR *jcr = (JCR *)arg;
841 pthread_detach(pthread_self());
842 ua = new_ua_context(jcr);
843 control_jcr = new_control_jcr("*CancelThread*", JT_SYSTEM);
844 ua->jcr = control_jcr;
846 Dmsg3(400, "Cancelling JCR %p JobId=%d (%s)\n", jcr, jcr->JobId, jcr->Job);
847 cancel_job(ua, jcr, 120);
848 Dmsg2(400, "Have cancelled JCR %p JobId=%d\n", jcr, jcr->JobId);
851 free_jcr(control_jcr);
856 static void job_monitor_watchdog(watchdog_t *wd)
861 Dmsg1(800, "job_monitor_watchdog %p called\n", wd);
866 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
867 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
871 /* check MaxWaitTime */
872 if (job_check_maxwaittime(jcr)) {
873 jcr->setJobStatus(JS_Canceled);
874 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
876 /* check MaxRunTime */
877 } else if (job_check_maxruntime(jcr)) {
878 jcr->setJobStatus(JS_Canceled);
879 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
881 /* check MaxRunSchedTime */
882 } else if (job_check_maxrunschedtime(jcr)) {
883 jcr->setJobStatus(JS_Canceled);
884 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
891 jcr->inc_use_count();
892 if ((status=pthread_create(&thid, NULL, cancel_thread, (void *)jcr)) != 0) {
894 Jmsg1(jcr, M_WARNING, 0, _("Cannot create cancel thread: ERR=%s\n"), be.bstrerror(status));
899 /* Keep reference counts correct */
904 * Check if the maxwaittime has expired and it is possible
907 static bool job_check_maxwaittime(JCR *jcr)
913 if (!job_waiting(jcr)) {
917 if (jcr->wait_time) {
918 current = watchdog_time - jcr->wait_time;
921 Dmsg2(200, "check maxwaittime %u >= %u\n",
922 current + jcr->wait_time_sum, job->MaxWaitTime);
923 if (job->MaxWaitTime != 0 &&
924 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
932 * Check if maxruntime has expired and if the job can be
935 static bool job_check_maxruntime(JCR *jcr)
941 if (job_canceled(jcr) || !jcr->job_started) {
944 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
945 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
948 run_time = watchdog_time - jcr->start_time;
949 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
950 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
951 job->IncMaxRunTime, job->DiffMaxRunTime);
953 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
954 run_time >= job->FullMaxRunTime) {
955 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
957 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
958 run_time >= job->DiffMaxRunTime) {
959 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
961 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
962 run_time >= job->IncMaxRunTime) {
963 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
965 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
966 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
974 * Check if MaxRunSchedTime has expired and if the job can be
977 static bool job_check_maxrunschedtime(JCR *jcr)
979 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
982 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
983 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
984 jcr, jcr->Job, jcr->MaxRunSchedTime);
992 * Get or create a Pool record with the given name.
993 * Returns: 0 on error
996 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
1000 memset(&pr, 0, sizeof(pr));
1001 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
1002 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
1004 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
1005 /* Try to create the pool */
1006 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
1007 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
1008 db_strerror(jcr->db));
1011 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
1018 * Check for duplicate jobs.
1019 * Returns: true if current job should continue
1020 * false if current job should terminate
1022 bool allow_duplicate_job(JCR *jcr)
1024 JOB *job = jcr->job;
1025 JCR *djcr; /* possible duplicate job */
1027 /* Is AllowDuplicateJobs is set or is duplicate checking
1028 * disabled for this job? */
1029 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
1032 Dmsg0(800, "Enter allow_duplicate_job\n");
1034 * After this point, we do not want to allow any duplicate
1039 if (jcr == djcr || djcr->is_internal_job() || !djcr->job) {
1040 continue; /* do not cancel this job or consoles */
1042 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1043 * if so do not check it against other jobs */
1044 if (djcr->IgnoreDuplicateJobChecking) {
1047 if ((strcmp(job->name(), djcr->job->name()) == 0) &&
1048 djcr->getJobType() == jcr->getJobType()) /* A duplicate is about the same name and the same type */
1050 bool cancel_dup = false;
1051 bool cancel_me = false;
1052 if (job->DuplicateJobProximity > 0) {
1053 utime_t now = (utime_t)time(NULL);
1054 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1055 continue; /* not really a duplicate */
1058 if (job->CancelLowerLevelDuplicates &&
1059 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1060 switch (jcr->getJobLevel()) {
1062 case L_VIRTUAL_FULL:
1063 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1064 djcr->getJobLevel() == L_INCREMENTAL) {
1068 case L_DIFFERENTIAL:
1069 if (djcr->getJobLevel() == L_INCREMENTAL) {
1072 if (djcr->getJobLevel() == L_FULL) {
1077 if (djcr->getJobLevel() == L_FULL ||
1078 djcr->getJobLevel() == L_DIFFERENTIAL) {
1083 * cancel_dup will be done below
1086 /* Zap current job */
1087 jcr->setJobStatus(JS_Canceled);
1088 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1090 break; /* get out of foreach_jcr */
1093 /* Cancel one of the two jobs (me or dup) */
1094 /* If CancelQueuedDuplicates is set do so only if job is queued */
1095 if (job->CancelQueuedDuplicates) {
1096 switch (djcr->JobStatus) {
1099 case JS_WaitClientRes:
1100 case JS_WaitStoreRes:
1101 case JS_WaitPriority:
1102 case JS_WaitMaxJobs:
1103 case JS_WaitStartTime:
1105 cancel_dup = true; /* cancel queued duplicate */
1111 if (cancel_dup || job->CancelRunningDuplicates) {
1112 /* Zap the duplicated job djcr */
1113 UAContext *ua = new_ua_context(jcr);
1114 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1115 cancel_job(ua, djcr, 60);
1116 bmicrosleep(0, 500000);
1117 djcr->setJobStatus(JS_Canceled);
1118 cancel_job(ua, djcr, 60);
1119 free_ua_context(ua);
1120 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1122 /* Zap current job */
1123 jcr->setJobStatus(JS_Canceled);
1124 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1126 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1128 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1129 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1130 break; /* did our work, get out of foreach loop */
1139 * Apply pool overrides to get the storage properly setup.
1141 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1145 Dmsg1(100, "Original pool=%s\n", opool->name());
1146 if (jcr->cmdline_next_pool_override) {
1147 /* Can be Command line or User input */
1148 source = NPRT(jcr->next_pool_source);
1149 } else if (jcr->run_next_pool_override) {
1150 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1151 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1152 source = _("Run NextPool override");
1153 } else if (jcr->job->next_pool) {
1154 /* Use Job Next Pool */
1155 jcr->next_pool = jcr->job->next_pool;
1156 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1157 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1158 source = _("Job's NextPool resource");
1160 /* Default to original pool->NextPool */
1161 jcr->next_pool = opool->NextPool;
1162 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1163 if (jcr->next_pool) {
1164 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1166 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1167 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1168 source = _("Pool's NextPool resource");
1172 * If the original backup pool has a NextPool, make sure a
1173 * record exists in the database.
1175 if (jcr->next_pool) {
1176 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1177 if (jcr->jr.PoolId == 0) {
1182 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1186 /* Set write pool and source. Not read pool is in rpool. */
1187 jcr->pool = jcr->next_pool;
1188 pm_strcpy(jcr->pool_source, source);
1194 void apply_pool_overrides(JCR *jcr)
1196 bool pool_override = false;
1198 if (jcr->run_pool_override) {
1199 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1202 * Apply any level related Pool selections
1204 switch (jcr->getJobLevel()) {
1206 if (jcr->full_pool) {
1207 jcr->pool = jcr->full_pool;
1208 pool_override = true;
1209 if (jcr->run_full_pool_override) {
1210 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1212 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1216 case L_VIRTUAL_FULL:
1217 if (jcr->vfull_pool) {
1218 jcr->pool = jcr->vfull_pool;
1219 pool_override = true;
1220 if (jcr->run_vfull_pool_override) {
1221 pm_strcpy(jcr->pool_source, _("Run VFullPool override"));
1223 pm_strcpy(jcr->pool_source, _("Job VFullPool override"));
1228 if (jcr->inc_pool) {
1229 jcr->pool = jcr->inc_pool;
1230 pool_override = true;
1231 if (jcr->run_inc_pool_override) {
1232 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1234 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1238 case L_DIFFERENTIAL:
1239 if (jcr->diff_pool) {
1240 jcr->pool = jcr->diff_pool;
1241 pool_override = true;
1242 if (jcr->run_diff_pool_override) {
1243 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1245 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1250 /* Update catalog if pool overridden */
1251 if (pool_override && jcr->pool->catalog) {
1252 jcr->catalog = jcr->pool->catalog;
1253 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1259 * Get or create a Client record for this Job
1261 bool get_or_create_client_record(JCR *jcr)
1266 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1269 memset(&cr, 0, sizeof(cr));
1270 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1271 cr.AutoPrune = jcr->client->AutoPrune;
1272 cr.FileRetention = jcr->client->FileRetention;
1273 cr.JobRetention = jcr->client->JobRetention;
1274 if (!jcr->client_name) {
1275 jcr->client_name = get_pool_memory(PM_NAME);
1277 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1278 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1279 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1280 db_strerror(jcr->db));
1283 jcr->jr.ClientId = cr.ClientId;
1285 if (!jcr->client_uname) {
1286 jcr->client_uname = get_pool_memory(PM_NAME);
1288 pm_strcpy(jcr->client_uname, cr.Uname);
1290 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1296 * Get or Create FileSet record
1298 bool get_or_create_fileset_record(JCR *jcr)
1302 memset(&fsr, 0, sizeof(FILESET_DBR));
1303 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1304 if (jcr->fileset->have_MD5) {
1305 struct MD5Context md5c;
1306 unsigned char digest[MD5HashSize];
1307 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1308 MD5Final(digest, &md5c);
1310 * Keep the flag (last arg) set to false otherwise old FileSets will
1311 * get new MD5 sums and the user will get Full backups on everything
1313 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1314 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1316 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1318 if (!jcr->fileset->ignore_fs_changes ||
1319 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1320 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1321 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1322 fsr.FileSet, db_strerror(jcr->db));
1326 jcr->jr.FileSetId = fsr.FileSetId;
1327 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1328 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1333 void init_jcr_job_record(JCR *jcr)
1335 jcr->jr.SchedTime = jcr->sched_time;
1336 jcr->jr.StartTime = jcr->start_time;
1337 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1338 jcr->jr.JobType = jcr->getJobType();
1339 jcr->jr.JobLevel = jcr->getJobLevel();
1340 jcr->jr.JobStatus = jcr->JobStatus;
1341 jcr->jr.JobId = jcr->JobId;
1342 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1343 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1347 * Write status and such in DB
1349 void update_job_end_record(JCR *jcr)
1351 jcr->jr.EndTime = time(NULL);
1352 jcr->end_time = jcr->jr.EndTime;
1353 jcr->jr.JobId = jcr->JobId;
1354 jcr->jr.JobStatus = jcr->JobStatus;
1355 jcr->jr.JobFiles = jcr->JobFiles;
1356 jcr->jr.JobBytes = jcr->JobBytes;
1357 jcr->jr.ReadBytes = jcr->ReadBytes;
1358 jcr->jr.VolSessionId = jcr->VolSessionId;
1359 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1360 jcr->jr.JobErrors = jcr->JobErrors + jcr->SDErrors;
1361 jcr->jr.HasBase = jcr->HasBase;
1362 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1363 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1364 db_strerror(jcr->db));
1369 * Takes base_name and appends (unique) current
1370 * date and time to form unique job name.
1372 * Note, the seconds are actually a sequence number. This
1373 * permits us to start a maximum fo 59 unique jobs a second, which
1374 * should be sufficient.
1376 * Returns: unique job name in jcr->Job
1377 * date/time in jcr->start_time
1379 void create_unique_job_name(JCR *jcr, const char *base_name)
1381 /* Job start mutex */
1382 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1383 static time_t last_start_time = 0;
1385 time_t now = time(NULL);
1387 char dt[MAX_TIME_LENGTH];
1388 char name[MAX_NAME_LENGTH];
1393 /* Guarantee unique start time -- maximum one per second, and
1394 * thus unique Job Name
1396 P(mutex); /* lock creation of jobs */
1398 if (seq > 59) { /* wrap as if it is seconds */
1400 while (now == last_start_time) {
1401 bmicrosleep(0, 500000);
1405 last_start_time = now;
1407 V(mutex); /* allow creation of jobs */
1408 jcr->start_time = now;
1409 /* Form Unique JobName */
1410 (void)localtime_r(&now, &tm);
1411 /* Use only characters that are permitted in Windows filenames */
1412 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1413 len = strlen(dt) + 5; /* dt + .%02d EOS */
1414 bstrncpy(name, base_name, sizeof(name));
1415 name[sizeof(name)-len] = 0; /* truncate if too long */
1416 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1417 /* Convert spaces into underscores */
1418 for (p=jcr->Job; *p; p++) {
1423 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1426 /* Called directly from job rescheduling */
1427 void dird_free_jcr_pointers(JCR *jcr)
1429 /* Close but do not free bsock packets */
1430 if (jcr->file_bsock) {
1431 Dmsg0(200, "Close File bsock\n");
1432 jcr->file_bsock->close();
1434 if (jcr->store_bsock) {
1435 Dmsg0(200, "Close Store bsock\n");
1436 jcr->store_bsock->close();
1439 bfree_and_null(jcr->sd_auth_key);
1440 bfree_and_null(jcr->where);
1441 bfree_and_null(jcr->RestoreBootstrap);
1442 jcr->cached_attribute = false;
1443 bfree_and_null(jcr->ar);
1445 free_and_null_pool_memory(jcr->JobIds);
1446 free_and_null_pool_memory(jcr->client_uname);
1447 free_and_null_pool_memory(jcr->attr);
1448 free_and_null_pool_memory(jcr->fname);
1449 free_and_null_pool_memory(jcr->media_type);
1453 * Free the Job Control Record if no one is still using it.
1454 * Called from main free_jcr() routine in src/lib/jcr.c so
1455 * that we can do our Director specific cleanup of the jcr.
1457 void dird_free_jcr(JCR *jcr)
1459 Dmsg0(200, "Start dird free_jcr\n");
1461 dird_free_jcr_pointers(jcr);
1463 free_jcr(jcr->wjcr);
1466 /* Free bsock packets */
1467 free_bsock(jcr->file_bsock);
1468 free_bsock(jcr->store_bsock);
1469 if (jcr->term_wait_inited) {
1470 pthread_cond_destroy(&jcr->term_wait);
1471 jcr->term_wait_inited = false;
1473 if (jcr->db_batch) {
1474 db_close_database(jcr, jcr->db_batch);
1475 jcr->db_batch = NULL;
1476 jcr->batch_started = false;
1479 db_close_database(jcr, jcr->db);
1483 free_and_null_pool_memory(jcr->stime);
1484 free_and_null_pool_memory(jcr->fname);
1485 free_and_null_pool_memory(jcr->pool_source);
1486 free_and_null_pool_memory(jcr->next_pool_source);
1487 free_and_null_pool_memory(jcr->catalog_source);
1488 free_and_null_pool_memory(jcr->rpool_source);
1489 free_and_null_pool_memory(jcr->wstore_source);
1490 free_and_null_pool_memory(jcr->rstore_source);
1491 free_and_null_pool_memory(jcr->next_vol_list);
1492 free_and_null_pool_memory(jcr->component_fname);
1494 /* Delete lists setup to hold storage pointers */
1495 free_rwstorage(jcr);
1497 jcr->job_end_push.destroy();
1499 if (jcr->JobId != 0)
1500 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1502 if (jcr->plugin_config) {
1503 free_plugin_config_items(jcr->plugin_config);
1504 delete jcr->plugin_config;
1505 jcr->plugin_config = NULL;
1507 free_plugins(jcr); /* release instantiated plugins */
1509 garbage_collect_memory_pool();
1511 Dmsg0(200, "End dird free_jcr\n");
1515 * The Job storage definition must be either in the Job record
1516 * or in the Pool record. The Pool record overrides the Job
1519 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1521 if (run && run->pool && run->pool->storage) {
1522 store->store = (STORE *)run->pool->storage->first();
1523 pm_strcpy(store->store_source, _("Run pool override"));
1526 if (run && run->storage) {
1527 store->store = run->storage;
1528 pm_strcpy(store->store_source, _("Run storage override"));
1531 if (job->pool->storage) {
1532 store->store = (STORE *)job->pool->storage->first();
1533 pm_strcpy(store->store_source, _("Pool resource"));
1535 store->store = (STORE *)job->storage->first();
1536 pm_strcpy(store->store_source, _("Job resource"));
1541 * Set some defaults in the JCR necessary to
1542 * run. These items are pulled from the job
1543 * definition as defaults, but can be overridden
1544 * later either by the Run record in the Schedule resource,
1545 * or by the Console program.
1547 void set_jcr_defaults(JCR *jcr, JOB *job)
1550 jcr->setJobType(job->JobType);
1551 jcr->JobStatus = JS_Created;
1553 switch (jcr->getJobType()) {
1555 jcr->setJobLevel(L_NONE);
1558 jcr->setJobLevel(job->JobLevel);
1561 if (!jcr->next_vol_list) {
1562 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1565 jcr->fname = get_pool_memory(PM_FNAME);
1567 if (!jcr->pool_source) {
1568 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1570 if (!jcr->next_pool_source) {
1571 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1573 if (!jcr->catalog_source) {
1574 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1577 jcr->JobPriority = job->Priority;
1578 /* Copy storage definitions -- deleted in dir_free_jcr above */
1580 copy_rwstorage(jcr, job->storage, _("Job resource"));
1582 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1584 jcr->client = job->client;
1585 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1586 if (!jcr->client_name) {
1587 jcr->client_name = get_pool_memory(PM_NAME);
1589 pm_strcpy(jcr->client_name, jcr->client->name());
1590 jcr->pool = job->pool;
1591 pm_strcpy(jcr->pool_source, _("Job resource"));
1592 if (job->next_pool) {
1593 /* Use Job's Next Pool */
1594 jcr->next_pool = job->next_pool;
1595 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1597 /* Default to original pool->NextPool */
1598 jcr->next_pool = job->pool->NextPool;
1599 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1601 jcr->full_pool = job->full_pool;
1602 jcr->vfull_pool = job->vfull_pool;
1603 jcr->inc_pool = job->inc_pool;
1604 jcr->diff_pool = job->diff_pool;
1605 if (job->pool->catalog) {
1606 jcr->catalog = job->pool->catalog;
1607 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1609 jcr->catalog = job->client->catalog;
1610 pm_strcpy(jcr->catalog_source, _("Client resource"));
1612 jcr->fileset = job->fileset;
1613 jcr->accurate = job->accurate;
1614 jcr->messages = job->messages;
1615 jcr->spool_data = job->spool_data;
1616 jcr->spool_size = job->spool_size;
1617 jcr->write_part_after_job = job->write_part_after_job;
1618 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1619 if (jcr->RestoreBootstrap) {
1620 free(jcr->RestoreBootstrap);
1621 jcr->RestoreBootstrap = NULL;
1623 /* This can be overridden by Console program */
1624 if (job->RestoreBootstrap) {
1625 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1627 /* This can be overridden by Console program */
1628 jcr->verify_job = job->verify_job;
1629 /* If no default level given, set one */
1630 if (jcr->getJobLevel() == 0) {
1631 switch (jcr->getJobType()) {
1633 jcr->setJobLevel(L_VERIFY_CATALOG);
1636 jcr->setJobLevel(L_INCREMENTAL);
1640 jcr->setJobLevel(L_NONE);
1643 jcr->setJobLevel(L_FULL);
1650 * Copy the storage definitions from an alist to the JCR
1652 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1654 if (jcr->JobReads()) {
1655 copy_rstorage(jcr, storage, where);
1657 copy_wstorage(jcr, storage, where);
1661 /* Set storage override. Releases any previous storage definition */
1662 void set_rwstorage(JCR *jcr, USTORE *store)
1665 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1668 if (jcr->JobReads()) {
1669 set_rstorage(jcr, store);
1671 set_wstorage(jcr, store);
1674 void free_rwstorage(JCR *jcr)
1681 * Copy the storage definitions from an alist to the JCR
1683 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1687 if (jcr->rstorage) {
1688 delete jcr->rstorage;
1690 jcr->rstorage = New(alist(10, not_owned_by_alist));
1691 foreach_alist(st, storage) {
1692 jcr->rstorage->append(st);
1694 if (!jcr->rstore_source) {
1695 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1697 pm_strcpy(jcr->rstore_source, where);
1698 if (jcr->rstorage) {
1699 jcr->rstore = (STORE *)jcr->rstorage->first();
1705 /* Set storage override. Remove all previous storage */
1706 void set_rstorage(JCR *jcr, USTORE *store)
1710 if (!store->store) {
1713 if (jcr->rstorage) {
1716 if (!jcr->rstorage) {
1717 jcr->rstorage = New(alist(10, not_owned_by_alist));
1719 jcr->rstore = store->store;
1720 if (!jcr->rstore_source) {
1721 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1723 pm_strcpy(jcr->rstore_source, store->store_source);
1724 foreach_alist(storage, jcr->rstorage) {
1725 if (store->store == storage) {
1729 /* Store not in list, so add it */
1730 jcr->rstorage->prepend(store->store);
1733 void free_rstorage(JCR *jcr)
1735 if (jcr->rstorage) {
1736 delete jcr->rstorage;
1737 jcr->rstorage = NULL;
1743 * Copy the storage definitions from an alist to the JCR
1745 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1749 if (jcr->wstorage) {
1750 delete jcr->wstorage;
1752 jcr->wstorage = New(alist(10, not_owned_by_alist));
1753 foreach_alist(st, storage) {
1754 Dmsg1(100, "wstorage=%s\n", st->name());
1755 jcr->wstorage->append(st);
1757 if (!jcr->wstore_source) {
1758 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1760 pm_strcpy(jcr->wstore_source, where);
1761 if (jcr->wstorage) {
1762 jcr->wstore = (STORE *)jcr->wstorage->first();
1763 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1769 /* Set storage override. Remove all previous storage */
1770 void set_wstorage(JCR *jcr, USTORE *store)
1774 if (!store->store) {
1777 if (jcr->wstorage) {
1780 if (!jcr->wstorage) {
1781 jcr->wstorage = New(alist(10, not_owned_by_alist));
1783 jcr->wstore = store->store;
1784 if (!jcr->wstore_source) {
1785 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1787 pm_strcpy(jcr->wstore_source, store->store_source);
1788 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1789 foreach_alist(storage, jcr->wstorage) {
1790 if (store->store == storage) {
1794 /* Store not in list, so add it */
1795 jcr->wstorage->prepend(store->store);
1798 void free_wstorage(JCR *jcr)
1800 if (jcr->wstorage) {
1801 delete jcr->wstorage;
1802 jcr->wstorage = NULL;
1807 void create_clones(JCR *jcr)
1810 * Fire off any clone jobs (run directives)
1812 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1813 if (!jcr->cloned && jcr->job->run_cmds) {
1815 JOB *job = jcr->job;
1816 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1817 UAContext *ua = new_ua_context(jcr);
1819 foreach_alist(runcmd, job->run_cmds) {
1820 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1821 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1822 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1823 parse_ua_args(ua); /* parse command */
1824 int stat = run_cmd(ua, ua->cmd);
1826 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1829 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1832 free_ua_context(ua);
1833 free_pool_memory(cmd);
1838 * Given: a JobId and FileIndex
1839 * this subroutine writes a bsr file to restore that job.
1840 * Returns: -1 on error
1841 * number of files if OK
1843 int create_restore_bootstrap_file(JCR *jcr, JobId_t jobid, int findex1, int findex2)
1849 memset(&rx, 0, sizeof(rx));
1850 rx.JobIds = (char *)"";
1852 rx.bsr_list = create_bsr_list(jobid, findex1, findex2);
1854 ua = new_ua_context(jcr);
1855 if (!complete_bsr(ua, rx.bsr_list)) {
1860 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1861 if (jcr->ExpectedFiles == 0) {
1865 free_ua_context(ua);
1866 free_bsr(rx.bsr_list);
1867 jcr->needs_sd = true;
1868 return jcr->ExpectedFiles;
1871 free_ua_context(ua);
1872 free_bsr(rx.bsr_list);
1877 * Given: a JobId in jcr->previous_jr.JobId,
1878 * this subroutine writes a bsr file to restore that job.
1879 * Returns: -1 on error
1880 * number of files if OK
1882 int create_restore_bootstrap_file(JCR *jcr)
1884 return create_restore_bootstrap_file(jcr, jcr->previous_jr.JobId, 1, jcr->previous_jr.JobFiles);
1887 /* TODO: redirect command ouput to job log */
1888 bool run_console_command(JCR *jcr, const char *cmd)
1892 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1893 ua = new_ua_context(ljcr);
1894 /* run from runscript and check if commands are authorized */
1895 ua->runscript = true;
1896 Mmsg(ua->cmd, "%s", cmd);
1897 Dmsg1(100, "Console command: %s\n", ua->cmd);
1899 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1900 ok = do_a_dot_command(ua);
1902 ok = do_a_command(ua);
1905 free_ua_context(ua);