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->mult_db_connections,
122 jcr->catalog->disable_batch_insert);
123 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
124 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
125 jcr->catalog->db_name);
127 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
128 db_close_database(jcr, jcr->db);
134 Dmsg0(150, "DB opened\n");
136 jcr->fname = get_pool_memory(PM_FNAME);
138 if (!jcr->pool_source) {
139 jcr->pool_source = get_pool_memory(PM_MESSAGE);
140 pm_strcpy(jcr->pool_source, _("unknown source"));
142 if (!jcr->next_pool_source) {
143 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
144 pm_strcpy(jcr->next_pool_source, _("unknown source"));
147 if (jcr->JobReads()) {
148 if (!jcr->rpool_source) {
149 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
150 pm_strcpy(jcr->rpool_source, _("unknown source"));
157 init_jcr_job_record(jcr);
158 if (!get_or_create_client_record(jcr)) {
162 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
163 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
166 jcr->JobId = jcr->jr.JobId;
167 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
168 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
170 generate_daemon_event(jcr, "JobStart");
171 new_plugins(jcr); /* instantiate plugins for this jcr */
172 generate_plugin_event(jcr, bDirEventJobStart);
174 if (job_canceled(jcr)) {
178 if (jcr->JobReads() && !jcr->rstorage) {
179 if (jcr->job->storage) {
180 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
182 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
185 if (!jcr->JobReads()) {
190 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
191 * this allows us to setup a proper job start record for restarting
192 * in case of later errors.
194 switch (jcr->getJobType()) {
196 if (!do_backup_init(jcr)) {
197 backup_cleanup(jcr, JS_ErrorTerminated);
202 if (!do_verify_init(jcr)) {
203 verify_cleanup(jcr, JS_ErrorTerminated);
208 if (!do_restore_init(jcr)) {
209 restore_cleanup(jcr, JS_ErrorTerminated);
214 if (!do_admin_init(jcr)) {
215 admin_cleanup(jcr, JS_ErrorTerminated);
221 if (!do_mac_init(jcr)) {
222 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
227 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
228 jcr->setJobStatus(JS_ErrorTerminated);
232 generate_plugin_event(jcr, bDirEventJobInit);
241 * Setup a job for a resume command
243 static bool setup_resume_job(JCR *jcr, JOB_DBR *jr)
248 init_msg(jcr, jcr->messages);
250 /* Initialize termination condition variable */
251 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
253 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
257 jcr->term_wait_inited = true;
259 jcr->setJobStatus(JS_Created);
265 Dmsg0(100, "Open database\n");
266 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
267 jcr->catalog->db_user, jcr->catalog->db_password,
268 jcr->catalog->db_address, jcr->catalog->db_port,
269 jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
270 jcr->catalog->disable_batch_insert);
271 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
272 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
273 jcr->catalog->db_name);
275 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
276 db_close_database(jcr, jcr->db);
281 Dmsg0(100, "DB opened\n");
283 jcr->fname = get_pool_memory(PM_FNAME);
285 if (!jcr->pool_source) {
286 jcr->pool_source = get_pool_memory(PM_MESSAGE);
287 pm_strcpy(jcr->pool_source, _("unknown source"));
289 if (!jcr->next_pool_source) {
290 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
291 pm_strcpy(jcr->next_pool_source, _("unknown source"));
296 * Setup Job record. Make sure original job is Incomplete.
298 memcpy(&jcr->jr, jr, sizeof(JOB_DBR));
299 jcr->sched_time = jcr->jr.SchedTime;
300 jcr->start_time = jcr->jr.StartTime;
301 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
302 jcr->setJobType(jcr->jr.JobType);
303 jcr->setJobLevel(jcr->jr.JobLevel);
304 jcr->JobId = jcr->jr.JobId;
305 if (!get_or_create_client_record(jcr)) {
306 Dmsg0(100, "Could not create client record.\n");
310 Dmsg6(100, "Got job record JobId=%d Job=%s Name=%s Type=%c Level=%c Status=%c\n",
311 jcr->jr.JobId, jcr->jr.Job, jcr->jr.Name, jcr->jr.JobType, jcr->jr.JobLevel,
313 if (jcr->jr.JobStatus != JS_Incomplete) {
314 /* ***FIXME*** add error message */
315 Dmsg1(100, "Job is not an Incomplete: status=%c\n", jcr->jr.JobStatus);
318 bstrncpy(jcr->Job, jcr->jr.Job, sizeof(jcr->Job));
319 jcr->setJobType(jcr->jr.JobType);
320 jcr->setJobLevel(jcr->jr.JobLevel);
322 generate_daemon_event(jcr, "JobStart");
323 new_plugins(jcr); /* instantiate plugins for this jcr */
324 generate_plugin_event(jcr, bDirEventJobStart);
326 if (job_canceled(jcr)) {
327 Dmsg0(100, "Oops. Job canceled\n");
331 /* Re-run the old job */
332 jcr->rerunning = true;
335 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
336 * this allows us to setup a proper job start record for restarting
337 * in case of later errors.
339 switch (jcr->getJobType()) {
341 if (!do_backup_init(jcr)) {
342 backup_cleanup(jcr, JS_ErrorTerminated);
347 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
348 jcr->setJobStatus(JS_ErrorTerminated);
352 generate_plugin_event(jcr, bDirEventJobInit);
360 JobId_t resume_job(JCR *jcr, JOB_DBR *jr)
363 if (setup_resume_job(jcr, jr)) {
364 Dmsg0(200, "Add jrc to work queue\n");
365 /* Queue the job to be run */
366 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
368 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
378 void update_job_end(JCR *jcr, int TermCode)
380 dequeue_messages(jcr); /* display any queued messages */
381 jcr->setJobStatus(TermCode);
382 update_job_end_record(jcr);
386 * This is the engine called by jobq.c:jobq_add() when we were pulled
387 * from the work queue.
388 * At this point, we are running in our own thread and all
389 * necessary resources are allocated -- see jobq.c
391 static void *job_thread(void *arg)
393 JCR *jcr = (JCR *)arg;
395 pthread_detach(pthread_self());
398 Dmsg0(200, "=====Start Job=========\n");
399 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
400 jcr->start_time = time(NULL); /* set the real start time */
401 jcr->jr.StartTime = jcr->start_time;
403 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
404 (utime_t)(jcr->start_time - jcr->sched_time)) {
405 jcr->setJobStatus(JS_Canceled);
406 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
409 if (job_check_maxrunschedtime(jcr)) {
410 jcr->setJobStatus(JS_Canceled);
411 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
414 /* TODO : check if it is used somewhere */
415 if (jcr->job->RunScripts == NULL) {
416 Dmsg0(200, "Warning, job->RunScripts is empty\n");
417 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
420 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
421 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
424 /* Run any script BeforeJob on dird */
425 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
428 * We re-update the job start record so that the start
429 * time is set after the run before job. This avoids
430 * that any files created by the run before job will
431 * be saved twice. They will be backed up in the current
432 * job, but not in the next one unless they are changed.
433 * Without this, they will be backed up in this job and
434 * in the next job run because in that case, their date
435 * is after the start of this run.
437 jcr->start_time = time(NULL);
438 jcr->jr.StartTime = jcr->start_time;
439 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
440 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
442 generate_plugin_event(jcr, bDirEventJobRun);
444 switch (jcr->getJobType()) {
446 if (!job_canceled(jcr) && do_backup(jcr)) {
449 backup_cleanup(jcr, JS_ErrorTerminated);
453 if (!job_canceled(jcr) && do_verify(jcr)) {
456 verify_cleanup(jcr, JS_ErrorTerminated);
460 if (!job_canceled(jcr) && do_restore(jcr)) {
463 restore_cleanup(jcr, JS_ErrorTerminated);
467 if (!job_canceled(jcr) && do_admin(jcr)) {
470 admin_cleanup(jcr, JS_ErrorTerminated);
475 if (!job_canceled(jcr) && do_mac(jcr)) {
478 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
482 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
486 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
488 /* Send off any queued messages */
489 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
490 dequeue_messages(jcr);
493 generate_daemon_event(jcr, "JobEnd");
494 generate_plugin_event(jcr, bDirEventJobEnd);
495 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
500 void sd_msg_thread_send_signal(JCR *jcr, int sig)
503 if ( !jcr->sd_msg_thread_done
504 && jcr->SD_msg_chan_started
505 && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
507 Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
508 pthread_kill(jcr->SD_msg_chan, sig);
513 static bool cancel_file_daemon_job(UAContext *ua, const char *cmd, JCR *jcr)
518 Dmsg0(100, "No client to cancel\n");
521 old_client = ua->jcr->client;
522 ua->jcr->client = jcr->client;
523 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
524 ua->error_msg(_("Failed to connect to File daemon.\n"));
525 ua->jcr->client = old_client;
528 Dmsg3(10, "Connected to file daemon %s for cancel ua.jcr=%p jcr=%p\n",
529 ua->jcr->client->name(), ua->jcr, jcr);
530 BSOCK *fd = ua->jcr->file_bsock;
531 fd->fsend("%s Job=%s\n", cmd, jcr->Job);
532 while (fd->recv() >= 0) {
533 ua->send_msg("%s", fd->msg);
535 fd->signal(BNET_TERMINATE);
536 free_bsock(ua->jcr->file_bsock);
537 ua->jcr->client = old_client;
541 static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
543 if (jcr->store_bsock) {
545 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
547 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
552 store.store = jcr->rstore;
554 store.store = jcr->wstore;
556 set_wstorage(ua->jcr, &store);
559 if (!ua->jcr->wstore) {
560 ua->error_msg(_("Failed to select Storage daemon.\n"));
564 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
565 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
569 Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
570 ua->jcr->wstore->name(), ua->jcr, jcr);
572 BSOCK *sd = ua->jcr->store_bsock;
573 sd->fsend("%s Job=%s\n", cmd, jcr->Job);
574 while (sd->recv() >= 0) {
575 ua->send_msg("%s", sd->msg);
577 sd->signal(BNET_TERMINATE);
578 free_bsock(ua->jcr->store_bsock);
582 /* The FD is not connected, so we try to complete JCR fields and send
583 * the cancel command.
585 static int cancel_inactive_job(UAContext *ua, JCR *jcr)
593 Dmsg2(10, "cancel_inactive_job ua.jcr=%p jcr=%p\n", ua->jcr, jcr);
596 memset(&cr, 0, sizeof(cr));
598 /* User is kind enough to provide the client name */
599 if ((i = find_arg_with_value(ua, "client")) > 0) {
600 bstrncpy(cr.Name, ua->argv[i], sizeof(cr.Name));
602 memset(&jr, 0, sizeof(jr));
603 bstrncpy(jr.Job, jcr->Job, sizeof(jr.Job));
605 if (!open_client_db(ua)) {
608 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
611 cr.ClientId = jr.ClientId;
612 if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
617 if (acl_access_ok(ua, Client_ACL, cr.Name)) {
618 client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
620 jcr->client = client;
622 Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
630 cancel_file_daemon_job(ua, "cancel", jcr);
632 /* At this time, we can't really guess the storage name from
635 store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
640 set_wstorage(ua->jcr, &store);
642 cancel_sd_job(ua, "cancel", jcr);
649 * Cancel a job -- typically called by the UA (Console program), but may also
650 * be called by the job watchdog.
652 * Returns: true if cancel appears to be successful
653 * false on failure. Message sent to ua->jcr.
656 cancel_job(UAContext *ua, JCR *jcr, bool cancel)
659 int32_t old_status = jcr->JobStatus;
661 const char *reason, *cmd;
662 bool force = find_arg(ua, "inactive") > 0;
664 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
666 /* If the user explicitely ask, we can send the cancel command to
669 if (cancel && force) {
670 return cancel_inactive_job(ua, jcr);
674 status = JS_Canceled;
675 reason = _("canceled");
678 status = JS_Incomplete;
679 reason = _("stopped");
681 jcr->RescheduleIncompleteJobs = false; /* do not restart */
684 jcr->setJobStatus(status);
686 switch (old_status) {
689 case JS_WaitClientRes:
690 case JS_WaitStoreRes:
691 case JS_WaitPriority:
693 case JS_WaitStartTime:
695 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
696 edit_uint64(jcr->JobId, ed1), jcr->Job,
698 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
703 /* Cancel File daemon */
704 if (jcr->file_bsock) {
705 /* do not return now, we want to try to cancel the sd */
706 cancel_file_daemon_job(ua, cmd, jcr);
709 /* We test file_bsock because the previous operation can take
712 if (jcr->file_bsock && cancel) {
713 jcr->file_bsock->set_terminated();
714 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
717 /* Cancel Storage daemon */
718 if (jcr->store_bsock) {
719 /* do not return now, we want to try to cancel the sd socket */
720 cancel_sd_job(ua, cmd, jcr);
723 /* We test file_bsock because the previous operation can take
726 if (jcr->store_bsock && cancel) {
727 jcr->store_bsock->set_timed_out();
728 jcr->store_bsock->set_terminated();
729 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
730 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
733 /* Cancel Copy/Migration Storage daemon */
735 /* The wjcr is valid until we call free_jcr(jcr) */
736 JCR *wjcr = jcr->wjcr;
738 if (wjcr->store_bsock) {
739 /* do not return now, we want to try to cancel the sd socket */
740 cancel_sd_job(ua, cmd, wjcr);
742 /* We test file_bsock because the previous operation can take
745 if (wjcr->store_bsock && cancel) {
746 wjcr->store_bsock->set_timed_out();
747 wjcr->store_bsock->set_terminated();
748 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
749 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
758 void cancel_storage_daemon_job(JCR *jcr)
760 if (jcr->sd_canceled) {
761 return; /* cancel only once */
764 UAContext *ua = new_ua_context(jcr);
765 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
768 ua->jcr = control_jcr;
769 if (jcr->store_bsock) {
770 if (!ua->jcr->wstorage) {
772 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
774 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
779 store.store = jcr->rstore;
781 store.store = jcr->wstore;
783 set_wstorage(ua->jcr, &store);
786 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
789 Dmsg0(200, "Connected to storage daemon\n");
790 sd = ua->jcr->store_bsock;
791 sd->fsend("cancel Job=%s\n", jcr->Job);
792 while (sd->recv() >= 0) {
794 sd->signal(BNET_TERMINATE);
795 free_bsock(ua->jcr->store_bsock);
796 jcr->sd_canceled = true;
797 jcr->store_bsock->set_timed_out();
798 jcr->store_bsock->set_terminated();
799 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
800 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
803 free_jcr(control_jcr);
807 static void job_monitor_destructor(watchdog_t *self)
809 JCR *control_jcr = (JCR *)self->data;
811 free_jcr(control_jcr);
814 static void job_monitor_watchdog(watchdog_t *self)
816 JCR *control_jcr, *jcr;
818 control_jcr = (JCR *)self->data;
821 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
826 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
827 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
831 /* check MaxWaitTime */
832 if (job_check_maxwaittime(jcr)) {
833 jcr->setJobStatus(JS_Canceled);
834 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
836 /* check MaxRunTime */
837 } else if (job_check_maxruntime(jcr)) {
838 jcr->setJobStatus(JS_Canceled);
839 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
841 /* check MaxRunSchedTime */
842 } else if (job_check_maxrunschedtime(jcr)) {
843 jcr->setJobStatus(JS_Canceled);
844 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
849 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
850 UAContext *ua = new_ua_context(jcr);
851 ua->jcr = control_jcr;
854 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
858 /* Keep reference counts correct */
863 * Check if the maxwaittime has expired and it is possible
866 static bool job_check_maxwaittime(JCR *jcr)
872 if (!job_waiting(jcr)) {
876 if (jcr->wait_time) {
877 current = watchdog_time - jcr->wait_time;
880 Dmsg2(200, "check maxwaittime %u >= %u\n",
881 current + jcr->wait_time_sum, job->MaxWaitTime);
882 if (job->MaxWaitTime != 0 &&
883 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
891 * Check if maxruntime has expired and if the job can be
894 static bool job_check_maxruntime(JCR *jcr)
900 if (job_canceled(jcr) || !jcr->job_started) {
903 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
904 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
907 run_time = watchdog_time - jcr->start_time;
908 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
909 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
910 job->IncMaxRunTime, job->DiffMaxRunTime);
912 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
913 run_time >= job->FullMaxRunTime) {
914 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
916 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
917 run_time >= job->DiffMaxRunTime) {
918 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
920 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
921 run_time >= job->IncMaxRunTime) {
922 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
924 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
925 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
933 * Check if MaxRunSchedTime has expired and if the job can be
936 static bool job_check_maxrunschedtime(JCR *jcr)
938 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
941 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
942 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
943 jcr, jcr->Job, jcr->MaxRunSchedTime);
951 * Get or create a Pool record with the given name.
952 * Returns: 0 on error
955 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
959 memset(&pr, 0, sizeof(pr));
960 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
961 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
963 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
964 /* Try to create the pool */
965 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
966 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
967 db_strerror(jcr->db));
970 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
977 * Check for duplicate jobs.
978 * Returns: true if current job should continue
979 * false if current job should terminate
981 bool allow_duplicate_job(JCR *jcr)
984 JCR *djcr; /* possible duplicate job */
986 /* Is AllowDuplicateJobs is set or is duplicate checking
987 * disabled for this job? */
988 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
991 Dmsg0(800, "Enter allow_duplicate_job\n");
993 * After this point, we do not want to allow any duplicate
998 if (jcr == djcr || djcr->JobId == 0) {
999 continue; /* do not cancel this job or consoles */
1001 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1002 * if so do not check it against other jobs */
1003 if (djcr->IgnoreDuplicateJobChecking) {
1006 if (strcmp(job->name(), djcr->job->name()) == 0) {
1007 bool cancel_dup = false;
1008 bool cancel_me = false;
1009 if (job->DuplicateJobProximity > 0) {
1010 utime_t now = (utime_t)time(NULL);
1011 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1012 continue; /* not really a duplicate */
1015 if (job->CancelLowerLevelDuplicates &&
1016 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1017 switch (jcr->getJobLevel()) {
1019 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1020 djcr->getJobLevel() == L_INCREMENTAL) {
1024 case L_DIFFERENTIAL:
1025 if (djcr->getJobLevel() == L_INCREMENTAL) {
1028 if (djcr->getJobLevel() == L_FULL) {
1033 if (djcr->getJobLevel() == L_FULL ||
1034 djcr->getJobLevel() == L_DIFFERENTIAL) {
1039 * cancel_dup will be done below
1042 /* Zap current job */
1043 jcr->setJobStatus(JS_Canceled);
1044 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1046 break; /* get out of foreach_jcr */
1049 /* Cancel one of the two jobs (me or dup) */
1050 /* If CancelQueuedDuplicates is set do so only if job is queued */
1051 if (job->CancelQueuedDuplicates) {
1052 switch (djcr->JobStatus) {
1055 case JS_WaitClientRes:
1056 case JS_WaitStoreRes:
1057 case JS_WaitPriority:
1058 case JS_WaitMaxJobs:
1059 case JS_WaitStartTime:
1061 cancel_dup = true; /* cancel queued duplicate */
1067 if (cancel_dup || job->CancelRunningDuplicates) {
1068 /* Zap the duplicated job djcr */
1069 UAContext *ua = new_ua_context(jcr);
1070 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1071 cancel_job(ua, djcr);
1072 bmicrosleep(0, 500000);
1073 djcr->setJobStatus(JS_Canceled);
1074 cancel_job(ua, djcr);
1075 free_ua_context(ua);
1076 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1078 /* Zap current job */
1079 jcr->setJobStatus(JS_Canceled);
1080 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1082 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1084 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1085 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1086 break; /* did our work, get out of foreach loop */
1095 * Apply pool overrides to get the storage properly setup.
1097 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1101 Dmsg1(100, "Original pool=%s\n", opool->name());
1102 if (jcr->cmdline_next_pool_override) {
1103 /* Can be Command line or User input */
1104 source = NPRT(jcr->next_pool_source);
1105 } else if (jcr->run_next_pool_override) {
1106 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1107 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1108 source = _("Run NextPool override");
1109 } else if (jcr->job->next_pool) {
1110 /* Use Job Next Pool */
1111 jcr->next_pool = jcr->job->next_pool;
1112 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1113 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1114 source = _("Job's NextPool resource");
1116 /* Default to original pool->NextPool */
1117 jcr->next_pool = opool->NextPool;
1118 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1119 if (jcr->next_pool) {
1120 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1122 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1123 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1124 source = _("Pool's NextPool resource");
1128 * If the original backup pool has a NextPool, make sure a
1129 * record exists in the database.
1131 if (jcr->next_pool) {
1132 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1133 if (jcr->jr.PoolId == 0) {
1138 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1142 /* Set write pool and source. Not read pool is in rpool. */
1143 jcr->pool = jcr->next_pool;
1144 pm_strcpy(jcr->pool_source, source);
1150 void apply_pool_overrides(JCR *jcr)
1152 bool pool_override = false;
1154 if (jcr->run_pool_override) {
1155 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1158 * Apply any level related Pool selections
1160 switch (jcr->getJobLevel()) {
1162 if (jcr->full_pool) {
1163 jcr->pool = jcr->full_pool;
1164 pool_override = true;
1165 if (jcr->run_full_pool_override) {
1166 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1168 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1173 if (jcr->inc_pool) {
1174 jcr->pool = jcr->inc_pool;
1175 pool_override = true;
1176 if (jcr->run_inc_pool_override) {
1177 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1179 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1183 case L_DIFFERENTIAL:
1184 if (jcr->diff_pool) {
1185 jcr->pool = jcr->diff_pool;
1186 pool_override = true;
1187 if (jcr->run_diff_pool_override) {
1188 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1190 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1195 /* Update catalog if pool overridden */
1196 if (pool_override && jcr->pool->catalog) {
1197 jcr->catalog = jcr->pool->catalog;
1198 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1204 * Get or create a Client record for this Job
1206 bool get_or_create_client_record(JCR *jcr)
1211 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1214 memset(&cr, 0, sizeof(cr));
1215 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1216 cr.AutoPrune = jcr->client->AutoPrune;
1217 cr.FileRetention = jcr->client->FileRetention;
1218 cr.JobRetention = jcr->client->JobRetention;
1219 if (!jcr->client_name) {
1220 jcr->client_name = get_pool_memory(PM_NAME);
1222 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1223 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1224 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1225 db_strerror(jcr->db));
1228 jcr->jr.ClientId = cr.ClientId;
1230 if (!jcr->client_uname) {
1231 jcr->client_uname = get_pool_memory(PM_NAME);
1233 pm_strcpy(jcr->client_uname, cr.Uname);
1235 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1241 * Get or Create FileSet record
1243 bool get_or_create_fileset_record(JCR *jcr)
1247 memset(&fsr, 0, sizeof(FILESET_DBR));
1248 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1249 if (jcr->fileset->have_MD5) {
1250 struct MD5Context md5c;
1251 unsigned char digest[MD5HashSize];
1252 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1253 MD5Final(digest, &md5c);
1255 * Keep the flag (last arg) set to false otherwise old FileSets will
1256 * get new MD5 sums and the user will get Full backups on everything
1258 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1259 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1261 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1263 if (!jcr->fileset->ignore_fs_changes ||
1264 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1265 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1266 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1267 fsr.FileSet, db_strerror(jcr->db));
1271 jcr->jr.FileSetId = fsr.FileSetId;
1272 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1273 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1278 void init_jcr_job_record(JCR *jcr)
1280 jcr->jr.SchedTime = jcr->sched_time;
1281 jcr->jr.StartTime = jcr->start_time;
1282 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1283 jcr->jr.JobType = jcr->getJobType();
1284 jcr->jr.JobLevel = jcr->getJobLevel();
1285 jcr->jr.JobStatus = jcr->JobStatus;
1286 jcr->jr.JobId = jcr->JobId;
1287 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1288 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1292 * Write status and such in DB
1294 void update_job_end_record(JCR *jcr)
1296 jcr->jr.EndTime = time(NULL);
1297 jcr->end_time = jcr->jr.EndTime;
1298 jcr->jr.JobId = jcr->JobId;
1299 jcr->jr.JobStatus = jcr->JobStatus;
1300 jcr->jr.JobFiles = jcr->JobFiles;
1301 jcr->jr.JobBytes = jcr->JobBytes;
1302 jcr->jr.ReadBytes = jcr->ReadBytes;
1303 jcr->jr.VolSessionId = jcr->VolSessionId;
1304 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1305 jcr->jr.JobErrors = jcr->JobErrors;
1306 jcr->jr.HasBase = jcr->HasBase;
1307 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1308 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1309 db_strerror(jcr->db));
1314 * Takes base_name and appends (unique) current
1315 * date and time to form unique job name.
1317 * Note, the seconds are actually a sequence number. This
1318 * permits us to start a maximum fo 59 unique jobs a second, which
1319 * should be sufficient.
1321 * Returns: unique job name in jcr->Job
1322 * date/time in jcr->start_time
1324 void create_unique_job_name(JCR *jcr, const char *base_name)
1326 /* Job start mutex */
1327 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1328 static time_t last_start_time = 0;
1330 time_t now = time(NULL);
1332 char dt[MAX_TIME_LENGTH];
1333 char name[MAX_NAME_LENGTH];
1338 /* Guarantee unique start time -- maximum one per second, and
1339 * thus unique Job Name
1341 P(mutex); /* lock creation of jobs */
1343 if (seq > 59) { /* wrap as if it is seconds */
1345 while (now == last_start_time) {
1346 bmicrosleep(0, 500000);
1350 last_start_time = now;
1352 V(mutex); /* allow creation of jobs */
1353 jcr->start_time = now;
1354 /* Form Unique JobName */
1355 (void)localtime_r(&now, &tm);
1356 /* Use only characters that are permitted in Windows filenames */
1357 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1358 len = strlen(dt) + 5; /* dt + .%02d EOS */
1359 bstrncpy(name, base_name, sizeof(name));
1360 name[sizeof(name)-len] = 0; /* truncate if too long */
1361 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1362 /* Convert spaces into underscores */
1363 for (p=jcr->Job; *p; p++) {
1368 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1371 /* Called directly from job rescheduling */
1372 void dird_free_jcr_pointers(JCR *jcr)
1374 /* Close but do not free bsock packets */
1375 if (jcr->file_bsock) {
1376 Dmsg0(200, "Close File bsock\n");
1377 jcr->file_bsock->close();
1379 if (jcr->store_bsock) {
1380 Dmsg0(200, "Close Store bsock\n");
1381 jcr->store_bsock->close();
1384 bfree_and_null(jcr->sd_auth_key);
1385 bfree_and_null(jcr->where);
1386 bfree_and_null(jcr->RestoreBootstrap);
1387 jcr->cached_attribute = false;
1388 bfree_and_null(jcr->ar);
1390 free_and_null_pool_memory(jcr->JobIds);
1391 free_and_null_pool_memory(jcr->client_uname);
1392 free_and_null_pool_memory(jcr->attr);
1393 free_and_null_pool_memory(jcr->fname);
1394 free_and_null_pool_memory(jcr->media_type);
1398 * Free the Job Control Record if no one is still using it.
1399 * Called from main free_jcr() routine in src/lib/jcr.c so
1400 * that we can do our Director specific cleanup of the jcr.
1402 void dird_free_jcr(JCR *jcr)
1404 Dmsg0(200, "Start dird free_jcr\n");
1406 dird_free_jcr_pointers(jcr);
1408 free_jcr(jcr->wjcr);
1411 /* Free bsock packets */
1412 free_bsock(jcr->file_bsock);
1413 free_bsock(jcr->store_bsock);
1414 if (jcr->term_wait_inited) {
1415 pthread_cond_destroy(&jcr->term_wait);
1416 jcr->term_wait_inited = false;
1418 if (jcr->db_batch) {
1419 db_close_database(jcr, jcr->db_batch);
1420 jcr->db_batch = NULL;
1421 jcr->batch_started = false;
1424 db_close_database(jcr, jcr->db);
1428 free_and_null_pool_memory(jcr->stime);
1429 free_and_null_pool_memory(jcr->fname);
1430 free_and_null_pool_memory(jcr->pool_source);
1431 free_and_null_pool_memory(jcr->next_pool_source);
1432 free_and_null_pool_memory(jcr->catalog_source);
1433 free_and_null_pool_memory(jcr->rpool_source);
1434 free_and_null_pool_memory(jcr->wstore_source);
1435 free_and_null_pool_memory(jcr->rstore_source);
1436 free_and_null_pool_memory(jcr->next_vol_list);
1438 /* Delete lists setup to hold storage pointers */
1439 free_rwstorage(jcr);
1441 jcr->job_end_push.destroy();
1443 if (jcr->JobId != 0) {
1444 write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
1447 free_plugins(jcr); /* release instantiated plugins */
1449 Dmsg0(200, "End dird free_jcr\n");
1453 * The Job storage definition must be either in the Job record
1454 * or in the Pool record. The Pool record overrides the Job
1457 void get_job_storage(USTORE *store, JOB *job, RUN *run)
1459 if (run && run->pool && run->pool->storage) {
1460 store->store = (STORE *)run->pool->storage->first();
1461 pm_strcpy(store->store_source, _("Run pool override"));
1464 if (run && run->storage) {
1465 store->store = run->storage;
1466 pm_strcpy(store->store_source, _("Run storage override"));
1469 if (job->pool->storage) {
1470 store->store = (STORE *)job->pool->storage->first();
1471 pm_strcpy(store->store_source, _("Pool resource"));
1473 store->store = (STORE *)job->storage->first();
1474 pm_strcpy(store->store_source, _("Job resource"));
1479 * Set some defaults in the JCR necessary to
1480 * run. These items are pulled from the job
1481 * definition as defaults, but can be overridden
1482 * later either by the Run record in the Schedule resource,
1483 * or by the Console program.
1485 void set_jcr_defaults(JCR *jcr, JOB *job)
1488 jcr->setJobType(job->JobType);
1489 jcr->JobStatus = JS_Created;
1491 switch (jcr->getJobType()) {
1493 jcr->setJobLevel(L_NONE);
1496 jcr->setJobLevel(job->JobLevel);
1499 if (!jcr->next_vol_list) {
1500 jcr->next_vol_list = get_pool_memory(PM_FNAME);
1503 jcr->fname = get_pool_memory(PM_FNAME);
1505 if (!jcr->pool_source) {
1506 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1508 if (!jcr->next_pool_source) {
1509 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1511 if (!jcr->catalog_source) {
1512 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1515 jcr->JobPriority = job->Priority;
1516 /* Copy storage definitions -- deleted in dir_free_jcr above */
1518 copy_rwstorage(jcr, job->storage, _("Job resource"));
1520 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1522 jcr->client = job->client;
1523 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1524 if (!jcr->client_name) {
1525 jcr->client_name = get_pool_memory(PM_NAME);
1527 pm_strcpy(jcr->client_name, jcr->client->name());
1528 jcr->pool = job->pool;
1529 pm_strcpy(jcr->pool_source, _("Job resource"));
1530 if (job->next_pool) {
1531 /* Use Job's Next Pool */
1532 jcr->next_pool = job->next_pool;
1533 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1535 /* Default to original pool->NextPool */
1536 jcr->next_pool = job->pool->NextPool;
1537 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1539 jcr->full_pool = job->full_pool;
1540 jcr->inc_pool = job->inc_pool;
1541 jcr->diff_pool = job->diff_pool;
1542 if (job->pool->catalog) {
1543 jcr->catalog = job->pool->catalog;
1544 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1546 jcr->catalog = job->client->catalog;
1547 pm_strcpy(jcr->catalog_source, _("Client resource"));
1549 jcr->fileset = job->fileset;
1550 jcr->accurate = job->accurate;
1551 jcr->messages = job->messages;
1552 jcr->spool_data = job->spool_data;
1553 jcr->spool_size = job->spool_size;
1554 jcr->write_part_after_job = job->write_part_after_job;
1555 jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
1556 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1557 if (jcr->RestoreBootstrap) {
1558 free(jcr->RestoreBootstrap);
1559 jcr->RestoreBootstrap = NULL;
1561 /* This can be overridden by Console program */
1562 if (job->RestoreBootstrap) {
1563 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1565 /* This can be overridden by Console program */
1566 jcr->verify_job = job->verify_job;
1567 /* If no default level given, set one */
1568 if (jcr->getJobLevel() == 0) {
1569 switch (jcr->getJobType()) {
1571 jcr->setJobLevel(L_VERIFY_CATALOG);
1574 jcr->setJobLevel(L_INCREMENTAL);
1578 jcr->setJobLevel(L_NONE);
1581 jcr->setJobLevel(L_FULL);
1588 * Copy the storage definitions from an alist to the JCR
1590 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1592 if (jcr->JobReads()) {
1593 copy_rstorage(jcr, storage, where);
1595 copy_wstorage(jcr, storage, where);
1599 /* Set storage override. Releases any previous storage definition */
1600 void set_rwstorage(JCR *jcr, USTORE *store)
1603 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1606 if (jcr->JobReads()) {
1607 set_rstorage(jcr, store);
1609 set_wstorage(jcr, store);
1612 void free_rwstorage(JCR *jcr)
1619 * Copy the storage definitions from an alist to the JCR
1621 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1625 if (jcr->rstorage) {
1626 delete jcr->rstorage;
1628 jcr->rstorage = New(alist(10, not_owned_by_alist));
1629 foreach_alist(st, storage) {
1630 jcr->rstorage->append(st);
1632 if (!jcr->rstore_source) {
1633 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1635 pm_strcpy(jcr->rstore_source, where);
1636 if (jcr->rstorage) {
1637 jcr->rstore = (STORE *)jcr->rstorage->first();
1643 /* Set storage override. Remove all previous storage */
1644 void set_rstorage(JCR *jcr, USTORE *store)
1648 if (!store->store) {
1651 if (jcr->rstorage) {
1654 if (!jcr->rstorage) {
1655 jcr->rstorage = New(alist(10, not_owned_by_alist));
1657 jcr->rstore = store->store;
1658 if (!jcr->rstore_source) {
1659 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1661 pm_strcpy(jcr->rstore_source, store->store_source);
1662 foreach_alist(storage, jcr->rstorage) {
1663 if (store->store == storage) {
1667 /* Store not in list, so add it */
1668 jcr->rstorage->prepend(store->store);
1671 void free_rstorage(JCR *jcr)
1673 if (jcr->rstorage) {
1674 delete jcr->rstorage;
1675 jcr->rstorage = NULL;
1681 * Copy the storage definitions from an alist to the JCR
1683 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1687 if (jcr->wstorage) {
1688 delete jcr->wstorage;
1690 jcr->wstorage = New(alist(10, not_owned_by_alist));
1691 foreach_alist(st, storage) {
1692 Dmsg1(100, "wstorage=%s\n", st->name());
1693 jcr->wstorage->append(st);
1695 if (!jcr->wstore_source) {
1696 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1698 pm_strcpy(jcr->wstore_source, where);
1699 if (jcr->wstorage) {
1700 jcr->wstore = (STORE *)jcr->wstorage->first();
1701 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1707 /* Set storage override. Remove all previous storage */
1708 void set_wstorage(JCR *jcr, USTORE *store)
1712 if (!store->store) {
1715 if (jcr->wstorage) {
1718 if (!jcr->wstorage) {
1719 jcr->wstorage = New(alist(10, not_owned_by_alist));
1721 jcr->wstore = store->store;
1722 if (!jcr->wstore_source) {
1723 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1725 pm_strcpy(jcr->wstore_source, store->store_source);
1726 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1727 foreach_alist(storage, jcr->wstorage) {
1728 if (store->store == storage) {
1732 /* Store not in list, so add it */
1733 jcr->wstorage->prepend(store->store);
1736 void free_wstorage(JCR *jcr)
1738 if (jcr->wstorage) {
1739 delete jcr->wstorage;
1740 jcr->wstorage = NULL;
1745 void create_clones(JCR *jcr)
1748 * Fire off any clone jobs (run directives)
1750 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1751 if (!jcr->cloned && jcr->job->run_cmds) {
1753 JOB *job = jcr->job;
1754 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1755 UAContext *ua = new_ua_context(jcr);
1757 foreach_alist(runcmd, job->run_cmds) {
1758 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1759 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1760 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1761 parse_ua_args(ua); /* parse command */
1762 int stat = run_cmd(ua, ua->cmd);
1764 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1767 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1770 free_ua_context(ua);
1771 free_pool_memory(cmd);
1776 * Given: a JobId in jcr->previous_jr.JobId,
1777 * this subroutine writes a bsr file to restore that job.
1778 * Returns: -1 on error
1779 * number of files if OK
1781 int create_restore_bootstrap_file(JCR *jcr)
1787 memset(&rx, 0, sizeof(rx));
1789 rx.JobIds = (char *)"";
1790 rx.bsr->JobId = jcr->previous_jr.JobId;
1791 ua = new_ua_context(jcr);
1792 if (!complete_bsr(ua, rx.bsr)) {
1796 rx.bsr->fi = new_findex();
1797 rx.bsr->fi->findex = 1;
1798 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1799 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1800 if (jcr->ExpectedFiles == 0) {
1804 free_ua_context(ua);
1806 jcr->needs_sd = true;
1807 return jcr->ExpectedFiles;
1810 free_ua_context(ua);
1815 /* TODO: redirect command ouput to job log */
1816 bool run_console_command(JCR *jcr, const char *cmd)
1820 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1821 ua = new_ua_context(ljcr);
1822 /* run from runscript and check if commands are authorized */
1823 ua->runscript = true;
1824 Mmsg(ua->cmd, "%s", cmd);
1825 Dmsg1(100, "Console command: %s\n", ua->cmd);
1827 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1828 ok = do_a_dot_command(ua);
1830 ok = do_a_command(ua);
1832 free_ua_context(ua);