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_key,
120 jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
121 jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
122 jcr->catalog->mult_db_connections,
123 jcr->catalog->disable_batch_insert);
124 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
125 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
126 jcr->catalog->db_name);
128 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
129 db_close_database(jcr, jcr->db);
135 Dmsg0(150, "DB opened\n");
137 jcr->fname = get_pool_memory(PM_FNAME);
139 if (!jcr->pool_source) {
140 jcr->pool_source = get_pool_memory(PM_MESSAGE);
141 pm_strcpy(jcr->pool_source, _("unknown source"));
143 if (!jcr->next_pool_source) {
144 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
145 pm_strcpy(jcr->next_pool_source, _("unknown source"));
148 if (jcr->JobReads()) {
149 if (!jcr->rpool_source) {
150 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
151 pm_strcpy(jcr->rpool_source, _("unknown source"));
158 init_jcr_job_record(jcr);
159 if (!get_or_create_client_record(jcr)) {
163 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
164 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
167 jcr->JobId = jcr->jr.JobId;
168 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
169 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
171 generate_daemon_event(jcr, "JobStart");
172 new_plugins(jcr); /* instantiate plugins for this jcr */
173 generate_plugin_event(jcr, bDirEventJobStart);
175 if (job_canceled(jcr)) {
179 if (jcr->JobReads() && !jcr->rstorage) {
180 if (jcr->job->storage) {
181 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
183 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
186 if (!jcr->JobReads()) {
191 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
192 * this allows us to setup a proper job start record for restarting
193 * in case of later errors.
195 switch (jcr->getJobType()) {
197 if (!do_backup_init(jcr)) {
198 backup_cleanup(jcr, JS_ErrorTerminated);
203 if (!do_verify_init(jcr)) {
204 verify_cleanup(jcr, JS_ErrorTerminated);
209 if (!do_restore_init(jcr)) {
210 restore_cleanup(jcr, JS_ErrorTerminated);
215 if (!do_admin_init(jcr)) {
216 admin_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_mac_init(jcr)) {
223 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
228 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
229 jcr->setJobStatus(JS_ErrorTerminated);
233 generate_plugin_event(jcr, bDirEventJobInit);
242 * Setup a job for a resume command
244 static bool setup_resume_job(JCR *jcr, JOB_DBR *jr)
249 init_msg(jcr, jcr->messages);
251 /* Initialize termination condition variable */
252 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
254 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
258 jcr->term_wait_inited = true;
260 jcr->setJobStatus(JS_Created);
266 Dmsg0(100, "Open database\n");
267 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
268 jcr->catalog->db_user, jcr->catalog->db_password,
269 jcr->catalog->db_address, jcr->catalog->db_port,
270 jcr->catalog->db_socket, jcr->catalog->db_ssl_key,
271 jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
272 jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
273 jcr->catalog->mult_db_connections,
274 jcr->catalog->disable_batch_insert);
275 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
276 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
277 jcr->catalog->db_name);
279 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
280 db_close_database(jcr, jcr->db);
285 Dmsg0(100, "DB opened\n");
287 jcr->fname = get_pool_memory(PM_FNAME);
289 if (!jcr->pool_source) {
290 jcr->pool_source = get_pool_memory(PM_MESSAGE);
291 pm_strcpy(jcr->pool_source, _("unknown source"));
293 if (!jcr->next_pool_source) {
294 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
295 pm_strcpy(jcr->next_pool_source, _("unknown source"));
300 * Setup Job record. Make sure original job is Incomplete.
302 memcpy(&jcr->jr, jr, sizeof(JOB_DBR));
303 jcr->sched_time = jcr->jr.SchedTime;
304 jcr->start_time = jcr->jr.StartTime;
305 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
306 jcr->setJobType(jcr->jr.JobType);
307 jcr->setJobLevel(jcr->jr.JobLevel);
308 jcr->JobId = jcr->jr.JobId;
309 if (!get_or_create_client_record(jcr)) {
310 Dmsg0(100, "Could not create client record.\n");
314 Dmsg6(100, "Got job record JobId=%d Job=%s Name=%s Type=%c Level=%c Status=%c\n",
315 jcr->jr.JobId, jcr->jr.Job, jcr->jr.Name, jcr->jr.JobType, jcr->jr.JobLevel,
317 if (jcr->jr.JobStatus != JS_Incomplete) {
318 /* ***FIXME*** add error message */
319 Dmsg1(100, "Job is not an Incomplete: status=%c\n", jcr->jr.JobStatus);
322 bstrncpy(jcr->Job, jcr->jr.Job, sizeof(jcr->Job));
323 jcr->setJobType(jcr->jr.JobType);
324 jcr->setJobLevel(jcr->jr.JobLevel);
326 generate_daemon_event(jcr, "JobStart");
327 new_plugins(jcr); /* instantiate plugins for this jcr */
328 generate_plugin_event(jcr, bDirEventJobStart);
330 if (job_canceled(jcr)) {
331 Dmsg0(100, "Oops. Job canceled\n");
335 /* Re-run the old job */
336 jcr->rerunning = true;
339 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
340 * this allows us to setup a proper job start record for restarting
341 * in case of later errors.
343 switch (jcr->getJobType()) {
345 if (!do_backup_init(jcr)) {
346 backup_cleanup(jcr, JS_ErrorTerminated);
351 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
352 jcr->setJobStatus(JS_ErrorTerminated);
356 generate_plugin_event(jcr, bDirEventJobInit);
364 JobId_t resume_job(JCR *jcr, JOB_DBR *jr)
367 if (setup_resume_job(jcr, jr)) {
368 Dmsg0(200, "Add jrc to work queue\n");
369 /* Queue the job to be run */
370 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
372 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
382 void update_job_end(JCR *jcr, int TermCode)
384 dequeue_messages(jcr); /* display any queued messages */
385 jcr->setJobStatus(TermCode);
386 update_job_end_record(jcr);
390 * This is the engine called by jobq.c:jobq_add() when we were pulled
391 * from the work queue.
392 * At this point, we are running in our own thread and all
393 * necessary resources are allocated -- see jobq.c
395 static void *job_thread(void *arg)
397 JCR *jcr = (JCR *)arg;
399 pthread_detach(pthread_self());
402 Dmsg0(200, "=====Start Job=========\n");
403 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
404 jcr->start_time = time(NULL); /* set the real start time */
405 jcr->jr.StartTime = jcr->start_time;
407 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
408 (utime_t)(jcr->start_time - jcr->sched_time)) {
409 jcr->setJobStatus(JS_Canceled);
410 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
413 if (job_check_maxrunschedtime(jcr)) {
414 jcr->setJobStatus(JS_Canceled);
415 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
418 /* TODO : check if it is used somewhere */
419 if (jcr->job->RunScripts == NULL) {
420 Dmsg0(200, "Warning, job->RunScripts is empty\n");
421 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
424 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
425 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
428 /* Run any script BeforeJob on dird */
429 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
432 * We re-update the job start record so that the start
433 * time is set after the run before job. This avoids
434 * that any files created by the run before job will
435 * be saved twice. They will be backed up in the current
436 * job, but not in the next one unless they are changed.
437 * Without this, they will be backed up in this job and
438 * in the next job run because in that case, their date
439 * is after the start of this run.
441 jcr->start_time = time(NULL);
442 jcr->jr.StartTime = jcr->start_time;
443 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
444 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
446 generate_plugin_event(jcr, bDirEventJobRun);
448 switch (jcr->getJobType()) {
450 if (!job_canceled(jcr) && do_backup(jcr)) {
453 backup_cleanup(jcr, JS_ErrorTerminated);
457 if (!job_canceled(jcr) && do_verify(jcr)) {
460 verify_cleanup(jcr, JS_ErrorTerminated);
464 if (!job_canceled(jcr) && do_restore(jcr)) {
467 restore_cleanup(jcr, JS_ErrorTerminated);
471 if (!job_canceled(jcr) && do_admin(jcr)) {
474 admin_cleanup(jcr, JS_ErrorTerminated);
479 if (!job_canceled(jcr) && do_mac(jcr)) {
482 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
486 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
490 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
492 /* Send off any queued messages */
493 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
494 dequeue_messages(jcr);
497 generate_daemon_event(jcr, "JobEnd");
498 generate_plugin_event(jcr, bDirEventJobEnd);
499 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
504 void sd_msg_thread_send_signal(JCR *jcr, int sig)
507 if ( !jcr->sd_msg_thread_done
508 && jcr->SD_msg_chan_started
509 && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
511 Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
512 pthread_kill(jcr->SD_msg_chan, sig);
517 static bool cancel_file_daemon_job(UAContext *ua, const char *cmd, JCR *jcr)
522 Dmsg0(100, "No client to cancel\n");
525 old_client = ua->jcr->client;
526 ua->jcr->client = jcr->client;
527 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
528 ua->error_msg(_("Failed to connect to File daemon.\n"));
529 ua->jcr->client = old_client;
532 Dmsg3(10, "Connected to file daemon %s for cancel ua.jcr=%p jcr=%p\n",
533 ua->jcr->client->name(), ua->jcr, jcr);
534 BSOCK *fd = ua->jcr->file_bsock;
535 fd->fsend("%s Job=%s\n", cmd, jcr->Job);
536 while (fd->recv() >= 0) {
537 ua->send_msg("%s", fd->msg);
539 fd->signal(BNET_TERMINATE);
540 free_bsock(ua->jcr->file_bsock);
541 ua->jcr->client = old_client;
545 static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
547 if (jcr->store_bsock) {
549 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
551 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
556 store.store = jcr->rstore;
558 store.store = jcr->wstore;
560 set_wstorage(ua->jcr, &store);
563 if (!ua->jcr->wstore) {
564 ua->error_msg(_("Failed to select Storage daemon.\n"));
568 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
569 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
573 Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
574 ua->jcr->wstore->name(), ua->jcr, jcr);
576 BSOCK *sd = ua->jcr->store_bsock;
577 sd->fsend("%s Job=%s\n", cmd, jcr->Job);
578 while (sd->recv() >= 0) {
579 ua->send_msg("%s", sd->msg);
581 sd->signal(BNET_TERMINATE);
582 free_bsock(ua->jcr->store_bsock);
586 /* The FD is not connected, so we try to complete JCR fields and send
587 * the cancel command.
589 int cancel_inactive_job(UAContext *ua)
596 JCR *jcr = new_jcr(sizeof(JCR), dird_free_jcr);
598 memset(&jr, 0, sizeof(jr));
599 memset(&cr, 0, sizeof(cr));
601 if ((i = find_arg_with_value(ua, "jobid")) > 0) {
602 jr.JobId = str_to_int64(ua->argv[i]);
604 } else if ((i = find_arg_with_value(ua, "ujobid")) > 0) {
605 bstrncpy(jr.Job, ua->argv[i], sizeof(jr.Job));
608 ua->error_msg(_("jobid/ujobid argument not found.\n"));
612 if (!open_client_db(ua)) {
616 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
617 ua->error_msg(_("Job %ld/%s not found in database.\n"), jr.JobId, jr.Job);
621 if (!acl_access_ok(ua, Job_ACL, jr.Name)) {
622 ua->error_msg(_("Job %s is not accessible from this console\n"), jr.Name);
626 cr.ClientId = jr.ClientId;
627 if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
628 ua->error_msg(_("Client %ld not found in database.\n"), jr.ClientId);
632 if (acl_access_client_ok(ua, cr.Name, jr.JobType)) {
633 client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
635 jcr->client = client;
637 Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
644 jcr->JobId = jr.JobId;
645 bstrncpy(jcr->Job, jr.Job, sizeof(jcr->Job));
647 cancel_file_daemon_job(ua, "cancel", jcr);
649 /* At this time, we can't really guess the storage name from
652 store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
657 set_wstorage(jcr, &store);
658 cancel_sd_job(ua, "cancel", jcr);
667 * Cancel a job -- typically called by the UA (Console program), but may also
668 * be called by the job watchdog.
670 * Returns: true if cancel appears to be successful
671 * false on failure. Message sent to ua->jcr.
674 cancel_job(UAContext *ua, JCR *jcr, int wait, bool cancel)
677 int32_t old_status = jcr->JobStatus;
679 const char *reason, *cmd;
681 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
684 status = JS_Canceled;
685 reason = _("canceled");
688 status = JS_Incomplete;
689 reason = _("stopped");
691 jcr->RescheduleIncompleteJobs = false; /* do not restart */
694 jcr->setJobStatus(status);
696 switch (old_status) {
699 case JS_WaitClientRes:
700 case JS_WaitStoreRes:
701 case JS_WaitPriority:
703 case JS_WaitStartTime:
705 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
706 edit_uint64(jcr->JobId, ed1), jcr->Job,
708 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
713 /* Cancel File daemon */
714 if (jcr->file_bsock) {
716 /* do not return now, we want to try to cancel the sd */
717 tid = start_bsock_timer(jcr->file_bsock, 120);
718 cancel_file_daemon_job(ua, cmd, jcr);
719 stop_bsock_timer(tid);
722 /* We test file_bsock because the previous operation can take
725 if (jcr->file_bsock && cancel) {
726 jcr->file_bsock->set_terminated();
727 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
730 /* Cancel Storage daemon */
731 if (jcr->store_bsock) {
733 /* do not return now, we want to try to cancel the sd socket */
734 tid = start_bsock_timer(jcr->store_bsock, 120);
735 cancel_sd_job(ua, cmd, jcr);
736 stop_bsock_timer(tid);
739 /* We test file_bsock because the previous operation can take
742 if (jcr->store_bsock && cancel) {
743 jcr->store_bsock->set_timed_out();
744 jcr->store_bsock->set_terminated();
745 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
746 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
749 /* Cancel Copy/Migration Storage daemon */
751 /* The wjcr is valid until we call free_jcr(jcr) */
752 JCR *wjcr = jcr->wjcr;
754 if (wjcr->store_bsock) {
756 /* do not return now, we want to try to cancel the sd socket */
757 tid = start_bsock_timer(wjcr->store_bsock, 120);
758 cancel_sd_job(ua, cmd, wjcr);
759 stop_bsock_timer(tid);
761 /* We test store_bsock because the previous operation can take
764 if (wjcr->store_bsock && cancel) {
765 wjcr->store_bsock->set_timed_out();
766 wjcr->store_bsock->set_terminated();
767 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
768 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
777 void cancel_storage_daemon_job(JCR *jcr)
779 if (jcr->sd_canceled) {
780 return; /* cancel only once */
783 UAContext *ua = new_ua_context(jcr);
784 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
787 ua->jcr = control_jcr;
788 if (jcr->store_bsock) {
789 if (!ua->jcr->wstorage) {
791 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
793 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
798 store.store = jcr->rstore;
800 store.store = jcr->wstore;
802 set_wstorage(ua->jcr, &store);
805 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
808 Dmsg0(200, "Connected to storage daemon\n");
809 sd = ua->jcr->store_bsock;
810 sd->fsend("cancel Job=%s\n", jcr->Job);
811 while (sd->recv() >= 0) {
813 sd->signal(BNET_TERMINATE);
814 free_bsock(ua->jcr->store_bsock);
815 jcr->sd_canceled = true;
816 jcr->store_bsock->set_timed_out();
817 jcr->store_bsock->set_terminated();
818 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
819 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
822 free_jcr(control_jcr);
826 static void job_monitor_destructor(watchdog_t *self)
828 JCR *control_jcr = (JCR *)self->data;
830 free_jcr(control_jcr);
833 extern "C" void *cancel_thread(void *arg)
835 JCR *jcr = (JCR *)arg;
839 pthread_detach(pthread_self());
840 ua = new_ua_context(jcr);
841 control_jcr = new_control_jcr("*CancelThread*", JT_SYSTEM);
842 ua->jcr = control_jcr;
844 Dmsg3(400, "Cancelling JCR %p JobId=%d (%s)\n", jcr, jcr->JobId, jcr->Job);
845 cancel_job(ua, jcr, 120);
846 Dmsg2(400, "Have cancelled JCR %p JobId=%d\n", jcr, jcr->JobId);
849 free_jcr(control_jcr);
854 static void job_monitor_watchdog(watchdog_t *wd)
859 Dmsg1(800, "job_monitor_watchdog %p called\n", wd);
864 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
865 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
869 /* check MaxWaitTime */
870 if (job_check_maxwaittime(jcr)) {
871 jcr->setJobStatus(JS_Canceled);
872 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
874 /* check MaxRunTime */
875 } else if (job_check_maxruntime(jcr)) {
876 jcr->setJobStatus(JS_Canceled);
877 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
879 /* check MaxRunSchedTime */
880 } else if (job_check_maxrunschedtime(jcr)) {
881 jcr->setJobStatus(JS_Canceled);
882 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
889 jcr->inc_use_count();
890 if ((status=pthread_create(&thid, NULL, cancel_thread, (void *)jcr)) != 0) {
892 Jmsg1(jcr, M_WARNING, 0, _("Cannot create cancel thread: ERR=%s\n"), be.bstrerror(status));
897 /* Keep reference counts correct */
902 * Check if the maxwaittime has expired and it is possible
905 static bool job_check_maxwaittime(JCR *jcr)
911 if (!job_waiting(jcr)) {
915 if (jcr->wait_time) {
916 current = watchdog_time - jcr->wait_time;
919 Dmsg2(200, "check maxwaittime %u >= %u\n",
920 current + jcr->wait_time_sum, job->MaxWaitTime);
921 if (job->MaxWaitTime != 0 &&
922 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
930 * Check if maxruntime has expired and if the job can be
933 static bool job_check_maxruntime(JCR *jcr)
939 if (job_canceled(jcr) || !jcr->job_started) {
942 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
943 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
946 run_time = watchdog_time - jcr->start_time;
947 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
948 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
949 job->IncMaxRunTime, job->DiffMaxRunTime);
951 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
952 run_time >= job->FullMaxRunTime) {
953 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
955 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
956 run_time >= job->DiffMaxRunTime) {
957 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
959 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
960 run_time >= job->IncMaxRunTime) {
961 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
963 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
964 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
972 * Check if MaxRunSchedTime has expired and if the job can be
975 static bool job_check_maxrunschedtime(JCR *jcr)
977 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
980 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
981 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
982 jcr, jcr->Job, jcr->MaxRunSchedTime);
990 * Get or create a Pool record with the given name.
991 * Returns: 0 on error
994 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
998 memset(&pr, 0, sizeof(pr));
999 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
1000 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
1002 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
1003 /* Try to create the pool */
1004 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
1005 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
1006 db_strerror(jcr->db));
1009 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
1016 * Check for duplicate jobs.
1017 * Returns: true if current job should continue
1018 * false if current job should terminate
1020 bool allow_duplicate_job(JCR *jcr)
1022 JOB *job = jcr->job;
1023 JCR *djcr; /* possible duplicate job */
1025 /* Is AllowDuplicateJobs is set or is duplicate checking
1026 * disabled for this job? */
1027 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
1030 Dmsg0(800, "Enter allow_duplicate_job\n");
1032 * After this point, we do not want to allow any duplicate
1037 if (jcr == djcr || djcr->is_internal_job() || !djcr->job) {
1038 continue; /* do not cancel this job or consoles */
1040 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1041 * if so do not check it against other jobs */
1042 if (djcr->IgnoreDuplicateJobChecking) {
1045 if ((strcmp(job->name(), djcr->job->name()) == 0) &&
1046 djcr->getJobType() == jcr->getJobType()) /* A duplicate is about the same name and the same type */
1048 bool cancel_dup = false;
1049 bool cancel_me = false;
1050 if (job->DuplicateJobProximity > 0) {
1051 utime_t now = (utime_t)time(NULL);
1052 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1053 continue; /* not really a duplicate */
1056 if (job->CancelLowerLevelDuplicates &&
1057 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1058 switch (jcr->getJobLevel()) {
1060 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1061 djcr->getJobLevel() == L_INCREMENTAL) {
1065 case L_DIFFERENTIAL:
1066 if (djcr->getJobLevel() == L_INCREMENTAL) {
1069 if (djcr->getJobLevel() == L_FULL) {
1074 if (djcr->getJobLevel() == L_FULL ||
1075 djcr->getJobLevel() == L_DIFFERENTIAL) {
1080 * cancel_dup will be done below
1083 /* Zap current job */
1084 jcr->setJobStatus(JS_Canceled);
1085 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1087 break; /* get out of foreach_jcr */
1090 /* Cancel one of the two jobs (me or dup) */
1091 /* If CancelQueuedDuplicates is set do so only if job is queued */
1092 if (job->CancelQueuedDuplicates) {
1093 switch (djcr->JobStatus) {
1096 case JS_WaitClientRes:
1097 case JS_WaitStoreRes:
1098 case JS_WaitPriority:
1099 case JS_WaitMaxJobs:
1100 case JS_WaitStartTime:
1102 cancel_dup = true; /* cancel queued duplicate */
1108 if (cancel_dup || job->CancelRunningDuplicates) {
1109 /* Zap the duplicated job djcr */
1110 UAContext *ua = new_ua_context(jcr);
1111 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1112 cancel_job(ua, djcr, 60);
1113 bmicrosleep(0, 500000);
1114 djcr->setJobStatus(JS_Canceled);
1115 cancel_job(ua, djcr, 60);
1116 free_ua_context(ua);
1117 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1119 /* Zap current job */
1120 jcr->setJobStatus(JS_Canceled);
1121 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1123 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1125 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1126 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1127 break; /* did our work, get out of foreach loop */
1136 * Apply pool overrides to get the storage properly setup.
1138 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1142 Dmsg1(100, "Original pool=%s\n", opool->name());
1143 if (jcr->cmdline_next_pool_override) {
1144 /* Can be Command line or User input */
1145 source = NPRT(jcr->next_pool_source);
1146 } else if (jcr->run_next_pool_override) {
1147 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1148 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1149 source = _("Run NextPool override");
1150 } else if (jcr->job->next_pool) {
1151 /* Use Job Next Pool */
1152 jcr->next_pool = jcr->job->next_pool;
1153 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1154 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1155 source = _("Job's NextPool resource");
1157 /* Default to original pool->NextPool */
1158 jcr->next_pool = opool->NextPool;
1159 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1160 if (jcr->next_pool) {
1161 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1163 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1164 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1165 source = _("Pool's NextPool resource");
1169 * If the original backup pool has a NextPool, make sure a
1170 * record exists in the database.
1172 if (jcr->next_pool) {
1173 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1174 if (jcr->jr.PoolId == 0) {
1179 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1183 /* Set write pool and source. Not read pool is in rpool. */
1184 jcr->pool = jcr->next_pool;
1185 pm_strcpy(jcr->pool_source, source);
1191 void apply_pool_overrides(JCR *jcr)
1193 bool pool_override = false;
1195 if (jcr->run_pool_override) {
1196 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1199 * Apply any level related Pool selections
1201 switch (jcr->getJobLevel()) {
1203 if (jcr->full_pool) {
1204 jcr->pool = jcr->full_pool;
1205 pool_override = true;
1206 if (jcr->run_full_pool_override) {
1207 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1209 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1214 if (jcr->inc_pool) {
1215 jcr->pool = jcr->inc_pool;
1216 pool_override = true;
1217 if (jcr->run_inc_pool_override) {
1218 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1220 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1224 case L_DIFFERENTIAL:
1225 if (jcr->diff_pool) {
1226 jcr->pool = jcr->diff_pool;
1227 pool_override = true;
1228 if (jcr->run_diff_pool_override) {
1229 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1231 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1236 /* Update catalog if pool overridden */
1237 if (pool_override && jcr->pool->catalog) {
1238 jcr->catalog = jcr->pool->catalog;
1239 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1245 * Get or create a Client record for this Job
1247 bool get_or_create_client_record(JCR *jcr)
1252 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1255 memset(&cr, 0, sizeof(cr));
1256 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1257 cr.AutoPrune = jcr->client->AutoPrune;
1258 cr.FileRetention = jcr->client->FileRetention;
1259 cr.JobRetention = jcr->client->JobRetention;
1260 if (!jcr->client_name) {
1261 jcr->client_name = get_pool_memory(PM_NAME);
1263 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1264 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1265 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1266 db_strerror(jcr->db));
1269 jcr->jr.ClientId = cr.ClientId;
1271 if (!jcr->client_uname) {
1272 jcr->client_uname = get_pool_memory(PM_NAME);
1274 pm_strcpy(jcr->client_uname, cr.Uname);
1276 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1282 * Get or Create FileSet record
1284 bool get_or_create_fileset_record(JCR *jcr)
1288 memset(&fsr, 0, sizeof(FILESET_DBR));
1289 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1290 if (jcr->fileset->have_MD5) {
1291 struct MD5Context md5c;
1292 unsigned char digest[MD5HashSize];
1293 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1294 MD5Final(digest, &md5c);
1296 * Keep the flag (last arg) set to false otherwise old FileSets will
1297 * get new MD5 sums and the user will get Full backups on everything
1299 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1300 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1302 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1304 if (!jcr->fileset->ignore_fs_changes ||
1305 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1306 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1307 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1308 fsr.FileSet, db_strerror(jcr->db));
1312 jcr->jr.FileSetId = fsr.FileSetId;
1313 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1314 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1319 void init_jcr_job_record(JCR *jcr)
1321 jcr->jr.SchedTime = jcr->sched_time;
1322 jcr->jr.StartTime = jcr->start_time;
1323 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1324 jcr->jr.JobType = jcr->getJobType();
1325 jcr->jr.JobLevel = jcr->getJobLevel();
1326 jcr->jr.JobStatus = jcr->JobStatus;
1327 jcr->jr.JobId = jcr->JobId;
1328 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1329 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1333 * Write status and such in DB
1335 void update_job_end_record(JCR *jcr)
1337 jcr->jr.EndTime = time(NULL);
1338 jcr->end_time = jcr->jr.EndTime;
1339 jcr->jr.JobId = jcr->JobId;
1340 jcr->jr.JobStatus = jcr->JobStatus;
1341 jcr->jr.JobFiles = jcr->JobFiles;
1342 jcr->jr.JobBytes = jcr->JobBytes;
1343 jcr->jr.ReadBytes = jcr->ReadBytes;
1344 jcr->jr.VolSessionId = jcr->VolSessionId;
1345 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1346 jcr->jr.JobErrors = jcr->JobErrors + jcr->SDErrors;
1347 jcr->jr.HasBase = jcr->HasBase;
1348 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1349 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1350 db_strerror(jcr->db));
1355 * Takes base_name and appends (unique) current
1356 * date and time to form unique job name.
1358 * Note, the seconds are actually a sequence number. This
1359 * permits us to start a maximum fo 59 unique jobs a second, which
1360 * should be sufficient.
1362 * Returns: unique job name in jcr->Job
1363 * date/time in jcr->start_time
1365 void create_unique_job_name(JCR *jcr, const char *base_name)
1367 /* Job start mutex */
1368 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1369 static time_t last_start_time = 0;
1371 time_t now = time(NULL);
1373 char dt[MAX_TIME_LENGTH];
1374 char name[MAX_NAME_LENGTH];
1379 /* Guarantee unique start time -- maximum one per second, and
1380 * thus unique Job Name
1382 P(mutex); /* lock creation of jobs */
1384 if (seq > 59) { /* wrap as if it is seconds */
1386 while (now == last_start_time) {
1387 bmicrosleep(0, 500000);
1391 last_start_time = now;
1393 V(mutex); /* allow creation of jobs */
1394 jcr->start_time = now;
1395 /* Form Unique JobName */
1396 (void)localtime_r(&now, &tm);
1397 /* Use only characters that are permitted in Windows filenames */
1398 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1399 len = strlen(dt) + 5; /* dt + .%02d EOS */
1400 bstrncpy(name, base_name, sizeof(name));
1401 name[sizeof(name)-len] = 0; /* truncate if too long */
1402 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1403 /* Convert spaces into underscores */
1404 for (p=jcr->Job; *p; p++) {
1409 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1412 /* Called directly from job rescheduling */
1413 void dird_free_jcr_pointers(JCR *jcr)
1415 /* Close but do not free bsock packets */
1416 if (jcr->file_bsock) {
1417 Dmsg0(200, "Close File bsock\n");
1418 jcr->file_bsock->close();
1420 if (jcr->store_bsock) {
1421 Dmsg0(200, "Close Store bsock\n");
1422 jcr->store_bsock->close();
1425 bfree_and_null(jcr->sd_auth_key);
1426 bfree_and_null(jcr->where);
1427 bfree_and_null(jcr->RestoreBootstrap);
1428 jcr->cached_attribute = false;
1429 bfree_and_null(jcr->ar);
1431 free_and_null_pool_memory(jcr->JobIds);
1432 free_and_null_pool_memory(jcr->client_uname);
1433 free_and_null_pool_memory(jcr->attr);
1434 free_and_null_pool_memory(jcr->fname);
1435 free_and_null_pool_memory(jcr->media_type);
1439 * Free the Job Control Record if no one is still using it.
1440 * Called from main free_jcr() routine in src/lib/jcr.c so
1441 * that we can do our Director specific cleanup of the jcr.
1443 void dird_free_jcr(JCR *jcr)
1445 Dmsg0(200, "Start dird free_jcr\n");
1447 dird_free_jcr_pointers(jcr);
1449 free_jcr(jcr->wjcr);
1452 /* Free bsock packets */
1453 free_bsock(jcr->file_bsock);
1454 free_bsock(jcr->store_bsock);
1455 if (jcr->term_wait_inited) {
1456 pthread_cond_destroy(&jcr->term_wait);
1457 jcr->term_wait_inited = false;
1459 if (jcr->db_batch) {
1460 db_close_database(jcr, jcr->db_batch);
1461 jcr->db_batch = NULL;
1462 jcr->batch_started = false;
1465 db_close_database(jcr, jcr->db);
1469 free_and_null_pool_memory(jcr->stime);
1470 free_and_null_pool_memory(jcr->fname);
1471 free_and_null_pool_memory(jcr->pool_source);
1472 free_and_null_pool_memory(jcr->next_pool_source);
1473 free_and_null_pool_memory(jcr->catalog_source);
1474 free_and_null_pool_memory(jcr->rpool_source);
1475 free_and_null_pool_memory(jcr->wstore_source);
1476 free_and_null_pool_memory(jcr->rstore_source);
1477 free_and_null_pool_memory(jcr->next_vol_list);
1478 free_and_null_pool_memory(jcr->component_fname);
1480 /* Delete lists setup to hold storage pointers */
1481 free_rwstorage(jcr);
1483 jcr->job_end_push.destroy();
1485 if (jcr->JobId != 0)
1486 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1488 if (jcr->plugin_config) {
1489 free_plugin_config_items(jcr->plugin_config);
1490 delete jcr->plugin_config;
1491 jcr->plugin_config = NULL;
1493 free_plugins(jcr); /* release instantiated plugins */
1495 garbage_collect_memory_pool();
1497 Dmsg0(200, "End dird free_jcr\n");
1501 * The Job storage definition must be either in the Job record
1502 * or in the Pool record. The Pool record overrides the Job
1505 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1507 if (run && run->pool && run->pool->storage) {
1508 store->store = (STORE *)run->pool->storage->first();
1509 pm_strcpy(store->store_source, _("Run pool override"));
1512 if (run && run->storage) {
1513 store->store = run->storage;
1514 pm_strcpy(store->store_source, _("Run storage override"));
1517 if (job->pool->storage) {
1518 store->store = (STORE *)job->pool->storage->first();
1519 pm_strcpy(store->store_source, _("Pool resource"));
1521 store->store = (STORE *)job->storage->first();
1522 pm_strcpy(store->store_source, _("Job resource"));
1527 * Set some defaults in the JCR necessary to
1528 * run. These items are pulled from the job
1529 * definition as defaults, but can be overridden
1530 * later either by the Run record in the Schedule resource,
1531 * or by the Console program.
1533 void set_jcr_defaults(JCR *jcr, JOB *job)
1536 jcr->setJobType(job->JobType);
1537 jcr->JobStatus = JS_Created;
1539 switch (jcr->getJobType()) {
1541 jcr->setJobLevel(L_NONE);
1544 jcr->setJobLevel(job->JobLevel);
1547 if (!jcr->next_vol_list) {
1548 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1551 jcr->fname = get_pool_memory(PM_FNAME);
1553 if (!jcr->pool_source) {
1554 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1556 if (!jcr->next_pool_source) {
1557 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1559 if (!jcr->catalog_source) {
1560 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1563 jcr->JobPriority = job->Priority;
1564 /* Copy storage definitions -- deleted in dir_free_jcr above */
1566 copy_rwstorage(jcr, job->storage, _("Job resource"));
1568 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1570 jcr->client = job->client;
1571 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1572 if (!jcr->client_name) {
1573 jcr->client_name = get_pool_memory(PM_NAME);
1575 pm_strcpy(jcr->client_name, jcr->client->name());
1576 jcr->pool = job->pool;
1577 pm_strcpy(jcr->pool_source, _("Job resource"));
1578 if (job->next_pool) {
1579 /* Use Job's Next Pool */
1580 jcr->next_pool = job->next_pool;
1581 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1583 /* Default to original pool->NextPool */
1584 jcr->next_pool = job->pool->NextPool;
1585 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1587 jcr->full_pool = job->full_pool;
1588 jcr->inc_pool = job->inc_pool;
1589 jcr->diff_pool = job->diff_pool;
1590 if (job->pool->catalog) {
1591 jcr->catalog = job->pool->catalog;
1592 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1594 jcr->catalog = job->client->catalog;
1595 pm_strcpy(jcr->catalog_source, _("Client resource"));
1597 jcr->fileset = job->fileset;
1598 jcr->accurate = job->accurate;
1599 jcr->messages = job->messages;
1600 jcr->spool_data = job->spool_data;
1601 jcr->spool_size = job->spool_size;
1602 jcr->write_part_after_job = job->write_part_after_job;
1603 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1604 if (jcr->RestoreBootstrap) {
1605 free(jcr->RestoreBootstrap);
1606 jcr->RestoreBootstrap = NULL;
1608 /* This can be overridden by Console program */
1609 if (job->RestoreBootstrap) {
1610 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1612 /* This can be overridden by Console program */
1613 jcr->verify_job = job->verify_job;
1614 /* If no default level given, set one */
1615 if (jcr->getJobLevel() == 0) {
1616 switch (jcr->getJobType()) {
1618 jcr->setJobLevel(L_VERIFY_CATALOG);
1621 jcr->setJobLevel(L_INCREMENTAL);
1625 jcr->setJobLevel(L_NONE);
1628 jcr->setJobLevel(L_FULL);
1635 * Copy the storage definitions from an alist to the JCR
1637 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1639 if (jcr->JobReads()) {
1640 copy_rstorage(jcr, storage, where);
1642 copy_wstorage(jcr, storage, where);
1646 /* Set storage override. Releases any previous storage definition */
1647 void set_rwstorage(JCR *jcr, USTORE *store)
1650 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1653 if (jcr->JobReads()) {
1654 set_rstorage(jcr, store);
1656 set_wstorage(jcr, store);
1659 void free_rwstorage(JCR *jcr)
1666 * Copy the storage definitions from an alist to the JCR
1668 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1672 if (jcr->rstorage) {
1673 delete jcr->rstorage;
1675 jcr->rstorage = New(alist(10, not_owned_by_alist));
1676 foreach_alist(st, storage) {
1677 jcr->rstorage->append(st);
1679 if (!jcr->rstore_source) {
1680 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1682 pm_strcpy(jcr->rstore_source, where);
1683 if (jcr->rstorage) {
1684 jcr->rstore = (STORE *)jcr->rstorage->first();
1690 /* Set storage override. Remove all previous storage */
1691 void set_rstorage(JCR *jcr, USTORE *store)
1695 if (!store->store) {
1698 if (jcr->rstorage) {
1701 if (!jcr->rstorage) {
1702 jcr->rstorage = New(alist(10, not_owned_by_alist));
1704 jcr->rstore = store->store;
1705 if (!jcr->rstore_source) {
1706 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1708 pm_strcpy(jcr->rstore_source, store->store_source);
1709 foreach_alist(storage, jcr->rstorage) {
1710 if (store->store == storage) {
1714 /* Store not in list, so add it */
1715 jcr->rstorage->prepend(store->store);
1718 void free_rstorage(JCR *jcr)
1720 if (jcr->rstorage) {
1721 delete jcr->rstorage;
1722 jcr->rstorage = NULL;
1728 * Copy the storage definitions from an alist to the JCR
1730 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1734 if (jcr->wstorage) {
1735 delete jcr->wstorage;
1737 jcr->wstorage = New(alist(10, not_owned_by_alist));
1738 foreach_alist(st, storage) {
1739 Dmsg1(100, "wstorage=%s\n", st->name());
1740 jcr->wstorage->append(st);
1742 if (!jcr->wstore_source) {
1743 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1745 pm_strcpy(jcr->wstore_source, where);
1746 if (jcr->wstorage) {
1747 jcr->wstore = (STORE *)jcr->wstorage->first();
1748 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1754 /* Set storage override. Remove all previous storage */
1755 void set_wstorage(JCR *jcr, USTORE *store)
1759 if (!store->store) {
1762 if (jcr->wstorage) {
1765 if (!jcr->wstorage) {
1766 jcr->wstorage = New(alist(10, not_owned_by_alist));
1768 jcr->wstore = store->store;
1769 if (!jcr->wstore_source) {
1770 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1772 pm_strcpy(jcr->wstore_source, store->store_source);
1773 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1774 foreach_alist(storage, jcr->wstorage) {
1775 if (store->store == storage) {
1779 /* Store not in list, so add it */
1780 jcr->wstorage->prepend(store->store);
1783 void free_wstorage(JCR *jcr)
1785 if (jcr->wstorage) {
1786 delete jcr->wstorage;
1787 jcr->wstorage = NULL;
1792 void create_clones(JCR *jcr)
1795 * Fire off any clone jobs (run directives)
1797 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1798 if (!jcr->cloned && jcr->job->run_cmds) {
1800 JOB *job = jcr->job;
1801 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1802 UAContext *ua = new_ua_context(jcr);
1804 foreach_alist(runcmd, job->run_cmds) {
1805 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1806 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1807 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1808 parse_ua_args(ua); /* parse command */
1809 int stat = run_cmd(ua, ua->cmd);
1811 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1814 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1817 free_ua_context(ua);
1818 free_pool_memory(cmd);
1823 * Given: a JobId and FileIndex
1824 * this subroutine writes a bsr file to restore that job.
1825 * Returns: -1 on error
1826 * number of files if OK
1828 int create_restore_bootstrap_file(JCR *jcr, JobId_t jobid, int findex1, int findex2)
1834 memset(&rx, 0, sizeof(rx));
1835 rx.JobIds = (char *)"";
1837 rx.bsr_list = create_bsr_list(jobid, findex1, findex2);
1839 ua = new_ua_context(jcr);
1840 if (!complete_bsr(ua, rx.bsr_list)) {
1845 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1846 if (jcr->ExpectedFiles == 0) {
1850 free_ua_context(ua);
1851 free_bsr(rx.bsr_list);
1852 jcr->needs_sd = true;
1853 return jcr->ExpectedFiles;
1856 free_ua_context(ua);
1857 free_bsr(rx.bsr_list);
1862 * Given: a JobId in jcr->previous_jr.JobId,
1863 * this subroutine writes a bsr file to restore that job.
1864 * Returns: -1 on error
1865 * number of files if OK
1867 int create_restore_bootstrap_file(JCR *jcr)
1869 return create_restore_bootstrap_file(jcr, jcr->previous_jr.JobId, 1, jcr->previous_jr.JobFiles);
1872 /* TODO: redirect command ouput to job log */
1873 bool run_console_command(JCR *jcr, const char *cmd)
1877 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1878 ua = new_ua_context(ljcr);
1879 /* run from runscript and check if commands are authorized */
1880 ua->runscript = true;
1881 Mmsg(ua->cmd, "%s", cmd);
1882 Dmsg1(100, "Console command: %s\n", ua->cmd);
1884 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1885 ok = do_a_dot_command(ua);
1887 ok = do_a_command(ua);
1890 free_ua_context(ua);