2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 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.
21 * Bacula Director Job processing routines
23 * Kern Sibbald, October MM
30 /* Forward referenced subroutines */
31 static void *job_thread(void *arg);
32 static void job_monitor_watchdog(watchdog_t *self);
33 static void job_monitor_destructor(watchdog_t *self);
34 static bool job_check_maxwaittime(JCR *jcr);
35 static bool job_check_maxruntime(JCR *jcr);
36 static bool job_check_maxrunschedtime(JCR *jcr);
38 /* Imported subroutines */
39 extern void term_scheduler();
40 extern void term_ua_server();
42 /* Imported variables */
46 void init_job_server(int max_workers)
51 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
53 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
56 wd->callback = job_monitor_watchdog;
57 wd->destructor = job_monitor_destructor;
60 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
61 register_watchdog(wd);
64 void term_job_server()
66 jobq_destroy(&job_queue); /* ignore any errors */
70 * Run a job -- typically called by the scheduler, but may also
71 * be called by the UA (Console program).
73 * Returns: 0 on failure
77 JobId_t run_job(JCR *jcr)
81 Dmsg0(200, "Add jrc to work queue\n");
82 /* Queue the job to be run */
83 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
85 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
93 bool setup_job(JCR *jcr)
99 init_msg(jcr, jcr->messages, job_code_callback_director);
101 /* Initialize termination condition variable */
102 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
104 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
108 jcr->term_wait_inited = true;
110 create_unique_job_name(jcr, jcr->job->name());
111 jcr->setJobStatus(JS_Created);
117 Dmsg0(100, "Open database\n");
118 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
119 jcr->catalog->db_user, jcr->catalog->db_password,
120 jcr->catalog->db_address, jcr->catalog->db_port,
121 jcr->catalog->db_socket, jcr->catalog->db_ssl_key,
122 jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
123 jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
124 jcr->catalog->mult_db_connections,
125 jcr->catalog->disable_batch_insert);
126 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
127 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
128 jcr->catalog->db_name);
130 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
131 db_close_database(jcr, jcr->db);
137 Dmsg0(150, "DB opened\n");
139 jcr->fname = get_pool_memory(PM_FNAME);
141 if (!jcr->pool_source) {
142 jcr->pool_source = get_pool_memory(PM_MESSAGE);
143 pm_strcpy(jcr->pool_source, _("unknown source"));
145 if (!jcr->next_pool_source) {
146 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
147 pm_strcpy(jcr->next_pool_source, _("unknown source"));
150 if (jcr->JobReads()) {
151 if (!jcr->rpool_source) {
152 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
153 pm_strcpy(jcr->rpool_source, _("unknown source"));
160 init_jcr_job_record(jcr);
161 if (!get_or_create_client_record(jcr)) {
165 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
166 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
169 jcr->JobId = jcr->jr.JobId;
170 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
171 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
173 generate_daemon_event(jcr, "JobStart");
174 new_plugins(jcr); /* instantiate plugins for this jcr */
175 generate_plugin_event(jcr, bDirEventJobStart);
177 if (job_canceled(jcr)) {
181 if (jcr->JobReads() && !jcr->rstorage) {
182 if (jcr->job->storage) {
183 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
185 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
188 if (!jcr->JobReads()) {
193 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
194 * this allows us to setup a proper job start record for restarting
195 * in case of later errors.
197 switch (jcr->getJobType()) {
199 if (!do_backup_init(jcr)) {
200 backup_cleanup(jcr, JS_ErrorTerminated);
205 if (!do_verify_init(jcr)) {
206 verify_cleanup(jcr, JS_ErrorTerminated);
211 if (!do_restore_init(jcr)) {
212 restore_cleanup(jcr, JS_ErrorTerminated);
217 if (!do_admin_init(jcr)) {
218 admin_cleanup(jcr, JS_ErrorTerminated);
224 if (!do_mac_init(jcr)) {
225 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
230 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
231 jcr->setJobStatus(JS_ErrorTerminated);
235 generate_plugin_event(jcr, bDirEventJobInit);
244 * Setup a job for a resume command
246 static bool setup_resume_job(JCR *jcr, JOB_DBR *jr)
251 init_msg(jcr, jcr->messages);
253 /* Initialize termination condition variable */
254 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
256 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
260 jcr->term_wait_inited = true;
262 jcr->setJobStatus(JS_Created);
268 Dmsg0(100, "Open database\n");
269 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
270 jcr->catalog->db_user, jcr->catalog->db_password,
271 jcr->catalog->db_address, jcr->catalog->db_port,
272 jcr->catalog->db_socket, jcr->catalog->db_ssl_key,
273 jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
274 jcr->catalog->db_ssl_capath, 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 static int cancel_inactive_job(UAContext *ua, JCR *jcr)
599 Dmsg2(10, "cancel_inactive_job ua.jcr=%p jcr=%p\n", ua->jcr, jcr);
602 memset(&cr, 0, sizeof(cr));
604 /* User is kind enough to provide the client name */
605 if ((i = find_arg_with_value(ua, "client")) > 0) {
606 bstrncpy(cr.Name, ua->argv[i], sizeof(cr.Name));
608 memset(&jr, 0, sizeof(jr));
609 bstrncpy(jr.Job, jcr->Job, sizeof(jr.Job));
611 if (!open_client_db(ua)) {
614 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
617 cr.ClientId = jr.ClientId;
618 if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
623 if (acl_access_ok(ua, Client_ACL, cr.Name)) {
624 client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
626 jcr->client = client;
628 Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
636 cancel_file_daemon_job(ua, "cancel", jcr);
638 /* At this time, we can't really guess the storage name from
641 store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
646 set_wstorage(ua->jcr, &store);
648 cancel_sd_job(ua, "cancel", jcr);
655 * Cancel a job -- typically called by the UA (Console program), but may also
656 * be called by the job watchdog.
658 * Returns: true if cancel appears to be successful
659 * false on failure. Message sent to ua->jcr.
662 cancel_job(UAContext *ua, JCR *jcr, bool cancel)
665 int32_t old_status = jcr->JobStatus;
667 const char *reason, *cmd;
668 bool force = find_arg(ua, "inactive") > 0;
670 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
672 /* If the user explicitely ask, we can send the cancel command to
675 if (cancel && force) {
676 return cancel_inactive_job(ua, jcr);
680 status = JS_Canceled;
681 reason = _("canceled");
684 status = JS_Incomplete;
685 reason = _("stopped");
687 jcr->RescheduleIncompleteJobs = false; /* do not restart */
690 jcr->setJobStatus(status);
692 switch (old_status) {
695 case JS_WaitClientRes:
696 case JS_WaitStoreRes:
697 case JS_WaitPriority:
699 case JS_WaitStartTime:
701 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
702 edit_uint64(jcr->JobId, ed1), jcr->Job,
704 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
709 /* Cancel File daemon */
710 if (jcr->file_bsock) {
711 /* do not return now, we want to try to cancel the sd */
712 cancel_file_daemon_job(ua, cmd, jcr);
715 /* We test file_bsock because the previous operation can take
718 if (jcr->file_bsock && cancel) {
719 jcr->file_bsock->set_terminated();
720 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
723 /* Cancel Storage daemon */
724 if (jcr->store_bsock) {
725 /* do not return now, we want to try to cancel the sd socket */
726 cancel_sd_job(ua, cmd, jcr);
729 /* We test file_bsock because the previous operation can take
732 if (jcr->store_bsock && cancel) {
733 jcr->store_bsock->set_timed_out();
734 jcr->store_bsock->set_terminated();
735 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
736 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
739 /* Cancel Copy/Migration Storage daemon */
741 /* The wjcr is valid until we call free_jcr(jcr) */
742 JCR *wjcr = jcr->wjcr;
744 if (wjcr->store_bsock) {
745 /* do not return now, we want to try to cancel the sd socket */
746 cancel_sd_job(ua, cmd, wjcr);
748 /* We test file_bsock because the previous operation can take
751 if (wjcr->store_bsock && cancel) {
752 wjcr->store_bsock->set_timed_out();
753 wjcr->store_bsock->set_terminated();
754 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
755 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
764 void cancel_storage_daemon_job(JCR *jcr)
766 if (jcr->sd_canceled) {
767 return; /* cancel only once */
770 UAContext *ua = new_ua_context(jcr);
771 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
774 ua->jcr = control_jcr;
775 if (jcr->store_bsock) {
776 if (!ua->jcr->wstorage) {
778 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
780 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
785 store.store = jcr->rstore;
787 store.store = jcr->wstore;
789 set_wstorage(ua->jcr, &store);
792 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
795 Dmsg0(200, "Connected to storage daemon\n");
796 sd = ua->jcr->store_bsock;
797 sd->fsend("cancel Job=%s\n", jcr->Job);
798 while (sd->recv() >= 0) {
800 sd->signal(BNET_TERMINATE);
801 free_bsock(ua->jcr->store_bsock);
802 jcr->sd_canceled = true;
803 jcr->store_bsock->set_timed_out();
804 jcr->store_bsock->set_terminated();
805 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
806 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
809 free_jcr(control_jcr);
813 static void job_monitor_destructor(watchdog_t *self)
815 JCR *control_jcr = (JCR *)self->data;
817 free_jcr(control_jcr);
820 static void job_monitor_watchdog(watchdog_t *self)
822 JCR *control_jcr, *jcr;
824 control_jcr = (JCR *)self->data;
827 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
832 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
833 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
837 /* check MaxWaitTime */
838 if (job_check_maxwaittime(jcr)) {
839 jcr->setJobStatus(JS_Canceled);
840 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
842 /* check MaxRunTime */
843 } else if (job_check_maxruntime(jcr)) {
844 jcr->setJobStatus(JS_Canceled);
845 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
847 /* check MaxRunSchedTime */
848 } else if (job_check_maxrunschedtime(jcr)) {
849 jcr->setJobStatus(JS_Canceled);
850 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
855 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
856 UAContext *ua = new_ua_context(jcr);
857 ua->jcr = control_jcr;
860 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
864 /* Keep reference counts correct */
869 * Check if the maxwaittime has expired and it is possible
872 static bool job_check_maxwaittime(JCR *jcr)
878 if (!job_waiting(jcr)) {
882 if (jcr->wait_time) {
883 current = watchdog_time - jcr->wait_time;
886 Dmsg2(200, "check maxwaittime %u >= %u\n",
887 current + jcr->wait_time_sum, job->MaxWaitTime);
888 if (job->MaxWaitTime != 0 &&
889 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
897 * Check if maxruntime has expired and if the job can be
900 static bool job_check_maxruntime(JCR *jcr)
906 if (job_canceled(jcr) || !jcr->job_started) {
909 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
910 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
913 run_time = watchdog_time - jcr->start_time;
914 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
915 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
916 job->IncMaxRunTime, job->DiffMaxRunTime);
918 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
919 run_time >= job->FullMaxRunTime) {
920 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
922 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
923 run_time >= job->DiffMaxRunTime) {
924 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
926 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
927 run_time >= job->IncMaxRunTime) {
928 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
930 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
931 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
939 * Check if MaxRunSchedTime has expired and if the job can be
942 static bool job_check_maxrunschedtime(JCR *jcr)
944 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
947 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
948 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
949 jcr, jcr->Job, jcr->MaxRunSchedTime);
957 * Get or create a Pool record with the given name.
958 * Returns: 0 on error
961 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
965 memset(&pr, 0, sizeof(pr));
966 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
967 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
969 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
970 /* Try to create the pool */
971 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
972 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
973 db_strerror(jcr->db));
976 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
983 * Check for duplicate jobs.
984 * Returns: true if current job should continue
985 * false if current job should terminate
987 bool allow_duplicate_job(JCR *jcr)
990 JCR *djcr; /* possible duplicate job */
992 /* Is AllowDuplicateJobs is set or is duplicate checking
993 * disabled for this job? */
994 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
997 Dmsg0(800, "Enter allow_duplicate_job\n");
999 * After this point, we do not want to allow any duplicate
1004 if (jcr == djcr || djcr->JobId == 0) {
1005 continue; /* do not cancel this job or consoles */
1007 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1008 * if so do not check it against other jobs */
1009 if (djcr->IgnoreDuplicateJobChecking) {
1012 if (strcmp(job->name(), djcr->job->name()) == 0) {
1013 bool cancel_dup = false;
1014 bool cancel_me = false;
1015 if (job->DuplicateJobProximity > 0) {
1016 utime_t now = (utime_t)time(NULL);
1017 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1018 continue; /* not really a duplicate */
1021 if (job->CancelLowerLevelDuplicates &&
1022 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1023 switch (jcr->getJobLevel()) {
1025 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1026 djcr->getJobLevel() == L_INCREMENTAL) {
1030 case L_DIFFERENTIAL:
1031 if (djcr->getJobLevel() == L_INCREMENTAL) {
1034 if (djcr->getJobLevel() == L_FULL) {
1039 if (djcr->getJobLevel() == L_FULL ||
1040 djcr->getJobLevel() == L_DIFFERENTIAL) {
1045 * cancel_dup will be done below
1048 /* Zap current job */
1049 jcr->setJobStatus(JS_Canceled);
1050 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1052 break; /* get out of foreach_jcr */
1055 /* Cancel one of the two jobs (me or dup) */
1056 /* If CancelQueuedDuplicates is set do so only if job is queued */
1057 if (job->CancelQueuedDuplicates) {
1058 switch (djcr->JobStatus) {
1061 case JS_WaitClientRes:
1062 case JS_WaitStoreRes:
1063 case JS_WaitPriority:
1064 case JS_WaitMaxJobs:
1065 case JS_WaitStartTime:
1067 cancel_dup = true; /* cancel queued duplicate */
1073 if (cancel_dup || job->CancelRunningDuplicates) {
1074 /* Zap the duplicated job djcr */
1075 UAContext *ua = new_ua_context(jcr);
1076 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1077 cancel_job(ua, djcr);
1078 bmicrosleep(0, 500000);
1079 djcr->setJobStatus(JS_Canceled);
1080 cancel_job(ua, djcr);
1081 free_ua_context(ua);
1082 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1084 /* Zap current job */
1085 jcr->setJobStatus(JS_Canceled);
1086 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1088 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1090 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1091 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1092 break; /* did our work, get out of foreach loop */
1101 * Apply pool overrides to get the storage properly setup.
1103 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1107 Dmsg1(100, "Original pool=%s\n", opool->name());
1108 if (jcr->cmdline_next_pool_override) {
1109 /* Can be Command line or User input */
1110 source = NPRT(jcr->next_pool_source);
1111 } else if (jcr->run_next_pool_override) {
1112 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1113 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1114 source = _("Run NextPool override");
1115 } else if (jcr->job->next_pool) {
1116 /* Use Job Next Pool */
1117 jcr->next_pool = jcr->job->next_pool;
1118 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1119 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1120 source = _("Job's NextPool resource");
1122 /* Default to original pool->NextPool */
1123 jcr->next_pool = opool->NextPool;
1124 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1125 if (jcr->next_pool) {
1126 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1128 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1129 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1130 source = _("Pool's NextPool resource");
1134 * If the original backup pool has a NextPool, make sure a
1135 * record exists in the database.
1137 if (jcr->next_pool) {
1138 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1139 if (jcr->jr.PoolId == 0) {
1144 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1148 /* Set write pool and source. Not read pool is in rpool. */
1149 jcr->pool = jcr->next_pool;
1150 pm_strcpy(jcr->pool_source, source);
1156 void apply_pool_overrides(JCR *jcr)
1158 bool pool_override = false;
1160 if (jcr->run_pool_override) {
1161 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1164 * Apply any level related Pool selections
1166 switch (jcr->getJobLevel()) {
1168 if (jcr->full_pool) {
1169 jcr->pool = jcr->full_pool;
1170 pool_override = true;
1171 if (jcr->run_full_pool_override) {
1172 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1174 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1178 case L_VIRTUAL_FULL:
1179 if (jcr->vfull_pool) {
1180 jcr->pool = jcr->vfull_pool;
1181 pool_override = true;
1182 if (jcr->run_vfull_pool_override) {
1183 pm_strcpy(jcr->pool_source, _("Run VFullPool override"));
1185 pm_strcpy(jcr->pool_source, _("Job VFullPool override"));
1190 if (jcr->inc_pool) {
1191 jcr->pool = jcr->inc_pool;
1192 pool_override = true;
1193 if (jcr->run_inc_pool_override) {
1194 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1196 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1200 case L_DIFFERENTIAL:
1201 if (jcr->diff_pool) {
1202 jcr->pool = jcr->diff_pool;
1203 pool_override = true;
1204 if (jcr->run_diff_pool_override) {
1205 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1207 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1212 /* Update catalog if pool overridden */
1213 if (pool_override && jcr->pool->catalog) {
1214 jcr->catalog = jcr->pool->catalog;
1215 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1221 * Get or create a Client record for this Job
1223 bool get_or_create_client_record(JCR *jcr)
1228 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1231 memset(&cr, 0, sizeof(cr));
1232 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1233 cr.AutoPrune = jcr->client->AutoPrune;
1234 cr.FileRetention = jcr->client->FileRetention;
1235 cr.JobRetention = jcr->client->JobRetention;
1236 if (!jcr->client_name) {
1237 jcr->client_name = get_pool_memory(PM_NAME);
1239 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1240 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1241 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1242 db_strerror(jcr->db));
1245 jcr->jr.ClientId = cr.ClientId;
1247 if (!jcr->client_uname) {
1248 jcr->client_uname = get_pool_memory(PM_NAME);
1250 pm_strcpy(jcr->client_uname, cr.Uname);
1252 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1258 * Get or Create FileSet record
1260 bool get_or_create_fileset_record(JCR *jcr)
1264 memset(&fsr, 0, sizeof(FILESET_DBR));
1265 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1266 if (jcr->fileset->have_MD5) {
1267 struct MD5Context md5c;
1268 unsigned char digest[MD5HashSize];
1269 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1270 MD5Final(digest, &md5c);
1272 * Keep the flag (last arg) set to false otherwise old FileSets will
1273 * get new MD5 sums and the user will get Full backups on everything
1275 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1276 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1278 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1280 if (!jcr->fileset->ignore_fs_changes ||
1281 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1282 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1283 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1284 fsr.FileSet, db_strerror(jcr->db));
1288 jcr->jr.FileSetId = fsr.FileSetId;
1289 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1290 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1295 void init_jcr_job_record(JCR *jcr)
1297 jcr->jr.SchedTime = jcr->sched_time;
1298 jcr->jr.StartTime = jcr->start_time;
1299 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1300 jcr->jr.JobType = jcr->getJobType();
1301 jcr->jr.JobLevel = jcr->getJobLevel();
1302 jcr->jr.JobStatus = jcr->JobStatus;
1303 jcr->jr.JobId = jcr->JobId;
1304 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1305 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1309 * Write status and such in DB
1311 void update_job_end_record(JCR *jcr)
1313 jcr->jr.EndTime = time(NULL);
1314 jcr->end_time = jcr->jr.EndTime;
1315 jcr->jr.JobId = jcr->JobId;
1316 jcr->jr.JobStatus = jcr->JobStatus;
1317 jcr->jr.JobFiles = jcr->JobFiles;
1318 jcr->jr.JobBytes = jcr->JobBytes;
1319 jcr->jr.ReadBytes = jcr->ReadBytes;
1320 jcr->jr.VolSessionId = jcr->VolSessionId;
1321 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1322 jcr->jr.JobErrors = jcr->JobErrors;
1323 jcr->jr.HasBase = jcr->HasBase;
1324 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1325 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1326 db_strerror(jcr->db));
1331 * Takes base_name and appends (unique) current
1332 * date and time to form unique job name.
1334 * Note, the seconds are actually a sequence number. This
1335 * permits us to start a maximum fo 59 unique jobs a second, which
1336 * should be sufficient.
1338 * Returns: unique job name in jcr->Job
1339 * date/time in jcr->start_time
1341 void create_unique_job_name(JCR *jcr, const char *base_name)
1343 /* Job start mutex */
1344 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1345 static time_t last_start_time = 0;
1347 time_t now = time(NULL);
1349 char dt[MAX_TIME_LENGTH];
1350 char name[MAX_NAME_LENGTH];
1355 /* Guarantee unique start time -- maximum one per second, and
1356 * thus unique Job Name
1358 P(mutex); /* lock creation of jobs */
1360 if (seq > 59) { /* wrap as if it is seconds */
1362 while (now == last_start_time) {
1363 bmicrosleep(0, 500000);
1367 last_start_time = now;
1369 V(mutex); /* allow creation of jobs */
1370 jcr->start_time = now;
1371 /* Form Unique JobName */
1372 (void)localtime_r(&now, &tm);
1373 /* Use only characters that are permitted in Windows filenames */
1374 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1375 len = strlen(dt) + 5; /* dt + .%02d EOS */
1376 bstrncpy(name, base_name, sizeof(name));
1377 name[sizeof(name)-len] = 0; /* truncate if too long */
1378 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1379 /* Convert spaces into underscores */
1380 for (p=jcr->Job; *p; p++) {
1385 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1388 /* Called directly from job rescheduling */
1389 void dird_free_jcr_pointers(JCR *jcr)
1391 /* Close but do not free bsock packets */
1392 if (jcr->file_bsock) {
1393 Dmsg0(200, "Close File bsock\n");
1394 jcr->file_bsock->close();
1396 if (jcr->store_bsock) {
1397 Dmsg0(200, "Close Store bsock\n");
1398 jcr->store_bsock->close();
1401 bfree_and_null(jcr->sd_auth_key);
1402 bfree_and_null(jcr->where);
1403 bfree_and_null(jcr->RestoreBootstrap);
1404 jcr->cached_attribute = false;
1405 bfree_and_null(jcr->ar);
1407 free_and_null_pool_memory(jcr->JobIds);
1408 free_and_null_pool_memory(jcr->client_uname);
1409 free_and_null_pool_memory(jcr->attr);
1410 free_and_null_pool_memory(jcr->fname);
1411 free_and_null_pool_memory(jcr->media_type);
1415 * Free the Job Control Record if no one is still using it.
1416 * Called from main free_jcr() routine in src/lib/jcr.c so
1417 * that we can do our Director specific cleanup of the jcr.
1419 void dird_free_jcr(JCR *jcr)
1421 Dmsg0(200, "Start dird free_jcr\n");
1423 dird_free_jcr_pointers(jcr);
1425 free_jcr(jcr->wjcr);
1428 /* Free bsock packets */
1429 free_bsock(jcr->file_bsock);
1430 free_bsock(jcr->store_bsock);
1431 if (jcr->term_wait_inited) {
1432 pthread_cond_destroy(&jcr->term_wait);
1433 jcr->term_wait_inited = false;
1435 if (jcr->db_batch) {
1436 db_close_database(jcr, jcr->db_batch);
1437 jcr->db_batch = NULL;
1438 jcr->batch_started = false;
1441 db_close_database(jcr, jcr->db);
1445 free_and_null_pool_memory(jcr->stime);
1446 free_and_null_pool_memory(jcr->fname);
1447 free_and_null_pool_memory(jcr->pool_source);
1448 free_and_null_pool_memory(jcr->next_pool_source);
1449 free_and_null_pool_memory(jcr->catalog_source);
1450 free_and_null_pool_memory(jcr->rpool_source);
1451 free_and_null_pool_memory(jcr->wstore_source);
1452 free_and_null_pool_memory(jcr->rstore_source);
1453 free_and_null_pool_memory(jcr->next_vol_list);
1455 /* Delete lists setup to hold storage pointers */
1456 free_rwstorage(jcr);
1458 jcr->job_end_push.destroy();
1460 if (jcr->JobId != 0) {
1461 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1464 free_plugins(jcr); /* release instantiated plugins */
1466 Dmsg0(200, "End dird free_jcr\n");
1470 * The Job storage definition must be either in the Job record
1471 * or in the Pool record. The Pool record overrides the Job
1474 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1476 if (run && run->pool && run->pool->storage) {
1477 store->store = (STORE *)run->pool->storage->first();
1478 pm_strcpy(store->store_source, _("Run pool override"));
1481 if (run && run->storage) {
1482 store->store = run->storage;
1483 pm_strcpy(store->store_source, _("Run storage override"));
1486 if (job->pool->storage) {
1487 store->store = (STORE *)job->pool->storage->first();
1488 pm_strcpy(store->store_source, _("Pool resource"));
1490 store->store = (STORE *)job->storage->first();
1491 pm_strcpy(store->store_source, _("Job resource"));
1496 * Set some defaults in the JCR necessary to
1497 * run. These items are pulled from the job
1498 * definition as defaults, but can be overridden
1499 * later either by the Run record in the Schedule resource,
1500 * or by the Console program.
1502 void set_jcr_defaults(JCR *jcr, JOB *job)
1505 jcr->setJobType(job->JobType);
1506 jcr->JobStatus = JS_Created;
1508 switch (jcr->getJobType()) {
1510 jcr->setJobLevel(L_NONE);
1513 jcr->setJobLevel(job->JobLevel);
1516 if (!jcr->next_vol_list) {
1517 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1520 jcr->fname = get_pool_memory(PM_FNAME);
1522 if (!jcr->pool_source) {
1523 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1525 if (!jcr->next_pool_source) {
1526 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1528 if (!jcr->catalog_source) {
1529 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1532 jcr->JobPriority = job->Priority;
1533 /* Copy storage definitions -- deleted in dir_free_jcr above */
1535 copy_rwstorage(jcr, job->storage, _("Job resource"));
1537 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1539 jcr->client = job->client;
1540 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1541 if (!jcr->client_name) {
1542 jcr->client_name = get_pool_memory(PM_NAME);
1544 pm_strcpy(jcr->client_name, jcr->client->name());
1545 jcr->pool = job->pool;
1546 pm_strcpy(jcr->pool_source, _("Job resource"));
1547 if (job->next_pool) {
1548 /* Use Job's Next Pool */
1549 jcr->next_pool = job->next_pool;
1550 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1552 /* Default to original pool->NextPool */
1553 jcr->next_pool = job->pool->NextPool;
1554 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1556 jcr->full_pool = job->full_pool;
1557 jcr->vfull_pool = job->vfull_pool;
1558 jcr->inc_pool = job->inc_pool;
1559 jcr->diff_pool = job->diff_pool;
1560 if (job->pool->catalog) {
1561 jcr->catalog = job->pool->catalog;
1562 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1564 jcr->catalog = job->client->catalog;
1565 pm_strcpy(jcr->catalog_source, _("Client resource"));
1567 jcr->fileset = job->fileset;
1568 jcr->accurate = job->accurate;
1569 jcr->messages = job->messages;
1570 jcr->spool_data = job->spool_data;
1571 jcr->spool_size = job->spool_size;
1572 jcr->write_part_after_job = job->write_part_after_job;
1573 jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
1574 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1575 if (jcr->RestoreBootstrap) {
1576 free(jcr->RestoreBootstrap);
1577 jcr->RestoreBootstrap = NULL;
1579 /* This can be overridden by Console program */
1580 if (job->RestoreBootstrap) {
1581 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1583 /* This can be overridden by Console program */
1584 jcr->verify_job = job->verify_job;
1585 /* If no default level given, set one */
1586 if (jcr->getJobLevel() == 0) {
1587 switch (jcr->getJobType()) {
1589 jcr->setJobLevel(L_VERIFY_CATALOG);
1592 jcr->setJobLevel(L_INCREMENTAL);
1596 jcr->setJobLevel(L_NONE);
1599 jcr->setJobLevel(L_FULL);
1606 * Copy the storage definitions from an alist to the JCR
1608 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1610 if (jcr->JobReads()) {
1611 copy_rstorage(jcr, storage, where);
1613 copy_wstorage(jcr, storage, where);
1617 /* Set storage override. Releases any previous storage definition */
1618 void set_rwstorage(JCR *jcr, USTORE *store)
1621 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1624 if (jcr->JobReads()) {
1625 set_rstorage(jcr, store);
1627 set_wstorage(jcr, store);
1630 void free_rwstorage(JCR *jcr)
1637 * Copy the storage definitions from an alist to the JCR
1639 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1643 if (jcr->rstorage) {
1644 delete jcr->rstorage;
1646 jcr->rstorage = New(alist(10, not_owned_by_alist));
1647 foreach_alist(st, storage) {
1648 jcr->rstorage->append(st);
1650 if (!jcr->rstore_source) {
1651 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1653 pm_strcpy(jcr->rstore_source, where);
1654 if (jcr->rstorage) {
1655 jcr->rstore = (STORE *)jcr->rstorage->first();
1661 /* Set storage override. Remove all previous storage */
1662 void set_rstorage(JCR *jcr, USTORE *store)
1666 if (!store->store) {
1669 if (jcr->rstorage) {
1672 if (!jcr->rstorage) {
1673 jcr->rstorage = New(alist(10, not_owned_by_alist));
1675 jcr->rstore = store->store;
1676 if (!jcr->rstore_source) {
1677 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1679 pm_strcpy(jcr->rstore_source, store->store_source);
1680 foreach_alist(storage, jcr->rstorage) {
1681 if (store->store == storage) {
1685 /* Store not in list, so add it */
1686 jcr->rstorage->prepend(store->store);
1689 void free_rstorage(JCR *jcr)
1691 if (jcr->rstorage) {
1692 delete jcr->rstorage;
1693 jcr->rstorage = NULL;
1699 * Copy the storage definitions from an alist to the JCR
1701 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1705 if (jcr->wstorage) {
1706 delete jcr->wstorage;
1708 jcr->wstorage = New(alist(10, not_owned_by_alist));
1709 foreach_alist(st, storage) {
1710 Dmsg1(100, "wstorage=%s\n", st->name());
1711 jcr->wstorage->append(st);
1713 if (!jcr->wstore_source) {
1714 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1716 pm_strcpy(jcr->wstore_source, where);
1717 if (jcr->wstorage) {
1718 jcr->wstore = (STORE *)jcr->wstorage->first();
1719 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1725 /* Set storage override. Remove all previous storage */
1726 void set_wstorage(JCR *jcr, USTORE *store)
1730 if (!store->store) {
1733 if (jcr->wstorage) {
1736 if (!jcr->wstorage) {
1737 jcr->wstorage = New(alist(10, not_owned_by_alist));
1739 jcr->wstore = store->store;
1740 if (!jcr->wstore_source) {
1741 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1743 pm_strcpy(jcr->wstore_source, store->store_source);
1744 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1745 foreach_alist(storage, jcr->wstorage) {
1746 if (store->store == storage) {
1750 /* Store not in list, so add it */
1751 jcr->wstorage->prepend(store->store);
1754 void free_wstorage(JCR *jcr)
1756 if (jcr->wstorage) {
1757 delete jcr->wstorage;
1758 jcr->wstorage = NULL;
1763 void create_clones(JCR *jcr)
1766 * Fire off any clone jobs (run directives)
1768 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1769 if (!jcr->cloned && jcr->job->run_cmds) {
1771 JOB *job = jcr->job;
1772 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1773 UAContext *ua = new_ua_context(jcr);
1775 foreach_alist(runcmd, job->run_cmds) {
1776 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1777 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1778 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1779 parse_ua_args(ua); /* parse command */
1780 int stat = run_cmd(ua, ua->cmd);
1782 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1785 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1788 free_ua_context(ua);
1789 free_pool_memory(cmd);
1794 * Given: a JobId in jcr->previous_jr.JobId,
1795 * this subroutine writes a bsr file to restore that job.
1796 * Returns: -1 on error
1797 * number of files if OK
1799 int create_restore_bootstrap_file(JCR *jcr)
1805 memset(&rx, 0, sizeof(rx));
1807 rx.JobIds = (char *)"";
1808 rx.bsr->JobId = jcr->previous_jr.JobId;
1809 ua = new_ua_context(jcr);
1810 if (!complete_bsr(ua, rx.bsr)) {
1814 rx.bsr->fi = new_findex();
1815 rx.bsr->fi->findex = 1;
1816 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1817 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1818 if (jcr->ExpectedFiles == 0) {
1822 free_ua_context(ua);
1824 jcr->needs_sd = true;
1825 return jcr->ExpectedFiles;
1828 free_ua_context(ua);
1833 /* TODO: redirect command ouput to job log */
1834 bool run_console_command(JCR *jcr, const char *cmd)
1838 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1839 ua = new_ua_context(ljcr);
1840 /* run from runscript and check if commands are authorized */
1841 ua->runscript = true;
1842 Mmsg(ua->cmd, "%s", cmd);
1843 Dmsg1(100, "Console command: %s\n", ua->cmd);
1845 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1846 ok = do_a_dot_command(ua);
1848 ok = do_a_command(ua);
1850 free_ua_context(ua);