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);
657 * Cancel a job -- typically called by the UA (Console program), but may also
658 * be called by the job watchdog.
660 * Returns: true if cancel appears to be successful
661 * false on failure. Message sent to ua->jcr.
664 cancel_job(UAContext *ua, JCR *jcr, bool cancel)
667 int32_t old_status = jcr->JobStatus;
669 const char *reason, *cmd;
670 bool force = find_arg(ua, "inactive") > 0;
672 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
674 /* If the user explicitely ask, we can send the cancel command to
677 if (cancel && force) {
678 return cancel_inactive_job(ua, jcr);
682 status = JS_Canceled;
683 reason = _("canceled");
686 status = JS_Incomplete;
687 reason = _("stopped");
689 jcr->RescheduleIncompleteJobs = false; /* do not restart */
692 jcr->setJobStatus(status);
694 switch (old_status) {
697 case JS_WaitClientRes:
698 case JS_WaitStoreRes:
699 case JS_WaitPriority:
701 case JS_WaitStartTime:
703 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
704 edit_uint64(jcr->JobId, ed1), jcr->Job,
706 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
711 /* Cancel File daemon */
712 if (jcr->file_bsock) {
713 /* do not return now, we want to try to cancel the sd */
714 cancel_file_daemon_job(ua, cmd, jcr);
717 /* We test file_bsock because the previous operation can take
720 if (jcr->file_bsock && cancel) {
721 jcr->file_bsock->set_terminated();
722 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
725 /* Cancel Storage daemon */
726 if (jcr->store_bsock) {
727 /* do not return now, we want to try to cancel the sd socket */
728 cancel_sd_job(ua, cmd, jcr);
731 /* We test file_bsock because the previous operation can take
734 if (jcr->store_bsock && cancel) {
735 jcr->store_bsock->set_timed_out();
736 jcr->store_bsock->set_terminated();
737 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
738 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
741 /* Cancel Copy/Migration Storage daemon */
743 /* The wjcr is valid until we call free_jcr(jcr) */
744 JCR *wjcr = jcr->wjcr;
746 if (wjcr->store_bsock) {
747 /* do not return now, we want to try to cancel the sd socket */
748 cancel_sd_job(ua, cmd, wjcr);
750 /* We test file_bsock because the previous operation can take
753 if (wjcr->store_bsock && cancel) {
754 wjcr->store_bsock->set_timed_out();
755 wjcr->store_bsock->set_terminated();
756 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
757 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
766 void cancel_storage_daemon_job(JCR *jcr)
768 if (jcr->sd_canceled) {
769 return; /* cancel only once */
772 UAContext *ua = new_ua_context(jcr);
773 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
776 ua->jcr = control_jcr;
777 if (jcr->store_bsock) {
778 if (!ua->jcr->wstorage) {
780 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
782 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
787 store.store = jcr->rstore;
789 store.store = jcr->wstore;
791 set_wstorage(ua->jcr, &store);
794 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
797 Dmsg0(200, "Connected to storage daemon\n");
798 sd = ua->jcr->store_bsock;
799 sd->fsend("cancel Job=%s\n", jcr->Job);
800 while (sd->recv() >= 0) {
802 sd->signal(BNET_TERMINATE);
803 free_bsock(ua->jcr->store_bsock);
804 jcr->sd_canceled = true;
805 jcr->store_bsock->set_timed_out();
806 jcr->store_bsock->set_terminated();
807 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
808 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
811 free_jcr(control_jcr);
815 static void job_monitor_destructor(watchdog_t *self)
817 JCR *control_jcr = (JCR *)self->data;
819 free_jcr(control_jcr);
822 static void job_monitor_watchdog(watchdog_t *self)
824 JCR *control_jcr, *jcr;
826 control_jcr = (JCR *)self->data;
829 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
834 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
835 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
839 /* check MaxWaitTime */
840 if (job_check_maxwaittime(jcr)) {
841 jcr->setJobStatus(JS_Canceled);
842 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
844 /* check MaxRunTime */
845 } else if (job_check_maxruntime(jcr)) {
846 jcr->setJobStatus(JS_Canceled);
847 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
849 /* check MaxRunSchedTime */
850 } else if (job_check_maxrunschedtime(jcr)) {
851 jcr->setJobStatus(JS_Canceled);
852 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
857 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
858 UAContext *ua = new_ua_context(jcr);
859 ua->jcr = control_jcr;
862 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
866 /* Keep reference counts correct */
871 * Check if the maxwaittime has expired and it is possible
874 static bool job_check_maxwaittime(JCR *jcr)
880 if (!job_waiting(jcr)) {
884 if (jcr->wait_time) {
885 current = watchdog_time - jcr->wait_time;
888 Dmsg2(200, "check maxwaittime %u >= %u\n",
889 current + jcr->wait_time_sum, job->MaxWaitTime);
890 if (job->MaxWaitTime != 0 &&
891 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
899 * Check if maxruntime has expired and if the job can be
902 static bool job_check_maxruntime(JCR *jcr)
908 if (job_canceled(jcr) || !jcr->job_started) {
911 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
912 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
915 run_time = watchdog_time - jcr->start_time;
916 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
917 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
918 job->IncMaxRunTime, job->DiffMaxRunTime);
920 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
921 run_time >= job->FullMaxRunTime) {
922 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
924 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
925 run_time >= job->DiffMaxRunTime) {
926 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
928 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
929 run_time >= job->IncMaxRunTime) {
930 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
932 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
933 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
941 * Check if MaxRunSchedTime has expired and if the job can be
944 static bool job_check_maxrunschedtime(JCR *jcr)
946 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
949 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
950 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
951 jcr, jcr->Job, jcr->MaxRunSchedTime);
959 * Get or create a Pool record with the given name.
960 * Returns: 0 on error
963 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
967 memset(&pr, 0, sizeof(pr));
968 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
969 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
971 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
972 /* Try to create the pool */
973 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
974 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
975 db_strerror(jcr->db));
978 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
985 * Check for duplicate jobs.
986 * Returns: true if current job should continue
987 * false if current job should terminate
989 bool allow_duplicate_job(JCR *jcr)
992 JCR *djcr; /* possible duplicate job */
994 /* Is AllowDuplicateJobs is set or is duplicate checking
995 * disabled for this job? */
996 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
999 Dmsg0(800, "Enter allow_duplicate_job\n");
1001 * After this point, we do not want to allow any duplicate
1006 if (jcr == djcr || djcr->JobId == 0) {
1007 continue; /* do not cancel this job or consoles */
1009 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1010 * if so do not check it against other jobs */
1011 if (djcr->IgnoreDuplicateJobChecking) {
1014 if ((strcmp(job->name(), djcr->job->name()) == 0) &&
1015 djcr->getJobType() == jcr->getJobType()) /* A duplicate is about the same name and the same type */
1017 bool cancel_dup = false;
1018 bool cancel_me = false;
1019 if (job->DuplicateJobProximity > 0) {
1020 utime_t now = (utime_t)time(NULL);
1021 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1022 continue; /* not really a duplicate */
1025 if (job->CancelLowerLevelDuplicates &&
1026 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1027 switch (jcr->getJobLevel()) {
1029 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1030 djcr->getJobLevel() == L_INCREMENTAL) {
1034 case L_DIFFERENTIAL:
1035 if (djcr->getJobLevel() == L_INCREMENTAL) {
1038 if (djcr->getJobLevel() == L_FULL) {
1043 if (djcr->getJobLevel() == L_FULL ||
1044 djcr->getJobLevel() == L_DIFFERENTIAL) {
1049 * cancel_dup will be done below
1052 /* Zap current job */
1053 jcr->setJobStatus(JS_Canceled);
1054 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1056 break; /* get out of foreach_jcr */
1059 /* Cancel one of the two jobs (me or dup) */
1060 /* If CancelQueuedDuplicates is set do so only if job is queued */
1061 if (job->CancelQueuedDuplicates) {
1062 switch (djcr->JobStatus) {
1065 case JS_WaitClientRes:
1066 case JS_WaitStoreRes:
1067 case JS_WaitPriority:
1068 case JS_WaitMaxJobs:
1069 case JS_WaitStartTime:
1071 cancel_dup = true; /* cancel queued duplicate */
1077 if (cancel_dup || job->CancelRunningDuplicates) {
1078 /* Zap the duplicated job djcr */
1079 UAContext *ua = new_ua_context(jcr);
1080 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1081 cancel_job(ua, djcr);
1082 bmicrosleep(0, 500000);
1083 djcr->setJobStatus(JS_Canceled);
1084 cancel_job(ua, djcr);
1085 free_ua_context(ua);
1086 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1088 /* Zap current job */
1089 jcr->setJobStatus(JS_Canceled);
1090 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1092 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1094 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1095 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1096 break; /* did our work, get out of foreach loop */
1105 * Apply pool overrides to get the storage properly setup.
1107 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1111 Dmsg1(100, "Original pool=%s\n", opool->name());
1112 if (jcr->cmdline_next_pool_override) {
1113 /* Can be Command line or User input */
1114 source = NPRT(jcr->next_pool_source);
1115 } else if (jcr->run_next_pool_override) {
1116 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1117 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1118 source = _("Run NextPool override");
1119 } else if (jcr->job->next_pool) {
1120 /* Use Job Next Pool */
1121 jcr->next_pool = jcr->job->next_pool;
1122 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1123 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1124 source = _("Job's NextPool resource");
1126 /* Default to original pool->NextPool */
1127 jcr->next_pool = opool->NextPool;
1128 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1129 if (jcr->next_pool) {
1130 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1132 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1133 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1134 source = _("Pool's NextPool resource");
1138 * If the original backup pool has a NextPool, make sure a
1139 * record exists in the database.
1141 if (jcr->next_pool) {
1142 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1143 if (jcr->jr.PoolId == 0) {
1148 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1152 /* Set write pool and source. Not read pool is in rpool. */
1153 jcr->pool = jcr->next_pool;
1154 pm_strcpy(jcr->pool_source, source);
1160 void apply_pool_overrides(JCR *jcr)
1162 bool pool_override = false;
1164 if (jcr->run_pool_override) {
1165 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1168 * Apply any level related Pool selections
1170 switch (jcr->getJobLevel()) {
1172 if (jcr->full_pool) {
1173 jcr->pool = jcr->full_pool;
1174 pool_override = true;
1175 if (jcr->run_full_pool_override) {
1176 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1178 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1182 case L_VIRTUAL_FULL:
1183 if (jcr->vfull_pool) {
1184 jcr->pool = jcr->vfull_pool;
1185 pool_override = true;
1186 if (jcr->run_vfull_pool_override) {
1187 pm_strcpy(jcr->pool_source, _("Run VFullPool override"));
1189 pm_strcpy(jcr->pool_source, _("Job VFullPool override"));
1194 if (jcr->inc_pool) {
1195 jcr->pool = jcr->inc_pool;
1196 pool_override = true;
1197 if (jcr->run_inc_pool_override) {
1198 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1200 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1204 case L_DIFFERENTIAL:
1205 if (jcr->diff_pool) {
1206 jcr->pool = jcr->diff_pool;
1207 pool_override = true;
1208 if (jcr->run_diff_pool_override) {
1209 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1211 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1216 /* Update catalog if pool overridden */
1217 if (pool_override && jcr->pool->catalog) {
1218 jcr->catalog = jcr->pool->catalog;
1219 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1225 * Get or create a Client record for this Job
1227 bool get_or_create_client_record(JCR *jcr)
1232 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1235 memset(&cr, 0, sizeof(cr));
1236 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1237 cr.AutoPrune = jcr->client->AutoPrune;
1238 cr.FileRetention = jcr->client->FileRetention;
1239 cr.JobRetention = jcr->client->JobRetention;
1240 if (!jcr->client_name) {
1241 jcr->client_name = get_pool_memory(PM_NAME);
1243 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1244 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1245 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1246 db_strerror(jcr->db));
1249 jcr->jr.ClientId = cr.ClientId;
1251 if (!jcr->client_uname) {
1252 jcr->client_uname = get_pool_memory(PM_NAME);
1254 pm_strcpy(jcr->client_uname, cr.Uname);
1256 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1262 * Get or Create FileSet record
1264 bool get_or_create_fileset_record(JCR *jcr)
1268 memset(&fsr, 0, sizeof(FILESET_DBR));
1269 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1270 if (jcr->fileset->have_MD5) {
1271 struct MD5Context md5c;
1272 unsigned char digest[MD5HashSize];
1273 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1274 MD5Final(digest, &md5c);
1276 * Keep the flag (last arg) set to false otherwise old FileSets will
1277 * get new MD5 sums and the user will get Full backups on everything
1279 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1280 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1282 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1284 if (!jcr->fileset->ignore_fs_changes ||
1285 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1286 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1287 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1288 fsr.FileSet, db_strerror(jcr->db));
1292 jcr->jr.FileSetId = fsr.FileSetId;
1293 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1294 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1299 void init_jcr_job_record(JCR *jcr)
1301 jcr->jr.SchedTime = jcr->sched_time;
1302 jcr->jr.StartTime = jcr->start_time;
1303 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1304 jcr->jr.JobType = jcr->getJobType();
1305 jcr->jr.JobLevel = jcr->getJobLevel();
1306 jcr->jr.JobStatus = jcr->JobStatus;
1307 jcr->jr.JobId = jcr->JobId;
1308 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1309 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1313 * Write status and such in DB
1315 void update_job_end_record(JCR *jcr)
1317 jcr->jr.EndTime = time(NULL);
1318 jcr->end_time = jcr->jr.EndTime;
1319 jcr->jr.JobId = jcr->JobId;
1320 jcr->jr.JobStatus = jcr->JobStatus;
1321 jcr->jr.JobFiles = jcr->JobFiles;
1322 jcr->jr.JobBytes = jcr->JobBytes;
1323 jcr->jr.ReadBytes = jcr->ReadBytes;
1324 jcr->jr.VolSessionId = jcr->VolSessionId;
1325 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1326 jcr->jr.JobErrors = jcr->JobErrors;
1327 jcr->jr.HasBase = jcr->HasBase;
1328 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1329 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1330 db_strerror(jcr->db));
1335 * Takes base_name and appends (unique) current
1336 * date and time to form unique job name.
1338 * Note, the seconds are actually a sequence number. This
1339 * permits us to start a maximum fo 59 unique jobs a second, which
1340 * should be sufficient.
1342 * Returns: unique job name in jcr->Job
1343 * date/time in jcr->start_time
1345 void create_unique_job_name(JCR *jcr, const char *base_name)
1347 /* Job start mutex */
1348 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1349 static time_t last_start_time = 0;
1351 time_t now = time(NULL);
1353 char dt[MAX_TIME_LENGTH];
1354 char name[MAX_NAME_LENGTH];
1359 /* Guarantee unique start time -- maximum one per second, and
1360 * thus unique Job Name
1362 P(mutex); /* lock creation of jobs */
1364 if (seq > 59) { /* wrap as if it is seconds */
1366 while (now == last_start_time) {
1367 bmicrosleep(0, 500000);
1371 last_start_time = now;
1373 V(mutex); /* allow creation of jobs */
1374 jcr->start_time = now;
1375 /* Form Unique JobName */
1376 (void)localtime_r(&now, &tm);
1377 /* Use only characters that are permitted in Windows filenames */
1378 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1379 len = strlen(dt) + 5; /* dt + .%02d EOS */
1380 bstrncpy(name, base_name, sizeof(name));
1381 name[sizeof(name)-len] = 0; /* truncate if too long */
1382 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1383 /* Convert spaces into underscores */
1384 for (p=jcr->Job; *p; p++) {
1389 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1392 /* Called directly from job rescheduling */
1393 void dird_free_jcr_pointers(JCR *jcr)
1395 /* Close but do not free bsock packets */
1396 if (jcr->file_bsock) {
1397 Dmsg0(200, "Close File bsock\n");
1398 jcr->file_bsock->close();
1400 if (jcr->store_bsock) {
1401 Dmsg0(200, "Close Store bsock\n");
1402 jcr->store_bsock->close();
1405 bfree_and_null(jcr->sd_auth_key);
1406 bfree_and_null(jcr->where);
1407 bfree_and_null(jcr->RestoreBootstrap);
1408 jcr->cached_attribute = false;
1409 bfree_and_null(jcr->ar);
1411 free_and_null_pool_memory(jcr->JobIds);
1412 free_and_null_pool_memory(jcr->client_uname);
1413 free_and_null_pool_memory(jcr->attr);
1414 free_and_null_pool_memory(jcr->fname);
1415 free_and_null_pool_memory(jcr->media_type);
1419 * Free the Job Control Record if no one is still using it.
1420 * Called from main free_jcr() routine in src/lib/jcr.c so
1421 * that we can do our Director specific cleanup of the jcr.
1423 void dird_free_jcr(JCR *jcr)
1425 Dmsg0(200, "Start dird free_jcr\n");
1427 dird_free_jcr_pointers(jcr);
1429 free_jcr(jcr->wjcr);
1432 /* Free bsock packets */
1433 free_bsock(jcr->file_bsock);
1434 free_bsock(jcr->store_bsock);
1435 if (jcr->term_wait_inited) {
1436 pthread_cond_destroy(&jcr->term_wait);
1437 jcr->term_wait_inited = false;
1439 if (jcr->db_batch) {
1440 db_close_database(jcr, jcr->db_batch);
1441 jcr->db_batch = NULL;
1442 jcr->batch_started = false;
1445 db_close_database(jcr, jcr->db);
1449 free_and_null_pool_memory(jcr->stime);
1450 free_and_null_pool_memory(jcr->fname);
1451 free_and_null_pool_memory(jcr->pool_source);
1452 free_and_null_pool_memory(jcr->next_pool_source);
1453 free_and_null_pool_memory(jcr->catalog_source);
1454 free_and_null_pool_memory(jcr->rpool_source);
1455 free_and_null_pool_memory(jcr->wstore_source);
1456 free_and_null_pool_memory(jcr->rstore_source);
1457 free_and_null_pool_memory(jcr->next_vol_list);
1459 /* Delete lists setup to hold storage pointers */
1460 free_rwstorage(jcr);
1462 jcr->job_end_push.destroy();
1464 if (jcr->JobId != 0) {
1465 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1468 free_plugins(jcr); /* release instantiated plugins */
1470 Dmsg0(200, "End dird free_jcr\n");
1474 * The Job storage definition must be either in the Job record
1475 * or in the Pool record. The Pool record overrides the Job
1478 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1480 if (run && run->pool && run->pool->storage) {
1481 store->store = (STORE *)run->pool->storage->first();
1482 pm_strcpy(store->store_source, _("Run pool override"));
1485 if (run && run->storage) {
1486 store->store = run->storage;
1487 pm_strcpy(store->store_source, _("Run storage override"));
1490 if (job->pool->storage) {
1491 store->store = (STORE *)job->pool->storage->first();
1492 pm_strcpy(store->store_source, _("Pool resource"));
1494 store->store = (STORE *)job->storage->first();
1495 pm_strcpy(store->store_source, _("Job resource"));
1500 * Set some defaults in the JCR necessary to
1501 * run. These items are pulled from the job
1502 * definition as defaults, but can be overridden
1503 * later either by the Run record in the Schedule resource,
1504 * or by the Console program.
1506 void set_jcr_defaults(JCR *jcr, JOB *job)
1509 jcr->setJobType(job->JobType);
1510 jcr->JobStatus = JS_Created;
1512 switch (jcr->getJobType()) {
1514 jcr->setJobLevel(L_NONE);
1517 jcr->setJobLevel(job->JobLevel);
1520 if (!jcr->next_vol_list) {
1521 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1524 jcr->fname = get_pool_memory(PM_FNAME);
1526 if (!jcr->pool_source) {
1527 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1529 if (!jcr->next_pool_source) {
1530 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1532 if (!jcr->catalog_source) {
1533 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1536 jcr->JobPriority = job->Priority;
1537 /* Copy storage definitions -- deleted in dir_free_jcr above */
1539 copy_rwstorage(jcr, job->storage, _("Job resource"));
1541 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1543 jcr->client = job->client;
1544 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1545 if (!jcr->client_name) {
1546 jcr->client_name = get_pool_memory(PM_NAME);
1548 pm_strcpy(jcr->client_name, jcr->client->name());
1549 jcr->pool = job->pool;
1550 pm_strcpy(jcr->pool_source, _("Job resource"));
1551 if (job->next_pool) {
1552 /* Use Job's Next Pool */
1553 jcr->next_pool = job->next_pool;
1554 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1556 /* Default to original pool->NextPool */
1557 jcr->next_pool = job->pool->NextPool;
1558 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1560 jcr->full_pool = job->full_pool;
1561 jcr->vfull_pool = job->vfull_pool;
1562 jcr->inc_pool = job->inc_pool;
1563 jcr->diff_pool = job->diff_pool;
1564 if (job->pool->catalog) {
1565 jcr->catalog = job->pool->catalog;
1566 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1568 jcr->catalog = job->client->catalog;
1569 pm_strcpy(jcr->catalog_source, _("Client resource"));
1571 jcr->fileset = job->fileset;
1572 jcr->accurate = job->accurate;
1573 jcr->messages = job->messages;
1574 jcr->spool_data = job->spool_data;
1575 jcr->spool_size = job->spool_size;
1576 jcr->write_part_after_job = job->write_part_after_job;
1577 jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
1578 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1579 if (jcr->RestoreBootstrap) {
1580 free(jcr->RestoreBootstrap);
1581 jcr->RestoreBootstrap = NULL;
1583 /* This can be overridden by Console program */
1584 if (job->RestoreBootstrap) {
1585 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1587 /* This can be overridden by Console program */
1588 jcr->verify_job = job->verify_job;
1589 /* If no default level given, set one */
1590 if (jcr->getJobLevel() == 0) {
1591 switch (jcr->getJobType()) {
1593 jcr->setJobLevel(L_VERIFY_CATALOG);
1596 jcr->setJobLevel(L_INCREMENTAL);
1600 jcr->setJobLevel(L_NONE);
1603 jcr->setJobLevel(L_FULL);
1610 * Copy the storage definitions from an alist to the JCR
1612 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1614 if (jcr->JobReads()) {
1615 copy_rstorage(jcr, storage, where);
1617 copy_wstorage(jcr, storage, where);
1621 /* Set storage override. Releases any previous storage definition */
1622 void set_rwstorage(JCR *jcr, USTORE *store)
1625 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1628 if (jcr->JobReads()) {
1629 set_rstorage(jcr, store);
1631 set_wstorage(jcr, store);
1634 void free_rwstorage(JCR *jcr)
1641 * Copy the storage definitions from an alist to the JCR
1643 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1647 if (jcr->rstorage) {
1648 delete jcr->rstorage;
1650 jcr->rstorage = New(alist(10, not_owned_by_alist));
1651 foreach_alist(st, storage) {
1652 jcr->rstorage->append(st);
1654 if (!jcr->rstore_source) {
1655 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1657 pm_strcpy(jcr->rstore_source, where);
1658 if (jcr->rstorage) {
1659 jcr->rstore = (STORE *)jcr->rstorage->first();
1665 /* Set storage override. Remove all previous storage */
1666 void set_rstorage(JCR *jcr, USTORE *store)
1670 if (!store->store) {
1673 if (jcr->rstorage) {
1676 if (!jcr->rstorage) {
1677 jcr->rstorage = New(alist(10, not_owned_by_alist));
1679 jcr->rstore = store->store;
1680 if (!jcr->rstore_source) {
1681 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1683 pm_strcpy(jcr->rstore_source, store->store_source);
1684 foreach_alist(storage, jcr->rstorage) {
1685 if (store->store == storage) {
1689 /* Store not in list, so add it */
1690 jcr->rstorage->prepend(store->store);
1693 void free_rstorage(JCR *jcr)
1695 if (jcr->rstorage) {
1696 delete jcr->rstorage;
1697 jcr->rstorage = NULL;
1703 * Copy the storage definitions from an alist to the JCR
1705 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1709 if (jcr->wstorage) {
1710 delete jcr->wstorage;
1712 jcr->wstorage = New(alist(10, not_owned_by_alist));
1713 foreach_alist(st, storage) {
1714 Dmsg1(100, "wstorage=%s\n", st->name());
1715 jcr->wstorage->append(st);
1717 if (!jcr->wstore_source) {
1718 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1720 pm_strcpy(jcr->wstore_source, where);
1721 if (jcr->wstorage) {
1722 jcr->wstore = (STORE *)jcr->wstorage->first();
1723 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1729 /* Set storage override. Remove all previous storage */
1730 void set_wstorage(JCR *jcr, USTORE *store)
1734 if (!store->store) {
1737 if (jcr->wstorage) {
1740 if (!jcr->wstorage) {
1741 jcr->wstorage = New(alist(10, not_owned_by_alist));
1743 jcr->wstore = store->store;
1744 if (!jcr->wstore_source) {
1745 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1747 pm_strcpy(jcr->wstore_source, store->store_source);
1748 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1749 foreach_alist(storage, jcr->wstorage) {
1750 if (store->store == storage) {
1754 /* Store not in list, so add it */
1755 jcr->wstorage->prepend(store->store);
1758 void free_wstorage(JCR *jcr)
1760 if (jcr->wstorage) {
1761 delete jcr->wstorage;
1762 jcr->wstorage = NULL;
1767 void create_clones(JCR *jcr)
1770 * Fire off any clone jobs (run directives)
1772 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1773 if (!jcr->cloned && jcr->job->run_cmds) {
1775 JOB *job = jcr->job;
1776 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1777 UAContext *ua = new_ua_context(jcr);
1779 foreach_alist(runcmd, job->run_cmds) {
1780 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1781 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1782 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1783 parse_ua_args(ua); /* parse command */
1784 int stat = run_cmd(ua, ua->cmd);
1786 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1789 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1792 free_ua_context(ua);
1793 free_pool_memory(cmd);
1798 * Given: a JobId in jcr->previous_jr.JobId,
1799 * this subroutine writes a bsr file to restore that job.
1800 * Returns: -1 on error
1801 * number of files if OK
1803 int create_restore_bootstrap_file(JCR *jcr)
1809 memset(&rx, 0, sizeof(rx));
1811 rx.JobIds = (char *)"";
1812 rx.bsr->JobId = jcr->previous_jr.JobId;
1813 ua = new_ua_context(jcr);
1814 if (!complete_bsr(ua, rx.bsr)) {
1818 rx.bsr->fi = new_findex();
1819 rx.bsr->fi->findex = 1;
1820 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1821 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1822 if (jcr->ExpectedFiles == 0) {
1826 free_ua_context(ua);
1828 jcr->needs_sd = true;
1829 return jcr->ExpectedFiles;
1832 free_ua_context(ua);
1837 /* TODO: redirect command ouput to job log */
1838 bool run_console_command(JCR *jcr, const char *cmd)
1842 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1843 ua = new_ua_context(ljcr);
1844 /* run from runscript and check if commands are authorized */
1845 ua->runscript = true;
1846 Mmsg(ua->cmd, "%s", cmd);
1847 Dmsg1(100, "Console command: %s\n", ua->cmd);
1849 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1850 ok = do_a_dot_command(ua);
1852 ok = do_a_command(ua);
1854 free_ua_context(ua);